yuxiqian commented on code in PR #4482:
URL: https://github.com/apache/flink-cdc/pull/4482#discussion_r3654317371
##########
flink-cdc-runtime/src/main/java/org/apache/flink/cdc/runtime/parser/JaninoCompiler.java:
##########
@@ -804,6 +916,418 @@ 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);
Review Comment:
`rvalue.toString()` is for debugging purposes only and may not generate Java
code with correct parentheses.
For example, SQL statement `(a - b) / (c + 1)` will be converted to `a - b /
c + 1`.
##########
flink-cdc-runtime/src/main/java/org/apache/flink/cdc/runtime/parser/GeneratedExpression.java:
##########
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.runtime.parser;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/** Statement-level Java code generated from a transform expression. */
+public class GeneratedExpression implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final String code;
+ private final String resultTerm;
+ private final Class<?> resultClass;
+
+ private GeneratedExpression(String code, String resultTerm, Class<?>
resultClass) {
+ this.code = Objects.requireNonNull(code);
+ this.resultTerm = Objects.requireNonNull(resultTerm);
+ this.resultClass = Objects.requireNonNull(resultClass);
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getResultTerm() {
+ return resultTerm;
+ }
+
+ public Class<?> getResultClass() {
+ return resultClass;
+ }
+
+ public String asScript() {
+ StringBuilder script = new StringBuilder();
+ appendCode(script, code);
+ script.append("return ").append(resultTerm).append(";");
+ return script.toString();
+ }
+
+ public static GeneratedExpression of(String code, String resultTerm,
Class<?> resultClass) {
+ return new GeneratedExpression(code, resultTerm, resultClass);
+ }
+
+ public static GeneratedExpression fromExpression(String resultTerm,
Class<?> resultClass) {
+ return of("", resultTerm, resultClass);
+ }
+
+ private static void appendCode(StringBuilder builder, String code) {
+ if (code.isEmpty()) {
+ return;
+ }
+ builder.append(code);
+ if (code.charAt(code.length() - 1) != '\n') {
+ builder.append('\n');
+ }
+ }
Review Comment:
Ditto, avoid string ops
##########
flink-cdc-runtime/src/main/java/org/apache/flink/cdc/runtime/parser/JaninoCompiler.java:
##########
@@ -496,6 +511,103 @@ private static Java.Rvalue generateEqualsOperation(
Location.NOWHERE, null,
StringUtils.convertToCamelCase("VALUE_EQUALS"), atoms);
}
+ private static Class<?> deduceGeneratedExpressionClass(Context context,
SqlNode sqlNode) {
+ if (sqlNode instanceof SqlIdentifier) {
+ return deduceIdentifierClass(context, (SqlIdentifier) sqlNode);
+ }
+ if (sqlNode instanceof SqlLiteral) {
+ return deduceLiteralClass((SqlLiteral) sqlNode);
+ }
+ if (sqlNode instanceof SqlBasicCall &&
isBooleanResultCall((SqlBasicCall) sqlNode)) {
+ return Boolean.class;
+ }
+ try {
+ return JavaClassConverter.toJavaClass(
+ TransformParser.deduceSubExpressionType(
+ context.columns,
+ sqlNode,
+ context.udfDescriptors,
+ context.supportedMetadataColumns));
+ } catch (RuntimeException e) {
+ return Object.class;
+ }
+ }
+
+ private static Class<?> deduceIdentifierClass(Context context,
SqlIdentifier sqlIdentifier) {
+ String columnName = sqlIdentifier.names.get(sqlIdentifier.names.size()
- 1);
+ for (Column column : context.columns) {
+ if (column.getName().equals(columnName)) {
+ return JavaClassConverter.toJavaClass(column.getType());
+ }
+ }
+ for (SupportedMetadataColumn metadataColumn :
context.supportedMetadataColumns) {
+ if (metadataColumn.getName().equals(columnName)) {
+ return metadataColumn.getJavaClass();
+ }
+ }
+ Optional<Class<?>> metadataColumnClass =
+ MetadataColumns.METADATA_COLUMNS.stream()
+ .filter(column -> column.f0.equals(columnName))
+ .findFirst()
+ .map(column -> (Class<?>) column.f2);
+ return metadataColumnClass.orElse(Object.class);
+ }
+
+ private static Class<?> deduceLiteralClass(SqlLiteral sqlLiteral) {
+ if (sqlLiteral.getValue() == null) {
+ return Object.class;
+ }
+ if (sqlLiteral instanceof SqlCharStringLiteral) {
+ return String.class;
+ }
+ if (sqlLiteral instanceof SqlNumericLiteral) {
+ SqlNumericLiteral numericLiteral = (SqlNumericLiteral) sqlLiteral;
+ if (numericLiteral.isInteger()) {
+ long longValue = numericLiteral.longValue(true);
+ if (longValue > Integer.MAX_VALUE || longValue <
Integer.MIN_VALUE) {
+ return Long.class;
+ }
+ return Integer.class;
+ }
+ return Double.class;
+ }
+ if (sqlLiteral.getTypeName() == SqlTypeName.BOOLEAN) {
+ return Boolean.class;
+ }
+ return Object.class;
+ }
+
+ private static boolean isBooleanResultCall(SqlBasicCall sqlBasicCall) {
Review Comment:
One may write a UDF returning `BOOLEAN`?
##########
flink-cdc-runtime/src/main/java/org/apache/flink/cdc/runtime/parser/GeneratedExpression.java:
##########
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.cdc.runtime.parser;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/** Statement-level Java code generated from a transform expression. */
+public class GeneratedExpression implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final String code;
+ private final String resultTerm;
+ private final Class<?> resultClass;
+
+ private GeneratedExpression(String code, String resultTerm, Class<?>
resultClass) {
+ this.code = Objects.requireNonNull(code);
+ this.resultTerm = Objects.requireNonNull(resultTerm);
+ this.resultClass = Objects.requireNonNull(resultClass);
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getResultTerm() {
+ return resultTerm;
+ }
+
+ public Class<?> getResultClass() {
+ return resultClass;
+ }
+
+ public String asScript() {
+ StringBuilder script = new StringBuilder();
+ appendCode(script, code);
+ script.append("return ").append(resultTerm).append(";");
+ return script.toString();
+ }
Review Comment:
Better avoid string manipulations on dumped Java codes. Is
`Java.ReturnStatement` useful here?
--
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]