This is an automated email from the ASF dual-hosted git repository.
zabetak 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 90712c8a18 [CALCITE-7201] ClassCastException in RexInterpreter#search
with different NUMERIC values
90712c8a18 is described below
commit 90712c8a18df637571ccefe2c04a17e8c2059be9
Author: Stamatis Zampetakis <[email protected]>
AuthorDate: Mon Oct 20 15:08:23 2025 +0200
[CALCITE-7201] ClassCastException in RexInterpreter#search with different
NUMERIC values
---
.../org/apache/calcite/rex/RexInterpreter.java | 8 ++-
.../org/apache/calcite/rex/RexInterpreterTest.java | 62 ++++++++++++++++++++++
.../apache/calcite/rex/RexProgramBuilderBase.java | 3 ++
3 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java
b/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java
index 9e2bd0e3a7..549efa5387 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java
@@ -304,7 +304,7 @@ private Comparable similar(List<Comparable> values) {
@SuppressWarnings({"rawtypes", "unchecked"})
private static Comparable search(SqlTypeName typeName, List<Comparable>
values) {
- final Comparable value = values.get(0);
+ Comparable value = values.get(0);
final Sarg sarg = (Sarg) values.get(1);
if (value == N) {
switch (sarg.nullAs) {
@@ -316,6 +316,9 @@ private static Comparable search(SqlTypeName typeName,
List<Comparable> values)
return N;
}
}
+ if (SqlTypeName.NUMERIC_TYPES.contains(typeName)) {
+ value = number(value);
+ }
return translate(sarg.rangeSet, typeName).contains(value);
}
@@ -332,6 +335,9 @@ private static RangeSet translate(RangeSet rangeSet,
SqlTypeName typeName) {
case TIMESTAMP:
return RangeSets.copy(rangeSet, TimestampString::getMillisSinceEpoch);
default:
+ if (SqlTypeName.NUMERIC_TYPES.contains(typeName)) {
+ return RangeSets.copy(rangeSet, RexInterpreter::number);
+ }
return rangeSet;
}
}
diff --git a/core/src/test/java/org/apache/calcite/rex/RexInterpreterTest.java
b/core/src/test/java/org/apache/calcite/rex/RexInterpreterTest.java
new file mode 100644
index 0000000000..ca91f20760
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/rex/RexInterpreterTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.rex;
+
+import org.apache.calcite.rel.metadata.NullSentinel;
+
+import org.junit.jupiter.api.Test;
+
+import static org.apache.calcite.rex.RexInterpreter.evaluate;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import static java.util.Collections.emptyMap;
+
+/**
+ * Test for {@link RexInterpreter}.
+ */
+public final class RexInterpreterTest extends RexProgramBuilderBase {
+
+ @Test void testSearchWithNumerics() {
+ RexNode l100_35 = literal(100.35);
+ RexNode l222_34 = literal(222.34);
+ RexNode l350_34 = literal(350.34);
+ RexNode l100 = literal(100);
+ RexNode l200 = literal(200);
+ RexNode l300 = literal(300);
+ // Exact with exact numerics types
+ assertEquals(true, evaluate(in(l100, l100, l200), emptyMap()));
+ assertEquals(false, evaluate(in(l300, l100, l200), emptyMap()));
+ assertEquals(true, evaluate(in(l200, nullInt, l200), emptyMap()));
+ assertEquals(NullSentinel.INSTANCE, evaluate(in(l100, nullInt, l200),
emptyMap()));
+ assertEquals(NullSentinel.INSTANCE, evaluate(in(nullInt, l100, l200),
emptyMap()));
+ // Approximate with exact numerics types
+ assertEquals(false, evaluate(in(l100_35, l100, l200), emptyMap()));
+ assertEquals(NullSentinel.INSTANCE, evaluate(in(l100_35, nullInt, l200),
emptyMap()));
+ assertEquals(NullSentinel.INSTANCE, evaluate(in(nullDouble, l100, l200),
emptyMap()));
+ // Approximate with approximate numerics types
+ assertEquals(true, evaluate(in(l100_35, l100_35, l222_34), emptyMap()));
+ assertEquals(false, evaluate(in(l350_34, l100_35, l222_34), emptyMap()));
+ assertEquals(true, evaluate(in(l100_35, l100_35, nullDouble), emptyMap()));
+ assertEquals(NullSentinel.INSTANCE, evaluate(in(l100_35, nullDouble,
l222_34), emptyMap()));
+ assertEquals(NullSentinel.INSTANCE, evaluate(in(nullDouble, l100_35,
l222_34), emptyMap()));
+ // Exact with approximate numerics types
+ assertEquals(false, evaluate(in(l100, l100_35, l222_34), emptyMap()));
+ assertEquals(NullSentinel.INSTANCE, evaluate(in(l100, nullDouble,
l222_34), emptyMap()));
+ assertEquals(NullSentinel.INSTANCE, evaluate(in(nullInt, l100_35,
l222_34), emptyMap()));
+ }
+}
diff --git
a/core/src/test/java/org/apache/calcite/rex/RexProgramBuilderBase.java
b/core/src/test/java/org/apache/calcite/rex/RexProgramBuilderBase.java
index 5c451ca8e5..b0286bd73a 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexProgramBuilderBase.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexProgramBuilderBase.java
@@ -539,6 +539,9 @@ protected RexLiteral literal(String value) {
return rexBuilder.makeLiteral(value, nonNullableVarchar);
}
+ protected RexLiteral literal(double value) {
+ return rexBuilder.makeApproxLiteral(value, nonNullableDouble);
+ }
// Variables
/**