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"

Reply via email to