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]