This is an automated email from the ASF dual-hosted git repository. yiguolei pushed a commit to branch branch-2.1 in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-2.1 by this push: new 98be2cedcf7 branch-2.1: [fix](constant fold)Make sure FE cast double to varchar generate identical result with BE. #50425 (#50548) 98be2cedcf7 is described below commit 98be2cedcf7577cacef7037b1a5410e010cae6c7 Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> AuthorDate: Wed Apr 30 09:17:47 2025 +0800 branch-2.1: [fix](constant fold)Make sure FE cast double to varchar generate identical result with BE. #50425 (#50548) Cherry-picked from #50425 Co-authored-by: James <lijib...@selectdb.com> --- .../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 6014cbbcf35..0f1e3edb2a9 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 @@ -78,6 +78,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; @@ -448,6 +449,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); @@ -473,6 +477,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 faf6f1022f5..7a064e5f0f8 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('你')") @@ -1726,4 +1728,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: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org