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 index b13dff956ae3c2..ece43c5d826119 100644 --- 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 @@ -23,15 +23,15 @@ public class AndChecker extends FormatChecker { private final List checkers; - public AndChecker(StringInspect stringInspect, List checkers) { - super(stringInspect); + public AndChecker(String name, List checkers) { + super(name); this.checkers = checkers; } @Override - protected boolean doCheck() { + protected boolean doCheck(StringInspect stringInspect) { for (FormatChecker checker : checkers) { - if (!checker.check()) { + if (!checker.check(stringInspect).matched) { return false; } } 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 index 34fca52d58f7de..0c832d0aa29093 100644 --- 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 @@ -25,21 +25,22 @@ public class AtLeastChecker extends FormatChecker { private int maxRead; private Predicate checker; - public AtLeastChecker(StringInspect stringInspect, int minCount, int maxRead, Predicate checker) { - super(stringInspect); + public AtLeastChecker(String name, int minCount, int maxRead, Predicate checker) { + super(name); this.minCount = minCount; this.maxRead = maxRead; this.checker = checker; } @Override - protected boolean doCheck() { + protected boolean doCheck(StringInspect stringInspect) { int count = 0; boolean checkRead = maxRead >= 0; while (!stringInspect.eos() && (!checkRead || count < maxRead)) { - if (!checker.test(stringInspect.lookAndStep())) { + 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 index 1a3ab542b3e8b5..14934bcb846ef9 100644 --- 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 @@ -21,13 +21,13 @@ public class CharChecker extends FormatChecker { public final char c; - public CharChecker(StringInspect stringInspect, char c) { - super(stringInspect); + public CharChecker(String name, char c) { + super(name); this.c = c; } @Override - protected boolean doCheck() { + protected boolean doCheck(StringInspect stringInspect) { if (stringInspect.eos() || stringInspect.lookAndStep() != c) { return false; } 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 00000000000000..a7b473f0e2bdf1 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/CheckResult.java @@ -0,0 +1,48 @@ +// 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; + +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 index 3d9f116cf8a9d4..814fc243d5f5e9 100644 --- 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 @@ -23,13 +23,13 @@ public class CustomCharChecker extends FormatChecker { private Predicate checker; - public CustomCharChecker(StringInspect stringInspect, Predicate checker) { - super(stringInspect); + public CustomCharChecker(String name, Predicate checker) { + super(name); this.checker = checker; } @Override - protected boolean doCheck() { + protected boolean doCheck(StringInspect stringInspect) { if (stringInspect.eos() || !checker.test(stringInspect.lookAndStep())) { return false; } 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 index b0c1e15b2f11da..61302b276f09dc 100644 --- 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 @@ -21,79 +21,117 @@ /** DateTimeChecker */ public class DateTimeChecker extends FormatChecker { - private DateTimeChecker(StringInspect stringInspect) { - super(stringInspect); - } + private static final DateTimeChecker INSTANCE = new DateTimeChecker(); - public static boolean isValidDateTime(String str) { - str = str.trim(); - return new DateTimeChecker(new StringInspect(str)).check(); - } + private final FormatChecker checker; - @Override - protected boolean doCheck() { - FormatChecker dateFormatChecker = and( + private DateTimeChecker() { + super("DateTimeChecker"); + + this.checker = or( // date - and( + and("Date", or( // 20241012 - number(8, 8), + digit(8, 8), // 2024-10-12 and( - number(4, 4), // year + digit(1, 4), // year chars(DateLiteral.punctuations::contains), - number(2, 2), // month + digit(1, 2), // month chars(DateLiteral.punctuations::contains), - number(2, 2) // day + digit(1, 2) // day ) ), option(ch('Z')) ), // datetime - and( - or( + and("DateTime", + or("YearToSecond", // 20241012010203 - number(14, 14), + 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( - number(4, 4), // year + and("NormalDateTime", + digit(1, 4), // year chars(DateLiteral.punctuations::contains), - number(2, 2), // month + digit(1, 2), // month chars(DateLiteral.punctuations::contains), - number(2, 2), // day + digit(1, 2), // day atLeast(1, c -> c == 'T' || c == ' ' || DateLiteral.punctuations.contains(c)), - number(2, 2), // hour - chars(DateLiteral.punctuations::contains), - number(2, 2), // minute - chars(DateLiteral.punctuations::contains), - number(2, 2) // second + 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()), - option(timeZone()) + option("NanoSecond", nanoSecond()), + option("TimeZone", timeZone()) ) - ) - ); - return dateFormatChecker.check(); + ); + } + + 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('.'), - number(1) + digit(1) ); } private FormatChecker timeZone() { - // Z or +08:00 or -01:00 - return or( - ch('Z'), - and( - chars(c -> c == '+' || c == '-'), - number(2, 2), - ch(':'), - number(2, 2) + // 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 00000000000000..7432a206fca1b9 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DebugChecker.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.function.Predicate; + +public class DebugChecker extends FormatChecker { + private final T childChecker; + private final Predicate debugPoint; + + public DebugChecker(String name, T childChecker, Predicate debugPoint) { + super(name); + this.childChecker = childChecker; + this.debugPoint = debugPoint; + } + + @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/NumberChecker.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DigitChecker.java similarity index 74% rename from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/NumberChecker.java rename to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DigitChecker.java index 19ba2906649bb6..52cce4b55149fc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/NumberChecker.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DigitChecker.java @@ -17,19 +17,19 @@ package org.apache.doris.nereids.trees.expressions.literal.format; -/** NumberChecker */ -public class NumberChecker extends FormatChecker { +/** DigitChecker */ +public class DigitChecker extends FormatChecker { private int minCount; private int maxRead; - public NumberChecker(StringInspect stringInspect, int minCount, int maxRead) { - super(stringInspect); + public DigitChecker(String name, int minCount, int maxRead) { + super(name); this.minCount = minCount; this.maxRead = maxRead; } @Override - protected boolean doCheck() { + protected boolean doCheck(StringInspect stringInspect) { int numberCount = 0; boolean checkRead = maxRead >= 0; while (!stringInspect.eos() && (!checkRead || numberCount < maxRead)) { @@ -42,10 +42,4 @@ protected boolean doCheck() { } return numberCount >= minCount; } - - public static void main(String[] args) { - NumberChecker numberChecker = new NumberChecker(new StringInspect("123"), 1, 3); - System.out.println(numberChecker.check()); - System.out.println(numberChecker.getCheckContent()); - } } 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 index 98d539f7a74548..4676297fc6e3b9 100644 --- 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 @@ -19,40 +19,39 @@ /** FloatChecker */ public class FloatChecker extends FormatChecker { - private FloatChecker(StringInspect stringInspect) { - super(stringInspect); + 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) { - return new FloatChecker(new StringInspect(str.trim())).check(); - } - @Override - protected boolean doCheck() { - FormatChecker floatFormatChecker = and( - option(chars(c -> c == '+' || c == '-')), - or( - // 123 or 123.456 - and(number(1), option(and(ch('.'), number(0)))), - // .123 - and(ch('.'), number(1)) - ), - option( - // E+10 or E-10 or E10 - and( - ch('E'), - option(chars(c -> c == '+' || c == '-')), - number(1) - ) - ) - ); - return floatFormatChecker.check() && stringInspect.eos(); + + StringInspect stringInspect = new StringInspect(str.trim()); + return INSTANCE.check(stringInspect).matched && stringInspect.eos(); } - public static void main(String[] args) { - String str = "1."; - FloatChecker floatChecker = new FloatChecker(new StringInspect(str)); - System.out.println(floatChecker.check()); - System.out.println(floatChecker.getCheckContent()); + @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 index 5ead7815c81bff..2487292f6b3826 100644 --- 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 @@ -23,72 +23,132 @@ /** FormatChecker */ public abstract class FormatChecker { - protected final StringInspect stringInspect; - protected int checkStartIndex; - protected int checkEndIndex; + public final String name; - public FormatChecker(StringInspect stringInspect) { - this.stringInspect = stringInspect; + public FormatChecker(String name) { + this.name = name; } - protected abstract boolean doCheck(); + protected abstract boolean doCheck(StringInspect stringInspect); /** check */ - public final boolean check() { - this.checkStartIndex = stringInspect.index(); - boolean valid = doCheck(); - this.checkEndIndex = stringInspect.index(); - if (!valid) { - stepBack(); + 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 valid; + return checkResult; } - public void stepBack() { - this.stringInspect.setIndex(checkStartIndex); + protected DebugChecker debug(T childChecker, Predicate debugPoint) { + return debug("DebugChecker", childChecker, debugPoint); } - public String getCheckContent() { - return stringInspect.str.substring(checkStartIndex, checkEndIndex); + protected DebugChecker debug(String name, T childChecker, Predicate debugPoint) { + return new DebugChecker<>(name, childChecker, debugPoint); } protected OptionChecker option(FormatChecker checker) { - return new OptionChecker(stringInspect, checker); + return option("OptionChecker", checker); + } + + protected OptionChecker option(String name, FormatChecker checker) { + return new OptionChecker(name, checker); } protected AndChecker and(FormatChecker... checkers) { - return new AndChecker(stringInspect, Utils.fastToImmutableList(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 new OrChecker(stringInspect, Utils.fastToImmutableList(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 checker) { - return new AtLeastChecker(stringInspect, minCount, -1, checker); + return atLeast("AtLeastChecker", minCount, -1, checker); + } + + protected AtLeastChecker atLeast(String name, int minCount, Predicate checker) { + return new AtLeastChecker(name, minCount, -1, checker); } protected AtLeastChecker atLeast(int minCount, int maxRead, Predicate checker) { - return new AtLeastChecker(stringInspect, minCount, maxRead, checker); + return atLeast("AtLeastChecker", minCount, maxRead, checker); + } + + protected AtLeastChecker atLeast(String name, int minCount, int maxRead, Predicate 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 NumberChecker number(int minCount) { - return new NumberChecker(stringInspect, minCount, -1); + protected LetterChecker letter(int minCount, int maxRead) { + return letter("LetterChecker", minCount, maxRead); } - protected NumberChecker number(int minCount, int maxRead) { - return new NumberChecker(stringInspect, minCount, maxRead); + protected LetterChecker letter(String name, int minCount, int maxRead) { + return new LetterChecker(name, minCount, maxRead); } protected CharChecker ch(char c) { - return new CharChecker(stringInspect, c); + return ch("CharChecker", c); + } + + protected CharChecker ch(String name, char c) { + return new CharChecker(name, c); } protected CustomCharChecker chars(Predicate checker) { - return new CustomCharChecker(stringInspect, checker); + return chars("CustomCharChecker", checker); + } + + protected CustomCharChecker chars(String name, Predicate checker) { + return new CustomCharChecker(name, checker); } protected StringChecker string(String equalsTo) { - return new StringChecker(stringInspect, 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 index ead49de0eec43d..54efc875705158 100644 --- 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 @@ -19,21 +19,25 @@ /** IntegerChecker */ public class IntegerChecker extends FormatChecker { - private IntegerChecker(StringInspect stringInspect) { - super(stringInspect); + 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) { - IntegerChecker integerChecker = new IntegerChecker(new StringInspect(string)); - return integerChecker.check() && integerChecker.stringInspect.eos(); + StringInspect stringInspect = new StringInspect(string); + return INSTANCE.check(stringInspect).matched && stringInspect.eos(); } @Override - protected boolean doCheck() { - FormatChecker checker = and( - option(chars(c -> c == '+' || c == '-')), - number(1) - ); - return checker.check(); + 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 00000000000000..958d16618a3517 --- /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; + +/** NumberChecker */ +public class LetterChecker extends FormatChecker { + private int minCount; + private 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 index c97eb54b8c0322..9c8c88d6e5b651 100644 --- 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 @@ -21,14 +21,14 @@ public class OptionChecker extends FormatChecker { private final FormatChecker checker; - public OptionChecker(StringInspect stringInspect, FormatChecker checker) { - super(stringInspect); + public OptionChecker(String name, FormatChecker checker) { + super(name); this.checker = checker; } @Override - protected boolean doCheck() { - checker.check(); + 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 index ffdab3b8001f2c..f69de259a1de85 100644 --- 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 @@ -23,20 +23,28 @@ public class OrChecker extends FormatChecker { private final List checkers; - public OrChecker(StringInspect stringInspect, List checkers) { - super(stringInspect); + public OrChecker(String name, List checkers) { + super(name); this.checkers = checkers; } @Override - protected boolean doCheck() { + protected boolean doCheck(StringInspect stringInspect) { + int maxMatches = -1; + CheckResult maxMatchesResult = null; for (FormatChecker checker : checkers) { - if (!checker.check()) { - checker.stepBack(); - } else { - return true; + 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; } - 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 index fa2fae23e40044..22c4692f0bf8b0 100644 --- 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 @@ -21,13 +21,13 @@ public class StringChecker extends FormatChecker { private String str; - public StringChecker(StringInspect stringInspect, String str) { - super(stringInspect); + public StringChecker(String name, String str) { + super(name); this.str = str; } @Override - protected boolean doCheck() { + protected boolean doCheck(StringInspect stringInspect) { if (stringInspect.remain() < str.length()) { return false; } 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 aaef3775b34360..3dd2ae35c3e4c2 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 @@ 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 static DecimalV3Type createDecimalV3TypeLooseCheck(int precision, int sca 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/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 914246f08b6e47..0a8c3b214a6023 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.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 @@ void testBasic() { 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 @@ void testDetermineScale() { @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 @@ void testDateTimeZone1() { 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 @@ void testIrregularDateTimeHourMinuteSecondMicrosecond() { @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 @@ void testEquals() { Assertions.assertEquals(l1, l2); Assertions.assertNotEquals(l1, l3); } + + private L check(String str, Function 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 00000000000000..529695ae5791a7 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/FloatLiteralTest.java @@ -0,0 +1,63 @@ +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 check(String str, Function 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 00000000000000..a82020c225aeaa --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/IntegerLiteralTest.java @@ -0,0 +1,48 @@ +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 check(String str, Function literalBuilder) { + Assertions.assertTrue(IntegerChecker.isValidInteger(str), "Invalid integer: " + str); + return literalBuilder.apply(str); + } +}