Repository: calcite
Updated Branches:
  refs/heads/master 3b4e17142 -> 25a7d938d


[CALCITE-1434] User-defined aggregate function that uses a generic interface 
(Arun Mahadevan)

AggregateFunctionImpl doesn't work if the class implements a generic
interface. To make it work, kip bridge methods in
ReflectiveFunctionBase.findMethod so that user defined aggregate
functions can implement generic interfaces.

Close apache/calcite#308


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/55ba6b58
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/55ba6b58
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/55ba6b58

Branch: refs/heads/master
Commit: 55ba6b58363d8fc2a16aa02fd1ee998bc2c9b9e4
Parents: 3b4e171
Author: Arun Mahadevan <ar...@apache.org>
Authored: Thu Oct 13 16:31:54 2016 +0530
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 17 15:04:56 2016 -0700

----------------------------------------------------------------------
 .../schema/impl/ReflectiveFunctionBase.java     |  2 +-
 .../java/org/apache/calcite/test/UdfTest.java   | 57 ++++++++++++++++++++
 .../java/org/apache/calcite/util/Smalls.java    | 32 +++++++++++
 3 files changed, 90 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/55ba6b58/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java 
b/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java
index ab0daf5..981d652 100644
--- 
a/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java
+++ 
b/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java
@@ -82,7 +82,7 @@ public abstract class ReflectiveFunctionBase implements 
Function {
    */
   static Method findMethod(Class<?> clazz, String name) {
     for (Method method : clazz.getMethods()) {
-      if (method.getName().equals(name)) {
+      if (method.getName().equals(name) && !method.isBridge()) {
         return method;
       }
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/55ba6b58/core/src/test/java/org/apache/calcite/test/UdfTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/UdfTest.java 
b/core/src/test/java/org/apache/calcite/test/UdfTest.java
index c5058ed..a486a9a 100644
--- a/core/src/test/java/org/apache/calcite/test/UdfTest.java
+++ b/core/src/test/java/org/apache/calcite/test/UdfTest.java
@@ -440,6 +440,63 @@ public class UdfTest {
         "Caused by: java.lang.RuntimeException: In user-defined aggregate 
class 'org.apache.calcite.util.Smalls$SumFunctionBadIAdd', first parameter to 
'add' method must be the accumulator (the return type of the 'init' method)");
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-1434";>[CALCITE-1434]
+   * AggregateFunctionImpl doesnt work if the class implements a generic
+   * interface</a>. */
+  @Test public void testUserDefinedAggregateFunctionImplementsInterface() {
+    final String empDept = JdbcTest.EmpDeptTableFactory.class.getName();
+    final String mySum3 = Smalls.MySum3.class.getName();
+    final String model = "{\n"
+        + "  version: '1.0',\n"
+        + "   schemas: [\n"
+        + "     {\n"
+        + "       name: 'adhoc',\n"
+        + "       tables: [\n"
+        + "         {\n"
+        + "           name: 'EMPLOYEES',\n"
+        + "           type: 'custom',\n"
+        + "           factory: '" + empDept + "',\n"
+        + "           operand: {'foo': true, 'bar': 345}\n"
+        + "         }\n"
+        + "       ],\n"
+        + "       functions: [\n"
+        + "         {\n"
+        + "           name: 'MY_SUM3',\n"
+        + "           className: '" + mySum3 + "'\n"
+        + "         }\n"
+        + "       ]\n"
+        + "     }\n"
+        + "   ]\n"
+        + "}";
+    final CalciteAssert.AssertThat with = CalciteAssert.model(model)
+        .withDefaultSchema("adhoc");
+
+    with.query("select my_sum3(\"deptno\") as p from EMPLOYEES\n")
+        .returns("P=50\n");
+    with.withDefaultSchema(null)
+        .query("select \"adhoc\".my_sum3(\"deptno\") as p\n"
+            + "from \"adhoc\".EMPLOYEES\n")
+        .returns("P=50\n");
+    with.query("select my_sum3(\"empid\"), \"deptno\" as p from EMPLOYEES\n")
+        .throws_("Expression 'deptno' is not being grouped");
+    with.query("select my_sum3(\"deptno\") as p from EMPLOYEES\n")
+        .returns("P=50\n");
+    with.query("select my_sum3(\"name\") as p from EMPLOYEES\n")
+        .throws_("Cannot apply 'MY_SUM3' to arguments of type "
+            + "'MY_SUM3(<JAVATYPE(CLASS JAVA.LANG.STRING)>)'. "
+            + "Supported form(s): 'MY_SUM3(<NUMERIC>)");
+    with.query("select my_sum3(\"deptno\", 1) as p from EMPLOYEES\n")
+        .throws_("No match found for function signature "
+            + "MY_SUM3(<NUMERIC>, <NUMERIC>)");
+    with.query("select my_sum3() as p from EMPLOYEES\n")
+        .throws_("No match found for function signature MY_SUM3()");
+    with.query("select \"deptno\", my_sum3(\"deptno\") as p from EMPLOYEES\n"
+        + "group by \"deptno\"")
+        .returnsUnordered("deptno=20; P=20",
+            "deptno=10; P=30");
+  }
+
   private static CalciteAssert.AssertThat withBadUdf(Class clazz) {
     final String empDept = JdbcTest.EmpDeptTableFactory.class.getName();
     final String className = clazz.getName();

http://git-wip-us.apache.org/repos/asf/calcite/blob/55ba6b58/core/src/test/java/org/apache/calcite/util/Smalls.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/Smalls.java 
b/core/src/test/java/org/apache/calcite/util/Smalls.java
index af06df5..2f1cc51 100644
--- a/core/src/test/java/org/apache/calcite/util/Smalls.java
+++ b/core/src/test/java/org/apache/calcite/util/Smalls.java
@@ -469,6 +469,38 @@ public class Smalls {
     }
   }
 
+  /** A generic interface for defining user defined aggregate functions */
+  private interface MyGenericAggFunction<A, V, R> {
+    A init();
+
+    A add(A accumulator, V val);
+
+    A merge(A accumulator1, A accumulator2);
+
+    R result(A accumulator);
+  }
+
+  /** Example of a user-defined aggregate function that implements a generic
+   * interface. */
+  public static class MySum3
+      implements MyGenericAggFunction<Integer, Integer, Integer> {
+    public Integer init() {
+      return 0;
+    }
+
+    public Integer add(Integer accumulator, Integer val) {
+      return accumulator + val;
+    }
+
+    public Integer merge(Integer accumulator1, Integer accumulator2) {
+      return accumulator1 + accumulator2;
+    }
+
+    public Integer result(Integer accumulator) {
+      return accumulator;
+    }
+  }
+
   /** Example of a user-defined aggregate function (UDAF), whose methods are
    * static. */
   public static class MyStaticSumFunction {

Reply via email to