You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2017/07/06 23:00:39 UTC
[2/7] calcite git commit: [CALCITE-1833] User-defined aggregate
functions with more than one parameter (hzyuemeng1)
[CALCITE-1833] User-defined aggregate functions with more than one parameter (hzyuemeng1)
I don't like the fact that SqlUserDefinedAggregateFunction now has a
type factory field. I see why it is necessary - because the
SqlFunction.getParamTypes method does not take a type factory argument -
but we should consider changing it in future.
Close apache/calcite#481
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/47c8df9e
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/47c8df9e
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/47c8df9e
Branch: refs/heads/master
Commit: 47c8df9ecad8aa0c8a65530dd89b94b3749f54a2
Parents: f474652
Author: hzyuemeng1 <hz...@corp.netease.com>
Authored: Tue Jun 20 09:51:57 2017 +0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jul 6 11:24:37 2017 -0700
----------------------------------------------------------------------
.../calcite/prepare/CalciteCatalogReader.java | 2 +-
.../sql/validate/SqlUserDefinedAggFunction.java | 36 ++++++++-
.../java/org/apache/calcite/test/UdfTest.java | 81 +++++++++++++++++--
.../java/org/apache/calcite/util/Smalls.java | 82 ++++++++++++++++++++
4 files changed, 194 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/47c8df9e/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
index 9ec3df4..921191a 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
@@ -329,7 +329,7 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
} else if (function instanceof AggregateFunction) {
return new SqlUserDefinedAggFunction(name,
infer((AggregateFunction) function), InferTypes.explicit(argTypes),
- typeChecker, (AggregateFunction) function, false, false);
+ typeChecker, (AggregateFunction) function, false, false, typeFactory);
} else if (function instanceof TableMacro) {
return new SqlUserDefinedTableMacro(name, ReturnTypes.CURSOR,
InferTypes.explicit(argTypes), typeChecker, paramTypes,
http://git-wip-us.apache.org/repos/asf/calcite/blob/47c8df9e/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
index da1f833..a8be50b 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
@@ -16,8 +16,10 @@
*/
package org.apache.calcite.sql.validate;
+import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
import org.apache.calcite.schema.AggregateFunction;
import org.apache.calcite.schema.FunctionParameter;
import org.apache.calcite.sql.SqlAggFunction;
@@ -27,11 +29,13 @@ import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
import org.apache.calcite.sql.type.SqlOperandTypeInference;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
+import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.Util;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -42,17 +46,47 @@ import java.util.List;
*/
public class SqlUserDefinedAggFunction extends SqlAggFunction {
public final AggregateFunction function;
+ public final RelDataTypeFactory typeFactory;
/** Creates a SqlUserDefinedAggFunction. */
public SqlUserDefinedAggFunction(SqlIdentifier opName,
SqlReturnTypeInference returnTypeInference,
SqlOperandTypeInference operandTypeInference,
SqlOperandTypeChecker operandTypeChecker, AggregateFunction function,
- boolean requiresOrder, boolean requiresOver) {
+ boolean requiresOrder, boolean requiresOver, RelDataTypeFactory typeFactory) {
super(Util.last(opName.names), opName, SqlKind.OTHER_FUNCTION,
returnTypeInference, operandTypeInference, operandTypeChecker,
SqlFunctionCategory.USER_DEFINED_FUNCTION, requiresOrder, requiresOver);
this.function = function;
+ this.typeFactory = typeFactory;
+ }
+
+ @Override public List<RelDataType> getParamTypes() {
+ List<RelDataType> argTypes = new ArrayList<>();
+ for (FunctionParameter o : function.getParameters()) {
+ final RelDataType type = o.getType(typeFactory);
+ argTypes.add(type);
+ }
+ return toSql(argTypes);
+ }
+
+ private List<RelDataType> toSql(List<RelDataType> types) {
+ return Lists.transform(types,
+ new com.google.common.base.Function<RelDataType, RelDataType>() {
+ public RelDataType apply(RelDataType type) {
+ return toSql(type);
+ }
+ });
+ }
+
+ private RelDataType toSql(RelDataType type) {
+ if (type instanceof RelDataTypeFactoryImpl.JavaType
+ && ((RelDataTypeFactoryImpl.JavaType) type).getJavaClass()
+ == Object.class) {
+ return typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(SqlTypeName.ANY), true);
+ }
+ return JavaTypeFactoryImpl.toSql(typeFactory, type);
}
@SuppressWarnings("deprecation")
http://git-wip-us.apache.org/repos/asf/calcite/blob/47c8df9e/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 3297c27..3d0879f 100644
--- a/core/src/test/java/org/apache/calcite/test/UdfTest.java
+++ b/core/src/test/java/org/apache/calcite/test/UdfTest.java
@@ -463,8 +463,7 @@ public class UdfTest {
with.query("select my_sum(\"deptno\") as p from EMPLOYEES\n")
.returns("P=50\n");
with.query("select my_sum(\"name\") as p from EMPLOYEES\n")
- .throws_(
- "Cannot apply 'MY_SUM' to arguments of type 'MY_SUM(<JAVATYPE(CLASS JAVA.LANG.STRING)>)'. Supported form(s): 'MY_SUM(<NUMERIC>)");
+ .throws_("No match found for function signature MY_SUM(<CHARACTER>)");
with.query("select my_sum(\"deptno\", 1) as p from EMPLOYEES\n")
.throws_(
"No match found for function signature MY_SUM(<NUMERIC>, <NUMERIC>)");
@@ -481,6 +480,80 @@ public class UdfTest {
.returnsUnordered("deptno=20; P=20", "deptno=10; P=30");
}
+ /** Tests user-defined aggregate function. */
+ @Test public void testUserDefinedAggregateFunctionWithMultipleParameters() throws Exception {
+ final String empDept = JdbcTest.EmpDeptTableFactory.class.getName();
+ final String sum21 = Smalls.MyTwoParamsSumFunctionFilter1.class.getName();
+ final String sum22 = Smalls.MyTwoParamsSumFunctionFilter2.class.getName();
+ final String sum31 = Smalls.MyThreeParamsSumFunctionWithFilter1.class.getName();
+ final String sum32 = Smalls.MyThreeParamsSumFunctionWithFilter2.class.getName();
+ final CalciteAssert.AssertThat with = CalciteAssert.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_SUM2',\n"
+ + " className: '" + sum21 + "'\n"
+ + " },\n"
+ + " {\n"
+ + " name: 'MY_SUM2',\n"
+ + " className: '" + sum22 + "'\n"
+ + " },\n"
+ + " {\n"
+ + " name: 'MY_SUM3',\n"
+ + " className: '" + sum31 + "'\n"
+ + " },\n"
+ + " {\n"
+ + " name: 'MY_SUM3',\n"
+ + " className: '" + sum32 + "'\n"
+ + " }\n"
+ + " ]\n"
+ + " }\n"
+ + " ]\n"
+ + "}")
+ .withDefaultSchema("adhoc");
+ with.withDefaultSchema(null)
+ .query(
+ "select \"adhoc\".my_sum3(\"deptno\",\"name\",'Eric') as p from \"adhoc\".EMPLOYEES\n")
+ .returns("P=20\n");
+ with.query("select \"adhoc\".my_sum3(\"empid\",\"deptno\",\"commission\") as p "
+ + "from \"adhoc\".EMPLOYEES\n")
+ .returns("P=330\n");
+ with.query("select \"adhoc\".my_sum3(\"empid\",\"deptno\",\"commission\"),\"name\" as p "
+ + "from \"adhoc\".EMPLOYEES\n")
+ .throws_("Expression 'name' is not being grouped");
+ with.query("select \"name\",\"adhoc\".my_sum3(\"empid\",\"deptno\",\"commission\") as p "
+ + "from \"adhoc\".EMPLOYEES\n"
+ + "group by \"name\"")
+ .returnsUnordered("name=Theodore; P=0",
+ "name=Eric; P=220",
+ "name=Bill; P=110",
+ "name=Sebastian; P=0");
+ with.query("select \"adhoc\".my_sum3(\"empid\",\"deptno\",\"salary\") as p "
+ + "from \"adhoc\".EMPLOYEES\n")
+ .throws_("No match found for function signature MY_SUM3(<NUMERIC>, "
+ + "<NUMERIC>, <APPROXIMATE_NUMERIC>)");
+ with.query("select \"adhoc\".my_sum3(\"empid\",\"deptno\",\"name\") as p "
+ + "from \"adhoc\".EMPLOYEES\n");
+ with.query("select \"adhoc\".my_sum2(\"commission\",250) as p "
+ + "from \"adhoc\".EMPLOYEES\n")
+ .returns("P=1500\n");
+ with.query("select \"adhoc\".my_sum2(\"name\",250) as p from \"adhoc\".EMPLOYEES\n")
+ .throws_("No match found for function signature MY_SUM2(<CHARACTER>, <NUMERIC>)");
+ with.query("select \"adhoc\".my_sum2(\"empid\",0.0) as p from \"adhoc\".EMPLOYEES\n")
+ .throws_("No match found for function signature MY_SUM2(<NUMERIC>, <NUMERIC>)");
+ }
+
/** Test for
* {@link org.apache.calcite.runtime.CalciteResource#firstParameterOfAdd(String)}. */
@Test public void testUserDefinedAggregateFunction3() throws Exception {
@@ -531,9 +604,7 @@ public class UdfTest {
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>)");
+ .throws_("No match found for function signature MY_SUM3(<CHARACTER>)");
with.query("select my_sum3(\"deptno\", 1) as p from EMPLOYEES\n")
.throws_("No match found for function signature "
+ "MY_SUM3(<NUMERIC>, <NUMERIC>)");
http://git-wip-us.apache.org/repos/asf/calcite/blob/47c8df9e/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 c10d119..be5bd3e 100644
--- a/core/src/test/java/org/apache/calcite/util/Smalls.java
+++ b/core/src/test/java/org/apache/calcite/util/Smalls.java
@@ -553,6 +553,88 @@ public class Smalls {
}
}
+ /** Example of a user-defined aggregate function (UDAF). */
+ public static class MyTwoParamsSumFunctionFilter1 {
+ public MyTwoParamsSumFunctionFilter1() {
+ }
+ public int init() {
+ return 0;
+ }
+ public int add(int accumulator, int v1, int v2) {
+ if (v1 > v2) {
+ return accumulator + v1;
+ }
+ return accumulator;
+ }
+ public int merge(int accumulator0, int accumulator1) {
+ return accumulator0 + accumulator1;
+ }
+ public int result(int accumulator) {
+ return accumulator;
+ }
+ }
+
+ /** Example of a user-defined aggregate function (UDAF). */
+ public static class MyTwoParamsSumFunctionFilter2 {
+ public MyTwoParamsSumFunctionFilter2() {
+ }
+ public long init() {
+ return 0L;
+ }
+ public long add(long accumulator, int v1, String v2) {
+ if (v2.equals("Eric")) {
+ return accumulator + v1;
+ }
+ return accumulator;
+ }
+ public long merge(long accumulator0, long accumulator1) {
+ return accumulator0 + accumulator1;
+ }
+ public long result(long accumulator) {
+ return accumulator;
+ }
+ }
+
+ /** Example of a user-defined aggregate function (UDAF), whose methods are
+ * static. */
+ public static class MyThreeParamsSumFunctionWithFilter1 {
+ public static long init() {
+ return 0L;
+ }
+ public static long add(long accumulator, int v1, String v2, String v3) {
+ if (v2.equals(v3)) {
+ return accumulator + v1;
+ }
+ return accumulator;
+ }
+ public static long merge(long accumulator0, long accumulator1) {
+ return accumulator0 + accumulator1;
+ }
+ public static long result(long accumulator) {
+ return accumulator;
+ }
+ }
+
+ /** Example of a user-defined aggregate function (UDAF), whose methods are
+ * static. olny for validate to get exact function by calcite*/
+ public static class MyThreeParamsSumFunctionWithFilter2 {
+ public static long init() {
+ return 0L;
+ }
+ public static long add(long accumulator, int v1, int v2, int v3) {
+ if (v3 > 250) {
+ return accumulator + v1 + v2;
+ }
+ return accumulator;
+ }
+ public static long merge(long accumulator0, long accumulator1) {
+ return accumulator0 + accumulator1;
+ }
+ public static long result(long accumulator) {
+ return accumulator;
+ }
+ }
+
/** User-defined function. */
public static class SumFunctionBadIAdd {
public long init() {