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

yiguolei pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.2 by this push:
     new 46796299cf0 branch-4.2: [fix](constant folding) Reject overflowing 
from_second and from_millisecond literals #67037 (#70014)
46796299cf0 is described below

commit 46796299cf09b4b1a76da555044de24442c21dd1
Author: morrySnow <[email protected]>
AuthorDate: Tue Nov 3 17:21:25 2026 +0800

    branch-4.2: [fix](constant folding) Reject overflowing from_second and 
from_millisecond literals #67037 (#70014)
    
    picked from master #67037
    
    Co-authored-by: Ambuj Upadhyay <[email protected]>
---
 .../executable/DateTimeExtractAndTransform.java    | 23 ++++++++++-
 .../DateTimeExtractAndTransformTest.java           | 44 ++++++++++++++++++++++
 2 files changed, 65 insertions(+), 2 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
index f6a147a7b13..7a1e2a32f6e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
@@ -1422,12 +1422,14 @@ public class DateTimeExtractAndTransform {
 
     @ExecFunction(name = "from_second")
     public static Expression fromSecond(BigIntLiteral second) {
-        return fromMicroSecond(second.getValue() * 1000 * 1000, 
FromSecond.RESULT_SCALE);
+        return fromMicroSecond(toMicroSecond(second.getValue(), 1000L * 1000L, 
"from_second"),
+                FromSecond.RESULT_SCALE);
     }
 
     @ExecFunction(name = "from_millisecond")
     public static Expression fromMilliSecond(BigIntLiteral milliSecond) {
-        return fromMicroSecond(milliSecond.getValue() * 1000, 
FromMillisecond.RESULT_SCALE);
+        return fromMicroSecond(toMicroSecond(milliSecond.getValue(), 1000L, 
"from_millisecond"),
+                FromMillisecond.RESULT_SCALE);
     }
 
     @ExecFunction(name = "from_microsecond")
@@ -1455,6 +1457,23 @@ public class DateTimeExtractAndTransform {
         return nanos.divide(BigInteger.valueOf(nanosPerUnit)).longValueExact();
     }
 
+    /**
+     * Widens {@code value} to microseconds without letting the multiplication 
wrap.
+     *
+     * <p>The range check lives in {@link #fromMicroSecond(long, int)}, which 
runs after the
+     * widening, so a product that overflows long can land back inside the 
accepted range: a
+     * literal argument then folds to a bogus datetime instead of being 
reported as out of range.
+     * The BE divides rather than multiplies and rejects the same argument, so 
only constant
+     * folding on the FE was affected.
+     */
+    private static long toMicroSecond(long value, long ratio, String 
functionName) {
+        try {
+            return Math.multiplyExact(value, ratio);
+        } catch (ArithmeticException e) {
+            throw new AnalysisException("Operation " + functionName + " of " + 
value + " out of range");
+        }
+    }
+
     @ExecFunction(name = "microseconds_diff")
     public static Expression microsecondsDiff(DateTimeV2Literal t1, 
DateTimeV2Literal t2) {
         return new 
BigIntLiteral(DateTimeV2Literal.datetimeDiffInMicroSeconds(t1, t2));
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java
index 12e32deadef..239f13c5578 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java
@@ -285,4 +285,48 @@ class DateTimeExtractAndTransformTest {
                         new VarcharLiteral("Europe/Paris"),
                         new VarcharLiteral("UTC")));
     }
+
+    // from_second and from_millisecond widen their argument to microseconds 
BEFORE the range
+    // check in fromMicroSecond runs. Without an overflow-checked multiply the 
product wraps back
+    // into the accepted range and folds to a bogus datetime instead of 
reporting the argument as
+    // out of range: 18446744073710 * 1_000_000 wraps to 448384, and 
18446744073709552 * 1000
+    // wraps to 384. The BE rejects both, so only FE constant folding 
disagreed.
+    @Test
+    void testFromSecondRejectsOverflowingArgument() {
+        Assertions.assertThrows(AnalysisException.class,
+                () -> DateTimeExtractAndTransform.fromSecond(new 
BigIntLiteral(18446744073710L)));
+        Assertions.assertThrows(AnalysisException.class,
+                () -> DateTimeExtractAndTransform.fromSecond(new 
BigIntLiteral(Long.MAX_VALUE)));
+
+        Assertions.assertThrows(AnalysisException.class,
+                () -> DateTimeExtractAndTransform.fromMilliSecond(new 
BigIntLiteral(18446744073709552L)));
+        Assertions.assertThrows(AnalysisException.class,
+                () -> DateTimeExtractAndTransform.fromMilliSecond(new 
BigIntLiteral(Long.MAX_VALUE)));
+    }
+
+    // The pre-existing range check must keep rejecting a value that is out of 
range without
+    // overflowing, and negative arguments must still be rejected.
+    @Test
+    void testFromSecondStillRejectsOutOfRangeArgument() {
+        Assertions.assertThrows(AnalysisException.class,
+                () -> DateTimeExtractAndTransform.fromSecond(new 
BigIntLiteral(253402272000L)));
+        Assertions.assertThrows(AnalysisException.class,
+                () -> DateTimeExtractAndTransform.fromSecond(new 
BigIntLiteral(-20L)));
+        Assertions.assertThrows(AnalysisException.class,
+                () -> DateTimeExtractAndTransform.fromMilliSecond(new 
BigIntLiteral(-20L)));
+    }
+
+    // In-range arguments must still fold. The exact datetime depends on the 
session time zone,
+    // so this only asserts that folding happens and produces a datetime 
literal.
+    @Test
+    void testFromSecondStillFoldsInRangeArgument() {
+        Assertions.assertInstanceOf(DateTimeV2Literal.class,
+                DateTimeExtractAndTransform.fromSecond(new BigIntLiteral(0L)));
+        Assertions.assertInstanceOf(DateTimeV2Literal.class,
+                DateTimeExtractAndTransform.fromSecond(new 
BigIntLiteral(1735689600L)));
+        Assertions.assertInstanceOf(DateTimeV2Literal.class,
+                DateTimeExtractAndTransform.fromMilliSecond(new 
BigIntLiteral(1735689600000L)));
+        Assertions.assertInstanceOf(DateTimeV2Literal.class,
+                DateTimeExtractAndTransform.fromMicroSecond(new 
BigIntLiteral(1735689600000000L)));
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to