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 163a4a577e7 [fix](constant folding) Align FE constant folding results
with execution (#65319)
163a4a577e7 is described below
commit 163a4a577e7fe4ffe8b7175582abefaf8bb855ea
Author: morrySnow <[email protected]>
AuthorDate: Fri Jul 17 19:14:51 2026 +0800
[fix](constant folding) Align FE constant folding results with execution
(#65319)
### What problem does this PR solve?
Problem Summary:
Constant folding could diverge from BE execution for date and time
casts, decimal string formatting, str_to_date formats expressed as
constant expressions, and field arguments containing NaN. Align literal
handling with BE behavior and add focused unit and regression coverage.
### Release note
Fixes incorrect constant-folded results for affected expressions.
---
.../functions/executable/StringArithmetic.java | 4 +-
.../expressions/functions/scalar/StrToDate.java | 29 +++++++--
.../trees/expressions/literal/DateLiteral.java | 2 +-
.../trees/expressions/literal/DateTimeLiteral.java | 51 ++++++++--------
.../expressions/literal/DateTimeV2Literal.java | 4 +-
.../expressions/literal/DecimalV3Literal.java | 7 ++-
.../expressions/literal/StringLikeLiteral.java | 68 ++++++++++------------
.../trees/expressions/literal/TimeV2Literal.java | 5 +-
.../expressions/literal/TimestampTzLiteral.java | 4 +-
.../functions/executable/StringArithmeticTest.java | 66 +++++++++++++++++++++
.../functions/scalar/StrToDateTest.java | 43 ++++++++++++++
.../trees/expressions/literal/DateLiteralTest.java | 7 +--
.../expressions/literal/DecimalLiteralTest.java | 10 ++++
.../expressions/literal/StringLikeLiteralTest.java | 13 +++++
.../expressions/literal/TimeV2LiteralTest.java | 12 ++++
.../suites/cast_p0/cast_to_datetime.groovy | 7 ++-
.../fold_constant/fe_constant_cast_to_date.groovy | 18 +++---
.../fold_constant_string_arithmatic.groovy | 10 +++-
.../datetime_functions/test_date_function.groovy | 1 +
19 files changed, 268 insertions(+), 93 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmetic.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmetic.java
index e6169edd45c..6347bec6dc0 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmetic.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmetic.java
@@ -563,7 +563,7 @@ public class StringArithmetic {
float firstValue = first.getValue();
for (int i = 0; i < second.length; i++) {
float secondValue = second[i].getValue();
- if (secondValue == firstValue) {
+ if (secondValue == firstValue || Float.isNaN(secondValue) &&
Float.isNaN(firstValue)) {
return i + 1;
}
}
@@ -574,7 +574,7 @@ public class StringArithmetic {
double firstValue = first.getValue();
for (int i = 0; i < second.length; i++) {
double secondValue = second[i].getValue();
- if (secondValue == firstValue) {
+ if (secondValue == firstValue || Double.isNaN(secondValue) &&
Double.isNaN(firstValue)) {
return i + 1;
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDate.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDate.java
index 6436f439ce5..31887127eb4 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDate.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDate.java
@@ -19,10 +19,13 @@ package
org.apache.doris.nereids.trees.expressions.functions.scalar;
import org.apache.doris.analysis.DateLiteral;
import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Cast;
import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.ExpressionEvaluator;
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.PropagateNullLiteral;
+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;
@@ -90,12 +93,12 @@ public class StrToDate extends ScalarFunction
* Return type is DATETIME
*/
DataType returnType;
- if (getArgument(1) instanceof StringLikeLiteral) {
- if (DateLiteral.hasTimePart(((StringLikeLiteral)
getArgument(1)).getStringValue())) {
+ Literal formatLiteral = getConstantFormatLiteral();
+ if (formatLiteral != null) {
+ if (DateLiteral.hasTimePart(formatLiteral.getStringValue())) {
//FIXME: Here will pass different scale to BE with same input
types. Need to be fixed.
returnType = DateTimeV2Type.SYSTEM_DEFAULT;
- if (returnType.isDateTimeV2Type()
- && DateLiteral.hasMicroSecondPart(((StringLikeLiteral)
getArgument(1)).getStringValue())) {
+ if
(DateLiteral.hasMicroSecondPart(formatLiteral.getStringValue())) {
returnType = DateTimeV2Type.MAX;
}
} else {
@@ -107,6 +110,24 @@ public class StrToDate extends ScalarFunction
return signature.withReturnType(returnType);
}
+ private StringLikeLiteral getConstantFormatLiteral() {
+ Expression format = getArgument(1);
+ if (!format.isConstant()) {
+ return null;
+ }
+ if (!format.getDataType().isStringLikeType()) {
+ format = new Cast(format, StringType.INSTANCE);
+ }
+ if (format instanceof StringLikeLiteral) {
+ return (StringLikeLiteral) format;
+ }
+ Expression evaluated = ExpressionEvaluator.INSTANCE.eval(format);
+ if (evaluated instanceof StringLikeLiteral) {
+ return (StringLikeLiteral) evaluated;
+ }
+ return null;
+ }
+
/**
* withChildren.
*/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
index df42c370949..3d1f5017be3 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
@@ -370,7 +370,7 @@ public class DateLiteral extends Literal implements
ComparableLiteral {
month = DateUtils.getOrDefault(dateTime, ChronoField.MONTH_OF_YEAR);
day = DateUtils.getOrDefault(dateTime, ChronoField.DAY_OF_MONTH);
- if (checkDatetime(dateTime) || checkRange(year, month, day) ||
checkDate(year, month, day)) {
+ if (checkRange(year, month, day) || checkDate(year, month, day)) {
throw new AnalysisException("date/datetime literal [" + s + "] is
out of range");
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
index 4a8ac991168..c50f98b45a1 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
@@ -246,27 +246,16 @@ public class DateTimeLiteral extends DateLiteral {
// Microseconds have 7 digits.
long sevenDigit = microSecond % 10;
microSecond = microSecond / 10;
- if (sevenDigit >= 5 && (this instanceof DateTimeV2Literal || this
instanceof TimestampTzLiteral)) {
+ if (sevenDigit >= 5) {
DateTimeLiteral result;
- if (this instanceof DateTimeV2Literal) {
- result = (DateTimeV2Literal) ((DateTimeV2Literal)
this).plusMicroSeconds(1);
- this.second = result.second;
- this.minute = result.minute;
- this.hour = result.hour;
- this.day = result.day;
- this.month = result.month;
- this.year = result.year;
- this.microSecond = result.microSecond;
- } else if (this instanceof TimestampTzLiteral) {
- result = (TimestampTzLiteral) ((TimestampTzLiteral)
this).plusMicroSeconds(1);
- this.second = result.second;
- this.minute = result.minute;
- this.hour = result.hour;
- this.day = result.day;
- this.month = result.month;
- this.year = result.year;
- this.microSecond = result.microSecond;
- }
+ result = this.plusMicroSeconds(1);
+ this.second = result.second;
+ this.minute = result.minute;
+ this.hour = result.hour;
+ this.day = result.day;
+ this.month = result.month;
+ this.year = result.year;
+ this.microSecond = result.microSecond;
}
if (checkRange(year, month, day) || checkDate(year, month, day)) {
@@ -274,6 +263,12 @@ public class DateTimeLiteral extends DateLiteral {
}
}
+ // When performing addition or subtraction with MicroSeconds, the
precision must be set to 6 to display it
+ // completely. use multiplyExact to be aware of multiplication overflow
possibility.
+ public DateTimeLiteral plusMicroSeconds(long microSeconds) {
+ return
fromJavaDateType(toJavaDateType().plusNanos(Math.multiplyExact(microSeconds,
1000L)), 6);
+ }
+
private static LocalDateTime convertTimeZone(long year, long month, long
day, long hour, long minute,
long second, ZoneId fromZone, ZoneId toZone) {
LocalDateTime localDateTime = LocalDateTime.of((int) year, (int)
month, (int) day,
@@ -438,31 +433,31 @@ public class DateTimeLiteral extends DateLiteral {
}
public Expression plusDays(long days) {
- return fromJavaDateType(toJavaDateType().plusDays(days));
+ return fromJavaDateType(toJavaDateType().plusDays(days), 0);
}
public Expression plusMonths(long months) {
- return fromJavaDateType(toJavaDateType().plusMonths(months));
+ return fromJavaDateType(toJavaDateType().plusMonths(months), 0);
}
public Expression plusWeeks(long weeks) {
- return fromJavaDateType(toJavaDateType().plusWeeks(weeks));
+ return fromJavaDateType(toJavaDateType().plusWeeks(weeks), 0);
}
public Expression plusYears(long years) {
- return fromJavaDateType(toJavaDateType().plusYears(years));
+ return fromJavaDateType(toJavaDateType().plusYears(years), 0);
}
public Expression plusHours(long hours) {
- return fromJavaDateType(toJavaDateType().plusHours(hours));
+ return fromJavaDateType(toJavaDateType().plusHours(hours), 0);
}
public Expression plusMinutes(long minutes) {
- return fromJavaDateType(toJavaDateType().plusMinutes(minutes));
+ return fromJavaDateType(toJavaDateType().plusMinutes(minutes), 0);
}
public Expression plusSeconds(long seconds) {
- return fromJavaDateType(toJavaDateType().plusSeconds(seconds));
+ return fromJavaDateType(toJavaDateType().plusSeconds(seconds), 0);
}
public long getHour() {
@@ -498,7 +493,7 @@ public class DateTimeLiteral extends DateLiteral {
((int) getHour()), ((int) getMinute()), ((int) getSecond()),
(int) getMicroSecond() * 1000);
}
- public static Expression fromJavaDateType(LocalDateTime dateTime) {
+ public static DateTimeLiteral fromJavaDateType(LocalDateTime dateTime, int
precision) {
if (isDateOutOfRange(dateTime)) {
throw new AnalysisException("datetime out of range: " +
dateTime.toString());
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
index 93f221d4d99..bfdf1e3be6e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
@@ -409,7 +409,7 @@ public class DateTimeV2Literal extends DateTimeLiteral {
// When performing addition or subtraction with MicroSeconds, the
precision must be set to 6 to display it
// completely. use multiplyExact to be aware of multiplication overflow
possibility.
- public Expression plusMicroSeconds(long microSeconds) {
+ public DateTimeV2Literal plusMicroSeconds(long microSeconds) {
return
fromJavaDateType(toJavaDateType().plusNanos(Math.multiplyExact(microSeconds,
1000L)), 6);
}
@@ -474,7 +474,7 @@ public class DateTimeV2Literal extends DateTimeLiteral {
/**
* convert java LocalDateTime object to DateTimeV2Literal object.
*/
- public static Expression fromJavaDateType(LocalDateTime dateTime, int
precision) {
+ public static DateTimeV2Literal fromJavaDateType(LocalDateTime dateTime,
int precision) {
long value = (long) Math.pow(10, DateTimeV2Type.MAX_SCALE - precision);
if (isDateOutOfRange(dateTime)) {
throw new AnalysisException("datetime out of range" +
dateTime.toString());
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DecimalV3Literal.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DecimalV3Literal.java
index c8c161b35bd..e82acd634c7 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DecimalV3Literal.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DecimalV3Literal.java
@@ -174,7 +174,12 @@ public class DecimalV3Literal extends FractionalLiteral {
@Override
public String computeToSql() {
- return value.toPlainString();
+ return getStringValue();
+ }
+
+ @Override
+ public String getStringValue() {
+ return value.setScale(((DecimalV3Type) dataType).getScale(),
RoundingMode.HALF_UP).toPlainString();
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
index 148c3efb852..afe473ccf75 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
@@ -23,7 +23,6 @@ import org.apache.doris.nereids.exceptions.CastException;
import org.apache.doris.nereids.trees.expressions.Expression;
import
org.apache.doris.nereids.trees.expressions.literal.format.DateTimeChecker;
import org.apache.doris.nereids.types.DataType;
-import org.apache.doris.nereids.types.DateTimeType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.TimeStampTzType;
import org.apache.doris.nereids.types.TimeV2Type;
@@ -133,18 +132,9 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
return castToIntegral(targetType, strictCast);
}
if (targetType.isDateType() || targetType.isDateV2Type()) {
- Expression expression = castToDateTime(DateTimeV2Type.MAX,
strictCast, false);
- DateTimeV2Literal datetime = (DateTimeV2Literal) expression;
- if (targetType.isDateType()) {
- return new DateLiteral(datetime.year, datetime.month,
datetime.day);
- } else {
- return new DateV2Literal(datetime.year, datetime.month,
datetime.day);
- }
+ return castToDateTime(targetType, strictCast);
} else if (targetType.isDateTimeType()) {
- Expression expression = castToDateTime(DateTimeV2Type.MAX,
strictCast, true);
- DateTimeV2Literal datetime = (DateTimeV2Literal) expression;
- return new DateTimeLiteral((DateTimeType) targetType,
datetime.year, datetime.month, datetime.day,
- datetime.hour, datetime.minute, datetime.second,
datetime.microSecond);
+ return castToDateTime(targetType, strictCast);
} else if (targetType.isTimeStampTzType()) {
// Wildcard targets still need a concrete scale before parsing.
TimeStampTzType timeStampTzType = (TimeStampTzType) targetType;
@@ -154,10 +144,10 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
if (DateTimeChecker.hasTimeZone(value)) {
return new TimestampTzLiteral(timeStampTzType, value);
}
- DateTimeV2Literal datetime = castToDateTime(DateTimeV2Type.MAX,
strictCast, true);
+ DateTimeV2Literal datetime = (DateTimeV2Literal)
castToDateTime(DateTimeV2Type.MAX, strictCast);
return TimestampTzLiteral.fromSessionTimeZone(timeStampTzType,
datetime);
} else if (targetType.isDateTimeV2Type()) {
- return castToDateTime(targetType, strictCast, true);
+ return castToDateTime(targetType, strictCast);
} else if (targetType.isFloatType()) {
return castToFloat();
} else if (targetType.isDoubleType()) {
@@ -270,7 +260,7 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
throw new CastException(String.format("%s can't cast to decimal in
strict mode.", value));
}
- protected DateTimeV2Literal castToDateTime(DataType targetType, boolean
strictCast, boolean isDatetime) {
+ protected DateLiteral castToDateTime(DataType targetType, boolean
strictCast) {
Matcher strictMatcher = dateStrictPattern.matcher(value);
String year;
String month;
@@ -312,14 +302,7 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
if (tz != null && tz.equalsIgnoreCase("CST")) {
tz = "+08:00";
}
- DateTimeV2Literal dt = getDateTimeLiteral(year, month, date, hour,
minute, second,
- fraction, tz, targetType);
- if (isDatetime) {
- return dt;
- } else {
- return new
DateTimeV2Literal(Long.parseLong(year2ToYear4(year)), Long.parseLong(month),
- Long.parseLong(date), 0, 0, 0);
- }
+ return getDateTimeLiteral(year, month, date, hour, minute, second,
fraction, tz, targetType);
} else if (!strictCast) {
Matcher unStrictMatcher = dateUnStrictPattern.matcher(value);
if (unStrictMatcher.matches()) {
@@ -334,14 +317,7 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
if (tz != null && tz.equalsIgnoreCase("CST")) {
tz = "+08:00";
}
- DateTimeV2Literal dt = getDateTimeLiteral(year, month, date,
hour, minute, second,
- fraction, tz, targetType);
- if (isDatetime) {
- return dt;
- } else {
- return new
DateTimeV2Literal(Long.parseLong(year2ToYear4(year)), Long.parseLong(month),
- Long.parseLong(date), 0, 0, 0);
- }
+ return getDateTimeLiteral(year, month, date, hour, minute,
second, fraction, tz, targetType);
}
}
throw new CastException(String.format("[%s] can't cast to %s.", value,
targetType));
@@ -355,7 +331,7 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
return year;
}
- protected DateTimeV2Literal getDateTimeLiteral(String year, String month,
String date, String hour, String minute,
+ protected DateLiteral getDateTimeLiteral(String year, String month, String
date, String hour, String minute,
String second, String fraction, String tz, DataType targetType) {
String year4 = year2ToYear4(year);
tz = tz == null ? "" : tz;
@@ -385,10 +361,30 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
}
}
String format = String.format("%s-%s-%sT%s:%s:%s%s%s", year4, month,
date, hour, minute, second, fraction, tz);
- try {
- return new DateTimeV2Literal((DateTimeV2Type) targetType, format);
- } catch (AnalysisException e) {
- throw new CastException(e.getMessage(), e);
+ if (targetType.isDateType()) {
+ try {
+ return new DateLiteral(format);
+ } catch (AnalysisException e) {
+ throw new CastException(e.getMessage(), e);
+ }
+ } else if (targetType.isDateV2Type()) {
+ try {
+ return new DateV2Literal(format);
+ } catch (AnalysisException e) {
+ throw new CastException(e.getMessage(), e);
+ }
+ } else if (targetType.isDateTimeType()) {
+ try {
+ return new DateTimeLiteral(format);
+ } catch (AnalysisException e) {
+ throw new CastException(e.getMessage(), e);
+ }
+ } else {
+ try {
+ return new DateTimeV2Literal((DateTimeV2Type) targetType,
format);
+ } catch (AnalysisException e) {
+ throw new CastException(e.getMessage(), e);
+ }
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
index 0b2c7f067b6..8d04a006baf 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
@@ -302,9 +302,10 @@ public class TimeV2Literal extends Literal {
@Override
protected Expression uncheckedCastTo(DataType targetType) throws
AnalysisException {
+ long microsecondValue = ((Double) getValue()).longValue();
DateTimeV2Literal time = (DateTimeV2Literal)
DateTimeV2Literal.fromJavaDateType(LocalDateTime
-
.now(DateUtils.getTimeZone()).withHour(0).withMinute(0).withSecond(0).withNano(0).plusHours(getHour())
-
.plusMinutes(getMinute()).plusSeconds(getSecond()).plusNanos(getMicroSecond() *
1000),
+
.now(DateUtils.getTimeZone()).withHour(0).withMinute(0).withSecond(0).withNano(0)
+ .plusNanos(microsecondValue * 1000),
((TimeV2Type) dataType).getScale());
if (targetType.isDateType()) {
return new DateLiteral(time.getYear(), time.getMonth(),
time.getDay());
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimestampTzLiteral.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimestampTzLiteral.java
index 7caed5ecc01..810168d4985 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimestampTzLiteral.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimestampTzLiteral.java
@@ -380,7 +380,7 @@ public class TimestampTzLiteral extends DateTimeLiteral {
// When performing addition or subtraction with MicroSeconds, the
precision must be set to 6 to display it
// completely. use multiplyExact to be aware of multiplication overflow
possibility.
- public Expression plusMicroSeconds(long microSeconds) {
+ public TimestampTzLiteral plusMicroSeconds(long microSeconds) {
return
fromJavaDateType(toJavaDateType().plusNanos(Math.multiplyExact(microSeconds,
1000L)), 6);
}
@@ -473,7 +473,7 @@ public class TimestampTzLiteral extends DateTimeLiteral {
/**
* convert java LocalDateTime object to TimeStampTzTypeLiteral object.
*/
- public static Expression fromJavaDateType(LocalDateTime dateTime, int
precision) {
+ public static TimestampTzLiteral fromJavaDateType(LocalDateTime dateTime,
int precision) {
long value = (long) Math.pow(10, TimeStampTzType.MAX_SCALE -
precision);
if (isDateOutOfRange(dateTime)) {
throw new AnalysisException("datetime out of range" +
dateTime.toString());
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmeticTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmeticTest.java
new file mode 100644
index 00000000000..0bf26dd0da8
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmeticTest.java
@@ -0,0 +1,66 @@
+// 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.executable;
+
+import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.FloatLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class StringArithmeticTest {
+
+ @Test
+ void testFieldMatchesFloatNaN() {
+ IntegerLiteral result = (IntegerLiteral)
StringArithmetic.fieldFloat(new FloatLiteral(Float.NaN),
+ new FloatLiteral(Float.NaN));
+
+ Assertions.assertEquals(1, result.getValue());
+ }
+
+ @Test
+ void testFieldMatchesDoubleNaN() {
+ IntegerLiteral result = (IntegerLiteral)
StringArithmetic.fieldDouble(new DoubleLiteral(Double.NaN),
+ new DoubleLiteral(Double.NaN));
+
+ Assertions.assertEquals(1, result.getValue());
+ }
+
+ @Test
+ void testFieldMatchesFloatSignedZero() {
+ IntegerLiteral positiveZero = (IntegerLiteral)
StringArithmetic.fieldFloat(new FloatLiteral(0.0f),
+ new FloatLiteral(-0.0f));
+ IntegerLiteral negativeZero = (IntegerLiteral)
StringArithmetic.fieldFloat(new FloatLiteral(-0.0f),
+ new FloatLiteral(0.0f));
+
+ Assertions.assertEquals(1, positiveZero.getValue());
+ Assertions.assertEquals(1, negativeZero.getValue());
+ }
+
+ @Test
+ void testFieldMatchesDoubleSignedZero() {
+ IntegerLiteral positiveZero = (IntegerLiteral)
StringArithmetic.fieldDouble(new DoubleLiteral(0.0),
+ new DoubleLiteral(-0.0));
+ IntegerLiteral negativeZero = (IntegerLiteral)
StringArithmetic.fieldDouble(new DoubleLiteral(-0.0),
+ new DoubleLiteral(0.0));
+
+ Assertions.assertEquals(1, positiveZero.getValue());
+ Assertions.assertEquals(1, negativeZero.getValue());
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDateTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDateTest.java
new file mode 100644
index 00000000000..abb37cfc919
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StrToDateTest.java
@@ -0,0 +1,43 @@
+// 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.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
+import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.DateV2Type;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class StrToDateTest {
+
+ @Test
+ void testComputeSignatureWithFoldableFormat() {
+ StrToDate dateFormat = new StrToDate(new StringLiteral("2024-01-01"),
+ new Concat(new StringLiteral("%Y-%m"), new
StringLiteral("-%d")));
+ StrToDate dateTimeFormat = new StrToDate(new StringLiteral("2024-01-01
12:34:56"),
+ new Concat(new StringLiteral("%Y-%m-%d"), new StringLiteral("
%H:%i:%s")));
+
+ FunctionSignature dateSignature =
dateFormat.computeSignature(StrToDate.SIGNATURES.get(0));
+ FunctionSignature dateTimeSignature =
dateTimeFormat.computeSignature(StrToDate.SIGNATURES.get(0));
+
+ Assertions.assertEquals(DateV2Type.INSTANCE, dateSignature.returnType);
+ Assertions.assertEquals(DateTimeV2Type.SYSTEM_DEFAULT,
dateTimeSignature.returnType);
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
index f3bb60d0d36..8b2db5b3511 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
@@ -40,10 +40,9 @@ import java.util.function.Consumer;
class DateLiteralTest {
@Test
void reject() {
- Assertions.assertThrows(AnalysisException.class, () -> new
DateLiteral("2022-01-01 01:00:00.000000"));
- Assertions.assertThrows(AnalysisException.class, () -> new
DateLiteral("2022-01-01 00:01:00.000000"));
- Assertions.assertThrows(AnalysisException.class, () -> new
DateLiteral("2022-01-01 00:00:01.000000"));
- Assertions.assertThrows(AnalysisException.class, () -> new
DateLiteral("2022-01-01 00:00:00.000001"));
+ Assertions.assertThrows(AnalysisException.class, () -> new
DateLiteral("2022-01-01 24:00:00.000000"));
+ Assertions.assertThrows(AnalysisException.class, () -> new
DateLiteral("2022-01-01 00:60:00.000000"));
+ Assertions.assertThrows(AnalysisException.class, () -> new
DateLiteral("2022-01-01 00:00:60.000000"));
}
@Test
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DecimalLiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DecimalLiteralTest.java
index 7e5cf346b0e..cdb087c7ff1 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DecimalLiteralTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DecimalLiteralTest.java
@@ -130,4 +130,14 @@ public class DecimalLiteralTest {
Assertions.assertInstanceOf(StringLiteral.class, expression);
Assertions.assertEquals("234.567", ((StringLiteral) expression).value);
}
+
+ @Test
+ void testDecimalV3CastToStringUsesPlainNotation() {
+ DecimalV3Literal literal = new
DecimalV3Literal(DecimalV3Type.createDecimalV3Type(10, 2),
+ new BigDecimal("1E+3"));
+
+ StringLiteral string = (StringLiteral)
literal.uncheckedCastTo(StringType.INSTANCE);
+
+ Assertions.assertEquals("1000.00", string.getStringValue());
+ }
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteralTest.java
index b1b58520b20..0675a07c607 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteralTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteralTest.java
@@ -20,6 +20,8 @@ package org.apache.doris.nereids.trees.expressions.literal;
import org.apache.doris.nereids.exceptions.CastException;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DateType;
+import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.DecimalV3Type;
import org.apache.doris.nereids.types.DoubleType;
import org.apache.doris.nereids.types.FloatType;
@@ -204,6 +206,17 @@ public class StringLikeLiteralTest {
}
+ @Test
+ void testCastMaxDateTimeStringToDateDoesNotRoundTimePart() {
+ StringLiteral literal = new StringLiteral("9999-12-31
23:59:59.999999");
+
+ DateLiteral date = (DateLiteral)
literal.uncheckedCastTo(DateType.INSTANCE);
+ DateV2Literal dateV2 = (DateV2Literal)
literal.uncheckedCastTo(DateV2Type.INSTANCE);
+
+ Assertions.assertEquals("9999-12-31", date.getStringValue());
+ Assertions.assertEquals("9999-12-31", dateV2.getStringValue());
+ }
+
@Test
void testUncheckedCastToTimeStampTzRejectsUnstrictNoOffsetInStrictMode() {
try (MockedStatic<SessionVariable> mockedSessionVariable =
Mockito.mockStatic(SessionVariable.class)) {
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2LiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2LiteralTest.java
index ef73fe1efd4..96775d44bfc 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2LiteralTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2LiteralTest.java
@@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.expressions.literal;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.StringType;
import org.apache.doris.nereids.types.TimeV2Type;
@@ -174,4 +175,15 @@ public class TimeV2LiteralTest {
Assertions.assertEquals("00:00:00.000", ((StringLiteral)
expression).value);
}
+ @Test
+ public void testCastNegativeTimeToDateTimeV2KeepsSign() {
+ TimeV2Literal literal = new TimeV2Literal(TimeV2Type.of(0),
"-00:00:01");
+
+ DateTimeV2Literal dateTime = (DateTimeV2Literal)
literal.uncheckedCastTo(DateTimeV2Type.of(0));
+
+ Assertions.assertEquals(23, dateTime.getHour());
+ Assertions.assertEquals(59, dateTime.getMinute());
+ Assertions.assertEquals(59, dateTime.getSecond());
+ }
+
}
diff --git a/regression-test/suites/cast_p0/cast_to_datetime.groovy
b/regression-test/suites/cast_p0/cast_to_datetime.groovy
index 7a3084bd8e4..59960b54da2 100644
--- a/regression-test/suites/cast_p0/cast_to_datetime.groovy
+++ b/regression-test/suites/cast_p0/cast_to_datetime.groovy
@@ -237,6 +237,11 @@ qt_sql204 """ select cast('9999-12-31 23:59:59.999999
+00:00' as datetime(6)) ""
testFoldConst("select cast('9999-12-31 23:59:59.999999 +00:00' as
datetime(6))")
qt_sql205 """ select cast('0000-01-01 00:00:00+12:00' as datetime(6)); """
testFoldConst("select cast('0000-01-01 00:00:00+12:00' as datetime(6));")
+testFoldConst("select cast('9999-12-31 23:59:59.999999' as date), "
+ + "cast('9999-12-31 23:59:59.999999' as datev2)")
+waitUntilSafeExecutionTime("NOT_CROSS_DAY_BOUNDARY", 2)
+testFoldConst("select cast(cast('-00:00:01' as time(0)) as datetime(0)), "
+ + "cast(cast('-00:00:01' as time(0)) as datetimev2(0))")
sql "set debug_skip_fold_constant = false"
@@ -258,4 +263,4 @@ testFoldConst("select cast('0000-01-01 00:00:00+12:00' as
datetime(6));")
sql "select cast('0000-01-01 00:00:00+12:00' as datetime(6));"
exception "out of range"
}
-}
\ No newline at end of file
+}
diff --git
a/regression-test/suites/query_p0/expression/fold_constant/fe_constant_cast_to_date.groovy
b/regression-test/suites/query_p0/expression/fold_constant/fe_constant_cast_to_date.groovy
index 933ac7a47fd..87c2ebdc34d 100644
---
a/regression-test/suites/query_p0/expression/fold_constant/fe_constant_cast_to_date.groovy
+++
b/regression-test/suites/query_p0/expression/fold_constant/fe_constant_cast_to_date.groovy
@@ -57,36 +57,36 @@ suite("fe_constant_cast_to_date") {
test {
sql """select cast("2023-07-16T19.123+08:00" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
qt_sql """select cast("2024/05/01" as date)"""
test {
sql """select cast("24012" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
test {
sql """select cast("2411 123" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
test {
sql """select cast("2024-05-01 01:030:02" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
test {
sql """select cast("10000-01-01 00:00:00" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
test {
sql """select cast("2024-0131T12:00" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
test {
sql """select cast("2024-05-01@00:00" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
test {
sql """select cast("20120212051" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
test {
sql """select cast("2024-05-01T00:00XYZ" as date)"""
@@ -114,7 +114,7 @@ suite("fe_constant_cast_to_date") {
}
test {
sql """select cast("2024-05-01T00:00+08:25" as date)"""
- exception "can't cast to DATETIMEV2"
+ exception "can't cast to DATEV2"
}
test {
sql """select cast(1000 as date)"""
diff --git
a/regression-test/suites/query_p0/expression/fold_constant/fold_constant_string_arithmatic.groovy
b/regression-test/suites/query_p0/expression/fold_constant/fold_constant_string_arithmatic.groovy
index 522636aef46..6963e2363d5 100644
---
a/regression-test/suites/query_p0/expression/fold_constant/fold_constant_string_arithmatic.groovy
+++
b/regression-test/suites/query_p0/expression/fold_constant/fold_constant_string_arithmatic.groovy
@@ -155,6 +155,15 @@ suite("fold_constant_string_arithmatic") {
testFoldConst("select field('=', '+', '=', '=', 'こ')")
testFoldConst("select field('==', '+', '=', '==', 'こ')")
testFoldConst("select field('=', '+', '==', '==', 'こ')")
+ testFoldConst("select field(cast('nan' as float), cast('nan' as float)), "
+ + "field(cast('nan' as double), cast('nan' as double))")
+ testFoldConst("select field(cast(0.0 as float), cast(-0.0 as float)), "
+ + "field(cast(-0.0 as float), cast(0.0 as float)), "
+ + "field(cast(0.0 as double), cast(-0.0 as double)), "
+ + "field(cast(-0.0 as double), cast(0.0 as double))")
+
+ // cast decimalv3 to string
+ testFoldConst("select cast(cast('1E+3' as decimalv3(10, 2)) as string)")
// find_in_set
testFoldConst("select find_in_set('a', null)")
@@ -2048,4 +2057,3 @@ suite("fold_constant_string_arithmatic") {
testFoldConst("SELECT IS_UUID('6ccd780cbaba102')")
testFoldConst("SELECT IS_UUID(NULL)")
}
-
diff --git
a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
index e6780eb888c..a523b16656c 100644
---
a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
+++
b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
@@ -496,6 +496,7 @@ suite("test_date_function") {
check_fold_consistency("str_to_date('2026-01-28 11:32:47.1234567',
'%Y-%m-%d %T.%f')")
check_fold_consistency("str_to_date('2026-01-28 11:32:47.123456789',
'%Y-%m-%d %T.%f')")
check_fold_consistency("str_to_date('2026-01-28 11:32:47', '%Y-%m-%d %T')")
+ testFoldConst("select str_to_date('2024-01-01', concat('%Y-%m', '-%d'))")
sql """ truncate table ${tableName} """
sql """ insert into ${tableName} values ("2020-09-01") """
qt_sql """ select str_to_date(test_datetime, "%Y-%m-%d %H:%i:%s") from
${tableName};"""
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]