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

michaelsmith pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git

commit b59be457eb22c5be22eaa6c687f1fe2c8ee4aff0
Author: Steve Carlin <[email protected]>
AuthorDate: Mon Dec 22 14:37:35 2025 -0800

    IMPALA-14639: Calcite planner should not allow date cast to int
    
    The following query was passing before this commit (but now
    fails correctly):
    
    select cast(date '2000-12-21' as int);
    
    Testing: Added test to calcite.test, also, tests exist in
             test_date_queries.TestDateQueriesAllFormat.test_queries
    
    Change-Id: Icad76e6c1db489ecdfa620109baa47232331a42d
    Reviewed-on: http://gerrit.cloudera.org:8080/24048
    Reviewed-by: Michael Smith <[email protected]>
    Reviewed-by: Aman Sinha <[email protected]>
    Tested-by: Impala Public Jenkins <[email protected]>
---
 .../java/org/apache/impala/analysis/CastExpr.java  | 37 +++++++++++++---------
 .../impala/calcite/functions/RexCallConverter.java | 21 +++++++++---
 .../queries/QueryTest/calcite.test                 |  6 ++++
 3 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/fe/src/main/java/org/apache/impala/analysis/CastExpr.java 
b/fe/src/main/java/org/apache/impala/analysis/CastExpr.java
index 91abc6781..e86afa152 100644
--- a/fe/src/main/java/org/apache/impala/analysis/CastExpr.java
+++ b/fe/src/main/java/org/apache/impala/analysis/CastExpr.java
@@ -403,29 +403,36 @@ public class CastExpr extends Expr {
     noOp_ = childType.equals(type_);
     if (noOp_) return;
 
-    FunctionName fnName = new FunctionName(BuiltinsDb.NAME, getFnName(type_));
-    Type[] args = { childType };
+    fn_ = getFunction(childType, type_, isImplicit_);
+    if (fn_ == null) {
+      throw new AnalysisException("Invalid type cast of " + 
getChild(0).toSql() +
+          " from " + childType + " to " + type_);
+    }
+
+    Preconditions.checkState(type_.matchesType(fn_.getReturnType()),
+        type_ + " != " + fn_.getReturnType());
+  }
+
+  public static Function getFunction(Type fromType, Type toType, boolean 
isImplicit)
+      throws AnalysisException {
+    Function fn = null;
+    FunctionName fnName = new FunctionName(BuiltinsDb.NAME, getFnName(toType));
+    Type[] args = { fromType };
     Function searchDesc = new Function(fnName, args, Type.INVALID, false);
-    if (isImplicit_) {
-      fn_ = BuiltinsDb.getInstance().getFunction(searchDesc,
+    if (isImplicit) {
+      fn = BuiltinsDb.getInstance().getFunction(searchDesc,
           CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
-      Preconditions.checkState(fn_ != null);
+      Preconditions.checkState(fn != null);
     } else {
-      fn_ = BuiltinsDb.getInstance().getFunction(searchDesc,
+      fn = BuiltinsDb.getInstance().getFunction(searchDesc,
           CompareMode.IS_IDENTICAL);
-      if (fn_ == null) {
+      if (fn == null) {
         // allow for promotion from CHAR to STRING; only if no exact match is 
found
-        fn_ =  BuiltinsDb.getInstance().getFunction(
+        fn = BuiltinsDb.getInstance().getFunction(
             searchDesc.promoteCharsToStrings(), CompareMode.IS_IDENTICAL);
       }
     }
-    if (fn_ == null) {
-      throw new AnalysisException("Invalid type cast of " + 
getChild(0).toSql() +
-          " from " + childType + " to " + type_);
-    }
-
-    Preconditions.checkState(type_.matchesType(fn_.getReturnType()),
-        type_ + " != " + fn_.getReturnType());
+    return fn;
   }
 
   /**
diff --git 
a/java/calcite-planner/src/main/java/org/apache/impala/calcite/functions/RexCallConverter.java
 
b/java/calcite-planner/src/main/java/org/apache/impala/calcite/functions/RexCallConverter.java
index f71a67ba6..57a42eb07 100644
--- 
a/java/calcite-planner/src/main/java/org/apache/impala/calcite/functions/RexCallConverter.java
+++ 
b/java/calcite-planner/src/main/java/org/apache/impala/calcite/functions/RexCallConverter.java
@@ -33,6 +33,7 @@ import org.apache.impala.analysis.Analyzer;
 import org.apache.impala.analysis.ArithmeticExpr;
 import org.apache.impala.analysis.BinaryPredicate;
 import org.apache.impala.analysis.CaseWhenClause;
+import org.apache.impala.analysis.CastExpr;
 import org.apache.impala.analysis.CompoundPredicate;
 import org.apache.impala.analysis.Expr;
 import org.apache.impala.analysis.FunctionCallExpr;
@@ -44,6 +45,7 @@ import org.apache.impala.calcite.rules.ImpalaRexExecutor;
 import org.apache.impala.calcite.type.ImpalaTypeConverter;
 import org.apache.impala.catalog.Function;
 import org.apache.impala.catalog.Type;
+import org.apache.impala.common.AnalysisException;
 import org.apache.impala.common.ImpalaException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -191,13 +193,14 @@ public class RexCallConverter {
   private static Expr createCastExpr(RexCall call, List<Expr> params, Analyzer 
analyzer)
       throws ImpalaException {
     Type impalaRetType = ImpalaTypeConverter.createImpalaType(call.getType());
-    if (params.get(0).getType() == Type.NULL) {
+    Expr paramsOperand = params.get(0);
+    if (paramsOperand.getType() == Type.NULL) {
       return new AnalyzedNullLiteral(impalaRetType);
     }
 
     // no need for redundant cast.
-    if (params.get(0).getType().equals(impalaRetType)) {
-      return params.get(0);
+    if (paramsOperand.getType().equals(impalaRetType)) {
+      return paramsOperand;
     }
 
     // Hack logic: Partition pruning needs the exact number when the column
@@ -212,8 +215,16 @@ public class RexCallConverter {
     // Small hack: Most cast expressions have "isImplicit" set to true. If this
     // is the case, then it blocks "analyze" from working through the cast. We
     // need to analyze the expression before creating the cast around it.
-    params.get(0).analyze(analyzer);
-    return new AnalyzedCastExpr(impalaRetType, params.get(0));
+    paramsOperand.analyze(analyzer);
+
+
+    // call getFunction which will return null if the cast is not valid.
+    Function fn = CastExpr.getFunction(paramsOperand.getType(), impalaRetType, 
false);
+    if (fn == null) {
+      throw new AnalysisException("Invalid type cast " +
+          "from " + paramsOperand.getType() + " to " + impalaRetType);
+    }
+    return new AnalyzedCastExpr(impalaRetType, paramsOperand);
   }
 
   private static Expr createDecodeExpr(Function fn, List<Expr> params,
diff --git a/testdata/workloads/functional-query/queries/QueryTest/calcite.test 
b/testdata/workloads/functional-query/queries/QueryTest/calcite.test
index 0d4f03767..b5471c28f 100644
--- a/testdata/workloads/functional-query/queries/QueryTest/calcite.test
+++ b/testdata/workloads/functional-query/queries/QueryTest/calcite.test
@@ -1076,6 +1076,12 @@ where 10.1 not in (tinyint_col, smallint_col, int_col, 
bigint_col, float_col, do
 8990
 ---- TYPES
 bigint
+=====
+---- QUERY
+# Test that casts are not allowed between DATE and numerical types
+select cast(date '2000-12-21' as int);
+---- CATCH
+AnalysisException: Invalid type cast from DATE to INT
 ====
 ---- QUERY
 # Test for varchar ndv with both 1 and 2 parameters

Reply via email to