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

alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 95d92e85c08 IGNITE-24350 SQL Calcite: Forbid to register user defined 
function with duplicated signature - Fixes #11837.
95d92e85c08 is described below

commit 95d92e85c08bb2b39bc422d64c46fc1535e2bf2b
Author: Vladimir Steshin <[email protected]>
AuthorDate: Fri Feb 14 21:45:36 2025 +0300

    IGNITE-24350 SQL Calcite: Forbid to register user defined function with 
duplicated signature - Fixes #11837.
    
    Signed-off-by: Aleksey Plekhanov <[email protected]>
---
 .../query/calcite/schema/IgniteSchema.java         | 23 +++++++++++
 .../UserDefinedFunctionsIntegrationTest.java       | 44 ++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteSchema.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteSchema.java
index 2e032f66067..6d22ac2d51d 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteSchema.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteSchema.java
@@ -18,16 +18,20 @@
 package org.apache.ignite.internal.processors.query.calcite.schema;
 
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
 import org.apache.calcite.schema.Function;
+import org.apache.calcite.schema.FunctionParameter;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.tools.FrameworkConfig;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
 
 /**
  * Ignite schema.
@@ -90,6 +94,25 @@ public class IgniteSchema extends AbstractSchema {
      * @param func SQL function.
      */
     public void addFunction(String name, Function func) {
+        for (Function existingFun : getFunctions(name)) {
+            List<FunctionParameter> params = func.getParameters();
+            List<FunctionParameter> existingParams = 
existingFun.getParameters();
+
+            if (params.size() != existingParams.size())
+                continue;
+
+            for (int i = 0; i < params.size(); ++i) {
+                FunctionParameter p = params.get(i);
+                FunctionParameter existingP = existingParams.get(i);
+
+                if 
(!p.getType(Commons.typeFactory()).equalsSansFieldNames(existingP.getType(Commons.typeFactory())))
+                    break;
+            }
+
+            throw new IgniteException("Unable to register function '" + name + 
"'. Other function with the same " +
+                "name and parameters is already registered in schema '" + 
schemaName + "'.");
+        }
+
         funcMap.put(name, func);
     }
 
diff --git 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/UserDefinedFunctionsIntegrationTest.java
 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/UserDefinedFunctionsIntegrationTest.java
index f46b0bb2f96..ac2e9acecc3 100644
--- 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/UserDefinedFunctionsIntegrationTest.java
+++ 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/UserDefinedFunctionsIntegrationTest.java
@@ -64,6 +64,35 @@ public class UserDefinedFunctionsIntegrationTest extends 
AbstractBasicIntegratio
         return cfg;
     }
 
+    /** */
+    @Test
+    public void testSameSignatureNotRegistered() throws Exception {
+        LogListener logChecker = LogListener.matches("Unable to register 
function 'SAMESIGN'. Other function " +
+            "with the same name and parameters is already registered").build();
+
+        listeningLog.registerListener(logChecker);
+
+        // Actually, we might use QuerySqlFunction#alias instead of declaring 
additional method holding class (OtherFunctionsLibrary2).
+        // But Class#getDeclaredMethods() seems to give methods with a 
different order. If we define methods with one class,
+        // we can get one 'sameSign' registered before another. And the test 
would become flaky.
+        client.getOrCreateCache(new CacheConfiguration<Integer, Object>("emp")
+            .setSqlFunctionClasses(OtherFunctionsLibrary.class, 
OtherFunctionsLibrary2.class));
+
+        // Ensure that 1::INTEGER isn't returned by 
OtherFunctionsLibrary2#sameSign(int).
+        assertQuery("SELECT \"emp\".sameSign(1)").returns("echo_1").check();
+
+        // Ensure that OtherFunctionsLibrary#sameSign2(int) isn't registered.
+        assertThrows("SELECT \"emp\".sameSign2(1)", 
SqlValidatorException.class,
+            "No match found for function signature SAMESIGN2");
+
+        assertTrue(logChecker.check(getTestTimeout()));
+
+        SchemaPlus schema = 
queryProcessor(client).schemaHolder().schema("emp");
+
+        assertEquals(1, schema.getFunctions("SAMESIGN").size());
+    }
+
+
     /** */
     @Test
     public void testSystemFunctionOverriding() throws Exception {
@@ -618,6 +647,21 @@ public class UserDefinedFunctionsIntegrationTest extends 
AbstractBasicIntegratio
         public static String echo(String s) {
             return s;
         }
+
+        /** The signature interferes with aliased {@link 
OtherFunctionsLibrary2#sameSign2(int)}. */
+        @QuerySqlFunction
+        public static String sameSign(int v) {
+            return "echo_" + v;
+        }
+    }
+
+    /** */
+    public static class OtherFunctionsLibrary2 {
+        /** The aliased signature interferes with {@link 
OtherFunctionsLibrary#sameSign(int)}. */
+        @QuerySqlFunction(alias = "sameSign")
+        public static int sameSign2(int v) {
+            return v;
+        }
     }
 
     /** */

Reply via email to