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

chengzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 684b73718b7 Support Oracle Interval Expression (#27470)
684b73718b7 is described below

commit 684b73718b71c491acc51d96146bcfda5001930b
Author: Zichao <[email protected]>
AuthorDate: Wed Jul 26 17:40:30 2023 +1200

    Support Oracle Interval Expression (#27470)
---
 .../src/main/antlr4/imports/oracle/BaseRule.g4     | 22 +++++-
 .../visitor/statement/OracleStatementVisitor.java  | 53 +++++++++++++++
 .../statement/type/OracleDMLStatementVisitor.java  | 12 ++++
 .../dml/expr/IntervalDayToSecondExpression.java    | 52 ++++++++++++++
 .../dml/expr/IntervalYearToMonthExpression.java    | 49 ++++++++++++++
 .../dml/item/IntervalExpressionProjection.java     | 55 +++++++++++++++
 .../segment/expression/ExpressionAssert.java       | 79 ++++++++++++++++++++++
 .../jaxb/segment/impl/expr/ExpectedExpression.java |  3 +
 .../ExpectedIntervalDayToSecondExpression.java     | 47 +++++++++++++
 .../impl/expr/ExpectedIntervalExpression.java      | 48 +++++++++++++
 .../ExpectedIntervalYearToMonthExpression.java     | 44 ++++++++++++
 .../main/resources/case/dml/select-expression.xml  | 24 +++++++
 .../sql/supported/dml/select-expression.xml        |  1 +
 13 files changed, 486 insertions(+), 3 deletions(-)

diff --git 
a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4 
b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
index 02407dd05b0..9b212ab3407 100644
--- a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
+++ b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
@@ -661,12 +661,12 @@ bitExpr
     | bitExpr SIGNED_LEFT_SHIFT_ bitExpr
     | bitExpr SIGNED_RIGHT_SHIFT_ bitExpr
     | bitExpr PLUS_ bitExpr
+    | simpleExpr
     | bitExpr MINUS_ bitExpr
     | bitExpr ASTERISK_ bitExpr
     | bitExpr SLASH_ bitExpr
     | bitExpr MOD_ bitExpr
     | bitExpr CARET_ bitExpr
-    | simpleExpr
     ;
 
 simpleExpr
@@ -790,7 +790,7 @@ regularFunctionName
     ;
 
 joinOperator
-    : LP_ PLUS_  RP_
+    : LP_ PLUS_ RP_
     ;
 
 caseExpression
@@ -886,7 +886,23 @@ elseClause
     ;
 
 intervalExpression
-    : LP_ expr MINUS_ expr RP_ (DAY (LP_ NUMBER_ RP_)? TO SECOND (LP_ NUMBER_ 
RP_)? | YEAR (LP_ NUMBER_ RP_)? TO MONTH)
+    : LP_ expr MINUS_ expr RP_ (intervalDayToSecondExpression | 
intervalYearToMonthExpression)
+    ;
+
+intervalDayToSecondExpression
+    : DAY (LP_ leadingFieldPrecision RP_)? TO SECOND (LP_ 
fractionalSecondPrecision RP_)?
+    ;
+
+intervalYearToMonthExpression
+    : YEAR (LP_ leadingFieldPrecision RP_)? TO MONTH
+    ;
+
+leadingFieldPrecision
+    : INTEGER_
+    ;
+
+fractionalSecondPrecision
+    : INTEGER_
     ;
 
 objectAccessExpression
diff --git 
a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/OracleStatementVisitor.java
 
b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/OracleStatementVisitor.java
index 50f69257f97..7ddca6a0ea3 100644
--- 
a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/OracleStatementVisitor.java
+++ 
b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/OracleStatementVisitor.java
@@ -48,6 +48,9 @@ import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.Hexade
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IdentifierContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IndexNameContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IndexTypeNameContext;
+import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IntervalDayToSecondExpressionContext;
+import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IntervalExpressionContext;
+import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IntervalYearToMonthExpressionContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.LiteralsContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.NullValueLiteralsContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.NumberLiteralsContext;
@@ -57,6 +60,7 @@ import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.OwnerC
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.PackageNameContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.ParameterMarkerContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.PredicateContext;
+import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.PrivateExprOfDbContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.RegularFunctionContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.SchemaNameContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.SimpleExprContext;
@@ -99,6 +103,9 @@ import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.Datetime
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.FunctionSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.IntervalDayToSecondExpression;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.IntervalExpressionProjection;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.IntervalYearToMonthExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ListExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.NotExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.XmlNameSpaceStringAsIdentifierSegment;
@@ -507,9 +514,55 @@ public abstract class OracleStatementVisitor extends 
OracleStatementBaseVisitor<
             return null == ctx.joinOperator() ? visit(ctx.columnName())
                     : new ColumnWithJoinOperatorSegment(startIndex, stopIndex, 
(ColumnSegment) visitColumnName(ctx.columnName()), 
ctx.joinOperator().getText());
         }
+        if (null != ctx.privateExprOfDb()) {
+            return visit(ctx.privateExprOfDb());
+        }
         return new CommonExpressionSegment(startIndex, stopIndex, 
ctx.getText());
     }
     
+    @Override
+    public ASTNode visitPrivateExprOfDb(final PrivateExprOfDbContext ctx) {
+        if (null != ctx.intervalExpression()) {
+            return visit(ctx.intervalExpression());
+        }
+        return super.visitPrivateExprOfDb(ctx);
+    }
+    
+    @Override
+    public ASTNode visitIntervalExpression(final IntervalExpressionContext 
ctx) {
+        IntervalExpressionProjection result = new 
IntervalExpressionProjection(ctx.getStart().getStartIndex(), 
ctx.getStop().getStopIndex(), (ExpressionSegment) visit(ctx.expr(0)),
+                (ExpressionSegment) visit(ctx.MINUS_()), (ExpressionSegment) 
visit(ctx.expr(1)));
+        if (null != ctx.intervalDayToSecondExpression()) {
+            result.setDayToSecondExpression((IntervalDayToSecondExpression) 
visit(ctx.intervalDayToSecondExpression()));
+        } else {
+            result.setYearToMonthExpression((IntervalYearToMonthExpression) 
visit(ctx.intervalYearToMonthExpression()));
+        }
+        return result;
+    }
+    
+    @Override
+    public ASTNode visitIntervalDayToSecondExpression(final 
IntervalDayToSecondExpressionContext ctx) {
+        IntervalDayToSecondExpression result = new 
IntervalDayToSecondExpression(ctx.getStart().getStartIndex(), 
ctx.getStop().getStopIndex(),
+                ctx.DAY().getText(), ctx.TO().getText(), 
ctx.SECOND().getText());
+        if (null != ctx.leadingFieldPrecision()) {
+            
result.setLeadingFieldPrecision(Integer.parseInt(ctx.leadingFieldPrecision().INTEGER_().getText()));
+        }
+        if (null != ctx.fractionalSecondPrecision()) {
+            
result.setFractionalSecondPrecision(Integer.parseInt(ctx.fractionalSecondPrecision().getText()));
+        }
+        return result;
+    }
+    
+    @Override
+    public ASTNode visitIntervalYearToMonthExpression(final 
IntervalYearToMonthExpressionContext ctx) {
+        IntervalYearToMonthExpression result = new 
IntervalYearToMonthExpression(ctx.getStart().getStartIndex(), 
ctx.getStop().getStopIndex(),
+                ctx.YEAR().getText(), ctx.TO().getText(), 
ctx.MONTH().getText());
+        if (null != ctx.leadingFieldPrecision()) {
+            
result.setLeadingFieldPrecision(Integer.parseInt(ctx.leadingFieldPrecision().INTEGER_().getText()));
+        }
+        return result;
+    }
+    
     @Override
     public final ASTNode visitFunctionCall(final FunctionCallContext ctx) {
         if (null != ctx.aggregationFunction()) {
diff --git 
a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
 
b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
index 1829cfafbca..01803f301a4 100644
--- 
a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
+++ 
b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
@@ -115,6 +115,7 @@ import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOp
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.DatetimeExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.FunctionSegment;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.IntervalExpressionProjection;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.XmlPiFunctionSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.XmlQueryAndExistsFunctionSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.XmlSerializeFunctionSegment;
@@ -733,6 +734,17 @@ public final class OracleDMLStatementVisitor extends 
OracleStatementVisitor impl
             ((AliasAvailable) projection).setAlias(alias);
             return projection;
         }
+        if (projection instanceof IntervalExpressionProjection) {
+            IntervalExpressionProjection intervalExpressionProjection = 
(IntervalExpressionProjection) projection;
+            IntervalExpressionProjection result = new 
IntervalExpressionProjection(intervalExpressionProjection.getStartIndex(), 
intervalExpressionProjection.getStopIndex(),
+                    intervalExpressionProjection.getLeft(), 
intervalExpressionProjection.getMinus(), 
intervalExpressionProjection.getRight());
+            if (null != 
intervalExpressionProjection.getDayToSecondExpression()) {
+                
result.setDayToSecondExpression(intervalExpressionProjection.getDayToSecondExpression());
+            } else {
+                
result.setYearToMonthExpression(intervalExpressionProjection.getYearToMonthExpression());
+            }
+            return result;
+        }
         LiteralExpressionSegment column = (LiteralExpressionSegment) 
projection;
         ExpressionProjectionSegment result = null == alias
                 ? new ExpressionProjectionSegment(column.getStartIndex(), 
column.getStopIndex(), String.valueOf(column.getLiterals()), column)
diff --git 
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/IntervalDayToSecondExpression.java
 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/IntervalDayToSecondExpression.java
new file mode 100644
index 00000000000..dd972002ef5
--- /dev/null
+++ 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/IntervalDayToSecondExpression.java
@@ -0,0 +1,52 @@
+/*
+ * 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.shardingsphere.sql.parser.sql.common.segment.dml.expr;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Between expression.
+ */
+@RequiredArgsConstructor
+@Getter
+@Setter
+public final class IntervalDayToSecondExpression implements ExpressionSegment {
+    
+    private final int startIndex;
+    
+    private final int stopIndex;
+    
+    private final String day;
+    
+    private final String to;
+    
+    private final String second;
+    
+    @Setter
+    private Integer leadingFieldPrecision;
+    
+    @Setter
+    private Integer fractionalSecondPrecision;
+    
+    @Override
+    public String getText() {
+        return null;
+    }
+}
diff --git 
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/IntervalYearToMonthExpression.java
 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/IntervalYearToMonthExpression.java
new file mode 100644
index 00000000000..a7e22d53f52
--- /dev/null
+++ 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/IntervalYearToMonthExpression.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Interval year to month expression.
+ */
+@RequiredArgsConstructor
+@Getter
+@Setter
+public final class IntervalYearToMonthExpression implements ExpressionSegment {
+    
+    private final int startIndex;
+    
+    private final int stopIndex;
+    
+    private final String year;
+    
+    private final String to;
+    
+    private final String month;
+    
+    @Setter
+    private Integer leadingFieldPrecision;
+    
+    @Override
+    public String getText() {
+        return null;
+    }
+}
diff --git 
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/IntervalExpressionProjection.java
 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/IntervalExpressionProjection.java
new file mode 100644
index 00000000000..5871e52a93f
--- /dev/null
+++ 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/IntervalExpressionProjection.java
@@ -0,0 +1,55 @@
+/*
+ * 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.shardingsphere.sql.parser.sql.common.segment.dml.item;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.IntervalDayToSecondExpression;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.IntervalYearToMonthExpression;
+
+/**
+ * Between expression.
+ */
+@RequiredArgsConstructor
+@Getter
+@Setter
+public final class IntervalExpressionProjection implements ExpressionSegment, 
ProjectionSegment {
+    
+    private final int startIndex;
+    
+    private final int stopIndex;
+    
+    private final ExpressionSegment left;
+    
+    private final ExpressionSegment minus;
+    
+    private final ExpressionSegment right;
+    
+    @Setter
+    private IntervalDayToSecondExpression dayToSecondExpression;
+    
+    @Setter
+    private IntervalYearToMonthExpression yearToMonthExpression;
+    
+    @Override
+    public String getText() {
+        return minus.getText();
+    }
+}
diff --git 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
index 86ebb930ac9..e65dd42cbe3 100644
--- 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
+++ 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
@@ -30,6 +30,9 @@ import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.Expressi
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExtractArgExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.FunctionSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.IntervalDayToSecondExpression;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.IntervalExpressionProjection;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.IntervalYearToMonthExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ListExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.MatchAgainstExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.NotExpression;
@@ -62,6 +65,9 @@ import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.s
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedExpression;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedExtractArgExpression;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedInExpression;
+import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedIntervalDayToSecondExpression;
+import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedIntervalExpression;
+import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedIntervalYearToMonthExpression;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedListExpression;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedMatchExpression;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedNotExpression;
@@ -79,6 +85,7 @@ import java.util.Iterator;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
@@ -421,6 +428,76 @@ public final class ExpressionAssert {
         }
     }
     
+    /**
+     * Assert expression by actual expression segment class type.
+     *
+     * @param assertContext assert context
+     * @param actual actual interval expression
+     * @param expected expected interval expression
+     */
+    private static void assertIntervalExpression(final SQLCaseAssertContext 
assertContext, final IntervalExpressionProjection actual, final 
ExpectedIntervalExpression expected) {
+        if (null == expected) {
+            assertNull(actual, assertContext.getText("Actual interval 
expression should not exist."));
+        } else {
+            assertNotNull(actual, assertContext.getText("Actual interval 
expression should exist"));
+            assertExpression(assertContext, actual.getLeft(), 
expected.getLeft());
+            assertExpression(assertContext, actual.getRight(), 
expected.getRight());
+            assertExpression(assertContext, actual.getMinus(), 
expected.getOperator());
+            if (null != actual.getDayToSecondExpression()) {
+                assertIntervalDayToSecondExpression(assertContext, 
actual.getDayToSecondExpression(), expected.getDayToSecondExpression());
+            } else {
+                assertIntervalYearToMonthExpression(assertContext, 
actual.getYearToMonthExpression(), expected.getYearToMonthExpression());
+            }
+        }
+    }
+    
+    /**
+     * Assert expression by actual expression segment class type.
+     *
+     * @param assertContext assert context
+     * @param actual actual interval day to second expression
+     * @param expected expected interval day to second expression
+     */
+    private static void assertIntervalDayToSecondExpression(final 
SQLCaseAssertContext assertContext,
+                                                            final 
IntervalDayToSecondExpression actual, final 
ExpectedIntervalDayToSecondExpression expected) {
+        if (null == expected) {
+            assertNull(actual, assertContext.getText("Actual interval 
expression should not exist."));
+        } else {
+            assertNotNull(actual, assertContext.getText("Actual interval 
expression should exist"));
+            if (null != actual.getLeadingFieldPrecision()) {
+                assertEquals(actual.getLeadingFieldPrecision(), 
expected.getLeadingFieldPrecision());
+            } else {
+                assertNull(expected.getLeadingFieldPrecision(), 
assertContext.getText("Actual leading field precision should not exist."));
+            }
+            if (null != actual.getFractionalSecondPrecision()) {
+                assertEquals(actual.getFractionalSecondPrecision(), 
expected.getFractionalSecondPrecision());
+            } else {
+                assertNull(expected.getFractionalSecondPrecision(), 
assertContext.getText("Actual fractional second precision should not exist."));
+            }
+        }
+    }
+    
+    /**
+     * Assert expression by actual expression segment class type.
+     *
+     * @param assertContext assert context
+     * @param actual actual interval year to month expression
+     * @param expected expected interval year to month expression
+     */
+    private static void assertIntervalYearToMonthExpression(final 
SQLCaseAssertContext assertContext,
+                                                            final 
IntervalYearToMonthExpression actual, final 
ExpectedIntervalYearToMonthExpression expected) {
+        if (null == expected) {
+            assertNull(actual, assertContext.getText("Actual interval 
expression should not exist."));
+        } else {
+            assertNotNull(actual, assertContext.getText("Actual interval 
expression should exist"));
+            if (null != actual.getLeadingFieldPrecision()) {
+                assertEquals(actual.getLeadingFieldPrecision(), 
expected.getLeadingFieldPrecision());
+            } else {
+                assertNull(expected.getLeadingFieldPrecision(), 
assertContext.getText("Actual leading field precision should not exist."));
+            }
+        }
+    }
+    
     /**
      * Assert expression by actual expression segment class type.
      *
@@ -482,6 +559,8 @@ public final class ExpressionAssert {
             assertMatchSegment(assertContext, (MatchAgainstExpression) actual, 
expected.getMatchExpression());
         } else if (actual instanceof ColumnWithJoinOperatorSegment) {
             ColumnWithJoinOperatorAssert.assertIs(assertContext, 
(ColumnWithJoinOperatorSegment) actual, 
expected.getColumnWithJoinOperatorSegment());
+        } else if (actual instanceof IntervalExpressionProjection) {
+            assertIntervalExpression(assertContext, 
(IntervalExpressionProjection) actual, expected.getIntervalExpression());
         } else {
             throw new UnsupportedOperationException(String.format("Unsupported 
expression: %s", actual.getClass().getName()));
         }
diff --git 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
index 1a11a857ad7..08d66195e4b 100644
--- 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
+++ 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
@@ -107,4 +107,7 @@ public final class ExpectedExpression extends 
AbstractExpectedSQLSegment {
     
     @XmlElement(name = "colum-with-join-operator-segment")
     private ExpectedColumnWithJoinOperatorSegment 
columnWithJoinOperatorSegment;
+    
+    @XmlElement(name = "interval-expression")
+    private ExpectedIntervalExpression intervalExpression;
 }
diff --git 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalDayToSecondExpression.java
 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalDayToSecondExpression.java
new file mode 100644
index 00000000000..e505247a8fb
--- /dev/null
+++ 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalDayToSecondExpression.java
@@ -0,0 +1,47 @@
+/*
+ * 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.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr;
+
+import lombok.Getter;
+import lombok.Setter;
+import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedSQLSegment;
+
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * Expected interval day to second expression.
+ */
+@Getter
+@Setter
+public class ExpectedIntervalDayToSecondExpression extends 
AbstractExpectedSQLSegment implements ExpectedExpressionSegment {
+    
+    @XmlElement
+    private String day;
+    
+    @XmlElement
+    private String to;
+    
+    @XmlElement
+    private String second;
+    
+    @XmlElement(name = "leading-field-precision")
+    private Integer leadingFieldPrecision;
+    
+    @XmlElement(name = "fractional-second-precision")
+    private Integer fractionalSecondPrecision;
+}
diff --git 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalExpression.java
 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalExpression.java
new file mode 100644
index 00000000000..22543b3d5ab
--- /dev/null
+++ 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalExpression.java
@@ -0,0 +1,48 @@
+/*
+ * 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.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr;
+
+import lombok.Getter;
+import lombok.Setter;
+import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedSQLSegment;
+
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * Expected match expression.
+ */
+@Getter
+@Setter
+public class ExpectedIntervalExpression extends AbstractExpectedSQLSegment 
implements ExpectedExpressionSegment {
+    
+    @XmlElement
+    private ExpectedExpression left;
+    
+    @XmlElement
+    private ExpectedExpression right;
+    
+    @XmlElement
+    private ExpectedExpression operator;
+    
+    @XmlElement(name = "interval-day-to-second-expr")
+    private ExpectedIntervalDayToSecondExpression dayToSecondExpression;
+    
+    @XmlElement(name = "interval-year-to-month-expr")
+    private ExpectedIntervalYearToMonthExpression yearToMonthExpression;
+    
+}
diff --git 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalYearToMonthExpression.java
 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalYearToMonthExpression.java
new file mode 100644
index 00000000000..73a6497c563
--- /dev/null
+++ 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedIntervalYearToMonthExpression.java
@@ -0,0 +1,44 @@
+/*
+ * 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.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr;
+
+import lombok.Getter;
+import lombok.Setter;
+import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedSQLSegment;
+
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * Expected interval day to second expression.
+ */
+@Getter
+@Setter
+public class ExpectedIntervalYearToMonthExpression extends 
AbstractExpectedSQLSegment implements ExpectedExpressionSegment {
+    
+    @XmlElement
+    private String year;
+    
+    @XmlElement
+    private String to;
+    
+    @XmlElement
+    private String month;
+    
+    @XmlElement(name = "leading-field-precision")
+    private Integer leadingFieldPrecision;
+}
diff --git a/test/it/parser/src/main/resources/case/dml/select-expression.xml 
b/test/it/parser/src/main/resources/case/dml/select-expression.xml
index c2f46ecb29b..998704efef7 100644
--- a/test/it/parser/src/main/resources/case/dml/select-expression.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-expression.xml
@@ -2595,4 +2595,28 @@
             <simple-table name="V$LOGMNR_CONTENTS" start-index="70" 
stop-index="86" />
         </from>
     </select>
+    
+    <select sql-case-id="select_interval_day_to_second_expression">
+        <projections start-index="7" stop-index="50">
+            <expression-projection text="(SYSTIMESTAMP - order_date) DAY(9) TO 
SECOND" start-index="7" stop-index="50">
+                <function>
+                    <interval-expression>
+                        <left>
+                            <column name="SYSTIMESTAMP" start-index="" 
stop-index=""/>
+                        </left>
+                        <operator>-</operator>
+                        <right>
+                            <column name="order_date" start-index="" 
stop-index="" />
+                        </right>
+                        <interval-day-to-second-expr>
+                            
<leading-field-precision>9</leading-field-precision>
+                        </interval-day-to-second-expr>
+                    </interval-expression>
+                </function>
+            </expression-projection>
+        </projections>
+        <from>
+            <simple-table name="orders" start-index="57" stop-index="62" />
+        </from>
+    </select>
 </sql-parser-test-cases>
diff --git 
a/test/it/parser/src/main/resources/sql/supported/dml/select-expression.xml 
b/test/it/parser/src/main/resources/sql/supported/dml/select-expression.xml
index 239ff3623d9..9ba0539ecdf 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select-expression.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select-expression.xml
@@ -106,4 +106,5 @@
     <sql-case id="select_datetime_expression" value="SELECT SYSTIMESTAMP AT 
TIME ZONE 'UTC' FROM DUAL;" db-types="Oracle" />
     <sql-case id="select_between_expression" value="SELECT item_id BETWEEN 1 
AND order_id, status FROM t_order_item;" db-types="MySQL" />
     <sql-case id="select_dbms_logmnr_mine_value_regular_function" 
value="SELECT DBMS_LOGMNR.MINE_VALUE(UNDO_VALUE, 'HR.EMPLOYEES.SALARY') FROM 
V$LOGMNR_CONTENTS;" db-types="Oracle" />
+    <sql-case id="select_interval_day_to_second_expression" value="SELECT 
(SYSTIMESTAMP - order_date) DAY(9) TO SECOND FROM orders" db-types="Oracle" />
 </sql-cases>


Reply via email to