This is an automated email from the ASF dual-hosted git repository.

danny0405 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 468b111  [CALCITE-4172] Expand columnar identifiers before resolving 
(James Starr)
468b111 is described below

commit 468b111b3cae44efd31e60c4bafe0018c8821e9a
Author: James Starr <jamesst...@gmail.com>
AuthorDate: Wed Aug 12 13:16:21 2020 -0700

    [CALCITE-4172] Expand columnar identifiers before resolving (James Starr)
    
    close apache/calcite#2108
---
 .../calcite/sql/validate/SqlValidatorImpl.java     |  2 +-
 .../org/apache/calcite/test/SqlValidatorTest.java  | 93 +++++++++++++++++++++-
 2 files changed, 91 insertions(+), 4 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index 9123f92..5782ee7 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -3997,7 +3997,6 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     final String clause = "GROUP BY";
     validateNoAggs(aggOrOverFinder, groupList, clause);
     final SqlValidatorScope groupScope = getGroupScope(select);
-    inferUnknownTypes(unknownType, groupScope, groupList);
 
     // expand the expression in group list.
     List<SqlNode> expandedList = new ArrayList<>();
@@ -4007,6 +4006,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     }
     groupList = new SqlNodeList(expandedList, groupList.getParserPosition());
     select.setGroupBy(groupList);
+    inferUnknownTypes(unknownType, groupScope, groupList);
     for (SqlNode groupItem : expandedList) {
       validateGroupByItem(select, groupItem);
     }
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index b9d7ed6..3623a18 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -25,31 +25,40 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.runtime.CalciteContextException;
 import org.apache.calcite.sql.SqlCollation;
+import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorTable;
+import org.apache.calcite.sql.SqlSelect;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.fun.SqlLibrary;
 import org.apache.calcite.sql.fun.SqlLibraryOperatorTableFactory;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParseException;
 import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.test.SqlTestFactory;
+import org.apache.calcite.sql.test.SqlValidatorTester;
 import org.apache.calcite.sql.type.ArraySqlType;
 import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.calcite.sql.util.SqlShuttle;
+import org.apache.calcite.sql.validate.SelectScope;
 import org.apache.calcite.sql.validate.SqlAbstractConformance;
 import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlConformanceEnum;
 import org.apache.calcite.sql.validate.SqlDelegatingConformance;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql.validate.SqlValidatorImpl;
+import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.test.catalog.CountingFactory;
 import org.apache.calcite.testlib.annotations.LocaleEnUs;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
 
@@ -62,7 +71,6 @@ import java.io.StringReader;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.nio.charset.Charset;
-import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
@@ -83,6 +91,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
+import static java.util.Arrays.asList;
+
 /**
  * Concrete child class of {@link SqlValidatorTestCase}, containing lots of 
unit
  * tests.
@@ -4082,7 +4092,7 @@ public class SqlValidatorTest extends 
SqlValidatorTestCase {
 
   @Test void testWindowFunctions2() {
     List<String> defined =
-        Arrays.asList("CUME_DIST", "DENSE_RANK", "PERCENT_RANK", "RANK",
+        asList("CUME_DIST", "DENSE_RANK", "PERCENT_RANK", "RANK",
             "ROW_NUMBER");
     if (Bug.TODO_FIXED) {
       sql("select rank() over (order by deptno) from emp")
@@ -7536,7 +7546,7 @@ public class SqlValidatorTest extends 
SqlValidatorTestCase {
     sql("select * from emp where deptno = ? and sal < 100000").ok();
     sql("select case when deptno = ? then 1 else 2 end from emp").ok();
     // It is not possible to infer type of ?, because SUBSTRING is overloaded
-    sql("select deptno from emp group by substring(name from ^?^ for ?)")
+    sql("select deptno from emp group by substring(ename from ^?^ for ?)")
         .fails("Illegal use of dynamic parameter");
     // In principle we could infer that ? should be a VARCHAR
     sql("select count(*) from emp group by position(^?^ in ename)")
@@ -8484,6 +8494,83 @@ public class SqlValidatorTest extends 
SqlValidatorTestCase {
         .rewritesTo(expected);
   }
 
+  @Test void testRewriteExpansionOfColumnReferenceBeforeResolution() {
+    SqlValidatorTester sqlValidatorTester = new SqlValidatorTester(
+        SqlTestFactory.INSTANCE.withValidator((opTab, catalogReader, 
typeFactory, config) ->
+             // Rewrites columnar sql identifiers 'UNEXPANDED'.'Something' to 
'DEPT'.'Something',
+             // where 'Something' is any string.
+            new SqlValidatorImpl(opTab, catalogReader, typeFactory, config) {
+              @Override public SqlNode expand(SqlNode expr, SqlValidatorScope 
scope) {
+                SqlNode rewrittenNode = rewriteNode(expr);
+                return super.expand(rewrittenNode, scope);
+              }
+
+              @Override public SqlNode expandSelectExpr(
+                  SqlNode expr,
+                  SelectScope scope,
+                  SqlSelect select) {
+                SqlNode rewrittenNode = rewriteNode(expr);
+                return super.expandSelectExpr(rewrittenNode, scope, select);
+              }
+
+              @Override public SqlNode expandGroupByOrHavingExpr(
+                  SqlNode expr,
+                  SqlValidatorScope scope,
+                  SqlSelect select,
+                  boolean havingExpression) {
+                SqlNode rewrittenNode = rewriteNode(expr);
+                return super.expandGroupByOrHavingExpr(
+                    rewrittenNode,
+                    scope,
+                    select,
+                    havingExpression);
+              }
+
+              private SqlNode rewriteNode(SqlNode sqlNode) {
+                return sqlNode.accept(new SqlShuttle() {
+                  @Override public SqlNode visit(SqlIdentifier id) {
+                    return rewriteIdentifier(id);
+                  }
+                });
+              }
+
+              private SqlIdentifier rewriteIdentifier(SqlIdentifier 
sqlIdentifier) {
+                Preconditions.checkArgument(sqlIdentifier.names.size() == 2);
+                if (sqlIdentifier.names.get(0).equals("UNEXPANDED")) {
+                  return new SqlIdentifier(
+                      asList("DEPT", sqlIdentifier.names.get(1)),
+                      null,
+                      sqlIdentifier.getParserPosition(),
+                      asList(
+                          sqlIdentifier.getComponentParserPosition(0),
+                          sqlIdentifier.getComponentParserPosition(1)));
+                } else if (sqlIdentifier.names.get(0).equals("DEPT")) {
+                  //  Identifiers are expanded multiple times
+                  return sqlIdentifier;
+                } else {
+                  throw new RuntimeException("Unknown Identifier " + 
sqlIdentifier);
+                }
+              }
+            }));
+
+    final String sql = "select unexpanded.deptno from dept \n"
+        + " where unexpanded.name = 'Moonracer' \n"
+        + " group by unexpanded.deptno\n"
+        + " having sum(unexpanded.deptno) > 0\n"
+        + " order by unexpanded.deptno";
+    final String expectedSql = "SELECT `DEPT`.`DEPTNO`\n"
+        + "FROM `CATALOG`.`SALES`.`DEPT` AS `DEPT`\n"
+        + "WHERE `DEPT`.`NAME` = 'Moonracer'\n"
+        + "GROUP BY `DEPT`.`DEPTNO`\n"
+        + "HAVING SUM(`DEPT`.`DEPTNO`) > 0\n"
+        + "ORDER BY `DEPT`.`DEPTNO`";
+    new Sql(sqlValidatorTester, sql, true, false)
+        .withValidatorIdentifierExpansion(true)
+        .withValidatorColumnReferenceExpansion(true)
+        .withConformance(SqlConformanceEnum.LENIENT)
+        .rewritesTo(expectedSql);
+  }
+
   @Test void testCoalesceWithoutRewrite() {
     final String sql = "select coalesce(deptno, empno) from emp";
     final String expected1 = "SELECT COALESCE(`EMP`.`DEPTNO`, `EMP`.`EMPNO`)\n"

Reply via email to