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

mbudiu 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 b60598b47e [CALCITE-6518] ClassCastException during validation when 
loading multiple libraries
b60598b47e is described below

commit b60598b47e86b2b21639d193b374f1d6d4dcd139
Author: Mihai Budiu <[email protected]>
AuthorDate: Mon Aug 12 23:39:01 2024 -0700

    [CALCITE-6518] ClassCastException during validation when loading multiple 
libraries
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 .../java/org/apache/calcite/sql/SqlFunction.java   |  4 +-
 .../main/java/org/apache/calcite/sql/SqlKind.java  | 94 +++++++++++++++++++++-
 .../main/java/org/apache/calcite/sql/SqlUtil.java  |  3 +-
 .../main/java/org/apache/calcite/util/Util.java    |  2 +-
 .../calcite/sql/test/SqlOperatorFixture.java       | 15 ++++
 .../org/apache/calcite/test/SqlOperatorTest.java   |  8 ++
 6 files changed, 122 insertions(+), 4 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java 
b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
index 626c28eb07..57e4748563 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
@@ -310,7 +310,9 @@ public class SqlFunction extends SqlOperator {
           // if we succeed, the arguments would be wrapped with CAST operator.
           if (function != null) {
             TypeCoercion typeCoercion = validator.getTypeCoercion();
-            if (typeCoercion.userDefinedFunctionCoercion(scope, call, 
function)) {
+            if ((function.category == SqlFunctionCategory.USER_DEFINED_FUNCTION
+                || function.category == 
SqlFunctionCategory.USER_DEFINED_TABLE_FUNCTION)
+                && typeCoercion.userDefinedFunctionCoercion(scope, call, 
function)) {
               break validCoercionType;
             }
           }
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 e292990e47..70094d1b49 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -29,7 +29,7 @@ import java.util.Set;
  * Enumerates the possible types of {@link SqlNode}.
  *
  * <p>The values are immutable, canonical constants, so you can use Kinds to
- * find particular types of expressions quickly. To identity a call to a common
+ * find particular types of expressions quickly. To identify a call to a common
  * operator such as '=', use {@link org.apache.calcite.sql.SqlNode#isA}:
  *
  * <blockquote>
@@ -1715,6 +1715,98 @@ public enum SqlKind {
     return category.contains(this);
   }
 
+  /**
+   * If this kind represents a non-standard function, return OTHER_FUNCTION, 
otherwise
+   * return this.  Do not add standard functions here.
+   */
+  public SqlKind getFunctionKind() {
+    switch (this) {
+    case CONVERT:
+    case TRANSLATE:
+    case POSITION:
+    case DECODE:
+    case NVL:
+    case NVL2:
+    case GREATEST:
+    case GREATEST_PG:
+    case CONCAT2:
+    case CONCAT_WITH_NULL:
+    case CONCAT_WS_MSSQL:
+    case CONCAT_WS_POSTGRESQL:
+    case CONCAT_WS_SPARK:
+    case IF:
+    case LEAST:
+    case LEAST_PG:
+    case LOG:
+    case DATE_ADD:
+    case DATE_TRUNC:
+    case DATE_SUB:
+    case TIME_ADD:
+    case TIME_SUB:
+    case TIMESTAMP_ADD:
+    case TIMESTAMP_DIFF:
+    case TIMESTAMP_SUB:
+    case SAFE_CAST:
+    case FLOOR:
+    case CEIL:
+    case TRIM:
+    case LTRIM:
+    case RTRIM:
+    case ARRAY_APPEND:
+    case ARRAY_COMPACT:
+    case ARRAY_CONCAT:
+    case ARRAY_CONTAINS:
+    case ARRAY_DISTINCT:
+    case ARRAY_EXCEPT:
+    case ARRAY_INSERT:
+    case ARRAY_INTERSECT:
+    case ARRAY_JOIN:
+    case ARRAY_LENGTH:
+    case ARRAY_MAX:
+    case ARRAY_MIN:
+    case ARRAY_POSITION:
+    case ARRAY_PREPEND:
+    case ARRAY_REMOVE:
+    case ARRAY_REPEAT:
+    case ARRAY_REVERSE:
+    case ARRAY_SIZE:
+    case ARRAY_TO_STRING:
+    case ARRAY_UNION:
+    case ARRAYS_OVERLAP:
+    case ARRAYS_ZIP:
+    case SORT_ARRAY:
+    case MAP_CONCAT:
+    case MAP_ENTRIES:
+    case MAP_KEYS:
+    case MAP_VALUES:
+    case MAP_CONTAINS_KEY:
+    case MAP_FROM_ARRAYS:
+    case MAP_FROM_ENTRIES:
+    case STR_TO_MAP:
+    case REVERSE:
+    case REVERSE_SPARK:
+    case SOUNDEX_SPARK:
+    case SUBSTR_BIG_QUERY:
+    case SUBSTR_MYSQL:
+    case SUBSTR_ORACLE:
+    case SUBSTR_POSTGRESQL:
+    case CHAR_LENGTH:
+    case ENDS_WITH:
+    case STARTS_WITH:
+    case JSON_TYPE:
+    case CONTAINS_SUBSTR:
+    case ST_DWITHIN:
+    case ST_POINT:
+    case ST_POINT3:
+    case ST_MAKE_LINE:
+    case ST_CONTAINS:
+    case HILBERT:
+      return OTHER_FUNCTION;
+    default:
+      return this;
+    }
+  }
+
   @SafeVarargs
   private static <E extends Enum<E>> EnumSet<E> concat(EnumSet<E> set0,
       EnumSet<E>... sets) {
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java 
b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
index edb50aac38..d0c9157b56 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
@@ -519,7 +519,8 @@ public abstract class SqlUtil {
   private static Iterator<SqlOperator> filterOperatorRoutinesByKind(
       Iterator<SqlOperator> routines, final SqlKind sqlKind) {
     return Iterators.filter(routines,
-        operator -> Objects.requireNonNull(operator, "operator").getKind() == 
sqlKind);
+        operator -> Objects.requireNonNull(operator, "operator")
+            .getKind().getFunctionKind() == sqlKind);
   }
 
   /**
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java 
b/core/src/main/java/org/apache/calcite/util/Util.java
index e08f8f5b75..9e3bfbbc3b 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -1075,7 +1075,7 @@ public class Util {
    * feature has not been implemented, but should be.
    *
    * <p>If every 'hole' in our functionality uses this method, it will be
-   * easier for us to identity the holes. Throwing a
+   * easier for us to identify the holes. Throwing a
    * {@link java.lang.UnsupportedOperationException} isn't as good, because
    * sometimes we actually want to partially implement an API.
    *
diff --git 
a/testkit/src/main/java/org/apache/calcite/sql/test/SqlOperatorFixture.java 
b/testkit/src/main/java/org/apache/calcite/sql/test/SqlOperatorFixture.java
index a4e2d0aaab..db200847c5 100644
--- a/testkit/src/main/java/org/apache/calcite/sql/test/SqlOperatorFixture.java
+++ b/testkit/src/main/java/org/apache/calcite/sql/test/SqlOperatorFixture.java
@@ -39,6 +39,8 @@ import org.apache.calcite.util.Bug;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.UnaryOperator;
 
@@ -568,6 +570,19 @@ public interface SqlOperatorFixture extends AutoCloseable {
                 .with(CalciteConnectionProperty.FUN, library.fun));
   }
 
+  default SqlOperatorFixture withLibraries(SqlLibrary... libraries) {
+    List<String> names = new ArrayList<>();
+    for (SqlLibrary lib : libraries) {
+      names.add(lib.fun);
+    }
+    return withOperatorTable(
+        SqlLibraryOperatorTableFactory.INSTANCE
+            .getOperatorTable(libraries))
+        .withConnectionFactory(cf ->
+            cf.with(ConnectionFactories.add(CalciteAssert.SchemaSpec.HR))
+                .with(CalciteConnectionProperty.FUN, String.join(",", names)));
+  }
+
   /** Applies this fixture to some code for each of the given libraries. */
   default void forEachLibrary(Iterable<? extends SqlLibrary> libraries,
       Consumer<SqlOperatorFixture> consumer) {
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 c14b6d0003..d6563f3aff 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -2424,6 +2424,14 @@ public class SqlOperatorTest {
     f.checkFails("^concat()^", INVALID_ARGUMENTS_NUMBER, false);
   }
 
+  /** Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-6518";>
+   * ClassCastException during validation when loading multiple libraries</a>. 
*/
+  @Test void testManyLibraries() {
+    SqlOperatorFixture f =
+        fixture().withLibraries(SqlLibrary.STANDARD, SqlLibrary.MYSQL, 
SqlLibrary.POSTGRESQL);
+    f.checkScalar("substr('a', 1, 2)", "a", "VARCHAR(1) NOT NULL");
+  }
+
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5771";>[CALCITE-5771]
    * Apply two different NULL semantics for CONCAT function(enabled in MySQL,

Reply via email to