diff --git a/babel/src/test/java/org/apache/calcite/test/BabelQuidemTest.java b/babel/src/test/java/org/apache/calcite/test/BabelQuidemTest.java index 543bfc000719..66978b4fc1c3 100644 --- a/babel/src/test/java/org/apache/calcite/test/BabelQuidemTest.java +++ b/babel/src/test/java/org/apache/calcite/test/BabelQuidemTest.java @@ -24,6 +24,7 @@ import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlWriter; +import org.apache.calcite.sql.dialect.BigQuerySqlDialect; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.babel.SqlBabelParserImpl; import org.apache.calcite.sql.pretty.SqlPrettyWriter; @@ -116,6 +117,8 @@ public static void main(String[] args) throws Exception { .with(CalciteConnectionProperty.CONFORMANCE, SqlConformanceEnum.BABEL) .with(CalciteConnectionProperty.LENIENT_OPERATOR_LOOKUP, true) + .with(CalciteConnectionProperty.TYPE_SYSTEM, + BigQuerySqlDialect.class.getName() + "#TYPE_SYSTEM") .with( ConnectionFactories.addType("DATETIME", typeFactory -> typeFactory.createSqlType(SqlTypeName.TIMESTAMP))) diff --git a/babel/src/test/resources/sql/big-query.iq b/babel/src/test/resources/sql/big-query.iq index a158bd16eed0..888f61afdd60 100755 --- a/babel/src/test/resources/sql/big-query.iq +++ b/babel/src/test/resources/sql/big-query.iq @@ -1034,9 +1034,9 @@ FROM SELECT email, - REGEXP_CONTAINS(email, '^([\w.+-]+@foo\.com|[\w.+-]+@bar\.org)\s+$') + REGEXP_CONTAINS(email, '^([\w.+-]+@foo\.com|[\w.+-]+@bar\.org)\s*$') AS valid_email_address, - REGEXP_CONTAINS(email, '^[\w.+-]+@foo\.com|[\w.+-]+@bar\.org\s+$') + REGEXP_CONTAINS(email, '^[\w.+-]+@foo\.com|[\w.+-]+@bar\.org\s*$') AS without_parentheses FROM (SELECT @@ -1046,11 +1046,11 @@ FROM +----------------+---------------------+---------------------+ | email | valid_email_address | without_parentheses | +----------------+---------------------+---------------------+ -| a@foo.com | true | true | | a@foo.computer | false | true | -| b@bar.org | true | true | -| !b@bar.org | false | true | | c@buz.net | false | false | +| !b@bar.org | false | true | +| a@foo.com | true | true | +| b@bar.org | true | true | +----------------+---------------------+---------------------+ (5 rows) @@ -2133,13 +2133,13 @@ WITH Recipes AS SELECT 'Ham scramble', 'Steak avocado salad', 'Tomato pasta' UNION ALL SELECT 'Avocado toast', 'Tomato soup', 'Blueberry salmon' UNION ALL SELECT 'Corned beef hash', 'Lentil potato soup', 'Glazed ham') -SELECT * FROM Recipes WHERE CONTAINS_SUBSTR((Lunch, Dinner), 'potato'); -+--------------------+-------------------------+------------------+ -| Breakfast | Lunch | Dinner | -+--------------------+-------------------------+------------------+ -| Blueberry pancakes | Egg salad sandwich | Potato dumplings | -| Corned beef hash | Lentil potato soup | Glazed ham | -+--------------------+-------------------------+------------------+ +SELECT *, LENGTH(lunch) AS LEN FROM Recipes WHERE CONTAINS_SUBSTR((Lunch, Dinner), 'potato'); ++--------------------+--------------------+------------------+-----+ +| Breakfast | Lunch | Dinner | LEN | ++--------------------+--------------------+------------------+-----+ +| Blueberry pancakes | Egg salad sandwich | Potato dumplings | 18 | +| Corned beef hash | Lentil potato soup | Glazed ham | 18 | ++--------------------+--------------------+------------------+-----+ (2 rows) !ok diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java index aedee052276a..206da0307b53 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java @@ -553,9 +553,12 @@ private static Expression checkExpressionPadTruncate( <= 0) { truncate = false; } - // If this is a widening cast, no need to pad. - if (SqlTypeUtil.comparePrecision(sourcePrecision, targetPrecision) - >= 0) { + // If this is a narrowing cast, no need to pad. + // However, conversion from VARCHAR(N) to CHAR(N) still requires padding, + // because VARCHAR(N) does not represent the spaces explicitly, + // whereas CHAR(N) does. + if ((SqlTypeUtil.comparePrecision(sourcePrecision, targetPrecision) >= 0) + && (sourceType.getSqlTypeName() != SqlTypeName.VARCHAR)) { pad = false; } // fall through diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java index 2368040cc4af..6f3c1dec8cfe 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java @@ -20,6 +20,7 @@ import org.apache.calcite.avatica.util.TimeUnit; import org.apache.calcite.config.Lex; import org.apache.calcite.config.NullCollation; +import org.apache.calcite.rel.type.DelegatingTypeSystem; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeSystem; import org.apache.calcite.rex.RexCall; @@ -76,6 +77,15 @@ public class BigQuerySqlDialect extends SqlDialect { public static final SqlDialect DEFAULT = new BigQuerySqlDialect(DEFAULT_CONTEXT); + // The BigQuery type system differs from the DEFAULT type system in this respect, + // as evidenced by tests in big-query.iq + public static final RelDataTypeSystem TYPE_SYSTEM = + new DelegatingTypeSystem(RelDataTypeSystem.DEFAULT) { + @Override public boolean shouldConvertRaggedUnionTypesToVarying() { + return true; + } + }; + private static final List RESERVED_KEYWORDS = ImmutableList.copyOf( Arrays.asList("ALL", "AND", "ANY", "ARRAY", "AS", "ASC", @@ -115,6 +125,10 @@ public BigQuerySqlDialect(SqlDialect.Context context) { && !SqlTypeUtil.isNumeric(call.type); } + @Override public RelDataTypeSystem getTypeSystem() { + return TYPE_SYSTEM; + } + @Override public boolean supportsApproxCountDistinct() { return true; } diff --git a/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java index 4bd50d05980c..638216554f4d 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java @@ -110,19 +110,20 @@ public class SetopOperandTypeChecker implements SqlOperandTypeChecker { final RelDataType type = callBinding.getTypeFactory().leastRestrictive(columnIthTypes); - if (type == null) { - boolean coerced = false; - if (callBinding.isTypeCoercionEnabled()) { - for (int j = 0; j < callBinding.getOperandCount(); j++) { - TypeCoercion typeCoercion = validator.getTypeCoercion(); - RelDataType widenType = typeCoercion.getWiderTypeFor(columnIthTypes, true); - if (null != widenType) { - coerced = - typeCoercion.rowTypeCoercion(callBinding.getScope(), - callBinding.operand(j), i, widenType) || coerced; - } + // If any of the types is different we need to insert a coercion. + boolean coerced = false; + if (callBinding.isTypeCoercionEnabled()) { + for (int j = 0; j < callBinding.getOperandCount(); j++) { + TypeCoercion typeCoercion = validator.getTypeCoercion(); + RelDataType widenType = typeCoercion.getWiderTypeFor(columnIthTypes, true); + if (null != widenType) { + coerced = + typeCoercion.rowTypeCoercion(callBinding.getScope(), + callBinding.operand(j), i, widenType) || coerced; } } + } + if (type == null) { if (!coerced) { if (throwOnFailure) { SqlNode field = diff --git a/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java b/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java index 6d8d6f04156f..db8679285c09 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java @@ -274,9 +274,10 @@ protected boolean needToCast(SqlValidatorScope scope, SqlNode node, return false; } - // No need to cast between char and varchar. + // No need to cast between char and unlimited varchar. if (SqlTypeUtil.isCharacter(toType) - && SqlTypeUtil.isCharacter(fromType)) { + && SqlTypeUtil.isCharacter(fromType) + && toType.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED) { return false; } 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 f291bc4346c0..2648d3044617 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 @@ -4395,7 +4395,7 @@ private SqlDialect nonOrdinalDialect() { + "FROM (SELECT \"product_id\", \"net_weight\"\n" + "FROM \"foodmart\".\"product\"\n" + "UNION ALL\n" - + "SELECT \"product_id\", 0 AS \"net_weight\"\n" + + "SELECT \"product_id\", 0E0 AS \"net_weight\"\n" + "FROM \"foodmart\".\"sales_fact_1997\") AS \"t1\""; sql(query).ok(expected); } @@ -6545,7 +6545,7 @@ private void checkLiteral2(String expression, String expected) { + "UNION ALL\n" + "SELECT 2 `a`, 'yy' `b`) `t`"; final String expectedBigQuery = "SELECT a\n" - + "FROM (SELECT 1 AS a, 'x ' AS b\n" + + "FROM (SELECT 1 AS a, 'x' AS b\n" + "UNION ALL\n" + "SELECT 2 AS a, 'yy' AS b)"; final String expectedFirebolt = expectedPostgresql; @@ -7658,9 +7658,9 @@ private void checkLiteral2(String expression, String expected) { + "SELECT \"product\".\"product_id\" AS \"account_id\", " + "CAST(NULL AS INTEGER) AS \"account_parent\", CAST(NULL AS VARCHAR" + "(30) CHARACTER SET \"ISO-8859-1\") AS \"account_description\", " - + "CAST(\"product\".\"product_id\" AS VARCHAR CHARACTER SET " + + "CAST(\"product\".\"product_id\" AS VARCHAR(30) CHARACTER SET " + "\"ISO-8859-1\") AS \"account_type\", " - + "CAST(\"sales_fact_1997\".\"store_id\" AS VARCHAR CHARACTER SET \"ISO-8859-1\") AS " + + "CAST(\"sales_fact_1997\".\"store_id\" AS VARCHAR(30) CHARACTER SET \"ISO-8859-1\") AS " + "\"account_rollup\", " + "CAST(NULL AS VARCHAR(255) CHARACTER SET \"ISO-8859-1\") AS \"Custom_Members\"\n" + "FROM \"foodmart\".\"product\"\n" @@ -7777,7 +7777,7 @@ private void checkLiteral2(String expression, String expected) { final String expectedDefault = "INSERT INTO \"SCOTT\".\"DEPT\"" + " (\"DEPTNO\", \"DNAME\", \"LOC\")\n" + "VALUES (1, 'Fred', 'San Francisco'),\n" - + "(2, 'Eric', 'Washington ')"; + + "(2, 'Eric', 'Washington')"; final String expectedDefaultX = "INSERT INTO \"SCOTT\".\"DEPT\"" + " (\"DEPTNO\", \"DNAME\", \"LOC\")\n" + "SELECT 1, 'Fred', 'San Francisco'\n" @@ -7787,7 +7787,7 @@ private void checkLiteral2(String expression, String expected) { + "FROM (VALUES (0)) AS \"t\" (\"ZERO\")"; final String expectedHive = "INSERT INTO `SCOTT`.`DEPT` (`DEPTNO`, `DNAME`, `LOC`)\n" + "VALUES (1, 'Fred', 'San Francisco'),\n" - + "(2, 'Eric', 'Washington ')"; + + "(2, 'Eric', 'Washington')"; final String expectedHiveX = "INSERT INTO `SCOTT`.`DEPT` (`DEPTNO`, `DNAME`, `LOC`)\n" + "SELECT 1, 'Fred', 'San Francisco'\n" + "UNION ALL\n" @@ -7795,7 +7795,7 @@ private void checkLiteral2(String expression, String expected) { final String expectedMysql = "INSERT INTO `SCOTT`.`DEPT`" + " (`DEPTNO`, `DNAME`, `LOC`)\n" + "VALUES (1, 'Fred', 'San Francisco'),\n" - + "(2, 'Eric', 'Washington ')"; + + "(2, 'Eric', 'Washington')"; final String expectedMysqlX = "INSERT INTO `SCOTT`.`DEPT`" + " (`DEPTNO`, `DNAME`, `LOC`)\n" + "SELECT 1, 'Fred', 'San Francisco'\n" @@ -7804,7 +7804,7 @@ private void checkLiteral2(String expression, String expected) { final String expectedOracle = "INSERT INTO \"SCOTT\".\"DEPT\"" + " (\"DEPTNO\", \"DNAME\", \"LOC\")\n" + "VALUES (1, 'Fred', 'San Francisco'),\n" - + "(2, 'Eric', 'Washington ')"; + + "(2, 'Eric', 'Washington')"; final String expectedOracleX = "INSERT INTO \"SCOTT\".\"DEPT\"" + " (\"DEPTNO\", \"DNAME\", \"LOC\")\n" + "SELECT 1, 'Fred', 'San Francisco'\n" @@ -7815,7 +7815,7 @@ private void checkLiteral2(String expression, String expected) { final String expectedMssql = "INSERT INTO [SCOTT].[DEPT]" + " ([DEPTNO], [DNAME], [LOC])\n" + "VALUES (1, 'Fred', 'San Francisco'),\n" - + "(2, 'Eric', 'Washington ')"; + + "(2, 'Eric', 'Washington')"; final String expectedMssqlX = "INSERT INTO [SCOTT].[DEPT]" + " ([DEPTNO], [DNAME], [LOC])\n" + "SELECT 1, 'Fred', 'San Francisco'\n" @@ -7826,7 +7826,7 @@ private void checkLiteral2(String expression, String expected) { final String expectedCalcite = "INSERT INTO \"SCOTT\".\"DEPT\"" + " (\"DEPTNO\", \"DNAME\", \"LOC\")\n" + "VALUES (1, 'Fred', 'San Francisco'),\n" - + "(2, 'Eric', 'Washington ')"; + + "(2, 'Eric', 'Washington')"; final String expectedCalciteX = "INSERT INTO \"SCOTT\".\"DEPT\"" + " (\"DEPTNO\", \"DNAME\", \"LOC\")\n" + "SELECT 1, 'Fred', 'San Francisco'\n" @@ -8010,7 +8010,7 @@ private void checkLiteral2(String expression, String expected) { + "WHEN NOT MATCHED THEN INSERT (\"DEPTNO\", \"DNAME\", \"LOC\") " + "VALUES CAST(\"DEPT\".\"DEPTNO\" + 1 AS TINYINT),\n" + "'abc',\n" - + "LOWER(\"DEPT\".\"DNAME\")"; + + "CAST(LOWER(\"DEPT\".\"DNAME\") AS VARCHAR(13) CHARACTER SET \"ISO-8859-1\")"; sql(sql3) .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT) .ok(expected3); @@ -8083,8 +8083,8 @@ private void checkLiteral2(String expression, String expected) { + "WHEN MATCHED THEN UPDATE SET \"DNAME\" = 'abc'\n" + "WHEN NOT MATCHED THEN INSERT (\"DEPTNO\", \"DNAME\", \"LOC\") " + "VALUES CAST(\"t0\".\"EXPR$0\" + 1 AS TINYINT),\n" - + "LOWER(\"t0\".\"EXPR$1\"),\n" - + "UPPER(\"t0\".\"EXPR$2\")"; + + "CAST(LOWER(\"t0\".\"EXPR$1\") AS VARCHAR(14) CHARACTER SET \"ISO-8859-1\"),\n" + + "CAST(UPPER(\"t0\".\"EXPR$2\") AS VARCHAR(13) CHARACTER SET \"ISO-8859-1\")"; sql(sql7) .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT) .ok(expected7); diff --git a/core/src/test/java/org/apache/calcite/test/HepPlannerTest.java b/core/src/test/java/org/apache/calcite/test/HepPlannerTest.java index de1837f8b1c2..262bba031392 100644 --- a/core/src/test/java/org/apache/calcite/test/HepPlannerTest.java +++ b/core/src/test/java/org/apache/calcite/test/HepPlannerTest.java @@ -136,7 +136,7 @@ public final RelOptFixture sql(String sql) { final String sql = "(select name from dept union select ename from emp)\n" + "intersect (select fname from customer.contact)"; - sql(sql).withPlanner(planner).check(); + sql(sql).withPlanner(planner).checkUnchanged(); } @Test void testRuleDescription() { diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java index 49b30e832b4a..4882c193e336 100644 --- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java +++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java @@ -127,7 +127,7 @@ class JdbcAdapterTest { + " JdbcFilter(condition=[<($0, 10)])\n" + " JdbcTableScan(table=[[foodmart, store]])\n" + " JdbcToEnumerableConverter\n" - + " JdbcProject(ENAME=[$1])\n" + + " JdbcProject(EXPR$0=[CAST($1):VARCHAR(30)])\n" + " JdbcFilter(condition=[>(CAST($0):INTEGER NOT NULL, 10)])\n" + " JdbcTableScan(table=[[SCOTT, EMP]])") .runs() @@ -135,7 +135,7 @@ class JdbcAdapterTest { .planHasSql("SELECT \"store_name\"\n" + "FROM \"foodmart\".\"store\"\n" + "WHERE \"store_id\" < 10") - .planHasSql("SELECT \"ENAME\"\n" + .planHasSql("SELECT CAST(\"ENAME\" AS VARCHAR(30))\n" + "FROM \"SCOTT\".\"EMP\"\n" + "WHERE CAST(\"EMPNO\" AS INTEGER) > 10"); } @@ -1344,7 +1344,8 @@ private LockWrapper exclusiveCleanDb(Connection c) throws SQLException { + " JdbcTableModify(table=[[foodmart, expense_fact]], operation=[MERGE]," + " updateColumnList=[[amount]], flattened=[false])\n" + " JdbcProject(STORE_ID=[$0], $f1=[666], $f2=[1997-01-01 00:00:00], $f3=[666]," - + " $f4=['666'], $f5=[666], AMOUNT=[CAST($1):DECIMAL(10, 4) NOT NULL], store_id=[$2]," + + " $f4=['666':VARCHAR(30)], $f5=[666], AMOUNT=[CAST($1):DECIMAL(10, 4) NOT NULL]," + + " store_id=[$2]," + " account_id=[$3], exp_date=[$4], time_id=[$5], category_id=[$6], currency_id=[$7]," + " amount=[$8], AMOUNT0=[$1])\n" + " JdbcJoin(condition=[=($2, $0)], joinType=[left])\n" diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java index fb0e8b573788..d5511bd35e74 100644 --- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java @@ -405,7 +405,8 @@ final RelMetadataFixture sql(String sql) { .assertColumnOriginIsEmpty(); } - @Test void testColumnOriginsUnion() { + @Test @Disabled("Plan contains casts, which inhibit metadata propagation") + void testColumnOriginsUnion() { sql("select name from dept union all select ename from emp") .assertColumnOriginDouble("DEPT", "NAME", "EMP", "ENAME", false); } diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java index cabd12612e46..ed5fccb3f3f4 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -3219,7 +3219,10 @@ private void checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelT + "select *\n" + "from (values (5)) as t(y)"; sql(sql) - .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES) + .withRule( + CoreRules.PROJECT_REMOVE, + CoreRules.PROJECT_VALUES_MERGE, + CoreRules.UNION_TO_VALUES) .withInSubQueryThreshold(0) .check(); } @@ -3267,7 +3270,9 @@ private void checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelT + "select *\n" + "from (values (5)) as t(y)"; sql(sql) - .withRule(CoreRules.PROJECT_REMOVE, CoreRules.UNION_TO_VALUES) + .withRule(CoreRules.PROJECT_REMOVE, + CoreRules.PROJECT_VALUES_MERGE, + CoreRules.UNION_TO_VALUES) .withInSubQueryThreshold(0) .check(); } diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java index 29dc091b64fa..d11d633e7501 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -97,6 +97,13 @@ public static void checkActualAndReferenceFiles() { return LOCAL_FIXTURE; } + /** Test case for [CALCITE-6350] + * Unexpected result from UNION with literals expression. */ + @Test void testUnionLiterals() { + final String sql = "select * from (select 'word' i union all select 'w' i) t1 where i='w'"; + sql(sql).ok(); + } + @Test void testDotLiteralAfterNestedRow() { final String sql = "select ((1,2),(3,4,5)).\"EXPR$1\".\"EXPR$2\" from emp"; sql(sql).ok(); 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 5a841089f6c3..1576537df332 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -4399,7 +4399,7 @@ private void checkNegWindow(String s, String msg) { expr("(1,2) in ((1,2), (3,4))") .columnType("BOOLEAN NOT NULL"); expr("'medium' in (cast(null as varchar(10)), 'bc')") - .columnType("BOOLEAN"); + .columnType("BOOLEAN NOT NULL"); // nullability depends on nullability of both sides sql("select empno in (1, 2) from emp") @@ -8752,7 +8752,7 @@ void testGroupExpressionEquivalenceParams() { .withValidatorColumnReferenceExpansion(true) .rewritesTo("SELECT `DEPT`.`NAME`\n" + "FROM `CATALOG`.`SALES`.`DEPT` AS `DEPT`\n" - + "WHERE `DEPT`.`NAME` = 'Moonracer'\n" + + "WHERE `DEPT`.`NAME` = CAST('Moonracer' AS VARCHAR(10) CHARACTER SET `ISO-8859-1`)\n" + "GROUP BY `DEPT`.`NAME`\n" + "HAVING SUM(`DEPT`.`DEPTNO`) > 3\n" + "ORDER BY `NAME`"); @@ -8771,7 +8771,7 @@ void testGroupExpressionEquivalenceParams() { + " `EMP`.`MGR`, `EMP`.`HIREDATE`, `EMP`.`SAL`, `EMP`.`COMM`," + " `EMP`.`DEPTNO`, `EMP`.`SLACKER`\n" + "FROM `CATALOG`.`SALES`.`EMP` AS `EMP`) AS `E`\n" - + "WHERE `E`.`ENAME` = 'Moonracer'\n" + + "WHERE `E`.`ENAME` = CAST('Moonracer' AS VARCHAR(20) CHARACTER SET `ISO-8859-1`)\n" + "GROUP BY `E`.`ENAME`, `E`.`DEPTNO`, `E`.`SAL`\n" + "HAVING SUM(`E`.`DEPTNO`) > 3\n" + "ORDER BY `ENAME`, `E`.`DEPTNO`, `E`.`SAL`"; @@ -8789,7 +8789,7 @@ void testGroupExpressionEquivalenceParams() { + " order by unexpanded.deptno"; final String expectedSql = "SELECT `DEPT`.`DEPTNO`\n" + "FROM `CATALOG`.`SALES`.`DEPT` AS `DEPT`\n" - + "WHERE `DEPT`.`NAME` = 'Moonracer'\n" + + "WHERE `DEPT`.`NAME` = CAST('Moonracer' AS VARCHAR(10) CHARACTER SET `ISO-8859-1`)\n" + "GROUP BY `DEPT`.`DEPTNO`\n" + "HAVING SUM(`DEPT`.`DEPTNO`) > 0\n" + "ORDER BY `DEPT`.`DEPTNO`"; diff --git a/core/src/test/resources/org/apache/calcite/test/HepPlannerTest.xml b/core/src/test/resources/org/apache/calcite/test/HepPlannerTest.xml index c92bd6803ca6..58c63851b85f 100644 --- a/core/src/test/resources/org/apache/calcite/test/HepPlannerTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/HepPlannerTest.xml @@ -54,7 +54,7 @@ LogicalCalc(expr#0..1=[{inputs}], expr#2=[UPPER($t1)], expr#3=[20], expr#4=[=($t - - - diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml index d5c1bbc4d205..4b9adfabc3e0 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -4531,7 +4531,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$ @@ -7412,11 +7412,11 @@ LogicalMinus(all=[true]) LogicalProject(NAME=[$1], DEPTNO=[$0], $f2=[1]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) LogicalProject(NAME=[$0], DEPTNO=[$1]) - LogicalProject(NAME=[$1], DEPTNO=[$0], $f2=[1]) + LogicalProject(NAME=[$1], DEPTNO=[$0], EXPR$2=[1:BIGINT]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) LogicalMinus(all=[true]) LogicalProject(NAME=[$0], DEPTNO=[$1]) - LogicalProject(NAME=[$1], DEPTNO=[$0], $f2=[1]) + LogicalProject(NAME=[$1], DEPTNO=[$0], EXPR$2=[1:BIGINT]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) LogicalProject(NAME=[$0], DEPTNO=[$1]) LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT()]) @@ -7437,11 +7437,11 @@ LogicalProject(NAME=[$0], DEPTNO=[$1]) LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT()]) LogicalProject(NAME=[$1], DEPTNO=[$0], $f2=[1]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) - LogicalProject(NAME=[$1], DEPTNO=[$0], EXPR$2=[1]) + LogicalProject(NAME=[$1], DEPTNO=[$0], EXPR$2=[1:BIGINT]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) LogicalProject(NAME=[$0], DEPTNO=[$1]) LogicalMinus(all=[true]) - LogicalProject(NAME=[$1], DEPTNO=[$0], EXPR$2=[1]) + LogicalProject(NAME=[$1], DEPTNO=[$0], EXPR$2=[1:BIGINT]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT()]) LogicalProject(NAME=[$1], DEPTNO=[$0], $f2=[1]) @@ -12485,7 +12485,7 @@ where cast(e.job as varchar(1)) = 'Manager']]> @@ -12641,9 +12641,9 @@ LogicalProject(U=[$0], S=[$1]) LogicalProject(U=[UPPER(||(SUBSTRING($0, 1, 2), SUBSTRING($0, 3)))], S=[SUBSTRING($0, 1, 1)]) LogicalUnion(all=[false]) LogicalUnion(all=[false]) - LogicalProject(X=['table']) + LogicalProject(X=['table ']) LogicalValues(tuples=[[{ true }]]) - LogicalProject(EXPR$0=['view']) + LogicalProject(EXPR$0=['view ']) LogicalValues(tuples=[[{ true }]]) LogicalProject(EXPR$0=['foreign table']) LogicalValues(tuples=[[{ true }]]) @@ -12651,8 +12651,8 @@ LogicalProject(U=[$0], S=[$1]) @@ -16747,17 +16747,15 @@ from (values (5)) as t(y)]]> @@ -16841,17 +16839,15 @@ from (values (5)) as t(y)]]> diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index 2cc2aa6ca527..3a5c3d0b6f2d 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -3151,7 +3151,7 @@ LogicalTableModify(table=[[CATALOG, SALES, EMPNULLABLES]], operation=[INSERT], f @@ -6393,9 +6393,9 @@ QUALIFY RANK() OVER (PARTITION BY ename ($7, 5)]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]> @@ -8279,7 +8279,7 @@ LogicalProject(DEPTNO=[$1]) LogicalMinus(all=[true]) LogicalProject(ENAME=[$1], DEPTNO=[$7]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) - LogicalProject(NAME=[$1], DEPTNO=[$0]) + LogicalProject(EXPR$0=[CAST($1):VARCHAR(20) NOT NULL], DEPTNO=[$0]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) ]]> @@ -8297,7 +8297,7 @@ LogicalProject(DEPTNO=[$1]) LogicalMinus(all=[false]) LogicalProject(ENAME=[$1], DEPTNO=[$7]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) - LogicalProject(NAME=[$1], DEPTNO=[$0]) + LogicalProject(EXPR$0=[CAST($1):VARCHAR(20) NOT NULL], DEPTNO=[$0]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) ]]> @@ -8315,7 +8315,7 @@ LogicalProject(DEPTNO=[$1]) LogicalIntersect(all=[true]) LogicalProject(ENAME=[$1], DEPTNO=[$7]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) - LogicalProject(NAME=[$1], DEPTNO=[$0]) + LogicalProject(EXPR$0=[CAST($1):VARCHAR(20) NOT NULL], DEPTNO=[$0]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) ]]> @@ -8333,7 +8333,7 @@ LogicalProject(DEPTNO=[$1]) LogicalIntersect(all=[false]) LogicalProject(ENAME=[$1], DEPTNO=[$7]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) - LogicalProject(NAME=[$1], DEPTNO=[$0]) + LogicalProject(EXPR$0=[CAST($1):VARCHAR(20) NOT NULL], DEPTNO=[$0]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) ]]> @@ -8416,7 +8416,7 @@ LogicalProject(DEPTNO=[$1]) LogicalUnion(all=[false]) LogicalProject(ENAME=[$1], DEPTNO=[$7]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) - LogicalProject(NAME=[$1], DEPTNO=[$0]) + LogicalProject(EXPR$0=[CAST($1):VARCHAR(20) NOT NULL], DEPTNO=[$0]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) ]]> @@ -8584,10 +8584,24 @@ LogicalUnion(all=[true]) + + + + + + + + @@ -8934,7 +8948,7 @@ LogicalTableModify(table=[[CATALOG, SALES, EMP]], operation=[UPDATE], updateColu diff --git a/core/src/test/resources/sql/operator.iq b/core/src/test/resources/sql/operator.iq index cc1fea0ec49b..9e74030c3593 100644 --- a/core/src/test/resources/sql/operator.iq +++ b/core/src/test/resources/sql/operator.iq @@ -18,6 +18,16 @@ !use scott !set outputformat mysql +select * from (select 'word' i union all select 'w' i) t1 where i='w'; ++------+ +| I | ++------+ +| w | ++------+ +(1 row) + +!ok + # [CALCITE-1095] NOT precedence select * from "scott".emp where not sal > 1300; +-------+--------+----------+------+------------+---------+---------+--------+ diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java index a7ca44dc2a32..fb18e5b9fa4b 100644 --- a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java +++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java @@ -433,7 +433,7 @@ private static Consumer sortedResultSetChecker(String column, final String explain = "PLAN=ElasticsearchToEnumerableConverter\n" + " ElasticsearchSort(sort0=[$4], sort1=[$3], dir0=[ASC], dir1=[ASC])\n" + " ElasticsearchProject(city=[CAST(ITEM($0, 'city')):VARCHAR(20)], longitude=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], latitude=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], pop=[CAST(ITEM($0, 'pop')):INTEGER], state=[CAST(ITEM($0, 'state')):VARCHAR(2)], id=[CAST(ITEM($0, 'id')):VARCHAR(5)])\n" - + " ElasticsearchFilter(condition=[AND(=(CAST(ITEM($0, 'state')):VARCHAR(2), 'CA'), >=(CAST(ITEM($0, 'pop')):INTEGER, 94000))])\n" + + " ElasticsearchFilter(condition=[AND(=(CAST(CAST(ITEM($0, 'state')):VARCHAR(2)):CHAR(2), 'CA'), >=(CAST(ITEM($0, 'pop')):INTEGER, 94000))])\n" + " ElasticsearchTableScan(table=[[elastic, zips]])\n\n"; calciteAssert() .query(sql) @@ -466,7 +466,7 @@ private static Consumer sortedResultSetChecker(String column, final String explain = "PLAN=ElasticsearchToEnumerableConverter\n" + " ElasticsearchSort(sort0=[$4], sort1=[$3], dir0=[ASC], dir1=[ASC])\n" + " ElasticsearchProject(city=[CAST(ITEM($0, 'city')):VARCHAR(20)], longitude=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], latitude=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], pop=[CAST(ITEM($0, 'pop')):INTEGER], state=[CAST(ITEM($0, 'state')):VARCHAR(2)], id=[CAST(ITEM($0, 'id')):VARCHAR(5)])\n" - + " ElasticsearchFilter(condition=[OR(=(CAST(ITEM($0, 'state')):VARCHAR(2), 'CA'), >=(CAST(ITEM($0, 'pop')):INTEGER, 94000))])\n" + + " ElasticsearchFilter(condition=[OR(=(CAST(CAST(ITEM($0, 'state')):VARCHAR(2)):CHAR(2), 'CA'), >=(CAST(ITEM($0, 'pop')):INTEGER, 94000))])\n" + " ElasticsearchTableScan(table=[[elastic, zips]])\n\n"; calciteAssert() .query(sql) @@ -549,7 +549,7 @@ private static Consumer sortedResultSetChecker(String column, @Test void testFilter() { final String explain = "PLAN=ElasticsearchToEnumerableConverter\n" + " ElasticsearchProject(state=[CAST(ITEM($0, 'state')):VARCHAR(2)], city=[CAST(ITEM($0, 'city')):VARCHAR(20)])\n" - + " ElasticsearchFilter(condition=[=(CAST(ITEM($0, 'state')):VARCHAR(2), 'CA')])\n" + + " ElasticsearchFilter(condition=[=(CAST(CAST(ITEM($0, 'state')):VARCHAR(2)):CHAR(2), 'CA')])\n" + " ElasticsearchTableScan(table=[[elastic, zips]])"; calciteAssert() diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsTest.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsTest.java index a9e7d50d372c..bf42258edabc 100644 --- a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsTest.java +++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsTest.java @@ -64,7 +64,7 @@ private static Connection createConnection() throws SQLException { // add calcite view programmatically final String viewSql = "select \"_id\" AS \"id\", \"city\", \"loc\", " - + "cast(\"pop\" AS integer) AS \"pop\", cast(\"state\" AS varchar(2)) AS \"state\" " + + "cast(\"pop\" AS integer) AS \"pop\", cast(\"state\" AS char(2)) AS \"state\" " + "from \"geode\".\"zips\""; diff --git a/innodb/src/test/java/org/apache/calcite/adapter/innodb/InnodbAdapterTest.java b/innodb/src/test/java/org/apache/calcite/adapter/innodb/InnodbAdapterTest.java index 65937df50138..4b7724fda235 100644 --- a/innodb/src/test/java/org/apache/calcite/adapter/innodb/InnodbAdapterTest.java +++ b/innodb/src/test/java/org/apache/calcite/adapter/innodb/InnodbAdapterTest.java @@ -895,9 +895,10 @@ public class InnodbAdapterTest { @Test void testSelectByMultipleSkRangeQueryPushDownPartialCondition3() { sql("SELECT EMPNO,DEPTNO,JOB FROM \"EMP\" WHERE JOB >= 'SALE' AND DEPTNO >= 20") - .explainContains("PLAN=EnumerableCalc(expr#0..12=[{inputs}], expr#13=['SALE'], " - + "expr#14=[>=($t2, $t13)], " - + "EMPNO=[$t0], DEPTNO=[$t8], JOB=[$t2], $condition=[$t14])\n" + .explainContains("PLAN=EnumerableCalc(expr#0..12=[{inputs}], " + + "expr#13=[CAST($t2):CHAR(4) NOT NULL], " + + "expr#14=['SALE'], expr#15=[>=($t13, $t14)], " + + "EMPNO=[$t0], DEPTNO=[$t8], JOB=[$t2], $condition=[$t15])\n" + " InnodbToEnumerableConverter\n" + " InnodbFilter(condition=[(SK_RANGE_QUERY, index=DEPTNO_JOB_KEY, " + "DEPTNO>=20)])\n" diff --git a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java index 368340969398..483aa108b3e9 100644 --- a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java +++ b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java @@ -638,7 +638,7 @@ private CalciteAssert.AssertThat assertModel(URL url) { "STATE=CA; CITY=NORWALK") .explainContains("PLAN=MongoToEnumerableConverter\n" + " MongoProject(STATE=[CAST(ITEM($0, 'state')):VARCHAR(2)], CITY=[CAST(ITEM($0, 'city')):VARCHAR(20)])\n" - + " MongoFilter(condition=[=(CAST(ITEM($0, 'state')):VARCHAR(2), 'CA')])\n" + + " MongoFilter(condition=[=(CAST(CAST(ITEM($0, 'state')):VARCHAR(2)):CHAR(2), 'CA')])\n" + " MongoTableScan(table=[[mongo_raw, zips]])"); } diff --git a/server/src/test/resources/sql/materialized_view.iq b/server/src/test/resources/sql/materialized_view.iq index 0e02a18c1252..8a8b12992f81 100644 --- a/server/src/test/resources/sql/materialized_view.iq +++ b/server/src/test/resources/sql/materialized_view.iq @@ -39,12 +39,12 @@ select * from dept where deptno > 10; # Check contents select * from v; -+--------+-------------+ -| DEPTNO | NAME | -+--------+-------------+ -| 20 | Marketing | -| 30 | Engineering | -+--------+-------------+ ++--------+------------+ +| DEPTNO | NAME | ++--------+------------+ +| 20 | Marketing | +| 30 | Engineerin | ++--------+------------+ (2 rows) !ok @@ -64,12 +64,12 @@ select * from dept where deptno < 30; # Check contents are unchanged select * from v; -+--------+-------------+ -| DEPTNO | NAME | -+--------+-------------+ -| 20 | Marketing | -| 30 | Engineering | -+--------+-------------+ ++--------+------------+ +| DEPTNO | NAME | ++--------+------------+ +| 20 | Marketing | +| 30 | Engineerin | ++--------+------------+ (2 rows) !ok diff --git a/server/src/test/resources/sql/table_as.iq b/server/src/test/resources/sql/table_as.iq index 68ca9f177340..cf2450991422 100644 --- a/server/src/test/resources/sql/table_as.iq +++ b/server/src/test/resources/sql/table_as.iq @@ -37,14 +37,14 @@ select * from dept where deptno > 10; !update -# Check contents +# Check contents; "Engineering" is too long for varchar(10) select * from d; -+--------+-------------+ -| DEPTNO | NAME | -+--------+-------------+ -| 20 | Marketing | -| 30 | Engineering | -+--------+-------------+ ++--------+------------+ +| DEPTNO | NAME | ++--------+------------+ +| 20 | Marketing | +| 30 | Engineerin | ++--------+------------+ (2 rows) !ok @@ -64,12 +64,12 @@ select * from dept where deptno < 30; # Check contents are unchanged select * from d; -+--------+-------------+ -| DEPTNO | NAME | -+--------+-------------+ -| 20 | Marketing | -| 30 | Engineering | -+--------+-------------+ ++--------+------------+ +| DEPTNO | NAME | ++--------+------------+ +| 20 | Marketing | +| 30 | Engineerin | ++--------+------------+ (2 rows) !ok diff --git a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java index 66ba88520e45..7a56f471fbca 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -6730,13 +6730,13 @@ void checkRegexpExtract(SqlOperatorFixture f0, FunctionAlias functionAlias) { }; f.checkAggWithMultipleArgs("json_objectagg(x: x2)", values, - isSingle("{\"foo\":\"bar\",\"foo2\":null,\"foo3\":\"bar3\"}")); + isSingle("{\"foo \":\"bar\",\"foo2\":null,\"foo3\":\"bar3\"}")); f.checkAggWithMultipleArgs("json_objectagg(x: x2 null on null)", values, - isSingle("{\"foo\":\"bar\",\"foo2\":null,\"foo3\":\"bar3\"}")); + isSingle("{\"foo \":\"bar\",\"foo2\":null,\"foo3\":\"bar3\"}")); f.checkAggWithMultipleArgs("json_objectagg(x: x2 absent on null)", values, - isSingle("{\"foo\":\"bar\",\"foo3\":\"bar3\"}")); + isSingle("{\"foo \":\"bar\",\"foo3\":\"bar3\"}")); } @Test void testJsonValueExpressionOperator() { @@ -11917,7 +11917,7 @@ private static void checkDecodeFunc(SqlOperatorFixture f) { f.checkAggType("listagg('test')", "CHAR(4) NOT NULL"); f.checkAggType("listagg('test', ', ')", "CHAR(4) NOT NULL"); final String[] values1 = {"'hello'", "CAST(null AS CHAR)", "'world'", "'!'"}; - f.checkAgg("listagg(x)", values1, isSingle("hello,world,!")); + f.checkAgg("listagg(x)", values1, isSingle("hello,world,! ")); final String[] values2 = {"0", "1", "2", "3"}; f.checkAgg("listagg(cast(x as CHAR))", values2, isSingle("0,1,2,3")); } @@ -11931,10 +11931,10 @@ private static void checkDecodeFunc(SqlOperatorFixture f) { private static void checkStringAggFunc(SqlOperatorFixture f) { final String[] values = {"'x'", "null", "'yz'"}; - f.checkAgg("string_agg(x)", values, isSingle("x,yz")); - f.checkAgg("string_agg(x,':')", values, isSingle("x:yz")); - f.checkAgg("string_agg(x,':' order by x)", values, isSingle("x:yz")); - f.checkAgg("string_agg(x order by char_length(x) desc)", values, isSingle("yz,x")); + f.checkAgg("string_agg(x)", values, isSingle("x ,yz")); + f.checkAgg("string_agg(x,':')", values, isSingle("x :yz")); + f.checkAgg("string_agg(x,':' order by x)", values, isSingle("x :yz")); + f.checkAgg("string_agg(x order by char_length(x) desc)", values, isSingle("x ,yz")); f.checkAggFails("^string_agg(x respect nulls order by x desc)^", values, "Cannot specify IGNORE NULLS or RESPECT NULLS following 'STRING_AGG'", false); @@ -11967,13 +11967,13 @@ private static void checkStringAggFuncFails(SqlOperatorFixture f) { private static void checkGroupConcatFunc(SqlOperatorFixture f) { final String[] values = {"'x'", "null", "'yz'"}; - f.checkAgg("group_concat(x)", values, isSingle("x,yz")); - f.checkAgg("group_concat(x,':')", values, isSingle("x:yz")); - f.checkAgg("group_concat(x,':' order by x)", values, isSingle("x:yz")); + f.checkAgg("group_concat(x)", values, isSingle("x ,yz")); + f.checkAgg("group_concat(x,':')", values, isSingle("x :yz")); + f.checkAgg("group_concat(x,':' order by x)", values, isSingle("x :yz")); f.checkAgg("group_concat(x order by x separator '|')", values, - isSingle("x|yz")); + isSingle("x |yz")); f.checkAgg("group_concat(x order by char_length(x) desc)", values, - isSingle("yz,x")); + isSingle("x ,yz")); f.checkAggFails("^group_concat(x respect nulls order by x desc)^", values, "Cannot specify IGNORE NULLS or RESPECT NULLS following 'GROUP_CONCAT'", false); @@ -12008,16 +12008,16 @@ private static void checkArrayAggFunc(SqlOperatorFixture f) { f.setFor(SqlLibraryOperators.ARRAY_AGG, VM_JAVA); final String[] values = {"'x'", "null", "'yz'"}; f.checkAggType("array_agg(x)", "INTEGER NOT NULL ARRAY NOT NULL"); - f.checkAgg("array_agg(x)", values, "CHAR(2) ARRAY", isSingle("[x, yz]")); - f.checkAgg("array_agg(x ignore nulls)", values, "CHAR(2) ARRAY", isSingle("[x, yz]")); - f.checkAgg("array_agg(x respect nulls)", values, "CHAR(2) ARRAY", isSingle("[x, yz]")); + f.checkAgg("array_agg(x)", values, "CHAR(2) ARRAY", isSingle("[x , yz]")); + f.checkAgg("array_agg(x ignore nulls)", values, "CHAR(2) ARRAY", isSingle("[x , yz]")); + f.checkAgg("array_agg(x respect nulls)", values, "CHAR(2) ARRAY", isSingle("[x , yz]")); final String expectedError = "Invalid number of arguments " + "to function 'ARRAY_AGG'. Was expecting 1 arguments"; f.checkAggFails("^array_agg(x,':')^", values, expectedError, false); f.checkAggFails("^array_agg(x,':' order by x)^", values, expectedError, false); f.checkAgg("array_agg(x order by char_length(x) desc)", values, - isSingle("[yz, x]")); + isSingle("[x , yz]")); } private static void checkArrayAggFuncFails(SqlOperatorFixture t) {