You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jc...@apache.org on 2020/04/08 04:02:07 UTC
[calcite] branch master updated: [CALCITE-3898] RelOptPredicateList
may generate incorrect map of constant values
This is an automated email from the ASF dual-hosted git repository.
jcamacho pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push:
new c3147f4 [CALCITE-3898] RelOptPredicateList may generate incorrect map of constant values
c3147f4 is described below
commit c3147f477f843d283c43d1e858534d58a7174544
Author: Jesus Camacho Rodriguez <jc...@apache.org>
AuthorDate: Mon Apr 6 14:18:08 2020 -0700
[CALCITE-3898] RelOptPredicateList may generate incorrect map of constant values
Close apache/calcite#1899
---
.../main/java/org/apache/calcite/rex/RexUtil.java | 43 +++++++++++++++++++--
.../org/apache/calcite/rex/RexProgramTest.java | 44 +++++++++++++++++++++-
2 files changed, 82 insertions(+), 5 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index c53a7ea..7d5bcfc 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -422,7 +422,7 @@ public class RexUtil {
// Convert "CAST(c) = literal" to "c = literal", as long as it is a
// widening cast.
final RexNode operand = ((RexCall) left).getOperands().get(0);
- if (canAssignFrom(left.getType(), operand.getType())) {
+ if (canAssignFrom(left.getType(), operand.getType(), rexBuilder.getTypeFactory())) {
final RexNode castRight =
rexBuilder.makeCast(operand.getType(), constant);
if (castRight instanceof RexLiteral) {
@@ -454,15 +454,50 @@ public class RexUtil {
* <li>{@code canAssignFrom(BIGINT, VARCHAR)} returns {@code false}</li>
* </ul>
*/
- private static boolean canAssignFrom(RelDataType type1, RelDataType type2) {
+ private static boolean canAssignFrom(RelDataType type1, RelDataType type2,
+ RelDataTypeFactory typeFactory) {
final SqlTypeName name1 = type1.getSqlTypeName();
final SqlTypeName name2 = type2.getSqlTypeName();
if (name1.getFamily() == name2.getFamily()) {
switch (name1.getFamily()) {
case NUMERIC:
- return name1.compareTo(name2) >= 0;
+ if (SqlTypeUtil.isExactNumeric(type1)
+ && SqlTypeUtil.isExactNumeric(type2)) {
+ int precision1;
+ int scale1;
+ if (name1 == SqlTypeName.DECIMAL) {
+ type1 = typeFactory.decimalOf(type1);
+ precision1 = type1.getPrecision();
+ scale1 = type1.getScale();
+ } else {
+ precision1 = typeFactory.getTypeSystem().getMaxPrecision(name1);
+ scale1 = typeFactory.getTypeSystem().getMaxScale(name1);
+ }
+ int precision2;
+ int scale2;
+ if (name2 == SqlTypeName.DECIMAL) {
+ type2 = typeFactory.decimalOf(type2);
+ precision2 = type2.getPrecision();
+ scale2 = type2.getScale();
+ } else {
+ precision2 = typeFactory.getTypeSystem().getMaxPrecision(name2);
+ scale2 = typeFactory.getTypeSystem().getMaxScale(name2);
+ }
+ return precision1 >= precision2
+ && scale1 >= scale2;
+ } else if (SqlTypeUtil.isApproximateNumeric(type1)
+ && SqlTypeUtil.isApproximateNumeric(type2)) {
+ return type1.getPrecision() >= type2.getPrecision()
+ && type1.getScale() >= type2.getScale();
+ }
+ break;
default:
- return true;
+ // getPrecision() will return:
+ // - number of decimal digits for fractional seconds for datetime types
+ // - length in characters for character types
+ // - length in bytes for binary types
+ // - RelDataType.PRECISION_NOT_SPECIFIED (-1) if not applicable for this type
+ return type1.getPrecision() >= type2.getPrecision();
}
}
return false;
diff --git a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
index 390bfa4..53676e4 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
@@ -2196,12 +2196,17 @@ class RexProgramTest extends RexProgramTestBase {
@Test void testConstantMap() {
final RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER);
+ final RelDataType bigintType = typeFactory.createSqlType(SqlTypeName.BIGINT);
+ final RelDataType decimalType = typeFactory.createSqlType(SqlTypeName.DECIMAL, 4, 2);
+ final RelDataType charType = typeFactory.createSqlType(SqlTypeName.CHAR, 5);
final RelDataType rowType = typeFactory.builder()
.add("a", intType)
.add("b", intType)
.add("c", intType)
.add("d", intType)
- .add("e", intType)
+ .add("e", bigintType)
+ .add("f", decimalType)
+ .add("g", charType)
.build();
final RexDynamicParam range = rexBuilder.makeDynamicParam(rowType, 0);
@@ -2210,6 +2215,8 @@ class RexProgramTest extends RexProgramTestBase {
final RexNode cRef = rexBuilder.makeFieldAccess(range, 2);
final RexNode dRef = rexBuilder.makeFieldAccess(range, 3);
final RexNode eRef = rexBuilder.makeFieldAccess(range, 4);
+ final RexNode fRef = rexBuilder.makeFieldAccess(range, 5);
+ final RexNode gRef = rexBuilder.makeFieldAccess(range, 6);
final RexLiteral literal1 = rexBuilder.makeExactLiteral(BigDecimal.ONE);
final RexLiteral literal2 = rexBuilder.makeExactLiteral(BigDecimal.valueOf(2));
@@ -2237,6 +2244,41 @@ class RexProgramTest extends RexProgramTestBase {
ImmutableList.of(eq(aRef, literal1),
eq(aRef, literal2)));
assertThat(getString(map3), is("{1=?0.a, 2=?0.a}"));
+
+ // Different precision and scale in decimal
+ final ImmutableMap<RexNode, RexNode> map4 =
+ RexUtil.predicateConstants(RexNode.class, rexBuilder,
+ ImmutableList.of(
+ eq(cast(fRef, typeFactory.createSqlType(SqlTypeName.DECIMAL, 3, 1)),
+ rexBuilder.makeExactLiteral(BigDecimal.valueOf(21.2)))));
+ assertThat(
+ getString(map4), is("{21.2:DECIMAL(3, 1)=CAST(?0.f):DECIMAL(3, 1) NOT NULL,"
+ + " CAST(?0.f):DECIMAL(3, 1) NOT NULL=21.2:DECIMAL(3, 1)}"));
+
+ // Different precision in char
+ final ImmutableMap<RexNode, RexNode> map5 =
+ RexUtil.predicateConstants(RexNode.class, rexBuilder,
+ ImmutableList.of(
+ eq(cast(gRef, typeFactory.createSqlType(SqlTypeName.CHAR, 3)),
+ rexBuilder.makeLiteral("abc"))));
+ assertThat(
+ getString(map5), is("{'abc'=CAST(?0.g):CHAR(3) NOT NULL,"
+ + " CAST(?0.g):CHAR(3) NOT NULL='abc'}"));
+
+ // Cast bigint to int
+ final ImmutableMap<RexNode, RexNode> map6 =
+ RexUtil.predicateConstants(RexNode.class, rexBuilder,
+ ImmutableList.of(
+ eq(cast(eRef, typeFactory.createSqlType(SqlTypeName.INTEGER)), literal1)));
+ assertThat(
+ getString(map6), is("{1=CAST(?0.e):INTEGER NOT NULL, CAST(?0.e):INTEGER NOT NULL=1}"));
+
+ // Cast int to bigint
+ final ImmutableMap<RexNode, RexNode> map7 =
+ RexUtil.predicateConstants(RexNode.class, rexBuilder,
+ ImmutableList.of(
+ eq(cast(aRef, typeFactory.createSqlType(SqlTypeName.BIGINT)), literal1)));
+ assertThat(getString(map7), is("{1=CAST(?0.a):BIGINT NOT NULL, ?0.a=1}"));
}
@Test void notDistinct() {