diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeArithmetic.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeArithmetic.java index 033bff2afd33dd..54add9565ca9b6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeArithmetic.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeArithmetic.java @@ -174,6 +174,16 @@ public static Expression daysAdd(DateTimeV2Literal date, IntegerLiteral day) { /** * datetime arithmetic function hours-add. */ + @ExecFunction(name = "hours_add", argTypes = {"DATE", "INT"}, returnType = "DATE") + public static Expression hoursAdd(DateLiteral date, IntegerLiteral hour) { + return date.toBeginOfTheDay().plusHours(hour.getValue()); + } + + @ExecFunction(name = "hours_add", argTypes = {"DATEV2", "INT"}, returnType = "DATEV2") + public static Expression hoursAdd(DateV2Literal date, IntegerLiteral hour) { + return date.toBeginOfTheDay().plusHours(hour.getValue()); + } + @ExecFunction(name = "hours_add", argTypes = {"DATETIME", "INT"}, returnType = "DATETIME") public static Expression hoursAdd(DateTimeLiteral date, IntegerLiteral hour) { return date.plusHours(hour.getValue()); @@ -187,6 +197,16 @@ public static Expression hoursAdd(DateTimeV2Literal date, IntegerLiteral hour) { /** * datetime arithmetic function minutes-add. */ + @ExecFunction(name = "minutes_add", argTypes = {"DATE", "INT"}, returnType = "DATE") + public static Expression minutesAdd(DateLiteral date, IntegerLiteral minute) { + return date.toBeginOfTheDay().plusMinutes(minute.getValue()); + } + + @ExecFunction(name = "minutes_add", argTypes = {"DATEV2", "INT"}, returnType = "DATEV2") + public static Expression minutesAdd(DateV2Literal date, IntegerLiteral minute) { + return date.toBeginOfTheDay().plusMinutes(minute.getValue()); + } + @ExecFunction(name = "minutes_add", argTypes = {"DATETIME", "INT"}, returnType = "DATETIME") public static Expression minutesAdd(DateTimeLiteral date, IntegerLiteral minute) { return date.plusMinutes(minute.getValue()); @@ -200,6 +220,16 @@ public static Expression minutesAdd(DateTimeV2Literal date, IntegerLiteral minut /** * datetime arithmetic function seconds-add. */ + @ExecFunction(name = "seconds_add", argTypes = {"DATE", "INT"}, returnType = "DATE") + public static Expression secondsAdd(DateLiteral date, IntegerLiteral second) { + return date.toBeginOfTheDay().plusSeconds(second.getValue()); + } + + @ExecFunction(name = "seconds_add", argTypes = {"DATEV2", "INT"}, returnType = "DATEV2") + public static Expression secondsAdd(DateV2Literal date, IntegerLiteral second) { + return date.toBeginOfTheDay().plusSeconds(second.getValue()); + } + @ExecFunction(name = "seconds_add", argTypes = {"DATETIME", "INT"}, returnType = "DATETIME") public static Expression secondsAdd(DateTimeLiteral date, IntegerLiteral second) { return date.plusSeconds(second.getValue()); @@ -380,4 +410,14 @@ public static Expression dateDiff(DateTimeV2Literal date1, DateTimeV2Literal dat private static int dateDiff(LocalDateTime date1, LocalDateTime date2) { return ((int) ChronoUnit.DAYS.between(date2.toLocalDate(), date1.toLocalDate())); } + + @ExecFunction(name = "to_days", argTypes = {"DATE"}, returnType = "INT") + public static Expression toDays(DateLiteral date) { + return new IntegerLiteral((int) date.getDay()); + } + + @ExecFunction(name = "to_days", argTypes = {"DATEV2"}, returnType = "INT") + public static Expression toDays(DateV2Literal date) { + return new IntegerLiteral((int) date.getDay()); + } } 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 384bfcecead624..d553df69d79fd1 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 @@ -31,6 +31,18 @@ import org.apache.doris.nereids.trees.expressions.TimestampArithmetic; 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.AppendTrailingCharIfAbsent; +import org.apache.doris.nereids.trees.expressions.functions.scalar.ConvertTz; +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.FromUnixtime; +import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd; +import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesAdd; +import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd; +import org.apache.doris.nereids.trees.expressions.functions.scalar.StrToDate; +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; import org.apache.doris.nereids.trees.expressions.literal.DateLiteral; import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral; @@ -39,6 +51,8 @@ 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.VarcharLiteral; import org.apache.doris.nereids.trees.plans.RelationId; import org.apache.doris.nereids.types.DateTimeV2Type; @@ -155,9 +169,76 @@ public void testCastFold() { } @Test - public void testCompareFold() { + void testFoldDate() { + executor = new ExpressionRuleExecutor(ImmutableList.of( + bottomUp(FoldConstantRuleOnFE.VISITOR_INSTANCE) + )); + HoursAdd hoursAdd = new HoursAdd(DateLiteral.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 1)), + new IntegerLiteral(1)); + Expression rewritten = executor.rewrite(hoursAdd, context); + Assertions.assertEquals(new DateTimeLiteral("0001-01-01 01:00:00"), rewritten); + hoursAdd = new HoursAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 1)), + new IntegerLiteral(1)); + rewritten = executor.rewrite(hoursAdd, context); + Assertions.assertEquals(new DateTimeV2Literal("0001-01-01 01:00:00"), rewritten); + hoursAdd = new HoursAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(9999, 12, 31, 23, 1, 1)), + new IntegerLiteral(24)); + rewritten = executor.rewrite(hoursAdd, context); + Assertions.assertEquals(new NullLiteral(hoursAdd.getDataType()), rewritten); + hoursAdd = new HoursAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(0, 1, 1, 1, 1, 1)), + new IntegerLiteral(-25)); + rewritten = executor.rewrite(hoursAdd, context); + Assertions.assertEquals(new NullLiteral(hoursAdd.getDataType()), rewritten); + + MinutesAdd minutesAdd = new MinutesAdd(DateLiteral.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 1)), + new IntegerLiteral(1)); + rewritten = executor.rewrite(minutesAdd, context); + Assertions.assertEquals(new DateTimeLiteral("0001-01-01 00:01:00"), rewritten); + minutesAdd = new MinutesAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 1)), + new IntegerLiteral(1)); + rewritten = executor.rewrite(minutesAdd, context); + Assertions.assertEquals(new DateTimeV2Literal("0001-01-01 00:01:00"), rewritten); + minutesAdd = new MinutesAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(9999, 12, 31, 23, 59, 1)), + new IntegerLiteral(1440)); + rewritten = executor.rewrite(minutesAdd, context); + Assertions.assertEquals(new NullLiteral(minutesAdd.getDataType()), rewritten); + minutesAdd = new MinutesAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(0, 1, 1, 0, 1, 1)), + new IntegerLiteral(-2)); + rewritten = executor.rewrite(minutesAdd, context); + Assertions.assertEquals(new NullLiteral(minutesAdd.getDataType()), rewritten); + + SecondsAdd secondsAdd = new SecondsAdd(DateLiteral.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 1)), + new IntegerLiteral(1)); + rewritten = executor.rewrite(secondsAdd, context); + Assertions.assertEquals(new DateTimeLiteral("0001-01-01 00:00:01"), rewritten); + secondsAdd = new SecondsAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 1)), + new IntegerLiteral(1)); + rewritten = executor.rewrite(secondsAdd, context); + Assertions.assertEquals(new DateTimeV2Literal("0001-01-01 00:00:01"), rewritten); + secondsAdd = new SecondsAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(9999, 12, 31, 23, 59, 59)), + new IntegerLiteral(86400)); + rewritten = executor.rewrite(secondsAdd, context); + Assertions.assertEquals(new NullLiteral(secondsAdd.getDataType()), rewritten); + secondsAdd = new SecondsAdd(DateV2Literal.fromJavaDateType(LocalDateTime.of(0, 1, 1, 0, 1, 1)), + new IntegerLiteral(-61)); + rewritten = executor.rewrite(secondsAdd, context); + Assertions.assertEquals(new NullLiteral(secondsAdd.getDataType()), rewritten); + + ToDays toDays = new ToDays(DateLiteral.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 1))); + rewritten = executor.rewrite(toDays, context); + Assertions.assertEquals(new IntegerLiteral(366), rewritten); + toDays = new ToDays(DateV2Literal.fromJavaDateType(LocalDateTime.of(1, 1, 1, 1, 1, 1))); + rewritten = executor.rewrite(toDays, context); + Assertions.assertEquals(new IntegerLiteral(366), rewritten); + toDays = new ToDays(DateV2Literal.fromJavaDateType(LocalDateTime.of(9999, 12, 31, 1, 1, 1))); + rewritten = executor.rewrite(toDays, context); + Assertions.assertEquals(new IntegerLiteral(3652424), rewritten); + } + + @Test + void testCompareFold() { executor = new ExpressionRuleExecutor(ImmutableList.of(FoldConstantRuleOnFE.INSTANCE)); - assertRewriteAfterTypeCoercion("'1' = 2", "false"); + assertRewriteAfterTypeCoercion("'1' = 2", "false"); assertRewriteAfterTypeCoercion("1 = 2", "false"); assertRewriteAfterTypeCoercion("1 != 2", "true"); assertRewriteAfterTypeCoercion("2 > 2", "false"); diff --git a/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_by_fe.groovy b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_by_fe.groovy index 33b267f8f752d4..1d7fd7d397614d 100644 --- a/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_by_fe.groovy +++ b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_by_fe.groovy @@ -161,4 +161,6 @@ suite("test_fold_constant_by_fe") { res = sql """explain select "12" like '%123%'""" assertTrue(res.contains("like")) + testFoldConst("select DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY) + INTERVAL 3600 SECOND") + }