diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java index 5f3cbf95631..4e11245ae3e 100644 --- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java @@ -5583,6 +5583,10 @@ public static String arrayToString(List list, String delimiter) { /** SQL {@code ARRAY_TO_STRING(array, delimiter, nullText)} function. */ public static String arrayToString(List list, String delimiter, @Nullable String nullText) { + // Note that the SQL function ARRAY_TO_STRING that we implement will return + // 'NULL' when the nullText argument is NULL. However, that is handled by + // the nullPolicy of the RexToLixTranslator. So here a NULL value + // for the nullText argument can only come from the above 2-argument version. StringBuilder sb = new StringBuilder(); boolean isFirst = true; for (Object item : list) { diff --git a/core/src/main/java/org/apache/calcite/sql/SqlNumericLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlNumericLiteral.java index 25205b99ab2..ebf018ea5e8 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlNumericLiteral.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlNumericLiteral.java @@ -117,7 +117,7 @@ public boolean isExact() { scaleValue); } - // else we have a a float, real or double. make them all double for + // else we have a FLOAT, REAL or DOUBLE. make them all DOUBLE for // now. return typeFactory.createSqlType(SqlTypeName.DOUBLE); } diff --git a/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java b/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java index 8fe9284ee99..48da8b88a61 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java +++ b/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java @@ -591,7 +591,7 @@ public static SqlCall stripSeparator(SqlCall call) { }; /** - * Returns the element type of a ARRAY or MULTISET. + * Returns the element type of an ARRAY or MULTISET. * *
For example, given INTEGER ARRAY or MULTISET ARRAY
, returns
* INTEGER
.
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 9d84c823107..9b5f3a75b85 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -225,7 +225,8 @@ private static boolean skipItem(RexNode expr) {
}
/**
- * Test case for [CALCITE-5813]
+ * Test case for
+ * [CALCITE-5813]
* Type inference for sql functions REPEAT, SPACE, XML_TRANSFORM,
* and XML_EXTRACT is incorrect. */
@Test void testRepeat() {
@@ -246,7 +247,8 @@ private static boolean skipItem(RexNode expr) {
}
/**
- * Test case for [CALCITE-5813]
+ * Test case for
+ * [CALCITE-5813]
* Type inference for sql functions REPEAT, SPACE, XML_TRANSFORM,
* and XML_EXTRACT is incorrect. */
@Test void testReplace() {
@@ -263,7 +265,8 @@ private static boolean skipItem(RexNode expr) {
}
/**
- * Test case for [CALCITE-5989]
+ * Test case for
+ * [CALCITE-5989]
* Type inference for RPAD and LPAD functions (BIGQUERY) is incorrect. */
@Test void testRpad() {
HepProgramBuilder builder = new HepProgramBuilder();
@@ -283,7 +286,8 @@ private static boolean skipItem(RexNode expr) {
}
/**
- * Test case for [CALCITE-5989]
+ * Test case for
+ * [CALCITE-5989]
* Type inference for RPAD and LPAD functions (BIGQUERY) is incorrect. */
@Test void testLpad() {
HepProgramBuilder builder = new HepProgramBuilder();
@@ -303,7 +307,8 @@ private static boolean skipItem(RexNode expr) {
}
/**
- * Test case for [CALCITE-5971]
+ * Test case for
+ * [CALCITE-5971]
* Add the RelRule to rewrite the bernoulli sample as Filter. */
@Test void testSampleToFilter() {
final String sql = "select deptno from emp tablesample bernoulli(50)";
@@ -313,7 +318,8 @@ private static boolean skipItem(RexNode expr) {
}
/**
- * Test case for [CALCITE-5971]
+ * Test case for
+ * [CALCITE-5971]
* Add the RelRule to rewrite the bernoulli sample as Filter. */
@Test void testSampleToFilterWithSeed() {
final String sql = "select deptno from emp tablesample bernoulli(50) REPEATABLE(10)";
@@ -323,7 +329,8 @@ private static boolean skipItem(RexNode expr) {
}
/**
- * Test case for [CALCITE-5813]
+ * Test case for
+ * [CALCITE-5813]
* Type inference for sql functions REPEAT, SPACE, XML_TRANSFORM,
* and XML_EXTRACT is incorrect. */
@Test void testSpace() {
@@ -2034,6 +2041,21 @@ private void checkSemiOrAntiJoinProjectTranspose(JoinRelType type) {
.check();
}
+ /** Test case for
+ * [CALCITE-5884]
+ * ARRAY_TO_STRING function should return NULL if its 'nullValue' argument is NULL. */
+ @Test void testArrayToString() {
+ final String sql = "select array_to_string(array['1','2','3','4',NULL,'6'], ',', NULL)";
+ // We expect the result to be NULL, since array_to_string returns NULL if
+ // any argument is NULL.
+ sql(sql).withFactory(
+ t -> t.withOperatorTable(
+ opTab -> SqlLibraryOperatorTableFactory.INSTANCE.getOperatorTable(
+ SqlLibrary.STANDARD, SqlLibrary.BIG_QUERY))) // for array_to_string function
+ .withRule(CoreRules.PROJECT_REDUCE_EXPRESSIONS)
+ .check();
+ }
+
/** Test case for
* [CALCITE-1558]
* AggregateExpandDistinctAggregatesRule gets field mapping wrong if groupKey
@@ -2733,7 +2755,8 @@ private void checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelT
}
/**
- * Test case for [CALCITE-5073]
+ * Test case for
+ * [CALCITE-5073]
* JoinConditionPushRule cannot infer 'LHS.C1 = LHS.C2' from
* 'LHS.C1 = RHS.C1 AND LHS.C2 = RHS.C1'.
*/
@@ -2750,7 +2773,8 @@ private void checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelT
}
/**
- * Test case for [CALCITE-5073]
+ * Test case for
+ * [CALCITE-5073]
* JoinConditionPushRule cannot infer 'LHS.C1 = LHS.C2' from
* 'LHS.C1 = RHS.C1 AND LHS.C2 = RHS.C1'.
*/
@@ -5483,7 +5507,8 @@ private HepProgram getTransitiveProgram() {
}
/**
- * Test case for
+ * Test case for
+ *
* [CALCITE-5861] ReduceExpressionsRule rules should constant-fold
* expressions in window bounds.
*/
@@ -5682,7 +5707,8 @@ private HepProgram getTransitiveProgram() {
.checkUnchanged();
}
- /** Test case for
+ /** Test case for
+ *
* AssertionError during constant reduction of SPLIT expression that returns NULL. */
@Test public void testSplitNull() {
final String query = "select split('1|2|3', NULL)";
@@ -5695,7 +5721,8 @@ private HepProgram getTransitiveProgram() {
.check();
}
- /** Test case for
+ /** Test case for
+ *
* AssertionError during constant reduction of SPLIT expression that returns NULL. */
@Test public void testSplitNull1() {
final String query = "select split(NULL, '|')";
@@ -5708,7 +5735,8 @@ private HepProgram getTransitiveProgram() {
.check();
}
- /** Test case for
+ /** Test case for
+ *
* AssertionError during constant reduction of SPLIT expression that returns NULL. */
@Test public void testSplitNull2() {
final String query = "select split(NULL, NULL)";
@@ -5721,7 +5749,8 @@ private HepProgram getTransitiveProgram() {
.check();
}
- /** Test case for
+ /** Test case for
+ *
* [CALCITE-5882] Compile-time evaluation of SPLIT function returns incorrect result. */
@Test public void testSplit() {
final String query = "select split('1|2|3', '|')";
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 b322976ac28..0bfe265d30a 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1283,6 +1283,23 @@ LogicalProject(DEPTNO=[$0], EXPR$1=[OR(AND(IS NOT NULL($5), <>($2, 0)), AND(<($3
LogicalAggregate(group=[{0}], i=[LITERAL_AGG(true)])
LogicalProject(MGR=[$3])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+
+
+