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 f96a95be715 branch-4.2: [fix](function) Keep date partition pruning
correct across time zones #68681 (#70058)
f96a95be715 is described below
commit f96a95be7154fbc86a2f35f075e9fbf82e69fc62
Author: morrySnow <[email protected]>
AuthorDate: Wed Nov 4 08:17:49 2026 +0800
branch-4.2: [fix](function) Keep date partition pruning correct across time
zones #68681 (#70058)
picked from master #68681
Co-authored-by: Mryange <[email protected]>
---
.../doris/nereids/trees/expressions/Cast.java | 110 +-------
.../expressions/functions/DateAddSubMonotonic.java | 2 +-
.../functions/DateCeilFloorMonotonic.java | 11 +-
.../expressions/functions/DateDiffMonotonic.java | 3 +-
.../expressions/functions/FromSecondMonotonic.java | 9 +-
.../expressions/functions/MonotonicityUtils.java | 296 +++++++++++++++++++++
.../expressions/functions/scalar/ConvertTz.java | 7 +-
.../expressions/functions/scalar/DateFormat.java | 10 +-
.../expressions/functions/scalar/DayOfMonth.java | 8 +-
.../expressions/functions/scalar/DayOfYear.java | 7 +-
.../functions/scalar/FromMicrosecond.java | 6 +
.../functions/scalar/FromMillisecond.java | 6 +
.../expressions/functions/scalar/FromSecond.java | 6 +
.../expressions/functions/scalar/FromUnixtime.java | 12 +-
.../trees/expressions/functions/scalar/Hour.java | 9 +-
.../expressions/functions/scalar/Microsecond.java | 27 +-
.../trees/expressions/functions/scalar/Minute.java | 23 +-
.../trees/expressions/functions/scalar/Month.java | 7 +-
.../expressions/functions/scalar/Nanosecond.java | 26 +-
.../expressions/functions/scalar/Quarter.java | 7 +-
.../trees/expressions/functions/scalar/Second.java | 25 +-
.../expressions/functions/scalar/TimeFormat.java | 10 +-
.../functions/scalar/UnixTimestamp.java | 7 +-
.../expressions/functions/scalar/YearWeek.java | 6 +-
.../org/apache/doris/nereids/util/DateUtils.java | 33 +--
.../rules/rewrite/PruneOlapScanPartitionTest.java | 19 ++
.../functions/scalar/FromSecondMonotonicTest.java | 98 +++++++
.../month_quarter_cast_in_prune.groovy | 70 +++--
28 files changed, 521 insertions(+), 339 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Cast.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Cast.java
index 591042711da..fd9d7138134 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Cast.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Cast.java
@@ -17,20 +17,15 @@
package org.apache.doris.nereids.trees.expressions;
-import org.apache.doris.common.util.TimeUtils;
-import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.exceptions.UnboundException;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
-import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
-import org.apache.doris.nereids.trees.expressions.literal.TimeStampNsLiteral;
-import org.apache.doris.nereids.trees.expressions.literal.TimestampTzLiteral;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.ArrayType;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DataType;
-import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DecimalV2Type;
import org.apache.doris.nereids.types.DecimalV3Type;
import org.apache.doris.nereids.types.IntegerType;
@@ -40,20 +35,12 @@ import org.apache.doris.nereids.types.SmallIntType;
import org.apache.doris.nereids.types.StructField;
import org.apache.doris.nereids.types.StructType;
import org.apache.doris.nereids.types.TimeStampNsType;
-import org.apache.doris.nereids.types.TimeStampTzType;
import org.apache.doris.nereids.types.TinyIntType;
import org.apache.doris.nereids.types.VariantType;
-import org.apache.doris.nereids.types.coercion.DateLikeType;
-import org.apache.doris.nereids.util.DateUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
-import java.time.DateTimeException;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
import java.util.List;
import java.util.Objects;
@@ -403,99 +390,6 @@ public class Cast extends Expression implements
UnaryExpression, Monotonic {
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- DataType childType = child().getDataType();
- if (!(childType instanceof DateLikeType && targetType instanceof
DateLikeType)) {
- return false;
- }
-
- if (targetType instanceof TimeStampNsType &&
!isRangeWithinTimeStampNs(lower, upper)) {
- return false;
- }
-
- if (childType instanceof TimeStampTzType
- && (targetType instanceof DateTimeV2Type || targetType
instanceof TimeStampNsType)) {
- int destinationScale = targetType instanceof DateTimeV2Type
- ? ((DateTimeV2Type) targetType).getScale() :
TimeStampNsType.SCALE;
- return isTimeStampTzToLocalDateTimeMonotonic(
- (TimeStampTzType) childType, destinationScale, lower,
upper);
- }
- if (childType instanceof TimeStampNsType && targetType instanceof
TimeStampTzType) {
- return isTimeStampNsToTimeStampTzMonotonic(
- (TimeStampTzType) targetType, lower, upper);
- }
- return true;
- }
-
- private boolean isRangeWithinTimeStampNs(Literal lower, Literal upper) {
- if (lower == null || upper == null) {
- return false;
- }
- try {
- return !(lower.checkedCastTo(targetType) instanceof NullLiteral)
- && !(upper.checkedCastTo(targetType) instanceof
NullLiteral);
- } catch (AnalysisException e) {
- return false;
- }
- }
-
- private boolean isTimeStampTzToLocalDateTimeMonotonic(
- TimeStampTzType sourceType, int destinationScale, Literal lower,
Literal upper) {
- ZoneId timeZone;
- try {
- timeZone = TimeUtils.getDorisZoneId();
- } catch (DateTimeException e) {
- return false;
- }
- if (timeZone.getRules().isFixedOffset()) {
- return true;
- }
- // Scale reduction rounds the UTC value before applying the session
timezone. That rounding
- // can move values across a fall-back transition just outside the
original partition range.
- if (destinationScale < sourceType.getScale()) {
- return false;
- }
- if (!(lower instanceof TimestampTzLiteral) || !(upper instanceof
TimestampTzLiteral)) {
- return false;
- }
-
- // TimestampTzLiteral stores UTC civil fields. The cast renders those
instants in the
- // session timezone, which moves backward at a fall-back transition.
- Instant lowerInstant = ((TimestampTzLiteral)
lower).toJavaDateType().toInstant(ZoneOffset.UTC);
- Instant upperInstant = ((TimestampTzLiteral)
upper).toJavaDateType().toInstant(ZoneOffset.UTC);
- if (upperInstant.isBefore(lowerInstant)) {
- return false;
- }
- return !DateUtils.hasFallbackTransitionInInstantRange(timeZone,
lowerInstant, upperInstant);
- }
-
- private boolean isTimeStampNsToTimeStampTzMonotonic(
- TimeStampTzType destinationType, Literal lower, Literal upper) {
- ZoneId timeZone;
- try {
- timeZone = TimeUtils.getDorisZoneId();
- } catch (DateTimeException e) {
- return false;
- }
- if (timeZone.getRules().isFixedOffset()) {
- return true;
- }
- if (!(lower instanceof TimeStampNsLiteral) || !(upper instanceof
TimeStampNsLiteral)) {
- return false;
- }
- LocalDateTime lowerDateTime = roundTimeStampNs(
- (TimeStampNsLiteral) lower, destinationType.getScale());
- LocalDateTime upperDateTime = roundTimeStampNs(
- (TimeStampNsLiteral) upper, destinationType.getScale());
- if (upperDateTime.isBefore(lowerDateTime)) {
- return false;
- }
- return !DateUtils.hasGapTransitionInLocalDateTimeRange(
- timeZone, lowerDateTime, upperDateTime);
- }
-
- private LocalDateTime roundTimeStampNs(TimeStampNsLiteral literal, int
scale) {
- long factor = (long) Math.pow(10, DateUtils.NANOSECOND_SCALE - scale);
- LocalDateTime dateTime = literal.toJavaDateType().plusNanos(factor /
2);
- return dateTime.withNano((int) (dateTime.getNano() / factor * factor));
+ return
MonotonicityUtils.isDateLikeCastMonotonic(child().getDataType(), targetType,
lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateAddSubMonotonic.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateAddSubMonotonic.java
index 7fec22fd9d3..96265850456 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateAddSubMonotonic.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateAddSubMonotonic.java
@@ -23,7 +23,7 @@ import
org.apache.doris.nereids.trees.expressions.literal.Literal;
public interface DateAddSubMonotonic extends Monotonic {
@Override
default boolean isMonotonic(Literal lower, Literal upper) {
- return child(1) instanceof Literal;
+ return MonotonicityUtils.hasConstantOtherArguments(this, 0);
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateCeilFloorMonotonic.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateCeilFloorMonotonic.java
index 35e3caafc4f..cecb622684e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateCeilFloorMonotonic.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateCeilFloorMonotonic.java
@@ -30,16 +30,7 @@ import java.util.Optional;
public interface DateCeilFloorMonotonic extends RoundingMonotonic {
@Override
default boolean isMonotonic(Literal lower, Literal upper) {
- switch (arity()) {
- case 1:
- return true;
- case 2:
- return !(child(0) instanceof Literal) && child(1) instanceof
Literal;
- case 3:
- return !(child(0) instanceof Literal) && child(1) instanceof
Literal && child(2) instanceof Literal;
- default:
- return false;
- }
+ return MonotonicityUtils.hasConstantRoundingArguments(this);
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateDiffMonotonic.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateDiffMonotonic.java
index daaea895b6d..1fb17f2b2dd 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateDiffMonotonic.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/DateDiffMonotonic.java
@@ -23,8 +23,7 @@ import
org.apache.doris.nereids.trees.expressions.literal.Literal;
public interface DateDiffMonotonic extends Monotonic {
@Override
default boolean isMonotonic(Literal lower, Literal upper) {
- return !(child(0) instanceof Literal) && child(1) instanceof Literal
- || child(0) instanceof Literal && !(child(1) instanceof
Literal);
+ return MonotonicityUtils.hasOneVariableArgument(this);
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/FromSecondMonotonic.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/FromSecondMonotonic.java
index 96dfa7ac650..6df932c9577 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/FromSecondMonotonic.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/FromSecondMonotonic.java
@@ -17,17 +17,16 @@
package org.apache.doris.nereids.trees.expressions.functions;
-import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
/** monotonicity for from_{xx}second */
public interface FromSecondMonotonic extends Monotonic {
+ /** Number of input units in one epoch second. */
+ long getEpochUnitsPerSecond();
+
@Override
default boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof BigIntLiteral) {
- return ((BigIntLiteral) lower).getValue() >= 0;
- }
- return false;
+ return MonotonicityUtils.isEpochToLocalMonotonic(lower, upper,
getEpochUnitsPerSecond());
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/MonotonicityUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/MonotonicityUtils.java
new file mode 100644
index 00000000000..7efcce3a102
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/MonotonicityUtils.java
@@ -0,0 +1,296 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.functions;
+
+import org.apache.doris.common.util.TimeUtils;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
+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.Literal;
+import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.TimeStampNsLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.TimestampTzLiteral;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.TimeStampNsType;
+import org.apache.doris.nereids.types.TimeStampTzType;
+import org.apache.doris.nereids.types.coercion.DateLikeType;
+import org.apache.doris.nereids.util.DateUtils;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+
+/** Shared range predicates for monotonic date and time expressions. */
+public final class MonotonicityUtils {
+ // The last second accepted by FE constant folding for
from_{second,millisecond,microsecond}.
+ private static final long MAX_EPOCH_SECONDS = 253402271999L;
+
+ private MonotonicityUtils() {
+ }
+
+ /** All arguments other than the range argument must be literals. */
+ public static boolean hasConstantOtherArguments(ExpressionTrait
expression, int rangeArgument) {
+ for (int i = 0; i < expression.arity(); i++) {
+ if (i != rangeArgument && !(expression.child(i) instanceof
Literal)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean hasOneVariableArgument(ExpressionTrait expression) {
+ return expression.child(0) instanceof Literal ^ expression.child(1)
instanceof Literal;
+ }
+
+ public static boolean hasConstantRoundingArguments(ExpressionTrait
expression) {
+ return expression.arity() >= 1 && expression.arity() <= 3
+ && (expression.arity() == 1 || !(expression.child(0)
instanceof Literal))
+ && hasConstantOtherArguments(expression, 0);
+ }
+
+ public static boolean hasMonotonicFormat(Expression format) {
+ return format instanceof StringLikeLiteral
+ && DateUtils.monoFormat.contains(((StringLikeLiteral)
format).getValue());
+ }
+
+ /** A calendar field cannot wrap while its enclosing date fields are
unchanged. */
+ public static boolean isWithinSameYear(Literal lower, Literal upper) {
+ return hasSameDatePrefix(lower, upper, 1);
+ }
+
+ public static boolean isWithinSameMonth(Literal lower, Literal upper) {
+ return hasSameDatePrefix(lower, upper, 2);
+ }
+
+ public static boolean isWithinSameDay(Literal lower, Literal upper) {
+ return hasSameDatePrefix(lower, upper, 3);
+ }
+
+ private static boolean hasSameDatePrefix(Literal lower, Literal upper, int
fields) {
+ if (!(lower instanceof DateLiteral && upper instanceof DateLiteral)) {
+ return false;
+ }
+ DateLiteral start = (DateLiteral) lower;
+ DateLiteral end = (DateLiteral) upper;
+ return start.getYear() == end.getYear()
+ && (fields < 2 || start.getMonth() == end.getMonth())
+ && (fields < 3 || start.getDay() == end.getDay());
+ }
+
+ /** Preserve the date-only behavior of sub-day extractors. */
+ public static boolean isWithinSameHour(Literal lower, Literal upper) {
+ return hasSameTimePrefix(lower, upper, 1);
+ }
+
+ public static boolean isWithinSameMinute(Literal lower, Literal upper) {
+ return hasSameTimePrefix(lower, upper, 2);
+ }
+
+ public static boolean isWithinSameSecond(Literal lower, Literal upper) {
+ return hasSameTimePrefix(lower, upper, 3);
+ }
+
+ private static boolean hasSameTimePrefix(Literal lower, Literal upper, int
fields) {
+ if (lower instanceof TimeStampNsLiteral && upper instanceof
TimeStampNsLiteral) {
+ TimeStampNsLiteral start = (TimeStampNsLiteral) lower;
+ TimeStampNsLiteral end = (TimeStampNsLiteral) upper;
+ return hasSameDatePrefix(lower, upper, 3)
+ && start.getHour() == end.getHour()
+ && (fields < 2 || start.getMinute() == end.getMinute())
+ && (fields < 3 || start.getSecond() == end.getSecond());
+ }
+ if (lower instanceof DateTimeLiteral && upper instanceof
DateTimeLiteral) {
+ DateTimeLiteral start = (DateTimeLiteral) lower;
+ DateTimeLiteral end = (DateTimeLiteral) upper;
+ return hasSameDatePrefix(lower, upper, 3)
+ && start.getHour() == end.getHour()
+ && (fields < 2 || start.getMinute() == end.getMinute())
+ && (fields < 3 || start.getSecond() == end.getSecond());
+ }
+ return lower instanceof DateLiteral && upper instanceof DateLiteral;
+ }
+
+ /** Check the range in the unit used by from_second, from_millisecond, or
from_microsecond. */
+ public static boolean isEpochToLocalMonotonic(Literal lower, Literal
upper, long unitsPerSecond) {
+ if (!(lower instanceof BigIntLiteral) || ((BigIntLiteral)
lower).getValue() < 0) {
+ return false;
+ }
+ ZoneId zoneId;
+ try {
+ zoneId = TimeUtils.getDorisZoneId();
+ } catch (DateTimeException e) {
+ return false;
+ }
+ if (zoneId.getRules().isFixedOffset()) {
+ return true;
+ }
+ if (!(upper instanceof BigIntLiteral)) {
+ return false;
+ }
+ long lowerValue = ((BigIntLiteral) lower).getValue();
+ long upperValue = ((BigIntLiteral) upper).getValue();
+ if (upperValue < lowerValue || upperValue / unitsPerSecond >
MAX_EPOCH_SECONDS) {
+ return false;
+ }
+ Instant lowerInstant = epochToInstant(lowerValue, unitsPerSecond);
+ Instant upperInstant = epochToInstant(upperValue, unitsPerSecond);
+ if (LocalDateTime.ofInstant(upperInstant, zoneId).getYear() > 9999) {
+ return false;
+ }
+ return isInstantToLocalMonotonic(zoneId, lowerInstant, upperInstant);
+ }
+
+ private static Instant epochToInstant(long value, long unitsPerSecond) {
+ return Instant.ofEpochSecond(value / unitsPerSecond,
+ value % unitsPerSecond * (1000000000L / unitsPerSecond));
+ }
+
+ /** Instant-to-local conversion can move backward only at a fall-back
transition. */
+ public static boolean isInstantToLocalMonotonic(ZoneId zoneId, Instant
lower, Instant upper) {
+ return zoneId.getRules().isFixedOffset()
+ || lower != null && upper != null && !upper.isBefore(lower)
+ && !hasFallbackTransitionInInstantRange(zoneId, lower, upper);
+ }
+
+ /** Local-to-instant conversion may lose its order across a spring-forward
gap. */
+ public static boolean isLocalToInstantMonotonic(ZoneId zoneId,
LocalDateTime lower, LocalDateTime upper) {
+ return zoneId.getRules().isFixedOffset()
+ || lower != null && upper != null && !upper.isBefore(lower)
+ && !hasGapTransitionInLocalDateTimeRange(zoneId, lower, upper);
+ }
+
+ /** Whether the instant interval (lower, upper] crosses a fall-back
transition. */
+ private static boolean hasFallbackTransitionInInstantRange(ZoneId zoneId,
Instant lower, Instant upper) {
+ ZoneRules rules = zoneId.getRules();
+ ZoneOffsetTransition transition = rules.nextTransition(lower);
+ while (transition != null && !transition.getInstant().isAfter(upper)) {
+ if (transition.isOverlap()) {
+ return true;
+ }
+ transition = rules.nextTransition(transition.getInstant());
+ }
+ return false;
+ }
+
+ /** Whether the local interval intersects a spring-forward gap. */
+ private static boolean hasGapTransitionInLocalDateTimeRange(
+ ZoneId zoneId, LocalDateTime lower, LocalDateTime upper) {
+ ZoneRules rules = zoneId.getRules();
+ Instant searchStart = lower.minusDays(2).atZone(zoneId).toInstant();
+ ZoneOffsetTransition transition = rules.nextTransition(searchStart);
+ while (transition != null &&
!transition.getDateTimeBefore().isAfter(upper)) {
+ if (transition.isGap()
+ && upper.isAfter(transition.getDateTimeBefore())
+ && lower.isBefore(transition.getDateTimeAfter())) {
+ return true;
+ }
+ transition = rules.nextTransition(transition.getInstant());
+ }
+ return false;
+ }
+
+ /** Dispatch date-like casts to their range checks. */
+ public static boolean isDateLikeCastMonotonic(
+ DataType sourceType, DataType targetType, Literal lower, Literal
upper) {
+ if (!(sourceType instanceof DateLikeType && targetType instanceof
DateLikeType)) {
+ return false;
+ }
+ if (targetType instanceof TimeStampNsType &&
!isRangeWithinTimeStampNs(targetType, lower, upper)) {
+ return false;
+ }
+ if (sourceType instanceof TimeStampTzType
+ && (targetType instanceof DateTimeV2Type || targetType
instanceof TimeStampNsType)) {
+ int destinationScale = targetType instanceof DateTimeV2Type
+ ? ((DateTimeV2Type) targetType).getScale() :
TimeStampNsType.SCALE;
+ return isTimeStampTzToLocalMonotonic(
+ (TimeStampTzType) sourceType, destinationScale, lower,
upper);
+ }
+ if (sourceType instanceof TimeStampNsType && targetType instanceof
TimeStampTzType) {
+ return isTimeStampNsToTimeStampTzMonotonic((TimeStampTzType)
targetType, lower, upper);
+ }
+ return true;
+ }
+
+ private static boolean isRangeWithinTimeStampNs(DataType targetType,
Literal lower, Literal upper) {
+ if (lower == null || upper == null) {
+ return false;
+ }
+ try {
+ return !(lower.checkedCastTo(targetType) instanceof NullLiteral)
+ && !(upper.checkedCastTo(targetType) instanceof
NullLiteral);
+ } catch (AnalysisException e) {
+ return false;
+ }
+ }
+
+ /** Check a TIMESTAMPTZ cast to a local datetime after accounting for its
output scale. */
+ public static boolean isTimeStampTzToLocalMonotonic(
+ TimeStampTzType sourceType, int destinationScale, Literal lower,
Literal upper) {
+ ZoneId zoneId;
+ try {
+ zoneId = TimeUtils.getDorisZoneId();
+ } catch (DateTimeException e) {
+ return false;
+ }
+ if (zoneId.getRules().isFixedOffset()) {
+ return true;
+ }
+ // Rounding UTC before zone conversion may cross a fall-back just
outside the input range.
+ if (destinationScale < sourceType.getScale()
+ || !(lower instanceof TimestampTzLiteral) || !(upper
instanceof TimestampTzLiteral)) {
+ return false;
+ }
+ Instant lowerInstant = ((TimestampTzLiteral)
lower).toJavaDateType().toInstant(ZoneOffset.UTC);
+ Instant upperInstant = ((TimestampTzLiteral)
upper).toJavaDateType().toInstant(ZoneOffset.UTC);
+ return isInstantToLocalMonotonic(zoneId, lowerInstant, upperInstant);
+ }
+
+ /** Check a local TIMESTAMP_NS cast after rounding to the TIMESTAMPTZ
output scale. */
+ public static boolean isTimeStampNsToTimeStampTzMonotonic(
+ TimeStampTzType destinationType, Literal lower, Literal upper) {
+ ZoneId zoneId;
+ try {
+ zoneId = TimeUtils.getDorisZoneId();
+ } catch (DateTimeException e) {
+ return false;
+ }
+ if (zoneId.getRules().isFixedOffset()) {
+ return true;
+ }
+ if (!(lower instanceof TimeStampNsLiteral) || !(upper instanceof
TimeStampNsLiteral)) {
+ return false;
+ }
+ LocalDateTime lowerDateTime = roundTimeStampNs((TimeStampNsLiteral)
lower, destinationType.getScale());
+ LocalDateTime upperDateTime = roundTimeStampNs((TimeStampNsLiteral)
upper, destinationType.getScale());
+ return isLocalToInstantMonotonic(zoneId, lowerDateTime, upperDateTime);
+ }
+
+ private static LocalDateTime roundTimeStampNs(TimeStampNsLiteral literal,
int scale) {
+ long factor = (long) Math.pow(10, DateUtils.NANOSECOND_SCALE - scale);
+ LocalDateTime dateTime = literal.toJavaDateType().plusNanos(factor /
2);
+ return dateTime.withNano((int) (dateTime.getNano() / factor * factor));
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java
index 5606b023987..317f5bb1894 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java
@@ -24,6 +24,7 @@ import org.apache.doris.nereids.trees.expressions.Cast;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import
org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
@@ -36,7 +37,6 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.TimeStampNsType;
import org.apache.doris.nereids.types.VarcharType;
-import org.apache.doris.nereids.util.DateUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -147,10 +147,7 @@ public class ConvertTz extends ScalarFunction
*/
Instant lowerInstant =
DateTimeLiteral.convertLocalToInstant(lowerDateTime, fromZone);
Instant upperInstant =
DateTimeLiteral.convertLocalToInstant(upperDateTime, fromZone);
- if (upperInstant.isBefore(lowerInstant)) {
- return false;
- }
- return !DateUtils.hasFallbackTransitionInInstantRange(toZone,
lowerInstant, upperInstant);
+ return MonotonicityUtils.isInstantToLocalMonotonic(toZone,
lowerInstant, upperInstant);
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
index 5a5884d75ab..809afe0e366 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java
@@ -21,16 +21,15 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import
org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
-import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.TimeStampNsType;
import org.apache.doris.nereids.types.VarcharType;
-import org.apache.doris.nereids.util.DateUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -82,12 +81,7 @@ public class DateFormat extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- Expression format = child(1);
- if (!(format instanceof StringLikeLiteral)) {
- return false;
- }
- String str = ((StringLikeLiteral) format).getValue();
- return DateUtils.monoFormat.contains(str);
+ return MonotonicityUtils.hasMonotonicFormat(child(1));
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayOfMonth.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayOfMonth.java
index 07ef40c2814..0229c5a04ed 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayOfMonth.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayOfMonth.java
@@ -21,8 +21,8 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -95,10 +95,6 @@ public class DayOfMonth extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof DateLiteral && upper instanceof DateLiteral) {
- return ((DateLiteral) lower).getYear() == ((DateLiteral)
upper).getYear()
- && ((DateLiteral) lower).getMonth() == ((DateLiteral)
upper).getMonth();
- }
- return false;
+ return MonotonicityUtils.isWithinSameMonth(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayOfYear.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayOfYear.java
index 917e2cf95c9..a9687d0db1d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayOfYear.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DayOfYear.java
@@ -21,8 +21,8 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -95,9 +95,6 @@ public class DayOfYear extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof DateLiteral && upper instanceof DateLiteral) {
- return ((DateLiteral) lower).getYear() == ((DateLiteral)
upper).getYear();
- }
- return false;
+ return MonotonicityUtils.isWithinSameYear(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromMicrosecond.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromMicrosecond.java
index a7c21daae0b..0247fe2e24a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromMicrosecond.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromMicrosecond.java
@@ -41,6 +41,7 @@ public class FromMicrosecond extends ScalarFunction
FromSecondMonotonic {
public static final int RESULT_SCALE = 6;
+
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
FunctionSignature.ret(DateTimeV2Type.of(RESULT_SCALE)).args(BigIntType.INSTANCE));
@@ -69,6 +70,11 @@ public class FromMicrosecond extends ScalarFunction
return visitor.visitScalarFunction(this, context);
}
+ @Override
+ public long getEpochUnitsPerSecond() {
+ return 1000000;
+ }
+
@Override
public Expression withConstantArgs(Expression literal) {
return new FromMicrosecond(literal);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromMillisecond.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromMillisecond.java
index b2a719f17fa..3e5eee219cb 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromMillisecond.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromMillisecond.java
@@ -40,6 +40,7 @@ public class FromMillisecond extends ScalarFunction
implements BinaryExpression, ExplicitlyCastableSignature,
PropagateNullLiteral, PropagateNullable,
FromSecondMonotonic {
public static final int RESULT_SCALE = 3;
+
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
FunctionSignature.ret(DateTimeV2Type.of(RESULT_SCALE)).args(BigIntType.INSTANCE));
@@ -68,6 +69,11 @@ public class FromMillisecond extends ScalarFunction
return visitor.visitScalarFunction(this, context);
}
+ @Override
+ public long getEpochUnitsPerSecond() {
+ return 1000;
+ }
+
@Override
public Expression withConstantArgs(Expression literal) {
return new FromMillisecond(literal);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromSecond.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromSecond.java
index bde4678aefe..026c125c12c 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromSecond.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromSecond.java
@@ -41,6 +41,7 @@ public class FromSecond extends ScalarFunction
FromSecondMonotonic {
public static final int RESULT_SCALE = 0;
+
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
FunctionSignature.ret(DateTimeV2Type.of(RESULT_SCALE)).args(BigIntType.INSTANCE));
@@ -69,6 +70,11 @@ public class FromSecond extends ScalarFunction
return visitor.visitScalarFunction(this, context);
}
+ @Override
+ public long getEpochUnitsPerSecond() {
+ return 1;
+ }
+
@Override
public Expression withConstantArgs(Expression literal) {
return new FromSecond(literal);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromUnixtime.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromUnixtime.java
index 2c218c4342d..46323676aed 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromUnixtime.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromUnixtime.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import
org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
@@ -157,10 +158,7 @@ public class FromUnixtime extends ScalarFunction
}
Instant lowerInstant = toInstant(lower);
Instant upperInstant = toInstant(upper);
- if (lowerInstant == null || upperInstant == null ||
upperInstant.isBefore(lowerInstant)) {
- return false;
- }
- return !DateUtils.hasFallbackTransitionInInstantRange(timeZone,
lowerInstant, upperInstant);
+ return MonotonicityUtils.isInstantToLocalMonotonic(timeZone,
lowerInstant, upperInstant);
}
@Override
@@ -182,11 +180,7 @@ public class FromUnixtime extends ScalarFunction
}
private boolean isMonotonicFormat() {
- Expression format = child(1);
- if (!(format instanceof StringLikeLiteral)) {
- return false;
- }
- return DateUtils.monoFormat.contains(((StringLikeLiteral)
format).getValue());
+ return MonotonicityUtils.hasMonotonicFormat(child(1));
}
private void checkFractionFormatSpecifiers() {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Hour.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Hour.java
index 664412c4571..0a2873d5f3e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Hour.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Hour.java
@@ -21,8 +21,8 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -98,11 +98,6 @@ public class Hour extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof DateLiteral && upper instanceof DateLiteral) {
- return ((DateLiteral) lower).getYear() == ((DateLiteral)
upper).getYear()
- && ((DateLiteral) lower).getMonth() == ((DateLiteral)
upper).getMonth()
- && ((DateLiteral) lower).getDay() == ((DateLiteral)
upper).getDay();
- }
- return false;
+ return MonotonicityUtils.isWithinSameDay(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Microsecond.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Microsecond.java
index 444838d9edd..b5bc6ee1c6f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Microsecond.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Microsecond.java
@@ -21,11 +21,9 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-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.Literal;
-import org.apache.doris.nereids.trees.expressions.literal.TimeStampNsLiteral;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
@@ -98,27 +96,6 @@ public class Microsecond extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof TimeStampNsLiteral && upper instanceof
TimeStampNsLiteral) {
- TimeStampNsLiteral lowerDateTime = (TimeStampNsLiteral) lower;
- TimeStampNsLiteral upperDateTime = (TimeStampNsLiteral) upper;
- return lowerDateTime.getYear() == upperDateTime.getYear()
- && lowerDateTime.getMonth() == upperDateTime.getMonth()
- && lowerDateTime.getDay() == upperDateTime.getDay()
- && lowerDateTime.getHour() == upperDateTime.getHour()
- && lowerDateTime.getMinute() == upperDateTime.getMinute()
- && lowerDateTime.getSecond() == upperDateTime.getSecond();
- }
- if (lower instanceof DateTimeLiteral && upper instanceof
DateTimeLiteral) {
- DateTimeLiteral lowerDateTime = (DateTimeLiteral) lower;
- DateTimeLiteral upperDateTime = (DateTimeLiteral) upper;
- return lowerDateTime.getYear() == upperDateTime.getYear()
- && lowerDateTime.getMonth() == upperDateTime.getMonth()
- && lowerDateTime.getDay() == upperDateTime.getDay()
- && lowerDateTime.getHour() == upperDateTime.getHour()
- && lowerDateTime.getMinute() == upperDateTime.getMinute()
- && lowerDateTime.getSecond() == upperDateTime.getSecond();
- } else {
- return lower instanceof DateLiteral && upper instanceof
DateLiteral;
- }
+ return MonotonicityUtils.isWithinSameSecond(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Minute.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Minute.java
index 18454ea4b05..4e24e41553a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Minute.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Minute.java
@@ -21,11 +21,9 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-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.Literal;
-import org.apache.doris.nereids.trees.expressions.literal.TimeStampNsLiteral;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
@@ -99,23 +97,6 @@ public class Minute extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof TimeStampNsLiteral && upper instanceof
TimeStampNsLiteral) {
- TimeStampNsLiteral lowerDateTime = (TimeStampNsLiteral) lower;
- TimeStampNsLiteral upperDateTime = (TimeStampNsLiteral) upper;
- return lowerDateTime.getYear() == upperDateTime.getYear()
- && lowerDateTime.getMonth() == upperDateTime.getMonth()
- && lowerDateTime.getDay() == upperDateTime.getDay()
- && lowerDateTime.getHour() == upperDateTime.getHour();
- }
- if (lower instanceof DateTimeLiteral && upper instanceof
DateTimeLiteral) {
- DateTimeLiteral lowerDateTime = (DateTimeLiteral) lower;
- DateTimeLiteral upperDateTime = (DateTimeLiteral) upper;
- return lowerDateTime.getYear() == upperDateTime.getYear()
- && lowerDateTime.getMonth() == upperDateTime.getMonth()
- && lowerDateTime.getDay() == upperDateTime.getDay()
- && lowerDateTime.getHour() == upperDateTime.getHour();
- } else {
- return lower instanceof DateLiteral && upper instanceof
DateLiteral;
- }
+ return MonotonicityUtils.isWithinSameHour(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Month.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Month.java
index 550d9c465ad..6517e63e4b0 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Month.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Month.java
@@ -21,8 +21,8 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -96,9 +96,6 @@ public class Month extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof DateLiteral && upper instanceof DateLiteral) {
- return ((DateLiteral) lower).getYear() == ((DateLiteral)
upper).getYear();
- }
- return false;
+ return MonotonicityUtils.isWithinSameYear(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Nanosecond.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Nanosecond.java
index a730f41353b..b631f0cb643 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Nanosecond.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Nanosecond.java
@@ -21,11 +21,9 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-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.Literal;
-import org.apache.doris.nereids.trees.expressions.literal.TimeStampNsLiteral;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
@@ -90,26 +88,6 @@ public class Nanosecond extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof TimeStampNsLiteral && upper instanceof
TimeStampNsLiteral) {
- TimeStampNsLiteral lowerTimestamp = (TimeStampNsLiteral) lower;
- TimeStampNsLiteral upperTimestamp = (TimeStampNsLiteral) upper;
- return lowerTimestamp.getYear() == upperTimestamp.getYear()
- && lowerTimestamp.getMonth() == upperTimestamp.getMonth()
- && lowerTimestamp.getDay() == upperTimestamp.getDay()
- && lowerTimestamp.getHour() == upperTimestamp.getHour()
- && lowerTimestamp.getMinute() == upperTimestamp.getMinute()
- && lowerTimestamp.getSecond() ==
upperTimestamp.getSecond();
- }
- if (lower instanceof DateTimeLiteral && upper instanceof
DateTimeLiteral) {
- DateTimeLiteral lowerDateTime = (DateTimeLiteral) lower;
- DateTimeLiteral upperDateTime = (DateTimeLiteral) upper;
- return lowerDateTime.getYear() == upperDateTime.getYear()
- && lowerDateTime.getMonth() == upperDateTime.getMonth()
- && lowerDateTime.getDay() == upperDateTime.getDay()
- && lowerDateTime.getHour() == upperDateTime.getHour()
- && lowerDateTime.getMinute() == upperDateTime.getMinute()
- && lowerDateTime.getSecond() == upperDateTime.getSecond();
- }
- return lower instanceof DateLiteral && upper instanceof DateLiteral;
+ return MonotonicityUtils.isWithinSameSecond(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Quarter.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Quarter.java
index 60cbe488b84..a38dae15ea9 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Quarter.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Quarter.java
@@ -21,8 +21,8 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -95,9 +95,6 @@ public class Quarter extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof DateLiteral && upper instanceof DateLiteral) {
- return ((DateLiteral) lower).getYear() == ((DateLiteral)
upper).getYear();
- }
- return false;
+ return MonotonicityUtils.isWithinSameYear(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Second.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Second.java
index 9ddcf11f7ba..7bad0e30f62 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Second.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Second.java
@@ -21,11 +21,9 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
-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.Literal;
-import org.apache.doris.nereids.trees.expressions.literal.TimeStampNsLiteral;
import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
@@ -99,25 +97,6 @@ public class Second extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (lower instanceof TimeStampNsLiteral && upper instanceof
TimeStampNsLiteral) {
- TimeStampNsLiteral lowerDateTime = (TimeStampNsLiteral) lower;
- TimeStampNsLiteral upperDateTime = (TimeStampNsLiteral) upper;
- return lowerDateTime.getYear() == upperDateTime.getYear()
- && lowerDateTime.getMonth() == upperDateTime.getMonth()
- && lowerDateTime.getDay() == upperDateTime.getDay()
- && lowerDateTime.getHour() == upperDateTime.getHour()
- && lowerDateTime.getMinute() == upperDateTime.getMinute();
- }
- if (lower instanceof DateTimeLiteral && upper instanceof
DateTimeLiteral) {
- DateTimeLiteral lowerDateTime = (DateTimeLiteral) lower;
- DateTimeLiteral upperDateTime = (DateTimeLiteral) upper;
- return lowerDateTime.getYear() == upperDateTime.getYear()
- && lowerDateTime.getMonth() == upperDateTime.getMonth()
- && lowerDateTime.getDay() == upperDateTime.getDay()
- && lowerDateTime.getHour() == upperDateTime.getHour()
- && lowerDateTime.getMinute() == upperDateTime.getMinute();
- } else {
- return lower instanceof DateLiteral && upper instanceof
DateLiteral;
- }
+ return MonotonicityUtils.isWithinSameMinute(lower, upper);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeFormat.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeFormat.java
index 12b08ce1fac..2995fc17f8d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeFormat.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeFormat.java
@@ -22,15 +22,14 @@ import
org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
-import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.TimeStampNsType;
import org.apache.doris.nereids.types.TimeV2Type;
import org.apache.doris.nereids.types.VarcharType;
-import org.apache.doris.nereids.util.DateUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -85,12 +84,7 @@ public class TimeFormat extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- Expression format = child(1);
- if (!(format instanceof StringLikeLiteral)) {
- return false;
- }
- String str = ((StringLikeLiteral) format).getValue();
- return DateUtils.monoFormat.contains(str);
+ return MonotonicityUtils.hasMonotonicFormat(child(1));
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UnixTimestamp.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UnixTimestamp.java
index 2b6b8fb1aa4..9a19e7ee8b2 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UnixTimestamp.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UnixTimestamp.java
@@ -21,6 +21,7 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import
org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
@@ -171,11 +172,7 @@ public class UnixTimestamp extends ScalarFunction
}
LocalDateTime lowerDateTime = toLocalDateTime(lower);
LocalDateTime upperDateTime = toLocalDateTime(upper);
- if (lowerDateTime == null || upperDateTime == null ||
upperDateTime.isBefore(lowerDateTime)) {
- return false;
- }
- return !DateUtils.hasGapTransitionInLocalDateTimeRange(
- timeZone, lowerDateTime, upperDateTime);
+ return MonotonicityUtils.isLocalToInstantMonotonic(timeZone,
lowerDateTime, upperDateTime);
}
private LocalDateTime toLocalDateTime(Literal literal) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearWeek.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearWeek.java
index 632dd951e94..c5b857f3021 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearWeek.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearWeek.java
@@ -21,6 +21,7 @@ import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import org.apache.doris.nereids.trees.expressions.functions.MonotonicityUtils;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -88,10 +89,7 @@ public class YearWeek extends ScalarFunction
@Override
public boolean isMonotonic(Literal lower, Literal upper) {
- if (arity() == 1) {
- return true;
- }
- return child(1) instanceof Literal;
+ return MonotonicityUtils.hasConstantOtherArguments(this, 0);
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateUtils.java
index f34f67b2bc7..4110a055e81 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateUtils.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.util;
+import org.apache.doris.common.util.TimeUtils;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
import org.apache.doris.qe.ConnectContext;
@@ -503,36 +504,6 @@ public class DateUtils {
if (ConnectContext.get() == null ||
ConnectContext.get().getSessionVariable() == null) {
return ZoneId.systemDefault();
}
- return
ZoneId.of(ConnectContext.get().getSessionVariable().getTimeZone());
- }
-
- /**Determine whether there is a fallback transition within the interval
(lower, upper].
- * @return If there is one, return true.*/
- public static boolean hasFallbackTransitionInInstantRange(ZoneId zoneId,
Instant lower, Instant upper) {
- ZoneOffsetTransition transition =
zoneId.getRules().nextTransition(lower);
- while (transition != null && !transition.getInstant().isAfter(upper)) {
- if (transition.isOverlap()) {
- return true;
- }
- transition =
zoneId.getRules().nextTransition(transition.getInstant());
- }
- return false;
- }
-
- /** Determine whether the local interval intersects a spring-forward gap.
*/
- public static boolean hasGapTransitionInLocalDateTimeRange(
- ZoneId zoneId, LocalDateTime lower, LocalDateTime upper) {
- ZoneRules rules = zoneId.getRules();
- Instant searchStart = lower.minusDays(2).atZone(zoneId).toInstant();
- ZoneOffsetTransition transition = rules.nextTransition(searchStart);
- while (transition != null &&
!transition.getDateTimeBefore().isAfter(upper)) {
- if (transition.isGap()
- && upper.isAfter(transition.getDateTimeBefore())
- && lower.isBefore(transition.getDateTimeAfter())) {
- return true;
- }
- transition = rules.nextTransition(transition.getInstant());
- }
- return false;
+ return TimeUtils.getDorisZoneId();
}
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PruneOlapScanPartitionTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PruneOlapScanPartitionTest.java
index 107c3debe1f..6b7d10b308a 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PruneOlapScanPartitionTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PruneOlapScanPartitionTest.java
@@ -157,6 +157,25 @@ class PruneOlapScanPartitionTest extends TestWithFeService
implements MemoPatter
test("testOlapScanPartitionWithSingleColumnCase", "col1 >= 0 and col1
<= 5", 2);
}
+ @Test
+ void testEpochConversionWithTimeZoneAlias() throws Exception {
+ createTable("create table epoch_conversion_alias_prune ("
+ + "epoch_sec bigint not null) "
+ + "partition by range(epoch_sec) ("
+ + "partition p1 values[('1719792000'), ('1721001600')),"
+ + "partition p2 values[('1721001600'), ('1722470400'))"
+ + ") distributed by hash(epoch_sec) buckets 1 "
+ + "properties ('replication_num'='1')");
+
+ String previousTimeZone =
connectContext.getSessionVariable().getTimeZone();
+ try {
+ connectContext.getSessionVariable().setTimeZone("CST");
+ test("epoch_conversion_alias_prune", "from_second(epoch_sec) <
'2024-07-10 00:00:00'", 1);
+ } finally {
+ connectContext.getSessionVariable().setTimeZone(previousTimeZone);
+ }
+ }
+
@Test
void testOlapScanPartitionPruneWithTablet() throws Exception {
Database db =
Env.getCurrentInternalCatalog().getDbOrMetaException("test");
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromSecondMonotonicTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromSecondMonotonicTest.java
new file mode 100644
index 00000000000..153545e6eb7
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/FromSecondMonotonicTest.java
@@ -0,0 +1,98 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.functions.scalar;
+
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import
org.apache.doris.nereids.trees.expressions.functions.FromSecondMonotonic;
+import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
+import org.apache.doris.nereids.types.BigIntType;
+import org.apache.doris.qe.ConnectContext;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+class FromSecondMonotonicTest {
+ private final SlotReference epochSlot = new SlotReference("epoch",
BigIntType.INSTANCE);
+ private ConnectContext previousContext;
+
+ @BeforeEach
+ void setUp() {
+ previousContext = ConnectContext.get();
+ new ConnectContext().setThreadLocalInfo();
+ }
+
+ @AfterEach
+ void tearDown() {
+ ConnectContext.remove();
+ if (previousContext != null) {
+ previousContext.setThreadLocalInfo();
+ }
+ }
+
+ @Test
+ void testTimeZoneFallbackWithinRangeDisablesMonotonicity() {
+ List<FromSecondMonotonic> functions = Arrays.asList(
+ new FromSecond(epochSlot), new FromMillisecond(epochSlot), new
FromMicrosecond(epochSlot));
+ long[] fallbackSeconds = {1730613600L, 684867600L};
+ List<String> timeZones = Arrays.asList("America/New_York",
"Asia/Shanghai");
+ for (int i = 0; i < timeZones.size(); i++) {
+
ConnectContext.get().getSessionVariable().setTimeZone(timeZones.get(i));
+ for (FromSecondMonotonic function : functions) {
+ long units = function.getEpochUnitsPerSecond();
+ Assertions.assertFalse(function.isMonotonic(
+ new BigIntLiteral((fallbackSeconds[i] - 1) * units),
+ new BigIntLiteral((fallbackSeconds[i] + 1) * units)));
+ Assertions.assertTrue(function.isMonotonic(
+ new BigIntLiteral(1719792000L * units),
+ new BigIntLiteral(1719795600L * units)));
+ Assertions.assertFalse(function.isMonotonic(new
BigIntLiteral(1719792000), null));
+ }
+ }
+ }
+
+ @Test
+ void testShanghaiHistoricalFallbackAndEpochUnits() {
+ ConnectContext.get().getSessionVariable().setTimeZone("Asia/Shanghai");
+ Assertions.assertFalse(new FromMillisecond(epochSlot).isMonotonic(
+ new BigIntLiteral(100000), new BigIntLiteral(1000000009999L)));
+ Assertions.assertTrue(new FromMicrosecond(epochSlot).isMonotonic(
+ new BigIntLiteral(100000), new BigIntLiteral(1000000009999L)));
+ Assertions.assertFalse(new FromSecond(epochSlot).isMonotonic(
+ new BigIntLiteral(253402272000L), new
BigIntLiteral(253402272001L)));
+ }
+
+ @Test
+ void testFixedOffsetPreservesMonotonicityForNonnegativeInput() {
+ List<FromSecondMonotonic> functions = Arrays.asList(
+ new FromSecond(epochSlot), new FromMillisecond(epochSlot), new
FromMicrosecond(epochSlot));
+ for (String timeZone : Arrays.asList("+00:00", "+08:00")) {
+ ConnectContext.get().getSessionVariable().setTimeZone(timeZone);
+ for (FromSecondMonotonic function : functions) {
+ Assertions.assertTrue(function.isMonotonic(new
BigIntLiteral(0), new BigIntLiteral(1)));
+ Assertions.assertTrue(function.isMonotonic(new
BigIntLiteral(0), null));
+ Assertions.assertFalse(function.isMonotonic(new
BigIntLiteral(-1), new BigIntLiteral(1)));
+ Assertions.assertFalse(function.isMonotonic(null, new
BigIntLiteral(1)));
+ }
+ }
+ }
+}
diff --git
a/regression-test/suites/nereids_rules_p0/partition_prune/month_quarter_cast_in_prune.groovy
b/regression-test/suites/nereids_rules_p0/partition_prune/month_quarter_cast_in_prune.groovy
index be89d056e94..3a77c478977 100644
---
a/regression-test/suites/nereids_rules_p0/partition_prune/month_quarter_cast_in_prune.groovy
+++
b/regression-test/suites/nereids_rules_p0/partition_prune/month_quarter_cast_in_prune.groovy
@@ -125,29 +125,55 @@ suite("month_quarter_cast_in_prune") {
) distributed by hash(a) properties("replication_num"="1");"""
sql """INSERT INTO monotonic_function_t
values(10000,'1979-01-01','1979-01-01','abc'),(100000009999,'2012-01-01','2012-01-01','abc'),(100000009999999,'2020-01-01','2020-01-01','abc'),(10000000099999999,'2045-01-01','2045-01-01','abc')"""
- explain {
- sql """select * from monotonic_function_t where from_second(a) <
'2001-09-09 12:33:19' """
- contains("partitions=4/4 (p1,p2,p3,p4)")
- }
- explain {
- sql """select * from monotonic_function_t where from_second(a) >
'2001-09-09 12:33:19' """
- contains("partitions=4/4 (p1,p2,p3,p4)")
- }
- explain {
- sql """select * from monotonic_function_t where from_millisecond(a) <
'2001-09-09 12:33:19' """
- contains("partitions=4/4 (p1,p2,p3,p4)")
- }
- explain {
- sql """select * from monotonic_function_t where from_millisecond(a) >
'2001-09-09 12:33:19' """
- contains("partitions=3/4 (p1,p3,p4)")
- }
- explain {
- sql """select * from monotonic_function_t where from_microsecond(a) <
'2000-09-09 12:33:19' """
- contains("partitions=3/4 (p1,p2,p3)")
+ def originalTimeZone = sql("select @@time_zone")[0][0]
+ try {
+ sql "set time_zone = 'Asia/Shanghai'"
+ explain {
+ sql """select * from monotonic_function_t where from_second(a) <
'2001-09-09 12:33:19' """
+ contains("partitions=4/4 (p1,p2,p3,p4)")
+ }
+ explain {
+ sql """select * from monotonic_function_t where from_second(a) >
'2001-09-09 12:33:19' """
+ contains("partitions=4/4 (p1,p2,p3,p4)")
+ }
+ explain {
+ sql """select * from monotonic_function_t where
from_millisecond(a) < '2001-09-09 12:33:19' """
+ contains("partitions=4/4 (p1,p2,p3,p4)")
+ }
+ explain {
+ sql """select * from monotonic_function_t where
from_millisecond(a) > '2001-09-09 12:33:19' """
+ // p2 spans the 1991 Asia/Shanghai fall-back, so it is not
monotonic.
+ contains("partitions=4/4 (p1,p2,p3,p4)")
+ }
+ explain {
+ sql """select * from monotonic_function_t where
from_microsecond(a) < '2000-09-09 12:33:19' """
+ contains("partitions=4/4 (p1,p2,p3,p4)")
+ }
+ explain {
+ sql """select * from monotonic_function_t where
from_microsecond(a) > '2002-09-09 12:33:19' """
+ // p2 is a safe 1970 interval; p3 spans the 1991 fall-back.
+ contains("partitions=3/4 (p1,p3,p4)")
+ }
+ } finally {
+ sql "set time_zone = '${originalTimeZone}'"
}
- explain {
- sql """select * from monotonic_function_t where from_microsecond(a) >
'2002-09-09 12:33:19' """
- contains("partitions=2/4 (p1,p4)")
+
+ sql "drop table if exists epoch_cst_prune"
+ sql """create table epoch_cst_prune (a bigint) duplicate key(a)
+ partition by range(a) (
+ partition p2000 values [('946684800'), ('978307200')),
+ partition p2001 values [('978307200'), ('1009843200')),
+ partition p2002 values [('1009843200'), ('1041379200'))
+ ) distributed by hash(a) properties('replication_num'='1');"""
+ sql "insert into epoch_cst_prune values (946684800), (978307200),
(1009843200)"
+ try {
+ sql "set time_zone = 'CST'"
+ explain {
+ sql "select * from epoch_cst_prune where from_second(a) >
'2001-06-01 00:00:00'"
+ contains("partitions=2/3 (p2001,p2002)")
+ }
+ } finally {
+ sql "set time_zone = '${originalTimeZone}'"
}
// test makedate
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]