Skip to content

Commit

Permalink
[hotfix][table-planner] Fix primitives/boxed primitives behaviour of …
Browse files Browse the repository at this point in the history
…ExpressionEvaluator

Signed-off-by: slinkydeveloper <[email protected]>
  • Loading branch information
slinkydeveloper authored and twalthr committed Nov 12, 2021
1 parent 5c914e1 commit b51abc7
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@

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>
Expand Down Expand Up @@ -63,11 +68,19 @@ public CastExecutor<IN, OUT> create(
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b51abc7

Please sign in to comment.