This is an automated email from the ASF dual-hosted git repository.
morrySnow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 61725116570 [fix](expr opt) Handle maximum date in function rewrite
(#67815)
61725116570 is described below
commit 617251165709d8e4ac917b5a493d7c1dfd821a4d
Author: morrySnow <[email protected]>
AuthorDate: Fri Sep 11 14:35:53 2026 +0800
[fix](expr opt) Handle maximum date in function rewrite (#67815)
### What problem does this PR solve?
Problem Summary:
A valid comparison against the maximum supported date failed during
planning:
```sql
EXPLAIN SELECT * FROM t_datetime
WHERE DATE(dt) > '9999-12-31';
```
`DateFunctionRewrite` normally converts `DATE(datetime) > date_literal`
into a comparison with the beginning of the following day. For
`9999-12-31`, constructing that bound creates year 10000, which is
outside the Doris date domain and raises `datetime out of range`.
The rewrite now detects when the following day is outside the supported
range. Because no non-null `DATETIME` or `DATETIMEV2` value can have a
date above the maximum date, it simplifies the predicate to false while
preserving NULL semantics through `falseOrNull`. Other dates continue to
use the existing range rewrite.
Unit tests cover both datetime families, nullable values, and the
preceding day. Regression tests reproduce the original planning failure
for `DATETIME` and `DATETIMEV2(6)` and verify both filter and projection
semantics.
### Release note
Fix planning failures for `DATE` comparisons at the maximum supported
date.
### Check List (For Author)
- Test: Unit Test and Regression Test
- Behavior changed: Yes. An impossible upper-bound predicate is safely
simplified instead of failing planning.
- Does this need documentation: No
---
.../expression/rules/DateFunctionRewrite.java | 23 +++++++++++++---
.../expression/rules/DateFunctionRewriteTest.java | 26 ++++++++++++++++++
.../date_function_rewrite.out | 9 ++++++
.../date_function_rewrite.groovy | 32 +++++++++++++++++++++-
4 files changed, 85 insertions(+), 5 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/DateFunctionRewrite.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/DateFunctionRewrite.java
index 92b89221b43..84a70ba936e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/DateFunctionRewrite.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/DateFunctionRewrite.java
@@ -36,6 +36,7 @@ import
org.apache.doris.nereids.trees.expressions.literal.DateV2Literal;
import org.apache.doris.nereids.types.DateTimeType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.TimeStampNsType;
+import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.collect.ImmutableList;
@@ -103,21 +104,35 @@ public class DateFunctionRewrite implements
ExpressionPatternRuleFactory {
// V1
if (greaterThan.left().child(0).getDataType() instanceof
DateTimeType
&& greaterThan.right() instanceof DateLiteral) {
- DateTimeLiteral newLiteral = ((DateLiteral)
greaterThan.right()).toBeginOfTomorrow();
- return new GreaterThanEqual(greaterThan.left().child(0),
newLiteral);
+ Expression dateTime = greaterThan.left().child(0);
+ DateLiteral date = (DateLiteral) greaterThan.right();
+ if (isTomorrowOutOfRange(date)) {
+ return ExpressionUtils.falseOrNull(dateTime);
+ }
+ DateTimeLiteral newLiteral = date.toBeginOfTomorrow();
+ return new GreaterThanEqual(dateTime, newLiteral);
}
// V2
if (greaterThan.left().child(0).getDataType() instanceof
DateTimeV2Type
&& greaterThan.right() instanceof DateV2Literal) {
- DateTimeV2Literal newLiteral = ((DateV2Literal)
greaterThan.right()).toBeginOfTomorrow();
- return new GreaterThanEqual(greaterThan.left().child(0),
newLiteral);
+ Expression dateTime = greaterThan.left().child(0);
+ DateV2Literal date = (DateV2Literal) greaterThan.right();
+ if (isTomorrowOutOfRange(date)) {
+ return ExpressionUtils.falseOrNull(dateTime);
+ }
+ DateTimeV2Literal newLiteral = date.toBeginOfTomorrow();
+ return new GreaterThanEqual(dateTime, newLiteral);
}
}
return greaterThan;
}
+ private static boolean isTomorrowOutOfRange(DateLiteral date) {
+ return DateLiteral.isDateOutOfRange(date.toJavaDateType().plusDays(1));
+ }
+
private static Expression rewriteGreaterThanEqual(GreaterThanEqual
greaterThanEqual) {
if (isTimeStampNsDateComparison(greaterThanEqual)) {
return rewriteTimeStampNsDateComparison(greaterThanEqual);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/DateFunctionRewriteTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/DateFunctionRewriteTest.java
index 721414f0f70..03e464328a2 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/DateFunctionRewriteTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/DateFunctionRewriteTest.java
@@ -28,12 +28,18 @@ import org.apache.doris.nereids.trees.expressions.LessThan;
import org.apache.doris.nereids.trees.expressions.LessThanEqual;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Date;
+import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
import org.apache.doris.nereids.trees.expressions.literal.DateV2Literal;
import org.apache.doris.nereids.trees.expressions.literal.TimeStampNsLiteral;
+import org.apache.doris.nereids.types.DateTimeType;
+import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.TimeStampNsType;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -81,4 +87,24 @@ class DateFunctionRewriteTest extends
ExpressionRewriteTestHelper {
assertRewrite(new GreaterThanEqual(dateFunction, beforeMin),
ExpressionUtils.trueOrNull(timestampNs));
assertRewrite(new LessThanEqual(dateFunction, afterMax),
ExpressionUtils.trueOrNull(timestampNs));
}
+
+ @Test
+ void testRewriteGreaterThanAtMaximumDate() {
+ Expression dateTime = new SlotReference("dateTime",
DateTimeType.INSTANCE, true);
+ DateLiteral maxDate = new DateLiteral("9999-12-31");
+ Assertions.assertEquals(ExpressionUtils.falseOrNull(dateTime),
executor.rewrite(
+ new GreaterThan(new Date(dateTime), maxDate), context));
+
+ Expression dateTimeV2 = new SlotReference("dateTimeV2",
DateTimeV2Type.of(6), true);
+ DateV2Literal maxDateV2 = new DateV2Literal("9999-12-31");
+ assertRewrite(new GreaterThan(new Date(dateTimeV2), maxDateV2),
ExpressionUtils.falseOrNull(dateTimeV2));
+
+ DateLiteral previousDate = new DateLiteral("9999-12-30");
+ Assertions.assertEquals(new GreaterThanEqual(dateTime, new
DateTimeLiteral("9999-12-31 00:00:00")),
+ executor.rewrite(new GreaterThan(new Date(dateTime),
previousDate), context));
+
+ DateV2Literal previousDateV2 = new DateV2Literal("9999-12-30");
+ assertRewrite(new GreaterThan(new Date(dateTimeV2), previousDateV2),
+ new GreaterThanEqual(dateTimeV2, new
DateTimeV2Literal("9999-12-31 00:00:00")));
+ }
}
diff --git
a/regression-test/data/nereids_rules_p0/date_function_rewrite/date_function_rewrite.out
b/regression-test/data/nereids_rules_p0/date_function_rewrite/date_function_rewrite.out
index 2ef8304a2a0..f289de300bd 100644
---
a/regression-test/data/nereids_rules_p0/date_function_rewrite/date_function_rewrite.out
+++
b/regression-test/data/nereids_rules_p0/date_function_rewrite/date_function_rewrite.out
@@ -2,3 +2,12 @@
-- !test --
1
+-- !date_v1_greater_than_max --
+
+-- !date_v2_greater_than_max --
+
+-- !date_greater_than_max_null_semantics --
+1 false false
+2 \N \N
+3 false false
+
diff --git
a/regression-test/suites/nereids_rules_p0/date_function_rewrite/date_function_rewrite.groovy
b/regression-test/suites/nereids_rules_p0/date_function_rewrite/date_function_rewrite.groovy
index 01afc01431a..0be58e60260 100644
---
a/regression-test/suites/nereids_rules_p0/date_function_rewrite/date_function_rewrite.groovy
+++
b/regression-test/suites/nereids_rules_p0/date_function_rewrite/date_function_rewrite.groovy
@@ -27,4 +27,34 @@ suite("date_function_rewrite") {
qt_test """
select if (date(date_add(FROM_UNIXTIME(t1.test_time, '%Y-%m-%d'),2)) >
'2023-07-25',1,0) from test_date_func t1;
"""
-}
\ No newline at end of file
+
+ sql "drop table if exists test_date_func_boundary"
+ sql """
+ create table test_date_func_boundary(
+ id int,
+ dt datetime,
+ dtv2 datetimev2(6)
+ ) distributed by hash(id) buckets 1
+ properties("replication_num"="1")
+ """
+ sql """
+ insert into test_date_func_boundary values
+ (1, '9999-12-31 23:59:59', '9999-12-31 23:59:59.999999'),
+ (2, null, null),
+ (3, '9999-12-30 12:00:00', '9999-12-30 12:00:00.123456')
+ """
+
+ qt_date_v1_greater_than_max """
+ select id from test_date_func_boundary where date(dt) > '9999-12-31'
+ """
+
+ qt_date_v2_greater_than_max """
+ select id from test_date_func_boundary where date(dtv2) > '9999-12-31'
+ """
+
+ order_qt_date_greater_than_max_null_semantics """
+ select id, date(dt) > '9999-12-31', date(dtv2) > '9999-12-31'
+ from test_date_func_boundary
+ order by id
+ """
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]