From bf7273a346c12337a62fdfd02c29b3106a830afb Mon Sep 17 00:00:00 2001 From: Mryange Date: Fri, 14 Aug 2026 21:16:12 +0800 Subject: [PATCH 1/2] [fix](fe) Validate casts before constant folding ### What problem does this PR solve? Issue Number: N/A Problem Summary: Constant folding evaluated literal casts before validating whether their source and target types were compatible. This allowed an unsupported BIGINT to TIMESTAMPTZ cast to be folded into an incorrect timestamp literal while the same cast on a column was rejected. Reuse CheckCast during FE constant folding so unsupported casts remain for the normal validation rule to reject consistently. ### Release note Reject unsupported constant casts from BIGINT to TIMESTAMPTZ consistently with non-constant casts. ### Check List (For Author) - Test: Added unit and regression coverage; passed FE Checkstyle. Unit and regression tests were not run. - Behavior changed: Yes. Unsupported constant casts are rejected instead of being folded. - Does this need documentation: No --- .../rules/expression/rules/FoldConstantRuleOnFE.java | 4 ++++ .../doris/nereids/rules/expression/FoldConstantTest.java | 4 ++++ .../nereids/rules/expression/check/CheckCastTest.java | 7 +++++++ .../datatype_p0/timestamptz/test_timestamptz_cast.groovy | 4 ++++ 4 files changed, 19 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java index 5338bf7df9b2ef..e0be2f174ccfef 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java @@ -36,6 +36,7 @@ import org.apache.doris.nereids.rules.expression.ExpressionRuleType; import org.apache.doris.nereids.rules.expression.ExpressionTraverseListener; import org.apache.doris.nereids.rules.expression.ExpressionTraverseListenerFactory; +import org.apache.doris.nereids.rules.expression.check.CheckCast; import org.apache.doris.nereids.trees.expressions.AggregateExpression; import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.BinaryArithmetic; @@ -501,6 +502,9 @@ public Expression visitCast(Cast cast, ExpressionRewriteContext context) { } Expression child = cast.child(); DataType dataType = cast.getDataType(); + if (!CheckCast.check(child.getDataType(), dataType, SessionVariable.enableStrictCast())) { + return cast; + } // todo: process other null case if (child.isNullLiteral()) { return new NullLiteral(dataType); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java index 9f46a7970a2c72..851442fd6fdfeb 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java @@ -123,6 +123,7 @@ import org.apache.doris.nereids.types.DoubleType; import org.apache.doris.nereids.types.FloatType; import org.apache.doris.nereids.types.IntegerType; +import org.apache.doris.nereids.types.TimeStampTzType; import org.apache.doris.nereids.types.TinyIntType; import org.apache.doris.nereids.types.VarcharType; import org.apache.doris.nereids.util.MemoTestUtils; @@ -276,6 +277,9 @@ void testCastFold() { Expression rewritten = executor.rewrite(c, context); Literal expected = Literal.of((byte) 1); Assertions.assertEquals(rewritten, expected); + + Cast unsupportedCast = new Cast(new BigIntLiteral(20240229112233L), TimeStampTzType.of(6)); + Assertions.assertEquals(unsupportedCast, executor.rewrite(unsupportedCast, context)); } @Test diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/check/CheckCastTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/check/CheckCastTest.java index c0bf68cedbf82e..85d3a8fee61753 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/check/CheckCastTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/check/CheckCastTest.java @@ -42,6 +42,7 @@ import org.apache.doris.nereids.types.StringType; import org.apache.doris.nereids.types.StructField; import org.apache.doris.nereids.types.StructType; +import org.apache.doris.nereids.types.TimeStampTzType; import org.apache.doris.nereids.types.TimeV2Type; import org.apache.doris.nereids.types.TinyIntType; import org.apache.doris.nereids.types.VarcharType; @@ -65,6 +66,12 @@ public void testCastBetweenVariantTypes() { Assertions.assertTrue(CheckCast.check(v1Source, v1DifferentProperties, true)); } + @Test + public void testCastFromBigIntToTimeStampTz() { + Assertions.assertFalse(CheckCast.check(BigIntType.INSTANCE, TimeStampTzType.of(6), true)); + Assertions.assertFalse(CheckCast.check(BigIntType.INSTANCE, TimeStampTzType.of(6), false)); + } + @Test public void testCastFromBoolean() { // Strict mode diff --git a/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_cast.groovy b/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_cast.groovy index b4e225c77aa09d..d46a9792fe9f6f 100644 --- a/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_cast.groovy +++ b/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_cast.groovy @@ -27,6 +27,10 @@ suite("test_timestamptz_cast") { qt_cast_from_string1 """ select cast("2020-01-01 23:59:59.999999+08:00" as timestamptz(5)); """ + test { + sql """select cast(cast(20240229112233 as bigint) as timestamptz(6));""" + exception "cannot cast BIGINT to TIMESTAMPTZ(6)" + } sql " set debug_skip_fold_constant = true; " qt_cast_from_string2 """ select cast("2020-01-01 00:00:00.123456+08:00" as timestamptz(5)); From a17eff51f9152da2fb1dc0049686cd8adb193424 Mon Sep 17 00:00:00 2001 From: Mryange Date: Mon, 17 Aug 2026 11:15:27 +0800 Subject: [PATCH 2/2] [fix](fe) Reject unsupported casts during constant folding ### What problem does this PR solve? Issue Number: N/A Problem Summary: FE constant folding could evaluate unsupported constant casts before cast validation. Throw a Nereids AnalysisException when CheckCast rejects the source and target types so special planning paths cannot accept the invalid expression. ### Release note Reject unsupported constant casts consistently with non-constant casts. ### Check List (For Author) - Test: Unit Test - FoldConstantTest and CheckCastTest: 51 tests passed - Behavior changed: Yes. Unsupported constant casts fail during FE constant folding. - Does this need documentation: No --- .../nereids/rules/expression/rules/FoldConstantRuleOnFE.java | 3 ++- .../doris/nereids/rules/expression/FoldConstantTest.java | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java index e0be2f174ccfef..383abc7af48fab 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java @@ -503,7 +503,8 @@ public Expression visitCast(Cast cast, ExpressionRewriteContext context) { Expression child = cast.child(); DataType dataType = cast.getDataType(); if (!CheckCast.check(child.getDataType(), dataType, SessionVariable.enableStrictCast())) { - return cast; + throw new AnalysisException("cannot cast " + child.getDataType().toSql() + + " to " + dataType.toSql()); } // todo: process other null case if (child.isNullLiteral()) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java index 851442fd6fdfeb..3e2f3aac220ecb 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java @@ -279,7 +279,9 @@ void testCastFold() { Assertions.assertEquals(rewritten, expected); Cast unsupportedCast = new Cast(new BigIntLiteral(20240229112233L), TimeStampTzType.of(6)); - Assertions.assertEquals(unsupportedCast, executor.rewrite(unsupportedCast, context)); + AnalysisException exception = Assertions.assertThrows( + AnalysisException.class, () -> executor.rewrite(unsupportedCast, context)); + Assertions.assertEquals("cannot cast BIGINT to TIMESTAMPTZ(6)", exception.getMessage()); } @Test