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 e9db5bdb7c [CALCITE-6979] Invalid unparse for IS TRUE,IS FALSE,IS NOT
TRUE and IS NOT FALSE in ClickHouseDialect
e9db5bdb7c is described below
commit e9db5bdb7c78cdbbed5bb7917b62a53b6450aa40
Author: Yu Xu <[email protected]>
AuthorDate: Wed Apr 23 18:10:56 2025 +0800
[CALCITE-6979] Invalid unparse for IS TRUE,IS FALSE,IS NOT TRUE and IS NOT
FALSE in ClickHouseDialect
---
.../calcite/sql/dialect/ClickHouseSqlDialect.java | 5 ++
.../calcite/sql/dialect/StarRocksSqlDialect.java | 66 +-----------------
.../apache/calcite/util/RelToSqlConverterUtil.java | 79 ++++++++++++++++++++++
.../calcite/rel/rel2sql/RelToSqlConverterTest.java | 37 ++++++++--
4 files changed, 118 insertions(+), 69 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/sql/dialect/ClickHouseSqlDialect.java
b/core/src/main/java/org/apache/calcite/sql/dialect/ClickHouseSqlDialect.java
index 9e7fa6b9e0..630ef0cb74 100644
---
a/core/src/main/java/org/apache/calcite/sql/dialect/ClickHouseSqlDialect.java
+++
b/core/src/main/java/org/apache/calcite/sql/dialect/ClickHouseSqlDialect.java
@@ -21,6 +21,7 @@
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.RexNode;
import org.apache.calcite.sql.SqlAbstractDateTimeLiteral;
import org.apache.calcite.sql.SqlBasicTypeNameSpec;
import org.apache.calcite.sql.SqlCall;
@@ -112,6 +113,10 @@ public ClickHouseSqlDialect(Context context) {
return CalendarPolicy.SHIFT;
}
+ @Override public RexNode prepareUnparse(RexNode arg) {
+ return RelToSqlConverterUtil.unparseIsTrueOrFalse(arg);
+ }
+
@Override public @Nullable SqlNode getCastSpec(RelDataType type) {
if (type instanceof BasicSqlType) {
SqlTypeName typeName = type.getSqlTypeName();
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 a21c1b577b..8b62bd8bfd 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,10 +21,7 @@
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;
@@ -35,16 +32,12 @@
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.apache.calcite.util.RelToSqlConverterUtil;
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;
/**
@@ -103,62 +96,7 @@ public StarRocksSqlDialect(Context context) {
}
@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);
- }
+ return RelToSqlConverterUtil.unparseIsTrueOrFalse(arg);
}
@Override public void unparseCall(SqlWriter writer, SqlCall call, int
leftPrec, int rightPrec) {
diff --git
a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java
b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java
index 80e234abc1..aaa1603bbe 100644
--- a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java
+++ b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java
@@ -16,6 +16,10 @@
*/
package org.apache.calcite.util;
+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.SqlCall;
import org.apache.calcite.sql.SqlCharStringLiteral;
import org.apache.calcite.sql.SqlKind;
@@ -64,6 +68,81 @@ public static void unparseHiveTrim(
}
}
+ /**
+ * Unparses IS TRUE,IS FALSE,IS NOT TRUE and IS NOT FALSE.
+ *
+ * <p>For example :
+ *
+ * <blockquote><pre>
+ * A IS TRUE → A IS NOT NUL AND A
+ * A IS FALSE → A IS NOT NUL AND NOT A
+ * A IS NOT TRUE → A IS NUL OR NOT A
+ * A IS NOT FALSE → A IS NUL OR A
+ *
+ * an exception will be thrown when A is a non-deterministic function such
as RAND_INTEGER.
+ * </pre></blockquote>
+ *
+ * @param rexNode rexNode
+ */
+ public static RexNode unparseIsTrueOrFalse(RexNode rexNode) {
+ if (!(rexNode instanceof RexCall)) {
+ return rexNode;
+ }
+ RexCall call = (RexCall) rexNode;
+ 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 rexNode;
+ }
+ }
+
/**
* Unparses Array and Map 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 2e9c3648ec..77a41f894d 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
@@ -8679,7 +8679,10 @@ private void checkLiteral2(String expression, String
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>. */
+ * in StarRocksDialect</a>,
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-6979">[CALCITE-6979]
+ * Invalid unparse for IS TRUE,IS FALSE,IS NOT TRUE and IS NOT FALSE
+ * in ClickHouseDialect</a>.*/
@Test void testIsTrue() {
final String sql = "SELECT * FROM \"EMP\" WHERE \"COMM\" > 0 IS TRUE";
final String expected = "SELECT *\n"
@@ -8688,16 +8691,22 @@ private void checkLiteral2(String expression, String
expected) {
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";
+ String expectedClickHouse = "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);
+ .withStarRocks().ok(expectedStarRocks)
+ .withClickHouse().ok(expectedClickHouse);
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")
+ .withClickHouse()
.throws_("Unsupported unparse: IS TRUE");
}
@@ -8709,16 +8718,22 @@ private void checkLiteral2(String expression, String
expected) {
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";
+ String expectedClickHouse = "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);
+ .withStarRocks().ok(expectedStarRocks)
+ .withClickHouse().ok(expectedClickHouse);
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")
+ .withClickHouse()
.throws_("Unsupported unparse: IS NOT TRUE");
}
@@ -8730,16 +8745,22 @@ private void checkLiteral2(String expression, String
expected) {
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";
+ String expectedClickHouse = "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);
+ .withStarRocks().ok(expectedStarRocks)
+ .withClickHouse().ok(expectedClickHouse);
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")
+ .withClickHouse()
.throws_("Unsupported unparse: IS FALSE");
}
@@ -8751,16 +8772,22 @@ private void checkLiteral2(String expression, String
expected) {
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";
+ String expectedClickHouse = "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);
+ .withStarRocks().ok(expectedStarRocks)
+ .withClickHouse().ok(expectedClickHouse);
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")
+ .withClickHouse()
.throws_("Unsupported unparse: IS NOT FALSE");
}