Code review comment: Can we just pass a flag into `BeamSqlLikeExpression`? 

Code before review:
private static BeamSqlExpression getBeamSqlExpression(RexNode rexNode) {
BeamSqlExpression ret;
if (rexNode instanceof RexLiteral) {
RexLiteral node = (RexLiteral) rexNode;
SqlTypeName type = node.getTypeName();
Object value = node.getValue();
if (SqlTypeName.CHAR_TYPES.contains(type) && node.getValue() instanceof NlsString) {
ret = BeamSqlPrimitive.of(type, ((NlsString) value).getValue());
} else if (isDateNode(type, value)) {
ret = BeamSqlPrimitive.of(type, new DateTime(((Calendar) value).getTimeInMillis()));
} else {
SqlTypeName realType = node.getType().getSqlTypeName();
Object realValue = value;
if (SqlTypeName.NUMERIC_TYPES.contains(type)) {
switch (realType) {
case TINYINT:
realValue = SqlFunctions.toByte(value);
break;
case SMALLINT:
realValue = SqlFunctions.toShort(value);
break;
case INTEGER:
realValue = SqlFunctions.toInt(value);
break;
case BIGINT:
realValue = SqlFunctions.toLong(value);
break;
case FLOAT:
realValue = SqlFunctions.toFloat(value);
break;
case DOUBLE:
realValue = SqlFunctions.toDouble(value);
break;
case DECIMAL:
realValue = SqlFunctions.toBigDecimal(value);
break;
default:
throw new IllegalStateException(
"Unsupported conversion: Attempted convert node "
+ node.toString()
+ " of type "
+ type
+ "to "
+ realType);
}
}
ret = BeamSqlPrimitive.of(realType, realValue);
}
} else if (rexNode instanceof RexInputRef) {
RexInputRef node = (RexInputRef) rexNode;
ret = new BeamSqlInputRefExpression(node.getType().getSqlTypeName(), node.getIndex());
} else if (rexNode instanceof RexCorrelVariable) {
RexCorrelVariable correlVariable = (RexCorrelVariable) rexNode;
ret =
new BeamSqlCorrelVariableExpression(
correlVariable.getType().getSqlTypeName(), correlVariable.id.getId());
} else if (rexNode instanceof RexLocalRef) {
RexLocalRef localRef = (RexLocalRef) rexNode;
ret = new BeamSqlLocalRefExpression(localRef.getType().getSqlTypeName(), localRef.getIndex());
} else if (rexNode instanceof RexFieldAccess) {
RexFieldAccess fieldAccessNode = (RexFieldAccess) rexNode;
BeamSqlExpression referenceExpression = buildExpression(fieldAccessNode.getReferenceExpr());
int nestedFieldIndex = fieldAccessNode.getField().getIndex();
SqlTypeName nestedFieldType = fieldAccessNode.getField().getType().getSqlTypeName();
ret =
new BeamSqlFieldAccessExpression(referenceExpression, nestedFieldIndex, nestedFieldType);
} else if (rexNode instanceof RexCall) {
RexCall node = (RexCall) rexNode;
String opName = node.op.getName();
List<BeamSqlExpression> subExps = new ArrayList<>();
for (RexNode subNode : node.getOperands()) {
subExps.add(buildExpression(subNode));
}
switch (opName) {
case "AND":
ret = new BeamSqlAndExpression(subExps);
break;
case "OR":
ret = new BeamSqlOrExpression(subExps);
break;
case "NOT":
ret = new BeamSqlNotExpression(subExps);
break;
case "=":
ret = new BeamSqlEqualsExpression(subExps);
break;
case "<>":
ret = new BeamSqlNotEqualsExpression(subExps);
break;
case ">":
ret = new BeamSqlGreaterThanExpression(subExps);
break;
case ">=":
ret = new BeamSqlGreaterThanOrEqualsExpression(subExps);
break;
case "<":
ret = new BeamSqlLessThanExpression(subExps);
break;
case "<=":
ret = new BeamSqlLessThanOrEqualsExpression(subExps);
break;
case "LIKE":
ret = new BeamSqlLikeExpression(subExps);
break;
case "NOT LIKE":
ret = new BeamSqlNotLikeExpression(subExps);
break;
case "+":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlPlusExpression(subExps);
} else {
ret = new BeamSqlDatetimePlusExpression(subExps);
}
break;
case "-":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlMinusExpression(subExps);
} else {
ret = new BeamSqlDatetimeMinusExpression(subExps, node.type.getSqlTypeName());
}
break;
case "*":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlMultiplyExpression(subExps);
} else {
ret = new BeamSqlIntervalMultiplyExpression(subExps);
}
break;
case "/":
case "/INT":
ret = new BeamSqlDivideExpression(subExps);
break;
case "MOD":
ret = new BeamSqlModExpression(subExps);
break;
case "ABS":
ret = new BeamSqlAbsExpression(subExps);
break;
case "ROUND":
ret = new BeamSqlRoundExpression(subExps);
break;
case "LN":
ret = new BeamSqlLnExpression(subExps);
break;
case "LOG10":
ret = new BeamSqlLogExpression(subExps);
break;
case "EXP":
ret = new BeamSqlExpExpression(subExps);
break;
case "ACOS":
ret = new BeamSqlAcosExpression(subExps);
break;
case "ASIN":
ret = new BeamSqlAsinExpression(subExps);
break;
case "ATAN":
ret = new BeamSqlAtanExpression(subExps);
break;
case "COT":
ret = new BeamSqlCotExpression(subExps);
break;
case "DEGREES":
ret = new BeamSqlDegreesExpression(subExps);
break;
case "RADIANS":
ret = new BeamSqlRadiansExpression(subExps);
break;
case "COS":
ret = new BeamSqlCosExpression(subExps);
break;
case "SIN":
ret = new BeamSqlSinExpression(subExps);
break;
case "TAN":
ret = new BeamSqlTanExpression(subExps);
break;
case "SIGN":
ret = new BeamSqlSignExpression(subExps);
break;
case "POWER":
ret = new BeamSqlPowerExpression(subExps);
break;
case "PI":
ret = new BeamSqlPiExpression();
break;
case "ATAN2":
ret = new BeamSqlAtan2Expression(subExps);
break;
case "TRUNCATE":
ret = new BeamSqlTruncateExpression(subExps);
break;
case "RAND":
ret = new BeamSqlRandExpression(subExps);
break;
case "RAND_INTEGER":
ret = new BeamSqlRandIntegerExpression(subExps);
break;
case "||":
ret = new BeamSqlOperatorExpression(StringOperators.CONCAT, subExps);
break;
case "POSITION":
ret = new BeamSqlOperatorExpression(StringOperators.POSITION, subExps);
break;
case "CHAR_LENGTH":
case "CHARACTER_LENGTH":
ret = new BeamSqlOperatorExpression(StringOperators.CHAR_LENGTH, subExps);
break;
case "UPPER":
ret = new BeamSqlOperatorExpression(StringOperators.UPPER, subExps);
break;
case "LOWER":
ret = new BeamSqlOperatorExpression(StringOperators.LOWER, subExps);
break;
case "TRIM":
ret = new BeamSqlOperatorExpression(StringOperators.TRIM, subExps);
break;
case "SUBSTRING":
ret = new BeamSqlOperatorExpression(StringOperators.SUBSTRING, subExps);
break;
case "OVERLAY":
ret = new BeamSqlOperatorExpression(StringOperators.OVERLAY, subExps);
break;
case "INITCAP":
ret = new BeamSqlOperatorExpression(StringOperators.INIT_CAP, subExps);
break;
case "Reinterpret":
ret = new BeamSqlReinterpretExpression(subExps, node.type.getSqlTypeName());
break;
case "CEIL":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlCeilExpression(subExps);
} else {
ret = new BeamSqlOperatorExpression(DateOperators.DATETIME_CEIL, subExps);
}
break;
case "FLOOR":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlFloorExpression(subExps);
} else {
ret = new BeamSqlOperatorExpression(DateOperators.DATETIME_FLOOR, subExps);
}
break;
case "EXTRACT_DATE":
case "EXTRACT":
ret = new BeamSqlOperatorExpression(DateOperators.EXTRACT, subExps);
break;
case "LOCALTIME":
case "CURRENT_TIME":
ret = new BeamSqlCurrentTimeExpression(subExps);
break;
case "CURRENT_TIMESTAMP":
case "LOCALTIMESTAMP":
ret = new BeamSqlCurrentTimestampExpression(subExps);
break;
case "CURRENT_DATE":
ret = new BeamSqlCurrentDateExpression();
break;
case "DATETIME_PLUS":
ret = new BeamSqlDatetimePlusExpression(subExps);
break;
case "ARRAY":
ret = new BeamSqlArrayExpression(subExps);
break;
case "MAP":
ret = new BeamSqlMapExpression(subExps);
break;
case "ITEM":
switch (subExps.get(0).getOutputType()) {
case MAP:
ret = new BeamSqlMapItemExpression(subExps, node.type.getSqlTypeName());
break;
case ARRAY:
ret = new BeamSqlArrayItemExpression(subExps, node.type.getSqlTypeName());
break;
default:
throw new UnsupportedOperationException(
"Operator: " + opName + " is not supported yet");
}
break;
case "ELEMENT":
ret = new BeamSqlSingleElementExpression(subExps, node.type.getSqlTypeName());
break;
case "CARDINALITY":
ret = new BeamSqlCardinalityExpression(subExps, node.type.getSqlTypeName());
break;
case "DOT":
ret = new BeamSqlDotExpression(subExps, node.type.getSqlTypeName());
break;
case "DEFAULT":
ret = new BeamSqlDefaultExpression();
break;
case "CASE":
ret = new BeamSqlCaseExpression(subExps);
break;
case "CAST":
ret = new BeamSqlCastExpression(subExps, node.type.getSqlTypeName());
break;
case "IS NULL":
ret = new BeamSqlIsNullExpression(subExps.get(0));
break;
case "IS NOT NULL":
ret = new BeamSqlIsNotNullExpression(subExps.get(0));
break;
case "HOP":
case "TUMBLE":
case "SESSION":
ret = new BeamSqlWindowExpression(subExps, node.type.getSqlTypeName());
break;
case "HOP_START":
case "TUMBLE_START":
case "SESSION_START":
ret = new BeamSqlWindowStartExpression();
break;
case "HOP_END":
case "TUMBLE_END":
case "SESSION_END":
ret = new BeamSqlWindowEndExpression();
break;
default:
if (((RexCall) rexNode).getOperator() instanceof SqlUserDefinedFunction) {
SqlUserDefinedFunction udf = (SqlUserDefinedFunction) ((RexCall) rexNode).getOperator();
ScalarFunctionImpl fn = (ScalarFunctionImpl) udf.getFunction();
ret =
new BeamSqlUdfExpression(
fn.method, subExps, ((RexCall) rexNode).type.getSqlTypeName());
} else {
throw new UnsupportedOperationException(
"Operator: " + opName + " is not supported yet");
}
}
} else {
throw new UnsupportedOperationException(
String.format("%s is not supported yet", rexNode.getClass().toString()));
}
return ret;
}

Line under review: ret = new BeamSqlNotLikeExpression(subExps);

Code after addressing the review:
private static BeamSqlExpression getBeamSqlExpression(RexNode rexNode) {
BeamSqlExpression ret;
if (rexNode instanceof RexLiteral) {
RexLiteral node = (RexLiteral) rexNode;
SqlTypeName type = node.getTypeName();
Object value = node.getValue();
if (SqlTypeName.CHAR_TYPES.contains(type) && node.getValue() instanceof NlsString) {
ret = BeamSqlPrimitive.of(type, ((NlsString) value).getValue());
} else if (isDateNode(type, value)) {
ret = BeamSqlPrimitive.of(type, new DateTime(((Calendar) value).getTimeInMillis()));
} else {
SqlTypeName realType = node.getType().getSqlTypeName();
Object realValue = value;
if (SqlTypeName.NUMERIC_TYPES.contains(type)) {
switch (realType) {
case TINYINT:
realValue = SqlFunctions.toByte(value);
break;
case SMALLINT:
realValue = SqlFunctions.toShort(value);
break;
case INTEGER:
realValue = SqlFunctions.toInt(value);
break;
case BIGINT:
realValue = SqlFunctions.toLong(value);
break;
case FLOAT:
realValue = SqlFunctions.toFloat(value);
break;
case DOUBLE:
realValue = SqlFunctions.toDouble(value);
break;
case DECIMAL:
realValue = SqlFunctions.toBigDecimal(value);
break;
default:
throw new IllegalStateException(
"Unsupported conversion: Attempted convert node "
+ node.toString()
+ " of type "
+ type
+ "to "
+ realType);
}
}
ret = BeamSqlPrimitive.of(realType, realValue);
}
} else if (rexNode instanceof RexInputRef) {
RexInputRef node = (RexInputRef) rexNode;
ret = new BeamSqlInputRefExpression(node.getType().getSqlTypeName(), node.getIndex());
} else if (rexNode instanceof RexCorrelVariable) {
RexCorrelVariable correlVariable = (RexCorrelVariable) rexNode;
ret =
new BeamSqlCorrelVariableExpression(
correlVariable.getType().getSqlTypeName(), correlVariable.id.getId());
} else if (rexNode instanceof RexLocalRef) {
RexLocalRef localRef = (RexLocalRef) rexNode;
ret = new BeamSqlLocalRefExpression(localRef.getType().getSqlTypeName(), localRef.getIndex());
} else if (rexNode instanceof RexFieldAccess) {
RexFieldAccess fieldAccessNode = (RexFieldAccess) rexNode;
BeamSqlExpression referenceExpression = buildExpression(fieldAccessNode.getReferenceExpr());
int nestedFieldIndex = fieldAccessNode.getField().getIndex();
SqlTypeName nestedFieldType = fieldAccessNode.getField().getType().getSqlTypeName();
ret =
new BeamSqlFieldAccessExpression(referenceExpression, nestedFieldIndex, nestedFieldType);
} else if (rexNode instanceof RexCall) {
RexCall node = (RexCall) rexNode;
String opName = node.op.getName();
List<BeamSqlExpression> subExps = new ArrayList<>();
for (RexNode subNode : node.getOperands()) {
subExps.add(buildExpression(subNode));
}
switch (opName) {
case "AND":
ret = new BeamSqlAndExpression(subExps);
break;
case "OR":
ret = new BeamSqlOrExpression(subExps);
break;
case "NOT":
ret = new BeamSqlNotExpression(subExps);
break;
case "=":
ret = new BeamSqlEqualsExpression(subExps);
break;
case "<>":
ret = new BeamSqlNotEqualsExpression(subExps);
break;
case ">":
ret = new BeamSqlGreaterThanExpression(subExps);
break;
case ">=":
ret = new BeamSqlGreaterThanOrEqualsExpression(subExps);
break;
case "<":
ret = new BeamSqlLessThanExpression(subExps);
break;
case "<=":
ret = new BeamSqlLessThanOrEqualsExpression(subExps);
break;
case "LIKE":
ret = new BeamSqlLikeExpression(subExps);
break;
case "NOT LIKE":
ret = new BeamSqlNotLikeExpression(subExps);
break;
case "+":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlPlusExpression(subExps);
} else {
ret = new BeamSqlDatetimePlusExpression(subExps);
}
break;
case "-":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlMinusExpression(subExps);
} else {
ret = new BeamSqlDatetimeMinusExpression(subExps, node.type.getSqlTypeName());
}
break;
case "*":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlMultiplyExpression(subExps);
} else {
ret = new BeamSqlIntervalMultiplyExpression(subExps);
}
break;
case "/":
case "/INT":
ret = new BeamSqlDivideExpression(subExps);
break;
case "MOD":
ret = new BeamSqlModExpression(subExps);
break;
case "ABS":
ret = new BeamSqlAbsExpression(subExps);
break;
case "ROUND":
ret = new BeamSqlRoundExpression(subExps);
break;
case "LN":
ret = new BeamSqlLnExpression(subExps);
break;
case "LOG10":
ret = new BeamSqlLogExpression(subExps);
break;
case "EXP":
ret = new BeamSqlExpExpression(subExps);
break;
case "ACOS":
ret = new BeamSqlAcosExpression(subExps);
break;
case "ASIN":
ret = new BeamSqlAsinExpression(subExps);
break;
case "ATAN":
ret = new BeamSqlAtanExpression(subExps);
break;
case "COT":
ret = new BeamSqlCotExpression(subExps);
break;
case "DEGREES":
ret = new BeamSqlDegreesExpression(subExps);
break;
case "RADIANS":
ret = new BeamSqlRadiansExpression(subExps);
break;
case "COS":
ret = new BeamSqlCosExpression(subExps);
break;
case "SIN":
ret = new BeamSqlSinExpression(subExps);
break;
case "TAN":
ret = new BeamSqlTanExpression(subExps);
break;
case "SIGN":
ret = new BeamSqlSignExpression(subExps);
break;
case "POWER":
ret = new BeamSqlPowerExpression(subExps);
break;
case "PI":
ret = new BeamSqlPiExpression();
break;
case "ATAN2":
ret = new BeamSqlAtan2Expression(subExps);
break;
case "TRUNCATE":
ret = new BeamSqlTruncateExpression(subExps);
break;
case "RAND":
ret = new BeamSqlRandExpression(subExps);
break;
case "RAND_INTEGER":
ret = new BeamSqlRandIntegerExpression(subExps);
break;
case "||":
ret = new BeamSqlOperatorExpression(StringOperators.CONCAT, subExps);
break;
case "POSITION":
ret = new BeamSqlOperatorExpression(StringOperators.POSITION, subExps);
break;
case "CHAR_LENGTH":
case "CHARACTER_LENGTH":
ret = new BeamSqlOperatorExpression(StringOperators.CHAR_LENGTH, subExps);
break;
case "UPPER":
ret = new BeamSqlOperatorExpression(StringOperators.UPPER, subExps);
break;
case "LOWER":
ret = new BeamSqlOperatorExpression(StringOperators.LOWER, subExps);
break;
case "TRIM":
ret = new BeamSqlOperatorExpression(StringOperators.TRIM, subExps);
break;
case "SUBSTRING":
ret = new BeamSqlOperatorExpression(StringOperators.SUBSTRING, subExps);
break;
case "OVERLAY":
ret = new BeamSqlOperatorExpression(StringOperators.OVERLAY, subExps);
break;
case "INITCAP":
ret = new BeamSqlOperatorExpression(StringOperators.INIT_CAP, subExps);
break;
case "Reinterpret":
ret = new BeamSqlReinterpretExpression(subExps, node.type.getSqlTypeName());
break;
case "CEIL":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlCeilExpression(subExps);
} else {
ret = new BeamSqlOperatorExpression(DateOperators.DATETIME_CEIL, subExps);
}
break;
case "FLOOR":
if (SqlTypeName.NUMERIC_TYPES.contains(node.type.getSqlTypeName())) {
ret = new BeamSqlFloorExpression(subExps);
} else {
ret = new BeamSqlOperatorExpression(DateOperators.DATETIME_FLOOR, subExps);
}
break;
case "EXTRACT_DATE":
case "EXTRACT":
ret = new BeamSqlOperatorExpression(DateOperators.EXTRACT, subExps);
break;
case "LOCALTIME":
case "CURRENT_TIME":
ret = new BeamSqlCurrentTimeExpression(subExps);
break;
case "CURRENT_TIMESTAMP":
case "LOCALTIMESTAMP":
ret = new BeamSqlCurrentTimestampExpression(subExps);
break;
case "CURRENT_DATE":
ret = new BeamSqlCurrentDateExpression();
break;
case "DATETIME_PLUS":
ret = new BeamSqlDatetimePlusExpression(subExps);
break;
case "ARRAY":
ret = new BeamSqlArrayExpression(subExps);
break;
case "MAP":
ret = new BeamSqlMapExpression(subExps);
break;
case "ITEM":
switch (subExps.get(0).getOutputType()) {
case MAP:
ret = new BeamSqlMapItemExpression(subExps, node.type.getSqlTypeName());
break;
case ARRAY:
ret = new BeamSqlArrayItemExpression(subExps, node.type.getSqlTypeName());
break;
default:
throw new UnsupportedOperationException(
"Operator: " + opName + " is not supported yet");
}
break;
case "ELEMENT":
ret = new BeamSqlSingleElementExpression(subExps, node.type.getSqlTypeName());
break;
case "CARDINALITY":
ret = new BeamSqlCardinalityExpression(subExps, node.type.getSqlTypeName());
break;
case "DOT":
ret = new BeamSqlDotExpression(subExps, node.type.getSqlTypeName());
break;
case "DEFAULT":
ret = new BeamSqlDefaultExpression();
break;
case "CASE":
ret = new BeamSqlCaseExpression(subExps);
break;
case "CAST":
ret = new BeamSqlCastExpression(subExps, node.type.getSqlTypeName());
break;
case "IS NULL":
ret = new BeamSqlIsNullExpression(subExps.get(0));
break;
case "IS NOT NULL":
ret = new BeamSqlIsNotNullExpression(subExps.get(0));
break;
case "HOP":
case "TUMBLE":
case "SESSION":
ret = new BeamSqlWindowExpression(subExps, node.type.getSqlTypeName());
break;
case "HOP_START":
case "TUMBLE_START":
case "SESSION_START":
ret = new BeamSqlWindowStartExpression();
break;
case "HOP_END":
case "TUMBLE_END":
case "SESSION_END":
ret = new BeamSqlWindowEndExpression();
break;
default:
if (((RexCall) rexNode).getOperator() instanceof SqlUserDefinedFunction) {
SqlUserDefinedFunction udf = (SqlUserDefinedFunction) ((RexCall) rexNode).getOperator();
ScalarFunctionImpl fn = (ScalarFunctionImpl) udf.getFunction();
ret =
new BeamSqlUdfExpression(
fn.method, subExps, ((RexCall) rexNode).type.getSqlTypeName());
} else {
throw new UnsupportedOperationException(
"Operator: " + opName + " is not supported yet");
}
}
} else {
throw new UnsupportedOperationException(
String.format("%s is not supported yet", rexNode.getClass().toString()));
}
return ret;
}