You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2017/02/24 08:20:09 UTC

calcite git commit: [CALCITE-1439] Handle errors during constant reduction

Repository: calcite
Updated Branches:
  refs/heads/master 98016a4e3 -> 052f85459


[CALCITE-1439] Handle errors during constant reduction

If there is an error during constant reduction, simply return the
original expression. Then the query will return an error when
executed, which is the desired behavior.


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/052f8545
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/052f8545
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/052f8545

Branch: refs/heads/master
Commit: 052f854594f92fd52a142c53998b83d70302075b
Parents: 98016a4
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Feb 23 10:58:59 2017 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Feb 23 15:47:35 2017 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/rex/RexExecutable.java   | 20 +++++---
 .../org/apache/calcite/test/RexProgramTest.java | 35 ++++++++++++++
 core/src/test/resources/sql/misc.iq             | 49 ++++++++++++++++++--
 3 files changed, 93 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/052f8545/core/src/main/java/org/apache/calcite/rex/RexExecutable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexExecutable.java b/core/src/main/java/org/apache/calcite/rex/RexExecutable.java
index 03047f3..2907651 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexExecutable.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexExecutable.java
@@ -76,12 +76,20 @@ public class RexExecutable {
 
   public void reduce(RexBuilder rexBuilder, List<RexNode> constExps,
       List<RexNode> reducedValues) {
-    Object[] values = compiledFunction.apply(dataContext);
-    assert values.length == constExps.size();
-    final List<Object> valueList = Arrays.asList(values);
-    for (Pair<RexNode, Object> value : Pair.zip(constExps, valueList)) {
-      reducedValues.add(
-          rexBuilder.makeLiteral(value.right, value.left.getType(), true));
+    Object[] values;
+    try {
+      values = compiledFunction.apply(dataContext);
+      assert values.length == constExps.size();
+      final List<Object> valueList = Arrays.asList(values);
+      for (Pair<RexNode, Object> value : Pair.zip(constExps, valueList)) {
+        reducedValues.add(
+            rexBuilder.makeLiteral(value.right, value.left.getType(), true));
+      }
+    } catch (RuntimeException e) {
+      // One or more of the expressions failed.
+      // Don't reduce any of the expressions.
+      reducedValues.addAll(constExps);
+      values = new Object[constExps.size()];
     }
     Hook.EXPRESSION_REDUCER.run(Pair.of(code, values));
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/052f8545/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
index d021a5b..090f3ba 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -120,6 +120,11 @@ public class RexProgramTest {
     checkSimplify2(node, expected, expected);
   }
 
+  /** Simplifies an expression and checks that the result is unchanged. */
+  private void checkSimplifyUnchanged(RexNode node) {
+    checkSimplify(node, node.toString());
+  }
+
   /** Simplifies an expression and checks the result if unknowns remain
    * unknown, or if unknown becomes false. If the result is the same, use
    * {@link #checkSimplify(RexNode, String)}.
@@ -191,6 +196,10 @@ public class RexProgramTest {
     return rexBuilder.makeCall(SqlStdOperatorTable.CASE, nodes);
   }
 
+  private RexNode cast(RexNode e, RelDataType type) {
+    return rexBuilder.makeCast(type, e);
+  }
+
   private RexNode eq(RexNode n1, RexNode n2) {
     return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, n1, n2);
   }
@@ -1274,6 +1283,32 @@ public class RexProgramTest {
     }
   }
 
+  @Test public void testSimplifyCastLiteral2() {
+    final RexLiteral literalAbc = rexBuilder.makeLiteral("abc");
+    final RexLiteral literalOne = rexBuilder.makeExactLiteral(BigDecimal.ONE);
+    final RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER);
+    final RelDataType varcharType =
+        typeFactory.createSqlType(SqlTypeName.VARCHAR, 10);
+    final RelDataType booleanType =
+        typeFactory.createSqlType(SqlTypeName.BOOLEAN);
+    final RelDataType dateType = typeFactory.createSqlType(SqlTypeName.DATE);
+    final RelDataType timestampType =
+        typeFactory.createSqlType(SqlTypeName.TIMESTAMP);
+    checkSimplifyUnchanged(cast(literalAbc, intType));
+    checkSimplify(cast(literalOne, intType), "1");
+    checkSimplify(cast(literalAbc, varcharType), "'abc'");
+    checkSimplify(cast(literalOne, varcharType), "'1'");
+    checkSimplifyUnchanged(cast(literalAbc, booleanType));
+    checkSimplify(cast(literalOne, booleanType),
+        "false"); // different from Hive
+    checkSimplifyUnchanged(cast(literalAbc, dateType));
+    checkSimplify(cast(literalOne, dateType),
+        "1970-01-02"); // different from Hive
+    checkSimplifyUnchanged(cast(literalAbc, timestampType));
+    checkSimplify(cast(literalOne, timestampType),
+        "1970-01-01 00:00:00"); // different from Hive
+  }
+
   private Calendar cal(int y, int m, int d, int h, int mm, int s) {
     final Calendar c = Calendar.getInstance(DateTimeUtils.GMT_ZONE);
     c.set(Calendar.YEAR, y);

http://git-wip-us.apache.org/repos/asf/calcite/blob/052f8545/core/src/test/resources/sql/misc.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.iq b/core/src/test/resources/sql/misc.iq
index cbeb56a..271c43b 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -1633,65 +1633,104 @@ EnumerableCalc(expr#0=[{inputs}], expr#1=['TR'], expr#2=['UE'], expr#3=[||($t1,
   EnumerableValues(tuples=[[{ 0 }]])
 !plan
 
-!if (fixed.calcite1439) {
+# In the following, that we get an error at run time,
+# and that the plan shows that the expression has not been reduced.
 values cast('null' as boolean);
+Invalid character for cast
 !error
+EnumerableCalc(expr#0=[{inputs}], expr#1=['null'], expr#2=[CAST($t1):BOOLEAN NOT NULL], EXPR$0=[$t2])
+  EnumerableValues(tuples=[[{ 0 }]])
 !plan
 
+# The following throw give an error (good!)
+# but throw java.lang.ExceptionInInitializerError (not great).
 values cast('' as date);
+Caused by: java.lang.NumberFormatException: For input string: ""
 !error
 
 values cast('' as timestamp);
+Caused by: java.lang.NumberFormatException: For input string: ""
 !error
 
 values cast('' as integer);
+Caused by: java.lang.NumberFormatException: For input string: ""
 !error
 
 values cast('' as boolean);
+Caused by: java.lang.RuntimeException: Invalid character for cast
 !error
 
 values cast('' as double);
+Caused by: java.lang.NumberFormatException: empty String
 !error
 
 # Postgres fails:
 #  ERROR:  invalid input syntax for integer: "1.56"
 values cast('15.6' as integer);
+Caused by: java.lang.NumberFormatException: For input string: "15.6"
 !error
 
 # Postgres fails:
 #  ERROR:  invalid input syntax for integer: " - 5 "
 values cast(' - 5 ' as double);
+Caused by: java.lang.NumberFormatException: For input string: "- 5"
 !error
 
 # Out of TINYINT range (max 127)
 values cast('200' as tinyint);
+Caused by: java.lang.NumberFormatException: Value out of range. Value:"200" Radix:10
 !error
 
 # Out of SMALLINT range (max 32767)
 values cast('50000' as smallint);
+Caused by: java.lang.NumberFormatException: Value out of range. Value:"50000" Radix:10
 !error
 
 # Out of INTEGER range (max 2.1e9)
 values cast('4567891234' as integer);
+Caused by: java.lang.NumberFormatException: For input string: "4567891234"
 !error
 
 # Out of BIGINT range (max 9.2e18)
 values cast('12345678901234567890' as bigint);
+Caused by: java.lang.NumberFormatException: For input string: "12345678901234567890"
 !error
 
 # Out of REAL range
+# (Should give an error, not infinity.)
 values cast('12.34e56' as real);
-!error
++----------+
+| EXPR$0   |
++----------+
+| Infinity |
++----------+
+(1 row)
+
+!ok
 
 # Out of FLOAT range
+# (Should give an error, not infinity.)
 values cast('12.34e5678' as float);
-!error
++----------+
+| EXPR$0   |
++----------+
+| Infinity |
++----------+
+(1 row)
+
+!ok
 
 # Out of DOUBLE range
+# (Should give an error, not infinity.)
 values cast('12.34e5678' as double);
-!error
++----------+
+| EXPR$0   |
++----------+
+| Infinity |
++----------+
+(1 row)
 
-!}
+!ok
 
 # Postgres succeeds
 values cast(' -5 ' as double);