Copilot commented on code in PR #4482:
URL: https://github.com/apache/flink-cdc/pull/4482#discussion_r3636121566
##########
flink-cdc-runtime/src/main/java/org/apache/flink/cdc/runtime/parser/JaninoCompiler.java:
##########
@@ -804,6 +904,265 @@ private static String
generateInvokeExpression(UserDefinedFunctionDescriptor udf
}
}
+ private static class GeneratedExpressionGenerator {
+ private final Context context;
+ private int termId;
+
+ private GeneratedExpressionGenerator(Context context) {
+ this.context = context;
+ }
+
+ private GeneratedExpression translate(SqlNode sqlNode, Class<?>
resultClass) {
+ if (sqlNode instanceof SqlBasicCall) {
+ return translateSqlBasicCall((SqlBasicCall) sqlNode,
resultClass);
+ }
+ if (sqlNode instanceof SqlCase) {
+ return translateSqlCase((SqlCase) sqlNode, resultClass);
+ }
+ Java.Rvalue rvalue = translateSqlNodeToJaninoRvalue(context,
sqlNode);
+ if (rvalue == null) {
+ throw new ParseException("Unrecognized expression: " +
sqlNode);
+ }
+ return GeneratedExpression.fromExpression(rvalue.toString(),
resultClass);
+ }
+
+ private GeneratedExpression translateSqlBasicCall(
+ SqlBasicCall sqlBasicCall, Class<?> resultClass) {
+ switch (sqlBasicCall.getKind()) {
+ case AND:
+ return translateLogicalBinaryOperation(sqlBasicCall, true);
+ case OR:
+ return translateLogicalBinaryOperation(sqlBasicCall,
false);
+ case OTHER_FUNCTION:
+ if
(sqlBasicCall.getOperator().getName().equalsIgnoreCase("IF")) {
+ return translateIf(sqlBasicCall, resultClass);
+ }
+ return translateGenericBasicCall(sqlBasicCall,
resultClass);
+ default:
+ return translateGenericBasicCall(sqlBasicCall,
resultClass);
+ }
+ }
+
+ private GeneratedExpression translateLogicalBinaryOperation(
+ SqlBasicCall sqlBasicCall, boolean isAnd) {
+ List<SqlNode> operands = sqlBasicCall.getOperandList();
+ if (operands.size() != 2) {
+ throw new ParseException("Unrecognized expression: " +
sqlBasicCall);
+ }
+
+ GeneratedExpression left = translate(operands.get(0),
Boolean.class);
+ GeneratedExpression right = translate(operands.get(1),
Boolean.class);
+
+ String resultTerm = newTerm("result");
+ String leftTerm = newTerm("left");
+ String rightTerm = newTerm("right");
+ String shortCircuitValue = isAnd ? "FALSE" : "TRUE";
+ String functionName = isAnd ? "and" : "or";
+
+ StringBuilder code = new StringBuilder();
+ appendCode(code, left.getCode());
+ code.append("Boolean ").append(resultTerm).append(";\n");
+ code.append("Boolean ")
+ .append(leftTerm)
+ .append(" = ")
+ .append(left.getResultTerm())
+ .append(";\n");
+ code.append("if (Boolean.")
+ .append(shortCircuitValue)
+ .append(".equals(")
+ .append(leftTerm)
+ .append(")) {\n");
+ code.append(resultTerm).append(" =
Boolean.").append(shortCircuitValue).append(";\n");
+ code.append("} else {\n");
+ appendCode(code, right.getCode());
+ code.append("Boolean ")
+ .append(rightTerm)
+ .append(" = ")
+ .append(right.getResultTerm())
+ .append(";\n");
+ code.append(resultTerm)
+ .append(" = ")
+ .append(functionName)
+ .append("(")
+ .append(leftTerm)
+ .append(", ")
+ .append(rightTerm)
+ .append(");\n");
+ code.append("}\n");
+
+ return GeneratedExpression.of(code.toString(), resultTerm,
Boolean.class);
+ }
+
+ private GeneratedExpression translateIf(SqlBasicCall sqlBasicCall,
Class<?> resultClass) {
+ List<SqlNode> operands = sqlBasicCall.getOperandList();
+ if (operands.size() != 3) {
+ throw new ParseException("Unrecognized expression: " +
sqlBasicCall);
+ }
+
+ GeneratedExpression condition = translate(operands.get(0),
Boolean.class);
+ GeneratedExpression thenExpression = translate(operands.get(1),
resultClass);
+ GeneratedExpression elseExpression = translate(operands.get(2),
resultClass);
+
+ String resultTerm = newTerm("result");
+ String conditionTerm = newTerm("condition");
+ StringBuilder code = new StringBuilder();
+ appendCode(code, condition.getCode());
+ code.append(className(resultClass)).append("
").append(resultTerm).append(";\n");
+ code.append("Boolean ")
+ .append(conditionTerm)
+ .append(" = ")
+ .append(condition.getResultTerm())
+ .append(";\n");
+ code.append("if (isTrue(").append(conditionTerm).append(")) {\n");
+ appendCode(code, thenExpression.getCode());
+ code.append(resultTerm)
+ .append(" = ")
+ .append(thenExpression.getResultTerm())
+ .append(";\n");
+ code.append("} else {\n");
+ appendCode(code, elseExpression.getCode());
+ code.append(resultTerm)
+ .append(" = ")
+ .append(elseExpression.getResultTerm())
+ .append(";\n");
+ code.append("}\n");
+
+ return GeneratedExpression.of(code.toString(), resultTerm,
resultClass);
+ }
+
+ private GeneratedExpression translateSqlCase(SqlCase sqlCase, Class<?>
resultClass) {
+ String resultTerm = newTerm("result");
+ StringBuilder code = new StringBuilder();
+ code.append(className(resultClass)).append("
").append(resultTerm).append(";\n");
+ appendCaseBranch(
+ code,
+ resultTerm,
+ sqlCase.getWhenOperands(),
+ sqlCase.getThenOperands(),
+ sqlCase.getElseOperand(),
+ 0,
+ resultClass);
+ return GeneratedExpression.of(code.toString(), resultTerm,
resultClass);
+ }
+
+ private void appendCaseBranch(
+ StringBuilder code,
+ String resultTerm,
+ SqlNodeList whenOperands,
+ SqlNodeList thenOperands,
+ SqlNode elseOperand,
+ int index,
+ Class<?> resultClass) {
+ if (index >= whenOperands.size()) {
+ GeneratedExpression elseExpression =
+ elseOperand == null
+ ? GeneratedExpression.fromExpression("null",
resultClass)
+ : translate(elseOperand, resultClass);
+ appendCode(code, elseExpression.getCode());
+ code.append(resultTerm)
+ .append(" = ")
+ .append(elseExpression.getResultTerm())
+ .append(";\n");
+ return;
+ }
+
+ GeneratedExpression whenExpression =
translate(whenOperands.get(index), Boolean.class);
+ GeneratedExpression thenExpression =
translate(thenOperands.get(index), resultClass);
+ String conditionTerm = newTerm("condition");
+ appendCode(code, whenExpression.getCode());
+ code.append("Boolean ")
+ .append(conditionTerm)
+ .append(" = ")
+ .append(whenExpression.getResultTerm())
+ .append(";\n");
+ code.append("if (isTrue(").append(conditionTerm).append(")) {\n");
+ appendCode(code, thenExpression.getCode());
+ code.append(resultTerm)
+ .append(" = ")
+ .append(thenExpression.getResultTerm())
+ .append(";\n");
+ code.append("} else {\n");
+ appendCaseBranch(
+ code,
+ resultTerm,
+ whenOperands,
+ thenOperands,
+ elseOperand,
+ index + 1,
+ resultClass);
+ code.append("}\n");
+ }
+
+ private GeneratedExpression translateGenericBasicCall(
+ SqlBasicCall sqlBasicCall, Class<?> resultClass) {
+ List<GeneratedExpression> atoms = new ArrayList<>();
+ for (SqlNode sqlNode : sqlBasicCall.getOperandList()) {
+ translateSqlNodeToGeneratedAtoms(sqlNode, atoms);
+ }
+ if (TIMEZONE_FREE_TEMPORAL_FUNCTIONS.contains(
+ sqlBasicCall.getOperator().getName().toUpperCase())) {
+
atoms.add(GeneratedExpression.fromExpression(DEFAULT_EPOCH_TIME, Long.class));
+ } else if (TIMEZONE_REQUIRED_TEMPORAL_FUNCTIONS.contains(
+ sqlBasicCall.getOperator().getName().toUpperCase())) {
+
atoms.add(GeneratedExpression.fromExpression(DEFAULT_EPOCH_TIME, Long.class));
+
atoms.add(GeneratedExpression.fromExpression(DEFAULT_TIME_ZONE, String.class));
+ } else if
(TIMEZONE_REQUIRED_TEMPORAL_CONVERSION_FUNCTIONS.contains(
+ sqlBasicCall.getOperator().getName().toUpperCase())) {
+
atoms.add(GeneratedExpression.fromExpression(DEFAULT_TIME_ZONE, String.class));
+ }
+
+ StringBuilder code = new StringBuilder();
+ Java.Rvalue[] rvalues = new Java.Rvalue[atoms.size()];
+ for (int i = 0; i < atoms.size(); i++) {
+ GeneratedExpression atom = atoms.get(i);
+ appendCode(code, atom.getCode());
+ rvalues[i] = toRvalue(atom);
+ }
+ Java.Rvalue rvalue = sqlBasicCallToJaninoRvalue(context,
sqlBasicCall, rvalues);
+ return GeneratedExpression.of(code.toString(), rvalue.toString(),
resultClass);
+ }
+
+ private void translateSqlNodeToGeneratedAtoms(
+ SqlNode sqlNode, List<GeneratedExpression> atoms) {
+ if (sqlNode instanceof SqlNodeList) {
+ for (SqlNode node : (SqlNodeList) sqlNode) {
+ translateSqlNodeToGeneratedAtoms(node, atoms);
+ }
+ } else if (sqlNode instanceof SqlIdentifier
+ || sqlNode instanceof SqlLiteral
+ || sqlNode instanceof SqlBasicCall
+ || sqlNode instanceof SqlCase) {
+ atoms.add(translate(sqlNode,
deduceGeneratedExpressionClass(context, sqlNode)));
+ }
+ }
Review Comment:
translateSqlNodeToGeneratedAtoms(...) silently ignores unsupported SqlNode
operand types (falls through without adding an atom or throwing). This can mask
invalid expressions and may lead to wrong argument counts being passed to
sqlBasicCallToJaninoRvalue(), producing confusing errors or incorrect generated
code.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]