You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by tw...@apache.org on 2021/11/12 14:43:36 UTC

[flink] 02/04: [hotfix][table-planner] Fix primitives/boxed primitives behaviour of ExpressionEvaluator

This is an automated email from the ASF dual-hosted git repository.

twalthr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git

commit b51abc7c8c230507749b237a52fb9ba3eddf9e9c
Author: slinkydeveloper <fr...@gmail.com>
AuthorDate: Mon Nov 8 17:34:55 2021 +0100

    [hotfix][table-planner] Fix primitives/boxed primitives behaviour of ExpressionEvaluator
    
    Signed-off-by: slinkydeveloper <fr...@gmail.com>
---
 .../AbstractExpressionCodeGeneratorCastRule.java   | 23 ++++++++++++----
 .../flink/table/planner/codegen/CodeGenUtils.scala | 32 ++++++++++++++++++++++
 2 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/functions/casting/rules/AbstractExpressionCodeGeneratorCastRule.java b/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/functions/casting/rules/AbstractExpressionCodeGeneratorCastRule.java
index f3ed23f..aba38f0 100644
--- a/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/functions/casting/rules/AbstractExpressionCodeGeneratorCastRule.java
+++ b/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/functions/casting/rules/AbstractExpressionCodeGeneratorCastRule.java
@@ -30,10 +30,15 @@ import org.apache.flink.table.types.logical.utils.LogicalTypeUtils;
 
 import java.util.Collections;
 
+import static org.apache.flink.table.planner.codegen.CodeGenUtils.box;
+import static org.apache.flink.table.planner.codegen.CodeGenUtils.unbox;
+
 /**
  * Base class for cast rules that supports code generation, requiring only an expression to perform
  * the cast. If the casting logic requires to generate several statements, look at {@link
  * AbstractNullAwareCodeGeneratorCastRule}.
+ *
+ * <p>NOTE: the {@code inputTerm} is always either a primitive or a non-null object.
  */
 @Internal
 public abstract class AbstractExpressionCodeGeneratorCastRule<IN, OUT>
@@ -63,11 +68,19 @@ public abstract class AbstractExpressionCodeGeneratorCastRule<IN, OUT>
         final String inputArgumentName = "inputValue";
 
         final String expression =
-                generateExpression(
-                        createCodeGeneratorCastRuleContext(context),
-                        inputArgumentName,
-                        inputLogicalType,
-                        targetLogicalType);
+                // We need to wrap the expression in a null check
+                CastRuleUtils.ternaryOperator(
+                        inputArgumentName + " == null",
+                        "null",
+                        // Values are always boxed when passed to ExpressionEvaluator and no auto
+                        // boxing/unboxing is provided, so we need to take care of it manually
+                        box(
+                                generateExpression(
+                                        createCodeGeneratorCastRuleContext(context),
+                                        unbox(inputArgumentName, inputLogicalType),
+                                        inputLogicalType,
+                                        targetLogicalType),
+                                targetLogicalType));
 
         return new CodeGeneratedExpressionCastExecutor<>(
                 CompileUtils.compileExpression(
diff --git a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/CodeGenUtils.scala b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/CodeGenUtils.scala
index 748c583..f63f3aa 100644
--- a/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/CodeGenUtils.scala
+++ b/flink-table/flink-table-planner/src/main/scala/org/apache/flink/table/planner/codegen/CodeGenUtils.scala
@@ -195,6 +195,38 @@ object CodeGenUtils {
     case _ => boxedTypeTermForType(t)
   }
 
+  /**
+   * Execute primitive unboxing.
+   */
+  def unbox(term: String, ty: LogicalType): String = ty.getTypeRoot match {
+    // ordered by type root definition
+    case BOOLEAN => s"$term.booleanValue()"
+    case TINYINT => s"$term.byteValue()"
+    case SMALLINT => s"$term.shortValue()"
+    case INTEGER | DATE | TIME_WITHOUT_TIME_ZONE | INTERVAL_YEAR_MONTH => s"$term.intValue()"
+    case BIGINT | INTERVAL_DAY_TIME => s"$term.longValue()"
+    case FLOAT => s"$term.floatValue()"
+    case DOUBLE => s"$term.doubleValue()"
+    case DISTINCT_TYPE => unbox(term, ty.asInstanceOf[DistinctType].getSourceType)
+    case _ => term
+  }
+
+  /**
+   * Execute primitive unboxing.
+   */
+  def box(term: String, ty: LogicalType): String = ty.getTypeRoot match {
+    // ordered by type root definition
+    case BOOLEAN => s"Boolean.valueOf($term)"
+    case TINYINT => s"Byte.valueOf($term)"
+    case SMALLINT => s"Short.valueOf($term)"
+    case INTEGER | DATE | TIME_WITHOUT_TIME_ZONE | INTERVAL_YEAR_MONTH => s"Integer.valueOf($term)"
+    case BIGINT | INTERVAL_DAY_TIME => s"Long.valueOf($term)"
+    case FLOAT => s"Float.valueOf($term)"
+    case DOUBLE => s"Double.valueOf($term)"
+    case DISTINCT_TYPE => unbox(term, ty.asInstanceOf[DistinctType].getSourceType)
+    case _ => term
+  }
+
   @tailrec
   def boxedTypeTermForType(t: LogicalType): String = t.getTypeRoot match {
     // ordered by type root definition