[CALCITE-4716] ClassCastException converting SARG in RelNode to SQL
Close apache/calcite#2474
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 1af0b05..be8ac7c 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
@@ -48,6 +48,7 @@
import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.rex.RexSubQuery;
import org.apache.calcite.rex.RexUnknownAs;
+import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.rex.RexWindow;
import org.apache.calcite.rex.RexWindowBound;
import org.apache.calcite.sql.JoinType;
@@ -692,10 +693,13 @@
case SEARCH:
final RexCall search = (RexCall) rex;
- literal = (RexLiteral) search.operands.get(1);
- final Sarg sarg = castNonNull(literal.getValueAs(Sarg.class));
- //noinspection unchecked
- return toSql(program, search.operands.get(0), literal.getType(), sarg);
+ if (search.operands.get(1).getKind() == SqlKind.LITERAL) {
+ literal = (RexLiteral) search.operands.get(1);
+ final Sarg sarg = castNonNull(literal.getValueAs(Sarg.class));
+ //noinspection unchecked
+ return toSql(program, search.operands.get(0), literal.getType(), sarg);
+ }
+ return toSql(program, RexUtil.expandSearch(implementor().rexBuilder, program, search));
case EXISTS:
case SCALAR_QUERY:
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 94ef0c0..2ef2b39 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
@@ -1043,6 +1043,28 @@
}
/** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-4716">[CALCITE-4716]
+ * ClassCastException converting SARG in RelNode to SQL</a>. */
+ @Test void testSargConversion() {
+ final Function<RelBuilder, RelNode> relFn = b -> b
+ .scan("EMP")
+ .filter(
+ b.or(
+ b.and(
+ b.call(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, b.field("EMPNO"), b.literal(10)),
+ b.call(SqlStdOperatorTable.LESS_THAN, b.field("EMPNO"), b.literal(12))),
+ b.and(
+ b.call(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, b.field("EMPNO"), b.literal(6)),
+ b.call(SqlStdOperatorTable.LESS_THAN, b.field("EMPNO"), b.literal(8)))))
+ .build();
+ final RuleSet rules = RuleSets.ofList(CoreRules.FILTER_TO_CALC);
+ final String expected = "SELECT *\n"
+ + "FROM \"scott\".\"EMP\"\n"
+ + "WHERE \"EMPNO\" >= 6 AND \"EMPNO\" < 8 OR \"EMPNO\" >= 10 AND \"EMPNO\" < 12";
+ relFn(relFn).optimize(rules, null).ok(expected);
+ }
+
+ /** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-1946">[CALCITE-1946]
* JDBC adapter should generate sub-SELECT if dialect does not support nested
* aggregate functions</a>. */