This is an automated email from the ASF dual-hosted git repository. danny0405 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push: new d934d12 [CALCITE-3565] Explicitly cast assignable operand types to decimal for udf (DonnyZone) d934d12 is described below commit d934d121077f271331810827ce9cf7ccb5d4768e Author: wellfengzhu <wellfeng...@gmail.com> AuthorDate: Wed Dec 4 18:58:45 2019 +0800 [CALCITE-3565] Explicitly cast assignable operand types to decimal for udf (DonnyZone) During query execution, some of the assignable types need explicit conversion to the target types. i.e., Decimal expression should be converted to Integer before it is assigned to the Integer type Lvalue (In Java, Decimal can not be assigned to Integer directly). close apache/calcite#1628 --- .../calcite/adapter/enumerable/EnumUtils.java | 51 ++++++++++++++++++++++ .../ReflectiveCallNotNullImplementor.java | 2 + .../java/org/apache/calcite/test/JdbcTest.java | 16 +++++++ 3 files changed, 69 insertions(+) diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java index 02f7f7f..ea95bae 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java @@ -529,6 +529,57 @@ public class EnumUtils { || type == java.sql.Timestamp.class; } + /** + * In {@link org.apache.calcite.sql.type.SqlTypeAssignmentRule}, + * some rules decide whether one type can be assignable to another type. + * Based on these rules, a function can accept arguments with assignable types. + * + * <p>For example, a function with Long type operand can accept Integer as input. + * See {@code org.apache.calcite.sql.SqlUtil#filterRoutinesByParameterType()} for details. + * + * <p>During query execution, some of the assignable types need explicit conversion + * to the target types. i.e., Decimal expression should be converted to Integer + * before it is assigned to the Integer type Lvalue(In Java, Decimal can not be assigned to + * Integer directly). + * + * @param targetTypes Formal operand types declared for the function arguments + * @param arguments Input expressions to the function + * @return Input expressions with probable type conversion + */ + static List<Expression> convertAssignableTypes(Class<?>[] targetTypes, + List<Expression> arguments) { + final List<Expression> list = new ArrayList<>(); + if (targetTypes.length == arguments.size()) { + for (int i = 0; i < arguments.size(); i++) { + list.add(convertAssignableType(arguments.get(i), targetTypes[i])); + } + } else { + int j = 0; + for (Expression argument: arguments) { + Class<?> type; + if (!targetTypes[j].isArray()) { + type = targetTypes[j]; + j++; + } else { + type = targetTypes[j].getComponentType(); + } + list.add(convertAssignableType(argument, type)); + } + } + return list; + } + + /** + * Handle decimal type specifically with explicit type conversion + */ + private static Expression convertAssignableType( + Expression argument, Type targetType) { + if (targetType != BigDecimal.class) { + return argument; + } + return convert(argument, targetType); + } + /** Transforms a JoinRelType to Linq4j JoinType. **/ static JoinType toLinq4jJoinType(JoinRelType joinRelType) { switch (joinRelType) { diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/ReflectiveCallNotNullImplementor.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/ReflectiveCallNotNullImplementor.java index c083d25..1e25e03 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/ReflectiveCallNotNullImplementor.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/ReflectiveCallNotNullImplementor.java @@ -47,6 +47,8 @@ public class ReflectiveCallNotNullImplementor implements NotNullImplementor { RexCall call, List<Expression> translatedOperands) { translatedOperands = EnumUtils.fromInternal(method.getParameterTypes(), translatedOperands); + translatedOperands = + EnumUtils.convertAssignableTypes(method.getParameterTypes(), translatedOperands); final Expression callExpr; if ((method.getModifiers() & Modifier.STATIC) != 0) { callExpr = Expressions.call(method, translatedOperands); diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java index 9941d31..e63baac 100644 --- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java +++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java @@ -7015,6 +7015,22 @@ public class JdbcTest { .returns("EXPR$0=[250, 500, 1000]\n"); } + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-3565">[CALCITE-3565] + * Explicitly cast assignable operand types to decimal for udf</a>. */ + @Test public void testAssignableTypeCast() { + final String sql = "SELECT ST_MakePoint(1, 2.1)"; + CalciteAssert.that() + .with(CalciteAssert.Config.GEO) + .query(sql) + .planContains("static final java.math.BigDecimal $L4J$C$new_java_math_BigDecimal_1_ = " + + "new java.math.BigDecimal(\n" + + " 1)") + .planContains("org.apache.calcite.runtime.GeoFunctions.ST_MakePoint(" + + "$L4J$C$new_java_math_BigDecimal_1_, v)") + .returns("EXPR$0={\"x\":1,\"y\":2.1}\n"); + } + @Test public void testMatchSimple() { final String sql = "select *\n" + "from \"hr\".\"emps\" match_recognize (\n"