This is an automated email from the ASF dual-hosted git repository.
englefly pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 81bbd658c92 [Feat](Nereids) support string functions fold constant by
fe (#40441)
81bbd658c92 is described below
commit 81bbd658c92657aa410f03960242b0dce5eca1c4
Author: LiBinfeng <[email protected]>
AuthorDate: Wed Sep 11 16:42:37 2024 +0800
[Feat](Nereids) support string functions fold constant by fe (#40441)
support string functions fold constant by fe:
Concat, Substring, Length, Lower, Upper, Trim, Ltrim, Rtrim, Replace,
Left, Right, Locate,
Instr, Ascii, Bin, ConcatWs, CharacterLength, Initcap, Md5, Md5Sum,
Field, FindInSet, Repeat, Reverse, Space, SplitByChar, SplitByString,
SplitPart,
SubstringIndex, Strcmp, StrLeft, StrRight, Overlay, ParseUrl, UrlDecode,
AppendTrailingCharIfAbsent, EndsWith, ExtractUrlParameter, Quote,
ReplaceEmpty, Password
---
.../expression/rules/FoldConstantRuleOnFE.java | 3 +
.../nereids/trees/expressions/ExecFunction.java | 5 +
.../trees/expressions/ExpressionEvaluator.java | 69 +-
.../functions/executable/StringArithmetic.java | 856 +++++++++++++++++++++
.../trees/expressions/functions/scalar/Field.java | 28 +-
.../trees/expressions/functions/scalar/Repeat.java | 2 +
.../rewrite/ArrayContainsToArrayOverlapTest.java | 5 +-
.../org/apache/doris/regression/suite/Suite.groovy | 14 +
.../fold_constant/fold_constant_by_be.groovy | 2 +-
.../fold_constant_string_arithmatic.groovy | 687 +++++++++++++++++
10 files changed, 1650 insertions(+), 21 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
index 1b830c7d11d..400577f5a6a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
@@ -92,6 +92,7 @@ import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Lists;
import org.apache.commons.codec.digest.DigestUtils;
+import java.time.DateTimeException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -443,6 +444,8 @@ public class FoldConstantRuleOnFE extends
AbstractExpressionRewriteRule
// If cast is from type coercion, we don't use NULL
literal and will throw exception.
throw t;
}
+ } catch (DateTimeException e) {
+ return new NullLiteral(dataType);
}
}
try {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExecFunction.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExecFunction.java
index 6778c0971ed..126449f4b04 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExecFunction.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExecFunction.java
@@ -43,4 +43,9 @@ public @interface ExecFunction {
* return type
*/
String returnType();
+
+ /**
+ * hasVarArgsc
+ */
+ boolean varArgs() default false;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExpressionEvaluator.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExpressionEvaluator.java
index 566798ec2d4..f3d471b2abe 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExpressionEvaluator.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExpressionEvaluator.java
@@ -18,6 +18,7 @@
package org.apache.doris.nereids.trees.expressions;
import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.nereids.trees.expressions.functions.BoundFunction;
import
org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction;
@@ -26,6 +27,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.executable.DateTimeA
import
org.apache.doris.nereids.trees.expressions.functions.executable.DateTimeExtractAndTransform;
import
org.apache.doris.nereids.trees.expressions.functions.executable.ExecutableFunctions;
import
org.apache.doris.nereids.trees.expressions.functions.executable.NumericArithmetic;
+import
org.apache.doris.nereids.trees.expressions.functions.executable.StringArithmetic;
import
org.apache.doris.nereids.trees.expressions.functions.executable.TimeRoundSeries;
import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
@@ -36,6 +38,7 @@ import org.apache.doris.nereids.util.TypeCoercionUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
+import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -96,10 +99,30 @@ public enum ExpressionEvaluator {
}
private Expression invoke(Expression expression, String fnName, DataType[]
args) {
- FunctionSignature signature = new FunctionSignature(fnName, args,
null);
+ FunctionSignature signature = new FunctionSignature(fnName, args,
null, false);
FunctionInvoker invoker = getFunction(signature);
if (invoker != null) {
try {
+ if (invoker.getSignature().hasVarArgs()) {
+ int fixedArgsSize =
invoker.getSignature().getArgTypes().length - 1;
+ int totalSize = expression.children().size();
+ Class<?>[] parameterTypes =
invoker.getMethod().getParameterTypes();
+ Class<?> parameterType =
parameterTypes[parameterTypes.length - 1];
+ Class<?> componentType = parameterType.getComponentType();
+ Object varArgs = Array.newInstance(componentType,
totalSize - fixedArgsSize);
+ for (int i = fixedArgsSize; i < totalSize; i++) {
+ if (!(expression.children().get(i) instanceof
NullLiteral)) {
+ Array.set(varArgs, i - fixedArgsSize,
expression.children().get(i));
+ }
+ }
+ Object[] objects = new Object[fixedArgsSize + 1];
+ for (int i = 0; i < fixedArgsSize; i++) {
+ objects[i] = expression.children().get(i);
+ }
+ objects[fixedArgsSize] = varArgs;
+
+ return invoker.invokeVars(objects);
+ }
return invoker.invoke(expression.children());
} catch (AnalysisException e) {
return expression;
@@ -114,9 +137,34 @@ public enum ExpressionEvaluator {
DataType[] candidateTypes = candidate.getSignature().getArgTypes();
DataType[] expectedTypes = signature.getArgTypes();
+ if (candidate.getSignature().hasVarArgs()) {
+ if (candidateTypes.length > expectedTypes.length) {
+ continue;
+ }
+ boolean match = true;
+ for (int i = 0; i < candidateTypes.length - 1; i++) {
+ if
(!(expectedTypes[i].toCatalogDataType().matchesType(candidateTypes[i].toCatalogDataType())))
{
+ match = false;
+ break;
+ }
+ }
+ Type varType = candidateTypes[candidateTypes.length -
1].toCatalogDataType();
+ for (int i = candidateTypes.length - 1; i <
expectedTypes.length; i++) {
+ if
(!(expectedTypes[i].toCatalogDataType().matchesType(varType))) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ return candidate;
+ } else {
+ continue;
+ }
+ }
if (candidateTypes.length != expectedTypes.length) {
continue;
}
+
boolean match = true;
for (int i = 0; i < candidateTypes.length; i++) {
if
(!(expectedTypes[i].toCatalogDataType().matchesType(candidateTypes[i].toCatalogDataType())))
{
@@ -143,6 +191,7 @@ public enum ExpressionEvaluator {
DateLiteral.class,
DateTimeArithmetic.class,
NumericArithmetic.class,
+ StringArithmetic.class,
TimeRoundSeries.class
);
for (Class<?> cls : classes) {
@@ -172,7 +221,7 @@ public enum ExpressionEvaluator {
for (int i = 0; i < argTypes.size(); i++) {
array[i] = argTypes.get(i);
}
- FunctionSignature signature = new FunctionSignature(name, array,
returnType);
+ FunctionSignature signature = new FunctionSignature(name, array,
returnType, annotation.varArgs());
mapBuilder.put(name, new FunctionInvoker(method, signature));
}
}
@@ -204,6 +253,14 @@ public enum ExpressionEvaluator {
throw new AnalysisException(e.getLocalizedMessage());
}
}
+
+ public Literal invokeVars(Object[] args) throws AnalysisException {
+ try {
+ return (Literal) method.invoke(null, args);
+ } catch (InvocationTargetException | IllegalAccessException |
IllegalArgumentException e) {
+ throw new AnalysisException(e.getLocalizedMessage());
+ }
+ }
}
/**
@@ -213,11 +270,13 @@ public enum ExpressionEvaluator {
private final String name;
private final DataType[] argTypes;
private final DataType returnType;
+ private final boolean hasVarArgs;
- public FunctionSignature(String name, DataType[] argTypes, DataType
returnType) {
+ public FunctionSignature(String name, DataType[] argTypes, DataType
returnType, boolean hasVarArgs) {
this.name = name;
this.argTypes = argTypes;
this.returnType = returnType;
+ this.hasVarArgs = hasVarArgs;
}
public DataType[] getArgTypes() {
@@ -231,6 +290,10 @@ public enum ExpressionEvaluator {
public String getName() {
return name;
}
+
+ public boolean hasVarArgs() {
+ return hasVarArgs;
+ }
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmetic.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmetic.java
new file mode 100644
index 00000000000..6f2ff11ad9a
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/StringArithmetic.java
@@ -0,0 +1,856 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.functions.executable;
+
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.ExecFunction;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.literal.ArrayLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
+import org.apache.doris.nereids.trees.expressions.literal.DecimalLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.DecimalV3Literal;
+import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.FloatLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.Literal;
+import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.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 java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * executable functions:
+ * concat
+ */
+public class StringArithmetic {
+ private static Expression castStringLikeLiteral(StringLikeLiteral first,
String value) {
+ if (first instanceof StringLiteral) {
+ return new StringLiteral(value);
+ } else if (first instanceof VarcharLiteral) {
+ return new VarcharLiteral(value);
+ }
+ throw new AnalysisException("Unsupported string literal type: " +
first.getClass().getSimpleName());
+ }
+
+ /**
+ * Executable arithmetic functions concat
+ */
+ @ExecFunction(name = "concat", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "VARCHAR")
+ public static Expression concatVarcharVarchar(StringLikeLiteral first,
StringLikeLiteral second) {
+ String result = first.getValue() + second.getValue();
+ return castStringLikeLiteral(first, result);
+ }
+
+ private static String substringImpl(String first, int second, int third) {
+ int stringLength = first.length();
+ if (stringLength == 0) {
+ return "";
+ }
+ int leftIndex = 0;
+ if (second < (- stringLength)) {
+ return "";
+ } else if (second < 0) {
+ leftIndex = stringLength + second;
+ } else if (second <= stringLength) {
+ leftIndex = second - 1;
+ } else {
+ return "";
+ }
+ int rightIndex = 0;
+ if (third <= 0) {
+ return "";
+ } else if ((third + leftIndex) > stringLength) {
+ rightIndex = stringLength;
+ } else {
+ rightIndex = third + leftIndex;
+ }
+ return first.substring(leftIndex, rightIndex);
+ }
+
+ /**
+ * Executable arithmetic functions substring
+ */
+ @ExecFunction(name = "substring", argTypes = {"VARCHAR", "INT", "INT"},
returnType = "VARCHAR")
+ public static Expression substringVarcharIntInt(StringLikeLiteral first,
+ IntegerLiteral second,
IntegerLiteral third) {
+ return castStringLikeLiteral(first, substringImpl(first.getValue(),
second.getValue(), third.getValue()));
+ }
+
+ /**
+ * Executable arithmetic functions length
+ */
+ @ExecFunction(name = "length", argTypes = {"VARCHAR"}, returnType = "INT")
+ public static Expression lengthVarchar(StringLikeLiteral first) {
+ return new IntegerLiteral(first.getValue().length());
+ }
+
+ /**
+ * Executable arithmetic functions Lower
+ */
+ @ExecFunction(name = "lower", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression lowerVarchar(StringLikeLiteral first) {
+ return castStringLikeLiteral(first, first.getValue().toLowerCase());
+ }
+
+ /**
+ * Executable arithmetic functions Upper
+ */
+ @ExecFunction(name = "upper", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression upperVarchar(StringLikeLiteral first) {
+ return castStringLikeLiteral(first, first.getValue().toUpperCase());
+ }
+
+ private static String trimImpl(String first, String second, boolean left,
boolean right) {
+ String result = first;
+ String afterReplace = first;
+ if (left) {
+ do {
+ result = afterReplace;
+ afterReplace = result.replaceFirst("^" + second, "");
+ } while (!afterReplace.equals(result));
+ }
+ if (right) {
+ do {
+ result = afterReplace;
+ afterReplace = result.replaceFirst(second + "$", "");
+ } while (!afterReplace.equals(result));
+ }
+ return result;
+ }
+
+ /**
+ * Executable arithmetic functions Trim
+ */
+ @ExecFunction(name = "trim", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression trimVarchar(StringLikeLiteral first) {
+ return castStringLikeLiteral(first, trimImpl(first.getValue(), " ",
true, true));
+ }
+
+ /**
+ * Executable arithmetic functions Trim
+ */
+ @ExecFunction(name = "trim", argTypes = {"VARCHAR", "VARCHAR"}, returnType
= "VARCHAR")
+ public static Expression trimVarcharVarchar(StringLikeLiteral first,
StringLikeLiteral second) {
+ return castStringLikeLiteral(first, trimImpl(first.getValue(),
second.getValue(), true, true));
+ }
+
+ /**
+ * Executable arithmetic functions ltrim
+ */
+ @ExecFunction(name = "ltrim", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression ltrimVarchar(StringLikeLiteral first) {
+ return castStringLikeLiteral(first, trimImpl(first.getValue(), " ",
true, false));
+ }
+
+ /**
+ * Executable arithmetic functions ltrim
+ */
+ @ExecFunction(name = "ltrim", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "VARCHAR")
+ public static Expression ltrimVarcharVarchar(StringLikeLiteral first,
StringLikeLiteral second) {
+ return castStringLikeLiteral(first, trimImpl(first.getValue(),
second.getValue(), true, false));
+ }
+
+ /**
+ * Executable arithmetic functions rtrim
+ */
+ @ExecFunction(name = "rtrim", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression rtrimVarchar(StringLikeLiteral first) {
+ return castStringLikeLiteral(first, trimImpl(first.getValue(), " ",
false, true));
+ }
+
+ /**
+ * Executable arithmetic functions rtrim
+ */
+ @ExecFunction(name = "rtrim", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "VARCHAR")
+ public static Expression rtrimVarcharVarchar(StringLikeLiteral first,
StringLikeLiteral second) {
+ return castStringLikeLiteral(first, trimImpl(first.getValue(),
second.getValue(), false, true));
+ }
+
+ /**
+ * Executable arithmetic functions Replace
+ */
+ @ExecFunction(name = "replace", argTypes = {"VARCHAR", "VARCHAR",
"VARCHAR"}, returnType = "VARCHAR")
+ public static Expression replace(StringLikeLiteral first,
StringLikeLiteral second, StringLikeLiteral third) {
+ if (second.getValue().length() == 0) {
+ return castStringLikeLiteral(first, first.getValue());
+ }
+ return castStringLikeLiteral(first,
first.getValue().replace(second.getValue(), third.getValue()));
+ }
+
+ /**
+ * Executable arithmetic functions Left
+ */
+ @ExecFunction(name = "left", argTypes = {"VARCHAR", "INT"}, returnType =
"VARCHAR")
+ public static Expression left(StringLikeLiteral first, IntegerLiteral
second) {
+ if (second.getValue() <= 0) {
+ return castStringLikeLiteral(first, "");
+ } else if (second.getValue() < first.getValue().length()) {
+ return castStringLikeLiteral(first, first.getValue().substring(0,
second.getValue()));
+ } else {
+ return first;
+ }
+ }
+
+ /**
+ * Executable arithmetic functions Right
+ */
+ @ExecFunction(name = "right", argTypes = {"VARCHAR", "INT"}, returnType =
"VARCHAR")
+ public static Expression right(StringLikeLiteral first, IntegerLiteral
second) {
+ if (second.getValue() < (- first.getValue().length()) ||
Math.abs(second.getValue()) == 0) {
+ return castStringLikeLiteral(first, "");
+ } else if (second.getValue() > first.getValue().length()) {
+ return first;
+ } else {
+ if (second.getValue() > 0) {
+ return castStringLikeLiteral(first, first.getValue().substring(
+ first.getValue().length() - second.getValue(),
first.getValue().length()));
+ } else {
+ return castStringLikeLiteral(first, first.getValue().substring(
+ Math.abs(second.getValue()) - 1,
first.getValue().length()));
+ }
+ }
+ }
+
+ /**
+ * Executable arithmetic functions Locate
+ */
+ @ExecFunction(name = "locate", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "INT")
+ public static Expression locate(StringLikeLiteral first, StringLikeLiteral
second) {
+ return new
IntegerLiteral(second.getValue().trim().indexOf(first.getValue()) + 1);
+ }
+
+ /**
+ * Executable arithmetic functions Instr
+ */
+ @ExecFunction(name = "instr", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "INT")
+ public static Expression instr(StringLikeLiteral first, StringLikeLiteral
second) {
+ return new IntegerLiteral(first.getValue().indexOf(second.getValue())
+ 1);
+ }
+
+ /**
+ * Executable arithmetic functions Ascii
+ */
+ @ExecFunction(name = "ascii", argTypes = {"VARCHAR"}, returnType = "INT")
+ public static Expression ascii(StringLikeLiteral first) {
+ if (first.getValue().length() == 0) {
+ return new IntegerLiteral(0);
+ }
+ char firstChar = first.getValue().charAt(0);
+ return new IntegerLiteral(firstChar);
+ }
+
+ /**
+ * Executable arithmetic functions Bin
+ */
+ @ExecFunction(name = "bin", argTypes = {"BIGINT"}, returnType = "VARCHAR")
+ public static Expression bin(BigIntLiteral first) {
+ return new VarcharLiteral(Long.toBinaryString(first.getValue()));
+ }
+
+ /**
+ * Executable arithmetic functions ConcatWs
+ */
+ @ExecFunction(name = "concat_ws", argTypes = {"VARCHAR",
"ARRAY<VARCHAR>"}, returnType = "VARCHAR")
+ public static Expression concatWsVarcharArray(StringLikeLiteral first,
ArrayLiteral second) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < second.getValue().size() - 1; i++) {
+ if (!(second.getValue().get(i) instanceof NullLiteral)) {
+ sb.append(second.getValue().get(i).getValue());
+ sb.append(first.getValue());
+ }
+ }
+ sb.append(second.getValue().get(second.getValue().size() -
1).getValue());
+ return castStringLikeLiteral(first, sb.toString());
+ }
+
+ /**
+ * Executable arithmetic functions ConcatWs
+ */
+ @ExecFunction(varArgs = true, name = "concat_ws", argTypes = {"VARCHAR",
"VARCHAR"}, returnType = "VARCHAR")
+ public static Expression concatWsVarcharVarchar(StringLikeLiteral first,
VarcharLiteral... second) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < second.length - 1; i++) {
+ sb.append(second[i].getValue());
+ sb.append(first.getValue());
+ }
+ sb.append(second[second.length - 1].getValue());
+ return castStringLikeLiteral(first, sb.toString());
+ }
+
+ /**
+ * Executable arithmetic functions CharacterLength
+ */
+ @ExecFunction(name = "character_length", argTypes = {"VARCHAR"},
returnType = "INT")
+ public static Expression characterLength(StringLikeLiteral first) {
+ return new IntegerLiteral(first.getValue().length());
+ }
+
+ private static boolean isSeparator(char c) {
+ if (".$|()[{^?*+\\".indexOf(c) == -1) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Executable arithmetic functions initCap
+ */
+ @ExecFunction(name = "initcap", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression initCap(StringLikeLiteral first) {
+ StringBuilder result = new StringBuilder(first.getValue().length());
+ boolean capitalizeNext = true;
+
+ for (char c : first.getValue().toCharArray()) {
+ if (Character.isWhitespace(c) || isSeparator(c)) {
+ result.append(c);
+ capitalizeNext = true; // Next character should be capitalized
+ } else if (capitalizeNext) {
+ result.append(Character.toUpperCase(c));
+ capitalizeNext = false;
+ } else {
+ result.append(Character.toLowerCase(c));
+ }
+ }
+ return castStringLikeLiteral(first, result.toString());
+ }
+
+ /**
+ * Executable arithmetic functions md5
+ */
+ @ExecFunction(name = "md5", argTypes = {"VARCHAR"}, returnType = "VARCHAR")
+ public static Expression md5(StringLikeLiteral first) {
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ // Update the digest with the input bytes
+ md.update(first.getValue().getBytes());
+ return castStringLikeLiteral(first, bytesToHex(md.digest()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Executable arithmetic functions md5
+ */
+ @ExecFunction(varArgs = true, name = "md5sum", argTypes = {"VARCHAR"},
returnType = "VARCHAR")
+ public static Expression md5Sum(VarcharLiteral... first) {
+ try {
+ // Step 1: Create a MessageDigest instance for MD5
+ MessageDigest md = MessageDigest.getInstance("MD5");
+
+ // Step 2: Concatenate all strings in the list into one string
+ StringBuilder combinedInput = new StringBuilder();
+ for (StringLikeLiteral input : first) {
+ combinedInput.append(input.getValue());
+ }
+
+ // Step 3: Convert the combined string to a byte array and pass it
to the digest() method
+ byte[] messageDigest =
md.digest(combinedInput.toString().getBytes());
+
+ // Step 4: Convert the byte array into a hexadecimal string
+ StringBuilder hexString = new StringBuilder();
+ for (byte b : messageDigest) {
+ String hex = Integer.toHexString(0xff & b);
+ if (hex.length() == 1) {
+ hexString.append('0'); // Add leading zero if needed
+ }
+ hexString.append(hex);
+ }
+
+ // Step 5: Return the hexadecimal string
+ return castStringLikeLiteral(first[0], hexString.toString());
+
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // Helper method to convert a byte array to a hexadecimal string
+ private static String bytesToHex(byte[] bytes) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02x", b));
+ }
+ return sb.toString();
+ }
+
+ private static int compareLiteral(Literal first, Literal... second) {
+ for (int i = 0; i < second.length; i++) {
+ if (second[i].getValue().equals(first.getValue())) {
+ return i + 1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"INT", "INT"},
returnType = "INT")
+ public static Expression fieldInt(IntegerLiteral first, IntegerLiteral...
second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"TINYINT",
"TINYINT"}, returnType = "INT")
+ public static Expression fieldTinyInt(TinyIntLiteral first,
TinyIntLiteral... second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"SMALLINT",
"SMALLINT"}, returnType = "INT")
+ public static Expression fieldSmallInt(SmallIntLiteral first,
SmallIntLiteral... second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"BIGINT",
"BIGINT"}, returnType = "INT")
+ public static Expression fieldBigInt(BigIntLiteral first, BigIntLiteral...
second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"LARGEINT",
"LARGEINT"}, returnType = "INT")
+ public static Expression fieldLargeInt(LargeIntLiteral first,
LargeIntLiteral... second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"FLOAT",
"FLOAT"}, returnType = "INT")
+ public static Expression fieldFloat(FloatLiteral first, FloatLiteral...
second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"DOUBLE",
"DOUBLE"}, returnType = "INT")
+ public static Expression fieldDouble(DoubleLiteral first, DoubleLiteral...
second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"DECIMAL",
"DECIMAL"}, returnType = "INT")
+ public static Expression fieldDecimalV2(DecimalLiteral first,
DecimalLiteral... second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"DECIMALV3",
"DECIMALV3"}, returnType = "INT")
+ public static Expression fieldDecimalV3(DecimalV3Literal first,
DecimalV3Literal... second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"DATETIME",
"DATETIME"}, returnType = "INT")
+ public static Expression fieldDateTime(DateTimeLiteral first,
DateTimeLiteral... second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"DATETIMEV2",
"DATETIMEV2"}, returnType = "INT")
+ public static Expression fieldDateTimeV2(DateTimeV2Literal first,
DateTimeV2Literal... second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ /**
+ * Executable arithmetic functions field
+ */
+ @ExecFunction(varArgs = true, name = "field", argTypes = {"VARCHAR",
"VARCHAR"}, returnType = "INT")
+ public static Expression fieldVarchar(StringLikeLiteral first,
VarcharLiteral... second) {
+ return new IntegerLiteral(compareLiteral(first, second));
+ }
+
+ private static int findStringInSet(String target, String input) {
+ String[] split = input.split(",");
+ for (int i = 0; i < split.length; i++) {
+ if (split[i].equals(target)) {
+ return i + 1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Executable arithmetic functions find_in_set
+ */
+ @ExecFunction(name = "find_in_set", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "INT")
+ public static Expression findInSetVarchar(StringLikeLiteral first,
StringLikeLiteral second) {
+ return new IntegerLiteral(findStringInSet(first.getValue(),
second.getValue()));
+ }
+
+ /**
+ * Executable arithmetic functions repeat
+ */
+ @ExecFunction(name = "repeat", argTypes = {"VARCHAR", "INT"}, returnType =
"VARCHAR")
+ public static Expression repeat(StringLikeLiteral first, IntegerLiteral
second) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < second.getValue(); i++) {
+ sb.append(first.getValue());
+ }
+ return castStringLikeLiteral(first, sb.toString());
+ }
+
+ /**
+ * Executable arithmetic functions reverse
+ */
+ @ExecFunction(name = "reverse", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression reverseVarchar(StringLikeLiteral first) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(first.getValue());
+ return castStringLikeLiteral(first, sb.reverse().toString());
+ }
+
+ /**
+ * Executable arithmetic functions space
+ */
+ @ExecFunction(name = "space", argTypes = {"INT"}, returnType = "VARCHAR")
+ public static Expression space(IntegerLiteral first) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < first.getValue(); i++) {
+ sb.append(' ');
+ }
+ return new VarcharLiteral(sb.toString());
+ }
+
+ /**
+ * Executable arithmetic functions split_by_char
+ */
+ @ExecFunction(name = "split_by_char", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "ARRAY<VARCHAR>")
+ public static Expression splitByChar(StringLikeLiteral first,
StringLikeLiteral second) {
+ String[] result = first.getValue().split(second.getValue());
+ List<Literal> items = new ArrayList<>();
+ for (int i = 1; i < result.length; i++) {
+ items.add((Literal) castStringLikeLiteral(first, result[i]));
+ }
+ return new ArrayLiteral(items);
+ }
+
+ /**
+ * Executable arithmetic functions split_part
+ */
+ @ExecFunction(name = "split_part", argTypes = {"VARCHAR", "VARCHAR",
"INT"}, returnType = "VARCHAR")
+ public static Expression splitPart(StringLikeLiteral first,
StringLikeLiteral chr, IntegerLiteral number) {
+ if (first.getValue().equals(chr.getValue())) {
+ if (Math.abs(number.getValue()) == 1 ||
Math.abs(number.getValue()) == 2) {
+ return castStringLikeLiteral(first, "");
+ }
+ }
+ String separator = chr.getValue();
+ String[] parts = null;
+ if (number.getValue() < 0) {
+ StringBuilder sb = new StringBuilder(first.getValue());
+ StringBuilder seperatorBuilder = new StringBuilder(separator);
+ separator = seperatorBuilder.reverse().toString();
+ if (".$|()[{^?*+\\".contains(separator) ||
separator.startsWith("\\")) {
+ separator = "\\" + separator;
+ }
+ parts = sb.reverse().toString().split(separator);
+ } else {
+ if (".$|()[{^?*+\\".contains(separator) ||
separator.startsWith("\\")) {
+ separator = "\\" + separator;
+ }
+ parts = first.getValue().split(separator);
+ }
+
+ if (parts.length < Math.abs(number.getValue()) || number.getValue() ==
0) {
+ if (parts.length == Math.abs(number.getValue()) - 1) {
+ if (number.getValue() < 0 &&
first.getValue().startsWith(chr.getValue())
+ || number.getValue() > 0 &&
first.getValue().endsWith(chr.getValue())) {
+ return castStringLikeLiteral(first, "");
+ }
+ }
+ return new NullLiteral();
+ } else if (number.getValue() < 0) {
+ StringBuilder result = new
StringBuilder(parts[Math.abs(number.getValue()) - 1]);
+ return castStringLikeLiteral(first, result.reverse().toString());
+ } else {
+ return castStringLikeLiteral(first, parts[number.getValue() - 1]);
+ }
+ }
+
+ /**
+ * Executable arithmetic functions substring_index
+ */
+ @ExecFunction(name = "substring_index", argTypes = {"VARCHAR", "VARCHAR",
"INT"}, returnType = "VARCHAR")
+ public static Expression substringIndex(StringLikeLiteral first,
StringLikeLiteral chr, IntegerLiteral number) {
+ String[] parts = first.getValue().split(chr.getValue());
+ if (Math.abs(number.getValue()) >= parts.length) {
+ return first;
+ }
+ int leftIndex;
+ int rightIndex;
+ if (parts.length < number.getValue() || number.getValue() < (-
parts.length) || number.getValue() == 0) {
+ return castStringLikeLiteral(first, "");
+ } else if (number.getValue() < 0) {
+ leftIndex = parts.length + number.getValue();
+ rightIndex = parts.length;
+ } else {
+ leftIndex = 0;
+ rightIndex = number.getValue();
+ }
+ StringBuilder sb = new StringBuilder();
+ for (int i = leftIndex; i < rightIndex - 1; i++) {
+ sb.append(parts[i]);
+ sb.append(chr.getValue());
+ }
+ sb.append(parts[rightIndex - 1]);
+ return castStringLikeLiteral(first, sb.toString());
+ }
+
+ /**
+ * Executable arithmetic functions strcmp
+ */
+ @ExecFunction(name = "strcmp", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "TINYINT")
+ public static Expression strcmp(StringLikeLiteral first, StringLikeLiteral
second) {
+ int result = first.getValue().compareTo(second.getValue());
+ if (result == 0) {
+ return new TinyIntLiteral((byte) 0);
+ } else if (result < 0) {
+ return new TinyIntLiteral((byte) -1);
+ } else {
+ return new TinyIntLiteral((byte) 1);
+ }
+ }
+
+ /**
+ * Executable arithmetic functions strLeft
+ */
+ @ExecFunction(name = "strleft", argTypes = {"VARCHAR", "INT"}, returnType
= "VARCHAR")
+ public static Expression strLeft(StringLikeLiteral first, IntegerLiteral
second) {
+ if (second.getValue() <= 0) {
+ return castStringLikeLiteral(first, "");
+ } else if (second.getValue() > first.getValue().length()) {
+ return first;
+ } else {
+ return castStringLikeLiteral(first, first.getValue().substring(0,
second.getValue()));
+ }
+ }
+
+ /**
+ * Executable arithmetic functions strRight
+ */
+ @ExecFunction(name = "strright", argTypes = {"VARCHAR", "INT"}, returnType
= "VARCHAR")
+ public static Expression strRight(StringLikeLiteral first, IntegerLiteral
second) {
+ if (second.getValue() < (- first.getValue().length()) ||
Math.abs(second.getValue()) == 0) {
+ return castStringLikeLiteral(first, "");
+ } else if (second.getValue() > first.getValue().length()) {
+ return first;
+ } else {
+ if (second.getValue() > 0) {
+ return castStringLikeLiteral(first, first.getValue().substring(
+ first.getValue().length() - second.getValue(),
first.getValue().length()));
+ } else {
+ return castStringLikeLiteral(first, first.getValue().substring(
+ Math.abs(second.getValue()) - 1,
first.getValue().length()));
+ }
+ }
+ }
+
+ /**
+ * Executable arithmetic functions overlay
+ */
+ @ExecFunction(name = "overlay", argTypes = {"VARCHAR", "INT", "INT",
"VARCHAR"}, returnType = "VARCHAR")
+ public static Expression overlay(StringLikeLiteral first,
+ IntegerLiteral second, IntegerLiteral
third, StringLikeLiteral four) {
+ StringBuilder sb = new StringBuilder();
+ if (second.getValue() <= 0 || second.getValue() >
first.getValue().length()) {
+ return first;
+ } else {
+ if (third.getValue() < 0 || third.getValue() >
(first.getValue().length() - third.getValue())) {
+ sb.append(first.getValue().substring(0, second.getValue() -
1));
+ sb.append(four.getValue());
+ return castStringLikeLiteral(first, sb.toString());
+ } else {
+ sb.append(first.getValue().substring(0, second.getValue() -
1));
+ sb.append(four.getValue());
+ sb.append(first.getValue().substring(second.getValue()
+ + third.getValue() - 1, first.getValue().length()));
+ return castStringLikeLiteral(first, sb.toString());
+ }
+ }
+ }
+
+ /**
+ * Executable arithmetic functions parseurl
+ */
+ @ExecFunction(name = "parse_url", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "VARCHAR")
+ public static Expression parseurl(StringLikeLiteral first,
StringLikeLiteral second) {
+ URI uri = null;
+ try {
+ uri = new URI(first.getValue());
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ StringBuilder sb = new StringBuilder();
+ switch (second.getValue().toUpperCase()) {
+ case "PROTOCOL":
+ sb.append(uri.getScheme()); // e.g., http, https
+ break;
+ case "HOST":
+ sb.append(uri.getHost()); // e.g., www.example.com
+ break;
+ case "PATH":
+ sb.append(uri.getPath()); // e.g., /page
+ break;
+ case "REF":
+ try {
+ sb.append(uri.toURL().getRef()); // e.g., /page
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ break;
+ case "AUTHORITY":
+ sb.append(uri.getAuthority()); // e.g.,
param1=value1¶m2=value2
+ break;
+ case "FILE":
+ try {
+ sb.append(uri.toURL().getFile()); // e.g.,
param1=value1¶m2=value2
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ break;
+ case "QUERY":
+ sb.append(uri.getQuery()); // e.g.,
param1=value1¶m2=value2
+ break;
+ case "PORT":
+ sb.append(uri.getPort());
+ break;
+ case "USERINFO":
+ sb.append(uri.getUserInfo()); // e.g., user:pass
+ break;
+ default:
+ throw new RuntimeException("Valid URL parts are 'PROTOCOL',
'HOST', "
+ + "'PATH', 'REF', 'AUTHORITY', 'FILE', 'USERINFO',
'PORT' and 'QUERY'");
+ }
+ return castStringLikeLiteral(first, sb.toString());
+ }
+
+ /**
+ * Executable arithmetic functions urldecode
+ */
+ @ExecFunction(name = "url_decode", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression urlDecode(StringLikeLiteral first) {
+ try {
+ return castStringLikeLiteral(first,
URLDecoder.decode(first.getValue(), StandardCharsets.UTF_8.name()));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Executable arithmetic functions append_trailing_char_if_absent
+ */
+ @ExecFunction(name = "append_trailing_char_if_absent", argTypes =
{"VARCHAR", "VARCHAR"}, returnType = "VARCHAR")
+ public static Expression appendTrailingCharIfAbsent(StringLikeLiteral
first, StringLikeLiteral second) {
+ if (first.getValue().endsWith(second.getValue())) {
+ return first;
+ } else {
+ return castStringLikeLiteral(first, first.getValue() +
second.getValue());
+ }
+ }
+
+ /**
+ * Executable arithmetic functions endsWith
+ */
+ @ExecFunction(name = "ends_with", argTypes = {"VARCHAR", "VARCHAR"},
returnType = "BOOLEAN")
+ public static Expression endsWith(StringLikeLiteral first,
StringLikeLiteral second) {
+ if (first.getValue().endsWith(second.getValue())) {
+ return BooleanLiteral.TRUE;
+ } else {
+ return BooleanLiteral.FALSE;
+ }
+ }
+
+ /**
+ * Executable arithmetic functions extractUrlParameter
+ */
+ @ExecFunction(name = "extract_url_parameter", argTypes = {"VARCHAR",
"VARCHAR"}, returnType = "VARCHAR")
+ public static Expression extractUrlParameter(StringLikeLiteral first,
StringLikeLiteral second) {
+ if (first.getValue() == null || first.getValue().indexOf('?') == -1) {
+ return castStringLikeLiteral(first, "");
+ }
+
+ String[] urlParts = first.getValue().split("\\?");
+ if (urlParts.length > 1) {
+ String query = urlParts[1];
+ String[] pairs = query.split("&");
+
+ for (String pair : pairs) {
+ String[] keyValue = pair.split("=");
+ if (second.getValue().equals(keyValue[0])) {
+ return castStringLikeLiteral(first, keyValue[1]);
+ }
+ }
+ }
+ return castStringLikeLiteral(first, "");
+ }
+
+ /**
+ * Executable arithmetic functions quote
+ */
+ @ExecFunction(name = "quote", argTypes = {"VARCHAR"}, returnType =
"VARCHAR")
+ public static Expression quote(StringLikeLiteral first) {
+ return castStringLikeLiteral(first, "\'" + first.getValue() + "\'");
+ }
+
+ /**
+ * Executable arithmetic functions replaceEmpty
+ */
+ @ExecFunction(name = "replace_empty", argTypes = {"VARCHAR", "VARCHAR",
"VARCHAR"}, returnType = "VARCHAR")
+ public static Expression replaceEmpty(StringLikeLiteral first,
StringLikeLiteral second, StringLikeLiteral third) {
+ return castStringLikeLiteral(first,
first.getValue().replace(second.getValue(), third.getValue()));
+ }
+
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Field.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Field.java
index ea454178c7c..25bee5e40a4 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Field.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Field.java
@@ -50,19 +50,21 @@ public class Field extends ScalarFunction
implements ExplicitlyCastableSignature, PropagateNullable {
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(TinyIntType.INSTANCE),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(SmallIntType.INSTANCE),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(IntegerType.INSTANCE),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(BigIntType.INSTANCE),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(LargeIntType.INSTANCE),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(FloatType.INSTANCE),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(DoubleType.INSTANCE),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(DecimalV2Type.SYSTEM_DEFAULT),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(DecimalV3Type.WILDCARD),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(DateV2Type.INSTANCE),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(DateTimeV2Type.SYSTEM_DEFAULT),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(VarcharType.SYSTEM_DEFAULT),
-
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(StringType.INSTANCE)
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(TinyIntType.INSTANCE,
TinyIntType.INSTANCE),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(SmallIntType.INSTANCE,
SmallIntType.INSTANCE),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(IntegerType.INSTANCE,
IntegerType.INSTANCE),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(BigIntType.INSTANCE,
BigIntType.INSTANCE),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(LargeIntType.INSTANCE,
LargeIntType.INSTANCE),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(FloatType.INSTANCE,
FloatType.INSTANCE),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(DoubleType.INSTANCE,
DoubleType.INSTANCE),
+ FunctionSignature.ret(IntegerType.INSTANCE)
+ .varArgs(DecimalV2Type.SYSTEM_DEFAULT,
DecimalV2Type.SYSTEM_DEFAULT),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(DecimalV3Type.WILDCARD,
DecimalV3Type.WILDCARD),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(DateV2Type.INSTANCE,
DateV2Type.INSTANCE),
+ FunctionSignature.ret(IntegerType.INSTANCE)
+ .varArgs(DateTimeV2Type.SYSTEM_DEFAULT,
DateTimeV2Type.SYSTEM_DEFAULT),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(VarcharType.SYSTEM_DEFAULT,
VarcharType.SYSTEM_DEFAULT),
+
FunctionSignature.ret(IntegerType.INSTANCE).varArgs(StringType.INSTANCE,
StringType.INSTANCE)
);
/**
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Repeat.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Repeat.java
index b85a812197f..5ed3b20ddb4 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Repeat.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Repeat.java
@@ -25,6 +25,7 @@ import
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.IntegerType;
import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.VarcharType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -38,6 +39,7 @@ public class Repeat extends ScalarFunction
implements BinaryExpression, ExplicitlyCastableSignature,
AlwaysNullable {
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+
FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(VarcharType.SYSTEM_DEFAULT,
IntegerType.INSTANCE),
FunctionSignature.ret(StringType.INSTANCE).args(StringType.INSTANCE,
IntegerType.INSTANCE)
);
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ArrayContainsToArrayOverlapTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ArrayContainsToArrayOverlapTest.java
index 1ef76c14347..028d85ce097 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ArrayContainsToArrayOverlapTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ArrayContainsToArrayOverlapTest.java
@@ -19,7 +19,6 @@ package org.apache.doris.nereids.rules.rewrite;
import org.apache.doris.nereids.rules.expression.ExpressionRewriteTestHelper;
import org.apache.doris.nereids.trees.expressions.And;
-import org.apache.doris.nereids.trees.expressions.EqualTo;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Or;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.ArraysOverlap;
@@ -74,9 +73,7 @@ class ArrayContainsToArrayOverlapTest extends
ExpressionRewriteTestHelper {
.getPlan();
Expression expression = plan.child(0).getExpressions().get(0).child(0);
Assertions.assertTrue(expression instanceof Or);
- Assertions.assertTrue(expression.child(0) instanceof Or);
- Assertions.assertTrue(expression.child(0).child(0) instanceof
ArraysOverlap);
- Assertions.assertTrue(expression.child(0).child(1) instanceof EqualTo);
+ Assertions.assertTrue(expression.child(0) instanceof ArraysOverlap);
Assertions.assertTrue(expression.child(1) instanceof And);
}
diff --git
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy
index eb816ecb73f..49e53cd94e3 100644
---
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy
+++
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy
@@ -1384,6 +1384,20 @@ class Suite implements GroovyInterceptable {
Assert.assertEquals("FINISHED", result)
}
+ void testFoldConst(String foldSql) {
+ String openFoldConstant = "set debug_skip_fold_constant=false";
+ sql(openFoldConstant)
+ logger.info(foldSql)
+ List<List<Object>> resultByFoldConstant = sql(foldSql)
+ logger.info("result by fold constant: " +
resultByFoldConstant.toString())
+ String closeFoldConstant = "set debug_skip_fold_constant=true";
+ sql(closeFoldConstant)
+ logger.info(foldSql)
+ List<List<Object>> resultExpected = sql(foldSql)
+ logger.info("result expected: " + resultExpected.toString())
+ Assert.assertEquals(resultExpected, resultByFoldConstant)
+ }
+
String getJobName(String dbName, String mtmvName) {
String showMTMV = "select JobName from
mv_infos('database'='${dbName}') where Name = '${mtmvName}'";
logger.info(showMTMV)
diff --git
a/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_by_be.groovy
b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_by_be.groovy
index a8ec9f45def..809b8e8b291 100644
---
a/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_by_be.groovy
+++
b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_by_be.groovy
@@ -53,4 +53,4 @@ suite("fold_constant_by_be") {
sql 'set query_timeout=12;'
qt_sql "select sleep(sign(1)*5);"
-}
\ No newline at end of file
+}
diff --git
a/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_string_arithmatic.groovy
b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_string_arithmatic.groovy
new file mode 100644
index 00000000000..2bcdfc2fd24
--- /dev/null
+++
b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_string_arithmatic.groovy
@@ -0,0 +1,687 @@
+// 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.
+
+suite("fold_constant_string_arithmatic") {
+ def db = "fold_constant_string_arithmatic"
+ sql "create database if not exists ${db}"
+
+ sql "set enable_nereids_planner=true"
+ sql "set enable_fallback_to_original_planner=false"
+ sql "set enable_fold_constant_by_be=false"
+
+ testFoldConst("SELECT Concat('Hello', ' ', 'World')")
+ testFoldConst("SELECT Substring('Hello World', 1, 5)")
+ testFoldConst("SELECT Substring('1', 1, 1)")
+ testFoldConst("select 100, 'abc', substring('abc', 1, 2),
substring(substring('abcdefg', 4, 3), 1, 2), null")
+ testFoldConst("SELECT Length('Hello World')")
+ testFoldConst("SELECT Lower('Hello World')")
+ testFoldConst("SELECT Upper('Hello World')")
+ testFoldConst("SELECT Trim(' Hello World ')")
+ testFoldConst("SELECT Trim('11111', 11)")
+ testFoldConst("SELECT Ltrim(' Hello World ')")
+ testFoldConst("SELECT LTrim(' 11111', 11)")
+ testFoldConst("SELECT LTrim('11111 ', 11)")
+ testFoldConst("SELECT Rtrim(' Hello World ')")
+ testFoldConst("SELECT RTrim('11111 ', 11)")
+ testFoldConst("SELECT RTrim(' 11111', 11)")
+ testFoldConst("SELECT Replace('Hello World', 'World', 'Everyone')")
+ testFoldConst("SELECT Left('Hello World', 5)")
+ testFoldConst("SELECT Right('Hello World', 5)")
+ testFoldConst("SELECT Locate('World', 'Hello World')")
+ testFoldConst("SELECT Instr('Hello World', 'World')")
+ testFoldConst("SELECT Ascii('A')")
+ testFoldConst("SELECT Bin(5)")
+ testFoldConst("SELECT Hex(255)")
+ testFoldConst("SELECT Unhex('FF')")
+ testFoldConst("SELECT Concat_Ws('-', '2024', '09', '02')")
+ testFoldConst("SELECT Char(65)")
+ testFoldConst("SELECT Character_Length('Hello World')")
+ testFoldConst("SELECT Initcap('hello world')")
+ testFoldConst("SELECT Md5('Hello World')")
+ testFoldConst("SELECT Md5Sum('Hello World')")
+// testFoldConst("SELECT JsonExtract('{"key": "value"}', '$.key')")
+// testFoldConst("SELECT JsonbExtractString('{"key": "value"}', '$.key')")
+// testFoldConst("SELECT JsonContains('{"key": "value"}', '"key"')")
+// testFoldConst("SELECT JsonLength('{"key1": "value1", "key2":
"value2"}')")
+// testFoldConst("SELECT JsonObject('key', 'value')")
+// testFoldConst("SELECT JsonArray('value1', 'value2')")
+// testFoldConst("SELECT JsonKeys('{"key1": "value1", "key2": "value2"}')")
+// testFoldConst("SELECT JsonInsert('{"key1": "value1"}', '$.key2',
'value2')")
+// testFoldConst("SELECT JsonReplace('{"key1": "value1"}', '$.key1',
'new_value')")
+// testFoldConst("SELECT JsonSet('{"key1": "value1"}', '$.key2',
'value2')")
+// testFoldConst("SELECT Json_Quote('Hello World')")
+// testFoldConst("SELECT Json_UnQuote('"Hello World"')")
+ testFoldConst("SELECT Field('b', 'a', 'b', 'c')")
+ testFoldConst("SELECT Find_In_Set('b', 'a,b,c')")
+ testFoldConst("SELECT Repeat('Hello', 3)")
+ testFoldConst("SELECT Reverse('Hello')")
+ testFoldConst("SELECT length(Space(10))")
+// testFoldConst("SELECT Split_By_Char('a,b,c',',')") has bug in be
execution
+ testFoldConst("SELECT Split_By_String('a::b::c', '::')")
+ testFoldConst("SELECT Split_Part('a,b,c', ',', 2)")
+ testFoldConst("SELECT Substring_Index('a,b,c', ',', 2)")
+ testFoldConst("SELECT Strcmp('abc', 'abd')")
+ testFoldConst("SELECT StrLeft('Hello World', 5)")
+ testFoldConst("SELECT StrRight('Hello World', 5)")
+ testFoldConst("SELECT Overlay('abcdef', '123', 3, 2)")
+ testFoldConst("SELECT Parse_Url('http://www.example.com/path?query=abc',
'HOST')")
+ testFoldConst("SELECT Url_Decode('%20Hello%20World%20')")
+
+ // Substring with negative start index
+ // Expected behavior: Depending on the SQL engine, might return an empty
string or error.
+ testFoldConst("SELECT Substring('Hello World', -1, 5)")
+
+ // Substring with length exceeding the string length
+ // Expected behavior: Return 'Hello' as the length exceeds the string
length.
+ testFoldConst("SELECT Substring('Hello', 1, 10)")
+
+ // Left with length greater than string length
+ // Expected behavior: Return 'Hello'.
+ testFoldConst("SELECT Left('Hello', 10)")
+
+ // Right with length greater than string length
+ // Expected behavior: Return 'Hello'.
+ testFoldConst("SELECT Right('Hello', 10)")
+
+ // SplitPart with part number greater than the number of parts
+ // Expected behavior: Return an empty string or error.
+ testFoldConst("SELECT Split_Part('a,b,c', ',', 5)")
+
+ // SplitPart with negative part number
+ // Expected behavior: Return an empty string or error.
+ testFoldConst("SELECT Split_Part('a,b,c', ',', -1)")
+
+ // Locate with the substring not present
+ // Expected behavior: Return 0 as 'World' is not found.
+ testFoldConst("SELECT Locate('World', 'Hello')")
+
+ // Instr with the substring not present
+ // Expected behavior: Return 0 as 'World' is not found.
+ testFoldConst("SELECT Instr('Hello', 'World')")
+
+ // Replace with an empty search string
+ // Expected behavior: Some SQL engines may treat this as a no-op, others
might throw an error.
+ testFoldConst("SELECT Replace('Hello World', '', 'Everyone')")
+
+ // Replace with an empty replacement string
+ // Expected behavior: Return 'Hello '.
+ testFoldConst("SELECT Replace('Hello World', 'World', '')")
+
+ // Concat with NULL values
+ // Expected behavior: Depending on the SQL engine, may return 'HelloWorld'
or NULL.
+ testFoldConst("SELECT Concat('Hello', NULL, 'World')")
+
+ // Ltrim with a string that has no leading spaces
+ // Expected behavior: Return 'Hello'.
+ testFoldConst("SELECT Ltrim('Hello')")
+
+ // Rtrim with a string that has no trailing spaces
+ // Expected behavior: Return 'Hello'.
+ testFoldConst("SELECT Rtrim('Hello')")
+
+ // JsonExtract with an invalid JSON path
+ // Expected behavior: Return NULL or an empty string.
+// testFoldConst("SELECT Json_Extract('{"key": "value"}', '$.invalid')")
+
+ // JsonLength with a non-JSON string
+ // Expected behavior: Return NULL or error.
+ testFoldConst("SELECT Json_Length('Hello World')")
+
+ // Field with a value not present in the list
+ // Expected behavior: Return 0 as 'd' is not found.
+ testFoldConst("SELECT Field('d', 'a', 'b', 'c')")
+
+ // FindInSet with a value not present in the set
+ // Expected behavior: Return 0 as 'd' is not found.
+ testFoldConst("SELECT Find_In_Set('d', 'a,b,c')")
+
+ // Repeat with a negative repeat count
+ // Expected behavior: Return an empty string or error.
+ testFoldConst("SELECT Repeat('Hello', -3)")
+
+ // Space with a negative number of spaces
+ // Expected behavior: Return an empty string or error.
+ testFoldConst("SELECT Space(-5)")
+
+ // SplitByChar with a delimiter not present in the string
+ // Expected behavior: Return the original string in a single element array.
+// testFoldConst("SELECT Split_By_Char('abc', ',')")
+
+ // SplitByString with a delimiter not present in the string
+ // Expected behavior: Return the original string in a single element array.
+ testFoldConst("SELECT Split_By_String('::', 'abc')")
+
+ // Strcmp with two identical strings
+ // Expected behavior: Return 0 as the strings are equal.
+ testFoldConst("SELECT Strcmp('abc', 'abc')")
+
+ // Strcmp with a null string
+ // Expected behavior: Return NULL or -1 depending on the SQL engine.
+ testFoldConst("SELECT Strcmp('abc', NULL)")
+
+ // Hex with a negative number
+ // Expected behavior: Return the hexadecimal representation of the two's
complement, or an error depending on the SQL engine.
+ testFoldConst("SELECT Hex(-255)")
+
+ // Unhex with an invalid hexadecimal string
+ // Expected behavior: Return NULL or error as 'GHIJ' is not a valid hex
string.
+ testFoldConst("SELECT Unhex('GHIJ')")
+
+ // JsonReplace with a path that does not exist
+ // Expected behavior: Depending on the engine, might return the original
JSON or an error.
+// testFoldConst("SELECT Json_Replace('{"key": "value"}', '$.nonexistent',
'new_value')")
+
+ // UrlDecode with an invalid percent-encoded string
+ // Expected behavior: Return NULL or error due to invalid encoding.
+ testFoldConst("SELECT Url_Decode('%ZZHello%20World')")
+
+ testFoldConst("select elt(0, \"hello\", \"doris\")")
+ testFoldConst("select elt(1, \"hello\", \"doris\")")
+ testFoldConst("select elt(2, \"hello\", \"doris\")")
+ testFoldConst("select elt(3, \"hello\", \"doris\")")
+ testFoldConst("select c1, c2, elt(c1, c2) from (select number as c1,
'varchar' as c2 from numbers('number'='5') where number > 0) a")
+
+ testFoldConst("select append_trailing_char_if_absent('a','c')")
+ testFoldConst("select append_trailing_char_if_absent('ac','c')")
+
+ testFoldConst("select ascii('1')")
+ testFoldConst("select ascii('a')")
+ testFoldConst("select ascii('A')")
+ testFoldConst("select ascii('!')")
+
+ testFoldConst("select bit_length(\"abc\")")
+
+ testFoldConst("select char_length(\"abc\")")
+
+ testFoldConst("select concat(\"a\", \"b\")")
+ testFoldConst("select concat(\"a\", \"b\", \"c\")")
+ testFoldConst("select concat(\"a\", null, \"c\")")
+
+ testFoldConst("select concat_ws(\"or\", \"d\", \"is\")")
+ testFoldConst("select concat_ws(NULL, \"d\", \"is\")")
+ testFoldConst("select concat_ws(\"or\", \"d\", NULL,\"is\")")
+ testFoldConst("select concat_ws(\"or\", [\"d\", \"is\"])")
+ testFoldConst("select concat_ws(NULL, [\"d\", \"is\"])")
+ testFoldConst("select concat_ws(\"or\", [\"d\", NULL,\"is\"])")
+ testFoldConst("select concat_ws(\"or\", [\"d\", \"\",\"is\"])")
+
+ testFoldConst("select ends_with(\"Hello doris\", \"doris\")")
+ testFoldConst("select ends_with(\"Hello doris\", \"Hello\")")
+
+ testFoldConst("select find_in_set(\"b\", \"a,b,c\")")
+ testFoldConst("select find_in_set(\"d\", \"a,b,c\")")
+ testFoldConst("select find_in_set(null, \"a,b,c\")")
+ testFoldConst("select find_in_set(\"a\", null)")
+
+ testFoldConst("select hex('1')")
+ testFoldConst("select hex('12')")
+ testFoldConst("select hex('@')")
+ testFoldConst("select hex('A')")
+ testFoldConst("select hex(12)")
+ testFoldConst("select hex(-1)")
+ testFoldConst("select hex('hello,doris')")
+
+ testFoldConst("select unhex('@')")
+ testFoldConst("select unhex('68656C6C6F2C646F726973')")
+ testFoldConst("select unhex('41')")
+ testFoldConst("select unhex('4142')")
+ testFoldConst("select unhex('')")
+ testFoldConst("select unhex(NULL)")
+
+ testFoldConst("select instr(\"abc\", \"b\")")
+ testFoldConst("select instr(\"abc\", \"d\")")
+ testFoldConst("select instr(\"abc\", null)")
+ testFoldConst("select instr(null, \"a\")")
+ testFoldConst("SELECT instr('foobar', '')")
+ testFoldConst("SELECT instr('上海天津北京杭州', '北京')")
+
+ testFoldConst("SELECT lcase(\"AbC123\")")
+ testFoldConst("SELECT lower(\"AbC123\")")
+
+ testFoldConst("SELECT initcap(\"AbC123abc abc.abc,?|abc\")")
+
+ testFoldConst("select left(\"Hello doris\",5)")
+ testFoldConst("select right(\"Hello doris\",5)")
+
+ testFoldConst("select length(\"abc\")")
+
+ testFoldConst("SELECT LOCATE('bar', 'foobarbar')")
+ testFoldConst("SELECT LOCATE('xbar', 'foobar')")
+ testFoldConst("SELECT LOCATE('', 'foobar')")
+ testFoldConst("SELECT LOCATE('北京', '上海天津北京杭州')")
+
+ testFoldConst("SELECT lpad(\"hi\", 5, \"xy\")")
+ testFoldConst("SELECT lpad(\"hi\", 1, \"xy\")")
+ testFoldConst("SELECT rpad(\"hi\", 5, \"xy\")")
+ testFoldConst("SELECT rpad(\"hi\", 1, \"xy\")")
+
+ testFoldConst("SELECT ltrim(' ab d')")
+
+ testFoldConst("select money_format(17014116)")
+ testFoldConst("select money_format(1123.456)")
+ testFoldConst("select money_format(1123.4)")
+ testFoldConst("select money_format(truncate(1000,10))")
+
+ testFoldConst("select null_or_empty(null)")
+ testFoldConst("select null_or_empty(\"\")")
+ testFoldConst("select null_or_empty(\"a\")")
+
+ testFoldConst("select not_null_or_empty(null)")
+ testFoldConst("select not_null_or_empty(\"\")")
+ testFoldConst("select not_null_or_empty(\"a\")")
+
+ testFoldConst("SELECT repeat(\"a\", 3)")
+ testFoldConst("SELECT repeat(\"a\", -1)")
+ testFoldConst("SELECT repeat(\"a\", 0)")
+ testFoldConst("SELECT repeat(\"a\",null)")
+ testFoldConst("SELECT repeat(null,1)")
+
+ testFoldConst("select replace(\"https://doris.apache.org:9090\",
\":9090\", \"\")")
+ testFoldConst("select replace(\"https://doris.apache.org:9090\", \"\",
\"new_str\")")
+
+ testFoldConst("SELECT REVERSE('hello')")
+
+ testFoldConst("select split_part('hello world', ' ', 1)")
+ testFoldConst("select split_part('hello world', ' ', 2)")
+ testFoldConst("select split_part('hello world', ' ', 0)")
+ testFoldConst("select split_part('hello world', ' ', -1)")
+ testFoldConst("select split_part('hello world', ' ', -2)")
+ testFoldConst("select split_part('hello world', ' ', -3)")
+ testFoldConst("select split_part('abc##123###xyz', '##', 0)")
+ testFoldConst("select split_part('abc##123###xyz', '##', 1)")
+ testFoldConst("select split_part('abc##123###xyz', '##', 3)")
+ testFoldConst("select split_part('abc##123###xyz', '##', 5)")
+ testFoldConst("select split_part('abc##123###xyz', '##', -1)")
+ testFoldConst("select split_part('abc##123###xyz', '##', -2)")
+ testFoldConst("select split_part('abc##123###xyz', '##', -4)")
+
+ testFoldConst("select starts_with(\"hello world\",\"hello\")")
+ testFoldConst("select starts_with(\"hello world\",\"world\")")
+ testFoldConst("select starts_with(\"hello world\",null)")
+
+ testFoldConst("select strleft(NULL, 1)")
+ testFoldConst("select strleft(\"good morning\", NULL)")
+ testFoldConst("select left(NULL, 1)")
+ testFoldConst("select left(\"good morning\", NULL)")
+ testFoldConst("select strleft(\"Hello doris\", 5)")
+ testFoldConst("select left(\"Hello doris\", 5)")
+ testFoldConst("select strright(NULL, 1)")
+ testFoldConst("select strright(\"good morning\", NULL)")
+ testFoldConst("select right(NULL, 1)")
+ testFoldConst("select right(\"good morning\", NULL)")
+ testFoldConst("select strright(\"Hello doris\", 5)")
+ testFoldConst("select right(\"Hello doris\", 5)")
+ testFoldConst("select strleft(\"good morning\", 120)")
+ testFoldConst("select strleft(\"good morning\", -5)")
+ testFoldConst("select strright(\"Hello doris\", 120)")
+ testFoldConst("select strright(\"Hello doris\", -5)")
+ testFoldConst("select left(\"good morning\", 120)")
+ testFoldConst("select left(\"good morning\", -5)")
+ testFoldConst("select right(\"Hello doris\", 120)")
+ testFoldConst("select right(\"Hello doris\", -6)")
+
+ testFoldConst("select substring('abc1', 2)")
+ testFoldConst("select substring('abc1', -2)")
+ testFoldConst("select substring('abc1', 5)")
+ testFoldConst("select substring('abc1def', 2, 2)")
+ testFoldConst("select substring('abcdef',3,-1)")
+ testFoldConst("select substring('abcdef',-3,-1)")
+ testFoldConst("select substring('abcdef',10,1)")
+
+ testFoldConst("select substr('a',3,1)")
+ testFoldConst("select substr('a',2,1)")
+ testFoldConst("select substr('a',1,1)")
+ testFoldConst("select substr('a',0,1)")
+ testFoldConst("select substr('a',-1,1)")
+ testFoldConst("select substr('a',-2,1)")
+ testFoldConst("select substr('a',-3,1)")
+ testFoldConst("select substr('abcdef',3,-1)")
+ testFoldConst("select substr('abcdef',-3,-1)")
+
+ testFoldConst("select sub_replace(\"this is origin str\",\"NEW-STR\",1)")
+ testFoldConst("select sub_replace(\"doris\",\"***\",1,2)")
+
+ testFoldConst("select substring_index(\"hello world\", \" \", 1)")
+ testFoldConst("select substring_index(\"hello world\", \" \", 2)")
+ testFoldConst("select substring_index(\"hello world\", \" \", 3)")
+ testFoldConst("select substring_index(\"hello world\", \" \", -1)")
+ testFoldConst("select substring_index(\"hello world\", \" \", -2)")
+ testFoldConst("select substring_index(\"hello world\", \" \", -3)")
+ testFoldConst("select substring_index(\"prefix__string2\", \"__\", 2)")
+ testFoldConst("select substring_index(\"prefix__string2\", \"_\", 2)")
+ testFoldConst("select substring_index(\"prefix_string2\", \"__\", 1)")
+ testFoldConst("select substring_index(null, \"__\", 1)")
+ testFoldConst("select substring_index(\"prefix_string\", null, 1)")
+ testFoldConst("select substring_index(\"prefix_string\", \"_\", null)")
+ testFoldConst("select substring_index(\"prefix_string\", \"__\", -1)")
+
+ testFoldConst("select elt(0, \"hello\", \"doris\")")
+ testFoldConst("select elt(1, \"hello\", \"doris\")")
+ testFoldConst("select elt(2, \"hello\", \"doris\")")
+ testFoldConst("select elt(3, \"hello\", \"doris\")")
+
+ testFoldConst("select sub_replace(\"this is origin str\",\"NEW-STR\",1)")
+ testFoldConst("select sub_replace(\"doris\",\"***\",1,2)")
+
+ testFoldConst("select strcmp('a', 'abc')")
+ testFoldConst("select strcmp('abc', 'abc')")
+ testFoldConst("select strcmp('abcd', 'abc')")
+
+ testFoldConst("SELECT Concat(cast('Hello' as string), cast(' ' as string),
cast('World' as string))")
+ testFoldConst("SELECT Substring(cast('Hello World' as string), 1, 5)")
+ testFoldConst("SELECT Substring(cast('1' as string), 1, 1)")
+ testFoldConst("SELECT 100, cast('abc' as string), Substring(cast('abc' as
string), 1, 2), Substring(Substring(cast('abcdefg' as string), 4, 3), 1, 2),
null")
+ testFoldConst("SELECT Length(cast('Hello World' as string))")
+ testFoldConst("SELECT Lower(cast('Hello World' as string))")
+ testFoldConst("SELECT Upper(cast('Hello World' as string))")
+ testFoldConst("SELECT Trim(cast(' Hello World ' as string))")
+ testFoldConst("SELECT Trim(cast('11111' as string), cast(11 as string))")
+ testFoldConst("SELECT Ltrim(cast(' Hello World ' as string))")
+ testFoldConst("SELECT LTrim(cast(' 11111' as string), cast(11 as string))")
+ testFoldConst("SELECT LTrim(cast('11111 ' as string), cast(11 as string))")
+ testFoldConst("SELECT Rtrim(cast(' Hello World ' as string))")
+ testFoldConst("SELECT RTrim(cast('11111 ' as string), cast(11 as string))")
+ testFoldConst("SELECT RTrim(cast(' 11111' as string), cast(11 as string))")
+ testFoldConst("SELECT Replace(cast('Hello World' as string), cast('World'
as string), cast('Everyone' as string))")
+ testFoldConst("SELECT Left(cast('Hello World' as string), 5)")
+ testFoldConst("SELECT Right(cast('Hello World' as string), 5)")
+ testFoldConst("SELECT Locate(cast('World' as string), cast('Hello World'
as string))")
+ testFoldConst("SELECT Instr(cast('Hello World' as string), cast('World' as
string))")
+ testFoldConst("SELECT Ascii(cast('A' as string))")
+ testFoldConst("SELECT Bin(5)")
+ testFoldConst("SELECT Hex(255)")
+ testFoldConst("SELECT Unhex(cast('FF' as string))")
+// testFoldConst("SELECT Concat_Ws(cast('-' as string), cast('2024' as
string), cast('09' as string), cast('02' as string))")
+ testFoldConst("SELECT Char(65)")
+ testFoldConst("SELECT Character_Length(cast('Hello World' as string))")
+ testFoldConst("SELECT Initcap(cast('hello world' as string))")
+ testFoldConst("SELECT Md5(cast('Hello World' as string))")
+// testFoldConst("SELECT Md5Sum(cast('Hello World' as string))")
+// testFoldConst("SELECT JsonExtract(cast('{\"key\": \"value\"}' as string),
cast('$.key' as string))")
+// testFoldConst("SELECT JsonbExtractString(cast('{\"key\": \"value\"}' as
string), cast('$.key' as string))")
+// testFoldConst("SELECT JsonContains(cast('{\"key\": \"value\"}' as string),
cast('\"key\"' as string))")
+// testFoldConst("SELECT JsonLength(cast('{\"key1\": \"value1\", \"key2\":
\"value2\"}' as string))")
+// testFoldConst("SELECT JsonObject(cast('key' as string), cast('value' as
string))")
+// testFoldConst("SELECT JsonArray(cast('value1' as string), cast('value2' as
string))")
+// testFoldConst("SELECT JsonKeys(cast('{\"key1\": \"value1\", \"key2\":
\"value2\"}' as string))")
+// testFoldConst("SELECT JsonInsert(cast('{\"key1\": \"value1\"}' as string),
cast('$.key2' as string), cast('value2' as string))")
+// testFoldConst("SELECT JsonReplace(cast('{\"key1\": \"value1\"}' as string),
cast('$.key1' as string), cast('new_value' as string))")
+// testFoldConst("SELECT JsonSet(cast('{\"key1\": \"value1\"}' as string),
cast('$.key2' as string), cast('value2' as string))")
+// testFoldConst("SELECT Json_Quote(cast('Hello World' as string))")
+// testFoldConst("SELECT Json_UnQuote(cast('\"Hello World\"' as string))")
+// testFoldConst("SELECT Field(cast('b' as string), cast('a' as string),
cast('b' as string), cast('c' as string))")
+ testFoldConst("SELECT Find_In_Set(cast('b' as string), cast('a,b,c' as
string))")
+ testFoldConst("SELECT Repeat(cast('Hello' as string), 3)")
+ testFoldConst("SELECT Reverse(cast('Hello' as string))")
+ testFoldConst("SELECT length(Space(10))")
+// testFoldConst("SELECT Split_By_Char(cast('a,b,c' as string), cast(',' as
string))") has bug in be execution
+ testFoldConst("SELECT Split_By_String(cast('a::b::c' as string), cast('::'
as string))")
+ testFoldConst("SELECT Split_Part(cast('a,b,c' as string), cast(',' as
string), 2)")
+ testFoldConst("SELECT Substring_Index(cast('a,b,c' as string), cast(',' as
string), 2)")
+ testFoldConst("SELECT Strcmp(cast('abc' as string), cast('abd' as
string))")
+ testFoldConst("SELECT StrLeft(cast('Hello World' as string), 5)")
+ testFoldConst("SELECT StrRight(cast('Hello World' as string), 5)")
+ testFoldConst("SELECT Overlay(cast('abcdef' as string), cast('123' as
string), 3, 2)")
+ testFoldConst("SELECT
Parse_Url(cast('http://www.example.com/path?query=abc' as string), cast('HOST'
as string))")
+ testFoldConst("SELECT Url_Decode(cast('%20Hello%20World%20' as string))")
+
+// Substring with negative start index
+// Expected behavior: Depending on the SQL engine, might return an empty
string or error.
+ testFoldConst("SELECT Substring(cast('Hello World' as string), -1, 5)")
+
+// Substring with length exceeding the string length
+// Expected behavior: Return 'Hello' as the length exceeds the string length.
+ testFoldConst("SELECT Substring(cast('Hello' as string), 1, 10)")
+
+// Left with length greater than string length
+// Expected behavior: Return 'Hello'.
+ testFoldConst("SELECT Left(cast('Hello' as string), 10)")
+
+// Right with length greater than string length
+// Expected behavior: Return 'Hello'.
+ testFoldConst("SELECT Right(cast('Hello' as string), 10)")
+
+// SplitPart with part number greater than the number of parts
+// Expected behavior: Return an empty string or error.
+ testFoldConst("SELECT Split_Part(cast('a,b,c' as string), cast(',' as
string), 5)")
+
+// SplitPart with negative part number
+// Expected behavior: Return an empty string or error.
+ testFoldConst("SELECT Split_Part(cast('a,b,c' as string), cast(',' as
string), -1)")
+
+// Locate with the substring not present
+// Expected behavior: Return 0 as 'World' is not found.
+ testFoldConst("SELECT Locate(cast('World' as string), cast('Hello' as
string))")
+
+// Instr with the substring not present
+// Expected behavior: Return 0 as 'World' is not found.
+ testFoldConst("SELECT Instr(cast('Hello' as string), cast('World' as
string))")
+
+// Replace with an empty search string
+// Expected behavior: Some SQL engines may treat this as a no-op, others might
throw an error.
+ testFoldConst("SELECT Replace(cast('Hello World' as string), '',
cast('Everyone' as string))")
+
+// Replace with an empty replacement string
+// Expected behavior: Return 'Hello '.
+ testFoldConst("SELECT Replace(cast('Hello World' as string), cast('World'
as string), '')")
+
+// Concat with NULL values
+// Expected behavior: Depending on the SQL engine, may return 'HelloWorld' or
NULL.
+ testFoldConst("SELECT Concat(cast('Hello' as string), NULL, cast('World'
as string))")
+
+// Ltrim with a string that has no leading spaces
+// Expected behavior: Return 'Hello'.
+ testFoldConst("SELECT Ltrim(cast('Hello' as string))")
+
+// Rtrim with a string that has no trailing spaces
+// Expected behavior: Return 'Hello'.
+ testFoldConst("SELECT Rtrim(cast('Hello' as string))")
+
+// Testing JSON Length function with a non-JSON string
+ testFoldConst("SELECT Json_Length(cast('Hello World' as string))")
+
+// Field with a value not present in the list
+// testFoldConst("SELECT Field(cast('d' as string), cast('a' as string),
cast('b' as string), cast('c' as string))")
+
+// FindInSet with a value not present in the set
+ testFoldConst("SELECT Find_In_Set(cast('d' as string), cast('a,b,c' as
string))")
+
+// Repeat with a negative repeat count
+ testFoldConst("SELECT Repeat(cast('Hello' as string), -3)")
+
+// Space with a negative number of spaces
+ testFoldConst("SELECT Space(-5)")
+
+// SplitByChar with a delimiter not present in the string
+// testFoldConst("SELECT Split_By_Char(cast('abc' as string), cast(',' as
string))")
+
+// SplitByString with a delimiter not present in the string
+ testFoldConst("SELECT Split_By_String(cast('abc' as string), cast('::' as
string))")
+
+// Strcmp with two identical strings
+ testFoldConst("SELECT Strcmp(cast('abc' as string), cast('abc' as
string))")
+
+// Strcmp with a null string
+ testFoldConst("SELECT Strcmp(cast('abc' as string), NULL)")
+
+// Hex with a negative number
+ testFoldConst("SELECT Hex(-255)")
+
+// Unhex with an invalid hexadecimal string
+ testFoldConst("SELECT Unhex(cast('GHIJ' as string))")
+
+// UrlDecode with an invalid percent-encoded string
+ testFoldConst("SELECT Url_Decode(cast('%ZZHello%20World' as string))")
+
+// Additional function tests
+ testFoldConst("SELECT Elt(0, cast('hello' as string), cast('doris' as
string))")
+ testFoldConst("SELECT Elt(1, cast('hello' as string), cast('doris' as
string))")
+ testFoldConst("SELECT Elt(2, cast('hello' as string), cast('doris' as
string))")
+ testFoldConst("SELECT Elt(3, cast('hello' as string), cast('doris' as
string))")
+ testFoldConst("SELECT Append_Trailing_Char_If_Absent(cast('a' as string),
cast('c' as string))")
+ testFoldConst("SELECT Append_Trailing_Char_If_Absent(cast('ac' as string),
cast('c' as string))")
+ testFoldConst("SELECT Ascii(cast('1' as string))")
+ testFoldConst("SELECT Ascii(cast('a' as string))")
+ testFoldConst("SELECT Ascii(cast('A' as string))")
+ testFoldConst("SELECT Ascii(cast('!' as string))")
+ testFoldConst("SELECT Bit_Length(cast('abc' as string))")
+ testFoldConst("SELECT Char_Length(cast('abc' as string))")
+ testFoldConst("SELECT Concat(cast('a' as string), cast('b' as string))")
+ testFoldConst("SELECT Concat(cast('a' as string), cast('b' as string),
cast('c' as string))")
+ testFoldConst("SELECT Concat(cast('a' as string), NULL, cast('c' as
string))")
+// testFoldConst("SELECT Concat_Ws(cast('or' as string), cast('d' as
string), cast('is' as string))")
+// testFoldConst("SELECT Concat_Ws(NULL, cast('d' as string), cast('is' as
string))")
+// testFoldConst("SELECT Concat_Ws(cast('or' as string), cast('d' as
string), NULL, cast('is' as string))")
+// testFoldConst("SELECT Concat_Ws(cast('or' as string), cast('d' as
string), cast('' as string), cast('is' as string))")
+ testFoldConst("SELECT Ends_With(cast('Hello doris' as string),
cast('doris' as string))")
+ testFoldConst("SELECT Ends_With(cast('Hello doris' as string),
cast('Hello' as string))")
+ testFoldConst("SELECT Find_In_Set(cast('b' as string), cast('a,b,c' as
string))")
+ testFoldConst("SELECT Find_In_Set(cast('d' as string), cast('a,b,c' as
string))")
+ testFoldConst("SELECT Find_In_Set(NULL, cast('a,b,c' as string))")
+ testFoldConst("SELECT Find_In_Set(cast('a' as string), NULL)")
+ testFoldConst("SELECT Hex(cast('1' as string))")
+ testFoldConst("SELECT Hex(cast('12' as string))")
+ testFoldConst("SELECT Hex(cast('@' as string))")
+ testFoldConst("SELECT Hex(cast('A' as string))")
+ testFoldConst("SELECT Hex(12)")
+ testFoldConst("SELECT Hex(-1)")
+ testFoldConst("SELECT Hex(cast('hello,doris' as string))")
+ testFoldConst("SELECT Unhex(cast('@' as string))")
+ testFoldConst("SELECT Unhex(cast('68656C6C6F2C646F726973' as string))")
+ testFoldConst("SELECT Unhex(cast('41' as string))")
+ testFoldConst("SELECT Unhex(cast('4142' as string))")
+ testFoldConst("SELECT Unhex(cast('' as string))")
+ testFoldConst("SELECT Unhex(NULL)")
+ testFoldConst("SELECT Instr(cast('abc' as string), cast('b' as string))")
+ testFoldConst("SELECT Instr(cast('abc' as string), cast('d' as string))")
+ testFoldConst("SELECT Instr(cast('abc' as string), NULL)")
+ testFoldConst("SELECT Instr(NULL, cast('a' as string))")
+ testFoldConst("SELECT Lcase(cast('AbC123' as string))")
+ testFoldConst("SELECT Lower(cast('AbC123' as string))")
+ testFoldConst("SELECT Initcap(cast('AbC123abc abc.abc,?|abc' as string))")
+ testFoldConst("SELECT Left(cast('Hello doris' as string), 5)")
+ testFoldConst("SELECT Right(cast('Hello doris' as string), 5)")
+ testFoldConst("SELECT Length(cast('abc' as string))")
+ testFoldConst("SELECT LOCATE(cast('bar' as string), cast('foobarbar' as
string))")
+ testFoldConst("SELECT LOCATE(cast('xbar' as string), cast('foobar' as
string))")
+ testFoldConst("SELECT LOCATE(cast('' as string), cast('foobar' as
string))")
+ testFoldConst("SELECT LOCATE(cast('北京' as string), cast('上海天津北京杭州' as
string))")
+ testFoldConst("SELECT Lpad(cast('hi' as string), 5, cast('xy' as string))")
+ testFoldConst("SELECT Lpad(cast('hi' as string), 1, cast('xy' as string))")
+ testFoldConst("SELECT Rpad(cast('hi' as string), 5, cast('xy' as string))")
+ testFoldConst("SELECT Rpad(cast('hi' as string), 1, cast('xy' as string))")
+ testFoldConst("SELECT Ltrim(cast(' ab d' as string))")
+ testFoldConst("SELECT Money_Format(17014116)")
+ testFoldConst("SELECT Money_Format(1123.456)")
+ testFoldConst("SELECT Money_Format(1123.4)")
+ testFoldConst("SELECT Money_Format(Truncate(1000,10))")
+ testFoldConst("SELECT Null_Or_Empty(NULL)")
+ testFoldConst("SELECT Null_Or_Empty(cast('' as string))")
+ testFoldConst("SELECT Null_Or_Empty(cast('a' as string))")
+ testFoldConst("SELECT Not_Null_Or_Empty(NULL)")
+ testFoldConst("SELECT Not_Null_Or_Empty(cast('' as string))")
+ testFoldConst("SELECT Not_Null_Or_Empty(cast('a' as string))")
+ testFoldConst("SELECT Repeat(cast('a' as string), 3)")
+ testFoldConst("SELECT Repeat(cast('a' as string), -1)")
+ testFoldConst("SELECT Repeat(cast('a' as string), 0)")
+ testFoldConst("SELECT Repeat(NULL, 1)")
+ testFoldConst("SELECT Replace(cast('https://doris.apache.org:9090' as
string), cast(':9090' as string), cast('' as string))")
+ testFoldConst("SELECT Replace(cast('https://doris.apache.org:9090' as
string), cast('' as string), cast('new_str' as string))")
+ testFoldConst("SELECT REVERSE(cast('hello' as string))")
+ testFoldConst("SELECT Split_Part(cast('hello world' as string), cast(' '
as string), 1)")
+ testFoldConst("SELECT Split_Part(cast('hello world' as string), cast(' '
as string), 2)")
+ testFoldConst("SELECT Split_Part(cast('hello world' as string), cast(' '
as string), 3)")
+ testFoldConst("SELECT Concat(CAST('Hello' AS STRING), CAST(' ' AS STRING),
CAST('World' AS STRING))")
+ testFoldConst("SELECT Concat(CAST('Hello' AS STRING), CAST(NULL AS
STRING))")
+ testFoldConst("SELECT Concat(CAST(NULL AS STRING), CAST('World' AS
STRING))")
+
+ testFoldConst("SELECT Starts_With(CAST('hello world' AS STRING),
CAST('hello' AS STRING))")
+ testFoldConst("SELECT Starts_With(CAST('hello world' AS STRING),
CAST('world' AS STRING))")
+ testFoldConst("SELECT Starts_With(CAST('hello world' AS STRING), CAST(NULL
AS STRING))")
+
+ testFoldConst("SELECT StrLeft(CAST(NULL AS STRING), 1)")
+ testFoldConst("SELECT StrLeft(CAST('good morning' AS STRING), NULL)")
+ testFoldConst("SELECT Left(CAST(NULL AS STRING), 1)")
+ testFoldConst("SELECT Left(CAST('good morning' AS STRING), NULL)")
+ testFoldConst("SELECT StrLeft(CAST('Hello doris' AS STRING), 5)")
+ testFoldConst("SELECT Left(CAST('Hello doris' AS STRING), 5)")
+ testFoldConst("SELECT StrRight(CAST(NULL AS STRING), 1)")
+ testFoldConst("SELECT StrRight(CAST('good morning' AS STRING), NULL)")
+ testFoldConst("SELECT Right(CAST(NULL AS STRING), 1)")
+ testFoldConst("SELECT Right(CAST('good morning' AS STRING), NULL)")
+ testFoldConst("SELECT StrRight(CAST('Hello doris' AS STRING), 5)")
+ testFoldConst("SELECT Right(CAST('Hello doris' AS STRING), 5)")
+ testFoldConst("SELECT StrLeft(CAST('good morning' AS STRING), 120)")
+ testFoldConst("SELECT StrLeft(CAST('good morning' AS STRING), -5)")
+ testFoldConst("SELECT StrRight(CAST('Hello doris' AS STRING), 120)")
+ testFoldConst("SELECT StrRight(CAST('Hello doris' AS STRING), -5)")
+ testFoldConst("SELECT Left(CAST('good morning' AS STRING), 120)")
+ testFoldConst("SELECT Left(CAST('good morning' AS STRING), -5)")
+ testFoldConst("SELECT Right(CAST('Hello doris' AS STRING), 120)")
+ testFoldConst("SELECT Right(CAST('Hello doris' AS STRING), -6)")
+
+ testFoldConst("SELECT Substring(CAST('abc1' AS STRING), 2)")
+ testFoldConst("SELECT Substring(CAST('abc1' AS STRING), -2)")
+ testFoldConst("SELECT Substring(CAST('abc1' AS STRING), 5)")
+ testFoldConst("SELECT Substring(CAST('abc1def' AS STRING), 2, 2)")
+ testFoldConst("SELECT Substring(CAST('abcdef' AS STRING), 3, -1)")
+ testFoldConst("SELECT Substring(CAST('abcdef' AS STRING), -3, -1)")
+ testFoldConst("SELECT Substring(CAST('abcdef' AS STRING), 10, 1)")
+
+ testFoldConst("SELECT Substr(CAST('a' AS STRING), 3, 1)")
+ testFoldConst("SELECT Substr(CAST('a' AS STRING), 2, 1)")
+ testFoldConst("SELECT Substr(CAST('a' AS STRING), 1, 1)")
+ testFoldConst("SELECT Substr(CAST('a' AS STRING), 0, 1)")
+ testFoldConst("SELECT Substr(CAST('a' AS STRING), -1, 1)")
+ testFoldConst("SELECT Substr(CAST('a' AS STRING), -2, 1)")
+ testFoldConst("SELECT Substr(CAST('a' AS STRING), -3, 1)")
+ testFoldConst("SELECT Substr(CAST('abcdef' AS STRING), 3, -1)")
+ testFoldConst("SELECT Substr(CAST('abcdef' AS STRING), -3, -1)")
+
+ testFoldConst("SELECT Sub_Replace(CAST('this is origin str' AS STRING),
CAST('NEW-STR' AS STRING), 1)")
+ testFoldConst("SELECT Sub_Replace(CAST('doris' AS STRING), CAST('***' AS
STRING), 1, 2)")
+
+ testFoldConst("SELECT Substring_Index(CAST('hello world' AS STRING),
CAST(' ' AS STRING), 1)")
+ testFoldConst("SELECT Substring_Index(CAST('hello world' AS STRING),
CAST(' ' AS STRING), 2)")
+ testFoldConst("SELECT Substring_Index(CAST('hello world' AS STRING),
CAST(' ' AS STRING), 3)")
+ testFoldConst("SELECT Substring_Index(CAST('hello world' AS STRING),
CAST(' ' AS STRING), -1)")
+ testFoldConst("SELECT Substring_Index(CAST('hello world' AS STRING),
CAST(' ' AS STRING), -2)")
+ testFoldConst("SELECT Substring_Index(CAST('hello world' AS STRING),
CAST(' ' AS STRING), -3)")
+ testFoldConst("SELECT Substring_Index(CAST('prefix__string2' AS STRING),
CAST('__' AS STRING), 2)")
+ testFoldConst("SELECT Substring_Index(CAST('prefix__string2' AS STRING),
CAST('_' AS STRING), 2)")
+ testFoldConst("SELECT Substring_Index(CAST('prefix_string2' AS STRING),
CAST('__' AS STRING), 1)")
+ testFoldConst("SELECT Substring_Index(CAST(NULL AS STRING), CAST('__' AS
STRING), 1)")
+ testFoldConst("SELECT Substring_Index(CAST('prefix_string' AS STRING),
CAST(NULL AS STRING), 1)")
+ testFoldConst("SELECT Substring_Index(CAST('prefix_string' AS STRING),
CAST('_' AS STRING), NULL)")
+ testFoldConst("SELECT Substring_Index(CAST('prefix_string' AS STRING),
CAST('__' AS STRING), -1)")
+
+ testFoldConst("SELECT Elt(0, CAST('hello' AS STRING), CAST('doris' AS
STRING))")
+ testFoldConst("SELECT Elt(1, CAST('hello' AS STRING), CAST('doris' AS
STRING))")
+ testFoldConst("SELECT Elt(2, CAST('hello' AS STRING), CAST('doris' AS
STRING))")
+ testFoldConst("SELECT Elt(3, CAST('hello' AS STRING), CAST('doris' AS
STRING))")
+
+ testFoldConst("SELECT Sub_Replace(CAST('this is origin str' AS STRING),
CAST('NEW-STR' AS STRING), 1)")
+ testFoldConst("SELECT Sub_Replace(CAST('doris' AS STRING), CAST('***' AS
STRING), 1, 2)")
+
+ testFoldConst("SELECT StrCmp(CAST('a' AS STRING), CAST('abc' AS STRING))")
+ testFoldConst("SELECT StrCmp(CAST('abc' AS STRING), CAST('abc' AS
STRING))")
+ testFoldConst("SELECT StrCmp(CAST('abcd' AS STRING), CAST('abc' AS
STRING))")
+
+ // fix problem of cast date and time function exception
+ testFoldConst("select ifnull(date_format(CONCAT_WS('', '9999-07', '-00'),
'%Y-%m'),3)")
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]