diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java index ff2903047d03..1949b2de2cfa 100644 --- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java @@ -46,6 +46,7 @@ import org.apache.calcite.sql.SqlOperatorTable; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; +import org.apache.calcite.sql.parser.SqlParser.Config; import org.apache.calcite.sql.util.SqlOperatorTables; import org.apache.calcite.sql.validate.SqlValidator; import org.apache.calcite.sql2rel.RelDecorrelator; @@ -117,14 +118,14 @@ public PlannerImpl(FrameworkConfig config) { this.convertletTable = config.getConvertletTable(); this.executor = config.getExecutor(); this.context = config.getContext(); - this.connectionConfig = connConfig(context, parserConfig); + this.connectionConfig = connConfig(context, parserConfig, sqlValidatorConfig); this.typeSystem = config.getTypeSystem(); reset(); } /** Gets a user-defined config and appends default connection values. */ private static CalciteConnectionConfig connConfig(Context context, - SqlParser.Config parserConfig) { + Config parserConfig, SqlValidator.Config sqlValidatorConfig) { CalciteConnectionConfigImpl config = context.maybeUnwrap(CalciteConnectionConfigImpl.class) .orElse(CalciteConnectionConfig.DEFAULT); @@ -138,6 +139,11 @@ private static CalciteConnectionConfig connConfig(Context context, config.set(CalciteConnectionProperty.CONFORMANCE, String.valueOf(parserConfig.conformance())); } + if (!config.isSet(CalciteConnectionProperty.DEFAULT_NULL_COLLATION)) { + config = + config.set(CalciteConnectionProperty.DEFAULT_NULL_COLLATION, + String.valueOf(sqlValidatorConfig.defaultNullCollation())); + } return config; } diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java index ccc422da83e9..f4129e34c691 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java @@ -35,7 +35,8 @@ class RelToSqlConverterStructsTest { private RelToSqlConverterTest.Sql sql(String sql) { return new RelToSqlConverterTest.Sql(CalciteAssert.SchemaSpec.MY_DB, sql, - CalciteSqlDialect.DEFAULT, SqlParser.Config.DEFAULT, ImmutableSet.of(), + CalciteSqlDialect.DEFAULT, CalciteSqlDialect.DEFAULT, + SqlParser.Config.DEFAULT, ImmutableSet.of(), UnaryOperator.identity(), null, ImmutableList.of()); } diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index 2648d3044617..ec52c5c8a281 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -72,6 +72,7 @@ import org.apache.calcite.sql.util.SqlShuttle; import org.apache.calcite.sql.validate.SqlConformance; import org.apache.calcite.sql.validate.SqlConformanceEnum; +import org.apache.calcite.sql.validate.SqlValidator; import org.apache.calcite.sql2rel.SqlToRelConverter; import org.apache.calcite.test.CalciteAssert; import org.apache.calcite.test.MockSqlOperatorTable; @@ -123,7 +124,8 @@ class RelToSqlConverterTest { private Sql fixture() { return new Sql(CalciteAssert.SchemaSpec.JDBC_FOODMART, "?", - CalciteSqlDialect.DEFAULT, SqlParser.Config.DEFAULT, ImmutableSet.of(), + CalciteSqlDialect.DEFAULT, CalciteSqlDialect.DEFAULT, + SqlParser.Config.DEFAULT, ImmutableSet.of(), UnaryOperator.identity(), null, ImmutableList.of()); } @@ -140,15 +142,16 @@ private Sql relFn(Function relFn) { } private static Planner getPlanner(List traitDefs, - SqlParser.Config parserConfig, SchemaPlus schema, - SqlToRelConverter.Config sqlToRelConf, Collection librarySet, - RelDataTypeSystem typeSystem, Program... programs) { + SqlParser.Config parserConfig, SqlValidator.Config validatorConfig, + SchemaPlus schema, SqlToRelConverter.Config sqlToRelConf, + Collection librarySet, RelDataTypeSystem typeSystem, Program... programs) { final FrameworkConfig config = Frameworks.newConfigBuilder() .parserConfig(parserConfig) .defaultSchema(schema) .traitDefs(traitDefs) .sqlToRelConverterConfig(sqlToRelConf) .programs(programs) + .sqlValidatorConfig(validatorConfig) .operatorTable(MockSqlOperatorTable.standard() .plus(librarySet) .extend()) @@ -559,7 +562,7 @@ private static String toSql(RelNode root, SqlDialect dialect, + "FROM `foodmart`.`product`\n" + "GROUP BY `product_class_id`, `product_id` WITH CUBE"; sql(query).withHive().ok(expected); - SqlDialect sqlDialect = sql(query).withHive().dialect; + SqlDialect sqlDialect = sql(query).withHive().targetDialect; assertTrue(sqlDialect.supportsGroupByWithCube()); } @@ -570,7 +573,7 @@ private static String toSql(RelNode root, SqlDialect dialect, + "FROM `foodmart`.`product`\n" + "GROUP BY `product_class_id`, `product_id` WITH ROLLUP"; sql(query).withHive().ok(expected); - SqlDialect sqlDialect = sql(query).withHive().dialect; + SqlDialect sqlDialect = sql(query).withHive().targetDialect; assertTrue(sqlDialect.supportsGroupByWithRollup()); } @@ -1292,6 +1295,7 @@ private static String toSql(RelNode root, SqlDialect dialect, + "FROM \"foodmart\".\"product\""; sql(query) .withRedshift() + .withSourceDialectEqualsTargetDialect() .ok(expectedRedshift); } @@ -2224,7 +2228,7 @@ private SqlDialect nonOrdinalDialect() { .ok("SELECT \"JOB\", \"ENAME\"\n" + "FROM \"scott\".\"EMP\"\n" + "ORDER BY '1', '23', '12', \"ENAME\", '34' DESC NULLS LAST") - .dialect(nonOrdinalDialect()) + .targetDialect(nonOrdinalDialect()) .ok("SELECT JOB, ENAME\n" + "FROM scott.EMP\n" + "ORDER BY 1, '23', 12, ENAME, 34 DESC NULLS LAST"); @@ -2261,9 +2265,9 @@ private SqlDialect nonOrdinalDialect() { + "ORDER BY 2"; sql(query) .ok(ordinalExpected) - .dialect(nonOrdinalDialect()) + .targetDialect(nonOrdinalDialect()) .ok(nonOrdinalExpected) - .dialect(PrestoSqlDialect.DEFAULT) + .targetDialect(PrestoSqlDialect.DEFAULT) .ok(prestoExpected); } @@ -3069,8 +3073,8 @@ private SqlDialect nonOrdinalDialect() { + "FROM [foodmart].[product]\n" + "ORDER BY CASE WHEN [product_id] IS NULL THEN 0 ELSE 1 END, [product_id] DESC"; sql(query) - .dialect(HiveSqlDialect.DEFAULT).ok(expected) - .dialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); + .targetDialect(HiveSqlDialect.DEFAULT).ok(expected) + .targetDialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); } @Test void testSelectOrderByAscNullsLast() { @@ -3084,8 +3088,8 @@ private SqlDialect nonOrdinalDialect() { + "FROM [foodmart].[product]\n" + "ORDER BY CASE WHEN [product_id] IS NULL THEN 1 ELSE 0 END, [product_id]"; sql(query) - .dialect(HiveSqlDialect.DEFAULT).ok(expected) - .dialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); + .targetDialect(HiveSqlDialect.DEFAULT).ok(expected) + .targetDialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); } @Test void testSelectOrderByAscNullsFirst() { @@ -3100,8 +3104,8 @@ private SqlDialect nonOrdinalDialect() { + "FROM [foodmart].[product]\n" + "ORDER BY [product_id]"; sql(query) - .dialect(HiveSqlDialect.DEFAULT).ok(expected) - .dialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); + .targetDialect(HiveSqlDialect.DEFAULT).ok(expected) + .targetDialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); } @Test void testSelectOrderByDescNullsLast() { @@ -3116,8 +3120,8 @@ private SqlDialect nonOrdinalDialect() { + "FROM [foodmart].[product]\n" + "ORDER BY [product_id] DESC"; sql(query) - .dialect(HiveSqlDialect.DEFAULT).ok(expectedHive) - .dialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); + .targetDialect(HiveSqlDialect.DEFAULT).ok(expectedHive) + .targetDialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); } @Test void testHiveSelectQueryWithOverDescAndNullsFirstShouldBeEmulated() { @@ -3126,7 +3130,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() " + "OVER (ORDER BY `hire_date` IS NULL DESC, `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(HiveSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(HiveSqlDialect.DEFAULT).ok(expected); } @Test void testHiveSelectQueryWithOverAscAndNullsLastShouldBeEmulated() { @@ -3134,7 +3138,7 @@ private SqlDialect nonOrdinalDialect() { + "(order by \"hire_date\" nulls last) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date` IS NULL, `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(HiveSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(HiveSqlDialect.DEFAULT).ok(expected); } @Test void testHiveSelectQueryWithOverAscNullsFirstShouldNotAddNullEmulation() { @@ -3142,7 +3146,7 @@ private SqlDialect nonOrdinalDialect() { + "(order by \"hire_date\" nulls first) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(HiveSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(HiveSqlDialect.DEFAULT).ok(expected); } @Test void testHiveSubstring() { @@ -3182,7 +3186,7 @@ private SqlDialect nonOrdinalDialect() { + "(order by \"hire_date\" desc nulls last) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(HiveSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(HiveSqlDialect.DEFAULT).ok(expected); } /** Test case for @@ -3243,8 +3247,8 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` DESC NULLS FIRST"; - sql(query).dialect(hive2_1Dialect).ok(expected); - sql(query).dialect(hive2_2_Dialect).ok(expected); + sql(query).targetDialect(hive2_1Dialect).ok(expected); + sql(query).targetDialect(hive2_2_Dialect).ok(expected); } @Test void testHiveSelectQueryWithOverDescAndHighNullsWithVersionGreaterThanOrEq21() { @@ -3264,8 +3268,8 @@ private SqlDialect nonOrdinalDialect() { + "(order by \"hire_date\" desc nulls first) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY hire_date DESC NULLS FIRST)\n" + "FROM foodmart.employee"; - sql(query).dialect(hive2_1Dialect).ok(expected); - sql(query).dialect(hive2_2_Dialect).ok(expected); + sql(query).targetDialect(hive2_1Dialect).ok(expected); + sql(query).targetDialect(hive2_2_Dialect).ok(expected); } @Test void testHiveSelectQueryWithOrderByDescAndHighNullsWithVersion20() { @@ -3279,7 +3283,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL DESC, `product_id` DESC"; - sql(query).dialect(hive2_1_0_Dialect).ok(expected); + sql(query).targetDialect(hive2_1_0_Dialect).ok(expected); } @Test void testHiveSelectQueryWithOverDescAndHighNullsWithVersion20() { @@ -3293,7 +3297,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() OVER " + "(ORDER BY hire_date IS NULL DESC, hire_date DESC)\n" + "FROM foodmart.employee"; - sql(query).dialect(hive2_1_0_Dialect).ok(expected); + sql(query).targetDialect(hive2_1_0_Dialect).ok(expected); } @Test void testJethroDataSelectQueryWithOrderByDescAndNullsFirstShouldBeEmulated() { @@ -3303,7 +3307,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT \"product_id\"\n" + "FROM \"foodmart\".\"product\"\n" + "ORDER BY \"product_id\", \"product_id\" DESC"; - sql(query).dialect(jethroDataSqlDialect()).ok(expected); + sql(query).targetDialect(jethroDataSqlDialect()).ok(expected); } @Test void testJethroDataSelectQueryWithOverDescAndNullsFirstShouldBeEmulated() { @@ -3313,7 +3317,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() OVER " + "(ORDER BY \"hire_date\", \"hire_date\" DESC)\n" + "FROM \"foodmart\".\"employee\""; - sql(query).dialect(jethroDataSqlDialect()).ok(expected); + sql(query).targetDialect(jethroDataSqlDialect()).ok(expected); } @Test void testMySqlSelectQueryWithOrderByDescAndNullsFirstShouldBeEmulated() { @@ -3322,7 +3326,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL DESC, `product_id` DESC"; - sql(query).dialect(MysqlSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(MysqlSqlDialect.DEFAULT).ok(expected); } @Test void testMySqlSelectQueryWithOverDescAndNullsFirstShouldBeEmulated() { @@ -3331,7 +3335,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() OVER " + "(ORDER BY `hire_date` IS NULL DESC, `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(MysqlSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(MysqlSqlDialect.DEFAULT).ok(expected); } @Test void testMySqlSelectQueryWithOrderByAscAndNullsLastShouldBeEmulated() { @@ -3340,7 +3344,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL, `product_id`"; - sql(query).dialect(MysqlSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(MysqlSqlDialect.DEFAULT).ok(expected); } @Test void testMySqlSelectQueryWithOverAscAndNullsLastShouldBeEmulated() { @@ -3349,7 +3353,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() OVER " + "(ORDER BY `hire_date` IS NULL, `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(MysqlSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(MysqlSqlDialect.DEFAULT).ok(expected); } @Test void testMySqlSelectQueryWithOrderByAscNullsFirstShouldNotAddNullEmulation() { @@ -3358,7 +3362,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id`"; - sql(query).dialect(MysqlSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(MysqlSqlDialect.DEFAULT).ok(expected); } @Test void testMySqlSelectQueryWithOverAscNullsFirstShouldNotAddNullEmulation() { @@ -3366,7 +3370,7 @@ private SqlDialect nonOrdinalDialect() { + "over (order by \"hire_date\" nulls first) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(MysqlSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(MysqlSqlDialect.DEFAULT).ok(expected); } @Test void testMySqlSelectQueryWithOrderByDescNullsLastShouldNotAddNullEmulation() { @@ -3375,7 +3379,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` DESC"; - sql(query).dialect(MysqlSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(MysqlSqlDialect.DEFAULT).ok(expected); } @Test void testMySqlSelectQueryWithOverDescNullsLastShouldNotAddNullEmulation() { @@ -3383,7 +3387,7 @@ private SqlDialect nonOrdinalDialect() { + "over (order by \"hire_date\" desc nulls last) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(MysqlSqlDialect.DEFAULT).ok(expected); + sql(query).targetDialect(MysqlSqlDialect.DEFAULT).ok(expected); } @Test void testMySqlCastToVarcharWithLessThanMaxPrecision() { @@ -3442,7 +3446,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id`"; - sql(query).dialect(mySqlDialect(NullCollation.HIGH)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.HIGH)).ok(expected); } @Test void testMySqlWithHighNullsSelectWithOverAscNullsLastAndNoEmulation() { @@ -3450,7 +3454,7 @@ private SqlDialect nonOrdinalDialect() { + "over (order by \"hire_date\" nulls last) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.HIGH)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.HIGH)).ok(expected); } @Test void testMySqlWithHighNullsSelectWithOrderByAscNullsFirstAndNullEmulation() { @@ -3459,7 +3463,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL DESC, `product_id`"; - sql(query).dialect(mySqlDialect(NullCollation.HIGH)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.HIGH)).ok(expected); } @Test void testMySqlWithHighNullsSelectWithOverAscNullsFirstAndNullEmulation() { @@ -3468,7 +3472,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() " + "OVER (ORDER BY `hire_date` IS NULL DESC, `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.HIGH)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.HIGH)).ok(expected); } @Test void testMySqlWithHighNullsSelectWithOrderByDescNullsFirstAndNoEmulation() { @@ -3477,7 +3481,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` DESC"; - sql(query).dialect(mySqlDialect(NullCollation.HIGH)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.HIGH)).ok(expected); } @Test void testMySqlWithHighNullsSelectWithOverDescNullsFirstAndNoEmulation() { @@ -3485,7 +3489,7 @@ private SqlDialect nonOrdinalDialect() { + "over (order by \"hire_date\" desc nulls first) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.HIGH)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.HIGH)).ok(expected); } @Test void testMySqlWithHighNullsSelectWithOrderByDescNullsLastAndNullEmulation() { @@ -3494,7 +3498,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL, `product_id` DESC"; - sql(query).dialect(mySqlDialect(NullCollation.HIGH)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.HIGH)).ok(expected); } @Test void testMySqlWithHighNullsSelectWithOverDescNullsLastAndNullEmulation() { @@ -3503,7 +3507,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() " + "OVER (ORDER BY `hire_date` IS NULL, `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.HIGH)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.HIGH)).ok(expected); } @Test void testMySqlWithFirstNullsSelectWithOrderByDescAndNullsFirstShouldNotBeEmulated() { @@ -3512,7 +3516,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` DESC"; - sql(query).dialect(mySqlDialect(NullCollation.FIRST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.FIRST)).ok(expected); } @Test void testMySqlWithFirstNullsSelectWithOverDescAndNullsFirstShouldNotBeEmulated() { @@ -3520,7 +3524,7 @@ private SqlDialect nonOrdinalDialect() { + "over (order by \"hire_date\" desc nulls first) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.FIRST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.FIRST)).ok(expected); } @Test void testMySqlWithFirstNullsSelectWithOrderByAscAndNullsFirstShouldNotBeEmulated() { @@ -3529,7 +3533,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id`"; - sql(query).dialect(mySqlDialect(NullCollation.FIRST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.FIRST)).ok(expected); } @Test void testMySqlWithFirstNullsSelectWithOverAscAndNullsFirstShouldNotBeEmulated() { @@ -3537,7 +3541,7 @@ private SqlDialect nonOrdinalDialect() { + "over (order by \"hire_date\" nulls first) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.FIRST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.FIRST)).ok(expected); } @Test void testMySqlWithFirstNullsSelectWithOrderByDescAndNullsLastShouldBeEmulated() { @@ -3546,7 +3550,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL, `product_id` DESC"; - sql(query).dialect(mySqlDialect(NullCollation.FIRST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.FIRST)).ok(expected); } @Test void testMySqlWithFirstNullsSelectWithOverDescAndNullsLastShouldBeEmulated() { @@ -3555,7 +3559,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() " + "OVER (ORDER BY `hire_date` IS NULL, `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.FIRST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.FIRST)).ok(expected); } @Test void testMySqlWithFirstNullsSelectWithOrderByAscAndNullsLastShouldBeEmulated() { @@ -3564,7 +3568,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL, `product_id`"; - sql(query).dialect(mySqlDialect(NullCollation.FIRST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.FIRST)).ok(expected); } @Test void testMySqlWithFirstNullsSelectWithOverAscAndNullsLastShouldBeEmulated() { @@ -3573,7 +3577,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() " + "OVER (ORDER BY `hire_date` IS NULL, `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.FIRST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.FIRST)).ok(expected); } @Test void testMySqlWithLastNullsSelectWithOrderByDescAndNullsFirstShouldBeEmulated() { @@ -3582,7 +3586,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL DESC, `product_id` DESC"; - sql(query).dialect(mySqlDialect(NullCollation.LAST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.LAST)).ok(expected); } @Test void testMySqlWithLastNullsSelectWithOverDescAndNullsFirstShouldBeEmulated() { @@ -3591,7 +3595,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() " + "OVER (ORDER BY `hire_date` IS NULL DESC, `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.LAST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.LAST)).ok(expected); } @Test void testMySqlWithLastNullsSelectWithOrderByAscAndNullsFirstShouldBeEmulated() { @@ -3600,7 +3604,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` IS NULL DESC, `product_id`"; - sql(query).dialect(mySqlDialect(NullCollation.LAST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.LAST)).ok(expected); } @Test void testMySqlWithLastNullsSelectWithOverAscAndNullsFirstShouldBeEmulated() { @@ -3609,7 +3613,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT ROW_NUMBER() " + "OVER (ORDER BY `hire_date` IS NULL DESC, `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.LAST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.LAST)).ok(expected); } @Test void testMySqlWithLastNullsSelectWithOrderByDescAndNullsLastShouldNotBeEmulated() { @@ -3618,7 +3622,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id` DESC"; - sql(query).dialect(mySqlDialect(NullCollation.LAST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.LAST)).ok(expected); } @Test void testMySqlWithLastNullsSelectWithOverDescAndNullsLastShouldNotBeEmulated() { @@ -3626,7 +3630,7 @@ private SqlDialect nonOrdinalDialect() { + "over (order by \"hire_date\" desc nulls last) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date` DESC)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.LAST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.LAST)).ok(expected); } @Test void testMySqlWithLastNullsSelectWithOrderByAscAndNullsLastShouldNotBeEmulated() { @@ -3635,7 +3639,7 @@ private SqlDialect nonOrdinalDialect() { final String expected = "SELECT `product_id`\n" + "FROM `foodmart`.`product`\n" + "ORDER BY `product_id`"; - sql(query).dialect(mySqlDialect(NullCollation.LAST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.LAST)).ok(expected); } @Test void testMySqlWithLastNullsSelectWithOverAscAndNullsLastShouldNotBeEmulated() { @@ -3643,7 +3647,7 @@ private SqlDialect nonOrdinalDialect() { + "(order by \"hire_date\" nulls last) FROM \"employee\""; final String expected = "SELECT ROW_NUMBER() OVER (ORDER BY `hire_date`)\n" + "FROM `foodmart`.`employee`"; - sql(query).dialect(mySqlDialect(NullCollation.LAST)).ok(expected); + sql(query).targetDialect(mySqlDialect(NullCollation.LAST)).ok(expected); } /** Test case for @@ -3691,10 +3695,10 @@ private SqlDialect nonOrdinalDialect() { final String expectedSpark = "SELECT CAST(`product_id` AS CHAR(1))\n" + "FROM `foodmart`.`product`"; sql(query) - .withMysql().ok(expectedMysql) - .withMssql().ok(expectedMssql) - .withHive().ok(expectedHive) - .withSpark().ok(expectedSpark); + .withMysql().withSourceDialectEqualsTargetDialect().ok(expectedMysql) + .withMssql().withSourceDialectEqualsTargetDialect().ok(expectedMssql) + .withHive().withSourceDialectEqualsTargetDialect().ok(expectedHive) + .withSpark().withSourceDialectEqualsTargetDialect().ok(expectedSpark); } @Test void testCastToCharWithPrecision() { @@ -5495,6 +5499,7 @@ private void checkLiteral2(String expression, String expected) { final String expected = "SELECT MOD(2.00000000000000000000, 2)\nFROM (VALUES (0)) AS \"t\" (\"ZERO\")"; sql(sql).withPostgresqlModifiedDecimalTypeSystem() + .withSourceDialectEqualsTargetDialect() .ok(expected); } @@ -5507,7 +5512,9 @@ private void checkLiteral2(String expression, String expected) { + "DECIMAL(39, 10)) + CAST(\"t0\".\"EXPR$0\" AS " + "DECIMAL(39, 10))\nFROM (VALUES ('4.2')) AS " + "\"t\" (\"EXPR$0\"),\n(VALUES ('4.2')) AS \"t0\" (\"EXPR$0\")"; - sql(sql).withPostgresqlModifiedDecimalTypeSystem() + sql(sql) + .withPostgresqlModifiedDecimalTypeSystem() + .withSourceDialectEqualsTargetDialect() .ok(expected); } @@ -6554,16 +6561,16 @@ private void checkLiteral2(String expression, String expected) { + "FROM (SELECT 1 AS \"a\", 'x ' AS \"b\"\n" + "UNION ALL\nSELECT 2 AS \"a\", 'yy' AS \"b\")"; sql(sql) - .withClickHouse().ok(expectedClickHouse) - .withFirebolt().ok(expectedFirebolt) - .withBigQuery().ok(expectedBigQuery) - .withHive().ok(expectedHive) - .withHsqldb().ok(expectedHsqldb) - .withMysql().ok(expectedMysql) - .withOracle().ok(expectedOracle) - .withPostgresql().ok(expectedPostgresql) - .withRedshift().ok(expectedRedshift) - .withSnowflake().ok(expectedSnowflake); + .withClickHouse().withSourceDialectEqualsTargetDialect().ok(expectedClickHouse) + .withFirebolt().withSourceDialectEqualsTargetDialect().ok(expectedFirebolt) + .withBigQuery().withSourceDialectEqualsTargetDialect().ok(expectedBigQuery) + .withHive().withSourceDialectEqualsTargetDialect().ok(expectedHive) + .withHsqldb().withSourceDialectEqualsTargetDialect().ok(expectedHsqldb) + .withMysql().withSourceDialectEqualsTargetDialect().ok(expectedMysql) + .withOracle().withSourceDialectEqualsTargetDialect().ok(expectedOracle) + .withPostgresql().withSourceDialectEqualsTargetDialect().ok(expectedPostgresql) + .withRedshift().withSourceDialectEqualsTargetDialect().ok(expectedRedshift) + .withSnowflake().withSourceDialectEqualsTargetDialect().ok(expectedSnowflake); } /** @@ -6785,7 +6792,7 @@ private void checkLiteral2(String expression, String expected) { super.unparseCall(writer, call, leftPrec, rightPrec); } }; - sql(query).dialect(dialect).ok(expected); + sql(query).targetDialect(dialect).ok(expected); assertThat("Dialect must be able to customize unparseCall() for SqlSelect", callsUnparseCallOnSqlSelect[0], is(true)); @@ -8738,7 +8745,7 @@ private void checkLiteral2(String expression, String expected) { final String mssqlExpected = "SELECT 1.24, FLOOR(1.24), CEILING(1.24)\n" + "FROM (VALUES (0)) AS [t] ([ZERO])"; sql(query) - .dialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); + .targetDialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected); } /** Test case for @@ -8787,69 +8794,83 @@ private void checkLiteral2(String expression, String expected) { static class Sql { private final CalciteAssert.SchemaSpec schemaSpec; private final String sql; - private final SqlDialect dialect; + // The dialect of the source sql + private final SqlDialect sourceDialect; + + // The dialect of the target sql + private final SqlDialect targetDialect; private final Set librarySet; private final @Nullable Function relFn; private final List> transforms; private final SqlParser.Config parserConfig; + private final SqlValidator.Config validatorConfig; private final UnaryOperator config; - Sql(CalciteAssert.SchemaSpec schemaSpec, String sql, SqlDialect dialect, + Sql(CalciteAssert.SchemaSpec schemaSpec, String sql, + SqlDialect sourceDialect, SqlDialect targetDialect, SqlParser.Config parserConfig, Set librarySet, UnaryOperator config, @Nullable Function relFn, List> transforms) { this.schemaSpec = schemaSpec; this.sql = sql; - this.dialect = dialect; + this.sourceDialect = sourceDialect; + this.targetDialect = targetDialect; this.librarySet = librarySet; this.relFn = relFn; this.transforms = ImmutableList.copyOf(transforms); this.parserConfig = parserConfig; + this.validatorConfig = SqlValidator.Config.DEFAULT + .withDefaultNullCollation(sourceDialect.getNullCollation()); this.config = config; } Sql withSql(String sql) { - return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, config, + return new Sql(schemaSpec, sql, sourceDialect, targetDialect, parserConfig, librarySet, config, relFn, transforms); } - Sql dialect(SqlDialect dialect) { - return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, config, + Sql sourceDialect(SqlDialect dialect) { + return new Sql(schemaSpec, sql, dialect, targetDialect, parserConfig, librarySet, config, relFn, transforms); } - Sql relFn(Function relFn) { - return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, config, + Sql targetDialect(SqlDialect dialect) { + return new Sql(schemaSpec, sql, sourceDialect, dialect, parserConfig, librarySet, config, relFn, transforms); } + Sql relFn(Function relFn) { + return new Sql(schemaSpec, sql, sourceDialect, targetDialect, parserConfig, + librarySet, config, relFn, transforms); + } + Sql withCalcite() { - return dialect(DatabaseProduct.CALCITE.getDialect()); + return targetDialect(DatabaseProduct.CALCITE.getDialect()); } Sql withClickHouse() { - return dialect(DatabaseProduct.CLICKHOUSE.getDialect()); + return targetDialect(DatabaseProduct.CLICKHOUSE.getDialect()); } Sql withDb2() { - return dialect(DatabaseProduct.DB2.getDialect()); + return targetDialect(DatabaseProduct.DB2.getDialect()); } Sql withExasol() { - return dialect(DatabaseProduct.EXASOL.getDialect()); + return targetDialect(DatabaseProduct.EXASOL.getDialect()); } Sql withFirebolt() { - return dialect(DatabaseProduct.FIREBOLT.getDialect()); + return targetDialect(DatabaseProduct.FIREBOLT.getDialect()); } Sql withHive() { - return dialect(DatabaseProduct.HIVE.getDialect()); + return targetDialect(DatabaseProduct.HIVE.getDialect()); } Sql withHsqldb() { - return dialect(DatabaseProduct.HSQLDB.getDialect()); + return targetDialect(DatabaseProduct.HSQLDB.getDialect()); } Sql withMssql() { @@ -8858,7 +8879,7 @@ Sql withMssql() { Sql withMssql(int majorVersion) { final SqlDialect mssqlDialect = DatabaseProduct.MSSQL.getDialect(); - return dialect( + return targetDialect( new MssqlSqlDialect(MssqlSqlDialect.DEFAULT_CONTEXT .withDatabaseMajorVersion(majorVersion) .withIdentifierQuoteString(mssqlDialect.quoteIdentifier("") @@ -8867,12 +8888,12 @@ Sql withMssql(int majorVersion) { } Sql withMysql() { - return dialect(DatabaseProduct.MYSQL.getDialect()); + return targetDialect(DatabaseProduct.MYSQL.getDialect()); } Sql withMysql8() { final SqlDialect mysqlDialect = DatabaseProduct.MYSQL.getDialect(); - return dialect( + return targetDialect( new SqlDialect(MysqlSqlDialect.DEFAULT_CONTEXT .withDatabaseMajorVersion(8) .withIdentifierQuoteString(mysqlDialect.quoteIdentifier("") @@ -8886,7 +8907,7 @@ Sql withOracle() { Sql withOracle(int majorVersion) { final SqlDialect oracleDialect = DatabaseProduct.ORACLE.getDialect(); - return dialect( + return targetDialect( new OracleSqlDialect(OracleSqlDialect.DEFAULT_CONTEXT .withDatabaseProduct(DatabaseProduct.ORACLE) .withDatabaseMajorVersion(majorVersion) @@ -8896,43 +8917,43 @@ Sql withOracle(int majorVersion) { } Sql withPostgresql() { - return dialect(DatabaseProduct.POSTGRESQL.getDialect()); + return targetDialect(DatabaseProduct.POSTGRESQL.getDialect()); } Sql withPresto() { - return dialect(DatabaseProduct.PRESTO.getDialect()); + return targetDialect(DatabaseProduct.PRESTO.getDialect()); } Sql withRedshift() { - return dialect(DatabaseProduct.REDSHIFT.getDialect()); + return targetDialect(DatabaseProduct.REDSHIFT.getDialect()); } Sql withInformix() { - return dialect(DatabaseProduct.INFORMIX.getDialect()); + return targetDialect(DatabaseProduct.INFORMIX.getDialect()); } Sql withSnowflake() { - return dialect(DatabaseProduct.SNOWFLAKE.getDialect()); + return targetDialect(DatabaseProduct.SNOWFLAKE.getDialect()); } Sql withSybase() { - return dialect(DatabaseProduct.SYBASE.getDialect()); + return targetDialect(DatabaseProduct.SYBASE.getDialect()); } Sql withVertica() { - return dialect(DatabaseProduct.VERTICA.getDialect()); + return targetDialect(DatabaseProduct.VERTICA.getDialect()); } Sql withBigQuery() { - return dialect(DatabaseProduct.BIG_QUERY.getDialect()); + return targetDialect(DatabaseProduct.BIG_QUERY.getDialect()); } Sql withSpark() { - return dialect(DatabaseProduct.SPARK.getDialect()); + return targetDialect(DatabaseProduct.SPARK.getDialect()); } Sql withStarRocks() { - return dialect(DatabaseProduct.STARROCKS.getDialect()); + return targetDialect(DatabaseProduct.STARROCKS.getDialect()); } Sql withPostgresqlModifiedTypeSystem() { @@ -8949,7 +8970,7 @@ Sql withPostgresqlModifiedTypeSystem() { } } })); - return dialect(postgresqlSqlDialect); + return targetDialect(postgresqlSqlDialect); } Sql withPostgresqlModifiedDecimalTypeSystem() { @@ -8983,7 +9004,11 @@ Sql withPostgresqlModifiedDecimalTypeSystem() { } } })); - return dialect(postgresqlSqlDialect); + return targetDialect(postgresqlSqlDialect); + } + + Sql withSourceDialectEqualsTargetDialect() { + return sourceDialect(this.targetDialect); } Sql withOracleModifiedTypeSystem() { @@ -9000,17 +9025,17 @@ Sql withOracleModifiedTypeSystem() { } } })); - return dialect(oracleSqlDialect); + return targetDialect(oracleSqlDialect); } Sql parserConfig(SqlParser.Config parserConfig) { - return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, config, - relFn, transforms); + return new Sql(schemaSpec, sql, sourceDialect, targetDialect, parserConfig, + librarySet, config, relFn, transforms); } Sql withConfig(UnaryOperator config) { - return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, config, - relFn, transforms); + return new Sql(schemaSpec, sql, sourceDialect, targetDialect, parserConfig, + librarySet, config, relFn, transforms); } final Sql withLibrary(SqlLibrary library) { @@ -9018,7 +9043,7 @@ final Sql withLibrary(SqlLibrary library) { } Sql withLibrarySet(Iterable librarySet) { - return new Sql(schemaSpec, sql, dialect, parserConfig, + return new Sql(schemaSpec, sql, sourceDialect, targetDialect, parserConfig, ImmutableSet.copyOf(librarySet), config, relFn, transforms); } @@ -9035,8 +9060,8 @@ Sql optimize(final RuleSet ruleSet, return program.run(p, r, r.getTraitSet(), ImmutableList.of(), ImmutableList.of()); }); - return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, config, - relFn, transforms); + return new Sql(schemaSpec, sql, sourceDialect, targetDialect, parserConfig, + librarySet, config, relFn, transforms); } Sql ok(String expectedQuery) { @@ -9070,9 +9095,10 @@ String exec() { } else { final SqlToRelConverter.Config config = this.config.apply(SqlToRelConverter.config() .withTrimUnusedFields(false)); - RelDataTypeSystem typeSystem = dialect.getTypeSystem(); + RelDataTypeSystem typeSystem = sourceDialect.getTypeSystem(); final Planner planner = - getPlanner(null, parserConfig, defaultSchema, config, librarySet, typeSystem); + getPlanner(null, parserConfig, validatorConfig, defaultSchema, + config, librarySet, typeSystem); SqlNode parse = planner.parse(sql); SqlNode validate = planner.validate(parse); rel = planner.rel(validate).project(); @@ -9080,15 +9106,15 @@ String exec() { for (Function transform : transforms) { rel = transform.apply(rel); } - return toSql(rel, dialect); + return toSql(rel, targetDialect); } catch (Exception e) { throw TestUtil.rethrow(e); } } public Sql schema(CalciteAssert.SchemaSpec schemaSpec) { - return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, config, - relFn, transforms); + return new Sql(schemaSpec, sql, sourceDialect, targetDialect, parserConfig, + librarySet, config, relFn, transforms); } } }