This is an automated email from the ASF dual-hosted git repository.
huajianlan pushed a commit to branch branch-3.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.0 by this push:
new 48ea74b050a [enhancement](Nereids) boost characterLiteralTypeCoercion
(#42941) (#43094)
48ea74b050a is described below
commit 48ea74b050a52c6bd1f900577a9e3107d66e3a64
Author: 924060929 <[email protected]>
AuthorDate: Mon Nov 4 11:53:23 2024 +0800
[enhancement](Nereids) boost characterLiteralTypeCoercion (#42941) (#43094)
Boost characterLiteralTypeCoercion by check the string format and skip
throw Throwable when can not parse string to integer/float/date/datetime.
This logical usually appear when search `If` function signature, because
the If has lots of signature, we need cast argument to the signature type to
matches the best signature, for example:
```
select if(column_1, 'xxx', 'yyy')
```
we will check whether the 'xxx' and 'yyy' can be parsed to int/datetime and
so on.
In some scenarios, this optimize can provide 16% QPS
before: optimize:
<img width="1901" alt="image"
src="https://github.com/user-attachments/assets/b03d2d29-5d3b-45a6-ba54-2bcc7c2dccca">
<img width="1484" alt="image"
src="https://github.com/user-attachments/assets/82cbb2b0-dfe8-4a05-bc2f-ebb35dc23209">
after optimize:
<img width="1724" alt="image"
src="https://github.com/user-attachments/assets/d60a867d-596d-4ac1-9377-6460ed6d3dd1">
<img width="1722" alt="image"
src="https://github.com/user-attachments/assets/c9c9f72c-3a5f-4c24-95d9-9ca99ecab0a6">
---
.../expressions/functions/SearchSignature.java | 9 +-
.../trees/expressions/literal/DateLiteral.java | 73 ++-
.../trees/expressions/literal/DateTimeLiteral.java | 75 +++-
.../expressions/literal/DateTimeV2Literal.java | 2 +-
.../expressions/literal/DecimalV3Literal.java | 13 +-
.../nereids/trees/expressions/literal/Result.java | 66 +++
.../expressions/literal/format/AndChecker.java | 45 ++
.../expressions/literal/format/AtLeastChecker.java | 49 ++
.../expressions/literal/format/CharChecker.java | 36 ++
.../expressions/literal/format/CheckResult.java | 49 ++
.../literal/format/CustomCharChecker.java | 39 ++
.../literal/format/DateTimeChecker.java | 137 ++++++
.../expressions/literal/format/DebugChecker.java | 38 ++
.../expressions/literal/format/DigitChecker.java | 45 ++
.../expressions/literal/format/FloatChecker.java | 55 +++
.../expressions/literal/format/FormatChecker.java | 170 +++++++
.../expressions/literal/format/IntegerChecker.java | 43 ++
.../expressions/literal/format/LetterChecker.java | 45 ++
.../expressions/literal/format/OptionChecker.java | 36 ++
.../expressions/literal/format/OrChecker.java | 55 +++
.../expressions/literal/format/StringChecker.java | 44 ++
.../expressions/literal/format/StringInspect.java | 64 +++
.../apache/doris/nereids/types/DecimalV3Type.java | 25 +-
.../doris/nereids/util/TypeCoercionUtils.java | 54 ++-
.../trees/expressions/literal/DateLiteralTest.java | 16 +-
.../expressions/literal/DateTimeLiteralTest.java | 496 +++++++++++----------
.../expressions/literal/FloatLiteralTest.java | 80 ++++
.../expressions/literal/IntegerLiteralTest.java | 64 +++
28 files changed, 1604 insertions(+), 319 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/SearchSignature.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/SearchSignature.java
index 4d6bb658356..5fa426a99a2 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/SearchSignature.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/SearchSignature.java
@@ -207,13 +207,14 @@ public class SearchSignature {
int arity = arguments.size();
for (int i = 0; i < arity; i++) {
DataType sigArgType = sig.getArgType(i);
- DataType realType = arguments.get(i).getDataType();
+ Expression argument = arguments.get(i);
+ DataType realType = argument.getDataType();
// we need to try to do string literal coercion when search
signature.
// for example, FUNC_A has two signature FUNC_A(datetime) and
FUNC_A(string)
// if SQL block is `FUNC_A('2020-02-02 00:00:00')`, we should
return signature FUNC_A(datetime).
- if (arguments.get(i).isLiteral() && realType.isStringLikeType()) {
- realType =
TypeCoercionUtils.characterLiteralTypeCoercion(((Literal)
arguments.get(i)).getStringValue(),
- sigArgType).orElse(arguments.get(i)).getDataType();
+ if (!argument.isNullLiteral() && argument.isLiteral() &&
realType.isStringLikeType()) {
+ realType =
TypeCoercionUtils.characterLiteralTypeCoercion(((Literal)
argument).getStringValue(),
+ sigArgType).orElse(argument).getDataType();
}
if (!typePredicate.apply(sigArgType, realType)) {
return false;
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 efef246d4e8..6ea1d2af725 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
@@ -44,6 +44,10 @@ import java.util.function.UnaryOperator;
public class DateLiteral extends Literal {
public static final String JAVA_DATE_FORMAT = "yyyy-MM-dd";
+ public static final Set<Character> punctuations = ImmutableSet.of('!',
'@', '#', '$', '%', '^', '&', '*', '(', ')',
+ '-', '+', '=', '_', '{', '}', '[', ']', '|', '\\', ':', ';', '"',
'\'', '<', '>', ',', '.', '?', '/', '~',
+ '`');
+
// for cast datetime type to date type.
private static final LocalDateTime START_OF_A_DAY = LocalDateTime.of(0, 1,
1, 0, 0, 0);
private static final LocalDateTime END_OF_A_DAY = LocalDateTime.of(9999,
12, 31, 23, 59, 59, 999999000);
@@ -51,10 +55,6 @@ public class DateLiteral extends Literal {
private static final DateLiteral MAX_DATE = new DateLiteral(9999, 12, 31);
private static final int[] DAYS_IN_MONTH = new int[] {0, 31, 28, 31, 30,
31, 30, 31, 31, 30, 31, 30, 31};
- private static final Set<Character> punctuations = ImmutableSet.of('!',
'@', '#', '$', '%', '^', '&', '*', '(', ')',
- '-', '+', '=', '_', '{', '}', '[', ']', '|', '\\', ':', ';', '"',
'\'', '<', '>', ',', '.', '?', '/', '~',
- '`');
-
protected long year;
protected long month;
protected long day;
@@ -145,7 +145,7 @@ public class DateLiteral extends Literal {
return punctuations.contains(c);
}
- static String normalize(String s) {
+ static Result<String, AnalysisException> normalize(String s) {
// merge consecutive space
if (s.contains(" ")) {
s = s.replaceAll(" +", " ");
@@ -208,7 +208,10 @@ public class DateLiteral extends Literal {
sb.append('0').append(c);
}
} else {
- throw new AnalysisException("date/datetime literal [" + s
+ "] is invalid");
+ final String currentString = s;
+ return Result.err(
+ () -> new AnalysisException("date/datetime literal
[" + currentString + "] is invalid")
+ );
}
i = j;
partNumber += 1;
@@ -228,7 +231,10 @@ public class DateLiteral extends Literal {
} else if (partNumber > 3 && isPunctuation(c)) {
sb.append(':');
} else {
- throw new AnalysisException("date/datetime literal [" + s
+ "] is invalid");
+ final String currentString = s;
+ return Result.err(
+ () -> new AnalysisException("date/datetime literal
[" + currentString + "] is invalid")
+ );
}
} else {
break;
@@ -259,15 +265,33 @@ public class DateLiteral extends Literal {
// trim use to remove any blank before zone id or zone offset
sb.append(s.substring(i).trim());
- return sb.toString();
+ return Result.ok(sb.toString());
}
- protected static TemporalAccessor parse(String s) {
+ /** parseDateLiteral */
+ public static Result<DateLiteral, AnalysisException>
parseDateLiteral(String s) {
+ Result<TemporalAccessor, AnalysisException> parseResult =
parseDateTime(s);
+ if (parseResult.isError()) {
+ return parseResult.cast();
+ }
+ TemporalAccessor dateTime = parseResult.get();
+ int year = DateUtils.getOrDefault(dateTime, ChronoField.YEAR);
+ int month = DateUtils.getOrDefault(dateTime,
ChronoField.MONTH_OF_YEAR);
+ int day = DateUtils.getOrDefault(dateTime, ChronoField.DAY_OF_MONTH);
+
+ if (checkDatetime(dateTime) || checkRange(year, month, day) ||
checkDate(year, month, day)) {
+ return Result.err(() -> new AnalysisException("date/datetime
literal [" + s + "] is out of range"));
+ }
+ return Result.ok(new DateLiteral(year, month, day));
+ }
+
+ /** parseDateTime */
+ public static Result<TemporalAccessor, AnalysisException>
parseDateTime(String s) {
// fast parse '2022-01-01'
if (s.length() == 10 && s.charAt(4) == '-' && s.charAt(7) == '-') {
TemporalAccessor date = fastParseDate(s);
if (date != null) {
- return date;
+ return Result.ok(date);
}
}
@@ -289,15 +313,20 @@ public class DateLiteral extends Literal {
if (!containsPunctuation) {
s = normalizeBasic(s);
// mysql reject "20200219 010101" "200219 010101", can't use '
' spilt basic date time.
+
if (!s.contains("T")) {
dateTime =
DateTimeFormatterUtils.BASIC_FORMATTER_WITHOUT_T.parse(s);
} else {
dateTime =
DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER.parse(s);
}
- return dateTime;
+ return Result.ok(dateTime);
}
- s = normalize(s);
+ Result<String, AnalysisException> normalizeResult = normalize(s);
+ if (normalizeResult.isError()) {
+ return normalizeResult.cast();
+ }
+ s = normalizeResult.get();
if (!s.contains(" ")) {
dateTime = DateTimeFormatterUtils.ZONE_DATE_FORMATTER.parse(s);
@@ -307,32 +336,34 @@ public class DateLiteral extends Literal {
// if Year is not present, throw exception
if (!dateTime.isSupported(ChronoField.YEAR)) {
- throw new AnalysisException("date/datetime literal [" +
originalString + "] is invalid");
+ return Result.err(
+ () -> new AnalysisException("date/datetime literal ["
+ originalString + "] is invalid")
+ );
}
- return dateTime;
+ return Result.ok(dateTime);
} catch (Exception ex) {
- throw new AnalysisException("date/datetime literal [" +
originalString + "] is invalid");
+ return Result.err(() -> new AnalysisException("date/datetime
literal [" + originalString + "] is invalid"));
}
}
protected void init(String s) throws AnalysisException {
- TemporalAccessor dateTime = parse(s);
+ TemporalAccessor dateTime = parseDateTime(s).get();
year = DateUtils.getOrDefault(dateTime, ChronoField.YEAR);
month = DateUtils.getOrDefault(dateTime, ChronoField.MONTH_OF_YEAR);
day = DateUtils.getOrDefault(dateTime, ChronoField.DAY_OF_MONTH);
- if (checkDatetime(dateTime) || checkRange() || checkDate()) {
+ if (checkDatetime(dateTime) || checkRange(year, month, day) ||
checkDate(year, month, day)) {
throw new AnalysisException("date/datetime literal [" + s + "] is
out of range");
}
}
- protected boolean checkRange() {
+ protected static boolean checkRange(long year, long month, long day) {
return year > MAX_DATE.getYear() || month > MAX_DATE.getMonth() || day
> MAX_DATE.getDay();
}
- protected boolean checkDate() {
- if (month != 0 && day > DAYS_IN_MONTH[((int) month)]) {
+ protected static boolean checkDate(long year, long month, long day) {
+ if (month != 0 && day > DAYS_IN_MONTH[(int) month]) {
if (month == 2 && day == 29 && (Year.isLeap(year) && year > 0)) {
return false;
}
@@ -345,7 +376,7 @@ public class DateLiteral extends Literal {
return dateTime == null || dateTime.isBefore(START_OF_A_DAY) ||
dateTime.isAfter(END_OF_A_DAY);
}
- private boolean checkDatetime(TemporalAccessor dateTime) {
+ private static boolean checkDatetime(TemporalAccessor dateTime) {
return DateUtils.getOrDefault(dateTime, ChronoField.HOUR_OF_DAY) != 0
|| DateUtils.getOrDefault(dateTime,
ChronoField.MINUTE_OF_HOUR) != 0
|| DateUtils.getOrDefault(dateTime,
ChronoField.SECOND_OF_MINUTE) != 0
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 726c39c8bb9..27470187eae 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
@@ -23,6 +23,7 @@ import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeType;
+import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.coercion.DateLikeType;
import org.apache.doris.nereids.util.DateUtils;
@@ -108,7 +109,7 @@ public class DateTimeLiteral extends DateLiteral {
if (s.indexOf("-") == s.lastIndexOf("-") && s.indexOf(":") ==
s.lastIndexOf(":")) {
return 0;
}
- s = normalize(s);
+ s = normalize(s).get();
if (s.length() <= 19 || s.charAt(19) != '.') {
return 0;
}
@@ -130,10 +131,73 @@ public class DateTimeLiteral extends DateLiteral {
return scale;
}
- @Override
+ /** parseDateTimeLiteral */
+ public static Result<DateTimeLiteral, AnalysisException>
parseDateTimeLiteral(String s, boolean isV2) {
+ Result<TemporalAccessor, AnalysisException> parseResult =
parseDateTime(s);
+ if (parseResult.isError()) {
+ return parseResult.cast();
+ }
+
+ TemporalAccessor temporal = parseResult.get();
+ long year = DateUtils.getOrDefault(temporal, ChronoField.YEAR);
+ long month = DateUtils.getOrDefault(temporal,
ChronoField.MONTH_OF_YEAR);
+ long day = DateUtils.getOrDefault(temporal, ChronoField.DAY_OF_MONTH);
+ long hour = DateUtils.getOrDefault(temporal, ChronoField.HOUR_OF_DAY);
+ long minute = DateUtils.getOrDefault(temporal,
ChronoField.MINUTE_OF_HOUR);
+ long second = DateUtils.getOrDefault(temporal,
ChronoField.SECOND_OF_MINUTE);
+
+ ZoneId zoneId = temporal.query(TemporalQueries.zone());
+ if (zoneId != null) {
+ // get correct DST of that time.
+ Instant thatTime = ZonedDateTime
+ .of((int) year, (int) month, (int) day, (int) hour, (int)
minute, (int) second, 0, zoneId)
+ .toInstant();
+
+ int offset =
DateUtils.getTimeZone().getRules().getOffset(thatTime).getTotalSeconds()
+ - zoneId.getRules().getOffset(thatTime).getTotalSeconds();
+ if (offset != 0) {
+ DateTimeLiteral tempLiteral = new DateTimeLiteral(year, month,
day, hour, minute, second);
+ DateTimeLiteral result = (DateTimeLiteral)
tempLiteral.plusSeconds(offset);
+ second = result.second;
+ minute = result.minute;
+ hour = result.hour;
+ day = result.day;
+ month = result.month;
+ year = result.year;
+ }
+ }
+
+ long microSecond = DateUtils.getOrDefault(temporal,
ChronoField.NANO_OF_SECOND) / 100L;
+ // Microseconds have 7 digits.
+ long sevenDigit = microSecond % 10;
+ microSecond = microSecond / 10;
+ if (sevenDigit >= 5 && isV2) {
+ DateTimeV2Literal tempLiteral = new DateTimeV2Literal(year, month,
day, hour, minute, second, microSecond);
+ DateTimeV2Literal result = (DateTimeV2Literal)
tempLiteral.plusMicroSeconds(1);
+ second = result.second;
+ minute = result.minute;
+ hour = result.hour;
+ day = result.day;
+ month = result.month;
+ year = result.year;
+ microSecond = result.microSecond;
+ }
+
+ if (checkRange(year, month, day) || checkDate(year, month, day)) {
+ return Result.err(() -> new AnalysisException("datetime literal ["
+ s + "] is out of range"));
+ }
+
+ if (isV2) {
+ DateTimeV2Type type = DateTimeV2Type.forTypeFromString(s);
+ return Result.ok(new DateTimeV2Literal(type, year, month, day,
hour, minute, second, microSecond));
+ } else {
+ return Result.ok(new DateTimeLiteral(DateTimeType.INSTANCE, year,
month, day, hour, minute, second));
+ }
+ }
+
protected void init(String s) throws AnalysisException {
// TODO: check and do fast parse like fastParseDate
- TemporalAccessor temporal = parse(s);
+ TemporalAccessor temporal = parseDateTime(s).get();
year = DateUtils.getOrDefault(temporal, ChronoField.YEAR);
month = DateUtils.getOrDefault(temporal, ChronoField.MONTH_OF_YEAR);
@@ -177,14 +241,13 @@ public class DateTimeLiteral extends DateLiteral {
this.microSecond = result.microSecond;
}
- if (checkRange() || checkDate()) {
+ if (checkRange(year, month, day) || checkDate(year, month, day)) {
throw new AnalysisException("datetime literal [" + s + "] is out
of range");
}
}
- @Override
protected boolean checkRange() {
- return super.checkRange() || hour > MAX_DATETIME.getHour() || minute >
MAX_DATETIME.getMinute()
+ return checkRange(year, month, day) || hour > MAX_DATETIME.getHour()
|| minute > MAX_DATETIME.getMinute()
|| second > MAX_DATETIME.getSecond() || microSecond >
MAX_MICROSECOND;
}
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 0ca19bf2a92..c6ec4b99d4f 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
@@ -77,7 +77,7 @@ public class DateTimeV2Literal extends DateTimeLiteral {
this.second = localDateTime.getSecond();
this.microSecond -= 1000000;
}
- if (checkRange() || checkDate()) {
+ if (checkRange() || checkDate(year, month, day)) {
// may fallback to legacy planner. make sure the behaviour of
rounding is same.
throw new AnalysisException("datetime literal [" + toString() + "]
is out of range");
}
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 1ff2e50169c..d8be4faf0c9 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
@@ -44,11 +44,16 @@ public class DecimalV3Literal extends FractionalLiteral {
* Constructor for DecimalV3Literal
*/
public DecimalV3Literal(DecimalV3Type dataType, BigDecimal value) {
-
super(DecimalV3Type.createDecimalV3TypeLooseCheck(dataType.getPrecision(),
dataType.getScale()));
+ super(DecimalV3Type.createDecimalV3TypeLooseCheck(
+ dataType.getPrecision() == -1 ? value.precision() :
dataType.getPrecision(),
+ dataType.getScale() == -1 ? value.scale() :
dataType.getScale())
+ );
+
+ int precision = dataType.getPrecision() == -1 ? value.precision() :
dataType.getPrecision();
+ int scale = dataType.getScale() == -1 ? value.scale() :
dataType.getScale();
Objects.requireNonNull(value, "value not be null");
- checkPrecisionAndScale(dataType.getPrecision(), dataType.getScale(),
value);
- BigDecimal adjustedValue = value.scale() < 0 ? value
- : value.setScale(dataType.getScale(), RoundingMode.HALF_UP);
+ checkPrecisionAndScale(precision, scale, value);
+ BigDecimal adjustedValue = value.scale() < 0 ? value :
value.setScale(scale, RoundingMode.HALF_UP);
this.value = Objects.requireNonNull(adjustedValue);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Result.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Result.java
new file mode 100644
index 00000000000..aa5040abcf4
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Result.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.literal;
+
+import java.util.Optional;
+import java.util.function.Supplier;
+
+/** Result */
+public class Result<R, T extends RuntimeException> {
+ private final Optional<R> result;
+ private final Optional<Supplier<T>> exceptionSupplier;
+
+ private Result(Optional<R> result, Optional<Supplier<T>>
exceptionSupplier) {
+ this.result = result;
+ this.exceptionSupplier = exceptionSupplier;
+ }
+
+ public static <R, T extends RuntimeException> Result<R, T> ok(R result) {
+ return new Result<>(Optional.of(result), Optional.empty());
+ }
+
+ public static <R, T extends RuntimeException> Result<R, T> err(Supplier<T>
exceptionSupplier) {
+ return new Result<>(Optional.empty(), Optional.of(exceptionSupplier));
+ }
+
+ public boolean isOk() {
+ return !exceptionSupplier.isPresent();
+ }
+
+ public boolean isError() {
+ return exceptionSupplier.isPresent();
+ }
+
+ public <R, T extends RuntimeException> Result<R, T> cast() {
+ return (Result<R, T>) this;
+ }
+
+ public R get() {
+ if (exceptionSupplier.isPresent()) {
+ throw exceptionSupplier.get().get();
+ }
+ return result.get();
+ }
+
+ public R orElse(R other) {
+ if (exceptionSupplier.isPresent()) {
+ return other;
+ }
+ return result.get();
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/AndChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/AndChecker.java
new file mode 100644
index 00000000000..377d8b2202b
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/AndChecker.java
@@ -0,0 +1,45 @@
+// 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.literal.format;
+
+import org.apache.doris.nereids.util.Utils;
+
+import java.util.List;
+import java.util.Objects;
+
+/** AndChecker */
+public class AndChecker extends FormatChecker {
+ private final List<FormatChecker> checkers;
+
+ public AndChecker(String name, List<FormatChecker> checkers) {
+ super(name);
+ this.checkers = Utils.fastToImmutableList(
+ Objects.requireNonNull(checkers, "checkers can not be null")
+ );
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ for (FormatChecker checker : checkers) {
+ if (!checker.check(stringInspect).matched) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/AtLeastChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/AtLeastChecker.java
new file mode 100644
index 00000000000..f69c942d966
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/AtLeastChecker.java
@@ -0,0 +1,49 @@
+// 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.literal.format;
+
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/** AtLeastChecker */
+public class AtLeastChecker extends FormatChecker {
+ private final int minCount;
+ private final int maxRead;
+ private final Predicate<Character> checker;
+
+ public AtLeastChecker(String name, int minCount, int maxRead,
Predicate<Character> checker) {
+ super(name);
+ this.minCount = minCount;
+ this.maxRead = maxRead;
+ this.checker = Objects.requireNonNull(checker, "checker can not be
null");
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ int count = 0;
+ boolean checkRead = maxRead >= 0;
+ while (!stringInspect.eos() && (!checkRead || count < maxRead)) {
+ if (!checker.test(stringInspect.lookAt())) {
+ break;
+ }
+ stringInspect.step();
+ count++;
+ }
+ return count >= minCount;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CharChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CharChecker.java
new file mode 100644
index 00000000000..14934bcb846
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CharChecker.java
@@ -0,0 +1,36 @@
+// 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.literal.format;
+
+/** CharChecker */
+public class CharChecker extends FormatChecker {
+ public final char c;
+
+ public CharChecker(String name, char c) {
+ super(name);
+ this.c = c;
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ if (stringInspect.eos() || stringInspect.lookAndStep() != c) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CheckResult.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CheckResult.java
new file mode 100644
index 00000000000..b604a3516ab
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CheckResult.java
@@ -0,0 +1,49 @@
+// 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.literal.format;
+
+/** CheckResult */
+public class CheckResult {
+ public final FormatChecker checker;
+ public final StringInspect stringInspect;
+ public final boolean matched;
+ public final int checkStartIndex;
+ public final int checkEndIndex;
+
+ public CheckResult(
+ FormatChecker checker, StringInspect stringInspect,
+ boolean matched, int checkStartIndex, int checkEndIndex) {
+ this.checker = checker;
+ this.stringInspect = stringInspect;
+ this.matched = matched;
+ this.checkStartIndex = checkStartIndex;
+ this.checkEndIndex = checkEndIndex;
+ }
+
+ public int matchesLength() {
+ return checkEndIndex - checkStartIndex;
+ }
+
+ public String matchesContent() {
+ return stringInspect.str.substring(checkStartIndex, checkEndIndex);
+ }
+
+ public void stepBack() {
+ stringInspect.setIndex(checkStartIndex);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CustomCharChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CustomCharChecker.java
new file mode 100644
index 00000000000..0718202bf03
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CustomCharChecker.java
@@ -0,0 +1,39 @@
+// 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.literal.format;
+
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/** CustomCharChecker */
+public class CustomCharChecker extends FormatChecker {
+ private final Predicate<Character> checker;
+
+ public CustomCharChecker(String name, Predicate<Character> checker) {
+ super(name);
+ this.checker = Objects.requireNonNull(checker, "checker can not be
null");
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ if (stringInspect.eos() || !checker.test(stringInspect.lookAndStep()))
{
+ return false;
+ }
+ return true;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DateTimeChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DateTimeChecker.java
new file mode 100644
index 00000000000..7d60a01c041
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DateTimeChecker.java
@@ -0,0 +1,137 @@
+// 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.literal.format;
+
+import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
+
+/** DateTimeChecker */
+public class DateTimeChecker extends FormatChecker {
+ private static final DateTimeChecker INSTANCE = new DateTimeChecker();
+
+ private final FormatChecker checker;
+
+ private DateTimeChecker() {
+ super("DateTimeChecker");
+
+ this.checker =
+ or(
+ // date
+ and("Date",
+ or(
+ // 20241012
+ digit(8, 8),
+ // 2024-10-12
+ and(
+ digit(1, 4), // year
+ chars(DateLiteral.punctuations::contains),
+ digit(1, 2), // month
+ chars(DateLiteral.punctuations::contains),
+ digit(1, 2) // day
+ )
+ )
+ ),
+ // datetime
+ and("DateTime",
+ or("YearToSecond",
+ // 20241012010203
+ and("FullCompactDateTime",
+ digit(8, 8),
+ atLeast(0, c -> c == 'T'),
+ digit(6, 6)
+ ),
+
+ // 241012010203 or 241012T010203
+ and("ShortCompactDateTime",
+ digit(6, 6),
+ atLeast(0, c -> c == 'T'),
+ digit(6, 6)
+ ),
+
+ // 2024-01-01 01:02:03
+ and("NormalDateTime",
+ digit(1, 4), // year
+ chars(DateLiteral.punctuations::contains),
+ digit(1, 2), // month
+ chars(DateLiteral.punctuations::contains),
+ digit(1, 2), // day
+ atLeast(1, c -> c == 'T' || c == ' ' ||
DateLiteral.punctuations.contains(c)),
+ digit(1, 2), // hour
+ option(
+ and(
+
chars(DateLiteral.punctuations::contains),
+ digit(1, 2), // minute
+ option(
+ and(
+
chars(DateLiteral.punctuations::contains),
+ digit(1, 2) // second
+ )
+ )
+ )
+ )
+ )
+ ),
+ option("NanoSecond", nanoSecond()),
+ option("TimeZone", timeZone())
+ )
+ );
+ }
+
+ public static boolean isValidDateTime(String str) {
+ str = str.trim();
+ StringInspect stringInspect = new StringInspect(str.trim());
+ return INSTANCE.check(stringInspect).matched && stringInspect.eos();
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ return checker.check(stringInspect).matched;
+ }
+
+ private FormatChecker nanoSecond() {
+ return and(
+ ch('.'),
+ digit(1)
+ );
+ }
+
+ private FormatChecker timeZone() {
+ // Z or +08:00 or UTC-01:00
+ return and(
+ // timezone: Europe/London, America/New_York
+ atLeast(0, c -> ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
|| c == '/' || c == '_'),
+ option(
+ and(
+ chars(c -> c == '+' || c == '-'),
+ digit(1, 2),
+ option(
+ and(
+ ch(':'),
+ digit(1, 2),
+ option(
+ and(
+ ch(':'),
+ digit(1, 2)
+ )
+ )
+ )
+ )
+ )
+ )
+ );
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DebugChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DebugChecker.java
new file mode 100644
index 00000000000..6569b914d5e
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DebugChecker.java
@@ -0,0 +1,38 @@
+// 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.literal.format;
+
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/** DebugChecker */
+public class DebugChecker<T extends FormatChecker> extends FormatChecker {
+ private final T childChecker;
+ private final Predicate<T> debugPoint;
+
+ public DebugChecker(String name, T childChecker, Predicate<T> debugPoint) {
+ super(name);
+ this.childChecker = Objects.requireNonNull(childChecker, "childChecker
can not be null");
+ this.debugPoint = Objects.requireNonNull(debugPoint, "debugPoint can
not be null");
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ return debugPoint.test(childChecker);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DigitChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DigitChecker.java
new file mode 100644
index 00000000000..fe1cb26fda4
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DigitChecker.java
@@ -0,0 +1,45 @@
+// 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.literal.format;
+
+/** DigitChecker */
+public class DigitChecker extends FormatChecker {
+ private final int minCount;
+ private final int maxRead;
+
+ public DigitChecker(String name, int minCount, int maxRead) {
+ super(name);
+ this.minCount = minCount;
+ this.maxRead = maxRead;
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ int numberCount = 0;
+ boolean checkRead = maxRead >= 0;
+ while (!stringInspect.eos() && (!checkRead || numberCount < maxRead)) {
+ char c = stringInspect.lookAt();
+ if (!('0' <= c && c <= '9')) {
+ break;
+ }
+ stringInspect.step();
+ numberCount++;
+ }
+ return numberCount >= minCount;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/FloatChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/FloatChecker.java
new file mode 100644
index 00000000000..9b438f45324
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/FloatChecker.java
@@ -0,0 +1,55 @@
+// 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.literal.format;
+
+/** FloatChecker */
+public class FloatChecker extends FormatChecker {
+ private static final FloatChecker INSTANCE = new FloatChecker();
+ private final FormatChecker checker;
+
+ private FloatChecker() {
+ super("FloatChecker");
+ checker = and(
+ option(chars(c -> c == '+' || c == '-')),
+ or(
+ // 123 or 123.456
+ and(digit(1), option(and(ch('.'), digit(0)))),
+ // .123
+ and(ch('.'), digit(1))
+ ),
+ option(
+ // E+10 or E-10 or E10
+ and(
+ chars(c -> c == 'e' || c == 'E'),
+ option(chars(c -> c == '+' || c == '-')),
+ digit(1)
+ )
+ )
+ );
+ }
+
+ public static boolean isValidFloat(String str) {
+ StringInspect stringInspect = new StringInspect(str.trim());
+ return INSTANCE.check(stringInspect).matched && stringInspect.eos();
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ return checker.check(stringInspect).matched;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/FormatChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/FormatChecker.java
new file mode 100644
index 00000000000..fc6d2acc993
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/FormatChecker.java
@@ -0,0 +1,170 @@
+// 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.literal.format;
+
+import org.apache.doris.nereids.util.Utils;
+
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/**
+ * FormatChecker
+ *
+ * This class is used to check whether the string satisfy the underscore
format(like DSL), without throw Exception.
+ * For example, to check whether the string can be converted to integer, you
can use below format, it can
+ * check "1", "-123", and "-143". More complex example is DateTimeChecker
+ *
+ * <pre>
+ * FormatChecker checker = and(
+ * option(chars(c -> c == '+' || c == '-')),
+ * digit(1)
+ * );
+ *
+ * checker.check(new StringInspector("+12345"))
+ * </pre>
+ */
+public abstract class FormatChecker {
+ public final String name;
+
+ public FormatChecker(String name) {
+ this.name = Objects.requireNonNull(name, "name can not be null");
+ }
+
+ protected abstract boolean doCheck(StringInspect stringInspect);
+
+ /** check */
+ public final CheckResult check(StringInspect stringInspect) {
+ int checkStartIndex = stringInspect.index();
+ boolean matches = doCheck(stringInspect);
+ int checkEndIndex = stringInspect.index();
+ CheckResult checkResult = new CheckResult(this, stringInspect,
matches, checkStartIndex, checkEndIndex);
+ if (!matches) {
+ checkResult.stepBack();
+ }
+ return checkResult;
+ }
+
+ protected <T extends FormatChecker> DebugChecker<T> debug(T childChecker,
Predicate<T> debugPoint) {
+ return debug("DebugChecker", childChecker, debugPoint);
+ }
+
+ protected <T extends FormatChecker> DebugChecker<T> debug(String name, T
childChecker, Predicate<T> debugPoint) {
+ return new DebugChecker<>(name, childChecker, debugPoint);
+ }
+
+ protected OptionChecker option(FormatChecker checker) {
+ return option("OptionChecker", checker);
+ }
+
+ protected OptionChecker option(String name, FormatChecker checker) {
+ return new OptionChecker(name, checker);
+ }
+
+ protected AndChecker and(FormatChecker... checkers) {
+ return and("AndChecker", checkers);
+ }
+
+ protected AndChecker and(String name, FormatChecker... checkers) {
+ return new AndChecker(name, Utils.fastToImmutableList(checkers));
+ }
+
+ protected OrChecker or(FormatChecker... checkers) {
+ return or("OrChecker", checkers);
+ }
+
+ protected OrChecker or(String name, FormatChecker... checkers) {
+ return new OrChecker(name, Utils.fastToImmutableList(checkers));
+ }
+
+ protected AtLeastChecker atLeast(int minCount, Predicate<Character>
checker) {
+ return atLeast("AtLeastChecker", minCount, -1, checker);
+ }
+
+ protected AtLeastChecker atLeast(String name, int minCount,
Predicate<Character> checker) {
+ return new AtLeastChecker(name, minCount, -1, checker);
+ }
+
+ protected AtLeastChecker atLeast(int minCount, int maxRead,
Predicate<Character> checker) {
+ return atLeast("AtLeastChecker", minCount, maxRead, checker);
+ }
+
+ protected AtLeastChecker atLeast(String name, int minCount, int maxRead,
Predicate<Character> checker) {
+ return new AtLeastChecker(name, minCount, maxRead, checker);
+ }
+
+ protected DigitChecker digit(int minCount) {
+ return digit("DigitChecker", minCount, -1);
+ }
+
+ protected DigitChecker digit(String name, int minCount) {
+ return new DigitChecker(name, minCount, -1);
+ }
+
+ protected DigitChecker digit(int minCount, int maxRead) {
+ return digit("DigitChecker", minCount, maxRead);
+ }
+
+ protected DigitChecker digit(String name, int minCount, int maxRead) {
+ return new DigitChecker(name, minCount, maxRead);
+ }
+
+ protected LetterChecker letter(int minCount) {
+ return letter("LetterChecker", minCount, -1);
+ }
+
+ protected LetterChecker letter(String name, int minCount) {
+ return new LetterChecker(name, minCount, -1);
+ }
+
+ protected LetterChecker letter(int minCount, int maxRead) {
+ return letter("LetterChecker", minCount, maxRead);
+ }
+
+ protected LetterChecker letter(String name, int minCount, int maxRead) {
+ return new LetterChecker(name, minCount, maxRead);
+ }
+
+ protected CharChecker ch(char c) {
+ return ch("CharChecker", c);
+ }
+
+ protected CharChecker ch(String name, char c) {
+ return new CharChecker(name, c);
+ }
+
+ protected CustomCharChecker chars(Predicate<Character> checker) {
+ return chars("CustomCharChecker", checker);
+ }
+
+ protected CustomCharChecker chars(String name, Predicate<Character>
checker) {
+ return new CustomCharChecker(name, checker);
+ }
+
+ protected StringChecker string(String equalsTo) {
+ return string("StringChecker", equalsTo);
+ }
+
+ protected StringChecker string(String name, String equalsTo) {
+ return new StringChecker(name, equalsTo);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/IntegerChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/IntegerChecker.java
new file mode 100644
index 00000000000..54efc875705
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/IntegerChecker.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.literal.format;
+
+/** IntegerChecker */
+public class IntegerChecker extends FormatChecker {
+ private static final IntegerChecker INSTANCE = new IntegerChecker();
+
+ private final FormatChecker checker;
+
+ private IntegerChecker() {
+ super("IntegerChecker");
+ checker = and(
+ option(chars(c -> c == '+' || c == '-')),
+ digit(1)
+ );
+ }
+
+ public static boolean isValidInteger(String string) {
+ StringInspect stringInspect = new StringInspect(string);
+ return INSTANCE.check(stringInspect).matched && stringInspect.eos();
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ return checker.check(stringInspect).matched;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/LetterChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/LetterChecker.java
new file mode 100644
index 00000000000..d4ba3131608
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/LetterChecker.java
@@ -0,0 +1,45 @@
+// 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.literal.format;
+
+/** LetterChecker */
+public class LetterChecker extends FormatChecker {
+ private final int minCount;
+ private final int maxRead;
+
+ public LetterChecker(String name, int minCount, int maxRead) {
+ super(name);
+ this.minCount = minCount;
+ this.maxRead = maxRead;
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ int numberCount = 0;
+ boolean checkRead = maxRead >= 0;
+ while (!stringInspect.eos() && (!checkRead || numberCount < maxRead)) {
+ char c = stringInspect.lookAt();
+ if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) {
+ break;
+ }
+ stringInspect.step();
+ numberCount++;
+ }
+ return numberCount >= minCount;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/OptionChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/OptionChecker.java
new file mode 100644
index 00000000000..0946c95fefc
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/OptionChecker.java
@@ -0,0 +1,36 @@
+// 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.literal.format;
+
+import java.util.Objects;
+
+/** OptionChecker */
+public class OptionChecker extends FormatChecker {
+ private final FormatChecker checker;
+
+ public OptionChecker(String name, FormatChecker checker) {
+ super(name);
+ this.checker = Objects.requireNonNull(checker, "checker can not be
null");
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ checker.check(stringInspect);
+ return true;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/OrChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/OrChecker.java
new file mode 100644
index 00000000000..dbf109d8193
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/OrChecker.java
@@ -0,0 +1,55 @@
+// 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.literal.format;
+
+import org.apache.doris.nereids.util.Utils;
+
+import java.util.List;
+import java.util.Objects;
+
+/** OrChecker */
+public class OrChecker extends FormatChecker {
+ private final List<FormatChecker> checkers;
+
+ public OrChecker(String name, List<FormatChecker> checkers) {
+ super(name);
+ this.checkers = Utils.fastToImmutableList(
+ Objects.requireNonNull(checkers, "checkers can not be null")
+ );
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ int maxMatches = -1;
+ CheckResult maxMatchesResult = null;
+ for (FormatChecker checker : checkers) {
+ CheckResult checkResult = checker.check(stringInspect);
+ if (checkResult.matched && checkResult.matchesLength() >
maxMatches) {
+ maxMatches = checkResult.matchesLength();
+ maxMatchesResult = checkResult;
+ }
+ checkResult.stepBack();
+ }
+ if (maxMatches >= 0) {
+ stringInspect.setIndex(maxMatchesResult.checkEndIndex);
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/StringChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/StringChecker.java
new file mode 100644
index 00000000000..e1bf9e0f9b5
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/StringChecker.java
@@ -0,0 +1,44 @@
+// 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.literal.format;
+
+import java.util.Objects;
+
+/** StringChecker */
+public class StringChecker extends FormatChecker {
+ private final String str;
+
+ public StringChecker(String name, String str) {
+ super(name);
+ this.str = Objects.requireNonNull(str, "str can not be null");
+ }
+
+ @Override
+ protected boolean doCheck(StringInspect stringInspect) {
+ if (stringInspect.remain() < str.length()) {
+ return false;
+ }
+
+ for (int i = 0; i < str.length(); i++) {
+ if (stringInspect.lookAndStep() != str.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/StringInspect.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/StringInspect.java
new file mode 100644
index 00000000000..fab366b6078
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/StringInspect.java
@@ -0,0 +1,64 @@
+// 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.literal.format;
+
+import java.util.Objects;
+
+/**
+ * StringInspect, a simple lexer can save and move the index
+ */
+public class StringInspect {
+ public final String str;
+ private int index;
+
+ public StringInspect(String str) {
+ this.str = Objects.requireNonNull(str, "str cannot be null");
+ }
+
+ public boolean eos() {
+ return index >= str.length();
+ }
+
+ public int remain() {
+ return str.length() - index;
+ }
+
+ public char lookAt() {
+ return str.charAt(index);
+ }
+
+ public void step() {
+ this.index++;
+ }
+
+ public void step(int step) {
+ this.index += step;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public char lookAndStep() {
+ return str.charAt(index++);
+ }
+
+ public int index() {
+ return index;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DecimalV3Type.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DecimalV3Type.java
index aaef3775b34..3dd2ae35c3e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DecimalV3Type.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DecimalV3Type.java
@@ -20,6 +20,7 @@ package org.apache.doris.nereids.types;
import org.apache.doris.catalog.ScalarType;
import org.apache.doris.catalog.Type;
import org.apache.doris.nereids.annotation.Developing;
+import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.exceptions.NotSupportedException;
import org.apache.doris.nereids.types.coercion.FractionalType;
import org.apache.doris.qe.ConnectContext;
@@ -136,15 +137,25 @@ public class DecimalV3Type extends FractionalType {
enableDecimal256 =
connectContext.getSessionVariable().isEnableDecimal256();
}
if (enableDecimal256) {
- Preconditions.checkArgument(precision > 0 && precision <=
MAX_DECIMAL256_PRECISION,
- "precision should in (0, " + MAX_DECIMAL256_PRECISION +
"], but real precision is " + precision);
+ if (!(precision > 0 && precision <= MAX_DECIMAL256_PRECISION)) {
+ throw new AnalysisException(
+ "precision should in (0, " + MAX_DECIMAL256_PRECISION
+ "], but real precision is " + precision
+ );
+ }
} else {
- Preconditions.checkArgument(precision > 0 && precision <=
MAX_DECIMAL128_PRECISION,
- "precision should in (0, " + MAX_DECIMAL128_PRECISION +
"], but real precision is " + precision);
+ if (!(precision > 0 && precision <= MAX_DECIMAL128_PRECISION)) {
+ throw new AnalysisException(
+ "precision should in (0, " + MAX_DECIMAL128_PRECISION
+ "], but real precision is " + precision
+ );
+ }
+ }
+ if (scale < 0) {
+ throw new AnalysisException("scale should not smaller than 0, but
real scale is " + scale);
+ }
+ if (precision < scale) {
+ throw new AnalysisException("precision should not smaller than
scale,"
+ + " but precision is " + precision + ", scale is " +
scale);
}
- Preconditions.checkArgument(scale >= 0, "scale should not smaller than
0, but real scale is " + scale);
- Preconditions.checkArgument(precision >= scale, "precision should not
smaller than scale,"
- + " but precision is " + precision, ", scale is " + scale);
return new DecimalV3Type(precision, scale);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
index ca9d79fbc01..d7f9fc83baf 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
@@ -65,11 +65,15 @@ import
org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.literal.MapLiteral;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.Result;
import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
+import
org.apache.doris.nereids.trees.expressions.literal.format.DateTimeChecker;
+import org.apache.doris.nereids.trees.expressions.literal.format.FloatChecker;
+import
org.apache.doris.nereids.trees.expressions.literal.format.IntegerChecker;
import org.apache.doris.nereids.types.ArrayType;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.BooleanType;
@@ -534,7 +538,7 @@ public class TypeCoercionUtils {
if ("false".equalsIgnoreCase(value)) {
ret = BooleanLiteral.FALSE;
}
- } else if (dataType instanceof TinyIntType) {
+ } else if (dataType instanceof TinyIntType &&
IntegerChecker.isValidInteger(value)) {
BigInteger bigInt = new BigInteger(value);
if (BigInteger.valueOf(bigInt.byteValue()).equals(bigInt)) {
ret = new TinyIntLiteral(bigInt.byteValue());
@@ -547,7 +551,7 @@ public class TypeCoercionUtils {
} else {
ret = new LargeIntLiteral(bigInt);
}
- } else if (dataType instanceof SmallIntType) {
+ } else if (dataType instanceof SmallIntType &&
IntegerChecker.isValidInteger(value)) {
BigInteger bigInt = new BigInteger(value);
if (BigInteger.valueOf(bigInt.shortValue()).equals(bigInt)) {
ret = new SmallIntLiteral(bigInt.shortValue());
@@ -558,7 +562,7 @@ public class TypeCoercionUtils {
} else {
ret = new LargeIntLiteral(bigInt);
}
- } else if (dataType instanceof IntegerType) {
+ } else if (dataType instanceof IntegerType &&
IntegerChecker.isValidInteger(value)) {
BigInteger bigInt = new BigInteger(value);
if (BigInteger.valueOf(bigInt.intValue()).equals(bigInt)) {
ret = new IntegerLiteral(bigInt.intValue());
@@ -567,23 +571,23 @@ public class TypeCoercionUtils {
} else {
ret = new LargeIntLiteral(bigInt);
}
- } else if (dataType instanceof BigIntType) {
+ } else if (dataType instanceof BigIntType &&
IntegerChecker.isValidInteger(value)) {
BigInteger bigInt = new BigInteger(value);
if (BigInteger.valueOf(bigInt.longValue()).equals(bigInt)) {
ret = new BigIntLiteral(bigInt.longValueExact());
} else {
ret = new LargeIntLiteral(bigInt);
}
- } else if (dataType instanceof LargeIntType) {
+ } else if (dataType instanceof LargeIntType &&
IntegerChecker.isValidInteger(value)) {
BigInteger bigInt = new BigInteger(value);
ret = new LargeIntLiteral(bigInt);
- } else if (dataType instanceof FloatType) {
+ } else if (dataType instanceof FloatType &&
FloatChecker.isValidFloat(value)) {
ret = new FloatLiteral(Float.parseFloat(value));
- } else if (dataType instanceof DoubleType) {
+ } else if (dataType instanceof DoubleType &&
FloatChecker.isValidFloat(value)) {
ret = new DoubleLiteral(Double.parseDouble(value));
- } else if (dataType instanceof DecimalV2Type) {
+ } else if (dataType instanceof DecimalV2Type &&
FloatChecker.isValidFloat(value)) {
ret = new DecimalLiteral(new BigDecimal(value));
- } else if (dataType instanceof DecimalV3Type) {
+ } else if (dataType instanceof DecimalV3Type &&
FloatChecker.isValidFloat(value)) {
ret = new DecimalV3Literal((DecimalV3Type) dataType, new
BigDecimal(value));
} else if (dataType instanceof CharType) {
ret = new VarcharLiteral(value, ((CharType)
dataType).getLen());
@@ -591,22 +595,24 @@ public class TypeCoercionUtils {
ret = new VarcharLiteral(value, ((VarcharType)
dataType).getLen());
} else if (dataType instanceof StringType) {
ret = new StringLiteral(value);
- } else if (dataType.isDateTimeV2Type()) {
- ret = new DateTimeV2Literal(value);
- } else if (dataType.isDateTimeType()) {
- ret = new DateTimeLiteral(value);
- } else if (dataType.isDateV2Type()) {
- try {
- ret = new DateV2Literal(value);
- } catch (AnalysisException e) {
- ret = new DateTimeV2Literal(value);
- }
- } else if (dataType.isDateType()) {
- try {
- ret = new DateLiteral(value);
- } catch (AnalysisException e) {
- ret = new DateTimeLiteral(value);
+ } else if (dataType.isDateTimeV2Type() &&
DateTimeChecker.isValidDateTime(value)) {
+ ret = DateTimeLiteral.parseDateTimeLiteral(value,
true).orElse(null);
+ } else if (dataType.isDateTimeType() &&
DateTimeChecker.isValidDateTime(value)) {
+ ret = DateTimeLiteral.parseDateTimeLiteral(value,
false).orElse(null);
+ } else if (dataType.isDateV2Type() &&
DateTimeChecker.isValidDateTime(value)) {
+ Result<DateLiteral, AnalysisException> parseResult
+ = DateV2Literal.parseDateLiteral(value);
+ if (parseResult.isOk()) {
+ ret = parseResult.get();
+ } else {
+ Result<DateTimeLiteral, AnalysisException> parseResult2
+ = DateTimeV2Literal.parseDateTimeLiteral(value,
true);
+ if (parseResult2.isOk()) {
+ ret = parseResult2.get();
+ }
}
+ } else if (dataType.isDateType() &&
DateTimeChecker.isValidDateTime(value)) {
+ ret = DateLiteral.parseDateLiteral(value).orElse(null);
}
} catch (Exception e) {
if (LOG.isDebugEnabled()) {
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 7c8ad5ed0e6..8db1c9446d0 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
@@ -36,22 +36,22 @@ class DateLiteralTest {
@Test
void testNormalize() {
- String s = DateLiteral.normalize("2021-5");
+ String s = DateLiteral.normalize("2021-5").get();
Assertions.assertEquals("2021-05", s);
- s = DateLiteral.normalize("2021-5-1");
+ s = DateLiteral.normalize("2021-5-1").get();
Assertions.assertEquals("2021-05-01", s);
- s = DateLiteral.normalize("2021-5-01");
+ s = DateLiteral.normalize("2021-5-01").get();
Assertions.assertEquals("2021-05-01", s);
- s = DateLiteral.normalize("2021-5-01 0:0:0");
+ s = DateLiteral.normalize("2021-5-01 0:0:0").get();
Assertions.assertEquals("2021-05-01 00:00:00", s);
- s = DateLiteral.normalize("2021-5-01 0:0:0.001");
+ s = DateLiteral.normalize("2021-5-01 0:0:0.001").get();
Assertions.assertEquals("2021-05-01 00:00:00.001", s);
- s = DateLiteral.normalize("2021-5-01 0:0:0.12345678");
+ s = DateLiteral.normalize("2021-5-01 0:0:0.12345678").get();
Assertions.assertEquals("2021-05-01 00:00:00.1234567", s);
- s = DateLiteral.normalize("2021-5-1 Asia/Shanghai");
+ s = DateLiteral.normalize("2021-5-1 Asia/Shanghai").get();
Assertions.assertEquals("2021-05-01Asia/Shanghai", s);
- s = DateLiteral.normalize("2021-5-1 0:0:0.12345678 Asia/Shanghai");
+ s = DateLiteral.normalize("2021-5-1 0:0:0.12345678
Asia/Shanghai").get();
Assertions.assertEquals("2021-05-01 00:00:00.1234567Asia/Shanghai", s);
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
index 914246f08b6..50cf9d024ea 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.trees.expressions.literal;
+import
org.apache.doris.nereids.trees.expressions.literal.format.DateTimeChecker;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.junit.jupiter.api.Assertions;
@@ -24,20 +25,22 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.function.Consumer;
+import java.util.function.Function;
class DateTimeLiteralTest {
@Test
void reject() {
// Assertions.assertThrows(IllegalArgumentException.class, () -> {
- // new DateTimeV2Literal("2022-08-01T01:01:01-00:00");
+ // check("", DateTimeV2Literal::new"2022-08-01T01:01:01-00:00");
// });
}
@Test
void mysqlStrangeCase() {
- new DateTimeV2Literal("0-08-01 13:21:03");
- new DateTimeV2Literal("0001-01-01: 00:01:01.001");
- new DateTimeV2Literal("2021?01?01 00.00.00");
+ check("0-08-01 13:21:03", DateTimeV2Literal::new);
+ check("0-08-01 13:21:03", DateTimeV2Literal::new);
+ check("0001-01-01: 00:01:01.001", DateTimeV2Literal::new);
+ check("2021?01?01 00.00.00", DateTimeV2Literal::new);
}
@Test
@@ -51,43 +54,43 @@ class DateTimeLiteralTest {
Assertions.assertEquals(2, datetime.second);
};
- assertFunc.accept(new DateTimeV2Literal("20220801010102"));
- assertFunc.accept(new DateTimeV2Literal("20220801T010102"));
- assertFunc.accept(new DateTimeV2Literal("220801010102"));
- assertFunc.accept(new DateTimeV2Literal("220801T010102"));
- assertFunc.accept(new DateTimeV2Literal("20220801010101.9999999"));
+ assertFunc.accept(check("20220801010102", DateTimeV2Literal::new));
+ assertFunc.accept(check("20220801T010102", DateTimeV2Literal::new));
+ assertFunc.accept(check("220801010102", DateTimeV2Literal::new));
+ assertFunc.accept(check("220801T010102", DateTimeV2Literal::new));
+ assertFunc.accept(check("20220801010101.9999999",
DateTimeV2Literal::new));
}
@Test
void testMicrosecond() {
DateTimeV2Literal literal;
- literal = new DateTimeV2Literal("2016-07-02 00:00:00.123");
+ literal = check("2016-07-02 00:00:00.123", DateTimeV2Literal::new);
Assertions.assertEquals(123000, literal.microSecond);
- literal = new DateTimeV2Literal("2016-07-02 00:00:00.123456");
+ literal = check("2016-07-02 00:00:00.123456", DateTimeV2Literal::new);
Assertions.assertEquals(123456, literal.microSecond);
- literal = new DateTimeV2Literal("2016-07-02 00:00:00.1");
+ literal = check("2016-07-02 00:00:00.1", DateTimeV2Literal::new);
Assertions.assertEquals(100000, literal.microSecond);
- literal = new DateTimeV2Literal("2016-07-02 00:00:00.000001");
+ literal = check("2016-07-02 00:00:00.000001", DateTimeV2Literal::new);
Assertions.assertEquals(1, literal.microSecond);
- literal = new DateTimeV2Literal("2016-07-02 00:00:00.12345");
+ literal = check("2016-07-02 00:00:00.12345", DateTimeV2Literal::new);
Assertions.assertEquals(123450, literal.microSecond);
}
@Test
void testWithoutZoneOrOffset() {
- new DateTimeV2Literal("2022-08-01");
+ check("2022-08-01", DateTimeV2Literal::new);
- new DateTimeV2Literal("2022-08-01 01:01:01");
- new DateTimeV2Literal("2022-08-01 01:01");
- new DateTimeV2Literal("2022-08-01 01");
+ check("2022-08-01 01:01:01", DateTimeV2Literal::new);
+ check("2022-08-01 01:01", DateTimeV2Literal::new);
+ check("2022-08-01 01", DateTimeV2Literal::new);
- new DateTimeV2Literal("2022-08-01T01:01:01");
- new DateTimeV2Literal("2022-08-01T01:01");
- new DateTimeV2Literal("2022-08-01T01");
+ check("2022-08-01T01:01:01", DateTimeV2Literal::new);
+ check("2022-08-01T01:01", DateTimeV2Literal::new);
+ check("2022-08-01T01", DateTimeV2Literal::new);
- new DateTimeV2Literal("22-08-01T01:01:01");
- new DateTimeV2Literal("22-08-01T01:01");
- new DateTimeV2Literal("22-08-01T01");
+ check("22-08-01T01:01:01", DateTimeV2Literal::new);
+ check("22-08-01T01:01", DateTimeV2Literal::new);
+ check("22-08-01T01", DateTimeV2Literal::new);
}
@Test
@@ -112,102 +115,102 @@ class DateTimeLiteralTest {
@Test
void testTwoDigitYear() {
- new DateTimeV2Literal("22-08-01T01");
- new DateTimeV2Literal("22-08-01 01");
- new DateTimeV2Literal("22-08-01T01:01");
- new DateTimeV2Literal("22-08-01 01:01");
- new DateTimeV2Literal("22-08-01T01:01:01");
- new DateTimeV2Literal("22-08-01 01:01:01");
- new DateTimeV2Literal("22-08-01T01");
- new DateTimeV2Literal("22-08-01 01");
- new DateTimeV2Literal("22-08-01T01:01");
- new DateTimeV2Literal("22-08-01 01:01");
- new DateTimeV2Literal("22-08-01T01:01:01");
- new DateTimeV2Literal("22-08-01 01:01:01");
+ check("22-08-01T01", DateTimeV2Literal::new);
+ check("22-08-01 01", DateTimeV2Literal::new);
+ check("22-08-01T01:01", DateTimeV2Literal::new);
+ check("22-08-01 01:01", DateTimeV2Literal::new);
+ check("22-08-01T01:01:01", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01", DateTimeV2Literal::new);
+ check("22-08-01T01", DateTimeV2Literal::new);
+ check("22-08-01 01", DateTimeV2Literal::new);
+ check("22-08-01T01:01", DateTimeV2Literal::new);
+ check("22-08-01 01:01", DateTimeV2Literal::new);
+ check("22-08-01T01:01:01", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01", DateTimeV2Literal::new);
}
@Test
void testZone() {
- new DateTimeV2Literal("2022-08-01 01:01:01UTC");
- new DateTimeV2Literal("2022-08-01 01:01:01UT");
- new DateTimeV2Literal("2022-08-01 01:01:01GMT");
- new DateTimeV2Literal("2022-08-01 01:01:01Z");
- new DateTimeV2Literal("2022-08-01 01:01:01Europe/London");
- new DateTimeV2Literal("2022-08-01 01:01:01America/New_York");
- new DateTimeV2Literal("2022-08-01 01:01:01Z");
- new DateTimeV2Literal("2022-08-01 01:01:01Europe/Berlin");
- new DateTimeV2Literal("2022-08-01 01:01:01Europe/London");
- new DateTimeV2Literal("2022-08-01 00:00:00Asia/Shanghai");
+ check("2022-08-01 01:01:01UTC", DateTimeV2Literal::new);
+ check("2022-08-01 01:01:01UT", DateTimeV2Literal::new);
+ check("2022-08-01 01:01:01GMT", DateTimeV2Literal::new);
+ check("2022-08-01 01:01:01Z", DateTimeV2Literal::new);
+ check("2022-08-01 01:01:01Europe/London", DateTimeV2Literal::new);
+ check("2022-08-01 01:01:01America/New_York", DateTimeV2Literal::new);
+ check("2022-08-01 01:01:01Z", DateTimeV2Literal::new);
+ check("2022-08-01 01:01:01Europe/Berlin", DateTimeV2Literal::new);
+ check("2022-08-01 01:01:01Europe/London", DateTimeV2Literal::new);
+ check("2022-08-01 00:00:00Asia/Shanghai", DateTimeV2Literal::new);
}
@Test
void testTwoDigitalYearZone() {
- new DateTimeV2Literal("22-08-01 01:01:01UTC");
- new DateTimeV2Literal("22-08-01 01:01:01UT");
- new DateTimeV2Literal("22-08-01 01:01:01GMT");
- new DateTimeV2Literal("22-08-01 01:01:01Z");
- new DateTimeV2Literal("22-08-01 01:01:01Europe/London");
- new DateTimeV2Literal("22-08-01 01:01:01UTC");
- new DateTimeV2Literal("22-08-01 01:01:01America/New_York");
- new DateTimeV2Literal("22-08-01 01:01:01Z");
- new DateTimeV2Literal("22-08-01 01:01:01Europe/Berlin");
- new DateTimeV2Literal("22-08-01 01:01:01Europe/London");
+ check("22-08-01 01:01:01UTC", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01UT", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01GMT", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01Z", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01Europe/London", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01UTC", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01America/New_York", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01Z", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01Europe/Berlin", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01Europe/London", DateTimeV2Literal::new);
}
@Test
@Disabled
void testTwoDigitalYearZoneOffset() {
- new DateTimeV2Literal("22-08-01 01:01:01UTC+01:01:01");
- new DateTimeV2Literal("22-08-01 01:01:01UTC+1:1:1");
+ check("22-08-01 01:01:01UTC+01:01:01", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01UTC+1:1:1", DateTimeV2Literal::new);
- new DateTimeV2Literal("22-08-01 01:01:01UTC+01:01");
+ check("22-08-01 01:01:01UTC+01:01", DateTimeV2Literal::new);
- new DateTimeV2Literal("22-08-01 01:01:01UTC+01");
- new DateTimeV2Literal("22-08-01 01:01:01UTC+1");
+ check("22-08-01 01:01:01UTC+01", DateTimeV2Literal::new);
+ check("22-08-01 01:01:01UTC+1", DateTimeV2Literal::new);
}
@Test
void testOffset() {
- new DateTimeV2Literal("2022-05-01 01:02:55+02:30");
- new DateTimeV2Literal("2022-05-01 01:02:55.123-02:30");
- new DateTimeV2Literal("2022-06-01T01:02:55+04:30");
- new DateTimeV2Literal("2022-06-01 01:02:55.123-07:30");
- new DateTimeV2Literal("2022-05-01 01:02:55+02:30");
-
- new DateTimeV2Literal("2022-05-01 01:02:55.123-02:30");
- new DateTimeV2Literal("2022-06-01T01:02:55+04:30");
- new DateTimeV2Literal("2022-06-01 01:02:55.123-07:30");
-
- new DateTimeV2Literal("20220701010255+07:00");
- new DateTimeV2Literal("20220701010255-05:00");
+ check("2022-05-01 01:02:55+02:30", DateTimeV2Literal::new);
+ check("2022-05-01 01:02:55.123-02:30", DateTimeV2Literal::new);
+ check("2022-06-01T01:02:55+04:30", DateTimeV2Literal::new);
+ check("2022-06-01 01:02:55.123-07:30", DateTimeV2Literal::new);
+ check("2022-05-01 01:02:55+02:30", DateTimeV2Literal::new);
+
+ check("2022-05-01 01:02:55.123-02:30", DateTimeV2Literal::new);
+ check("2022-06-01T01:02:55+04:30", DateTimeV2Literal::new);
+ check("2022-06-01 01:02:55.123-07:30", DateTimeV2Literal::new);
+
+ check("20220701010255+07:00", DateTimeV2Literal::new);
+ check("20220701010255-05:00", DateTimeV2Literal::new);
}
@Test
@Disabled
void testDateTimeZone() {
- new DateTimeV2Literal("0001-01-01 00:01:01");
- new DateTimeV2Literal("0001-01-01 00:01:01.001");
- new DateTimeV2Literal("0001-01-01 00:01:01.00305");
-
- new DateTimeV2Literal("2022-01-01 01:02:55");
- new DateTimeV2Literal("2022-01-01 01:02:55.123");
- new DateTimeV2Literal("2022-02-01 01:02:55Z");
- new DateTimeV2Literal("2022-02-01 01:02:55.123Z");
- new DateTimeV2Literal("2022-03-01 01:02:55UTC+8");
- new DateTimeV2Literal("2022-03-01 01:02:55.123UTC");
- new DateTimeV2Literal("2022-04-01 01:02:55UTC-6");
- new DateTimeV2Literal("2022-04-01T01:02:55UTC-6");
- new DateTimeV2Literal("2022-04-01T01:02:55.123UTC+6");
-
- new DateTimeV2Literal("2022-01-01 01:02:55");
- new DateTimeV2Literal("2022-01-01 01:02:55.123");
- new DateTimeV2Literal("2022-02-01 01:02:55Z");
- new DateTimeV2Literal("2022-02-01 01:02:55.123Z");
- new DateTimeV2Literal("2022-03-01 01:02:55UTC+8");
- new DateTimeV2Literal("2022-03-01 01:02:55.123UTC");
- new DateTimeV2Literal("2022-04-01T01:02:55UTC-6");
-
- new DateTimeV2Literal("0001-01-01");
+ check("0001-01-01 00:01:01", DateTimeV2Literal::new);
+ check("0001-01-01 00:01:01.001", DateTimeV2Literal::new);
+ check("0001-01-01 00:01:01.00305", DateTimeV2Literal::new);
+
+ check("2022-01-01 01:02:55", DateTimeV2Literal::new);
+ check("2022-01-01 01:02:55.123", DateTimeV2Literal::new);
+ check("2022-02-01 01:02:55Z", DateTimeV2Literal::new);
+ check("2022-02-01 01:02:55.123Z", DateTimeV2Literal::new);
+ check("2022-03-01 01:02:55UTC+8", DateTimeV2Literal::new);
+ check("2022-03-01 01:02:55.123UTC", DateTimeV2Literal::new);
+ check("2022-04-01 01:02:55UTC-6", DateTimeV2Literal::new);
+ check("2022-04-01T01:02:55UTC-6", DateTimeV2Literal::new);
+ check("2022-04-01T01:02:55.123UTC+6", DateTimeV2Literal::new);
+
+ check("2022-01-01 01:02:55", DateTimeV2Literal::new);
+ check("2022-01-01 01:02:55.123", DateTimeV2Literal::new);
+ check("2022-02-01 01:02:55Z", DateTimeV2Literal::new);
+ check("2022-02-01 01:02:55.123Z", DateTimeV2Literal::new);
+ check("2022-03-01 01:02:55UTC+8", DateTimeV2Literal::new);
+ check("2022-03-01 01:02:55.123UTC", DateTimeV2Literal::new);
+ check("2022-04-01T01:02:55UTC-6", DateTimeV2Literal::new);
+
+ check("0001-01-01", DateTimeV2Literal::new);
}
@Test
@@ -221,191 +224,191 @@ class DateTimeLiteralTest {
Assertions.assertEquals(0, datetime.second);
};
DateTimeV2Literal literal;
- literal = new DateTimeV2Literal("2022-01-02 12:00:00UTC+08:00");
+ literal = check("2022-01-02 12:00:00UTC+08:00",
DateTimeV2Literal::new);
assertFunc.accept(literal);
- literal = new DateTimeV2Literal("2022-01-02 04:00:00UTC");
+ literal = check("2022-01-02 04:00:00UTC", DateTimeV2Literal::new);
assertFunc.accept(literal);
- literal = new DateTimeV2Literal("2022-01-01 20:00:00UTC-08:00");
+ literal = check("2022-01-01 20:00:00UTC-08:00",
DateTimeV2Literal::new);
assertFunc.accept(literal);
- literal = new DateTimeV2Literal("2022-01-02 04:00:00Z");
+ literal = check("2022-01-02 04:00:00Z", DateTimeV2Literal::new);
assertFunc.accept(literal);
}
@Test
void testIrregularDateTime() {
- new DateTimeV2Literal("2016-7-02 01:01:00");
- new DateTimeV2Literal("2016-07-2 01:01:00");
- new DateTimeV2Literal("2016-7-2 01:01:00");
-
- new DateTimeV2Literal("2016-07-02 1:01:00");
- new DateTimeV2Literal("2016-07-02 01:1:00");
- new DateTimeV2Literal("2016-07-02 01:01:0");
- new DateTimeV2Literal("2016-07-02 1:1:00");
- new DateTimeV2Literal("2016-07-02 1:01:0");
- new DateTimeV2Literal("2016-07-02 10:1:0");
- new DateTimeV2Literal("2016-07-02 1:1:0");
-
- new DateTimeV2Literal("2016-7-2 1:1:0");
- new DateTimeV2Literal("2016-7-02 1:01:0");
- new DateTimeV2Literal("2016-07-2 1:1:0");
- new DateTimeV2Literal("2016-7-02 01:01:0");
- new DateTimeV2Literal("2016-7-2 01:1:0");
+ check("2016-7-02 01:01:00", DateTimeV2Literal::new);
+ check("2016-07-2 01:01:00", DateTimeV2Literal::new);
+ check("2016-7-2 01:01:00", DateTimeV2Literal::new);
+
+ check("2016-07-02 1:01:00", DateTimeV2Literal::new);
+ check("2016-07-02 01:1:00", DateTimeV2Literal::new);
+ check("2016-07-02 01:01:0", DateTimeV2Literal::new);
+ check("2016-07-02 1:1:00", DateTimeV2Literal::new);
+ check("2016-07-02 1:01:0", DateTimeV2Literal::new);
+ check("2016-07-02 10:1:0", DateTimeV2Literal::new);
+ check("2016-07-02 1:1:0", DateTimeV2Literal::new);
+
+ check("2016-7-2 1:1:0", DateTimeV2Literal::new);
+ check("2016-7-02 1:01:0", DateTimeV2Literal::new);
+ check("2016-07-2 1:1:0", DateTimeV2Literal::new);
+ check("2016-7-02 01:01:0", DateTimeV2Literal::new);
+ check("2016-7-2 01:1:0", DateTimeV2Literal::new);
}
@Test
void testIrregularDateTimeHour() {
- new DateTimeV2Literal("2016-07-02 01");
- new DateTimeV2Literal("2016-07-02 1");
+ check("2016-07-02 01", DateTimeV2Literal::new);
+ check("2016-07-02 1", DateTimeV2Literal::new);
- new DateTimeV2Literal("2016-7-02 1");
- new DateTimeV2Literal("2016-7-02 01");
+ check("2016-7-02 1", DateTimeV2Literal::new);
+ check("2016-7-02 01", DateTimeV2Literal::new);
- new DateTimeV2Literal("2016-07-2 1");
- new DateTimeV2Literal("2016-07-2 01");
+ check("2016-07-2 1", DateTimeV2Literal::new);
+ check("2016-07-2 01", DateTimeV2Literal::new);
- new DateTimeV2Literal("2016-7-2 1");
- new DateTimeV2Literal("2016-7-2 01");
+ check("2016-7-2 1", DateTimeV2Literal::new);
+ check("2016-7-2 01", DateTimeV2Literal::new);
}
@Test
void testIrregularDateTimeHourMinute() {
- new DateTimeV2Literal("2016-07-02 01:01");
- new DateTimeV2Literal("2016-07-02 1:01");
- new DateTimeV2Literal("2016-07-02 01:1");
- new DateTimeV2Literal("2016-07-02 1:1");
-
- new DateTimeV2Literal("2016-7-02 01:01");
- new DateTimeV2Literal("2016-7-02 1:01");
- new DateTimeV2Literal("2016-7-02 01:1");
- new DateTimeV2Literal("2016-7-02 1:1");
-
- new DateTimeV2Literal("2016-07-2 01:01");
- new DateTimeV2Literal("2016-07-2 1:01");
- new DateTimeV2Literal("2016-07-2 01:1");
- new DateTimeV2Literal("2016-07-2 1:1");
-
- new DateTimeV2Literal("2016-7-2 01:01");
- new DateTimeV2Literal("2016-7-2 1:01");
- new DateTimeV2Literal("2016-7-2 01:1");
- new DateTimeV2Literal("2016-7-2 1:1");
+ check("2016-07-02 01:01", DateTimeV2Literal::new);
+ check("2016-07-02 1:01", DateTimeV2Literal::new);
+ check("2016-07-02 01:1", DateTimeV2Literal::new);
+ check("2016-07-02 1:1", DateTimeV2Literal::new);
+
+ check("2016-7-02 01:01", DateTimeV2Literal::new);
+ check("2016-7-02 1:01", DateTimeV2Literal::new);
+ check("2016-7-02 01:1", DateTimeV2Literal::new);
+ check("2016-7-02 1:1", DateTimeV2Literal::new);
+
+ check("2016-07-2 01:01", DateTimeV2Literal::new);
+ check("2016-07-2 1:01", DateTimeV2Literal::new);
+ check("2016-07-2 01:1", DateTimeV2Literal::new);
+ check("2016-07-2 1:1", DateTimeV2Literal::new);
+
+ check("2016-7-2 01:01", DateTimeV2Literal::new);
+ check("2016-7-2 1:01", DateTimeV2Literal::new);
+ check("2016-7-2 01:1", DateTimeV2Literal::new);
+ check("2016-7-2 1:1", DateTimeV2Literal::new);
}
@Test
void testIrregularDateTimeHourMinuteSecond() {
- new DateTimeV2Literal("2016-07-02 01:01:01");
- new DateTimeV2Literal("2016-07-02 1:01:01");
- new DateTimeV2Literal("2016-07-02 01:1:01");
- new DateTimeV2Literal("2016-07-02 1:1:01");
- new DateTimeV2Literal("2016-07-02 01:01:1");
- new DateTimeV2Literal("2016-07-02 1:01:1");
- new DateTimeV2Literal("2016-07-02 01:1:1");
- new DateTimeV2Literal("2016-07-02 1:1:1");
-
- new DateTimeV2Literal("2016-7-02 01:01:01");
- new DateTimeV2Literal("2016-7-02 1:01:01");
- new DateTimeV2Literal("2016-7-02 01:1:01");
- new DateTimeV2Literal("2016-7-02 1:1:01");
- new DateTimeV2Literal("2016-7-02 01:01:1");
- new DateTimeV2Literal("2016-7-02 1:01:1");
- new DateTimeV2Literal("2016-7-02 01:1:1");
- new DateTimeV2Literal("2016-7-02 1:1:1");
-
- new DateTimeV2Literal("2016-07-2 01:01:01");
- new DateTimeV2Literal("2016-07-2 1:01:01");
- new DateTimeV2Literal("2016-07-2 01:1:01");
- new DateTimeV2Literal("2016-07-2 1:1:01");
- new DateTimeV2Literal("2016-07-2 01:01:1");
- new DateTimeV2Literal("2016-07-2 1:01:1");
- new DateTimeV2Literal("2016-07-2 01:1:1");
- new DateTimeV2Literal("2016-07-2 1:1:1");
-
- new DateTimeV2Literal("2016-7-2 01:01:01");
- new DateTimeV2Literal("2016-7-2 1:01:01");
- new DateTimeV2Literal("2016-7-2 01:1:01");
- new DateTimeV2Literal("2016-7-2 1:1:01");
- new DateTimeV2Literal("2016-7-2 01:01:1");
- new DateTimeV2Literal("2016-7-2 1:01:1");
- new DateTimeV2Literal("2016-7-2 01:1:1");
- new DateTimeV2Literal("2016-7-2 1:1:1");
+ check("2016-07-02 01:01:01", DateTimeV2Literal::new);
+ check("2016-07-02 1:01:01", DateTimeV2Literal::new);
+ check("2016-07-02 01:1:01", DateTimeV2Literal::new);
+ check("2016-07-02 1:1:01", DateTimeV2Literal::new);
+ check("2016-07-02 01:01:1", DateTimeV2Literal::new);
+ check("2016-07-02 1:01:1", DateTimeV2Literal::new);
+ check("2016-07-02 01:1:1", DateTimeV2Literal::new);
+ check("2016-07-02 1:1:1", DateTimeV2Literal::new);
+
+ check("2016-7-02 01:01:01", DateTimeV2Literal::new);
+ check("2016-7-02 1:01:01", DateTimeV2Literal::new);
+ check("2016-7-02 01:1:01", DateTimeV2Literal::new);
+ check("2016-7-02 1:1:01", DateTimeV2Literal::new);
+ check("2016-7-02 01:01:1", DateTimeV2Literal::new);
+ check("2016-7-02 1:01:1", DateTimeV2Literal::new);
+ check("2016-7-02 01:1:1", DateTimeV2Literal::new);
+ check("2016-7-02 1:1:1", DateTimeV2Literal::new);
+
+ check("2016-07-2 01:01:01", DateTimeV2Literal::new);
+ check("2016-07-2 1:01:01", DateTimeV2Literal::new);
+ check("2016-07-2 01:1:01", DateTimeV2Literal::new);
+ check("2016-07-2 1:1:01", DateTimeV2Literal::new);
+ check("2016-07-2 01:01:1", DateTimeV2Literal::new);
+ check("2016-07-2 1:01:1", DateTimeV2Literal::new);
+ check("2016-07-2 01:1:1", DateTimeV2Literal::new);
+ check("2016-07-2 1:1:1", DateTimeV2Literal::new);
+
+ check("2016-7-2 01:01:01", DateTimeV2Literal::new);
+ check("2016-7-2 1:01:01", DateTimeV2Literal::new);
+ check("2016-7-2 01:1:01", DateTimeV2Literal::new);
+ check("2016-7-2 1:1:01", DateTimeV2Literal::new);
+ check("2016-7-2 01:01:1", DateTimeV2Literal::new);
+ check("2016-7-2 1:01:1", DateTimeV2Literal::new);
+ check("2016-7-2 01:1:1", DateTimeV2Literal::new);
+ check("2016-7-2 1:1:1", DateTimeV2Literal::new);
}
@Test
void testIrregularDateTimeHourMinuteSecondMicrosecond() {
- new DateTimeV2Literal("2016-07-02 01:01:01.1");
- new DateTimeV2Literal("2016-07-02 1:01:01.1");
- new DateTimeV2Literal("2016-07-02 01:1:01.1");
- new DateTimeV2Literal("2016-07-02 1:1:01.1");
- new DateTimeV2Literal("2016-07-02 01:01:1.1");
- new DateTimeV2Literal("2016-07-02 1:01:1.1");
- new DateTimeV2Literal("2016-07-02 01:1:1.1");
- new DateTimeV2Literal("2016-07-02 1:1:1.1");
-
- new DateTimeV2Literal("2016-7-02 01:01:01.1");
- new DateTimeV2Literal("2016-7-02 1:01:01.1");
- new DateTimeV2Literal("2016-7-02 01:1:01.1");
- new DateTimeV2Literal("2016-7-02 1:1:01.1");
- new DateTimeV2Literal("2016-7-02 01:01:1.1");
- new DateTimeV2Literal("2016-7-02 1:01:1.1");
- new DateTimeV2Literal("2016-7-02 01:1:1.1");
- new DateTimeV2Literal("2016-7-02 1:1:1.1");
-
- new DateTimeV2Literal("2016-07-2 01:01:01.1");
- new DateTimeV2Literal("2016-07-2 1:01:01.1");
- new DateTimeV2Literal("2016-07-2 01:1:01.1");
- new DateTimeV2Literal("2016-07-2 1:1:01.1");
- new DateTimeV2Literal("2016-07-2 01:01:1.1");
- new DateTimeV2Literal("2016-07-2 1:01:1.1");
- new DateTimeV2Literal("2016-07-2 01:1:1.1");
- new DateTimeV2Literal("2016-07-2 1:1:1.1");
-
- new DateTimeV2Literal("2016-7-2 01:01:01.1");
- new DateTimeV2Literal("2016-7-2 1:01:01.1");
- new DateTimeV2Literal("2016-7-2 01:1:01.1");
- new DateTimeV2Literal("2016-7-2 1:1:01.1");
- new DateTimeV2Literal("2016-7-2 01:01:1.1");
- new DateTimeV2Literal("2016-7-2 1:01:1.1");
- new DateTimeV2Literal("2016-7-2 01:1:1.1");
- new DateTimeV2Literal("2016-7-2 1:1:1.1");
+ check("2016-07-02 01:01:01.1", DateTimeV2Literal::new);
+ check("2016-07-02 1:01:01.1", DateTimeV2Literal::new);
+ check("2016-07-02 01:1:01.1", DateTimeV2Literal::new);
+ check("2016-07-02 1:1:01.1", DateTimeV2Literal::new);
+ check("2016-07-02 01:01:1.1", DateTimeV2Literal::new);
+ check("2016-07-02 1:01:1.1", DateTimeV2Literal::new);
+ check("2016-07-02 01:1:1.1", DateTimeV2Literal::new);
+ check("2016-07-02 1:1:1.1", DateTimeV2Literal::new);
+
+ check("2016-7-02 01:01:01.1", DateTimeV2Literal::new);
+ check("2016-7-02 1:01:01.1", DateTimeV2Literal::new);
+ check("2016-7-02 01:1:01.1", DateTimeV2Literal::new);
+ check("2016-7-02 1:1:01.1", DateTimeV2Literal::new);
+ check("2016-7-02 01:01:1.1", DateTimeV2Literal::new);
+ check("2016-7-02 1:01:1.1", DateTimeV2Literal::new);
+ check("2016-7-02 01:1:1.1", DateTimeV2Literal::new);
+ check("2016-7-02 1:1:1.1", DateTimeV2Literal::new);
+
+ check("2016-07-2 01:01:01.1", DateTimeV2Literal::new);
+ check("2016-07-2 1:01:01.1", DateTimeV2Literal::new);
+ check("2016-07-2 01:1:01.1", DateTimeV2Literal::new);
+ check("2016-07-2 1:1:01.1", DateTimeV2Literal::new);
+ check("2016-07-2 01:01:1.1", DateTimeV2Literal::new);
+ check("2016-07-2 1:01:1.1", DateTimeV2Literal::new);
+ check("2016-07-2 01:1:1.1", DateTimeV2Literal::new);
+ check("2016-07-2 1:1:1.1", DateTimeV2Literal::new);
+
+ check("2016-7-2 01:01:01.1", DateTimeV2Literal::new);
+ check("2016-7-2 1:01:01.1", DateTimeV2Literal::new);
+ check("2016-7-2 01:1:01.1", DateTimeV2Literal::new);
+ check("2016-7-2 1:1:01.1", DateTimeV2Literal::new);
+ check("2016-7-2 01:01:1.1", DateTimeV2Literal::new);
+ check("2016-7-2 1:01:1.1", DateTimeV2Literal::new);
+ check("2016-7-2 01:1:1.1", DateTimeV2Literal::new);
+ check("2016-7-2 1:1:1.1", DateTimeV2Literal::new);
// Testing with microsecond of length 2
- new DateTimeV2Literal("2016-07-02 01:01:01.12");
- new DateTimeV2Literal("2016-7-02 01:01:01.12");
+ check("2016-07-02 01:01:01.12", DateTimeV2Literal::new);
+ check("2016-7-02 01:01:01.12", DateTimeV2Literal::new);
// Testing with microsecond of length 3
- new DateTimeV2Literal("2016-07-02 01:01:01.123");
- new DateTimeV2Literal("2016-7-02 01:01:01.123");
+ check("2016-07-02 01:01:01.123", DateTimeV2Literal::new);
+ check("2016-7-02 01:01:01.123", DateTimeV2Literal::new);
// Testing with microsecond of length 4
- new DateTimeV2Literal("2016-07-02 01:01:01.1234");
- new DateTimeV2Literal("2016-7-02 01:01:01.1234");
+ check("2016-07-02 01:01:01.1234", DateTimeV2Literal::new);
+ check("2016-7-02 01:01:01.1234", DateTimeV2Literal::new);
// Testing with microsecond of length 5
- new DateTimeV2Literal("2016-07-02 01:01:01.12345");
- new DateTimeV2Literal("2016-7-02 01:01:01.12345");
+ check("2016-07-02 01:01:01.12345", DateTimeV2Literal::new);
+ check("2016-7-02 01:01:01.12345", DateTimeV2Literal::new);
// Testing with microsecond of length 6
- new DateTimeV2Literal("2016-07-02 01:01:01.123456");
- new DateTimeV2Literal("2016-7-02 01:01:01.123456");
+ check("2016-07-02 01:01:01.123456", DateTimeV2Literal::new);
+ check("2016-7-02 01:01:01.123456", DateTimeV2Literal::new);
// Testing with microsecond of length 7
- DateTimeV2Literal literal = new DateTimeV2Literal("2016-07-02
01:01:01.12345678");
+ DateTimeV2Literal literal = check("2016-07-02 01:01:01.12345678",
DateTimeV2Literal::new);
Assertions.assertEquals(123457, literal.microSecond);
- literal = new DateTimeV2Literal("2016-07-02 01:01:01.44444444");
+ literal = check("2016-07-02 01:01:01.44444444",
DateTimeV2Literal::new);
Assertions.assertEquals(444444, literal.microSecond);
- literal = new DateTimeV2Literal("2016-07-02 01:01:01.44444445");
+ literal = check("2016-07-02 01:01:01.44444445",
DateTimeV2Literal::new);
Assertions.assertEquals(444444, literal.microSecond);
- literal = new DateTimeV2Literal("2016-07-02 01:01:01.4444445");
+ literal = check("2016-07-02 01:01:01.4444445", DateTimeV2Literal::new);
Assertions.assertEquals(444445, literal.microSecond);
- literal = new DateTimeV2Literal("2016-07-02 01:01:01.9999995");
+ literal = check("2016-07-02 01:01:01.9999995", DateTimeV2Literal::new);
Assertions.assertEquals(0, literal.microSecond);
Assertions.assertEquals(2, literal.second);
- literal = new DateTimeV2Literal("2021-01-01 23:59:59.9999995");
+ literal = check("2021-01-01 23:59:59.9999995", DateTimeV2Literal::new);
Assertions.assertEquals(0, literal.microSecond);
Assertions.assertEquals(0, literal.second);
Assertions.assertEquals(0, literal.minute);
@@ -415,33 +418,33 @@ class DateTimeLiteralTest {
@Test
void testDateTimeV2Scale() {
Assertions.assertEquals(
- new DateTimeV2Literal(DateTimeV2Type.of(3), "2016-07-02
00:00:00.123"),
- new DateTimeV2Literal(DateTimeV2Type.of(3), "2016-07-02
00:00:00.123"));
+ check("2016-07-02 00:00:00.123", s -> new
DateTimeV2Literal(DateTimeV2Type.of(3), s)),
+ check("2016-07-02 00:00:00.123", s -> new
DateTimeV2Literal(DateTimeV2Type.of(3), s)));
Assertions.assertEquals(
- new DateTimeV2Literal(DateTimeV2Type.of(3), "2016-07-02
00:00:00.123456"),
- new DateTimeV2Literal(DateTimeV2Type.of(3), "2016-07-02
00:00:00.123"));
+ check("2016-07-02 00:00:00.123456", s -> new
DateTimeV2Literal(DateTimeV2Type.of(3), s)),
+ check("2016-07-02 00:00:00.123", s -> new
DateTimeV2Literal(DateTimeV2Type.of(3), s)));
Assertions.assertEquals(
- new DateTimeV2Literal(DateTimeV2Type.of(4), "2016-07-02
00:00:00.12345"),
- new DateTimeV2Literal(DateTimeV2Type.of(4), "2016-07-02
00:00:00.1235"));
+ check("2016-07-02 00:00:00.12345", s -> new
DateTimeV2Literal(DateTimeV2Type.of(4), s)),
+ check("2016-07-02 00:00:00.1235", s -> new
DateTimeV2Literal(DateTimeV2Type.of(4), s)));
Assertions.assertEquals(
- new DateTimeV2Literal(DateTimeV2Type.of(0), "2016-07-02
00:00:00.12345"),
- new DateTimeV2Literal(DateTimeV2Type.of(0), "2016-07-02
00:00:00"));
+ check("2016-07-02 00:00:00.12345", s -> new
DateTimeV2Literal(DateTimeV2Type.of(0), s)),
+ check("2016-07-02 00:00:00", s -> new
DateTimeV2Literal(DateTimeV2Type.of(0), s)));
Assertions.assertEquals(
- new DateTimeV2Literal(DateTimeV2Type.of(0), "2016-07-02
00:00:00.5123"),
- new DateTimeV2Literal(DateTimeV2Type.of(0), "2016-07-02
00:00:01"));
+ check("2016-07-02 00:00:00.5123", s -> new
DateTimeV2Literal(DateTimeV2Type.of(0), s)),
+ check("2016-07-02 00:00:01", s -> new
DateTimeV2Literal(DateTimeV2Type.of(0), s)));
Assertions.assertEquals(
- new DateTimeV2Literal(DateTimeV2Type.of(5), "2016-07-02
00:00:00.999999"),
- new DateTimeV2Literal(DateTimeV2Type.of(5), "2016-07-02
00:00:01.00000"));
+ check("2016-07-02 00:00:00.999999", s -> new
DateTimeV2Literal(DateTimeV2Type.of(5), s)),
+ check("2016-07-02 00:00:01.00000", s -> new
DateTimeV2Literal(DateTimeV2Type.of(5), s)));
// test overflow
Assertions.assertEquals(
- new DateTimeV2Literal(DateTimeV2Type.of(5), "2016-12-31
23:59:59.999999"),
- new DateTimeV2Literal(DateTimeV2Type.of(5), "2017-01-01
00:00:00.00000"));
+ check("2016-12-31 23:59:59.999999", s -> new
DateTimeV2Literal(DateTimeV2Type.of(5), s)),
+ check("2017-01-01 00:00:00.00000", s -> new
DateTimeV2Literal(DateTimeV2Type.of(5), s)));
}
@Test
@@ -500,4 +503,9 @@ class DateTimeLiteralTest {
Assertions.assertEquals(l1, l2);
Assertions.assertNotEquals(l1, l3);
}
+
+ private <L extends DateLiteral> L check(String str, Function<String, L>
literalBuilder) {
+ Assertions.assertTrue(DateTimeChecker.isValidDateTime(str), "Invalid
date: " + str);
+ return literalBuilder.apply(str);
+ }
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/FloatLiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/FloatLiteralTest.java
new file mode 100644
index 00000000000..11561846afe
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/FloatLiteralTest.java
@@ -0,0 +1,80 @@
+// 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.literal;
+
+import org.apache.doris.nereids.trees.expressions.literal.format.FloatChecker;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.util.function.Function;
+
+public class FloatLiteralTest {
+ @Test
+ public void testChecker() {
+ assertValid(
+ "123.45",
+ "-34.56",
+ "0",
+ "0.01",
+ "10000",
+ "+1",
+ "-1",
+ "+1",
+ "1.0",
+ "-1.0",
+ "-1.0e3",
+ ".1",
+ "1.",
+ "1e3"
+ );
+
+ assertInValid(
+ "e3",
+ "abc",
+ "12.34.56",
+ "1,234.56"
+ );
+
+ Assertions.assertThrows(
+ Throwable.class,
+ () -> check("e3", s -> new FloatLiteral(new
BigDecimal(s).floatValue()))
+ );
+ }
+
+ private void assertValid(String...validString) {
+ for (String str : validString) {
+ check(str, s -> new FloatLiteral(new BigDecimal(s).floatValue()));
+ }
+ }
+
+ private void assertInValid(String...validString) {
+ for (String str : validString) {
+ Assertions.assertThrows(
+ Throwable.class,
+ () -> check(str, s -> new FloatLiteral(new
BigDecimal(s).floatValue()))
+ );
+ }
+ }
+
+ private <T extends FractionalLiteral> T check(String str, Function<String,
T> literalBuilder) {
+ Assertions.assertTrue(FloatChecker.isValidFloat(str), "Invalid
fractional: " + str);
+ return literalBuilder.apply(str);
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/IntegerLiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/IntegerLiteralTest.java
new file mode 100644
index 00000000000..9f23d7fd5ff
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/IntegerLiteralTest.java
@@ -0,0 +1,64 @@
+// 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.literal;
+
+import
org.apache.doris.nereids.trees.expressions.literal.format.IntegerChecker;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigInteger;
+import java.util.function.Function;
+
+public class IntegerLiteralTest {
+ @Test
+ public void testChecker() {
+ assertValid(
+ "1",
+ "+1",
+ "-1",
+ "456"
+ );
+
+ assertInValid(
+ "1.0",
+ "1e3",
+ "abc"
+ );
+ }
+
+ private void assertValid(String...validString) {
+ for (String str : validString) {
+ check(str, s -> new IntegerLiteral(new
BigInteger(s).intValueExact()));
+ }
+ }
+
+ private void assertInValid(String...validString) {
+ for (String str : validString) {
+ Assertions.assertThrows(
+ Throwable.class,
+ () -> check(str, s -> new IntegerLiteral(new
BigInteger(s).intValueExact()))
+ );
+ }
+ }
+
+ private <T extends IntegerLikeLiteral> T check(String str,
Function<String, T> literalBuilder) {
+ Assertions.assertTrue(IntegerChecker.isValidInteger(str), "Invalid
integer: " + str);
+ return literalBuilder.apply(str);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]