This is an automated email from the ASF dual-hosted git repository.
zhenchen 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 8b5c17e51e [CALCITE-7258] RelBuilder.filter should throw if the
condition is not BOOLEAN
8b5c17e51e is described below
commit 8b5c17e51e0c9c3f8e3db17c8d449e67e4e2974a
Author: Zhen Chen <[email protected]>
AuthorDate: Sat Nov 1 17:52:36 2025 +0800
[CALCITE-7258] RelBuilder.filter should throw if the condition is not
BOOLEAN
---
core/src/main/java/org/apache/calcite/rel/core/Filter.java | 14 ++++++++++++++
.../test/java/org/apache/calcite/test/RelBuilderTest.java | 14 ++++++++++++++
.../src/main/java/org/apache/calcite/piglet/Handler.java | 6 +++++-
.../java/org/apache/calcite/piglet/PigRelOpVisitor.java | 7 ++++++-
.../test/java/org/apache/calcite/test/PigRelExTest.java | 11 ++++++-----
.../src/test/java/org/apache/calcite/test/PigletTest.java | 2 +-
6 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Filter.java
b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
index 14b4b2fcc2..27aafd3752 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Filter.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
@@ -28,12 +28,14 @@
import org.apache.calcite.rel.hint.RelHint;
import org.apache.calcite.rel.metadata.RelMdUtil;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rex.RexChecker;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexOver;
import org.apache.calcite.rex.RexProgram;
import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.Litmus;
import com.google.common.collect.ImmutableList;
@@ -146,6 +148,18 @@ public final boolean containsOver() {
if (RexUtil.isNullabilityCast(getCluster().getTypeFactory(), condition)) {
return litmus.fail("Cast for just nullability not allowed");
}
+
+ final RelDataType conditionType = condition.getType();
+ if (!conditionType.isNullable() && conditionType.getSqlTypeName() !=
SqlTypeName.BOOLEAN) {
+ return litmus.fail("Filter condition must have type BOOLEAN, got " +
conditionType);
+ }
+ if (conditionType.isNullable()
+ && conditionType.getSqlTypeName() != SqlTypeName.BOOLEAN
+ && conditionType.getSqlTypeName() != SqlTypeName.NULL) {
+ return litmus.fail("Filter condition must have type BOOLEAN or NULL, got
"
+ + conditionType);
+ }
+
final RexChecker checker =
new RexChecker(getInput().getRowType(), context, litmus);
condition.accept(checker);
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index f1dc0baac9..b54e08e26d 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -5969,6 +5969,20 @@ private static RelNode
buildCorrelateWithJoin(JoinRelType type, RelBuilder build
}
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7258">[CALCITE-7258]
+ * RelBuilder.filter should throw if the condition is not BOOLEAN</a>. */
+ @Test void testFilterWithNonBooleanLiteralCondition() {
+ final RelBuilder builder = RelBuilder.create(config().build());
+ try {
+ builder.scan("EMP")
+ .filter(builder.literal("foo"))
+ .build();
+ } catch (Error e) {
+ assertTrue(e.getMessage().contains("Filter condition must have type
BOOLEAN"));
+ }
+ }
+
/** Operand to a user-defined function. */
private interface Arg {
String name();
diff --git a/piglet/src/main/java/org/apache/calcite/piglet/Handler.java
b/piglet/src/main/java/org/apache/calcite/piglet/Handler.java
index 04646b5661..d8acf8432a 100644
--- a/piglet/src/main/java/org/apache/calcite/piglet/Handler.java
+++ b/piglet/src/main/java/org/apache/calcite/piglet/Handler.java
@@ -107,7 +107,11 @@ public Handler handle(Ast.Node node) {
builder.clear();
input = map.get(filter.source.value);
builder.push(input);
- final RexNode rexNode = toRex(filter.condition);
+ RexNode rexNode = toRex(filter.condition);
+ if (rexNode.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
+ RelDataType boolType =
builder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN);
+ rexNode = builder.getRexBuilder().makeCast(boolType, rexNode);
+ }
builder.filter(rexNode);
register(filter.target.value);
return this;
diff --git
a/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpVisitor.java
b/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpVisitor.java
index 62bf4f0bea..e1c90e25cc 100644
--- a/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpVisitor.java
+++ b/piglet/src/main/java/org/apache/calcite/piglet/PigRelOpVisitor.java
@@ -29,6 +29,7 @@
import org.apache.calcite.rex.RexWindowBounds;
import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.Pair;
@@ -169,7 +170,11 @@ List<RelNode> translate() throws FrontendException {
}
@Override public void visit(LOFilter filter) throws FrontendException {
- final RexNode relExFilter = PigRelExVisitor.translatePigEx(builder,
filter.getFilterPlan());
+ RexNode relExFilter = PigRelExVisitor.translatePigEx(builder,
filter.getFilterPlan());
+ if (relExFilter.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
+ RelDataType boolType =
builder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN);
+ relExFilter = builder.getRexBuilder().makeCast(boolType, relExFilter);
+ }
builder.filter(relExFilter);
builder.register(filter);
}
diff --git a/piglet/src/test/java/org/apache/calcite/test/PigRelExTest.java
b/piglet/src/test/java/org/apache/calcite/test/PigRelExTest.java
index 5d56694c04..aff0759796 100644
--- a/piglet/src/test/java/org/apache/calcite/test/PigRelExTest.java
+++ b/piglet/src/test/java/org/apache/calcite/test/PigRelExTest.java
@@ -173,15 +173,16 @@ public void testMatch() {
}
@Test void testTupleDereference() {
- checkTranslation("k2.k21", inTree("[$11.k21]"));
- checkTranslation("k2.(k21, k22)", inTree("[ROW($11.k21, $11.k22)]"));
+ checkTranslation("k2.k21", inTree("[<>($11.k21, 0)]"));
+ checkTranslation("k2.(k21, k22)", inTree("[CAST(ROW($11.k21,
$11.k22)):BOOLEAN NOT NULL]"));
checkTranslation("k2.k22.(k221,k222)",
- inTree("[ROW($11.k22.k221, $11.k22.k222)]"));
+ inTree("[CAST(ROW($11.k22.k221, $11.k22.k222)):BOOLEAN NOT NULL]"));
}
@Test void testBagDereference() {
- checkTranslation("l2.l22", inTree("[MULTISET_PROJECTION($13, 1)]"));
- checkTranslation("l2.(l21, l22)", inTree("[MULTISET_PROJECTION($13, 0,
1)]"));
+ checkTranslation("l2.l22", inTree("[CAST(MULTISET_PROJECTION($13,
1)):BOOLEAN NOT NULL]"));
+ checkTranslation("l2.(l21, l22)",
+ inTree("[CAST(MULTISET_PROJECTION($13, 0, 1)):BOOLEAN NOT NULL]"));
}
@Test void testMapLookup() {
diff --git a/piglet/src/test/java/org/apache/calcite/test/PigletTest.java
b/piglet/src/test/java/org/apache/calcite/test/PigletTest.java
index 5586b7fb27..3eddf31c8a 100644
--- a/piglet/src/test/java/org/apache/calcite/test/PigletTest.java
+++ b/piglet/src/test/java/org/apache/calcite/test/PigletTest.java
@@ -172,7 +172,7 @@ private static Fluent pig(String pig) {
@Test void testFilter() throws ParseException {
final String s = "A = LOAD 'DEPT';\n"
+ "B = FILTER A BY DEPTNO;";
- final String expected = "LogicalFilter(condition=[$0])\n"
+ final String expected = "LogicalFilter(condition=[<>($0, 0)])\n"
+ " LogicalTableScan(table=[[scott, DEPT]])\n";
pig(s).explainContains(expected);
}