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 {