[CALCITE-6265] Type coercion is failing for numeric values in prepared statements
Address some issues on the original patch
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java
index d4cfb7d..7382bee 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java
@@ -354,6 +354,9 @@
if (!Types.needTypeCast(fromType, toType)) {
return operand;
}
+
+ // TODO use Expressions#convertChecked to throw exception in case of overflow (CALCITE-6366)
+
// E.g. from "Short" to "int".
// Generate "x.intValue()".
final Primitive toPrimitive = Primitive.of(toType);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index 74a69fe..e49788c 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -31,7 +31,6 @@
import org.apache.calcite.linq4j.tree.ParameterExpression;
import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.linq4j.tree.Statement;
-import org.apache.calcite.linq4j.tree.Types;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexCall;
@@ -1453,20 +1452,17 @@
// For numeric types, use java.lang.Number to prevent cast exception
// when the parameter type differs from the target type
- Expression argumentExpression =
- EnumUtils.convert(
+ final Expression valueExpression = isNumeric
+ ? EnumUtils.convert(
+ EnumUtils.convert(
+ Expressions.call(root, BuiltInMethod.DATA_CONTEXT_GET.method,
+ Expressions.constant("?" + dynamicParam.getIndex())),
+ java.lang.Number.class),
+ storageType)
+ : EnumUtils.convert(
Expressions.call(root, BuiltInMethod.DATA_CONTEXT_GET.method,
Expressions.constant("?" + dynamicParam.getIndex())),
- isNumeric ? java.lang.Number.class : storageType);
-
- // Short-circuit if the expression evaluates to null. The cast
- // may throw a NullPointerException as it calls methods on the
- // object such as longValue().
- Expression valueExpression =
- Expressions.condition(
- Expressions.equal(argumentExpression, Expressions.constant(null)),
- Expressions.constant(null),
- Types.castIfNecessary(storageType, argumentExpression));
+ storageType);
final ParameterExpression valueVariable =
Expressions.parameter(valueExpression.getType(),
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 8fe3de2..023a57e 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -8453,6 +8453,33 @@
}
}
+ @Test void bindDecimalParameter() {
+ final String sql =
+ "with cte as (select 2500.55 as val)"
+ + "select * from cte where val = ?";
+
+ CalciteAssert.hr()
+ .query(sql)
+ .consumesPreparedStatement(p -> {
+ p.setBigDecimal(1, new BigDecimal("2500.55"));
+ })
+ .returnsUnordered("VAL=2500.55");
+ }
+
+ @Test void bindNullParameter() {
+ final String sql =
+ "with cte as (select 2500.55 as val)"
+ + "select * from cte where val = ?";
+
+ CalciteAssert.hr()
+ .query(sql)
+ .consumesPreparedStatement(p -> {
+ p.setBigDecimal(1, null);
+ })
+ .returnsUnordered("");
+ }
+
+ @Disabled("CALCITE-6366")
@Test void bindOverflowingTinyIntParameter() {
final String sql =
"with cte as (select cast(300 as smallint) as empid)"
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
index 3dec960..0be03c9 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
@@ -28,7 +28,6 @@
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
-import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -429,25 +428,11 @@
&& Number.class.isAssignableFrom((Class) returnType)
&& type instanceof Class
&& Number.class.isAssignableFrom((Class) type)) {
-
- if (returnType == BigDecimal.class) {
- return Expressions.call(
- BigDecimal.class,
- "valueOf",
- Expressions.call(expression, "longValue"));
- } else if (
- returnType == Byte.class
- || returnType == Short.class
- || returnType == Integer.class
- || returnType == Long.class) {
- return Expressions.convertChecked(expression, returnType);
- } else {
- // E.g.
- // Integer foo(BigDecimal o) {
- // return o.intValue();
- // }
- return Expressions.unbox(expression, requireNonNull(Primitive.ofBox(returnType)));
- }
+ // E.g.
+ // Integer foo(BigDecimal o) {
+ // return o.intValue();
+ // }
+ return Expressions.unbox(expression, requireNonNull(Primitive.ofBox(returnType)));
}
if (Primitive.is(returnType) && !Primitive.is(type)) {
// E.g.