This is an automated email from the ASF dual-hosted git repository.
dataroaring pushed a commit to branch branch-3.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.0 by this push:
new f35cc6a5c5d branch-3.0: [fix](constant fold)Make sure FE cast double
to varchar generate identical result with BE. #50425 (#50666)
f35cc6a5c5d is described below
commit f35cc6a5c5db24d347d0ca41bf117d4002c7b74a
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu May 8 09:54:35 2025 +0800
branch-3.0: [fix](constant fold)Make sure FE cast double to varchar
generate identical result with BE. #50425 (#50666)
Cherry-picked from #50425
Co-authored-by: James <[email protected]>
---
.../expression/rules/FoldConstantRuleOnFE.java | 23 +++++
.../trees/expressions/literal/DoubleLiteral.java | 30 +++++++
.../expressions/literal/DoubleLiteralTest.java | 49 +++++++++++
.../fold_constant_string_arithmatic.groovy | 98 ++++++++++++++++++++++
4 files changed, 200 insertions(+)
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 04c94f905fa..2e3b168926c 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
@@ -80,6 +80,7 @@ import
org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
import org.apache.doris.nereids.trees.expressions.literal.DateV2Literal;
+import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
@@ -464,6 +465,9 @@ public class FoldConstantRuleOnFE extends
AbstractExpressionRewriteRule
}
Expression child = cast.child();
DataType dataType = cast.getDataType();
+ if (!safeToCast(cast)) {
+ return cast;
+ }
// todo: process other null case
if (child.isNullLiteral()) {
return new NullLiteral(dataType);
@@ -489,6 +493,25 @@ public class FoldConstantRuleOnFE extends
AbstractExpressionRewriteRule
}
}
+ // Check if the given literal value is safe to cast to the targetType.
+ // We need to guarantee FE cast result is identical with BE cast result.
+ // Otherwise, it's not safe.
+ protected boolean safeToCast(Cast cast) {
+ if (cast == null || cast.child() == null || cast.getDataType() ==
null) {
+ return true;
+ }
+ // Check double type.
+ if (cast.child() instanceof DoubleLiteral &&
cast.getDataType().isStringLikeType()) {
+ Double value = ((DoubleLiteral) cast.child()).getValue();
+ if (value.isInfinite() || value.isNaN()) {
+ return true;
+ }
+ return -1E16 < value && value < 1E16;
+ }
+ // Check other types if needed.
+ return true;
+ }
+
@Override
public Expression visitBoundFunction(BoundFunction boundFunction,
ExpressionRewriteContext context) {
if (!boundFunction.foldable()) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DoubleLiteral.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DoubleLiteral.java
index bc7b356c376..a18f2e377bb 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DoubleLiteral.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DoubleLiteral.java
@@ -49,4 +49,34 @@ public class DoubleLiteral extends FractionalLiteral {
public LiteralExpr toLegacyLiteral() {
return new FloatLiteral(value, Type.DOUBLE);
}
+
+ @Override
+ public String getStringValue() {
+ Double num = getValue();
+ if (Double.isNaN(num)) {
+ return "nan";
+ } else if (Double.isInfinite(num)) {
+ return num > 0 ? "inf" : "-inf";
+ }
+
+ // Use %.17g to format the result,replace 'E' with 'e'
+ String formatted = String.format("%.17g", num).replace('E', 'e');
+
+ // Remove trailing .0 in scientific notation.
+ if (formatted.contains("e")) {
+ String[] parts = formatted.split("e");
+ String mantissa = parts[0];
+ String exponent = parts.length > 1 ? "e" + parts[1] : "";
+ mantissa = mantissa.replaceAll("\\.?0+$", "");
+ if (mantissa.isEmpty()) {
+ mantissa = "0";
+ }
+ formatted = mantissa + exponent;
+ } else if (formatted.contains(".")) {
+ // remove trailing .0 in fixed-point representation
+ formatted = formatted.replaceAll("\\.?0+$", "");
+ }
+
+ return formatted;
+ }
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DoubleLiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DoubleLiteralTest.java
new file mode 100644
index 00000000000..409815d5829
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DoubleLiteralTest.java
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.literal;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class DoubleLiteralTest {
+
+ @Test
+ public void testGetStringValue() {
+ Assertions.assertEquals("0", new DoubleLiteral(0).getStringValue());
+ Assertions.assertEquals("0", new DoubleLiteral(0.0).getStringValue());
+ Assertions.assertEquals("0", new DoubleLiteral(-0).getStringValue());
+ Assertions.assertEquals("1", new DoubleLiteral(1).getStringValue());
+ Assertions.assertEquals("1", new DoubleLiteral(1.0).getStringValue());
+ Assertions.assertEquals("-1", new DoubleLiteral(-1).getStringValue());
+ Assertions.assertEquals("1.554", new
DoubleLiteral(1.554).getStringValue());
+ Assertions.assertEquals("0.338", new
DoubleLiteral(0.338).getStringValue());
+ Assertions.assertEquals("-1", new
DoubleLiteral(-1.0).getStringValue());
+ Assertions.assertEquals("1e+100", new
DoubleLiteral(1e100).getStringValue());
+ Assertions.assertEquals("1e-100", new
DoubleLiteral(1e-100).getStringValue());
+ Assertions.assertEquals("10000000000000000", new
DoubleLiteral(1.0E16).getStringValue());
+ Assertions.assertEquals("-10000000000000000", new
DoubleLiteral(-1.0E16).getStringValue());
+ Assertions.assertEquals("1e+17", new
DoubleLiteral(1.0E17).getStringValue());
+ Assertions.assertEquals("-1e+17", new
DoubleLiteral(-1.0E17).getStringValue());
+ Assertions.assertEquals("0.0001", new
DoubleLiteral(0.0001).getStringValue());
+ Assertions.assertEquals("1e+308", new
DoubleLiteral(1e308).getStringValue());
+ Assertions.assertEquals("-1e+308", new
DoubleLiteral(-1e308).getStringValue());
+ Assertions.assertEquals("inf", new
DoubleLiteral(Double.POSITIVE_INFINITY).getStringValue());
+ Assertions.assertEquals("-inf", new
DoubleLiteral(Double.NEGATIVE_INFINITY).getStringValue());
+ Assertions.assertEquals("nan", new
DoubleLiteral(Double.NaN).getStringValue());
+ }
+}
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
index c231d89b69a..302557c5988 100644
---
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
@@ -394,6 +394,8 @@ suite("fold_constant_string_arithmatic") {
testFoldConst("select left('上海天津北京杭州', 5)")
testFoldConst("select left('上海天津北京杭州', -5)")
testFoldConst("select left('上海天津北京杭州', 0)")
+ testFoldConst("select left('20250409'-10000, 6)")
+
// length
testFoldConst("select length('你')")
@@ -1809,4 +1811,100 @@ suite("fold_constant_string_arithmatic") {
testFoldConst("select split_by_string('a😁a😁a', '')")
testFoldConst("select character_length('a😁a😁a')")
testFoldConst("select replace_empty('a😁a😁a', '', '2')")
+
+ // cast double to string like
+ testFoldConst("select cast(cast(0 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(0 as double) as string)")
+ testFoldConst("select cast(cast(0.0 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(0.0 as double) as string)")
+ testFoldConst("select cast(cast(1 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(1 as double) as string)")
+ testFoldConst("select cast(cast(1.0 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(1.0 as double) as string)")
+ testFoldConst("select cast(cast(0.1 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(0.1 as double) as string)")
+ testFoldConst("select cast(cast(1.1 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(1.1 as double) as string)")
+ testFoldConst("select cast(cast(100000 as double) as string)")
+ testFoldConst("select cast(cast(1000000000000000 as double) as string)")
+ testFoldConst("select cast(cast(10000000000000000 as double) as string)")
+ testFoldConst("select cast(cast(100000000000000000 as double) as string)")
+ testFoldConst("select cast(cast(1000000000000000000 as double) as string)")
+ testFoldConst("select cast(cast(1.888 as double) as string)")
+ testFoldConst("select cast(cast(1.888777888777888 as double) as string)")
+ testFoldConst("select cast(cast(1.8887778887778887 as double) as string)")
+ testFoldConst("select cast(cast(1.888777888777888777 as double) as
string)")
+ testFoldConst("select cast(cast(55556666.888777888777888777 as double) as
string)")
+ testFoldConst("select cast(cast(555566667777.888777888777888777 as double)
as string)")
+ testFoldConst("select cast(cast(5555666677778888.888777888777888777 as
double) as string)")
+ testFoldConst("select cast(cast(55556666777788889.888777888777888777 as
double) as string)")
+ testFoldConst("select cast(cast(55556666777788889999.888777888777888777 as
double) as string)")
+ testFoldConst("select cast(cast(0.001 as double) as string)")
+ testFoldConst("select cast(cast(0.0001 as double) as string)")
+ testFoldConst("select cast(cast(0.00001 as double) as string)")
+ testFoldConst("select cast(cast(0.000001 as double) as string)")
+ testFoldConst("select cast(cast(0.0000001 as double) as string)")
+ testFoldConst("select cast(cast(0.00000001 as double) as string)")
+ testFoldConst("select cast(cast(0.00000001 as double) as string)")
+ testFoldConst("select cast(cast(0.000000000000001 as double) as string)")
+ testFoldConst("select cast(cast(0.0000000000000001 as double) as string)")
+ testFoldConst("select cast(cast(0.00000000000000001 as double) as string)")
+ testFoldConst("select cast(cast(0.000000000000000001 as double) as
string)")
+ testFoldConst("select cast(cast(0.0000000000000000001 as double) as
string)")
+ testFoldConst("select cast(cast(1e308 as double) as string)")
+ testFoldConst("select cast(cast(1e309 as double) as string)")
+ testFoldConst("select cast(cast(1e-308 as double) as string)")
+ testFoldConst("select cast(cast(1e-309 as double) as string)")
+ testFoldConst("select cast(cast(10000000000000001 as double) as string)")
+ testFoldConst("select cast(cast(10000000000000010 as double) as string)")
+ testFoldConst("select cast(cast(10000000000000100 as double) as string)")
+
+ testFoldConst("select cast(cast(-0 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(-0 as double) as string)")
+ testFoldConst("select cast(cast(-0.0 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(-0.0 as double) as string)")
+ testFoldConst("select cast(cast(-1 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(-1 as double) as string)")
+ testFoldConst("select cast(cast(-1.0 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(-1.0 as double) as string)")
+ testFoldConst("select cast(cast(-0.1 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(-0.1 as double) as string)")
+ testFoldConst("select cast(cast(-1.1 as double) as varchar(65533))")
+ testFoldConst("select cast(cast(-1.1 as double) as string)")
+ testFoldConst("select cast(cast(-100000 as double) as string)")
+ testFoldConst("select cast(cast(-1000000000000000 as double) as string)")
+ testFoldConst("select cast(cast(-10000000000000000 as double) as string)")
+ testFoldConst("select cast(cast(-100000000000000000 as double) as string)")
+ testFoldConst("select cast(cast(-1000000000000000000 as double) as
string)")
+ testFoldConst("select cast(cast(-1.888 as double) as string)")
+ testFoldConst("select cast(cast(-1.888777888777888 as double) as string)")
+ testFoldConst("select cast(cast(-1.8887778887778887 as double) as string)")
+ testFoldConst("select cast(cast(-1.888777888777888777 as double) as
string)")
+ testFoldConst("select cast(cast(-55556666.888777888777888777 as double) as
string)")
+ testFoldConst("select cast(cast(-555566667777.888777888777888777 as
double) as string)")
+ testFoldConst("select cast(cast(-5555666677778888.888777888777888777 as
double) as string)")
+ testFoldConst("select cast(cast(-55556666777788889.888777888777888777 as
double) as string)")
+ testFoldConst("select cast(cast(-55556666777788889999.888777888777888777
as double) as string)")
+ testFoldConst("select cast(cast(-0.001 as double) as string)")
+ testFoldConst("select cast(cast(-0.0001 as double) as string)")
+ testFoldConst("select cast(cast(-0.00001 as double) as string)")
+ testFoldConst("select cast(cast(-0.000001 as double) as string)")
+ testFoldConst("select cast(cast(-0.0000001 as double) as string)")
+ testFoldConst("select cast(cast(-0.00000001 as double) as string)")
+ testFoldConst("select cast(cast(-0.00000001 as double) as string)")
+ testFoldConst("select cast(cast(-0.000000000000001 as double) as string)")
+ testFoldConst("select cast(cast(-0.0000000000000001 as double) as string)")
+ testFoldConst("select cast(cast(-0.00000000000000001 as double) as
string)")
+ testFoldConst("select cast(cast(-0.000000000000000001 as double) as
string)")
+ testFoldConst("select cast(cast(-0.0000000000000000001 as double) as
string)")
+ testFoldConst("select cast(cast(-1e308 as double) as string)")
+ testFoldConst("select cast(cast(-1e309 as double) as string)")
+ testFoldConst("select cast(cast(-1e-308 as double) as string)")
+ testFoldConst("select cast(cast(-1e-309 as double) as string)")
+ testFoldConst("select cast(cast(-10000000000000001 as double) as string)")
+ testFoldConst("select cast(cast(-10000000000000010 as double) as string)")
+ testFoldConst("select cast(cast(-10000000000000100 as double) as string)")
+ testFoldConst("select cast(cast('nan' as double) as string)")
+ testFoldConst("select cast(cast('inf' as double) as string)")
+ testFoldConst("select cast(cast('-inf' as double) as string)")
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]