From 1930e50cfffed3fdcea7e9e6eaff6587cde3b7f3 Mon Sep 17 00:00:00 2001 From: yumwang Date: Tue, 28 Jul 2020 16:40:44 +0800 Subject: [PATCH] [CARMEL-2691] Support % as well in the pattern spec for show like table 'xxx' (#6) --- .../sql/catalyst/analysis/Analyzer.scala | 20 ++++++++++ .../sql/catalyst/analysis/AnalysisSuite.scala | 37 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala index 6fb103e46a77b..b93dab6621341 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala @@ -1328,6 +1328,7 @@ class Analyzer( withPosition(u) { q.resolveChildren(nameParts, resolver) .orElse(resolveLiteralFunction(nameParts, u, q)) + .orElse(resolveReferencedAlias(nameParts, u, q)) .getOrElse(u) } logDebug(s"Resolving $u to $result") @@ -1605,6 +1606,25 @@ class Analyzer( func.map(wrapper) } + private def resolveReferencedAlias( + nameParts: Seq[String], + attribute: UnresolvedAttribute, + plan: LogicalPlan): Option[Expression] = { + def resolveAlias(exps: Seq[NamedExpression]) = { + val alias = exps + .filter(a => a.resolved && a.isInstanceOf[Alias] && resolver(a.name, nameParts.head)) + if (alias.size > 1) { + throw new AnalysisException(s"Found duplicate alias when resolving '${nameParts.head}'") + } + alias.headOption + } + plan match { + case Aggregate(groups, aggs, _) if !groups.contains(attribute) => resolveAlias(aggs) + case Project(projectList, _) => resolveAlias(projectList) + case _ => None + } + } + /** * Resolves the attribute, column value and extract value expressions(s) by traversing the * input expression in bottom-up manner. In order to resolve the nested complex type fields diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisSuite.scala index 02472e153b09e..55ab0c5d7c5f9 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisSuite.scala @@ -826,4 +826,41 @@ class AnalysisSuite extends AnalysisTest with Matchers { } } } + + test("Resolve referenced alias") { + val a = testRelation.output.head + checkAnalysis( + testRelation.select((a + 1).as("a_alias"), ($"a_alias" + 1).as("a_alias_ref")), + testRelation.select((a + 1).as("a_alias"), (a + 1 + 1).as("a_alias_ref"))) + checkAnalysis( + testRelation.groupBy(a.as("a1"))( + (min(a) + 1).as("min_a_alias"), ($"min_a_alias" + 1).as("min_a_alias_ref")), + testRelation.groupBy(a)( + (min(a) + 1).as("min_a_alias"), ((min(a) + 1) + 1).as("min_a_alias_ref"))) + checkAnalysis( + testRelation.select((a + 1).as("a_alias"), + CaseWhen(Seq((Literal(true), Symbol("a_alias").attr)), Symbol("a")).as("a_alias_ref")), + testRelation.select((a + 1).as("a_alias"), + CaseWhen(Seq((Literal(true), a + 1)), a).as("a_alias_ref"))) + + val inputPlan = testRelation.select((a + 1).as("a_alias"), $"A_ALIAS" + 1) + Seq(false, true).foreach { caseSensitive => + if (caseSensitive) { + assertAnalysisError(inputPlan, "cannot resolve '`A_ALIAS`'" :: Nil, caseSensitive) + } else { + assertAnalysisSuccess(inputPlan, caseSensitive) + } + } + + assertAnalysisError( + testRelation.select(a.as("a_alias"), a.as("a_alias"), $"a_alias" + 1), + "Found duplicate alias when resolving 'a_alias'" :: Nil) + + assertAnalysisError( + testRelation.select((a + 1).as("a_alias"), $"non_exist_alias" + 1), + "cannot resolve '`non_exist_alias`'" :: Nil) + assertAnalysisError( + testRelation.groupBy(a.as("a1"))((min(a) + 1).as("min_a_alias"), $"non_exist_alias" + 1), + "cannot resolve '`non_exist_alias`'" :: Nil) + } }