diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java index e0d717cd04f66a..2dbd5cbd31b8a9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; import org.apache.doris.nereids.trees.expressions.functions.Monotonic; import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral; +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; import org.apache.doris.nereids.trees.expressions.shape.TernaryExpression; @@ -87,6 +88,11 @@ public R accept(ExpressionVisitor visitor, C context) { return visitor.visitConvertTz(this, context); } + @Override + public boolean isMonotonic(Literal lower, Literal upper) { + return child(1).isConstant() && child(2).isConstant(); + } + @Override public boolean isPositive() { return true; diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java index 2cc97e7c3afecc..997464cf81a5ac 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateFormat.java @@ -21,7 +21,10 @@ import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.Monotonic; import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral; +import org.apache.doris.nereids.trees.expressions.literal.Literal; +import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral; import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.DateTimeType; @@ -32,14 +35,16 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import java.util.List; +import java.util.Set; /** * ScalarFunction 'date_format'. This class is generated by GenerateFunction. */ public class DateFormat extends ScalarFunction - implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable, PropagateNullLiteral { + implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable, PropagateNullLiteral, Monotonic { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT) @@ -49,6 +54,10 @@ public class DateFormat extends ScalarFunction FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(DateType.INSTANCE, VarcharType.SYSTEM_DEFAULT) ); + private static final Set monoFormat = ImmutableSet.of("yyyyMMdd", "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", + "%Y", "%Y-%m", "%Y-%m-%d", "%Y-%m-%d %H", "%Y-%m-%d %H:%i", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d %H:%i:%S", + "%Y-%m-%d %T", "%Y%m%d", "%Y%m"); + /** * constructor with 2 arguments. */ @@ -74,4 +83,29 @@ public List getSignatures() { public R accept(ExpressionVisitor visitor, C context) { return visitor.visitDateFormat(this, context); } + + @Override + public boolean isMonotonic(Literal lower, Literal upper) { + Expression format = child(1); + if (!(format instanceof VarcharLiteral)) { + return false; + } + String str = ((VarcharLiteral) format).getValue(); + return monoFormat.contains(str); + } + + @Override + public boolean isPositive() { + return true; + } + + @Override + public int getMonotonicFunctionChildIndex() { + return 0; + } + + @Override + public Expression withConstantArgs(Expression literal) { + return new DateFormat(literal, child(1)); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/LastDay.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/LastDay.java index bd3783abd9a963..bb45f13874778e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/LastDay.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/LastDay.java @@ -20,6 +20,7 @@ import org.apache.doris.catalog.FunctionSignature; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.Monotonic; import org.apache.doris.nereids.trees.expressions.functions.PropagateNullableOnDateLikeV2Args; import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; @@ -37,7 +38,7 @@ * ScalarFunction 'last_day'. This class is generated by GenerateFunction. */ public class LastDay extends ScalarFunction - implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args { + implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args, Monotonic { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(DateV2Type.INSTANCE).args(DateV2Type.INSTANCE), @@ -71,4 +72,19 @@ public R accept(ExpressionVisitor visitor, C context) { public List getSignatures() { return SIGNATURES; } + + @Override + public boolean isPositive() { + return true; + } + + @Override + public int getMonotonicFunctionChildIndex() { + return 0; + } + + @Override + public Expression withConstantArgs(Expression literal) { + return new LastDay(literal); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ToDate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ToDate.java index 7bda334f522710..0638ee2d33dbf5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ToDate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ToDate.java @@ -21,6 +21,7 @@ import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.Monotonic; import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral; import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; @@ -38,7 +39,7 @@ * ScalarFunction 'to_date'. This class is generated by GenerateFunction. */ public class ToDate extends ScalarFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNullable, PropagateNullLiteral { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNullable, PropagateNullLiteral, Monotonic { private static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(DateV2Type.INSTANCE).args(DateTimeV2Type.SYSTEM_DEFAULT), @@ -70,4 +71,19 @@ public List getSignatures() { public R accept(ExpressionVisitor visitor, C context) { return visitor.visitToDate(this, context); } + + @Override + public boolean isPositive() { + return true; + } + + @Override + public int getMonotonicFunctionChildIndex() { + return 0; + } + + @Override + public Expression withConstantArgs(Expression literal) { + return new ToDate(literal); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ToMonday.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ToMonday.java index 216b3d3ba78203..565861eacf16f4 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ToMonday.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ToMonday.java @@ -20,6 +20,7 @@ import org.apache.doris.catalog.FunctionSignature; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.Monotonic; import org.apache.doris.nereids.trees.expressions.functions.PropagateNullableOnDateLikeV2Args; import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; @@ -37,7 +38,7 @@ * ScalarFunction 'to_monday'. This class is generated by GenerateFunction. */ public class ToMonday extends ScalarFunction - implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args { + implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args, Monotonic { private static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(DateV2Type.INSTANCE).args(DateV2Type.INSTANCE), @@ -71,4 +72,19 @@ public R accept(ExpressionVisitor visitor, C context) { public List getSignatures() { return SIGNATURES; } + + @Override + public boolean isPositive() { + return true; + } + + @Override + public int getMonotonicFunctionChildIndex() { + return 0; + } + + @Override + public Expression withConstantArgs(Expression literal) { + return new ToMonday(literal); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Year.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Year.java index 7268e1a79bd885..6f60ecd3b85dbd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Year.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Year.java @@ -20,6 +20,7 @@ import org.apache.doris.catalog.FunctionSignature; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.Monotonic; import org.apache.doris.nereids.trees.expressions.functions.PropagateNullableOnDateLikeV2Args; import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; @@ -37,7 +38,7 @@ * ScalarFunction 'year'. This class is generated by GenerateFunction. */ public class Year extends ScalarFunction - implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args { + implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args, Monotonic { private static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(SmallIntType.INSTANCE).args(DateV2Type.INSTANCE), @@ -70,4 +71,19 @@ public List getSignatures() { public R accept(ExpressionVisitor visitor, C context) { return visitor.visitYear(this, context); } + + @Override + public boolean isPositive() { + return true; + } + + @Override + public int getMonotonicFunctionChildIndex() { + return 0; + } + + @Override + public Expression withConstantArgs(Expression literal) { + return new Year(literal); + } } diff --git a/regression-test/suites/nereids_rules_p0/partition_prune/always_mono_func.groovy b/regression-test/suites/nereids_rules_p0/partition_prune/always_mono_func.groovy new file mode 100644 index 00000000000000..1936dd85accc43 --- /dev/null +++ b/regression-test/suites/nereids_rules_p0/partition_prune/always_mono_func.groovy @@ -0,0 +1,221 @@ +// 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("always_mono_func") { + sql "drop table if exists always_mono_func" + sql """create table always_mono_func (a int, dt datetime, d date, c varchar(100)) duplicate key(a) + partition by range(dt) ( + partition p1 values less than ("2017-01-01"), + partition p2 values less than ("2018-01-01"), + partition p3 values less than ("2019-01-01"), + partition p4 values less than ("2020-01-01"), + partition p5 values less than ("2021-01-01") + ) distributed by hash(a) properties("replication_num"="1");""" + sql """INSERT INTO always_mono_func SELECT number, + date_add('2016-01-01 00:00:00', interval number month), + cast(date_add('2022-01-01 00:00:00', interval number month) as date), cast(number as varchar(65533)) FROM numbers('number'='55');""" + sql "INSERT INTO always_mono_func values(3,null,null,null);" + + explain { + sql """select * from always_mono_func where date_format(dt, "yyyyMMdd") <"20190101" """ + contains("partitions=3/5 (p1,p2,p3)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "yyyyMMdd") <"2019-01-01" """ + contains("partitions=3/5 (p1,p2,p3)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "yyyy-MM-dd") < "2019-01-01" """ + contains("partitions=3/5 (p1,p2,p3)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "yyyy-MM-dd") > "2019-01-01" """ + contains("partitions=2/5 (p4,p5)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "yyyy-MM-dd HH:mm:ss") < "2019-01-01" """ + contains("partitions=3/5 (p1,p2,p3)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "yyyy-MM-dd") = "2019-01-01" """ + contains("partitions=2/5 (p3,p4)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "yyyy-MM-dd HH:mm:ss") = "2019-01-01 00:00:00" """ + contains("partitions=2/5 (p3,p4)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y") <= "2018" and date_format(dt, "%Y") > "2017" """ + contains("partitions=2/5 (p2,p3)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y") <= "2019-01-01" """ + contains("partitions=4/5 (p1,p2,p3,p4)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y-%m")>="2019-01-01" """ + contains("partitions=2/5 (p4,p5)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "%Y-%m-%d")<>"2019-01-01" """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y-%m-%d %H")<="2019-01-01" """ + contains("partitions=3/5 (p1,p2,p3)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y-%m-%d %H:%i")> "2019-01-01" """ + contains("partitions=3/5 (p3,p4,p5)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "%Y-%m-%d %H:%i:%s")> "2019-01-01 00:00:00" """ + contains("partitions=2/5 (p4,p5)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y-%m-%d %H:%i:%S")> "2019-01-01 00:00:00" """ + contains("partitions=2/5 (p4,p5)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y-%m-%d %T") > "2019-01-01" """ + contains("partitions=3/5 (p3,p4,p5)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y%m") > "20190101" """ + contains("partitions=2/5 (p4,p5)") + } + explain { + sql """select * from always_mono_func where date_format(dt, "%Y %m") > "2019 01" """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "yyyyddMM") <"20190101" """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + + explain { + sql """select * from always_mono_func where date_format(dt, "%Y-%d-%m %T") <"2019-01-01" """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + + // year + explain { + sql """ select * from always_mono_func where year(dt) >= 2019 """ + contains("partitions=3/5 (p3,p4,p5)") + } + explain { + sql """select * from always_mono_func where year(dt) < 2019 and year(dt) > 2017""" + contains("partitions=2/5 (p2,p3)") + } + explain { + sql """select * from always_mono_func where year(dt) <2023""" + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + // to_monday + explain { + sql """select * from always_mono_func where to_monday(dt) <'2019-01-01' """ + contains("partitions=4/5 (p1,p2,p3,p4)") + } + explain { + sql """select * from always_mono_func where to_monday(dt) ='2019-01-01' """ + contains("partitions=2/5 (p1,p4)") + } + explain { + sql """select * from always_mono_func where to_monday(dt) >='2018-01-01' and to_monday(dt) <'2019-01-01' """ + contains("partitions=4/5 (p1,p2,p3,p4)") + } + explain { + sql """ select * from always_mono_func where to_monday(dt) >= "2019-01-01" """ + contains("partitions=3/5 (p1,p4,p5)") + } + // to_date + explain { + sql """select * from always_mono_func where to_date(dt) <'2019-02-01' """ + contains("partitions=4/5 (p1,p2,p3,p4)") + } + explain { + sql """select * from always_mono_func where to_date(dt) <='2023-02-01' """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + explain { + sql """select * from always_mono_func where to_date(dt) is null """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + explain { + sql """select * from always_mono_func where to_date(dt) is not null """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + explain { + sql """select * from always_mono_func where to_date(dt) >='2018-01-01' and to_date(dt) <'2019-01-01' """ + contains("partitions=2/5 (p2,p3)") + } + explain { + sql """ select * from always_mono_func where to_date(dt) > "2019-01-01" """ + contains("partitions=2/5 (p4,p5)") + } + // last_day + explain { + sql """select * from always_mono_func where last_day(dt) <='2019-02-01' """ + contains("partitions=4/5 (p1,p2,p3,p4)") + } + explain { + sql """select * from always_mono_func where last_day(dt) <='2023-02-01' """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + explain { + sql """select * from always_mono_func where last_day(dt) is null """ + contains("partitions=1/5 (p1)") + } + explain { + sql """select * from always_mono_func where last_day(dt) is not null """ + contains("partitions=5/5 (p1,p2,p3,p4,p5)") + } + explain { + sql """select * from always_mono_func where last_day(dt) >='2018-01-01' and last_day(dt) <'2019-01-01' """ + contains("partitions=2/5 (p2,p3)") + } + explain { + sql """ select * from always_mono_func where last_day(dt) > "2019-01-01" """ + contains("partitions=3/5 (p3,p4,p5)") + } + + explain { + sql """select * from always_mono_func where date_format(to_monday(dt), 'yyyyMMdd') >= "20190101" """ + contains("partitions=3/5 (p1,p4,p5)") + } + explain { + sql """select * from always_mono_func where date_format(last_day(to_monday(dt)), 'yyyyMMdd') < "20190101" """ + contains("partitions=4/5 (p1,p2,p3,p4)") + } + explain { + sql """select * from always_mono_func where date_format(last_day(to_monday(to_date(dt))), 'yyyyMMdd') <= "20190101" """ + contains("partitions=4/5 (p1,p2,p3,p4)") + } + + explain { + sql """select * from always_mono_func where date_format(date_trunc(last_day(to_monday(dt)),'month'), 'yyyyMMdd') > "20190101" """ + contains("partitions=3/5 (p1,p4,p5)") + } +} \ No newline at end of file