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

xiong 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 988caace5c [CALCITE-6951] Add STRING_TO_ARRAY function(enabled in 
PostgreSQL Library)
988caace5c is described below

commit 988caace5c423c2c98f60e3beeee6d0e660d3111
Author: Juntao Zhang <[email protected]>
AuthorDate: Fri May 16 09:17:05 2025 +0800

    [CALCITE-6951] Add STRING_TO_ARRAY function(enabled in PostgreSQL Library)
---
 babel/src/test/resources/sql/postgresql.iq         | 51 ++++++++++++++++++++++
 .../calcite/adapter/enumerable/RexImpTable.java    |  2 +
 .../org/apache/calcite/runtime/SqlFunctions.java   | 33 ++++++++++++++
 .../main/java/org/apache/calcite/sql/SqlKind.java  |  4 ++
 .../calcite/sql/fun/SqlLibraryOperators.java       |  7 +++
 .../org/apache/calcite/util/BuiltInMethod.java     |  2 +
 site/_docs/reference.md                            |  1 +
 .../org/apache/calcite/test/SqlOperatorTest.java   | 22 ++++++++++
 8 files changed, 122 insertions(+)

diff --git a/babel/src/test/resources/sql/postgresql.iq 
b/babel/src/test/resources/sql/postgresql.iq
index 383dbfad1c..bc1116af2b 100644
--- a/babel/src/test/resources/sql/postgresql.iq
+++ b/babel/src/test/resources/sql/postgresql.iq
@@ -50,6 +50,57 @@ EXPR$0
 ghi
 !ok
 
+# Test string_to_array function
+select string_to_array('a,b,c', ',', 'd');
+EXPR$0
+[a, b, c]
+!ok
+
+select string_to_array('a,b,,d', ',', 'd');
+EXPR$0
+[a, b, , null]
+!ok
+
+select string_to_array('a,b,,d', ',', null);
+EXPR$0
+[a, b, , d]
+!ok
+
+select string_to_array('abc', '');
+EXPR$0
+[abc]
+!ok
+
+select string_to_array('abc', ',', 'abc');
+EXPR$0
+[null]
+!ok
+
+select string_to_array('calcite apache org', ' ', 'apache');
+EXPR$0
+[calcite, null, org]
+!ok
+
+select string_to_array('calcite apache org', ' ');
+EXPR$0
+[calcite, apache, org]
+!ok
+
+select string_to_array('a*c', NULL, '*');
+EXPR$0
+[a, null, c]
+!ok
+
+select string_to_array(NULL, ' ');
+EXPR$0
+null
+!ok
+
+select string_to_array('', '');
+EXPR$0
+[]
+!ok
+
 # Test coercion string to array inside INSERT
 create table sal_emp (name varchar, pay_by_quarter int array, schedule varchar 
array array);
 (0 rows modified)
diff --git 
a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java 
b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index d182eff6e3..d6940f7cc3 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -309,6 +309,7 @@
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.SPLIT_PART;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.STARTS_WITH;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.STRCMP;
+import static org.apache.calcite.sql.fun.SqlLibraryOperators.STRING_TO_ARRAY;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.STR_TO_MAP;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.SUBSTRING_INDEX;
 import static org.apache.calcite.sql.fun.SqlLibraryOperators.SYSDATE;
@@ -1071,6 +1072,7 @@ void populate2() {
       defineMethod(ARRAY_SLICE, BuiltInMethod.ARRAY_SLICE.method, 
NullPolicy.STRICT);
       defineMethod(ARRAY_TO_STRING, BuiltInMethod.ARRAY_TO_STRING.method,
           NullPolicy.STRICT);
+      defineMethod(STRING_TO_ARRAY, BuiltInMethod.STRING_TO_ARRAY.method, 
NullPolicy.ARG0);
       defineMethod(ARRAY_UNION, BuiltInMethod.ARRAY_UNION.method, 
NullPolicy.ANY);
       defineMethod(ARRAYS_OVERLAP, BuiltInMethod.ARRAYS_OVERLAP.method, 
NullPolicy.ANY);
       defineMethod(ARRAYS_ZIP, BuiltInMethod.ARRAYS_ZIP.method, 
NullPolicy.ANY);
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 768767e9d6..04baae8128 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -6615,6 +6615,39 @@ public static String arrayToString(List list, String 
delimiter, @Nullable String
     return sb.toString();
   }
 
+  /** SQL {@code STRING_TO_ARRAY(string, delimiter)} function.
+   * Returns a one-dimensional string[] array by splitting the
+   * input string value into subvalues using the specified string value as the 
"delimiter".
+   * Optionally, allows a specified string value to be interpreted as NULL. */
+  public static List<@Nullable String> stringToArray(
+      String string, @Nullable String delimiter) {
+    return stringToArray(string, delimiter, null);
+  }
+
+  /** SQL {@code STRING_TO_ARRAY(string, delimiter, nullString)} function. */
+  public static List<@Nullable String> stringToArray(
+      String string, @Nullable String delimiter, @Nullable String nullString) {
+    String[] parts;
+    if (delimiter == null) {
+      parts = string.chars()
+          .mapToObj(c -> Character.toString((char) c))
+          .toArray(String[]::new);
+    } else if (delimiter.isEmpty()) {
+      parts = new String[]{string};
+    } else {
+      parts = string.split(delimiter);
+    }
+    List<@Nullable String> result = new ArrayList<>(parts.length);
+    for (String part : parts) {
+      if (nullString != null && nullString.equals(part)) {
+        result.add(null);
+      } else {
+        result.add(part);
+      }
+    }
+    return result;
+  }
+
   /**
    * Function that, given a certain List containing single-item structs (i.e. 
arrays / lists with
    * a single item), builds an Enumerable that returns those single items 
inside the structs.
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java 
b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index a870757ef7..1063b9df90 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -905,6 +905,9 @@ public enum SqlKind {
   /** {@code STARTS_WITH} function. */
   STARTS_WITH,
 
+  /** {@code STRING_TO_ARRAY} function (PostgreSQL semantics). */
+  STRING_TO_ARRAY,
+
   /** Call to a function using JDBC function syntax. */
   JDBC_FN,
 
@@ -1844,6 +1847,7 @@ public SqlKind getFunctionKind() {
     case REVERSE:
     case REVERSE_SPARK:
     case SOUNDEX_SPARK:
+    case STRING_TO_ARRAY:
     case SUBSTR_BIG_QUERY:
     case SUBSTR_MYSQL:
     case SUBSTR_ORACLE:
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
index cd1cd08ac6..e3f234a6f0 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
@@ -408,6 +408,13 @@ static RelDataType deriveTypeSplit(SqlOperatorBinding 
operatorBinding,
           OperandTypes.STRING_INTEGER_OPTIONAL_INTEGER,
           SqlFunctionCategory.STRING);
 
+  /** The "STRING_TO_ARRAY(string, delimiter [, null_string ])" function 
(PostgreSQL). */
+  @LibraryOperator(libraries = {POSTGRESQL})
+  public static final SqlFunction STRING_TO_ARRAY =
+      SqlBasicFunction.create(SqlKind.STRING_TO_ARRAY,
+          ReturnTypes.TO_ARRAY_NULLABLE,
+          OperandTypes.STRING_STRING_OPTIONAL_STRING);
+
   /** The "ENDS_WITH(value1, value2)" function (BigQuery). */
   @LibraryOperator(libraries = {BIG_QUERY})
   public static final SqlBasicFunction ENDS_WITH =
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java 
b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index ebfa61359b..3f472e382e 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -403,6 +403,8 @@ public enum BuiltInMethod {
   LOWER(SqlFunctions.class, "lower", String.class),
   ARRAY_TO_STRING(SqlFunctions.class, "arrayToString", List.class,
       String.class),
+  STRING_TO_ARRAY(SqlFunctions.class, "stringToArray", String.class, 
String.class,
+      String.class),
   SROUND(SqlFunctions.class, "sround", long.class),
   STRUNCATE(SqlFunctions.class, "struncate", long.class),
   ASCII(SqlFunctions.class, "ascii", String.class),
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 3a994d2460..1c55f4dd2b 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2945,6 +2945,7 @@ ### Dialect-specific Operators
 | s | MAP_FROM_ENTRIES(arrayOfRows)                  | Returns a map created 
from an arrays of row with two fields. Note that the number of fields in a row 
must be 2. Note that calcite is using the LAST_WIN strategy
 | s | STR_TO_MAP(string [, stringDelimiter [, keyValueDelimiter]]) | Returns a 
map after splitting the *string* into key/value pairs using delimiters. Default 
delimiters are ',' for *stringDelimiter* and ':' for *keyValueDelimiter*. Note 
that calcite is using the LAST_WIN strategy
 | s | SUBSTRING_INDEX(string, delim, count)          | Returns the substring 
from *string* before *count* occurrences of the delimiter *delim*. If *count* 
is positive, everything to the left of the final delimiter (counting from the 
left) is returned. If *count* is negative, everything to the right of the final 
delimiter (counting from the right) is returned. The function substring_index 
performs a case-sensitive match when searching for *delim*.
+| p r | STRING_TO_ARRAY(string, delimiter [, nullString ]) | Returns a 
one-dimensional string[] array by splitting the input string value into 
subvalues using the specified string value as the "delimiter". Optionally, 
allows a specified string value to be interpreted as NULL.
 | b m p r s h | MD5(string)                          | Calculates an MD5 
128-bit checksum of *string* and returns it as a hex string
 | m | MONTHNAME(date)                                | Returns the name, in 
the connection's locale, of the month in *datetime*; for example, for a locale 
of en, it will return 'February' for both DATE '2020-02-10' and TIMESTAMP 
'2020-02-10 10:10:10', and for a locale of zh, it will return '二月'
 | o r s | NVL(value1, value2)                        | Returns *value1* if 
*value1* is not null, otherwise *value2*
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 28a9b633a1..9313823fdc 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -12487,6 +12487,28 @@ private static void 
checkStringAggFuncFails(SqlOperatorFixture f) {
         false);
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6951";>[CALCITE-6951]
+   * Add STRING_TO_ARRAY function(enabled in PostgreSQL Library)</a>. */
+  @Test void testStringToArrayFunc() {
+    final SqlOperatorFixture f0 = fixture();
+    f0.setFor(SqlLibraryOperators.STRING_TO_ARRAY);
+    final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.POSTGRESQL);
+    f.checkNull("string_to_array(NULL, ' ')");
+    f.checkScalar("string_to_array('', '')", "[]",
+        "CHAR(0) NOT NULL ARRAY NOT NULL");
+    f.checkScalar("string_to_array('ab', NULL)",
+        "[a, b]", "CHAR(2) NOT NULL ARRAY");
+    f.checkScalar("string_to_array('www apache org', ' ')",
+        "[www, apache, org]", "CHAR(14) NOT NULL ARRAY NOT NULL");
+    f.checkScalar("string_to_array('www apache org', ' ', 'apache')",
+        "[www, null, org]", "CHAR(14) NOT NULL ARRAY NOT NULL");
+    f.checkFails("^string_to_array(NULL)^",
+        "Invalid number of arguments to function 'STRING_TO_ARRAY'.*", false);
+    f.checkFails("^string_to_array(NULL, NULL, NULL, NULL)^",
+        "Invalid number of arguments to function 'STRING_TO_ARRAY'.*", false);
+  }
+
   @Test void testGroupConcatFunc() {
     final SqlOperatorFixture f = fixture();
     checkGroupConcatFunc(f.withLibrary(SqlLibrary.MYSQL));

Reply via email to