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 <[email protected]>
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"