From 2926cdb07f65bbc763273f9559ee7478eab28fce Mon Sep 17 00:00:00 2001 From: LiBinfeng <46676950+LiBinfeng-01@users.noreply.github.com> Date: Mon, 30 Sep 2024 21:06:53 +0800 Subject: [PATCH] [Feat](Nereids) add numeric functions (#40744) add fold constant on fe of numeric functions: Coalesce, Round, Ceil, Floor, Exp, Ln, Log, Log10, Log2, Sqrt, Power, Sin, Cos, Tan, Acos, Asin, Atan, Atan2, Sign, Bin, BitCount, BitLength, Cbrt, Cosh, Tanh, Dexp, Dlog10, Dlog1, Dpow, Dsqrt, Fmod, Fpow, Radians, Degrees, Xor, Pi, E, Conv, Truncate, CountEqual, Pmod. --------- Co-authored-by: libinfeng --- .../apache/doris/analysis/FloatLiteral.java | 3 + .../expressions/ExpressionEvaluator.java | 17 +- .../executable/ExecutableFunctions.java | 115 ---- .../executable/NumericArithmetic.java | 566 +++++++++++++++++- .../expressions/literal/DecimalV3Literal.java | 28 + .../rules/expression/FoldConstantTest.java | 162 +++++ .../functions/ExecutableFunctionsTest.java | 64 -- .../datatype_p0/double/test_double_nan.out | 4 - .../data/datatype_p0/float/test_float_nan.out | 4 - .../datatype_p0/double/test_double_nan.groovy | 13 +- .../datatype_p0/float/test_float_nan.groovy | 12 +- .../scalar_function/A.groovy | 5 +- .../fold_constant_numeric_arithmatic.groovy | 412 +++++++++++++ .../test_multi_range_partition.groovy | 2 +- 14 files changed, 1201 insertions(+), 206 deletions(-) delete mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/ExecutableFunctions.java delete mode 100644 fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/ExecutableFunctionsTest.java create mode 100644 regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_numeric_arithmatic.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FloatLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FloatLiteral.java index c6cf403f949e71..8d4a9ef576523e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FloatLiteral.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FloatLiteral.java @@ -159,6 +159,9 @@ public String getStringValueInFe(FormatOptions options) { String timeStr = getStringValue(); return timeStr.substring(1, timeStr.length() - 1); } else { + if (Double.isInfinite(getValue())) { + return Double.toString(getValue()); + } return BigDecimal.valueOf(getValue()).toPlainString(); } } 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 0c612e42ddaf11..0233b9882663da 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,12 +18,12 @@ package org.apache.doris.nereids.trees.expressions; import org.apache.doris.catalog.Env; +import org.apache.doris.nereids.exceptions.NotSupportedException; import org.apache.doris.nereids.trees.expressions.functions.BoundFunction; import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; import org.apache.doris.nereids.trees.expressions.functions.executable.DateTimeAcquire; import org.apache.doris.nereids.trees.expressions.functions.executable.DateTimeArithmetic; 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; @@ -105,9 +105,7 @@ private Expression invoke(Expression expression, String fnName) { Class componentType = parameterType.getComponentType(); Object varArgs = Array.newInstance(componentType, inputSize - fixedArgsSize); for (int i = fixedArgsSize; i < inputSize; i++) { - if (!(expression.children().get(i) instanceof NullLiteral)) { - Array.set(varArgs, i - fixedArgsSize, expression.children().get(i)); - } + Array.set(varArgs, i - fixedArgsSize, expression.children().get(i)); } Object[] objects = new Object[fixedArgsSize + 1]; for (int i = 0; i < fixedArgsSize; i++) { @@ -115,10 +113,16 @@ private Expression invoke(Expression expression, String fnName) { } objects[fixedArgsSize] = varArgs; - return (Literal) method.invoke(null, varArgs); + return (Literal) method.invoke(null, objects); } return (Literal) method.invoke(null, expression.children().toArray()); - } catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException e) { + } catch (InvocationTargetException e) { + if (e.getTargetException() instanceof NotSupportedException) { + throw new NotSupportedException(e.getTargetException().getMessage()); + } else { + return expression; + } + } catch (IllegalAccessException | IllegalArgumentException e) { return expression; } } @@ -192,7 +196,6 @@ private void registerFunctions() { List> classes = ImmutableList.of( DateTimeAcquire.class, DateTimeExtractAndTransform.class, - ExecutableFunctions.class, DateLiteral.class, DateTimeArithmetic.class, NumericArithmetic.class, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/ExecutableFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/ExecutableFunctions.java deleted file mode 100644 index e3082b57c2f977..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/ExecutableFunctions.java +++ /dev/null @@ -1,115 +0,0 @@ -// 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.trees.expressions.ExecFunction; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral; -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.NullLiteral; -import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral; -import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; -import org.apache.doris.nereids.types.DoubleType; - -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.Random; - -/** - * functions that can be executed in FE. - */ -public class ExecutableFunctions { - public static final ExecutableFunctions INSTANCE = new ExecutableFunctions(); - private static final Random RANDOM = new SecureRandom(); - - /** - * other scalar function - */ - @ExecFunction(name = "abs") - public static Expression abs(TinyIntLiteral literal) { - return new SmallIntLiteral((short) Math.abs(literal.getValue())); - } - - @ExecFunction(name = "abs") - public static Expression abs(SmallIntLiteral literal) { - return new IntegerLiteral(Math.abs(literal.getValue())); - } - - @ExecFunction(name = "abs") - public static Expression abs(IntegerLiteral literal) { - return new BigIntLiteral(Math.abs((long) literal.getValue())); - } - - @ExecFunction(name = "abs") - public static Expression abs(BigIntLiteral literal) { - return new LargeIntLiteral(BigInteger.valueOf(literal.getValue()).abs()); - } - - @ExecFunction(name = "abs") - public static Expression abs(LargeIntLiteral literal) { - return new LargeIntLiteral(literal.getValue().abs()); - } - - @ExecFunction(name = "abs") - public static Expression abs(FloatLiteral literal) { - return new FloatLiteral(Math.abs(literal.getValue())); - } - - @ExecFunction(name = "abs") - public static Expression abs(DoubleLiteral literal) { - return new DoubleLiteral(Math.abs(literal.getValue())); - } - - @ExecFunction(name = "abs") - public static Expression abs(DecimalLiteral literal) { - return new DecimalLiteral(literal.getValue().abs()); - } - - @ExecFunction(name = "abs") - public static Expression abs(DecimalV3Literal literal) { - return new DecimalV3Literal(literal.getValue().abs()); - } - - /** - * acos scalar function - */ - @ExecFunction(name = "acos") - public static Expression acos(DoubleLiteral literal) { - double result = Math.acos(literal.getValue()); - if (Double.isNaN(result)) { - return new NullLiteral(DoubleType.INSTANCE); - } else { - return new DoubleLiteral(result); - } - } - - @ExecFunction(name = "e") - public static Expression e() { // CHECKSTYLE IGNORE THIS LINE - return new DoubleLiteral(Math.E); - } - - @ExecFunction(name = "pi") - public static Expression pi() { - return new DoubleLiteral(Math.PI); - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java index ba0b75e75dd77e..325e676fc046a0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java @@ -17,27 +17,82 @@ package org.apache.doris.nereids.trees.expressions.functions.executable; +import org.apache.doris.nereids.exceptions.NotSupportedException; import org.apache.doris.nereids.trees.expressions.ExecFunction; import org.apache.doris.nereids.trees.expressions.Expression; 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.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.StringLiteral; import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; +import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral; import org.apache.doris.nereids.types.DecimalV3Type; import java.math.BigDecimal; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; /** * executable functions: * add, subtract, multiply, divide */ public class NumericArithmetic { + /** + * other scalar function + */ + @ExecFunction(name = "abs") + public static Expression abs(TinyIntLiteral literal) { + return new SmallIntLiteral((short) Math.abs(literal.getValue())); + } + + @ExecFunction(name = "abs") + public static Expression abs(SmallIntLiteral literal) { + return new IntegerLiteral(Math.abs(literal.getValue())); + } + + @ExecFunction(name = "abs") + public static Expression abs(IntegerLiteral literal) { + return new BigIntLiteral(Math.abs((long) literal.getValue())); + } + + @ExecFunction(name = "abs") + public static Expression abs(BigIntLiteral literal) { + return new LargeIntLiteral(BigInteger.valueOf(literal.getValue()).abs()); + } + + @ExecFunction(name = "abs") + public static Expression abs(LargeIntLiteral literal) { + return new LargeIntLiteral(literal.getValue().abs()); + } + + @ExecFunction(name = "abs") + public static Expression abs(FloatLiteral literal) { + return new FloatLiteral(Math.abs(literal.getValue())); + } + + @ExecFunction(name = "abs") + public static Expression abs(DoubleLiteral literal) { + return new DoubleLiteral(Math.abs(literal.getValue())); + } + + @ExecFunction(name = "abs") + public static Expression abs(DecimalLiteral literal) { + return new DecimalLiteral(literal.getValue().abs()); + } + + @ExecFunction(name = "abs") + public static Expression abs(DecimalV3Literal literal) { + return new DecimalV3Literal(literal.getValue().abs()); + } + /** * Executable arithmetic functions add */ @@ -194,7 +249,7 @@ public static Expression addLargeIntLargeInt(LargeIntLiteral first, LargeIntLite @ExecFunction(name = "add") public static Expression addDoubleDouble(DoubleLiteral first, DoubleLiteral second) { double result = first.getValue() + second.getValue(); - return new DoubleLiteral(result); + return checkOutputBoundary(new DoubleLiteral(result)); } @ExecFunction(name = "add") @@ -365,7 +420,7 @@ public static Expression subtractLargeIntLargeInt(LargeIntLiteral first, LargeIn @ExecFunction(name = "subtract") public static Expression subtractDoubleDouble(DoubleLiteral first, DoubleLiteral second) { double result = first.getValue() - second.getValue(); - return new DoubleLiteral(result); + return checkOutputBoundary(new DoubleLiteral(result)); } @ExecFunction(name = "subtract") @@ -536,7 +591,7 @@ public static Expression multiplyLargeIntLargeInt(LargeIntLiteral first, LargeIn @ExecFunction(name = "multiply") public static Expression multiplyDoubleDouble(DoubleLiteral first, DoubleLiteral second) { double result = first.getValue() * second.getValue(); - return new DoubleLiteral(result); + return checkOutputBoundary(new DoubleLiteral(result)); } @ExecFunction(name = "multiply") @@ -567,7 +622,7 @@ public static Expression divideDouble(DoubleLiteral first, DoubleLiteral second) return new NullLiteral(first.getDataType()); } double result = first.getValue() / second.getValue(); - return new DoubleLiteral(result); + return checkOutputBoundary(new DoubleLiteral(result)); } /** @@ -596,4 +651,507 @@ public static Expression divideDecimalV3(DecimalV3Literal first, DecimalV3Litera return new DecimalV3Literal(DecimalV3Type.createDecimalV3TypeLooseCheck( t1.getPrecision(), t1.getScale() - t2.getScale()), result); } + + /** + * coalesce + */ + @ExecFunction(name = "coalesce") + public static Expression coalesce(Literal first, Literal... second) { + if (!(first instanceof NullLiteral)) { + return first; + } + for (Literal secondLiteral : second) { + if (!(secondLiteral instanceof NullLiteral)) { + return secondLiteral; + } + } + return first; + } + + /** + * Method to check boundary with options for inclusive or exclusive boundaries + */ + public static void checkInputBoundary(Literal input, double lowerBound, double upperBound, + boolean isLowerInclusive, boolean isUpperInclusive) { + if (input instanceof DoubleLiteral) { + double inputValue = ((DoubleLiteral) input).getValue(); + boolean lowerCheck = isLowerInclusive ? (inputValue >= lowerBound) : (inputValue > lowerBound); + // Check upper bound + boolean upperCheck = isUpperInclusive ? (inputValue <= upperBound) : (inputValue < upperBound); + // Return true if both checks are satisfied + if (!lowerCheck || !upperCheck) { + throw new NotSupportedException("input " + input.toSql() + " is out of boundary"); + } + } + } + + private static Expression checkOutputBoundary(Literal input) { + if (input instanceof DoubleLiteral) { + if (((DoubleLiteral) input).getValue().isNaN() || ((DoubleLiteral) input).getValue().isInfinite()) { + throw new NotSupportedException(input.toSql() + " result is invalid"); + } + } + return input; + } + + /** + * round + */ + @ExecFunction(name = "round") + public static Expression round(DecimalV3Literal first) { + return first.round(0); + } + + /** + * round + */ + @ExecFunction(name = "round") + public static Expression round(DecimalV3Literal first, IntegerLiteral second) { + return first.round(second.getValue()); + } + + /** + * round + */ + @ExecFunction(name = "round") + public static Expression round(DoubleLiteral first) { + DecimalV3Literal middleResult = new DecimalV3Literal(new BigDecimal(Double.toString(first.getValue()))); + return new DoubleLiteral(middleResult.round(0).getDouble()); + } + + /** + * round + */ + @ExecFunction(name = "round") + public static Expression round(DoubleLiteral first, IntegerLiteral second) { + DecimalV3Literal middleResult = new DecimalV3Literal(new BigDecimal(Double.toString(first.getValue()))); + return new DoubleLiteral(middleResult.round(second.getValue()).getDouble()); + } + + /** + * ceil + */ + @ExecFunction(name = "ceil") + public static Expression ceil(DecimalV3Literal first) { + return first.roundCeiling(0); + } + + /** + * ceil + */ + @ExecFunction(name = "ceil") + public static Expression ceil(DecimalV3Literal first, IntegerLiteral second) { + return first.roundCeiling(second.getValue()); + } + + /** + * ceil + */ + @ExecFunction(name = "ceil") + public static Expression ceil(DoubleLiteral first) { + DecimalV3Literal middleResult = new DecimalV3Literal(new BigDecimal(Double.toString(first.getValue()))); + return new DoubleLiteral(middleResult.roundCeiling(0).getDouble()); + } + + /** + * ceil + */ + @ExecFunction(name = "ceil") + public static Expression ceil(DoubleLiteral first, IntegerLiteral second) { + DecimalV3Literal middleResult = new DecimalV3Literal(new BigDecimal(Double.toString(first.getValue()))); + return new DoubleLiteral(middleResult.roundCeiling(second.getValue()).getDouble()); + } + + /** + * floor + */ + @ExecFunction(name = "floor") + public static Expression floor(DecimalV3Literal first) { + return first.roundFloor(0); + } + + /** + * floor + */ + @ExecFunction(name = "floor") + public static Expression floor(DecimalV3Literal first, IntegerLiteral second) { + return first.roundFloor(second.getValue()); + } + + /** + * floor + */ + @ExecFunction(name = "floor") + public static Expression floor(DoubleLiteral first) { + DecimalV3Literal middleResult = new DecimalV3Literal(new BigDecimal(Double.toString(first.getValue()))); + return new DoubleLiteral(middleResult.roundFloor(0).getDouble()); + } + + /** + * floor + */ + @ExecFunction(name = "floor") + public static Expression floor(DoubleLiteral first, IntegerLiteral second) { + DecimalV3Literal middleResult = new DecimalV3Literal(new BigDecimal(Double.toString(first.getValue()))); + return new DoubleLiteral(middleResult.roundFloor(second.getValue()).getDouble()); + } + + /** + * exp + */ + @ExecFunction(name = "exp") + public static Expression exp(DoubleLiteral first) { + return checkOutputBoundary(new DoubleLiteral(Math.exp(first.getValue()))); + } + + /** + * ln + */ + @ExecFunction(name = "ln") + public static Expression ln(DoubleLiteral first) { + checkInputBoundary(first, 0.0d, Double.MAX_VALUE, false, true); + return checkOutputBoundary(new DoubleLiteral(Math.log(first.getValue()))); + } + + /** + * log + */ + @ExecFunction(name = "log") + public static Expression log(DoubleLiteral first, DoubleLiteral second) { + checkInputBoundary(first, 0.0d, Double.MAX_VALUE, false, true); + return checkOutputBoundary(new DoubleLiteral(Math.log(first.getValue()) / Math.log(second.getValue()))); + } + + /** + * log2 + */ + @ExecFunction(name = "log2") + public static Expression log2(DoubleLiteral first) { + checkInputBoundary(first, 0.0d, Double.MAX_VALUE, false, true); + return checkOutputBoundary(new DoubleLiteral(Math.log(first.getValue()) / Math.log(2.0))); + } + + /** + * log10 + */ + @ExecFunction(name = "log10") + public static Expression log10(DoubleLiteral first) { + checkInputBoundary(first, 0.0d, Double.MAX_VALUE, false, true); + return checkOutputBoundary(new DoubleLiteral(Math.log10(first.getValue()))); + } + + /** + * sqrt + */ + @ExecFunction(name = "sqrt") + public static Expression sqrt(DoubleLiteral first) { + checkInputBoundary(first, 0.0d, Double.MAX_VALUE, true, true); + return checkOutputBoundary(new DoubleLiteral(Math.sqrt(first.getValue()))); + } + + /** + * power + */ + @ExecFunction(name = "power") + public static Expression power(DoubleLiteral first, DoubleLiteral second) { + checkInputBoundary(second, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false, false); + return checkOutputBoundary(new DoubleLiteral(Math.pow(first.getValue(), second.getValue()))); + } + + /** + * sin + */ + @ExecFunction(name = "sin") + public static Expression sin(DoubleLiteral first) { + checkInputBoundary(first, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false, false); + return checkOutputBoundary(new DoubleLiteral(Math.sin(first.getValue()))); + } + + /** + * cos + */ + @ExecFunction(name = "cos") + public static Expression cos(DoubleLiteral first) { + checkInputBoundary(first, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false, false); + return checkOutputBoundary(new DoubleLiteral(Math.cos(first.getValue()))); + } + + /** + * tan + */ + @ExecFunction(name = "tan") + public static Expression tan(DoubleLiteral first) { + checkInputBoundary(first, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false, false); + return checkOutputBoundary(new DoubleLiteral(Math.tan(first.getValue()))); + } + + /** + * asin + */ + @ExecFunction(name = "asin") + public static Expression asin(DoubleLiteral first) { + checkInputBoundary(first, -1.0, 1.0, true, true); + return checkOutputBoundary(new DoubleLiteral(Math.asin(first.getValue()))); + } + + /** + * acos + */ + @ExecFunction(name = "acos") + public static Expression acos(DoubleLiteral first) { + checkInputBoundary(first, -1.0, 1.0, true, true); + return checkOutputBoundary(new DoubleLiteral(Math.acos(first.getValue()))); + } + + /** + * atan + */ + @ExecFunction(name = "atan") + public static Expression atan(DoubleLiteral first) { + return checkOutputBoundary(new DoubleLiteral(Math.atan(first.getValue()))); + } + + /** + * atan2 + */ + @ExecFunction(name = "atan2") + public static Expression atan2(DoubleLiteral first, DoubleLiteral second) { + return checkOutputBoundary(new DoubleLiteral(Math.atan2(first.getValue(), second.getValue()))); + } + + /** + * sign + */ + @ExecFunction(name = "sign") + public static Expression sign(DoubleLiteral first) { + if (first.getValue() < 0) { + return new TinyIntLiteral((byte) -1); + } else if (first.getValue() == 0) { + return new TinyIntLiteral((byte) 0); + } else { + return new TinyIntLiteral((byte) 1); + } + } + + /** + * bit_count + */ + @ExecFunction(name = "bit_count") + public static Expression bitCount(TinyIntLiteral first) { + return new TinyIntLiteral((byte) Integer.bitCount(first.getValue() & 0xFF)); + } + + /** + * bit_count + */ + @ExecFunction(name = "bit_count") + public static Expression bitCount(SmallIntLiteral first) { + return new TinyIntLiteral((byte) Integer.bitCount(first.getValue() & 0xFFFF)); + } + + /** + * bit_count + */ + @ExecFunction(name = "bit_count") + public static Expression bitCount(IntegerLiteral first) { + return new TinyIntLiteral((byte) Integer.bitCount(first.getValue())); + } + + /** + * bit_count + */ + @ExecFunction(name = "bit_count") + public static Expression bitCount(BigIntLiteral first) { + return new TinyIntLiteral((byte) Long.bitCount(first.getValue())); + } + + /** + * bit_count + */ + @ExecFunction(name = "bit_count") + public static Expression bitCount(LargeIntLiteral first) { + if (first.getValue().compareTo(BigInteger.ZERO) < 0) { + return new SmallIntLiteral((short) (128 - first.getValue().bitCount())); + } else { + return new SmallIntLiteral((short) first.getValue().bitCount()); + } + } + + /** + * bit_length + */ + @ExecFunction(name = "bit_length") + public static Expression bitLength(VarcharLiteral first) { + byte[] byteArray = first.getValue().getBytes(StandardCharsets.UTF_8); // Convert to bytes in UTF-8 + int byteLength = byteArray.length; + return new IntegerLiteral(byteLength * Byte.SIZE); + } + + /** + * bit_length + */ + @ExecFunction(name = "bit_length") + public static Expression bitLength(StringLiteral first) { + byte[] byteArray = first.getValue().getBytes(StandardCharsets.UTF_8); // Convert to bytes in UTF-8 + int byteLength = byteArray.length; + return new IntegerLiteral(byteLength * Byte.SIZE); + } + + /** + * cbrt + */ + @ExecFunction(name = "cbrt") + public static Expression cbrt(DoubleLiteral first) { + return checkOutputBoundary(new DoubleLiteral(Math.cbrt(first.getValue()))); + } + + /** + * cosh + */ + @ExecFunction(name = "cosh") + public static Expression cosh(DoubleLiteral first) { + return checkOutputBoundary(new DoubleLiteral(Math.cosh(first.getValue()))); + } + + /** + * tanh + */ + @ExecFunction(name = "cosh") + public static Expression tanh(DoubleLiteral first) { + return checkOutputBoundary(new DoubleLiteral(Math.tanh(first.getValue()))); + } + + /** + * dexp + */ + @ExecFunction(name = "dexp") + public static Expression dexp(DoubleLiteral first) { + double exp = Math.exp(first.getValue()); + return checkOutputBoundary(new DoubleLiteral(exp)); + } + + /** + * dlog1 + */ + @ExecFunction(name = "dlog1") + public static Expression dlog1(DoubleLiteral first) { + checkInputBoundary(first, 0.0d, Double.MAX_VALUE, false, true); + return checkOutputBoundary(new DoubleLiteral(Math.log1p(first.getValue()))); + } + + /** + * dlog10 + */ + @ExecFunction(name = "dlog10") + public static Expression dlog10(DoubleLiteral first) { + checkInputBoundary(first, 0.0d, Double.MAX_VALUE, false, true); + return checkOutputBoundary(new DoubleLiteral(Math.log10(first.getValue()))); + } + + /** + * dsqrt + */ + @ExecFunction(name = "dsqrt") + public static Expression dsqrt(DoubleLiteral first) { + checkInputBoundary(first, 0.0d, Double.MAX_VALUE, false, true); + return checkOutputBoundary(new DoubleLiteral(Math.sqrt(first.getValue()))); + } + + /** + * dpower + */ + @ExecFunction(name = "dpow") + public static Expression dpow(DoubleLiteral first, DoubleLiteral second) { + return checkOutputBoundary(new DoubleLiteral(Math.pow(first.getValue(), second.getValue()))); + } + + /** + * fmod + */ + @ExecFunction(name = "fmod") + public static Expression fmod(DoubleLiteral first, DoubleLiteral second) { + return checkOutputBoundary(new DoubleLiteral(first.getValue() / second.getValue())); + } + + /** + * fmod + */ + @ExecFunction(name = "fmod") + public static Expression fmod(FloatLiteral first, FloatLiteral second) { + return new FloatLiteral(first.getValue() / second.getValue()); + } + + /** + * fpow + */ + @ExecFunction(name = "fpow") + public static Expression fpow(DoubleLiteral first, DoubleLiteral second) { + return checkOutputBoundary(new DoubleLiteral(Math.pow(first.getValue(), second.getValue()))); + } + + /** + * radians + */ + @ExecFunction(name = "radians") + public static Expression radians(DoubleLiteral first) { + return checkOutputBoundary(new DoubleLiteral(Math.toRadians(first.getValue()))); + } + + /** + * degrees + */ + @ExecFunction(name = "degrees") + public static Expression degrees(DoubleLiteral first) { + return checkOutputBoundary(new DoubleLiteral(Math.toDegrees(first.getValue()))); + } + + /** + * xor + */ + @ExecFunction(name = "xor") + public static Expression xor(BooleanLiteral first, BooleanLiteral second) { + return BooleanLiteral.of(Boolean.logicalXor(first.getValue(), second.getValue())); + } + + /** + * pi + */ + @ExecFunction(name = "pi") + public static Expression pi() { + return DoubleLiteral.of(Math.PI); + } + + /** + * E + */ + @ExecFunction(name = "e") + public static Expression mathE() { + return DoubleLiteral.of(Math.E); + } + + /** + * truncate + */ + @ExecFunction(name = "truncate") + public static Expression truncate(DecimalV3Literal first, IntegerLiteral second) { + if (first.getValue().compareTo(BigDecimal.ZERO) == 0) { + return first; + } else { + if (first.getValue().scale() < second.getValue()) { + return first; + } + if (second.getValue() < 0) { + double factor = Math.pow(10, Math.abs(second.getValue())); + return new DecimalV3Literal( + DecimalV3Type.createDecimalV3Type(first.getValue().precision(), 0), + BigDecimal.valueOf(Math.floor(first.getDouble() / factor) * factor)); + } + if (first.getValue().compareTo(BigDecimal.ZERO) == -1) { + return first.roundCeiling(second.getValue()); + } else { + return first.roundFloor(second.getValue()); + } + } + } + } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DecimalV3Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DecimalV3Literal.java index a16c57fa74ae88..9d311fe06646a5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DecimalV3Literal.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DecimalV3Literal.java @@ -72,14 +72,42 @@ public double getDouble() { return value.doubleValue(); } + /** + * get ceiling of a decimal v3 literal + * @param newScale scale we want to cast to + * @return new decimal v3 literal with new scalar + */ public DecimalV3Literal roundCeiling(int newScale) { + if (newScale >= this.getValue().scale()) { + return this; + } return new DecimalV3Literal(value.setScale(newScale, RoundingMode.CEILING)); } + /** + * get floor of a decimal v3 literal + * @param newScale scale we want to cast to + * @return new decimal v3 literal with new scalar + */ public DecimalV3Literal roundFloor(int newScale) { + if (newScale >= this.getValue().scale()) { + return this; + } return new DecimalV3Literal(value.setScale(newScale, RoundingMode.FLOOR)); } + /** + * get round of a decimal v3 literal + * @param newScale scale we want to cast to + * @return new decimal v3 literal with new scalar + */ + public DecimalV3Literal round(int newScale) { + if (newScale >= this.getValue().scale()) { + return this; + } + return new DecimalV3Literal(value.setScale(newScale, RoundingMode.HALF_UP)); + } + /** * check precision and scale is enough for value. */ diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java index 9009bc13e8ab77..0601b3b558d882 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/FoldConstantTest.java @@ -21,6 +21,7 @@ import org.apache.doris.common.Config; import org.apache.doris.nereids.analyzer.UnboundRelation; import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.nereids.exceptions.NotSupportedException; import org.apache.doris.nereids.parser.NereidsParser; import org.apache.doris.nereids.rules.analysis.ExpressionAnalyzer; import org.apache.doris.nereids.rules.expression.rules.FoldConstantRule; @@ -34,15 +35,31 @@ import org.apache.doris.nereids.trees.expressions.functions.executable.DateTimeArithmetic; import org.apache.doris.nereids.trees.expressions.functions.executable.DateTimeExtractAndTransform; import org.apache.doris.nereids.trees.expressions.functions.executable.TimeRoundSeries; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Acos; import org.apache.doris.nereids.trees.expressions.functions.scalar.AppendTrailingCharIfAbsent; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Asin; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Bin; +import org.apache.doris.nereids.trees.expressions.functions.scalar.BitCount; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Ceil; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Coalesce; import org.apache.doris.nereids.trees.expressions.functions.scalar.ConvertTz; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Cos; import org.apache.doris.nereids.trees.expressions.functions.scalar.DateFormat; import org.apache.doris.nereids.trees.expressions.functions.scalar.DateTrunc; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Exp; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Floor; import org.apache.doris.nereids.trees.expressions.functions.scalar.FromUnixtime; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Ln; import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesAdd; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Power; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Round; import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sign; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sin; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sqrt; import org.apache.doris.nereids.trees.expressions.functions.scalar.StrToDate; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Tan; import org.apache.doris.nereids.trees.expressions.functions.scalar.ToDays; import org.apache.doris.nereids.trees.expressions.functions.scalar.UnixTimestamp; import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral; @@ -51,11 +68,13 @@ 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.DecimalV3Literal; +import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral; import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; import org.apache.doris.nereids.trees.expressions.literal.Interval.TimeUnit; 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.StringLiteral; +import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral; import org.apache.doris.nereids.trees.plans.RelationId; import org.apache.doris.nereids.types.DateTimeV2Type; @@ -317,6 +336,149 @@ void testFoldString() { Assertions.assertEquals(new StringLiteral("13"), rewritten); } + @Test + void testleFoldNumeric() { + executor = new ExpressionRuleExecutor(ImmutableList.of( + bottomUp(FoldConstantRuleOnFE.VISITOR_INSTANCE) + )); + Coalesce c = new Coalesce(new NullLiteral(), new NullLiteral()); + Expression rewritten = executor.rewrite(c, context); + Assertions.assertEquals(new NullLiteral(), rewritten); + c = new Coalesce(new NullLiteral(), new IntegerLiteral(1)); + rewritten = executor.rewrite(c, context); + Assertions.assertEquals(new IntegerLiteral(1), rewritten); + c = new Coalesce(new IntegerLiteral(3), new IntegerLiteral(5)); + rewritten = executor.rewrite(c, context); + Assertions.assertEquals(new IntegerLiteral(3), rewritten); + + Round round = new Round(new DoubleLiteral(3.4d)); + rewritten = executor.rewrite(round, context); + Assertions.assertEquals(new DoubleLiteral(3d), rewritten); + round = new Round(new DoubleLiteral(3.4d), new IntegerLiteral(5)); + rewritten = executor.rewrite(round, context); + Assertions.assertEquals(new DoubleLiteral(3.4d), rewritten); + round = new Round(new DoubleLiteral(3.5d)); + rewritten = executor.rewrite(round, context); + Assertions.assertEquals(new DoubleLiteral(4d), rewritten); + + Ceil ceil = new Ceil(new DoubleLiteral(3.4d)); + rewritten = executor.rewrite(ceil, context); + Assertions.assertEquals(new DoubleLiteral(4d), rewritten); + ceil = new Ceil(new DoubleLiteral(3.4d), new IntegerLiteral(5)); + rewritten = executor.rewrite(ceil, context); + Assertions.assertEquals(new DoubleLiteral(3.4d), rewritten); + + Floor floor = new Floor(new DoubleLiteral(3.4d)); + rewritten = executor.rewrite(floor, context); + Assertions.assertEquals(new DoubleLiteral(3d), rewritten); + floor = new Floor(new DoubleLiteral(3.4d), new IntegerLiteral(5)); + rewritten = executor.rewrite(floor, context); + Assertions.assertEquals(new DoubleLiteral(3.4d), rewritten); + + Exp exp = new Exp(new DoubleLiteral(0d)); + rewritten = executor.rewrite(exp, context); + Assertions.assertEquals(new DoubleLiteral(1.0), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Exp exExp = new Exp(new DoubleLiteral(1000d)); + executor.rewrite(exExp, context); + }, "infinite result is invalid"); + + Ln ln = new Ln(new DoubleLiteral(1d)); + rewritten = executor.rewrite(ln, context); + Assertions.assertEquals(new DoubleLiteral(0.0), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Ln exExp = new Ln(new DoubleLiteral(0.0d)); + executor.rewrite(exExp, context); + }, "input 0.0 is out of boundary"); + Assertions.assertThrows(NotSupportedException.class, () -> { + Ln exExp = new Ln(new DoubleLiteral(-1d)); + executor.rewrite(exExp, context); + }, "input -1 is out of boundary"); + + Sqrt sqrt = new Sqrt(new DoubleLiteral(16d)); + rewritten = executor.rewrite(sqrt, context); + Assertions.assertEquals(new DoubleLiteral(4d), rewritten); + sqrt = new Sqrt(new DoubleLiteral(0d)); + rewritten = executor.rewrite(sqrt, context); + Assertions.assertEquals(new DoubleLiteral(0d), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Sqrt exExp = new Sqrt(new DoubleLiteral(-1d)); + executor.rewrite(exExp, context); + }, "input -1 is out of boundary"); + + Power power = new Power(new DoubleLiteral(2d), new DoubleLiteral(3)); + rewritten = executor.rewrite(power, context); + Assertions.assertEquals(new DoubleLiteral(8d), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Power exExp = new Power(new DoubleLiteral(2d), new DoubleLiteral(10000d)); + executor.rewrite(exExp, context); + }, "infinite result is invalid"); + + Sin sin = new Sin(new DoubleLiteral(Math.PI / 2)); + rewritten = executor.rewrite(sin, context); + Assertions.assertEquals(new DoubleLiteral(1d), rewritten); + sin = new Sin(new DoubleLiteral(0d)); + rewritten = executor.rewrite(sin, context); + Assertions.assertEquals(new DoubleLiteral(0d), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Sin exExp = new Sin(new DoubleLiteral(Double.POSITIVE_INFINITY)); + executor.rewrite(exExp, context); + }, "input infinity is out of boundary"); + + Cos cos = new Cos(new DoubleLiteral(0d)); + rewritten = executor.rewrite(cos, context); + Assertions.assertEquals(new DoubleLiteral(1d), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Cos exExp = new Cos(new DoubleLiteral(Double.POSITIVE_INFINITY)); + executor.rewrite(exExp, context); + }, "input infinity is out of boundary"); + + Tan tan = new Tan(new DoubleLiteral(0d)); + rewritten = executor.rewrite(tan, context); + Assertions.assertEquals(new DoubleLiteral(0d), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Tan exExp = new Tan(new DoubleLiteral(Double.POSITIVE_INFINITY)); + executor.rewrite(exExp, context); + }, "input infinity is out of boundary"); + + Asin asin = new Asin(new DoubleLiteral(1d)); + rewritten = executor.rewrite(asin, context); + Assertions.assertEquals(new DoubleLiteral(Math.PI / 2), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Asin exExp = new Asin(new DoubleLiteral(2d)); + executor.rewrite(exExp, context); + }, "input 2.0 is out of boundary"); + + Acos acos = new Acos(new DoubleLiteral(1d)); + rewritten = executor.rewrite(acos, context); + Assertions.assertEquals(new DoubleLiteral(0), rewritten); + Assertions.assertThrows(NotSupportedException.class, () -> { + Acos exExp = new Acos(new DoubleLiteral(2d)); + executor.rewrite(exExp, context); + }, "input 2.0 is out of boundary"); + + Sign sign = new Sign(new DoubleLiteral(1d)); + rewritten = executor.rewrite(sign, context); + Assertions.assertEquals(new TinyIntLiteral((byte) 1), rewritten); + sign = new Sign(new DoubleLiteral(-1d)); + rewritten = executor.rewrite(sign, context); + Assertions.assertEquals(new TinyIntLiteral((byte) -1), rewritten); + sign = new Sign(new DoubleLiteral(0d)); + rewritten = executor.rewrite(sign, context); + Assertions.assertEquals(new TinyIntLiteral((byte) 0), rewritten); + + Bin bin = new Bin(new BigIntLiteral(5)); + rewritten = executor.rewrite(bin, context); + Assertions.assertEquals(new VarcharLiteral("101"), rewritten); + + BitCount bitCount = new BitCount(new BigIntLiteral(16)); + rewritten = executor.rewrite(bitCount, context); + Assertions.assertEquals(new TinyIntLiteral((byte) 1), rewritten); + bitCount = new BitCount(new BigIntLiteral(-1)); + rewritten = executor.rewrite(bitCount, context); + Assertions.assertEquals(new TinyIntLiteral((byte) 64), rewritten); + } + @Test void testCompareFold() { executor = new ExpressionRuleExecutor(ImmutableList.of( diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/ExecutableFunctionsTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/ExecutableFunctionsTest.java deleted file mode 100644 index 6c2e9f144be883..00000000000000 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/ExecutableFunctionsTest.java +++ /dev/null @@ -1,64 +0,0 @@ -// 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; - -import org.apache.doris.nereids.trees.expressions.functions.executable.ExecutableFunctions; -import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral; -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.SmallIntLiteral; -import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.math.BigInteger; - -public class ExecutableFunctionsTest { - @Test - void testAbsFunctions() { - TinyIntLiteral tinyInt1 = new TinyIntLiteral((byte) -128); - Assertions.assertEquals(new SmallIntLiteral((short) 128), ExecutableFunctions.abs(tinyInt1)); - TinyIntLiteral tinyInt2 = new TinyIntLiteral((byte) 127); - Assertions.assertEquals(new SmallIntLiteral((short) 127), ExecutableFunctions.abs(tinyInt2)); - - SmallIntLiteral smallInt1 = new SmallIntLiteral((short) -32768); - Assertions.assertEquals(new IntegerLiteral(32768), ExecutableFunctions.abs(smallInt1)); - SmallIntLiteral smallInt2 = new SmallIntLiteral((short) 32767); - Assertions.assertEquals(new IntegerLiteral(32767), ExecutableFunctions.abs(smallInt2)); - - IntegerLiteral int1 = new IntegerLiteral(-2147483648); - Assertions.assertEquals(new BigIntLiteral(2147483648L), ExecutableFunctions.abs(int1)); - IntegerLiteral int2 = new IntegerLiteral(2147483647); - Assertions.assertEquals(new BigIntLiteral(2147483647L), ExecutableFunctions.abs(int2)); - - BigIntLiteral bigInt1 = new BigIntLiteral(-9223372036854775808L); - Assertions.assertEquals(new LargeIntLiteral(new BigInteger("9223372036854775808")), - ExecutableFunctions.abs(bigInt1)); - BigIntLiteral bigInt2 = new BigIntLiteral(9223372036854775807L); - Assertions.assertEquals(new LargeIntLiteral(new BigInteger("9223372036854775807")), - ExecutableFunctions.abs(bigInt2)); - - LargeIntLiteral largeInt1 = new LargeIntLiteral(new BigInteger("-170141183460469231731687303715884105728")); - Assertions.assertEquals(new LargeIntLiteral(new BigInteger("170141183460469231731687303715884105728")), - ExecutableFunctions.abs(largeInt1)); - LargeIntLiteral largeInt2 = new LargeIntLiteral(new BigInteger("170141183460469231731687303715884105727")); - Assertions.assertEquals(new LargeIntLiteral(new BigInteger("170141183460469231731687303715884105727")), - ExecutableFunctions.abs(largeInt2)); - } -} diff --git a/regression-test/data/datatype_p0/double/test_double_nan.out b/regression-test/data/datatype_p0/double/test_double_nan.out index 327a147e2db2e8..f958424e65c626 100644 --- a/regression-test/data/datatype_p0/double/test_double_nan.out +++ b/regression-test/data/datatype_p0/double/test_double_nan.out @@ -1,7 +1,3 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !select -- -1 \N - --- !select -- -\N diff --git a/regression-test/data/datatype_p0/float/test_float_nan.out b/regression-test/data/datatype_p0/float/test_float_nan.out index 327a147e2db2e8..f958424e65c626 100644 --- a/regression-test/data/datatype_p0/float/test_float_nan.out +++ b/regression-test/data/datatype_p0/float/test_float_nan.out @@ -1,7 +1,3 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !select -- -1 \N - --- !select -- -\N diff --git a/regression-test/suites/datatype_p0/double/test_double_nan.groovy b/regression-test/suites/datatype_p0/double/test_double_nan.groovy index b193b0132dbcfb..3d57fee2990d8c 100644 --- a/regression-test/suites/datatype_p0/double/test_double_nan.groovy +++ b/regression-test/suites/datatype_p0/double/test_double_nan.groovy @@ -19,10 +19,17 @@ suite("test_double_nan", "datatype_p0") { def tableName = "tbl_test_double_nan" sql "DROP TABLE IF EXISTS ${tableName}" sql "CREATE TABLE if NOT EXISTS ${tableName} (k int, value double) DUPLICATE KEY(k) DISTRIBUTED BY HASH (k) BUCKETS 1 PROPERTIES ('replication_num' = '1');" - sql """insert into ${tableName} select 1, sqrt(-1);""" + + test { + sql """insert into ${tableName} select 1, sqrt(-1);""" + exception "errCode" + } qt_select "select * from ${tableName} order by 1;" - qt_select "select sqrt(-1);" + test { + sql "select sqrt(-1);" + exception "errCode" + } sql "DROP TABLE IF EXISTS ${tableName}" -} \ No newline at end of file +} diff --git a/regression-test/suites/datatype_p0/float/test_float_nan.groovy b/regression-test/suites/datatype_p0/float/test_float_nan.groovy index 18958b27cf26a2..cf07006abad4b7 100644 --- a/regression-test/suites/datatype_p0/float/test_float_nan.groovy +++ b/regression-test/suites/datatype_p0/float/test_float_nan.groovy @@ -19,10 +19,16 @@ suite("test_float_nan", "datatype_p0") { def tableName = "tbl_test_float_nan" sql "DROP TABLE IF EXISTS ${tableName}" sql "CREATE TABLE if NOT EXISTS ${tableName} (k int, value float) DUPLICATE KEY(k) DISTRIBUTED BY HASH (k) BUCKETS 1 PROPERTIES ('replication_num' = '1');" - sql """insert into ${tableName} select 1, sqrt(-1);""" + test { + sql """insert into ${tableName} select 1, sqrt(-1);""" + exception "errCode" + } qt_select "select * from ${tableName} order by 1;" - qt_select "select sqrt(-1);" + test { + sql "select sqrt(-1);" + exception "errCode" + } sql "DROP TABLE IF EXISTS ${tableName}" -} \ No newline at end of file +} diff --git a/regression-test/suites/nereids_function_p0/scalar_function/A.groovy b/regression-test/suites/nereids_function_p0/scalar_function/A.groovy index bc8ffbe71b443d..b4df5d9e9c42fc 100644 --- a/regression-test/suites/nereids_function_p0/scalar_function/A.groovy +++ b/regression-test/suites/nereids_function_p0/scalar_function/A.groovy @@ -37,7 +37,10 @@ suite("nereids_scalar_fn_A") { qt_sql_abs_DecimalV2_notnull "select abs(kdcmls1) from fn_test_not_nullable order by kdcmls1" qt_sql_acos_Double "select acos(kdbl) from fn_test order by kdbl" qt_sql_acos_Double_notnull "select acos(kdbl) from fn_test_not_nullable order by kdbl" - qt_sql_acos_Double_NAN "select acos(cast(1.1 as double))" + test { + sql "select acos(cast(1.1 as double))" + exception "errCode" + } qt_sql_acos_Double_NULL "select acos(null)" sql "select aes_decrypt(kvchrs1, kvchrs1) from fn_test order by kvchrs1, kvchrs1" sql "select aes_decrypt(kvchrs1, kvchrs1) from fn_test_not_nullable order by kvchrs1, kvchrs1" diff --git a/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_numeric_arithmatic.groovy b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_numeric_arithmatic.groovy new file mode 100644 index 00000000000000..5f728651267e82 --- /dev/null +++ b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_numeric_arithmatic.groovy @@ -0,0 +1,412 @@ +// 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_numeric_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 truncate(123.456, -1)") +// testFoldConst("select pmod(-9223372036854775808,-1)") + //Coalesce function cases + testFoldConst("SELECT COALESCE(NULL, 5) AS coalesce_case_1") + testFoldConst("SELECT COALESCE(NULL, NULL, 7) AS coalesce_case_2") + testFoldConst("SELECT COALESCE(3, 5) AS coalesce_case_3") + testFoldConst("SELECT COALESCE(NULL, NULL) AS coalesce_case_4") + +//Round function cases + testFoldConst("SELECT ROUND(3.4) AS round_case_1") + testFoldConst("SELECT ROUND(3.5) AS round_case_2") + testFoldConst("SELECT ROUND(-3.4) AS round_case_3") + testFoldConst("SELECT ROUND(123.456, 2) AS round_case_4") //Rounding to 2 decimal places + +//Ceil function cases + testFoldConst("SELECT CEIL(3.4) AS ceil_case_1") + testFoldConst("SELECT CEIL(-3.4) AS ceil_case_2") + testFoldConst("SELECT CEIL(5.0) AS ceil_case_3") + +//Floor function cases + testFoldConst("SELECT FLOOR(3.7) AS floor_case_1") + testFoldConst("SELECT FLOOR(-3.7) AS floor_case_2") + testFoldConst("SELECT FLOOR(5.0) AS floor_case_3") + +//Exp function cases + testFoldConst("SELECT EXP(1) AS exp_case_1") //e^1 + testFoldConst("SELECT EXP(0) AS exp_case_2") //e^0 + testFoldConst("SELECT EXP(-1) AS exp_case_3") //e^-1 + +//Ln (natural logarithm) function cases + testFoldConst("SELECT LN(1) AS ln_case_1") //ln(1) = 0 + testFoldConst("SELECT LN(EXP(1)) AS ln_case_2") //ln(e) = 1 + testFoldConst("SELECT LN(0.5) AS ln_case_3") //ln(0.5) + +//Log10 function cases + testFoldConst("SELECT LOG10(100) AS log10_case_1") //log10(100) = 2 + testFoldConst("SELECT LOG10(1) AS log10_case_2") //log10(1) = 0 + testFoldConst("SELECT LOG10(1000) AS log10_case_3") //log10(1000) = 3 + +//Log2 function cases + testFoldConst("SELECT LOG2(2) AS log2_case_1") //log2(2) = 1 + testFoldConst("SELECT LOG2(8) AS log2_case_2") //log2(8) = 3 + testFoldConst("SELECT LOG2(1) AS log2_case_3") //log2(1) = 0 + +//Sqrt function cases + testFoldConst("SELECT SQRT(16) AS sqrt_case_1") //sqrt(16) = 4 + testFoldConst("SELECT SQRT(0) AS sqrt_case_2") //sqrt(0) = 0 + testFoldConst("SELECT SQRT(2) AS sqrt_case_3") //sqrt(2) + +//Power function cases + testFoldConst("SELECT POWER(2, 3) AS power_case_1") //2^3 = 8 + testFoldConst("SELECT POWER(10, 0) AS power_case_2") //10^0 = 1 + testFoldConst("SELECT POWER(5, -1) AS power_case_3") //5^-1 = 0.2 + +//Sin function cases + testFoldConst("SELECT SIN(PI() / 2) AS sin_case_1") //sin(π/2) = 1 + testFoldConst("SELECT SIN(0) AS sin_case_2") //sin(0) = 0 + testFoldConst("SELECT SIN(PI()) AS sin_case_3") //sin(π) + +//Cos function cases + testFoldConst("SELECT COS(PI()) AS cos_case_1") //cos(π) = -1 + testFoldConst("SELECT COS(0) AS cos_case_2") //cos(0) = 1 + testFoldConst("SELECT COS(PI() / 2) AS cos_case_3") //cos(π/2) + +//Tan function cases + testFoldConst("SELECT TAN(PI() / 4) AS tan_case_1") //tan(π/4) = 1 + testFoldConst("SELECT TAN(0) AS tan_case_2") //tan(0) = 0 + testFoldConst("SELECT TAN(PI()) AS tan_case_3") //tan(π) + +//Acos function cases + testFoldConst("SELECT ACOS(1) AS acos_case_1") //acos(1) = 0 + testFoldConst("SELECT ACOS(0) AS acos_case_2") //acos(0) = π/2 + testFoldConst("SELECT ACOS(-1) AS acos_case_3") //acos(-1) = π + +//Asin function cases + testFoldConst("SELECT ASIN(1) AS asin_case_1") //asin(1) = π/2 + testFoldConst("SELECT ASIN(0) AS asin_case_2") //asin(0) = 0 + testFoldConst("SELECT ASIN(-1) AS asin_case_3") //asin(-1) = -π/2 + +//Atan function cases + testFoldConst("SELECT ATAN(1) AS atan_case_1") //atan(1) = π/4 + testFoldConst("SELECT ATAN(0) AS atan_case_2") //atan(0) = 0 + testFoldConst("SELECT ATAN(-1) AS atan_case_3") //atan(-1) + +//Atan2 function cases + testFoldConst("SELECT ATAN2(1, 1) AS atan2_case_1") //atan2(1, 1) = π/4 + testFoldConst("SELECT ATAN2(0, 1) AS atan2_case_2") //atan2(0, 1) = 0 + testFoldConst("SELECT ATAN2(1, 0) AS atan2_case_3") //atan2(1, 0) = π/2 + +//Sign function cases + testFoldConst("SELECT SIGN(5) AS sign_case_1") //sign(5) = 1 + testFoldConst("SELECT SIGN(-5) AS sign_case_2") //sign(-5) = -1 + testFoldConst("SELECT SIGN(0) AS sign_case_3") //sign(0) = 0 + +//Bin function cases (binary conversion) + testFoldConst("SELECT BIN(5) AS bin_case_1") //bin(5) = 101 + testFoldConst("SELECT BIN(16) AS bin_case_2") //bin(16) = 10000 + testFoldConst("SELECT BIN(255) AS bin_case_3") //bin(255) + +//BitCount function cases (count bits set to 1) + testFoldConst("SELECT BIT_COUNT(5) AS bitcount_case_1") //bitcount(5) = 2 (101 has two 1s) + testFoldConst("SELECT BIT_COUNT(16) AS bitcount_case_2") //bitcount(16) = 1 + testFoldConst("SELECT BIT_COUNT(255) AS bitcount_case_3") //bitcount(255) + +//BitLength function cases + testFoldConst("SELECT BIT_LENGTH('5') AS bitlength_case_1") //bitlength(101) = 3 + testFoldConst("SELECT BIT_LENGTH('16') AS bitlength_case_2") //bitlength(10000) = 5 + testFoldConst("SELECT BIT_LENGTH('11111111') AS bitlength_case_3") //bitlength(11111111) + +//Cbrt (cube root) function cases + testFoldConst("SELECT CBRT(8) AS cbrt_case_1") //cbrt(8) = 2 + testFoldConst("SELECT CBRT(-8) AS cbrt_case_2") //cbrt(-8) = -2 +// testFoldConst("SELECT CBRT(27) AS cbrt_case_3") //cbrt(27) + +//Cosh function cases (hyperbolic cosine) + testFoldConst("SELECT COSH(0) AS cosh_case_1") //cosh(0) = 1 +// testFoldConst("SELECT COSH(1) AS cosh_case_2") //cosh(1) +// testFoldConst("SELECT COSH(-1) AS cosh_case_3") //cosh(-1) + +//Tanh function cases (hyperbolic tangent) + testFoldConst("SELECT TANH(0) AS tanh_case_1") //tanh(0) = 0 + testFoldConst("SELECT TANH(1) AS tanh_case_2") //tanh(1) + testFoldConst("SELECT TANH(-1) AS tanh_case_3") //tanh(-1) + +//Dexp function cases (double exp) + testFoldConst("SELECT EXP(2.0) AS dexp_case_1") //dexp(2.0) + testFoldConst("SELECT EXP(0.5) AS dexp_case_2") //dexp(0.5) + testFoldConst("SELECT EXP(-2.0) AS dexp_case_3") //dexp(-2.0) + +//Dlog10 function cases (double log base 10) + testFoldConst("SELECT LOG10(100.0) AS dlog10_case_1") //dlog10(100.0) = 2 + testFoldConst("SELECT LOG10(1.0) AS dlog10_case_2") //dlog10(1.0) = 0 + testFoldConst("SELECT LOG10(1000.0) AS dlog10_case_3") //dlog10(1000.0) + +//Dlog1 function cases (log base 1 is not commonly defined) + +//Dpow function cases (double power) + testFoldConst("SELECT POWER(2.0, 3.0) AS dpow_case_1") //dpow(2.0^3.0) = 8.0 + testFoldConst("SELECT POWER(10.0, 0.0) AS dpow_case_2") //dpow(10.0^0.0) = 1.0 + testFoldConst("SELECT POWER(5.0, -1.0) AS dpow_case_3") +//Coalesce function cases + testFoldConst("SELECT COALESCE(NULL, 5) AS coalesce_case_1") + testFoldConst("SELECT COALESCE(NULL, NULL, 7) AS coalesce_case_2") + testFoldConst("SELECT COALESCE(3, 5) AS coalesce_case_3") + testFoldConst("SELECT COALESCE(NULL, NULL) AS coalesce_case_4") + +//Round function cases + testFoldConst("SELECT ROUND(3.4) AS round_case_1") + testFoldConst("SELECT ROUND(3.5) AS round_case_2") + testFoldConst("SELECT ROUND(-3.4) AS round_case_3") + testFoldConst("SELECT ROUND(123.456, 2) AS round_case_4") //rounding to 2 decimal places +//Exception: Round overflow (not common but tested with extremely large values) + testFoldConst("SELECT ROUND(1E308) AS round_case_overflow") //very large number + +//Ceil function cases + testFoldConst("SELECT CEIL(3.4) AS ceil_case_1") + testFoldConst("SELECT CEIL(-3.4) AS ceil_case_2") + testFoldConst("SELECT CEIL(5.0) AS ceil_case_3") +//Exception: Ceil of extremely large number + testFoldConst("SELECT CEIL(1E308) AS ceil_case_overflow") + +//Floor function cases + testFoldConst("SELECT FLOOR(3.7) AS floor_case_1") + testFoldConst("SELECT FLOOR(-3.7) AS floor_case_2") + testFoldConst("SELECT FLOOR(5.0) AS floor_case_3") +//Exception: Floor of extremely large number + testFoldConst("SELECT FLOOR(1E308) AS floor_case_overflow") + +//Exp function cases + testFoldConst("SELECT EXP(1) AS exp_case_1") //e^1 + testFoldConst("SELECT EXP(0) AS exp_case_2") //e^0 + testFoldConst("SELECT EXP(-1) AS exp_case_3") //e^-1 + +//Ln (natural logarithm) function cases + testFoldConst("SELECT LN(1) AS ln_case_1") //ln(1) = 0 + testFoldConst("SELECT LN(EXP(1)) AS ln_case_2") //ln(e) = 1 + testFoldConst("SELECT LN(0.5) AS ln_case_3") //ln(0.5) + +//Log10 function cases + testFoldConst("SELECT LOG10(100) AS log10_case_1") //log10(100) = 2 + testFoldConst("SELECT LOG10(1) AS log10_case_2") //log10(1) = 0 + testFoldConst("SELECT LOG10(1000) AS log10_case_3") //log10(1000) = 3 + +//Sqrt function cases + testFoldConst("SELECT SQRT(16) AS sqrt_case_1") //sqrt(16) = 4 + testFoldConst("SELECT SQRT(0) AS sqrt_case_2") //sqrt(0) = 0 + testFoldConst("SELECT SQRT(2) AS sqrt_case_3") //sqrt(2) + +//Power function cases + testFoldConst("SELECT POWER(2, 3) AS power_case_1") //2^3 = 8 + testFoldConst("SELECT POWER(10, 0) AS power_case_2") //10^0 = 1 + testFoldConst("SELECT POWER(5, -1) AS power_case_3") //5^-1 = 0.2 + +//Sin function cases + testFoldConst("SELECT SIN(PI() / 2) AS sin_case_1") //sin(π/2) = 1 + testFoldConst("SELECT SIN(0) AS sin_case_2") //sin(0) = 0 + testFoldConst("SELECT SIN(PI()) AS sin_case_3") //sin(π) +//Exception: Sin of extremely large number + testFoldConst("SELECT SIN(1E308) AS sin_case_overflow") + +//Cos function cases + testFoldConst("SELECT COS(PI()) AS cos_case_1") //cos(π) = -1 + testFoldConst("SELECT COS(0) AS cos_case_2") //cos(0) = 1 + testFoldConst("SELECT COS(PI() / 2) AS cos_case_3") //cos(π/2) +//Exception: Cos of extremely large number + testFoldConst("SELECT COS(1E308) AS cos_case_overflow") + +//Tan function cases + testFoldConst("SELECT TAN(PI() / 4) AS tan_case_1") //tan(π/4) = 1 + testFoldConst("SELECT TAN(0) AS tan_case_2") //tan(0) = 0 + testFoldConst("SELECT TAN(PI()) AS tan_case_3") //tan(π) +//Exception: Tan of extremely large number (undefined for multiples of π/2) + testFoldConst("SELECT TAN(PI() / 2) AS tan_case_exception") //undefined (returns NULL or error) + +//Acos function cases + testFoldConst("SELECT ACOS(1) AS acos_case_1") //acos(1) = 0 + testFoldConst("SELECT ACOS(0) AS acos_case_2") //acos(0) = π/2 + testFoldConst("SELECT ACOS(-1) AS acos_case_3") //acos(-1) = π + +//Asin function cases + testFoldConst("SELECT ASIN(1) AS asin_case_1") //asin(1) = π/2 + testFoldConst("SELECT ASIN(0) AS asin_case_2") //asin(0) = 0 + testFoldConst("SELECT ASIN(-1) AS asin_case_3") //asin(-1) = -π/2 + +//Atan function cases + testFoldConst("SELECT ATAN(1) AS atan_case_1") //atan(1) = π/4 + testFoldConst("SELECT ATAN(0) AS atan_case_2") //atan(0) = 0 + testFoldConst("SELECT ATAN(-1) AS atan_case_3") //atan(-1) +//No exceptions for Atan, defined for all real numbers + +//Atan2 function cases + testFoldConst("SELECT ATAN2(1, 1) AS atan2_case_1") //atan2(1, 1) = π/4 + testFoldConst("SELECT ATAN2(0, 1) AS atan2_case_2") //atan2(0, 1) = 0 + testFoldConst("SELECT ATAN2(1, 0) AS atan2_case_3") //atan2(1, 0) = π/2 +//Exception: Atan2(0, 0) is undefined + testFoldConst("SELECT ATAN2(0, 0) AS atan2_case_exception") //undefined (returns NULL or error) + +//Sign function cases + testFoldConst("SELECT SIGN(5) AS sign_case_1") //sign(5) = 1 + testFoldConst("SELECT SIGN(-5) AS sign_case_2") //sign(-5) = -1 + testFoldConst("SELECT SIGN(0) AS sign_case_3") //sign(0) = 0 +//No exceptions for Sign + +//Bin function cases + testFoldConst("SELECT BIN(5) AS bin_case_1") //bin(5) = 101 + testFoldConst("SELECT BIN(16) AS bin_case_2") //bin(16) = 10000 + testFoldConst("SELECT BIN(255) AS bin_case_3") //bin(255) +//Exception: Bin of negative values (may not be defined in all DBs) + testFoldConst("SELECT BIN(-1) AS bin_case_exception") //returns NULL or error in some databases + +//BitCount function cases (count bits set to 1) + testFoldConst("SELECT BIT_COUNT(5) AS bitcount_case_1") //bitcount(5) = 2 (101 has two 1s) + testFoldConst("SELECT BIT_COUNT(16) AS bitcount_case_2") +//BitCount function cases (count bits set to 1) + testFoldConst("SELECT BIT_COUNT(5) AS bitcount_case_1") //bitcount(5) = 2 (101 has two 1s) + testFoldConst("SELECT BIT_COUNT(16) AS bitcount_case_2") //bitcount(16) = 1 + testFoldConst("SELECT BIT_COUNT(255) AS bitcount_case_3") //bitcount(255) = 8 +//Exception: BitCount of negative values + testFoldConst("SELECT BIT_COUNT(-1) AS bitcount_case_exception") //result depends on system's interpretation of negative values + +//Cbrt (cube root) function cases + testFoldConst("SELECT CBRT(8) AS cbrt_case_1") //cbrt(8) = 2 + testFoldConst("SELECT CBRT(-8) AS cbrt_case_2") //cbrt(-8) = -2 + +//Cosh function cases (hyperbolic cosine) + testFoldConst("SELECT COSH(0) AS cosh_case_1") //cosh(0) = 1 +// testFoldConst("SELECT COSH(1) AS cosh_case_2") //cosh(1) +// testFoldConst("SELECT COSH(-1) AS cosh_case_3") //cosh(-1) +//Exception: Overflow on large input +// testFoldConst("SELECT COSH(1E308) AS cosh_case_overflow") + +//Tanh function cases (hyperbolic tangent) + testFoldConst("SELECT TANH(0) AS tanh_case_1") //tanh(0) = 0 + testFoldConst("SELECT TANH(1) AS tanh_case_2") //tanh(1) + testFoldConst("SELECT TANH(-1) AS tanh_case_3") //tanh(-1) +//No exception cases for Tanh as it's defined for all real numbers + +//Dexp function cases (double exp) + testFoldConst("SELECT EXP(2.0) AS dexp_case_1") //dexp(2.0) + testFoldConst("SELECT EXP(0.5) AS dexp_case_2") //dexp(0.5) + testFoldConst("SELECT EXP(-2.0) AS dexp_case_3") //dexp(-2.0) + +//Dlog10 function cases (double log base 10) + testFoldConst("SELECT LOG10(100.0) AS dlog10_case_1") //dlog10(100.0) = 2 + testFoldConst("SELECT LOG10(1.0) AS dlog10_case_2") //dlog10(1.0) = 0 + testFoldConst("SELECT LOG10(1000.0) AS dlog10_case_3") //dlog10(1000.0) + +//Dpow function cases (double power) + testFoldConst("SELECT POWER(2.0, 3.0) AS dpow_case_1") //dpow(2.0^3.0) = 8.0 + testFoldConst("SELECT POWER(10.0, 0.0) AS dpow_case_2") //dpow(10.0^0.0) = 1.0 + testFoldConst("SELECT POWER(5.0, -1.0) AS dpow_case_3") //dpow(5.0^-1.0) = 0.2 + +//Dsqrt function cases (double sqrt) + testFoldConst("SELECT SQRT(16.0) AS dsqrt_case_1") //sqrt(16.0) = 4 + testFoldConst("SELECT SQRT(0.0) AS dsqrt_case_2") //sqrt(0.0) = 0 + testFoldConst("SELECT SQRT(2.0) AS dsqrt_case_3") //sqrt(2.0) + +//Fmod function cases (floating-point modulus) + testFoldConst("SELECT MOD(10.5, 3.2) AS fmod_case_1") //fmod(10.5 % 3.2) + testFoldConst("SELECT MOD(-10.5, 3.2) AS fmod_case_2") //fmod(-10.5 % 3.2) + testFoldConst("SELECT MOD(10.5, -3.2) AS fmod_case_3") //fmod(10.5 % -3.2) +//Exception: Division by zero in modulus + testFoldConst("SELECT MOD(10.5, 0) AS fmod_case_exception") //undefined (returns NULL or error) + +//Fpow function cases (floating-point power) + testFoldConst("SELECT POWER(2.5, 3.2) AS fpow_case_1") //fpow(2.5^3.2) + testFoldConst("SELECT POWER(10.0, 0.0) AS fpow_case_2") //fpow(10.0^0.0) = 1.0 + testFoldConst("SELECT POWER(5.5, -1.2) AS fpow_case_3") //fpow(5.5^-1.2) + +//Radians function cases (degrees to radians) + testFoldConst("SELECT RADIANS(180) AS radians_case_1") //radians(180) = π + testFoldConst("SELECT RADIANS(90) AS radians_case_2") //radians(90) = π/2 + testFoldConst("SELECT RADIANS(45) AS radians_case_3") //radians(45) +//No exception cases for Radians + +//Degrees function cases (radians to degrees) + testFoldConst("SELECT DEGREES(PI()) AS degrees_case_1") //degrees(π) = 180 + testFoldConst("SELECT DEGREES(PI()/2) AS degrees_case_2") //degrees(π/2) = 90 + testFoldConst("SELECT DEGREES(PI()/4) AS degrees_case_3") //degrees(π/4) +//No exception cases for Degrees + +//Xor function cases (bitwise XOR) + testFoldConst("SELECT 5 ^ 3 AS xor_case_1") //5 XOR 3 = 6 + testFoldConst("SELECT 0 ^ 1 AS xor_case_2") //0 XOR 1 = 1 + testFoldConst("SELECT 255 ^ 128 AS xor_case_3") //255 XOR 128 +//Exception: XOR on non-integer types (if applicable) +test { + sql "SELECT 'a' ^ 1 AS xor_case_exception" + exception("string literal 'a' cannot be cast to double") +} + +//Pi function cases + testFoldConst("SELECT PI() AS pi_case_1") //π = 3.141592653589793 +//No exception cases for Pi + +//E function cases + testFoldConst("SELECT EXP(1) AS e_case_1") //e = 2.718281828459045 +//No exception cases for E + +//Conv function cases (convert from one base to another) + testFoldConst("SELECT CONV(15, 10, 2) AS conv_case_1") //conv(15 from base 10 to base 2) = 1111 + testFoldConst("SELECT CONV(1111, 2, 10) AS conv_case_2") //conv(1111 from base 2 to base 10) = 15 + testFoldConst("SELECT CONV(255, 10, 16) AS conv_case_3") //conv(255 from base 10 to base 16) = FF +//Exception: Conv with invalid bases or negative values + testFoldConst("SELECT CONV(-10, 10, 2) AS conv_case_exception") //undefined or error + +//Truncate function cases + testFoldConst("SELECT TRUNCATE(123.456, 2) AS truncate_case_1") //truncate(123.456, 2) = 123.45 + testFoldConst("SELECT TRUNCATE(-123.456, 1) AS truncate_case_2") //truncate(-123.456, 1) = -123.4 + testFoldConst("SELECT TRUNCATE(123.456, 0) AS truncate_case_3") //truncate(123.456, 0) = 123 +//Exception: Truncate with negative decimal places + testFoldConst("SELECT TRUNCATE(123.456, -1) AS truncate_case_exception") //undefined or error + +//CountEqual function cases + testFoldConst("SELECT COUNT(CASE WHEN 5 = 5 THEN 1 END) AS countequal_case_1") //1 (true) + testFoldConst("SELECT COUNT(CASE WHEN 5 = 3 THEN 1 END) AS countequal_case_2") //0 (false) +//Exception: Undefined operation + testFoldConst("SELECT COUNT(CASE WHEN 'a' = 1 THEN 1 END) AS countequal_case_exception") //undefined or error + +//Pmod function cases (positive +//Pmod function cases (positive modulus) + testFoldConst("SELECT MOD(10, 3) AS pmod_case_1") //pmod(10 % 3) = 1 + testFoldConst("SELECT MOD(-10, 3) AS pmod_case_2") //pmod(-10 % 3) = 2 (makes result positive) + testFoldConst("SELECT MOD(10, -3) AS pmod_case_3") //pmod(10 % -3) = -2 (ensures result is positive) +//Exception: Division by zero in modulus + testFoldConst("SELECT MOD(10, 0) AS pmod_case_exception") //undefined (returns NULL or error) + +//Summary of Edge Cases and Overflows +//Round, Ceil, Floor with extremely large values + testFoldConst("SELECT ROUND(1E308) AS round_large_value") + testFoldConst("SELECT CEIL(1E308) AS ceil_large_value") + testFoldConst("SELECT FLOOR(1E308) AS floor_large_value") + +//Trigonometric functions with large inputs or boundary conditions + testFoldConst("SELECT SIN(1E308) AS sin_large_value") //Sin overflow + testFoldConst("SELECT COS(1E308) AS cos_large_value") //Cos overflow + testFoldConst("SELECT TAN(PI() / 2) AS tan_undefined") //Undefined for tan(π/2) + +//Miscellaneous operations like bit manipulations and modulo on edge cases + testFoldConst("SELECT BIN(-1) AS bin_negative_value") //Bin of negative number (may be undefined) + testFoldConst("SELECT BIT_COUNT(-1) AS bitcount_negative_value") //BitCount of negative number + testFoldConst("SELECT MOD(10.5, 0) AS fmod_divide_by_zero") //Modulo by zero (undefined) + testFoldConst("SELECT TRUNCATE(123.456, -1) AS truncate_negative_decimals") //Truncate with negative decimals + +//Additional cases for Xor, Conv, and other mathematical functions + testFoldConst("SELECT CONV(-10, 10, 2) AS conv_invalid_base") //Conv with negative input (may be undefined) +} diff --git a/regression-test/suites/nereids_rules_p0/partition_prune/test_multi_range_partition.groovy b/regression-test/suites/nereids_rules_p0/partition_prune/test_multi_range_partition.groovy index 23fad332f4c43d..319d6fb8141bd4 100644 --- a/regression-test/suites/nereids_rules_p0/partition_prune/test_multi_range_partition.groovy +++ b/regression-test/suites/nereids_rules_p0/partition_prune/test_multi_range_partition.groovy @@ -73,7 +73,7 @@ suite("test_multi_range_partition") { } explain{ sql "select * from pt where sin(k1)=0" - contains "artitions=3/3 (p1,p2,p3)" + contains "partitions=1/3 (p1)" } // fix BUG: p1 missed