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

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


The following commit(s) were added to refs/heads/main by this push:
     new 4c9011c388 [CALCITE-5884] ARRAY_TO_STRING function should return NULL 
if its 'nullValue' argument is NULL
4c9011c388 is described below

commit 4c9011c388f826c36463ae7da875ddb525104376
Author: Mihai Budiu <[email protected]>
AuthorDate: Wed Nov 1 19:34:53 2023 -0700

    [CALCITE-5884] ARRAY_TO_STRING function should return NULL if its 
'nullValue' argument is NULL
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 .../org/apache/calcite/runtime/SqlFunctions.java   |  4 ++
 .../org/apache/calcite/sql/SqlNumericLiteral.java  |  2 +-
 .../org/apache/calcite/sql/type/ReturnTypes.java   |  2 +-
 .../org/apache/calcite/test/RelOptRulesTest.java   | 57 ++++++++++++++++------
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 17 +++++++
 site/_docs/reference.md                            |  2 +-
 .../org/apache/calcite/test/SqlOperatorTest.java   |  1 +
 7 files changed, 68 insertions(+), 17 deletions(-)

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 5f3cbf9563..4e11245ae3 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 class SqlFunctions {
 
   /** 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 25205b99ab..ebf018ea5e 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 class SqlNumericLiteral extends SqlLiteral {
           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 8fe9284ee9..48da8b88a6 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 abstract class ReturnTypes {
   };
 
   /**
-   * Returns the element type of a ARRAY or MULTISET.
+   * Returns the element type of an ARRAY or MULTISET.
    *
    * <p>For example, given <code>INTEGER ARRAY or MULTISET ARRAY</code>, 
returns
    * <code>INTEGER</code>.
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 9d84c82310..9b5f3a75b8 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 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5813";>[CALCITE-5813]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5813";>[CALCITE-5813]
    * Type inference for sql functions REPEAT, SPACE, XML_TRANSFORM,
    * and XML_EXTRACT is incorrect</a>. */
   @Test void testRepeat() {
@@ -246,7 +247,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5813";>[CALCITE-5813]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5813";>[CALCITE-5813]
    * Type inference for sql functions REPEAT, SPACE, XML_TRANSFORM,
    * and XML_EXTRACT is incorrect</a>. */
   @Test void testReplace() {
@@ -263,7 +265,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5989";>[CALCITE-5989]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5989";>[CALCITE-5989]
    * Type inference for RPAD and LPAD functions (BIGQUERY) is incorrect</a>. */
   @Test void testRpad() {
     HepProgramBuilder builder = new HepProgramBuilder();
@@ -283,7 +286,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5989";>[CALCITE-5989]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5989";>[CALCITE-5989]
    * Type inference for RPAD and LPAD functions (BIGQUERY) is incorrect</a>. */
   @Test void testLpad() {
     HepProgramBuilder builder = new HepProgramBuilder();
@@ -303,7 +307,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5971";>[CALCITE-5971]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5971";>[CALCITE-5971]
    * Add the RelRule to rewrite the bernoulli sample as Filter</a>. */
   @Test void testSampleToFilter() {
     final String sql = "select deptno from emp tablesample bernoulli(50)";
@@ -313,7 +318,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5971";>[CALCITE-5971]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5971";>[CALCITE-5971]
    * Add the RelRule to rewrite the bernoulli sample as Filter</a>. */
   @Test void testSampleToFilterWithSeed() {
     final String sql = "select deptno from emp tablesample bernoulli(50) 
REPEATABLE(10)";
@@ -323,7 +329,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5813";>[CALCITE-5813]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5813";>[CALCITE-5813]
    * Type inference for sql functions REPEAT, SPACE, XML_TRANSFORM,
    * and XML_EXTRACT is incorrect</a>. */
   @Test void testSpace() {
@@ -2034,6 +2041,21 @@ class RelOptRulesTest extends RelOptTestBase {
         .check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5884";>[CALCITE-5884]
+   * ARRAY_TO_STRING function should return NULL if its 'nullValue' argument 
is NULL</a>. */
+  @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
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-1558";>[CALCITE-1558]
    * AggregateExpandDistinctAggregatesRule gets field mapping wrong if groupKey
@@ -2733,7 +2755,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5073";>[CALCITE-5073]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5073";>[CALCITE-5073]
    * JoinConditionPushRule cannot infer 'LHS.C1 = LHS.C2' from
    * 'LHS.C1 = RHS.C1 AND LHS.C2 = RHS.C1'</a>.
    */
@@ -2750,7 +2773,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5073";>[CALCITE-5073]
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5073";>[CALCITE-5073]
    * JoinConditionPushRule cannot infer 'LHS.C1 = LHS.C2' from
    * 'LHS.C1 = RHS.C1 AND LHS.C2 = RHS.C1'</a>.
    */
@@ -5483,7 +5507,8 @@ class RelOptRulesTest extends RelOptTestBase {
   }
 
   /**
-   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5861";>
+   * Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-5861";>
    * [CALCITE-5861] ReduceExpressionsRule rules should constant-fold
    * expressions in window bounds</a>.
    */
@@ -5682,7 +5707,8 @@ class RelOptRulesTest extends RelOptTestBase {
         .checkUnchanged();
   }
 
-  /** Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5879";>
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-5879";>
    * AssertionError during constant reduction of SPLIT expression that returns 
NULL</a>. */
   @Test public void testSplitNull() {
     final String query = "select split('1|2|3', NULL)";
@@ -5695,7 +5721,8 @@ class RelOptRulesTest extends RelOptTestBase {
         .check();
   }
 
-  /** Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5879";>
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-5879";>
    * AssertionError during constant reduction of SPLIT expression that returns 
NULL</a>. */
   @Test public void testSplitNull1() {
     final String query = "select split(NULL, '|')";
@@ -5708,7 +5735,8 @@ class RelOptRulesTest extends RelOptTestBase {
         .check();
   }
 
-  /** Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5879";>
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-5879";>
    * AssertionError during constant reduction of SPLIT expression that returns 
NULL</a>. */
   @Test public void testSplitNull2() {
     final String query = "select split(NULL, NULL)";
@@ -5721,7 +5749,8 @@ class RelOptRulesTest extends RelOptTestBase {
         .check();
   }
 
-  /** Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-5882";>
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-5882";>
    * [CALCITE-5882] Compile-time evaluation of SPLIT function returns 
incorrect result</a>. */
   @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 b322976ac2..0bfe265d30 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]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testArrayToString">
+    <Resource name="sql">
+      <![CDATA[select array_to_string(array['1','2','3','4',NULL,'6'], ',', 
NULL)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[ARRAY_TO_STRING(ARRAY('1', '2', '3', '4', null:CHAR(1), 
'6'), ',', null:NULL)])
+  LogicalValues(tuples=[[{ 0 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[null:VARCHAR])
+  LogicalValues(tuples=[[{ 0 }]])
 ]]>
     </Resource>
   </TestCase>
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 6210c1d8ff..1322abdc88 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2673,7 +2673,7 @@ BigQuery's type system uses confusingly different names 
for types and functions:
 | s | ARRAY_REPEAT(element, count)                   | Returns the array 
containing element count times.
 | b | ARRAY_REVERSE(array)                           | Reverses elements of 
*array*
 | s | ARRAY_SIZE(array)                              | Synonym for 
`CARDINALITY`
-| b | ARRAY_TO_STRING(array, delimiter [, nullText ])| Returns a concatenation 
of the elements in *array* as a STRING and take *delimiter* as the delimiter. 
If the *nullText* parameter is used, the function replaces any `NULL` values in 
the array with the value of *nullText*. If the *nullText* parameter is not 
used, the function omits the `NULL` value and its preceding delimiter
+| b | ARRAY_TO_STRING(array, delimiter [, nullText ])| Returns a concatenation 
of the elements in *array* as a STRING and take *delimiter* as the delimiter. 
If the *nullText* parameter is used, the function replaces any `NULL` values in 
the array with the value of *nullText*. If the *nullText* parameter is not 
used, the function omits the `NULL` value and its preceding delimiter. Returns 
`NULL` if any argument is `NULL`
 | s | ARRAY_UNION(array1, array2)                    | Returns an array of the 
elements in the union of *array1* and *array2*, without duplicates
 | s | ARRAYS_OVERLAP(array1, array2)                 | Returns true if *array1 
contains at least a non-null element present also in *array2*. If the arrays 
have no common element and they are both non-empty and either of them contains 
a null element null is returned, false otherwise
 | s | ARRAYS_ZIP(array [, array ]*)                  | Returns a merged 
*array* of structs in which the N-th struct contains all N-th values of input 
arrays
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 799b5ddbd0..e755747681 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -6600,6 +6600,7 @@ public class SqlOperatorTest {
     f.checkScalar("array_to_string(array['', ''], '-')", "-", "VARCHAR NOT 
NULL");
     f.checkNull("array_to_string(null, '-')");
     f.checkNull("array_to_string(array['a', 'b', null], null)");
+    f.checkNull("array_to_string(array['1','2','3'], ',', null)");
     f.checkFails("^array_to_string(array[1, 2, 3], '-', ' ')^",
         "Cannot apply 'ARRAY_TO_STRING' to arguments of type 'ARRAY_TO_STRING"
             + "\\(<INTEGER ARRAY>, <CHAR\\(1\\)>, <CHAR\\(1\\)>\\)'\\. 
Supported form\\(s\\):"

Reply via email to