This is an automated email from the ASF dual-hosted git repository.
xiong pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 82eb4bdd0f [CALCITE-6835] Invalid unparse for IS TRUE,IS FALSE,IS NOT
TRUE and IS NOT FALSE in StarRocksDialect
82eb4bdd0f is described below
commit 82eb4bdd0f9aa472ca11fed4bfba4ce372d6eaac
Author: Xiong Duan <[email protected]>
AuthorDate: Wed Feb 26 09:15:29 2025 +0800
[CALCITE-6835] Invalid unparse for IS TRUE,IS FALSE,IS NOT TRUE and IS NOT
FALSE in StarRocksDialect
---
.../apache/calcite/rel/rel2sql/SqlImplementor.java | 17 ++--
.../java/org/apache/calcite/rex/RexBuilder.java | 7 ++
.../java/org/apache/calcite/sql/SqlDialect.java | 5 ++
.../calcite/sql/dialect/StarRocksSqlDialect.java | 68 ++++++++++++++++
.../calcite/rel/rel2sql/RelToSqlConverterTest.java | 90 +++++++++++++++++++++-
5 files changed, 180 insertions(+), 7 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
index a0733b6924..d8e38d02d1 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
@@ -166,8 +166,12 @@ public abstract class SqlImplementor {
protected final Map<CorrelationId, Context> correlTableMap = new HashMap<>();
- /** Private RexBuilder for short-lived expressions. It has its own
- * dedicated type factory, so don't trust the types to be canonized. */
+ /**
+ * Private RexBuilder for short-lived expressions. It has its own
+ * dedicated type factory, so don't trust the types to be canonized.
+ *
+ * @deprecated Replaced by {@link RexBuilder#DEFAULT}. */
+ @Deprecated // to be removed before 2.0
final RexBuilder rexBuilder =
new RexBuilder(new SqlTypeFactoryImpl(RelDataTypeSystemImpl.DEFAULT));
@@ -652,6 +656,7 @@ public SqlNode orderField(int ordinal) {
* @param rex Expression to convert
*/
public SqlNode toSql(@Nullable RexProgram program, RexNode rex) {
+ rex = dialect.prepareUnparse(rex);
final RexSubQuery subQuery;
final SqlNode sqlSubQuery;
final RexLiteral literal;
@@ -798,7 +803,7 @@ public SqlNode toSql(@Nullable RexProgram program, RexNode
rex) {
//noinspection unchecked
return toSql(program, search.operands.get(0), literal.getType(),
sarg);
}
- return toSql(program, RexUtil.expandSearch(implementor().rexBuilder,
program, search));
+ return toSql(program, RexUtil.expandSearch(RexBuilder.DEFAULT,
program, search));
case EXISTS:
case UNIQUE:
@@ -953,7 +958,7 @@ private <C extends Comparable<C>> SqlNode toSql(@Nullable
RexProgram program,
final RangeSets.Consumer<C> consumer =
new RangeToSql<>(operandSql, orList, v ->
toSql(program,
- implementor().rexBuilder.makeLiteral(v, type)));
+ RexBuilder.DEFAULT.makeLiteral(v, type)));
RangeSets.forEach(sarg.rangeSet, consumer);
}
return SqlUtil.createCall(SqlStdOperatorTable.OR, POS, orList);
@@ -965,7 +970,7 @@ private <C extends Comparable<C>> SqlNode toIn(SqlNode
operandSql,
final SqlNodeList list = rangeSet.asRanges().stream()
.map(range ->
toSql(program,
- implementor().rexBuilder.makeLiteral(range.lowerEndpoint(),
+ RexBuilder.DEFAULT.makeLiteral(range.lowerEndpoint(),
type, true, true)))
.collect(SqlNode.toList());
switch (list.size()) {
@@ -1718,7 +1723,7 @@ private JoinContext(SqlDialect dialect, Context
leftContext,
&& ((RexInputRef) op0).getIndex() >= leftContext.fieldCount) {
// Arguments were of form 'op1 = op0'
final SqlOperator op2 = requireNonNull(call.getOperator().reverse());
- return (RexCall) rexBuilder.makeCall(call.getParserPosition(), op2,
op1, op0);
+ return (RexCall)
RexBuilder.DEFAULT.makeCall(call.getParserPosition(), op2, op1, op0);
}
// fall through
default:
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index a7d5559c54..641a0cb351 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -26,6 +26,7 @@
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
import org.apache.calcite.runtime.FlatLists;
import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.SqlCollation;
@@ -42,6 +43,7 @@
import org.apache.calcite.sql.type.IntervalSqlType;
import org.apache.calcite.sql.type.MapSqlType;
import org.apache.calcite.sql.type.MultisetSqlType;
+import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
import org.apache.calcite.sql.type.SqlTypeFamily;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.type.SqlTypeUtil;
@@ -94,6 +96,11 @@
* <p>Some common literal values (NULL, TRUE, FALSE, 0, 1, '') are cached.
*/
public class RexBuilder {
+
+ /** Default RexBuilder. */
+ public static final RexBuilder DEFAULT =
+ new RexBuilder(new SqlTypeFactoryImpl(RelDataTypeSystemImpl.DEFAULT));
+
/**
* Special operator that accesses an unadvertised field of an input record.
* This operator cannot be used in SQL queries; it is introduced temporarily
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
index 6402a283ac..e6525a1d21 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
@@ -795,6 +795,11 @@ public boolean supportBooleanCaseWhen() {
return true;
}
+ /** Converts {@link RexNode} expression to {@link RexNode} expression before
unparse. */
+ public RexNode prepareUnparse(RexNode rexNode) {
+ return rexNode;
+ }
+
/** Returns whether this dialect supports a given function or operator.
* It only applies to built-in scalar functions and operators, since
* user-defined functions and procedures should be read by JdbcSchema. */
diff --git
a/core/src/main/java/org/apache/calcite/sql/dialect/StarRocksSqlDialect.java
b/core/src/main/java/org/apache/calcite/sql/dialect/StarRocksSqlDialect.java
index e22b63b13d..a21c1b577b 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/StarRocksSqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/StarRocksSqlDialect.java
@@ -21,6 +21,10 @@
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeSystem;
import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.sql.SqlAbstractDateTimeLiteral;
import org.apache.calcite.sql.SqlAlienSystemTypeNameSpec;
import org.apache.calcite.sql.SqlBasicTypeNameSpec;
@@ -31,11 +35,16 @@
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.fun.SqlFloorFunction;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;
import org.checkerframework.checker.nullness.qual.Nullable;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_FALSE;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_NOT_FALSE;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_NOT_TRUE;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_TRUE;
import static org.apache.calcite.util.RelToSqlConverterUtil.unparseHiveTrim;
/**
@@ -93,6 +102,65 @@ public StarRocksSqlDialect(Context context) {
return true;
}
+ @Override public RexNode prepareUnparse(RexNode arg) {
+ if (!(arg instanceof RexCall)) {
+ return arg;
+ }
+ RexCall call = (RexCall) arg;
+ switch (call.getOperator().getKind()) {
+ case IS_FALSE:
+ RexNode operandIsFalse = call.operands.get(0);
+ if (RexUtil.isDeterministic(operandIsFalse)) {
+ // A IS FALSE -> A IS NOT NULL AND NOT A
+ RexNode isNotNullFunc =
+ RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.IS_NOT_NULL,
operandIsFalse);
+ RexNode notFunc =
+ RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.NOT,
operandIsFalse);
+ return RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.AND,
isNotNullFunc, notFunc);
+ } else {
+ throw new UnsupportedOperationException("Unsupported unparse: "
+ + call.getOperator().getName());
+ }
+ case IS_NOT_FALSE:
+ RexNode operandIsNotFalse = call.operands.get(0);
+ if (RexUtil.isDeterministic(operandIsNotFalse)) {
+ // A IS NOT FALSE -> A IS NULL OR A
+ RexNode isNullFunc =
+ RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.IS_NULL,
operandIsNotFalse);
+ return RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.OR, isNullFunc,
operandIsNotFalse);
+ } else {
+ throw new UnsupportedOperationException("Unsupported unparse: "
+ + call.getOperator().getName());
+ }
+ case IS_TRUE:
+ RexNode operandIsTrue = call.operands.get(0);
+ if (RexUtil.isDeterministic(operandIsTrue)) {
+ // A IS TRUE -> A IS NOT NULL AND A
+ RexNode isNotNullFunc =
+ RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.IS_NOT_NULL,
operandIsTrue);
+ return RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.AND,
isNotNullFunc, operandIsTrue);
+ } else {
+ throw new UnsupportedOperationException("Unsupported unparse: "
+ + call.getOperator().getName());
+ }
+ case IS_NOT_TRUE:
+ RexNode operandIsNotTrue = call.operands.get(0);
+ if (RexUtil.isDeterministic(operandIsNotTrue)) {
+ // A IS NOT TRUE -> A IS NULL OR NOT A
+ RexNode isNullFunc =
+ RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.IS_NULL,
operandIsNotTrue);
+ RexNode notFunc =
+ RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.NOT,
operandIsNotTrue);
+ return RexBuilder.DEFAULT.makeCall(SqlStdOperatorTable.OR, isNullFunc,
notFunc);
+ } else {
+ throw new UnsupportedOperationException("Unsupported unparse: "
+ + call.getOperator().getName());
+ }
+ default:
+ return super.prepareUnparse(arg);
+ }
+ }
+
@Override public void unparseCall(SqlWriter writer, SqlCall call, int
leftPrec, int rightPrec) {
switch (call.getKind()) {
case ARRAY_VALUE_CONSTRUCTOR:
diff --git
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index ba9d311f20..9169aebe48 100644
---
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -374,7 +374,7 @@ private static String toSql(RelNode root, SqlDialect
dialect,
+ "WHERE `product_id` > 0\n"
+ "GROUP BY `product_id`";
final String expectedStarRocks = "SELECT"
- + " SUM(CASE WHEN `net_weight` > 0E0 IS TRUE"
+ + " SUM(CASE WHEN `net_weight` > 0E0 IS NOT NULL AND `net_weight` >
0E0"
+ " THEN `shelf_width` ELSE NULL END), SUM(`shelf_width`)\n"
+ "FROM `foodmart`.`product`\n"
+ "WHERE `product_id` > 0\n"
@@ -8553,6 +8553,94 @@ private void checkLiteral2(String expression, String
expected) {
.ok(expected);
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-6835">[CALCITE-6835]
+ * Invalid unparse for IS TRUE,IS FALSE,IS NOT TRUE and IS NOT FALSE
+ * in StarRocksDialect</a>. */
+ @Test void testIsTrue() {
+ final String sql = "SELECT * FROM \"EMP\" WHERE \"COMM\" > 0 IS TRUE";
+ final String expected = "SELECT *\n"
+ + "FROM \"SCOTT\".\"EMP\"\n"
+ + "WHERE CAST(\"COMM\" AS DECIMAL(12, 2)) > 0.00 IS TRUE";
+ String expectedStarRocks = "SELECT *\n"
+ + "FROM `SCOTT`.`EMP`\n"
+ + "WHERE CAST(`COMM` AS DECIMAL(12, 2)) > 0.00 IS NOT NULL AND
CAST(`COMM` AS DECIMAL(12, 2)) > 0.00";
+ sql(sql)
+ .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+ .ok(expected)
+ .withStarRocks().ok(expectedStarRocks);
+
+ final String sqlNoDeterministic =
+ "SELECT * FROM \"EMP\" WHERE \"COMM\" > RAND_INTEGER(10) IS TRUE";
+ sql(sqlNoDeterministic)
+ .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+ .withStarRocks()
+ .throws_("Unsupported unparse: IS TRUE");
+ }
+
+ @Test void testIsNotTrue() {
+ final String sql = "SELECT * FROM \"EMP\" WHERE \"COMM\" > 0 IS NOT TRUE";
+ final String expected = "SELECT *\n"
+ + "FROM \"SCOTT\".\"EMP\"\n"
+ + "WHERE CAST(\"COMM\" AS DECIMAL(12, 2)) > 0.00 IS NOT TRUE";
+ String expectedStarRocks = "SELECT *\n"
+ + "FROM `SCOTT`.`EMP`\n"
+ + "WHERE CAST(`COMM` AS DECIMAL(12, 2)) > 0.00 IS NULL OR NOT
CAST(`COMM` AS DECIMAL(12, 2)) > 0.00";
+ sql(sql)
+ .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+ .ok(expected)
+ .withStarRocks().ok(expectedStarRocks);
+
+ final String sqlNoDeterministic = "SELECT * \n"
+ + "FROM \"EMP\" WHERE \"COMM\" > RAND_INTEGER(10) IS NOT TRUE";
+ sql(sqlNoDeterministic)
+ .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+ .withStarRocks()
+ .throws_("Unsupported unparse: IS NOT TRUE");
+ }
+
+ @Test void testIsFalse() {
+ final String sql = "SELECT * FROM \"EMP\" WHERE \"COMM\" > 0 IS FALSE";
+ final String expected = "SELECT *\n"
+ + "FROM \"SCOTT\".\"EMP\"\n"
+ + "WHERE CAST(\"COMM\" AS DECIMAL(12, 2)) > 0.00 IS FALSE";
+ String expectedStarRocks = "SELECT *\n"
+ + "FROM `SCOTT`.`EMP`\n"
+ + "WHERE CAST(`COMM` AS DECIMAL(12, 2)) > 0.00 IS NOT NULL AND NOT
CAST(`COMM` AS DECIMAL(12, 2)) > 0.00";
+ sql(sql)
+ .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+ .ok(expected)
+ .withStarRocks().ok(expectedStarRocks);
+
+ final String sqlNoDeterministic = "SELECT * \n"
+ + "FROM \"EMP\" WHERE \"COMM\" > RAND_INTEGER(10) IS FALSE";
+ sql(sqlNoDeterministic)
+ .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+ .withStarRocks()
+ .throws_("Unsupported unparse: IS FALSE");
+ }
+
+ @Test void testIsNotFalse() {
+ final String sql = "SELECT * FROM \"EMP\" WHERE \"COMM\" > 0 IS NOT FALSE";
+ final String expected = "SELECT *\n"
+ + "FROM \"SCOTT\".\"EMP\"\n"
+ + "WHERE CAST(\"COMM\" AS DECIMAL(12, 2)) > 0.00 IS NOT FALSE";
+ String expectedStarRocks = "SELECT *\n"
+ + "FROM `SCOTT`.`EMP`\n"
+ + "WHERE CAST(`COMM` AS DECIMAL(12, 2)) > 0.00 IS NULL OR CAST(`COMM`
AS DECIMAL(12, 2)) > 0.00";
+ sql(sql)
+ .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+ .ok(expected)
+ .withStarRocks().ok(expectedStarRocks);
+
+ final String sqlNoDeterministic = "SELECT * \n"
+ + "FROM \"EMP\" WHERE \"COMM\" > RAND_INTEGER(10) IS NOT FALSE";
+ sql(sqlNoDeterministic)
+ .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+ .withStarRocks()
+ .throws_("Unsupported unparse: IS NOT FALSE");
+ }
+
@Test void testMerge() {
final String sql1 = "merge into \"DEPT\" as \"t\"\n"
+ "using \"DEPT\" as \"s\"\n"