You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by du...@apache.org on 2023/01/17 01:22:38 UTC

[shardingsphere] branch master updated: Add TypeCastExpression for PostgreSQL/openGauss (#23580)

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

duanzhengqiang 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 6b095c835f5 Add TypeCastExpression for PostgreSQL/openGauss (#23580)
6b095c835f5 is described below

commit 6b095c835f5334f01bb6643565ddb3276e9f9a56
Author: 吴伟杰 <wu...@apache.org>
AuthorDate: Tue Jan 17 09:22:30 2023 +0800

    Add TypeCastExpression for PostgreSQL/openGauss (#23580)
    
    * Add TypeCastExpression for PostgreSQL/openGauss
    
    * Add TypeCastExpression to ExpressionExtractUtil
    
    * Add parser test for PostgreSQL/openGauss nested type cast
    
    * Use TypeCastExpression in openGauss parser
    
    * Remove TODO in select.xml
    
    * Complete ExpressionExtractUtilTest
---
 .../impl/OpenGaussStatementSQLVisitor.java         |  28 ++--
 .../impl/PostgreSQLStatementSQLVisitor.java        |  28 ++--
 .../segment/dml/expr/TypeCastExpression.java       |  38 +++++
 .../sql/common/util/ExpressionExtractUtil.java     |   4 +
 .../sql/common/util/ExpressionExtractUtilTest.java |  11 ++
 .../segment/expression/ExpressionAssert.java       |  15 +-
 .../jaxb/segment/impl/expr/ExpectedExpression.java |   3 +
 .../impl/expr/ExpectedTypeCastExpression.java      |  37 +++++
 .../resources/case/dml/select-special-function.xml |   7 +-
 .../parser/src/main/resources/case/dml/select.xml  | 153 +++++++++++++--------
 .../main/resources/sql/supported/dml/select.xml    |   1 +
 11 files changed, 238 insertions(+), 87 deletions(-)

diff --git a/sql-parser/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/impl/OpenGaussStatementSQLVisitor.java b/sql-parser/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/impl/OpenGaussStatementSQLVisitor.java
index 1362f4dcf2d..573d175ab57 100644
--- a/sql-parser/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/impl/OpenGaussStatementSQLVisitor.java
+++ b/sql-parser/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/impl/OpenGaussStatementSQLVisitor.java
@@ -134,6 +134,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.Expressi
 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.ListExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.TypeCastExpression;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
@@ -294,8 +295,7 @@ public abstract class OpenGaussStatementSQLVisitor extends OpenGaussStatementBas
             return visit(ctx.cExpr());
         }
         if (null != ctx.TYPE_CAST_()) {
-            return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.aExpr(0)),
-                    new CommonExpressionSegment(ctx.typeName().start.getStartIndex(), ctx.typeName().stop.getStopIndex(), ctx.typeName().getText()), ctx.TYPE_CAST_().getText(), ctx.getText());
+            return new TypeCastExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.aExpr(0)), ctx.typeName().getText());
         }
         if (null != ctx.BETWEEN()) {
             return createBetweenSegment(ctx);
@@ -452,6 +452,9 @@ public abstract class OpenGaussStatementSQLVisitor extends OpenGaussStatementBas
     
     @Override
     public ASTNode visitFunctionExprCommonSubexpr(final FunctionExprCommonSubexprContext ctx) {
+        if (null != ctx.CAST()) {
+            return new TypeCastExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.aExpr(0)), ctx.typeName().getText());
+        }
         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getChild(0).getText(), getOriginalText(ctx));
         Collection<ExpressionSegment> expressionSegments = getExpressionSegments(getTargetRuleContextFromParseTree(ctx, AExprContext.class));
         result.getParameters().addAll(expressionSegments);
@@ -495,6 +498,11 @@ public abstract class OpenGaussStatementSQLVisitor extends OpenGaussStatementBas
         } else {
             value = new OtherLiteralValue(ctx.getText());
         }
+        if (null != ctx.constTypeName() || null != ctx.funcName() && null == ctx.LP_()) {
+            LiteralExpressionSegment expression = new LiteralExpressionSegment(ctx.STRING_().getSymbol().getStartIndex(), ctx.STRING_().getSymbol().getStopIndex(), value.getValue().toString());
+            String dataType = null != ctx.constTypeName() ? ctx.constTypeName().getText() : ctx.funcName().getText();
+            return new TypeCastExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), expression, dataType);
+        }
         return SQLUtil.createLiteralExpression(value, ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.getText());
     }
     
@@ -553,17 +561,13 @@ public abstract class OpenGaussStatementSQLVisitor extends OpenGaussStatementBas
         if (null != ctx.cExpr()) {
             return visit(ctx.cExpr());
         }
-        if (null != ctx.TYPE_CAST_() || null != ctx.qualOp()) {
+        if (null != ctx.TYPE_CAST_()) {
+            return new TypeCastExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.bExpr(0)), ctx.typeName().getText());
+        }
+        if (null != ctx.qualOp()) {
             ExpressionSegment left = (ExpressionSegment) visit(ctx.bExpr(0));
-            String operator;
-            ExpressionSegment right;
-            if (null == ctx.TYPE_CAST_()) {
-                operator = ctx.qualOp().getText();
-                right = (ExpressionSegment) visit(ctx.bExpr(1));
-            } else {
-                operator = ctx.TYPE_CAST_().getText();
-                right = new CommonExpressionSegment(ctx.typeName().start.getStartIndex(), ctx.typeName().stop.getStopIndex(), ctx.typeName().getText());
-            }
+            ExpressionSegment right = (ExpressionSegment) visit(ctx.bExpr(1));
+            String operator = ctx.qualOp().getText();
             String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
             return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
         }
diff --git a/sql-parser/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLStatementSQLVisitor.java b/sql-parser/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLStatementSQLVisitor.java
index 210dbe61e86..7073cf4e819 100644
--- a/sql-parser/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLStatementSQLVisitor.java
+++ b/sql-parser/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLStatementSQLVisitor.java
@@ -134,6 +134,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.Expressi
 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.ListExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.TypeCastExpression;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
@@ -294,8 +295,7 @@ public abstract class PostgreSQLStatementSQLVisitor extends PostgreSQLStatementP
             return visit(ctx.cExpr());
         }
         if (null != ctx.TYPE_CAST_()) {
-            return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.aExpr(0)),
-                    new CommonExpressionSegment(ctx.typeName().start.getStartIndex(), ctx.typeName().stop.getStopIndex(), ctx.typeName().getText()), ctx.TYPE_CAST_().getText(), ctx.getText());
+            return new TypeCastExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.aExpr(0)), ctx.typeName().getText());
         }
         if (null != ctx.BETWEEN()) {
             return createBetweenSegment(ctx);
@@ -449,6 +449,9 @@ public abstract class PostgreSQLStatementSQLVisitor extends PostgreSQLStatementP
     
     @Override
     public ASTNode visitFunctionExprCommonSubexpr(final FunctionExprCommonSubexprContext ctx) {
+        if (null != ctx.CAST()) {
+            return new TypeCastExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.aExpr(0)), ctx.typeName().getText());
+        }
         FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getChild(0).getText(), getOriginalText(ctx));
         Collection<ExpressionSegment> expressionSegments = getExpressionSegments(getTargetRuleContextFromParseTree(ctx, AExprContext.class));
         result.getParameters().addAll(expressionSegments);
@@ -492,6 +495,11 @@ public abstract class PostgreSQLStatementSQLVisitor extends PostgreSQLStatementP
         } else {
             value = new OtherLiteralValue(ctx.getText());
         }
+        if (null != ctx.constTypeName() || null != ctx.funcName() && null == ctx.LP_()) {
+            LiteralExpressionSegment expression = new LiteralExpressionSegment(ctx.STRING_().getSymbol().getStartIndex(), ctx.STRING_().getSymbol().getStopIndex(), value.getValue().toString());
+            String dataType = null != ctx.constTypeName() ? ctx.constTypeName().getText() : ctx.funcName().getText();
+            return new TypeCastExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), expression, dataType);
+        }
         return SQLUtil.createLiteralExpression(value, ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.getText());
     }
     
@@ -550,17 +558,13 @@ public abstract class PostgreSQLStatementSQLVisitor extends PostgreSQLStatementP
         if (null != ctx.cExpr()) {
             return visit(ctx.cExpr());
         }
-        if (null != ctx.TYPE_CAST_() || null != ctx.qualOp()) {
+        if (null != ctx.TYPE_CAST_()) {
+            return new TypeCastExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.bExpr(0)), ctx.typeName().getText());
+        }
+        if (null != ctx.qualOp()) {
             ExpressionSegment left = (ExpressionSegment) visit(ctx.bExpr(0));
-            String operator;
-            ExpressionSegment right;
-            if (null == ctx.TYPE_CAST_()) {
-                operator = ctx.qualOp().getText();
-                right = (ExpressionSegment) visit(ctx.bExpr(1));
-            } else {
-                operator = ctx.TYPE_CAST_().getText();
-                right = new CommonExpressionSegment(ctx.typeName().start.getStartIndex(), ctx.typeName().stop.getStopIndex(), ctx.typeName().getText());
-            }
+            ExpressionSegment right = (ExpressionSegment) visit(ctx.bExpr(1));
+            String operator = ctx.qualOp().getText();
             String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
             return new BinaryOperationExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), left, right, operator, text);
         }
diff --git a/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/TypeCastExpression.java b/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/TypeCastExpression.java
new file mode 100644
index 00000000000..d9cdb22c7a7
--- /dev/null
+++ b/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/TypeCastExpression.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * Type cast expression.
+ */
+@RequiredArgsConstructor
+@Getter
+public final class TypeCastExpression implements ExpressionSegment {
+    
+    private final int startIndex;
+    
+    private final int stopIndex;
+    
+    private final ExpressionSegment expression;
+    
+    // TODO Parse data type after https://github.com/apache/shardingsphere/issues/23466 fixed
+    private final String dataType;
+}
diff --git a/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/ExpressionExtractUtil.java b/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/ExpressionExtractUtil.java
index fc3ad412f9a..2965d944429 100644
--- a/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/ExpressionExtractUtil.java
+++ b/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/ExpressionExtractUtil.java
@@ -23,6 +23,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.enums.LogicalOperator;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
 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.TypeCastExpression;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.AndPredicate;
 
@@ -111,6 +112,9 @@ public final class ExpressionExtractUtil {
             if (each instanceof FunctionSegment) {
                 extractParameterMarkerExpressions(result, ((FunctionSegment) each).getParameters());
             }
+            if (each instanceof TypeCastExpression) {
+                extractParameterMarkerExpressions(result, Collections.singletonList(((TypeCastExpression) each).getExpression()));
+            }
         }
     }
 }
diff --git a/sql-parser/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/util/ExpressionExtractUtilTest.java b/sql-parser/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/util/ExpressionExtractUtilTest.java
index d4af56a11df..1b4dd21b026 100644
--- a/sql-parser/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/util/ExpressionExtractUtilTest.java
+++ b/sql-parser/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/util/ExpressionExtractUtilTest.java
@@ -17,10 +17,12 @@
 
 package org.apache.shardingsphere.sql.parser.sql.common.util;
 
+import org.apache.shardingsphere.sql.parser.sql.common.enums.ParameterMarkerType;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
 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.TypeCastExpression;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
@@ -118,4 +120,13 @@ public final class ExpressionExtractUtilTest {
         List<ParameterMarkerExpressionSegment> result = ExpressionExtractUtil.getParameterMarkerExpressions(Collections.singletonList(functionSegment));
         assertThat(result.size(), is(1));
     }
+    
+    @Test
+    public void assertGetParameterMarkerExpressionsFromTypeCastExpression() {
+        ParameterMarkerExpressionSegment expected = new ParameterMarkerExpressionSegment(0, 0, 1, ParameterMarkerType.DOLLAR);
+        List<ExpressionSegment> input = Collections.singletonList(new TypeCastExpression(0, 0, expected, "varchar"));
+        List<ParameterMarkerExpressionSegment> actual = ExpressionExtractUtil.getParameterMarkerExpressions(input);
+        assertThat(actual.size(), is(1));
+        assertThat(actual.get(0), is(expected));
+    }
 }
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 ba87f1d9740..270180c1753 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,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.Function
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
 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.TypeCastExpression;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.ComplexExpressionSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
@@ -55,6 +56,7 @@ 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.ExpectedInExpression;
 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.ExpectedNotExpression;
+import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedTypeCastExpression;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.complex.ExpectedCommonExpression;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.simple.ExpectedLiteralExpression;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.simple.ExpectedParameterMarkerExpression;
@@ -349,13 +351,22 @@ public final class ExpressionAssert {
         assertExpression(assertContext, actual.getElseExpr(), expected.getElseExpr());
     }
     
+    private static void assertTypeCastExpression(final SQLCaseAssertContext assertContext, final TypeCastExpression actual, final ExpectedTypeCastExpression expected) {
+        if (null == expected) {
+            assertNull(assertContext.getText("Type cast expression should not exist."), actual);
+            return;
+        }
+        assertNotNull(assertContext.getText("Type cast expression is expected."), actual);
+        assertThat(assertContext.getText("Actual data type is different with expected in type case expression."), actual.getDataType(), is(expected.getDataType()));
+        assertExpression(assertContext, actual.getExpression(), expected.getExpression());
+    }
+    
     /**
      * Assert expression by actual expression segment class type.
      *
      * @param assertContext assert context
      * @param actual actual expression segment
      * @param expected expected expression
-     *
      * @throws UnsupportedOperationException When expression segment class type is not supported.
      */
     public static void assertExpression(final SQLCaseAssertContext assertContext,
@@ -399,6 +410,8 @@ public final class ExpressionAssert {
             assertCollateExpression(assertContext, (CollateExpression) actual, expected.getCollateExpression());
         } else if (actual instanceof CaseWhenExpression) {
             assertCaseWhenExpression(assertContext, (CaseWhenExpression) actual, expected.getCaseWhenExpression());
+        } else if (actual instanceof TypeCastExpression) {
+            assertTypeCastExpression(assertContext, (TypeCastExpression) actual, expected.getTypeCastExpression());
         } 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 67ffaf19253..a5fa04ed7be 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
@@ -89,4 +89,7 @@ public final class ExpectedExpression extends AbstractExpectedSQLSegment {
     
     @XmlElement(name = "case-when-expression")
     private ExpectedCaseWhenExpression caseWhenExpression;
+    
+    @XmlElement(name = "type-cast-expression")
+    private ExpectedTypeCastExpression typeCastExpression;
 }
diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedTypeCastExpression.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedTypeCastExpression.java
new file mode 100644
index 00000000000..693aec32b89
--- /dev/null
+++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedTypeCastExpression.java
@@ -0,0 +1,37 @@
+/*
+ * 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 type cast expression.
+ */
+@Getter
+@Setter
+public final class ExpectedTypeCastExpression extends AbstractExpectedSQLSegment {
+    
+    private ExpectedExpression expression;
+    
+    @XmlElement(name = "data-type")
+    private String dataType;
+}
diff --git a/test/it/parser/src/main/resources/case/dml/select-special-function.xml b/test/it/parser/src/main/resources/case/dml/select-special-function.xml
index 595b7f6c9d9..a63b6eff049 100644
--- a/test/it/parser/src/main/resources/case/dml/select-special-function.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-special-function.xml
@@ -188,7 +188,12 @@
                 <expr>
                     <function function-name="EXTRACT" start-index="7" stop-index="56" text="EXTRACT(YEAR FROM TIMESTAMP '2001-02-16 20:38:40')">
                         <parameter>
-                            <literal-expression value="2001-02-16 20:38:40" start-index="25" stop-index="55" />
+                            <type-cast-expression>
+                                <expression>
+                                    <literal-expression value="2001-02-16 20:38:40" start-index="35" stop-index="55" />
+                                </expression>
+                                <data-type>TIMESTAMP</data-type>
+                            </type-cast-expression>
                         </parameter>
                     </function>
                 </expr>
diff --git a/test/it/parser/src/main/resources/case/dml/select.xml b/test/it/parser/src/main/resources/case/dml/select.xml
index 203ff12abc0..039ccd14135 100644
--- a/test/it/parser/src/main/resources/case/dml/select.xml
+++ b/test/it/parser/src/main/resources/case/dml/select.xml
@@ -1960,15 +1960,12 @@
                                             </left>
                                             <operator>=</operator>
                                             <right>
-                                                <binary-operation-expression start-index="35" stop-index="60">
-                                                    <left>
+                                                <type-cast-expression>
+                                                    <expression>
                                                         <literal-expression value="{&quot;rule2&quot;:&quot;null2&quot;}" start-index="35" stop-index="53" />
-                                                    </left>
-                                                    <operator>::</operator>
-                                                    <right>
-                                                        <common-expression text="jsonb" start-index="56" stop-index="60" />
-                                                    </right>
-                                                </binary-operation-expression>
+                                                    </expression>
+                                                    <data-type>jsonb</data-type>
+                                                </type-cast-expression>
                                                 <parameter-marker-expression parameter-index="0" start-index="35" stop-index="42" />
                                             </right>
                                         </binary-operation-expression>
@@ -2047,27 +2044,21 @@
                                             <right>
                                                 <list-expression start-index="36" stop-index="55" literal-stop-index="91">
                                                     <items>
-                                                        <binary-operation-expression start-index="37" stop-index="62">
-                                                            <left>
+                                                        <type-cast-expression>
+                                                            <expression>
                                                                 <literal-expression value="{&quot;rule2&quot;:&quot;null2&quot;}" start-index="37" stop-index="55" />
-                                                            </left>
-                                                            <operator>::</operator>
-                                                            <right>
-                                                                <common-expression text="jsonb" start-index="58" stop-index="62" />
-                                                            </right>
-                                                        </binary-operation-expression>
+                                                            </expression>
+                                                            <data-type>jsonb</data-type>
+                                                        </type-cast-expression>
                                                         <parameter-marker-expression parameter-index="0" start-index="37" stop-index="44" />
                                                     </items>
                                                     <items>
-                                                        <binary-operation-expression start-index="65" stop-index="90">
-                                                            <left>
+                                                        <type-cast-expression>
+                                                            <expression>
                                                                 <literal-expression value="{&quot;rule3&quot;:&quot;null3&quot;}" start-index="65" stop-index="83" />
-                                                            </left>
-                                                            <operator>::</operator>
-                                                            <right>
-                                                                <common-expression text="jsonb" start-index="86" stop-index="90" />
-                                                            </right>
-                                                        </binary-operation-expression>
+                                                            </expression>
+                                                            <data-type>jsonb</data-type>
+                                                        </type-cast-expression>
                                                         <parameter-marker-expression parameter-index="1" start-index="47" stop-index="54" />
                                                     </items>
                                                 </list-expression>
@@ -2145,26 +2136,20 @@
                                     </left>
                                     <between-expr>
                                         <parameter-marker-expression parameter-index="0" start-index="41" stop-index="48" />
-                                        <binary-operation-expression start-index="41" stop-index="66">
-                                            <left>
+                                        <type-cast-expression>
+                                            <expression>
                                                 <literal-expression value="{&quot;rule2&quot;:&quot;null2&quot;}" start-index="41" stop-index="59" />
-                                            </left>
-                                            <operator>::</operator>
-                                            <right>
-                                                <common-expression text="jsonb" start-index="62" stop-index="66" />
-                                            </right>
-                                        </binary-operation-expression>
+                                            </expression>
+                                            <data-type>jsonb</data-type>
+                                        </type-cast-expression>
                                     </between-expr>
                                     <and-expr>
-                                        <binary-operation-expression start-index="72" stop-index="97">
-                                            <left>
+                                        <type-cast-expression>
+                                            <expression>
                                                 <literal-expression value="{&quot;rule3&quot;:&quot;null3&quot;}" start-index="72" stop-index="90" />
-                                            </left>
-                                            <operator>::</operator>
-                                            <right>
-                                                <common-expression text="jsonb" start-index="93" stop-index="97" />
-                                            </right>
-                                        </binary-operation-expression>
+                                            </expression>
+                                            <data-type>jsonb</data-type>
+                                        </type-cast-expression>
                                         <parameter-marker-expression parameter-index="1" start-index="54" stop-index="61" />
                                     </and-expr>
                                 </between-expression>
@@ -4845,15 +4830,14 @@
     <select sql-case-id="select_literal_type_cast_money">
         <projections start-index="7" stop-index="18">
             <expression-projection text="'$99'::money" start-index="7" stop-index="18">
-                <binary-operation-expression start-index="7" stop-index="18">
-                    <left>
-                        <literal-expression value="$99" start-index="7" stop-index="11" />
-                    </left>
-                    <operator>::</operator>
-                    <right>
-                        <common-expression text="money" start-index="14" stop-index="18" />
-                    </right>
-                </binary-operation-expression>
+                <expr>
+                    <type-cast-expression>
+                        <expression>
+                            <literal-expression value="$99" start-index="7" stop-index="11" />
+                        </expression>
+                        <data-type>money</data-type>
+                    </type-cast-expression>
+                </expr>
             </expression-projection>
         </projections>
     </select>
@@ -4861,27 +4845,74 @@
     <select sql-case-id="select_positional_parameter_type_cast_money" parameters="123.00">
         <projections start-index="7" stop-index="15">
             <expression-projection text="$1::money" start-index="7" stop-index="15">
-                <binary-operation-expression start-index="7" stop-index="15">
-                    <left>
-                        <parameter-marker-expression parameter-index="1" start-index="7" stop-index="8" />
-                    </left>
-                    <operator>::</operator>
-                    <right>
-                        <common-expression text="money" start-index="11" stop-index="15" />
-                    </right>
-                </binary-operation-expression>
+                <expr>
+                    <type-cast-expression>
+                        <expression>
+                            <parameter-marker-expression parameter-index="0" start-index="7" stop-index="8" />
+                        </expression>
+                        <data-type>money</data-type>
+                    </type-cast-expression>
+                </expr>
             </expression-projection>
         </projections>
     </select>
     
     <select sql-case-id="select_string_constant_type_cast">
         <projections start-index="7" stop-index="25">
-            <!-- TODO Fix this case after supported string const type cast syntax-->
             <expression-projection text="int4 '1'" start-index="7" stop-index="14">
-                <literal-expression value="1" start-index="7" stop-index="14" />
+                <expr>
+                    <type-cast-expression>
+                        <expression>
+                            <literal-expression value="1" start-index="12" stop-index="14" />
+                        </expression>
+                        <data-type>int4</data-type>
+                    </type-cast-expression>
+                </expr>
             </expression-projection>
             <expression-projection text="money '2'" start-index="17" stop-index="25">
-                <literal-expression value="2" start-index="17" stop-index="25" />
+                <expr>
+                    <type-cast-expression>
+                        <expression>
+                            <literal-expression value="2" start-index="23" stop-index="25" />
+                        </expression>
+                        <data-type>money</data-type>
+                    </type-cast-expression>
+                </expr>
+            </expression-projection>
+        </projections>
+    </select>
+    
+    <select sql-case-id="select_constant_with_nested_type_cast">
+        <projections start-index="7" stop-index="60">
+            <expression-projection text="CAST(MONEY '1' AS VARCHAR)::CHAR(10)::VARCHAR::CHAR(4)" start-index="7" stop-index="60">
+                <expr>
+                    <type-cast-expression>
+                        <expression>
+                            <type-cast-expression>
+                                <expression>
+                                    <type-cast-expression>
+                                        <expression>
+                                            <type-cast-expression>
+                                                <expression>
+                                                    <type-cast-expression>
+                                                        <expression>
+                                                            <literal-expression value="1" start-index="18" stop-index="20" />
+                                                        </expression>
+                                                        <data-type>MONEY</data-type>
+                                                    </type-cast-expression>
+                                                </expression>
+                                                <data-type>VARCHAR</data-type>
+                                            </type-cast-expression>
+                                        </expression>
+                                        <data-type>CHAR(10)</data-type>
+                                    </type-cast-expression>
+                                </expression>
+                                <data-type>VARCHAR</data-type>
+                            </type-cast-expression>
+                        </expression>
+                        <data-type>CHAR(4)</data-type>
+                    </type-cast-expression>
+                </expr>
             </expression-projection>
         </projections>
     </select>
diff --git a/test/it/parser/src/main/resources/sql/supported/dml/select.xml b/test/it/parser/src/main/resources/sql/supported/dml/select.xml
index 2fd1b55d9d0..973fcf2b9bf 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select.xml
@@ -159,4 +159,5 @@
     <sql-case id="select_literal_type_cast_money" value="SELECT '$99'::money" db-types="PostgreSQL,openGauss" />
     <sql-case id="select_positional_parameter_type_cast_money" value="SELECT $1::money" db-types="PostgreSQL,openGauss" case-types="Placeholder" />
     <sql-case id="select_string_constant_type_cast" value="SELECT int4 '1', money '2'" db-types="PostgreSQL,openGauss" />
+    <sql-case id="select_constant_with_nested_type_cast" value="SELECT CAST(MONEY '1' AS VARCHAR)::CHAR(10)::VARCHAR::CHAR(4)" db-types="PostgreSQL,openGauss"  />
 </sql-cases>