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

tanner 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 88a415032c [CALCITE-6182] Add LENGTH/LEN functions (enabled in 
Snowflake library)
88a415032c is described below

commit 88a415032c0c54bba18d192a4333f56b1da240c1
Author: Tanner Clary <[email protected]>
AuthorDate: Tue Dec 26 08:59:18 2023 -0800

    [CALCITE-6182] Add LENGTH/LEN functions (enabled in Snowflake library)
---
 .../src/main/java/org/apache/calcite/sql/SqlKind.java |  3 +++
 .../calcite/sql/dialect/SnowflakeSqlDialect.java      |  5 +++++
 .../apache/calcite/sql/fun/SqlLibraryOperators.java   |  7 ++++++-
 .../apache/calcite/sql/fun/SqlStdOperatorTable.java   |  5 ++---
 .../calcite/sql2rel/StandardConvertletTable.java      |  2 ++
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java    | 17 +++++++++++++++++
 site/_docs/reference.md                               |  3 ++-
 .../java/org/apache/calcite/test/SqlOperatorTest.java | 19 ++++++++++++++++++-
 8 files changed, 55 insertions(+), 6 deletions(-)

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 381531a82b..5375ee6748 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -806,6 +806,9 @@ public enum SqlKind {
   /** {@code SUBSTR} function (PostgreSQL semantics). */
   SUBSTR_POSTGRESQL,
 
+  /** {@code CHAR_LENGTH} function. */
+  CHAR_LENGTH,
+
   /** {@code ENDS_WITH} function. */
   ENDS_WITH,
 
diff --git 
a/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java 
b/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java
index 32c2874298..f7d8741491 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java
@@ -43,6 +43,11 @@ public class SnowflakeSqlDialect extends SqlDialect {
   @Override public void unparseCall(final SqlWriter writer, final SqlCall 
call, final int leftPrec,
       final int rightPrec) {
     switch (call.getKind()) {
+    case CHAR_LENGTH:
+      SqlCall lengthCall = SqlLibraryOperators.LENGTH
+          .createCall(SqlParserPos.ZERO, call.getOperandList());
+      super.unparseCall(writer, lengthCall, leftPrec, rightPrec);
+      break;
     case ENDS_WITH:
       SqlCall endsWithCall = SqlLibraryOperators.ENDSWITH
           .createCall(SqlParserPos.ZERO, call.getOperandList());
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 878e7e0ab3..d4c8b9d1ea 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
@@ -274,8 +274,13 @@ public abstract class SqlLibraryOperators {
   @LibraryOperator(libraries = {BIG_QUERY})
   public static final SqlFunction IFNULL = NVL.withName("IFNULL");
 
+  /** The "LEN(string)" function. */
+  @LibraryOperator(libraries = {SNOWFLAKE})
+  public static final SqlFunction LEN =
+      SqlStdOperatorTable.CHAR_LENGTH.withName("LEN");
+
   /** The "LENGTH(string)" function. */
-  @LibraryOperator(libraries = {BIG_QUERY})
+  @LibraryOperator(libraries = {BIG_QUERY, SNOWFLAKE})
   public static final SqlFunction LENGTH =
       SqlStdOperatorTable.CHAR_LENGTH.withName("LENGTH");
 
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 40ec61d624..4b07e5ad01 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -1613,10 +1613,9 @@ public class SqlStdOperatorTable extends 
ReflectiveSqlOperatorTable {
   public static final SqlFunction POSITION = new 
SqlPositionFunction("POSITION");
 
   public static final SqlBasicFunction CHAR_LENGTH =
-      SqlBasicFunction.create("CHAR_LENGTH",
+      SqlBasicFunction.create(SqlKind.CHAR_LENGTH,
           ReturnTypes.INTEGER_NULLABLE,
-          OperandTypes.CHARACTER,
-          SqlFunctionCategory.NUMERIC);
+          OperandTypes.CHARACTER);
 
   /** Alias for {@link #CHAR_LENGTH}. */
   public static final SqlFunction CHARACTER_LENGTH =
diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java 
b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index 69666ffd34..d9bc1d27d5 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -120,6 +120,8 @@ public class StandardConvertletTable extends 
ReflectiveConvertletTable {
 
     // Register aliases (operators which have a different name but
     // identical behavior to other operators).
+    addAlias(SqlLibraryOperators.LEN,
+        SqlStdOperatorTable.CHAR_LENGTH);
     addAlias(SqlLibraryOperators.LENGTH,
         SqlStdOperatorTable.CHAR_LENGTH);
     addAlias(SqlStdOperatorTable.CHARACTER_LENGTH,
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 3a4c480aa3..7a5bc0c499 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
@@ -6696,6 +6696,23 @@ class RelToSqlConverterTest {
     
sql(query).withLibrary(SqlLibrary.SNOWFLAKE).withSnowflake().ok(expectedSnowflake);
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6182";>[CALCITE-6182]
+   * Add LENGTH/LEN functions (enabled in Snowflake library)</a>. */
+  @Test void testSnowflakeLength() {
+    final String query = "select CHAR_LENGTH(\"brand_name\")\n"
+        + "from \"product\"";
+    final String expectedBigQuery = "SELECT CHAR_LENGTH(brand_name)\n"
+        + "FROM foodmart.product";
+    // Snowflake would accept either LEN or LENGTH, but we currently unparse 
into "LENGTH"
+    // since it seems to be used across more dialects.
+    final String expectedSnowflake = "SELECT LENGTH(\"brand_name\")\n"
+        + "FROM \"foodmart\".\"product\"";
+    Sql sql = sql(query).withLibrary(SqlLibrary.BIG_QUERY);
+    sql.withBigQuery().ok(expectedBigQuery);
+    sql.withSnowflake().ok(expectedSnowflake);
+  }
+
   @Test void testSubstringInSpark() {
     final String query = "select substring(\"brand_name\" from 2) "
         + "from \"product\"\n";
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 841c42650c..3f97448543 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -2769,7 +2769,8 @@ In the following:
 | m | JSON_STORAGE_SIZE(jsonValue)                   | Returns the number of 
bytes used to store the binary representation of *jsonValue*
 | b o | LEAST(expr [, expr ]* )                      | Returns the least of 
the expressions
 | b m p | LEFT(string, length)                       | Returns the leftmost 
*length* characters from the *string*
-| b | LENGTH(string)                                 | Equivalent to 
`CHAR_LENGTH(string)`
+| f | LEN(string)                                    | Equivalent to 
`CHAR_LENGTH(string)`
+| b f | LENGTH(string)                               | Equivalent to 
`CHAR_LENGTH(string)`
 | h s | LEVENSHTEIN(string1, string2)                | Returns the Levenshtein 
distance between *string1* and *string2*
 | b | LOG(numeric1 [, numeric2 ])                    | Returns the logarithm 
of *numeric1* to base *numeric2*, or base e if *numeric2* is not present
 | b o | LPAD(string, length [, pattern ])            | Returns a string or 
bytes value that consists of *string* prepended to *length* with *pattern*
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 583fd06882..0e270b7280 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -4111,6 +4111,23 @@ public class SqlOperatorTest {
     f.checkNull("CHARACTER_LENGTH(cast(null as varchar(1)))");
   }
 
+  /** Tests {@code LEN} function from Snowflake. {@code LEN} is a
+  * Snowflake-specific alias for {@code CHAR_LENGTH}. */
+  @Test void testLenFunc() {
+    final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.LEN);
+    f0.checkFails("^len('hello')^",
+        "No match found for function signature LEN\\(<CHARACTER>\\)",
+        false);
+    final SqlOperatorFixture f = f0.withLibrary(SqlLibrary.SNOWFLAKE);
+    f.checkScalar("len('hello')", "5", "INTEGER NOT NULL");
+    f.checkScalar("len('')", "0", "INTEGER NOT NULL");
+    f.checkScalar("len(CAST('x' as CHAR(3)))", "3", "INTEGER NOT NULL");
+    f.checkScalar("len(CAST('x' as VARCHAR(4)))", "1", "INTEGER NOT NULL");
+    f.checkNull("len(CAST(NULL as CHAR(5)))");
+  }
+
+  /** Tests {@code LENGTH} function from Big Query/Snowflake. {@code LENGTH} 
is a
+  * BQ/Snowflake-specific alias for {@code CHAR_LENGTH}. */
   @Test void testLengthFunc() {
     final SqlOperatorFixture f0 = fixture().setFor(SqlLibraryOperators.LENGTH);
     f0.checkFails("^length('hello')^",
@@ -4125,7 +4142,7 @@ public class SqlOperatorTest {
       f.checkNull("length(CAST(NULL as CHAR(5)))");
     };
 
-    f0.forEachLibrary(list(SqlLibrary.BIG_QUERY), consumer);
+    f0.forEachLibrary(list(SqlLibrary.BIG_QUERY, SqlLibrary.SNOWFLAKE), 
consumer);
   }
 
   @Test void testOctetLengthFunc() {

Reply via email to