This is an automated email from the ASF dual-hosted git repository.

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new 152528c8397 branch-3.1: [refactor](Nereids) refactor the parsing way 
of date series functions #46037 (#52443)
152528c8397 is described below

commit 152528c839754581bd4dbae3de70661f22ddc30e
Author: morrySnow <[email protected]>
AuthorDate: Mon Jun 30 10:59:11 2025 +0800

    branch-3.1: [refactor](Nereids) refactor the parsing way of date series 
functions #46037 (#52443)
    
    Cherry-picked #46037
---
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |  15 -
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |  70 +--
 .../doris/nereids/parser/LogicalPlanBuilder.java   | 265 ---------
 .../rules/analysis/ArithmeticFunctionBinder.java   |   3 +
 .../rules/analysis/DatetimeFunctionBinder.java     | 348 ++++++++++++
 .../nereids/rules/analysis/ExpressionAnalyzer.java |  54 +-
 .../expressions/literal/DateTimeV2Literal.java     |   3 +
 .../trees/expressions/literal/Interval.java        |  24 +-
 .../doris/nereids/util/TypeCoercionUtils.java      |  16 +
 .../rules/analysis/DatetimeFunctionBinderTest.java | 626 +++++++++++++++++++++
 10 files changed, 1060 insertions(+), 364 deletions(-)

diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
index d55306f79da..730441b1253 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
@@ -80,7 +80,6 @@ ACCOUNT_LOCK: 'ACCOUNT_LOCK';
 ACCOUNT_UNLOCK: 'ACCOUNT_UNLOCK';
 ACTIONS: 'ACTIONS';
 ADD: 'ADD';
-ADDDATE:'ADDDATE';
 ADMIN: 'ADMIN';
 AFTER: 'AFTER';
 AGG_STATE: 'AGG_STATE';
@@ -95,7 +94,6 @@ AND: 'AND';
 ANTI: 'ANTI';
 APPEND: 'APPEND';
 ARRAY: 'ARRAY';
-ARRAY_RANGE: 'ARRAY_RANGE';
 AS: 'AS';
 ASC: 'ASC';
 AT: 'AT';
@@ -182,21 +180,12 @@ DATA: 'DATA';
 DATABASE: 'DATABASE';
 DATABASES: 'DATABASES';
 DATE: 'DATE';
-DATE_ADD: 'DATE_ADD';
-DATE_CEIL: 'DATE_CEIL';
-DATE_DIFF: 'DATE_DIFF';
-DATE_FLOOR: 'DATE_FLOOR';
-DATE_SUB: 'DATE_SUB';
-DATEADD: 'DATEADD';
-DATEDIFF: 'DATEDIFF';
 DATETIME: 'DATETIME';
 DATETIMEV2: 'DATETIMEV2';
 DATEV2: 'DATEV2';
 DATETIMEV1: 'DATETIMEV1';
 DATEV1: 'DATEV1';
 DAY: 'DAY';
-DAYS_ADD: 'DAYS_ADD';
-DAYS_SUB: 'DAYS_SUB';
 DECIMAL: 'DECIMAL';
 DECIMALV2: 'DECIMALV2';
 DECIMALV3: 'DECIMALV3';
@@ -479,7 +468,6 @@ SCHEMAS: 'SCHEMAS';
 SECOND: 'SECOND';
 SELECT: 'SELECT';
 SEMI: 'SEMI';
-SEQUENCE: 'SEQUENCE';
 SERIALIZABLE: 'SERIALIZABLE';
 SESSION: 'SESSION';
 SESSION_USER: 'SESSION_USER';
@@ -508,7 +496,6 @@ STREAM: 'STREAM';
 STREAMING: 'STREAMING';
 STRING: 'STRING';
 STRUCT: 'STRUCT';
-SUBDATE: 'SUBDATE';
 SUM: 'SUM';
 SUPERUSER: 'SUPERUSER';
 SWITCH: 'SWITCH';
@@ -528,8 +515,6 @@ THAN: 'THAN';
 THEN: 'THEN';
 TIME: 'TIME';
 TIMESTAMP: 'TIMESTAMP';
-TIMESTAMPADD: 'TIMESTAMPADD';
-TIMESTAMPDIFF: 'TIMESTAMPDIFF';
 TINYINT: 'TINYINT';
 TO: 'TO';
 TOKENIZER: 'TOKENIZER';
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index 2e53b4187a4..efaebb8d445 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -1373,7 +1373,7 @@ fixedPartitionDef
     ;
 
 stepPartitionDef
-    : FROM from=partitionValueList TO to=partitionValueList INTERVAL 
unitsAmount=INTEGER_VALUE unit=datetimeUnit?
+    : FROM from=partitionValueList TO to=partitionValueList INTERVAL 
unitsAmount=INTEGER_VALUE unit=unitIdentifier?
     ;
 
 inPartitionDef
@@ -1471,61 +1471,10 @@ valueExpression
     | left=valueExpression operator=(PLUS | SUBTRACT | HAT | PIPE | AMPERSAND)
                            right=valueExpression                               
              #arithmeticBinary
     | left=valueExpression comparisonOperator right=valueExpression            
              #comparison
-    | operator=(BITAND | BITOR | BITXOR) LEFT_PAREN left = valueExpression
-                COMMA right = valueExpression RIGHT_PAREN                      
              #bitOperation
-    ;
-
-datetimeUnit
-    : YEAR | MONTH
-    | WEEK | DAY
-    | HOUR | MINUTE | SECOND
     ;
 
 primaryExpression
-    : name=(TIMESTAMPDIFF | DATEDIFF)
-            LEFT_PAREN
-                unit=datetimeUnit COMMA
-                startTimestamp=valueExpression COMMA
-                endTimestamp=valueExpression
-            RIGHT_PAREN                                                        
                #timestampdiff
-    | name=(TIMESTAMPADD | DATEADD)
-                  LEFT_PAREN
-                      unit=datetimeUnit COMMA
-                      startTimestamp=valueExpression COMMA
-                      endTimestamp=valueExpression
-                  RIGHT_PAREN                                                  
                #timestampadd
-    | name =(ADDDATE | DAYS_ADD | DATE_ADD)
-            LEFT_PAREN
-                timestamp=valueExpression COMMA
-                (INTERVAL unitsAmount=valueExpression unit=datetimeUnit
-                | unitsAmount=valueExpression)
-            RIGHT_PAREN                                                        
                #date_add
-    | name=(SUBDATE | DAYS_SUB | DATE_SUB)
-            LEFT_PAREN
-                timestamp=valueExpression COMMA
-                (INTERVAL unitsAmount=valueExpression  unit=datetimeUnit
-                | unitsAmount=valueExpression)
-            RIGHT_PAREN                                                        
                #date_sub
-    | name=DATE_FLOOR
-            LEFT_PAREN
-                timestamp=valueExpression COMMA
-                (INTERVAL unitsAmount=valueExpression  unit=datetimeUnit
-                | unitsAmount=valueExpression)
-            RIGHT_PAREN                                                        
                #dateFloor
-    | name=DATE_CEIL
-            LEFT_PAREN
-                timestamp=valueExpression COMMA
-                (INTERVAL unitsAmount=valueExpression  unit=datetimeUnit
-                | unitsAmount=valueExpression)
-            RIGHT_PAREN                                                        
                #dateCeil
-    | name =(ARRAY_RANGE | SEQUENCE)
-            LEFT_PAREN
-                start=valueExpression COMMA
-                end=valueExpression COMMA
-                (INTERVAL unitsAmount=valueExpression unit=datetimeUnit
-                | unitsAmount=valueExpression)
-            RIGHT_PAREN                                                        
                #arrayRange
-    | name=CURRENT_DATE                                                        
                #currentDate
+    : name=CURRENT_DATE                                                        
                #currentDate
     | name=CURRENT_TIME                                                        
                #currentTime
     | name=CURRENT_TIMESTAMP                                                   
                #currentTimestamp
     | name=LOCALTIME                                                           
                #localTime
@@ -1794,7 +1743,6 @@ number
 nonReserved
 //--DEFAULT-NON-RESERVED-START
     : ACTIONS
-    | ADDDATE
     | AFTER
     | AGG_STATE
     | AGGREGATE
@@ -1802,7 +1750,6 @@ nonReserved
     | ALWAYS
     | ANALYZED
     | ARRAY
-    | ARRAY_RANGE
     | AT
     | AUTHORS
     | AUTO_INCREMENT
@@ -1867,21 +1814,12 @@ nonReserved
     | CURRENT_USER
     | DATA
     | DATE
-    | DATE_ADD
-    | DATE_CEIL
-    | DATE_DIFF
-    | DATE_FLOOR
-    | DATE_SUB
-    | DATEADD
-    | DATEDIFF
     | DATETIME
     | DATETIMEV1
     | DATETIMEV2
     | DATEV1
     | DATEV2
     | DAY
-    | DAYS_ADD
-    | DAYS_SUB
     | DECIMAL
     | DECIMALV2
     | DECIMALV3
@@ -2062,7 +2000,6 @@ nonReserved
     | SECOND
     | SERIALIZABLE
     | SET_SESSION_VARIABLE
-    | SEQUENCE
     | SESSION
     | SESSION_USER
     | SHAPE
@@ -2083,7 +2020,6 @@ nonReserved
     | STREAMING
     | STRING
     | STRUCT
-    | SUBDATE
     | SUM
     | TABLES
     | TASK
@@ -2093,8 +2029,6 @@ nonReserved
     | THAN
     | TIME
     | TIMESTAMP
-    | TIMESTAMPADD
-    | TIMESTAMPDIFF
     | TRANSACTION
     | TREE
     | TRIGGERS
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index 90a73c68b02..09c0855a828 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -56,9 +56,7 @@ import org.apache.doris.nereids.DorisParser.AlterViewContext;
 import org.apache.doris.nereids.DorisParser.ArithmeticBinaryContext;
 import org.apache.doris.nereids.DorisParser.ArithmeticUnaryContext;
 import org.apache.doris.nereids.DorisParser.ArrayLiteralContext;
-import org.apache.doris.nereids.DorisParser.ArrayRangeContext;
 import org.apache.doris.nereids.DorisParser.ArraySliceContext;
-import org.apache.doris.nereids.DorisParser.BitOperationContext;
 import org.apache.doris.nereids.DorisParser.BooleanExpressionContext;
 import org.apache.doris.nereids.DorisParser.BooleanLiteralContext;
 import org.apache.doris.nereids.DorisParser.BracketDistributeTypeContext;
@@ -89,10 +87,6 @@ import 
org.apache.doris.nereids.DorisParser.CreateTableLikeContext;
 import org.apache.doris.nereids.DorisParser.CreateViewContext;
 import org.apache.doris.nereids.DorisParser.CteContext;
 import org.apache.doris.nereids.DorisParser.DataTypeWithNullableContext;
-import org.apache.doris.nereids.DorisParser.DateCeilContext;
-import org.apache.doris.nereids.DorisParser.DateFloorContext;
-import org.apache.doris.nereids.DorisParser.Date_addContext;
-import org.apache.doris.nereids.DorisParser.Date_subContext;
 import org.apache.doris.nereids.DorisParser.DecimalLiteralContext;
 import org.apache.doris.nereids.DorisParser.DeleteContext;
 import org.apache.doris.nereids.DorisParser.DereferenceContext;
@@ -206,8 +200,6 @@ import 
org.apache.doris.nereids.DorisParser.SystemVariableContext;
 import org.apache.doris.nereids.DorisParser.TableAliasContext;
 import org.apache.doris.nereids.DorisParser.TableNameContext;
 import org.apache.doris.nereids.DorisParser.TableValuedFunctionContext;
-import org.apache.doris.nereids.DorisParser.TimestampaddContext;
-import org.apache.doris.nereids.DorisParser.TimestampdiffContext;
 import org.apache.doris.nereids.DorisParser.TypeConstructorContext;
 import org.apache.doris.nereids.DorisParser.UnitIdentifierContext;
 import org.apache.doris.nereids.DorisParser.UnsupportedContext;
@@ -298,61 +290,18 @@ import 
org.apache.doris.nereids.trees.expressions.WindowFrame;
 import org.apache.doris.nereids.trees.expressions.functions.Function;
 import org.apache.doris.nereids.trees.expressions.functions.agg.Count;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Array;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRange;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeDayUnit;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeHourUnit;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeMinuteUnit;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeMonthUnit;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeSecondUnit;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeWeekUnit;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeYearUnit;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.ArraySlice;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Char;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.ConvertTo;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentDate;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentTime;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentUser;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.DayCeil;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.DayFloor;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysAdd;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysDiff;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysSub;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.ElementAt;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.EncryptKeyRef;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.HourCeil;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.HourFloor;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursDiff;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursSub;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Lambda;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MinuteCeil;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MinuteFloor;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesAdd;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesDiff;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesSub;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthCeil;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthFloor;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsAdd;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsDiff;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsSub;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Now;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondCeil;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondFloor;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsDiff;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsSub;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SessionUser;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.WeekCeil;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.WeekFloor;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksAdd;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksDiff;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksSub;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Xor;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.YearCeil;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.YearFloor;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsAdd;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsDiff;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsSub;
 import org.apache.doris.nereids.trees.expressions.literal.ArrayLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
@@ -1863,22 +1812,6 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         });
     }
 
-    @Override
-    public Expression visitBitOperation(BitOperationContext ctx) {
-        return ParserUtils.withOrigin(ctx, () -> {
-            Expression left = getExpression(ctx.left);
-            Expression right = getExpression(ctx.right);
-            if (ctx.operator.getType() == DorisParser.BITAND) {
-                return new BitAnd(left, right);
-            } else if (ctx.operator.getType() == DorisParser.BITOR) {
-                return new BitOr(left, right);
-            } else if (ctx.operator.getType() == DorisParser.BITXOR) {
-                return new BitXor(left, right);
-            }
-            throw new ParseException(" not supported", ctx);
-        });
-    }
-
     @Override
     public Expression visitArithmeticBinary(ArithmeticBinaryContext ctx) {
         return ParserUtils.withOrigin(ctx, () -> {
@@ -1935,204 +1868,6 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         });
     }
 
-    @Override
-    public Expression visitTimestampdiff(TimestampdiffContext ctx) {
-        Expression start = (Expression) visit(ctx.startTimestamp);
-        Expression end = (Expression) visit(ctx.endTimestamp);
-        String unit = ctx.unit.getText();
-        if ("YEAR".equalsIgnoreCase(unit)) {
-            return new YearsDiff(end, start);
-        } else if ("MONTH".equalsIgnoreCase(unit)) {
-            return new MonthsDiff(end, start);
-        } else if ("WEEK".equalsIgnoreCase(unit)) {
-            return new WeeksDiff(end, start);
-        } else if ("DAY".equalsIgnoreCase(unit)) {
-            return new DaysDiff(end, start);
-        } else if ("HOUR".equalsIgnoreCase(unit)) {
-            return new HoursDiff(end, start);
-        } else if ("MINUTE".equalsIgnoreCase(unit)) {
-            return new MinutesDiff(end, start);
-        } else if ("SECOND".equalsIgnoreCase(unit)) {
-            return new SecondsDiff(end, start);
-        }
-        throw new ParseException("Unsupported time stamp diff time unit: " + 
unit
-                + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND", ctx);
-
-    }
-
-    @Override
-    public Expression visitTimestampadd(TimestampaddContext ctx) {
-        Expression start = (Expression) visit(ctx.startTimestamp);
-        Expression end = (Expression) visit(ctx.endTimestamp);
-        String unit = ctx.unit.getText();
-        if ("YEAR".equalsIgnoreCase(unit)) {
-            return new YearsAdd(end, start);
-        } else if ("MONTH".equalsIgnoreCase(unit)) {
-            return new MonthsAdd(end, start);
-        } else if ("WEEK".equalsIgnoreCase(unit)) {
-            return new WeeksAdd(end, start);
-        } else if ("DAY".equalsIgnoreCase(unit)) {
-            return new DaysAdd(end, start);
-        } else if ("HOUR".equalsIgnoreCase(unit)) {
-            return new HoursAdd(end, start);
-        } else if ("MINUTE".equalsIgnoreCase(unit)) {
-            return new MinutesAdd(end, start);
-        } else if ("SECOND".equalsIgnoreCase(unit)) {
-            return new SecondsAdd(end, start);
-        }
-        throw new ParseException("Unsupported time stamp add time unit: " + 
unit
-                + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND", ctx);
-
-    }
-
-    @Override
-    public Expression visitDate_add(Date_addContext ctx) {
-        Expression timeStamp = (Expression) visit(ctx.timestamp);
-        Expression amount = (Expression) visit(ctx.unitsAmount);
-        if (ctx.unit == null) {
-            //use "DAY" as unit by default
-            return new DaysAdd(timeStamp, amount);
-        }
-
-        if ("Year".equalsIgnoreCase(ctx.unit.getText())) {
-            return new YearsAdd(timeStamp, amount);
-        } else if ("MONTH".equalsIgnoreCase(ctx.unit.getText())) {
-            return new MonthsAdd(timeStamp, amount);
-        } else if ("WEEK".equalsIgnoreCase(ctx.unit.getText())) {
-            return new WeeksAdd(timeStamp, amount);
-        } else if ("DAY".equalsIgnoreCase(ctx.unit.getText())) {
-            return new DaysAdd(timeStamp, amount);
-        } else if ("Hour".equalsIgnoreCase(ctx.unit.getText())) {
-            return new HoursAdd(timeStamp, amount);
-        } else if ("Minute".equalsIgnoreCase(ctx.unit.getText())) {
-            return new MinutesAdd(timeStamp, amount);
-        } else if ("Second".equalsIgnoreCase(ctx.unit.getText())) {
-            return new SecondsAdd(timeStamp, amount);
-        }
-        throw new ParseException("Unsupported time unit: " + ctx.unit
-                + ", supported time unit: YEAR/MONTH/DAY/HOUR/MINUTE/SECOND", 
ctx);
-    }
-
-    @Override
-    public Expression visitArrayRange(ArrayRangeContext ctx) {
-        Expression start = (Expression) visit(ctx.start);
-        Expression end = (Expression) visit(ctx.end);
-        Expression step = (Expression) visit(ctx.unitsAmount);
-
-        String unit = ctx.unit == null ? null : ctx.unit.getText();
-        if (unit != null && !unit.isEmpty()) {
-            if ("Year".equalsIgnoreCase(unit)) {
-                return new ArrayRangeYearUnit(start, end, step);
-            } else if ("Month".equalsIgnoreCase(unit)) {
-                return new ArrayRangeMonthUnit(start, end, step);
-            } else if ("Week".equalsIgnoreCase(unit)) {
-                return new ArrayRangeWeekUnit(start, end, step);
-            } else if ("Day".equalsIgnoreCase(unit)) {
-                return new ArrayRangeDayUnit(start, end, step);
-            } else if ("Hour".equalsIgnoreCase(unit)) {
-                return new ArrayRangeHourUnit(start, end, step);
-            } else if ("Minute".equalsIgnoreCase(unit)) {
-                return new ArrayRangeMinuteUnit(start, end, step);
-            } else if ("Second".equalsIgnoreCase(unit)) {
-                return new ArrayRangeSecondUnit(start, end, step);
-            }
-            throw new ParseException("Unsupported time unit: " + ctx.unit
-                    + ", supported time unit: 
YEAR/MONTH/DAY/HOUR/MINUTE/SECOND", ctx);
-        } else if (ctx.unitsAmount != null) {
-            return new ArrayRange(start, end, step);
-        } else if (ctx.end != null) {
-            return new ArrayRange(start, end);
-        } else {
-            return new ArrayRange(start);
-        }
-    }
-
-    @Override
-    public Expression visitDate_sub(Date_subContext ctx) {
-        Expression timeStamp = (Expression) visit(ctx.timestamp);
-        Expression amount = (Expression) visit(ctx.unitsAmount);
-        if (ctx.unit == null) {
-            //use "DAY" as unit by default
-            return new DaysSub(timeStamp, amount);
-        }
-
-        if ("Year".equalsIgnoreCase(ctx.unit.getText())) {
-            return new YearsSub(timeStamp, amount);
-        } else if ("MONTH".equalsIgnoreCase(ctx.unit.getText())) {
-            return new MonthsSub(timeStamp, amount);
-        } else if ("WEEK".equalsIgnoreCase(ctx.unit.getText())) {
-            return new WeeksSub(timeStamp, amount);
-        } else if ("DAY".equalsIgnoreCase(ctx.unit.getText())) {
-            return new DaysSub(timeStamp, amount);
-        } else if ("Hour".equalsIgnoreCase(ctx.unit.getText())) {
-            return new HoursSub(timeStamp, amount);
-        } else if ("Minute".equalsIgnoreCase(ctx.unit.getText())) {
-            return new MinutesSub(timeStamp, amount);
-        } else if ("Second".equalsIgnoreCase(ctx.unit.getText())) {
-            return new SecondsSub(timeStamp, amount);
-        }
-        throw new ParseException("Unsupported time unit: " + ctx.unit
-                + ", supported time unit: YEAR/MONTH/DAY/HOUR/MINUTE/SECOND", 
ctx);
-    }
-
-    @Override
-    public Expression visitDateFloor(DateFloorContext ctx) {
-        Expression timeStamp = (Expression) visit(ctx.timestamp);
-        Expression amount = (Expression) visit(ctx.unitsAmount);
-        if (ctx.unit == null) {
-            // use "SECOND" as unit by default
-            return new SecondFloor(timeStamp, amount);
-        }
-        Expression e = new DateTimeV2Literal(0001L, 01L, 01L, 0L, 0L, 0L, 0L);
-
-        if ("Year".equalsIgnoreCase(ctx.unit.getText())) {
-            return new YearFloor(timeStamp, amount, e);
-        } else if ("MONTH".equalsIgnoreCase(ctx.unit.getText())) {
-            return new MonthFloor(timeStamp, amount, e);
-        } else if ("WEEK".equalsIgnoreCase(ctx.unit.getText())) {
-            return new WeekFloor(timeStamp, amount, e);
-        } else if ("DAY".equalsIgnoreCase(ctx.unit.getText())) {
-            return new DayFloor(timeStamp, amount, e);
-        } else if ("Hour".equalsIgnoreCase(ctx.unit.getText())) {
-            return new HourFloor(timeStamp, amount, e);
-        } else if ("Minute".equalsIgnoreCase(ctx.unit.getText())) {
-            return new MinuteFloor(timeStamp, amount, e);
-        } else if ("Second".equalsIgnoreCase(ctx.unit.getText())) {
-            return new SecondFloor(timeStamp, amount, e);
-        }
-        throw new ParseException("Unsupported time unit: " + ctx.unit
-                + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND", ctx);
-    }
-
-    @Override
-    public Expression visitDateCeil(DateCeilContext ctx) {
-        Expression timeStamp = (Expression) visit(ctx.timestamp);
-        Expression amount = (Expression) visit(ctx.unitsAmount);
-        if (ctx.unit == null) {
-            // use "Second" as unit by default
-            return new SecondCeil(timeStamp, amount);
-        }
-        DateTimeV2Literal e = new DateTimeV2Literal(0001L, 01L, 01L, 0L, 0L, 
0L, 0L);
-
-        if ("Year".equalsIgnoreCase(ctx.unit.getText())) {
-            return new YearCeil(timeStamp, amount, e);
-        } else if ("MONTH".equalsIgnoreCase(ctx.unit.getText())) {
-            return new MonthCeil(timeStamp, amount, e);
-        } else if ("WEEK".equalsIgnoreCase(ctx.unit.getText())) {
-            return new WeekCeil(timeStamp, amount, e);
-        } else if ("DAY".equalsIgnoreCase(ctx.unit.getText())) {
-            return new DayCeil(timeStamp, amount, e);
-        } else if ("Hour".equalsIgnoreCase(ctx.unit.getText())) {
-            return new HourCeil(timeStamp, amount, e);
-        } else if ("Minute".equalsIgnoreCase(ctx.unit.getText())) {
-            return new MinuteCeil(timeStamp, amount, e);
-        } else if ("Second".equalsIgnoreCase(ctx.unit.getText())) {
-            return new SecondCeil(timeStamp, amount, e);
-        }
-        throw new ParseException("Unsupported time unit: " + ctx.unit
-                + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND", ctx);
-    }
-
     @Override
     public Expression visitCurrentDate(DorisParser.CurrentDateContext ctx) {
         return new CurrentDate();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ArithmeticFunctionBinder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ArithmeticFunctionBinder.java
index 0a1d2a788dd..102637a2abc 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ArithmeticFunctionBinder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ArithmeticFunctionBinder.java
@@ -39,6 +39,9 @@ import java.util.Map;
  * bind arithmetic function
  */
 public class ArithmeticFunctionBinder {
+
+    public static final ArithmeticFunctionBinder INSTANCE = new 
ArithmeticFunctionBinder();
+
     private static final NullLiteral DUMMY_EXPRESSION = new NullLiteral();
     private static final Map<String, Expression> FUNCTION_TO_EXPRESSION = 
ImmutableMap.<String, Expression>builder()
             .put("add", new Add(DUMMY_EXPRESSION, DUMMY_EXPRESSION))
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinder.java
new file mode 100644
index 00000000000..c45301893d5
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinder.java
@@ -0,0 +1,348 @@
+// 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.rules.analysis;
+
+import org.apache.doris.nereids.analyzer.UnboundFunction;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRange;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeDayUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeHourUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeMinuteUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeMonthUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeSecondUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeWeekUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeYearUnit;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DateDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DayCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DayFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HourCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HourFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinuteCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinuteFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeekCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeekFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsSub;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
+import org.apache.doris.nereids.trees.expressions.literal.Interval;
+import org.apache.doris.nereids.trees.expressions.literal.Interval.TimeUnit;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * bind arithmetic function
+ */
+public class DatetimeFunctionBinder {
+
+    public static final DatetimeFunctionBinder INSTANCE = new 
DatetimeFunctionBinder();
+
+    private static final String DATEDIFF = "DATEDIFF";
+
+    private static final ImmutableSet<String> TIMESTAMP_DIFF_FUNCTION_NAMES
+            = ImmutableSet.of("TIMESTAMPDIFF", DATEDIFF);
+    private static final ImmutableSet<String> TIMESTAMP_ADD_FUNCTION_NAMES
+            = ImmutableSet.of("TIMESTAMPADD", "DATEADD");
+    public static final ImmutableSet<String> TIMESTAMP_SERIES_FUNCTION_NAMES
+            = ImmutableSet.<String>builder()
+            .addAll(TIMESTAMP_DIFF_FUNCTION_NAMES)
+            .addAll(TIMESTAMP_ADD_FUNCTION_NAMES)
+            .build();
+
+    private static final ImmutableSet<String> ADD_DATE_FUNCTION_NAMES
+            = ImmutableSet.of("ADDDATE", "DAYS_ADD", "DATE_ADD");
+    private static final ImmutableSet<String> SUB_DATE_FUNCTION_NAMES
+            = ImmutableSet.of("SUBDATE", "DAYS_SUB", "DATE_SUB");
+    private static final ImmutableSet<String> 
DATE_ADD_SUB_SERIES_FUNCTION_NAMES
+            = ImmutableSet.<String>builder()
+            .addAll(ADD_DATE_FUNCTION_NAMES)
+            .addAll(SUB_DATE_FUNCTION_NAMES)
+            .build();
+    private static final ImmutableSet<String> DATE_FLOOR_FUNCTION_NAMES
+            = ImmutableSet.of("DATE_FLOOR");
+    private static final ImmutableSet<String> DATE_CEIL_FUNCTION_NAMES
+            = ImmutableSet.of("DATE_CEIL");
+    private static final ImmutableSet<String> 
DATE_FLOOR_CEIL_SERIES_FUNCTION_NAMES
+            = ImmutableSet.<String>builder()
+            .addAll(DATE_FLOOR_FUNCTION_NAMES)
+            .addAll(DATE_CEIL_FUNCTION_NAMES)
+            .build();
+    private static final ImmutableSet<String> DATE_SERIES_FUNCTION_NAMES
+            = ImmutableSet.<String>builder()
+            .addAll(DATE_ADD_SUB_SERIES_FUNCTION_NAMES)
+            .addAll(DATE_FLOOR_CEIL_SERIES_FUNCTION_NAMES)
+            .build();
+
+    private static final ImmutableSet<String> ARRAY_RANGE_FUNCTION_NAMES
+            = ImmutableSet.of("ARRAY_RANGE", "SEQUENCE");
+
+    private static final ImmutableSet<String> SUPPORT_FUNCTION_NAMES
+            = ImmutableSet.<String>builder()
+            .addAll(TIMESTAMP_SERIES_FUNCTION_NAMES)
+            .addAll(DATE_SERIES_FUNCTION_NAMES)
+            .addAll(ARRAY_RANGE_FUNCTION_NAMES)
+            .build();
+
+    public boolean isDatetimeFunction(String functionName) {
+        return SUPPORT_FUNCTION_NAMES.contains(functionName.toUpperCase());
+    }
+
+    /**
+     * bind datetime functions that have non-expression arguments.
+     *
+     * @param unboundFunction unbound datetime function
+     *
+     * @return bound function
+     */
+    public Expression bind(UnboundFunction unboundFunction) {
+        String functionName = unboundFunction.getName().toUpperCase();
+        if (TIMESTAMP_SERIES_FUNCTION_NAMES.contains(functionName)) {
+            if (unboundFunction.arity() == 2 && functionName.equals(DATEDIFF)) 
{
+                return new DateDiff(unboundFunction.child(0), 
unboundFunction.child(1));
+            } else if (unboundFunction.arity() != 3
+                    || !(unboundFunction.child(0) instanceof SlotReference)) {
+                throw new AnalysisException("Can not found function '" + 
functionName
+                        + "' with " + unboundFunction.arity() + " arguments");
+            }
+            String unitName = ((SlotReference) 
unboundFunction.child(0)).getName().toUpperCase();
+            TimeUnit unit;
+            try {
+                unit = TimeUnit.valueOf(unitName);
+            } catch (IllegalArgumentException e) {
+                throw new AnalysisException("Unsupported time stamp diff time 
unit: " + unitName
+                        + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND");
+            }
+            if (TIMESTAMP_DIFF_FUNCTION_NAMES.contains(functionName)) {
+                // timestampdiff(unit, start, end)
+                return processTimestampDiff(unit, unboundFunction.child(1), 
unboundFunction.child(2));
+            } else {
+                // timestampadd(unit, amount, basetime)
+                return processDateAdd(unit, unboundFunction.child(2), 
unboundFunction.child(1));
+            }
+        } else if (DATE_SERIES_FUNCTION_NAMES.contains(functionName)) {
+            if (unboundFunction.arity() != 2) {
+                throw new AnalysisException("Can not found function '" + 
functionName
+                        + "' with " + unboundFunction.arity() + " arguments");
+            }
+            // date_add and date_sub's default unit is DAY, date_ceil and 
date_floor's default unit is SECOND
+            TimeUnit unit = TimeUnit.DAY;
+            if (DATE_FLOOR_CEIL_SERIES_FUNCTION_NAMES.contains(functionName)) {
+                unit = TimeUnit.SECOND;
+            }
+            Expression amount = unboundFunction.child(1);
+            if (unboundFunction.child(1) instanceof Interval) {
+                Interval interval = (Interval) unboundFunction.child(1);
+                unit = interval.timeUnit();
+                amount = interval.value();
+            }
+            if (ADD_DATE_FUNCTION_NAMES.contains(functionName)) {
+                // date_add(date, interval amount unit | amount)
+                return processDateAdd(unit, unboundFunction.child(0), amount);
+            } else if (SUB_DATE_FUNCTION_NAMES.contains(functionName)) {
+                // date_add(date, interval amount unit | amount)
+                return processDateSub(unit, unboundFunction.child(0), amount);
+            } else if (DATE_FLOOR_FUNCTION_NAMES.contains(functionName)) {
+                // date_floor(date, interval amount unit | amount)
+                return processDateFloor(unit, unboundFunction.child(0), 
amount);
+            } else {
+                // date_ceil(date, interval amount unit | amount)
+                return processDateCeil(unit, unboundFunction.child(0), amount);
+            }
+        } else if (ARRAY_RANGE_FUNCTION_NAMES.contains(functionName)) {
+            switch (unboundFunction.arity()) {
+                case 1:
+                    return new ArrayRange(unboundFunction.child(0));
+                case 2:
+                    return new ArrayRange(unboundFunction.child(0), 
unboundFunction.child(1));
+                case 3:
+                    if (unboundFunction.child(2) instanceof Interval) {
+                        Interval interval = (Interval) 
unboundFunction.child(2);
+                        TimeUnit unit = interval.timeUnit();
+                        Expression step = interval.value();
+                        return processArrayRange(unit, 
unboundFunction.child(0), unboundFunction.child(1), step);
+                    }
+                    return new ArrayRange(unboundFunction.child(0),
+                            unboundFunction.child(1), 
unboundFunction.child(2));
+                default:
+                    throw new AnalysisException("Can not found function '" + 
functionName + "'");
+            }
+        }
+        throw new AnalysisException("Can not found function '" + functionName 
+ "'");
+    }
+
+    private Expression processTimestampDiff(TimeUnit unit, Expression start, 
Expression end) {
+        switch (unit) {
+            case YEAR:
+                return new YearsDiff(end, start);
+            case MONTH:
+                return new MonthsDiff(end, start);
+            case WEEK:
+                return new WeeksDiff(end, start);
+            case DAY:
+                return new DaysDiff(end, start);
+            case HOUR:
+                return new HoursDiff(end, start);
+            case MINUTE:
+                return new MinutesDiff(end, start);
+            case SECOND:
+                return new SecondsDiff(end, start);
+            default:
+                throw new AnalysisException("Unsupported time stamp diff time 
unit: " + unit
+                        + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND");
+        }
+    }
+
+    private Expression processDateAdd(TimeUnit unit, Expression timestamp, 
Expression amount) {
+        switch (unit) {
+            case YEAR:
+                return new YearsAdd(timestamp, amount);
+            case MONTH:
+                return new MonthsAdd(timestamp, amount);
+            case WEEK:
+                return new WeeksAdd(timestamp, amount);
+            case DAY:
+                return new DaysAdd(timestamp, amount);
+            case HOUR:
+                return new HoursAdd(timestamp, amount);
+            case MINUTE:
+                return new MinutesAdd(timestamp, amount);
+            case SECOND:
+                return new SecondsAdd(timestamp, amount);
+            default:
+                throw new AnalysisException("Unsupported time stamp add time 
unit: " + unit
+                        + ", supported time unit: 
YEAR/QUARTER/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND");
+        }
+    }
+
+    private Expression processDateSub(TimeUnit unit, Expression timeStamp, 
Expression amount) {
+        switch (unit) {
+            case YEAR:
+                return new YearsSub(timeStamp, amount);
+            case MONTH:
+                return new MonthsSub(timeStamp, amount);
+            case WEEK:
+                return new WeeksSub(timeStamp, amount);
+            case DAY:
+                return new DaysSub(timeStamp, amount);
+            case HOUR:
+                return new HoursSub(timeStamp, amount);
+            case MINUTE:
+                return new MinutesSub(timeStamp, amount);
+            case SECOND:
+                return new SecondsSub(timeStamp, amount);
+            default:
+                throw new AnalysisException("Unsupported time stamp sub time 
unit: " + unit
+                        + ", supported time unit: 
YEAR/QUARTER/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND");
+        }
+    }
+
+    private Expression processDateFloor(TimeUnit unit, Expression timeStamp, 
Expression amount) {
+        DateTimeV2Literal e = DateTimeV2Literal.USE_IN_FLOOR_CEIL;
+        switch (unit) {
+            case YEAR:
+                return new YearFloor(timeStamp, amount, e);
+            case MONTH:
+                return new MonthFloor(timeStamp, amount, e);
+            case WEEK:
+                return new WeekFloor(timeStamp, amount, e);
+            case DAY:
+                return new DayFloor(timeStamp, amount, e);
+            case HOUR:
+                return new HourFloor(timeStamp, amount, e);
+            case MINUTE:
+                return new MinuteFloor(timeStamp, amount, e);
+            case SECOND:
+                return new SecondFloor(timeStamp, amount, e);
+            default:
+                throw new AnalysisException("Unsupported time stamp floor time 
unit: " + unit
+                        + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND");
+        }
+    }
+
+    private Expression processDateCeil(TimeUnit unit, Expression timeStamp, 
Expression amount) {
+        DateTimeV2Literal e = DateTimeV2Literal.USE_IN_FLOOR_CEIL;
+        switch (unit) {
+            case YEAR:
+                return new YearCeil(timeStamp, amount, e);
+            case MONTH:
+                return new MonthCeil(timeStamp, amount, e);
+            case WEEK:
+                return new WeekCeil(timeStamp, amount, e);
+            case DAY:
+                return new DayCeil(timeStamp, amount, e);
+            case HOUR:
+                return new HourCeil(timeStamp, amount, e);
+            case MINUTE:
+                return new MinuteCeil(timeStamp, amount, e);
+            case SECOND:
+                return new SecondCeil(timeStamp, amount, e);
+            default:
+                throw new AnalysisException("Unsupported time stamp ceil time 
unit: " + unit
+                        + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND");
+        }
+    }
+
+    private Expression processArrayRange(TimeUnit unit, Expression start, 
Expression end, Expression step) {
+        switch (unit) {
+            case YEAR:
+                return new ArrayRangeYearUnit(start, end, step);
+            case MONTH:
+                return new ArrayRangeMonthUnit(start, end, step);
+            case WEEK:
+                return new ArrayRangeWeekUnit(start, end, step);
+            case DAY:
+                return new ArrayRangeDayUnit(start, end, step);
+            case HOUR:
+                return new ArrayRangeHourUnit(start, end, step);
+            case MINUTE:
+                return new ArrayRangeMinuteUnit(start, end, step);
+            case SECOND:
+                return new ArrayRangeSecondUnit(start, end, step);
+            default:
+                throw new AnalysisException("Unsupported array range time 
unit: " + unit
+                        + ", supported time unit: 
YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND");
+        }
+    }
+
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
index 5b6295d1bc2..a0d5579abdc 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
@@ -50,6 +50,7 @@ import org.apache.doris.nereids.trees.expressions.Cast;
 import org.apache.doris.nereids.trees.expressions.ComparisonPredicate;
 import org.apache.doris.nereids.trees.expressions.Divide;
 import org.apache.doris.nereids.trees.expressions.EqualTo;
+import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.InPredicate;
 import org.apache.doris.nereids.trees.expressions.InSubquery;
@@ -86,6 +87,7 @@ import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.TinyIntType;
 import org.apache.doris.nereids.util.ExpressionUtils;
 import org.apache.doris.nereids.util.TypeCoercionUtils;
 import org.apache.doris.nereids.util.Utils;
@@ -375,6 +377,26 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
         if (unboundFunction.isHighOrder()) {
             unboundFunction = bindHighOrderFunction(unboundFunction, context);
         } else {
+            // NOTICE: some trick code here. because below functions
+            //  TIMESTAMPADD / DATEDIFF / TIMESTAMPADD / DATEADD
+            //  the first argument of them is TimeUnit, but is cannot 
distinguish with UnboundSlot in parser.
+            //  So, convert the UnboundSlot to a fake SlotReference with 
ExprId = -1 here
+            //  And, the SlotReference will be processed in 
DatetimeFunctionBinder
+            if (StringUtils.isEmpty(unboundFunction.getDbName())
+                    && 
DatetimeFunctionBinder.TIMESTAMP_SERIES_FUNCTION_NAMES.contains(
+                            unboundFunction.getName().toUpperCase())
+                    && unboundFunction.arity() == 3
+                    && unboundFunction.child(0) instanceof UnboundSlot) {
+                SlotReference slotReference = new SlotReference(new ExprId(-1),
+                        ((UnboundSlot) unboundFunction.child(0)).getName(),
+                        TinyIntType.INSTANCE, true, ImmutableList.of());
+                ImmutableList.Builder<Expression> newChildrenBuilder = 
ImmutableList.builder();
+                newChildrenBuilder.add(slotReference);
+                for (int i = 1; i < unboundFunction.arity(); i++) {
+                    newChildrenBuilder.add(unboundFunction.child(i));
+                }
+                unboundFunction = 
unboundFunction.withChildren(newChildrenBuilder.build());
+            }
             unboundFunction = (UnboundFunction) super.visit(unboundFunction, 
context);
         }
 
@@ -391,10 +413,28 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
         if (StringUtils.isEmpty(dbName)) {
             // we will change arithmetic function like add(), subtract(), 
bitnot()
             // to the corresponding objects rather than BoundFunction.
-            ArithmeticFunctionBinder functionBinder = new 
ArithmeticFunctionBinder();
-            if (functionBinder.isBinaryArithmetic(unboundFunction.getName())) {
-                return 
functionBinder.bindBinaryArithmetic(unboundFunction.getName(), 
unboundFunction.children())
-                        .accept(this, context);
+            if 
(ArithmeticFunctionBinder.INSTANCE.isBinaryArithmetic(unboundFunction.getName()))
 {
+                Expression ret = 
ArithmeticFunctionBinder.INSTANCE.bindBinaryArithmetic(
+                        unboundFunction.getName(), unboundFunction.children());
+                if (ret instanceof Divide) {
+                    return TypeCoercionUtils.processDivide((Divide) ret);
+                } else if (ret instanceof IntegralDivide) {
+                    return 
TypeCoercionUtils.processIntegralDivide((IntegralDivide) ret);
+                } else if ((ret instanceof BinaryArithmetic)) {
+                    return 
TypeCoercionUtils.processBinaryArithmetic((BinaryArithmetic) ret);
+                } else if (ret instanceof BitNot) {
+                    return TypeCoercionUtils.processBitNot((BitNot) ret);
+                } else {
+                    return ret;
+                }
+            }
+            if 
(DatetimeFunctionBinder.INSTANCE.isDatetimeFunction(unboundFunction.getName())) 
{
+                Expression ret = 
DatetimeFunctionBinder.INSTANCE.bind(unboundFunction);
+                if (ret instanceof BoundFunction) {
+                    return 
TypeCoercionUtils.processBoundFunction((BoundFunction) ret);
+                } else {
+                    return ret;
+                }
             }
         }
 
@@ -481,11 +521,7 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
     @Override
     public Expression visitBitNot(BitNot bitNot, ExpressionRewriteContext 
context) {
         Expression child = bitNot.child().accept(this, context);
-        // type coercion
-        if (!(child.getDataType().isIntegralType() || 
child.getDataType().isBooleanType())) {
-            child = new Cast(child, BigIntType.INSTANCE);
-        }
-        return bitNot.withChildren(child);
+        return TypeCoercionUtils.processBitNot((BitNot) 
bitNot.withChildren(child));
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
index 69a75e001ab..599e903df39 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
@@ -36,6 +36,9 @@ import java.util.Objects;
  */
 public class DateTimeV2Literal extends DateTimeLiteral {
 
+    public static final DateTimeV2Literal USE_IN_FLOOR_CEIL
+            = new DateTimeV2Literal(0001L, 01L, 01L, 0L, 0L, 0L, 0L);
+
     public DateTimeV2Literal(String s) {
         this(DateTimeV2Type.forTypeFromString(s), s);
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Interval.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Interval.java
index 454001fb3f1..246122e59db 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Interval.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Interval.java
@@ -19,27 +19,31 @@ package org.apache.doris.nereids.trees.expressions.literal;
 
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
-import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
+import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DataType;
 import org.apache.doris.nereids.types.DateType;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import org.apache.commons.lang3.EnumUtils;
 
+import java.util.List;
 import java.util.Optional;
 
 /**
  * Interval for timestamp calculation.
  */
-public class Interval extends Expression implements LeafExpression, 
AlwaysNotNullable {
-    private final Expression value;
+public class Interval extends Expression implements UnaryExpression, 
AlwaysNotNullable {
     private final TimeUnit timeUnit;
 
     public Interval(Expression value, String desc) {
-        super(ImmutableList.of());
-        this.value = value;
-        this.timeUnit = TimeUnit.valueOf(desc.toUpperCase());
+        this(value, TimeUnit.valueOf(desc.toUpperCase()));
+    }
+
+    public Interval(Expression value, TimeUnit timeUnit) {
+        super(ImmutableList.of(value));
+        this.timeUnit = timeUnit;
     }
 
     @Override
@@ -48,13 +52,19 @@ public class Interval extends Expression implements 
LeafExpression, AlwaysNotNul
     }
 
     public Expression value() {
-        return value;
+        return child();
     }
 
     public TimeUnit timeUnit() {
         return timeUnit;
     }
 
+    @Override
+    public Expression withChildren(List<Expression> children) {
+        Preconditions.checkArgument(children.size() == 1);
+        return new Interval(children.get(0), timeUnit);
+    }
+
     @Override
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
         return visitor.visitInterval(this, context);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
index 64457acee15..15de1fd4c22 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
@@ -29,6 +29,7 @@ import org.apache.doris.nereids.trees.expressions.Add;
 import org.apache.doris.nereids.trees.expressions.BinaryArithmetic;
 import org.apache.doris.nereids.trees.expressions.BinaryOperator;
 import org.apache.doris.nereids.trees.expressions.BitAnd;
+import org.apache.doris.nereids.trees.expressions.BitNot;
 import org.apache.doris.nereids.trees.expressions.BitOr;
 import org.apache.doris.nereids.trees.expressions.BitXor;
 import org.apache.doris.nereids.trees.expressions.CaseWhen;
@@ -805,6 +806,21 @@ public class TypeCoercionUtils {
         return parent.withChildren(castIfNotSameType(left, commonType), 
castIfNotSameType(right, commonType));
     }
 
+    /**
+     * process BitNot type coercion, cast child to bigint.
+     */
+    public static Expression processBitNot(BitNot bitNot) {
+        Expression child = bitNot.child();
+        if (!(child.getDataType().isIntegralType() || 
child.getDataType().isBooleanType())) {
+            child = new Cast(child, BigIntType.INSTANCE);
+        }
+        if (child != bitNot.child()) {
+            return bitNot.withChildren(child);
+        } else {
+            return bitNot;
+        }
+    }
+
     /**
      * binary arithmetic type coercion
      */
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinderTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinderTest.java
new file mode 100644
index 00000000000..94f772f9508
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/DatetimeFunctionBinderTest.java
@@ -0,0 +1,626 @@
+// 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.rules.analysis;
+
+import org.apache.doris.nereids.analyzer.UnboundFunction;
+import org.apache.doris.nereids.analyzer.UnboundSlot;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRange;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeDayUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeHourUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeMinuteUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeMonthUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeSecondUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeWeekUnit;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayRangeYearUnit;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DateDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DayCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DayFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HourCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HourFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinuteCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinuteFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MinutesSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeekCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeekFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksSub;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearCeil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsAdd;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsDiff;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsSub;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
+import org.apache.doris.nereids.trees.expressions.literal.Interval;
+import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
+import org.apache.doris.nereids.types.TinyIntType;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class DatetimeFunctionBinderTest {
+
+    private final SlotReference yearUnit = new SlotReference("year", 
TinyIntType.INSTANCE);
+    private final SlotReference monthUnit = new SlotReference("month", 
TinyIntType.INSTANCE);
+    private final SlotReference weekUnit = new SlotReference("week", 
TinyIntType.INSTANCE);
+    private final SlotReference dayUnit = new SlotReference("day", 
TinyIntType.INSTANCE);
+    private final SlotReference hourUnit = new SlotReference("hour", 
TinyIntType.INSTANCE);
+    private final SlotReference minuteUnit = new SlotReference("minute", 
TinyIntType.INSTANCE);
+    private final SlotReference secondUnit = new SlotReference("second", 
TinyIntType.INSTANCE);
+    private final SlotReference invalidUnit = new SlotReference("xyz", 
TinyIntType.INSTANCE);
+
+    private final TinyIntLiteral tinyIntLiteral = new TinyIntLiteral((byte) 1);
+
+    private final Interval yearInterval = new Interval(tinyIntLiteral, "YEAR");
+    private final Interval quarterInterval = new Interval(tinyIntLiteral, 
"QUARTER");
+    private final Interval monthInterval = new Interval(tinyIntLiteral, 
"MONTH");
+    private final Interval weekInterval = new Interval(tinyIntLiteral, "WEEK");
+    private final Interval dayInterval = new Interval(tinyIntLiteral, "DAY");
+    private final Interval hourInterval = new Interval(tinyIntLiteral, "HOUR");
+    private final Interval minuteInterval = new Interval(tinyIntLiteral, 
"MINUTE");
+    private final Interval secondInterval = new Interval(tinyIntLiteral, 
"SECOND");
+
+    private final DateTimeV2Literal dateTimeV2Literal1 = new 
DateTimeV2Literal("2024-12-01");
+    private final DateTimeV2Literal dateTimeV2Literal2 = new 
DateTimeV2Literal("2024-12-26");
+
+    @Test
+    void testTimestampDiff() {
+        Expression result;
+        UnboundFunction timeDiff;
+        ImmutableList<String> functionNames = 
ImmutableList.of("timestampdiff", "datediff");
+
+        for (String functionName : functionNames) {
+            timeDiff = new UnboundFunction(functionName, ImmutableList.of(
+                    yearUnit, dateTimeV2Literal1, dateTimeV2Literal2));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeDiff);
+            Assertions.assertInstanceOf(YearsDiff.class, result);
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(1));
+
+            timeDiff = new UnboundFunction(functionName, ImmutableList.of(
+                    monthUnit, dateTimeV2Literal1, dateTimeV2Literal2));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeDiff);
+            Assertions.assertInstanceOf(MonthsDiff.class, result);
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(1));
+
+            timeDiff = new UnboundFunction(functionName, ImmutableList.of(
+                    weekUnit, dateTimeV2Literal1, dateTimeV2Literal2));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeDiff);
+            Assertions.assertInstanceOf(WeeksDiff.class, result);
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(1));
+
+            timeDiff = new UnboundFunction(functionName, ImmutableList.of(
+                    dayUnit, dateTimeV2Literal1, dateTimeV2Literal2));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeDiff);
+            Assertions.assertInstanceOf(DaysDiff.class, result);
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(1));
+
+            timeDiff = new UnboundFunction(functionName, ImmutableList.of(
+                    hourUnit, dateTimeV2Literal1, dateTimeV2Literal2));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeDiff);
+            Assertions.assertInstanceOf(HoursDiff.class, result);
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(1));
+
+            timeDiff = new UnboundFunction(functionName, ImmutableList.of(
+                    minuteUnit, dateTimeV2Literal1, dateTimeV2Literal2));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeDiff);
+            Assertions.assertInstanceOf(MinutesDiff.class, result);
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(1));
+
+            timeDiff = new UnboundFunction(functionName, ImmutableList.of(
+                    secondUnit, dateTimeV2Literal1, dateTimeV2Literal2));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeDiff);
+            Assertions.assertInstanceOf(SecondsDiff.class, result);
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(1));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of(invalidUnit,
+                                    dateTimeV2Literal1, dateTimeV2Literal2))));
+
+            if (functionName.equalsIgnoreCase("datediff")) {
+                timeDiff = new UnboundFunction(functionName, 
ImmutableList.of(dateTimeV2Literal1, dateTimeV2Literal2));
+                result = DatetimeFunctionBinder.INSTANCE.bind(timeDiff);
+                Assertions.assertInstanceOf(DateDiff.class, result);
+                Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+                Assertions.assertEquals(dateTimeV2Literal2, result.child(1));
+            } else {
+                Assertions.assertThrowsExactly(AnalysisException.class,
+                        () -> DatetimeFunctionBinder.INSTANCE.bind(
+                                new UnboundFunction(functionName, 
ImmutableList.of(yearUnit,
+                                        dateTimeV2Literal1))));
+            }
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of(new UnboundSlot("unbound"),
+                                    dateTimeV2Literal1, dateTimeV2Literal2))));
+        }
+    }
+
+    @Test
+    void testTimestampAdd() {
+        Expression result;
+        UnboundFunction timeAdd;
+        ImmutableList<String> functionNames = ImmutableList.of("timestampadd", 
"dateadd");
+
+        for (String functionName : functionNames) {
+            timeAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    yearUnit, tinyIntLiteral, dateTimeV2Literal1));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeAdd);
+            Assertions.assertInstanceOf(YearsAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            timeAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    monthUnit, tinyIntLiteral, dateTimeV2Literal1));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeAdd);
+            Assertions.assertInstanceOf(MonthsAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            timeAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    weekUnit, tinyIntLiteral, dateTimeV2Literal1));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeAdd);
+            Assertions.assertInstanceOf(WeeksAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            timeAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dayUnit, tinyIntLiteral, dateTimeV2Literal1));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeAdd);
+            Assertions.assertInstanceOf(DaysAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            timeAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    hourUnit, tinyIntLiteral, dateTimeV2Literal1));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeAdd);
+            Assertions.assertInstanceOf(HoursAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            timeAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    minuteUnit, tinyIntLiteral, dateTimeV2Literal1));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeAdd);
+            Assertions.assertInstanceOf(MinutesAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            timeAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    secondUnit, tinyIntLiteral, dateTimeV2Literal1));
+            result = DatetimeFunctionBinder.INSTANCE.bind(timeAdd);
+            Assertions.assertInstanceOf(SecondsAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, ImmutableList.of(
+                                    invalidUnit, tinyIntLiteral, 
dateTimeV2Literal1))));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of(yearUnit,
+                                    dateTimeV2Literal1))));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of(new UnboundSlot("unbound"),
+                                    tinyIntLiteral, dateTimeV2Literal1))));
+        }
+    }
+
+    @Test
+    void testDateAdd() {
+        Expression result;
+        UnboundFunction dateAdd;
+        ImmutableList<String> functionNames = ImmutableList.of("adddate", 
"days_add", "date_add");
+
+        for (String functionName : functionNames) {
+            dateAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, yearInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateAdd);
+            Assertions.assertInstanceOf(YearsAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, monthInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateAdd);
+            Assertions.assertInstanceOf(MonthsAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, weekInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateAdd);
+            Assertions.assertInstanceOf(WeeksAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dayInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateAdd);
+            Assertions.assertInstanceOf(DaysAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, hourInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateAdd);
+            Assertions.assertInstanceOf(HoursAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, minuteInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateAdd);
+            Assertions.assertInstanceOf(MinutesAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, secondInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateAdd);
+            Assertions.assertInstanceOf(SecondsAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateAdd = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, tinyIntLiteral));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateAdd);
+            Assertions.assertInstanceOf(DaysAdd.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of(dateTimeV2Literal1))));
+        }
+    }
+
+    @Test
+    void testDateSub() {
+        Expression result;
+        UnboundFunction dateSub;
+        ImmutableList<String> functionNames = ImmutableList.of("subdate", 
"days_sub", "date_sub");
+
+        for (String functionName : functionNames) {
+            dateSub = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, yearInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateSub);
+            Assertions.assertInstanceOf(YearsSub.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateSub = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, monthInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateSub);
+            Assertions.assertInstanceOf(MonthsSub.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateSub = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, weekInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateSub);
+            Assertions.assertInstanceOf(WeeksSub.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateSub = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dayInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateSub);
+            Assertions.assertInstanceOf(DaysSub.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateSub = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, hourInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateSub);
+            Assertions.assertInstanceOf(HoursSub.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateSub = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, minuteInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateSub);
+            Assertions.assertInstanceOf(MinutesSub.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateSub = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, secondInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateSub);
+            Assertions.assertInstanceOf(SecondsSub.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateSub = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, tinyIntLiteral));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateSub);
+            Assertions.assertInstanceOf(DaysSub.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of(dateTimeV2Literal1))));
+        }
+    }
+
+    @Test
+    void testDateCeil() {
+        Expression result;
+        UnboundFunction dateCeil;
+        ImmutableList<String> functionNames = ImmutableList.of("date_ceil");
+
+        for (String functionName : functionNames) {
+            dateCeil = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, yearInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateCeil);
+            Assertions.assertInstanceOf(YearCeil.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateCeil = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, monthInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateCeil);
+            Assertions.assertInstanceOf(MonthCeil.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateCeil = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, weekInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateCeil);
+            Assertions.assertInstanceOf(WeekCeil.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateCeil = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dayInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateCeil);
+            Assertions.assertInstanceOf(DayCeil.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateCeil = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, hourInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateCeil);
+            Assertions.assertInstanceOf(HourCeil.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateCeil = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, minuteInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateCeil);
+            Assertions.assertInstanceOf(MinuteCeil.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateCeil = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, secondInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateCeil);
+            Assertions.assertInstanceOf(SecondCeil.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateCeil = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, tinyIntLiteral));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateCeil);
+            Assertions.assertInstanceOf(SecondCeil.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of(dateTimeV2Literal1))));
+        }
+    }
+
+    @Test
+    void testDateFloor() {
+        Expression result;
+        UnboundFunction dateFloor;
+        ImmutableList<String> functionNames = ImmutableList.of("date_floor");
+
+        for (String functionName : functionNames) {
+            dateFloor = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, yearInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateFloor);
+            Assertions.assertInstanceOf(YearFloor.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateFloor = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, monthInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateFloor);
+            Assertions.assertInstanceOf(MonthFloor.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateFloor = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, weekInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateFloor);
+            Assertions.assertInstanceOf(WeekFloor.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateFloor = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dayInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateFloor);
+            Assertions.assertInstanceOf(DayFloor.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateFloor = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, hourInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateFloor);
+            Assertions.assertInstanceOf(HourFloor.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateFloor = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, minuteInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateFloor);
+            Assertions.assertInstanceOf(MinuteFloor.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateFloor = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, secondInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateFloor);
+            Assertions.assertInstanceOf(SecondFloor.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            dateFloor = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, tinyIntLiteral));
+            result = DatetimeFunctionBinder.INSTANCE.bind(dateFloor);
+            Assertions.assertInstanceOf(SecondFloor.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of(dateTimeV2Literal1))));
+        }
+    }
+
+    @Test
+    void testArrayRange() {
+        Expression result;
+        UnboundFunction arrayRange;
+        ImmutableList<String> functionNames = ImmutableList.of("array_range", 
"sequence");
+
+        for (String functionName : functionNames) {
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dateTimeV2Literal2, yearInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRangeYearUnit.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(1));
+            Assertions.assertEquals(tinyIntLiteral, result.child(2));
+
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dateTimeV2Literal2, monthInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRangeMonthUnit.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(1));
+            Assertions.assertEquals(tinyIntLiteral, result.child(2));
+
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dateTimeV2Literal2, weekInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRangeWeekUnit.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(1));
+            Assertions.assertEquals(tinyIntLiteral, result.child(2));
+
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dateTimeV2Literal2, dayInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRangeDayUnit.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(1));
+            Assertions.assertEquals(tinyIntLiteral, result.child(2));
+
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dateTimeV2Literal2, hourInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRangeHourUnit.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(1));
+            Assertions.assertEquals(tinyIntLiteral, result.child(2));
+
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dateTimeV2Literal2, minuteInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRangeMinuteUnit.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(1));
+            Assertions.assertEquals(tinyIntLiteral, result.child(2));
+
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    dateTimeV2Literal1, dateTimeV2Literal2, secondInterval));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRangeSecondUnit.class, result);
+            Assertions.assertEquals(dateTimeV2Literal1, result.child(0));
+            Assertions.assertEquals(dateTimeV2Literal2, result.child(1));
+            Assertions.assertEquals(tinyIntLiteral, result.child(2));
+
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    tinyIntLiteral, tinyIntLiteral, tinyIntLiteral));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRange.class, result);
+            Assertions.assertEquals(tinyIntLiteral, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+            Assertions.assertEquals(tinyIntLiteral, result.child(2));
+
+            arrayRange = new UnboundFunction(functionName, ImmutableList.of(
+                    tinyIntLiteral, tinyIntLiteral));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRange.class, result);
+            Assertions.assertEquals(tinyIntLiteral, result.child(0));
+            Assertions.assertEquals(tinyIntLiteral, result.child(1));
+
+            arrayRange = new UnboundFunction(functionName, 
ImmutableList.of(tinyIntLiteral));
+            result = DatetimeFunctionBinder.INSTANCE.bind(arrayRange);
+            Assertions.assertInstanceOf(ArrayRange.class, result);
+            Assertions.assertEquals(tinyIntLiteral, result.child(0));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, 
ImmutableList.of())));
+
+            Assertions.assertThrowsExactly(AnalysisException.class,
+                    () -> DatetimeFunctionBinder.INSTANCE.bind(
+                            new UnboundFunction(functionName, ImmutableList.of(
+                                    tinyIntLiteral, tinyIntLiteral, 
tinyIntLiteral, tinyIntLiteral))));
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to