This is an automated email from the ASF dual-hosted git repository.

mbudiu 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 ba9c840b75 [CALCITE-6168] RexExecutor can throw during compilation
ba9c840b75 is described below

commit ba9c840b7516acaccee20d778726c818928c40e2
Author: Mihai Budiu <[email protected]>
AuthorDate: Thu Jan 25 15:57:42 2024 -0800

    [CALCITE-6168] RexExecutor can throw during compilation
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 .../org/apache/calcite/rex/RexExecutorImpl.java    | 16 ++++++++++++----
 .../org/apache/calcite/rex/RexExecutorTest.java    | 22 ++++++++++++++++++++++
 .../java/org/apache/calcite/sql/test/SqlTests.java | 20 ++++++++++++++++++++
 3 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java 
b/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
index eaa3c7dd46..b32399b02f 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
@@ -129,10 +129,18 @@ public class RexExecutorImpl implements RexExecutor {
    */
   @Override public void reduce(RexBuilder rexBuilder, List<RexNode> constExps,
       List<RexNode> reducedValues) {
-    final String code =
-        compile(rexBuilder, constExps, (list, index, storageType) -> {
-          throw new UnsupportedOperationException();
-        });
+    String code;
+    try {
+      code = compile(rexBuilder, constExps, (list, index, storageType) -> {
+        throw new UnsupportedOperationException();
+      });
+    } catch (RuntimeException ex) {
+      // Give up on reduction and return expressions unchanged.
+      // This effectively moves the error from compile time to runtime.
+      // We could give a warning here if there was a mechanism for warnings.
+      reducedValues.addAll(constExps);
+      return;
+    }
 
     final RexExecutable executable = new RexExecutable(code, constExps);
     executable.setDataContext(dataContext);
diff --git a/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java 
b/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
index 74c51229f2..b4631eee0b 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
@@ -402,4 +402,26 @@ class RexExecutorTest {
       assertThat(reducedValues.get(1), instanceOf(RexCall.class));
     });
   }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6168";>[CALCITE-6168]
+   * RexExecutor can throw during compilation</a>. */
+  @Test void testCompileTimeException() {
+    check((rexBuilder, executor) -> {
+      final List<RexNode> reducedValues = new ArrayList<>();
+      final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
+      // CAST(200 as TINYINT)
+      final RelDataType tinyint =
+          typeFactory.createSqlType(SqlTypeName.TINYINT);
+      final RelDataType integer  =
+          typeFactory.createSqlType(SqlTypeName.INTEGER);
+      final RexNode cast =
+          rexBuilder.makeCast(tinyint,
+              rexBuilder.makeLiteral(200, integer, true));
+      executor.reduce(rexBuilder, ImmutableList.of(cast),
+          reducedValues);
+      assertThat(reducedValues, hasSize(1));
+      assertThat(reducedValues.get(0), instanceOf(RexCall.class));
+    });
+  }
 }
diff --git a/testkit/src/main/java/org/apache/calcite/sql/test/SqlTests.java 
b/testkit/src/main/java/org/apache/calcite/sql/test/SqlTests.java
index bb33212d97..7d9a633618 100644
--- a/testkit/src/main/java/org/apache/calcite/sql/test/SqlTests.java
+++ b/testkit/src/main/java/org/apache/calcite/sql/test/SqlTests.java
@@ -265,6 +265,20 @@ public abstract class SqlTests {
       }
     }
 
+    // Search for an IllegalStateException somewhere in the stack.
+    // These are thrown by the enumerable implementors when evaluating
+    // an expression that produces an error.
+    IllegalStateException ise = null;
+    for (Throwable x = ex; x != null; x = x.getCause()) {
+      if (x instanceof IllegalStateException) {
+        ise = (IllegalStateException) x;
+        break;
+      }
+      if (x.getCause() == x) {
+        break;
+      }
+    }
+
     // Search for a SqlParseException -- with its position set -- somewhere
     // in the stack.
     SqlParseException spe = null;
@@ -297,6 +311,12 @@ public abstract class SqlTests {
         actualException = spe.getCause();
         actualMessage = actualException.getMessage();
       }
+    } else if (ise != null) {
+      Throwable[] suppressed = ise.getSuppressed();
+      if (suppressed.length > 0) {
+        actualException = suppressed[0];
+        actualMessage = actualException.getMessage();
+      }
     } else {
       actualMessage = ex.getMessage();
       if (ex instanceof NumberFormatException) {

Reply via email to