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 c0ce9627ef8 Support sql federation cte (#28888)
c0ce9627ef8 is described below

commit c0ce9627ef8754d09a9cfe9fcac4488db2a576ad
Author: niu niu <[email protected]>
AuthorDate: Sun Oct 29 17:07:35 2023 +0800

    Support sql federation cte (#28888)
    
    * Support mysql cte sql parse
    
    * Add mysql cte sql parse test
    
    * Refactor sql federation WithConverter
    
    * Support sql federation SelectStatement with convert
    
    * Add sql federation cte execution plan test
    
    * Format test sql
    
    * Format parse code
    
    * Change SelectStatementHandler mysql test
---
 .../converter/segment/with/WithConverter.java      |  32 +--
 .../statement/select/SelectStatementConverter.java |   8 +-
 .../resources/cases/federation-query-sql-cases.xml |  12 +
 .../visitor/statement/MySQLStatementVisitor.java   |  29 ++-
 .../handler/dml/SelectStatementHandler.java        |   6 +
 .../statement/mysql/dml/MySQLSelectStatement.java  |  12 +
 .../handler/dml/SelectStatementHandlerTest.java    |  10 +
 .../src/test/resources/converter/delete.xml        |   4 +-
 .../src/test/resources/converter/select-with.xml   |  24 ++
 .../src/main/resources/case/dml/select-with.xml    | 279 +++++++++++++++++++++
 .../resources/sql/supported/dml/select-with.xml    |   4 +
 11 files changed, 400 insertions(+), 20 deletions(-)

diff --git 
a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/with/WithConverter.java
 
b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/with/WithConverter.java
index c27b9d0949b..138a5a80ce5 100644
--- 
a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/with/WithConverter.java
+++ 
b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/segment/with/WithConverter.java
@@ -26,8 +26,9 @@ import org.apache.calcite.sql.SqlWith;
 import org.apache.calcite.sql.SqlWithItem;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonTableExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WithSegment;
-import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.expression.ExpressionConverter;
+import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.expression.impl.ColumnConverter;
 import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.statement.select.SelectStatementConverter;
 
 import java.util.Collection;
@@ -48,21 +49,20 @@ public final class WithConverter {
      * @return sql node list
      */
     public static Optional<SqlNode> convert(final WithSegment withSegment, 
final SqlNode sqlNode) {
-        SqlIdentifier name = new 
SqlIdentifier(withSegment.getCommonTableExpressions().iterator().next().getIdentifier().getValue(),
 SqlParserPos.ZERO);
-        SqlNode selectSubquery = new 
SelectStatementConverter().convert(withSegment.getCommonTableExpressions().iterator().next().getSubquery().getSelect());
-        Collection<ColumnSegment> collectionColumns = 
withSegment.getCommonTableExpressions().iterator().next().getColumns();
-        Collection<SqlNode> convertedColumns;
-        SqlNodeList columns = null;
-        if (!collectionColumns.isEmpty()) {
-            convertedColumns = 
collectionColumns.stream().map(ExpressionConverter::convert).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
-            columns = new SqlNodeList(convertedColumns, SqlParserPos.ZERO);
-        }
-        SqlWithItem sqlWithItem = new SqlWithItem(SqlParserPos.ZERO, name, 
columns, selectSubquery);
-        SqlNodeList sqlWithItems = new SqlNodeList(SqlParserPos.ZERO);
-        sqlWithItems.add(sqlWithItem);
-        SqlWith sqlWith = new SqlWith(SqlParserPos.ZERO, sqlWithItems, 
sqlNode);
+        return Optional.of(new SqlWith(SqlParserPos.ZERO, 
convertWithItem(withSegment.getCommonTableExpressions()), sqlNode));
+    }
+    
+    private static SqlNodeList convertWithItem(final 
Collection<CommonTableExpressionSegment> commonTableExpressionSegments) {
         SqlNodeList result = new SqlNodeList(SqlParserPos.ZERO);
-        result.add(sqlWith);
-        return Optional.of(result);
+        for (CommonTableExpressionSegment each : 
commonTableExpressionSegments) {
+            SqlIdentifier name = new 
SqlIdentifier(each.getIdentifier().getValue(), SqlParserPos.ZERO);
+            SqlNodeList columns = each.getColumns().isEmpty() ? null : 
convertColumns(each.getColumns());
+            result.add(new SqlWithItem(SqlParserPos.ZERO, name, columns, new 
SelectStatementConverter().convert(each.getSubquery().getSelect())));
+        }
+        return result;
+    }
+    
+    private static SqlNodeList convertColumns(final Collection<ColumnSegment> 
columnSegments) {
+        return new SqlNodeList(columnSegments.stream().map(each -> 
ColumnConverter.convert(each).orElseThrow(IllegalStateException::new)).collect(Collectors.toList()),
 SqlParserPos.ZERO);
     }
 }
diff --git 
a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/statement/select/SelectStatementConverter.java
 
b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/statement/select/SelectStatementConverter.java
index a96dc7428e8..a975d0a0232 100644
--- 
a/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/statement/select/SelectStatementConverter.java
+++ 
b/kernel/sql-federation/optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/converter/statement/select/SelectStatementConverter.java
@@ -36,6 +36,7 @@ import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.proje
 import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.projection.ProjectionsConverter;
 import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.where.WhereConverter;
 import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.window.WindowConverter;
+import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.segment.with.WithConverter;
 import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.statement.SQLStatementConverter;
 import 
org.apache.shardingsphere.sqlfederation.optimizer.converter.type.CombineOperatorConverter;
 
@@ -50,7 +51,8 @@ public final class SelectStatementConverter implements 
SQLStatementConverter<Sel
     @Override
     public SqlNode convert(final SelectStatement selectStatement) {
         SqlSelect sqlSelect = convertSelect(selectStatement);
-        SqlNode sqlCombine = convertCombine(sqlSelect, selectStatement);
+        SqlNode sqlWith = convertWith(sqlSelect, selectStatement);
+        SqlNode sqlCombine = convertCombine(null != sqlWith ? sqlWith : 
sqlSelect, selectStatement);
         SqlNodeList orderBy = 
selectStatement.getOrderBy().flatMap(OrderByConverter::convert).orElse(SqlNodeList.EMPTY);
         Optional<LimitSegment> limit = 
SelectStatementHandler.getLimitSegment(selectStatement);
         if (limit.isPresent()) {
@@ -61,6 +63,10 @@ public final class SelectStatementConverter implements 
SQLStatementConverter<Sel
         return orderBy.isEmpty() ? sqlCombine : new 
SqlOrderBy(SqlParserPos.ZERO, sqlCombine, orderBy, null, null);
     }
     
+    private SqlNode convertWith(final SqlNode sqlSelect, final SelectStatement 
selectStatement) {
+        return 
SelectStatementHandler.getWithSegment(selectStatement).flatMap(segment -> 
WithConverter.convert(segment, sqlSelect)).orElse(null);
+    }
+    
     private SqlSelect convertSelect(final SelectStatement selectStatement) {
         SqlNodeList distinct = 
DistinctConverter.convert(selectStatement.getProjections()).orElse(null);
         SqlNodeList projection = 
ProjectionsConverter.convert(selectStatement.getProjections()).orElseThrow(IllegalStateException::new);
diff --git 
a/kernel/sql-federation/optimizer/src/test/resources/cases/federation-query-sql-cases.xml
 
b/kernel/sql-federation/optimizer/src/test/resources/cases/federation-query-sql-cases.xml
index 0584a210361..fbfc970006c 100644
--- 
a/kernel/sql-federation/optimizer/src/test/resources/cases/federation-query-sql-cases.xml
+++ 
b/kernel/sql-federation/optimizer/src/test/resources/cases/federation-query-sql-cases.xml
@@ -436,4 +436,16 @@
     <test-case sql="SELECT * FROM multi_types_first first JOIN 
multi_types_second second ON first.id = second.id WHERE 
second.long_varchar_column = '1'">
         <assertion expected-result="EnumerableHashJoin(condition=[=($0, $22)], 
joinType=[inner])   EnumerableScan(table=[[federate_jdbc, multi_types_first]], 
sql=[SELECT * FROM `federate_jdbc`.`multi_types_first`], 
dynamicParameters=[null])   EnumerableScan(table=[[federate_jdbc, 
multi_types_second]], sql=[SELECT * FROM `federate_jdbc`.`multi_types_second` 
WHERE `long_varchar_column` = '1'], dynamicParameters=[null]) " />
     </test-case>
+    
+    <test-case sql="WITH cte AS (SELECT 1 AS col1, 2 AS col2 UNION ALL SELECT 
3, 4) SELECT col1, col2 FROM cte">
+        <assertion expected-result="EnumerableUnion(all=[true])   
EnumerableValues(tuples=[[{ 1, 2 }]])   EnumerableValues(tuples=[[{ 3, 4 }]]) " 
/>
+    </test-case>
+    
+    <test-case sql="WITH cte1(col1, col2, col3) AS (SELECT id, bit_column, 
tiny_int_column FROM multi_types_first), cte2(col1, col2, col3) AS (SELECT id, 
bit_column, tiny_int_column FROM multi_types_second) SELECT * FROM cte1 inner 
join cte2 on cte1.col1 = cte2.col1">
+        <assertion expected-result="EnumerableHashJoin(condition=[=($0, $3)], 
joinType=[inner])   EnumerableScan(table=[[federate_jdbc, multi_types_first]], 
sql=[SELECT `id`, `bit_column`, `tiny_int_column` FROM 
`federate_jdbc`.`multi_types_first`], dynamicParameters=[null])   
EnumerableScan(table=[[federate_jdbc, multi_types_second]], sql=[SELECT `id`, 
`bit_column`, `tiny_int_column` FROM `federate_jdbc`.`multi_types_second`], 
dynamicParameters=[null]) " />
+    </test-case>
+    
+    <test-case sql="WITH cte1(col1, col2, col3) AS (SELECT 1, 2, 3 UNION ALL 
SELECT 4, 5, 6), cte2(col1, col2, col3) AS (SELECT 1, 2, 3 UNION ALL SELECT 4, 
5, 6) SELECT cte1.* FROM cte1 inner join cte2 on cte1.col1 = cte2.col1 WHERE 
cte1.col1 = 1">
+        <assertion expected-result="EnumerableCalc(expr#0..3=[{inputs}], 
proj#0..2=[{exprs}])   EnumerableHashJoin(condition=[=($0, $3)], 
joinType=[inner])     EnumerableUnion(all=[true])       
EnumerableCalc(expr#0..2=[{inputs}], expr#3=[1], expr#4=[=($t0, $t3)], 
proj#0..2=[{exprs}], $condition=[$t4])         EnumerableValues(tuples=[[{ 1, 
2, 3 }]])       EnumerableCalc(expr#0..2=[{inputs}], expr#3=[1], expr#4=[=($t0, 
$t3)], proj#0..2=[{exprs}], $condition=[$t4])         EnumerableValue [...]
+    </test-case>
 </test-cases>
diff --git 
a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
 
b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
index 9789712de37..821b8c117dc 100644
--- 
a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
+++ 
b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
@@ -49,6 +49,7 @@ import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.Complet
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ConstraintNameContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ConvertFunctionContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CurrentUserFunctionContext;
+import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CteClauseContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DataTypeContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DeleteContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DuplicateSpecificationContext;
@@ -147,6 +148,7 @@ import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowC
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowFunctionContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowItemContext;
 import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WindowSpecificationContext;
+import 
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WithClauseContext;
 import org.apache.shardingsphere.sql.parser.sql.common.enums.AggregationType;
 import org.apache.shardingsphere.sql.parser.sql.common.enums.CombineType;
 import org.apache.shardingsphere.sql.parser.sql.common.enums.JoinType;
@@ -181,6 +183,7 @@ import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.RowExpre
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.UnaryOperationExpression;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ValuesExpression;
 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.CommonTableExpressionSegment;
 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;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.SimpleExpressionSegment;
@@ -220,6 +223,7 @@ import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.Sim
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SubqueryTableSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WithSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.util.SQLUtils;
 import 
org.apache.shardingsphere.sql.parser.sql.common.value.collection.CollectionValue;
 import 
org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
@@ -712,6 +716,9 @@ public abstract class MySQLStatementVisitor extends 
MySQLStatementBaseVisitor<AS
         if (null != ctx.limitClause()) {
             result.setLimit((LimitSegment) visit(ctx.limitClause()));
         }
+        if (null != result && null != ctx.withClause()) {
+            result.setWithSegment((WithSegment) visit(ctx.withClause()));
+        }
         return result;
     }
     
@@ -727,6 +734,27 @@ public abstract class MySQLStatementVisitor extends 
MySQLStatementBaseVisitor<AS
         return result;
     }
     
+    @Override
+    public ASTNode visitWithClause(final WithClauseContext ctx) {
+        Collection<CommonTableExpressionSegment> commonTableExpressions = new 
LinkedList<>();
+        for (CteClauseContext each : ctx.cteClause()) {
+            commonTableExpressions.add((CommonTableExpressionSegment) 
visit(each));
+        }
+        return new WithSegment(ctx.start.getStartIndex(), 
ctx.stop.getStopIndex(), commonTableExpressions);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public ASTNode visitCteClause(final CteClauseContext ctx) {
+        CommonTableExpressionSegment result = new 
CommonTableExpressionSegment(ctx.getStart().getStartIndex(), 
ctx.getStop().getStopIndex(), (IdentifierValue) visit(ctx.identifier()),
+                new SubquerySegment(ctx.getStart().getStartIndex(), 
ctx.getStop().getStopIndex(), (MySQLSelectStatement) visit(ctx.subquery()), 
getOriginalText(ctx.subquery())));
+        if (null != ctx.columnNames()) {
+            CollectionValue<ColumnSegment> columns = 
(CollectionValue<ColumnSegment>) visit(ctx.columnNames());
+            result.getColumns().addAll(columns.getValue());
+        }
+        return result;
+    }
+    
     @Override
     public ASTNode visitQueryExpressionBody(final QueryExpressionBodyContext 
ctx) {
         if (1 == ctx.getChildCount() && ctx.getChild(0) instanceof 
QueryPrimaryContext) {
@@ -1592,7 +1620,6 @@ public abstract class MySQLStatementVisitor extends 
MySQLStatementBaseVisitor<AS
     
     @Override
     public ASTNode visitSelect(final SelectContext ctx) {
-        // TODO :Unsupported for withClause.
         MySQLSelectStatement result;
         if (null != ctx.queryExpression()) {
             result = (MySQLSelectStatement) visit(ctx.queryExpression());
diff --git 
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/handler/dml/SelectStatementHandler.java
 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/handler/dml/SelectStatementHandler.java
index daeeaeffcde..db1a92b0866 100644
--- 
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/handler/dml/SelectStatementHandler.java
+++ 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/handler/dml/SelectStatementHandler.java
@@ -183,6 +183,9 @@ public final class SelectStatementHandler implements 
SQLStatementHandler {
         if (selectStatement instanceof SQLServerSelectStatement) {
             return ((SQLServerSelectStatement) 
selectStatement).getWithSegment();
         }
+        if (selectStatement instanceof MySQLSelectStatement) {
+            return ((MySQLSelectStatement) selectStatement).getWithSegment();
+        }
         return Optional.empty();
     }
     
@@ -199,6 +202,9 @@ public final class SelectStatementHandler implements 
SQLStatementHandler {
         if (selectStatement instanceof SQLServerSelectStatement) {
             ((SQLServerSelectStatement) 
selectStatement).setWithSegment(withSegment);
         }
+        if (selectStatement instanceof MySQLSelectStatement) {
+            ((MySQLSelectStatement) 
selectStatement).setWithSegment(withSegment);
+        }
     }
     
     /**
diff --git 
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/mysql/dml/MySQLSelectStatement.java
 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/mysql/dml/MySQLSelectStatement.java
index 018bd27736b..f6d35886c5b 100644
--- 
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/mysql/dml/MySQLSelectStatement.java
+++ 
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/mysql/dml/MySQLSelectStatement.java
@@ -21,6 +21,7 @@ import lombok.Setter;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.LimitSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.LockSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WindowSegment;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WithSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.MySQLStatement;
@@ -41,6 +42,8 @@ public final class MySQLSelectStatement extends 
SelectStatement implements MySQL
     
     private WindowSegment window;
     
+    private WithSegment withSegment;
+    
     /**
      * Get order by segment.
      *
@@ -76,4 +79,13 @@ public final class MySQLSelectStatement extends 
SelectStatement implements MySQL
     public Optional<SimpleTableSegment> getTable() {
         return Optional.ofNullable(table);
     }
+    
+    /**
+     * Get with segment.
+     *
+     * @return with segment.
+     */
+    public Optional<WithSegment> getWithSegment() {
+        return Optional.ofNullable(withSegment);
+    }
 }
diff --git 
a/parser/sql/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/dialect/handler/dml/SelectStatementHandlerTest.java
 
b/parser/sql/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/dialect/handler/dml/SelectStatementHandlerTest.java
index 2b8abdc2f74..f4b3ff013d0 100644
--- 
a/parser/sql/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/dialect/handler/dml/SelectStatementHandlerTest.java
+++ 
b/parser/sql/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/dialect/handler/dml/SelectStatementHandlerTest.java
@@ -187,6 +187,16 @@ class SelectStatementHandlerTest {
         assertFalse(SelectStatementHandler.getWithSegment(new 
OracleSelectStatement()).isPresent());
     }
     
+    @Test
+    void assertGetWithSegmentForMysql() {
+        MySQLSelectStatement selectStatement = new MySQLSelectStatement();
+        selectStatement.setWithSegment(new WithSegment(0, 2, new 
LinkedList<>()));
+        Optional<WithSegment> withSegment = 
SelectStatementHandler.getWithSegment(selectStatement);
+        assertTrue(withSegment.isPresent());
+        assertThat(withSegment.get(), 
is(selectStatement.getWithSegment().get()));
+        assertFalse(SelectStatementHandler.getWithSegment(new 
MySQLSelectStatement()).isPresent());
+    }
+    
     @Test
     void assertGetWithSegmentForSQLServer() {
         SQLServerSelectStatement selectStatement = new 
SQLServerSelectStatement();
diff --git a/test/it/optimizer/src/test/resources/converter/delete.xml 
b/test/it/optimizer/src/test/resources/converter/delete.xml
index 1f320631d0b..331174393e6 100644
--- a/test/it/optimizer/src/test/resources/converter/delete.xml
+++ b/test/it/optimizer/src/test/resources/converter/delete.xml
@@ -40,6 +40,6 @@
     <test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM 
[t_order] AS [o] AS [o] WHERE [status] = 'init'" db-types="SQLServer" 
sql-case-types="LITERAL" />
     <test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM 
`t_order` AS `o` AS `o` WHERE `status` = ?" db-types="MySQL" 
sql-case-types="PLACEHOLDER" />
     <test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM 
[t_order] AS [o] AS [o] WHERE [status] = ?" db-types="SQLServer" 
sql-case-types="PLACEHOLDER" />
-    <test-cases sql-case-id="delete_with_with_clause" expected-sql="(WITH 
[cte] ([order_id], [user_id]) AS (SELECT [order_id], [user_id] FROM [t_order]) 
DELETE FROM ([cte], [t_order]) WHERE [t_order].[order_id] = [cte].[order_id])" 
db-types="SQLServer" />
-    <test-cases sql-case-id="delete_without_columns_with_with_clause" 
expected-sql="(WITH [cte] AS (SELECT [order_id], [user_id] FROM [t_order]) 
DELETE FROM ([cte], [t_order]) WHERE [t_order].[order_id] = [cte].[order_id])" 
db-types="SQLServer" />
+    <test-cases sql-case-id="delete_with_with_clause" expected-sql="WITH [cte] 
([order_id], [user_id]) AS (SELECT [order_id], [user_id] FROM [t_order]) DELETE 
FROM ([cte], [t_order]) WHERE [t_order].[order_id] = [cte].[order_id]" 
db-types="SQLServer" />
+    <test-cases sql-case-id="delete_without_columns_with_with_clause" 
expected-sql="WITH [cte] AS (SELECT [order_id], [user_id] FROM [t_order]) 
DELETE FROM ([cte], [t_order]) WHERE [t_order].[order_id] = [cte].[order_id]" 
db-types="SQLServer" />
 </sql-node-converter-test-cases>
diff --git a/test/it/optimizer/src/test/resources/converter/select-with.xml 
b/test/it/optimizer/src/test/resources/converter/select-with.xml
new file mode 100644
index 00000000000..646c41e1793
--- /dev/null
+++ b/test/it/optimizer/src/test/resources/converter/select-with.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<sql-node-converter-test-cases>
+    <test-cases sql-case-id="select_with_single_subquery" expected-sql="WITH 
`t` AS (SELECT `a` + 2 AS `c`, `b` FROM `t1`) SELECT `c`, `b` FROM `t`" 
db-types="MySQL" />
+    <test-cases sql-case-id="select_with_multiple_subquery" expected-sql="WITH 
`cte1` (`col1`, `col2`, `col3`) AS (SELECT `emp_no`, `first_name`, `last_name` 
FROM `employees` WHERE `emp_no` = 10012), `cte2` (`col1`, `col2`, `col3`) AS 
(SELECT `emp_no`, `first_name`, `last_name` FROM `employees` WHERE `emp_no` = 
10012) SELECT `col1`, `col2`, `col3` FROM `cte1`" db-types="MySQL" />
+    <test-cases sql-case-id="select_with_recursive_union_all1" 
expected-sql="WITH `DirectoryCTE` AS (SELECT * FROM `table1` WHERE `id` = 1 AND 
`project_id` = 2 UNION ALL SELECT * FROM `project_file_catalog` AS `t` INNER 
JOIN `DirectoryCTE` AS `cte` ON `t`.`project_id` = `cte`.`project_id` AND 
`t`.`parent_id` = `cte`.`id`) SELECT * FROM `DirectoryCTE` ORDER BY `level`" 
db-types="MySQL" />
+    <test-cases sql-case-id="select_with_recursive_union_all2" 
expected-sql="WITH `cte` AS (SELECT 1 AS `col1`, 2 AS `col2` UNION ALL SELECT 
3, 4) SELECT `col1`, `col2` FROM `cte`" db-types="MySQL" />
+</sql-node-converter-test-cases>
diff --git a/test/it/parser/src/main/resources/case/dml/select-with.xml 
b/test/it/parser/src/main/resources/case/dml/select-with.xml
index 1d579c10569..fb1b2021e4a 100644
--- a/test/it/parser/src/main/resources/case/dml/select-with.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-with.xml
@@ -364,4 +364,283 @@
             <column-projection name="item_id" start-index="145" 
stop-index="151" />
         </projections>
     </select>
+    
+    <select sql-case-id="select_with_single_subquery">
+        <with start-index="0" stop-index="33">
+            <common-table-expression name="t" start-index="5" stop-index="33">
+                <subquery-expression start-index="5" stop-index="33">
+                    <select>
+                        <from>
+                            <simple-table name="t1" start-index="31" 
stop-index="32" />
+                        </from>
+                        <projections start-index="18" stop-index="24">
+                            <expression-projection text="a+2" alias="c" 
start-index="18" stop-index="22">
+                                <expr>
+                                    <binary-operation-expression 
start-index="18" stop-index="20">
+                                        <left>
+                                            <column name="a" start-index="18" 
stop-index="18" />
+                                        </left>
+                                        <operator>+</operator>
+                                        <right>
+                                            <literal-expression value="2" 
start-index="20" stop-index="20" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </expr>
+                            </expression-projection>
+                            <column-projection name="b" start-index="24" 
stop-index="24" />
+                        </projections>
+                    </select>
+                </subquery-expression>
+            </common-table-expression>
+        </with>
+        <projections start-index="42" stop-index="44">
+            <column-projection name="c" start-index="42" stop-index="42" />
+            <column-projection name="b" start-index="44" stop-index="44" />
+        </projections>
+        <from>
+            <simple-table name="t" start-index="51" stop-index="51" />
+        </from>
+    </select>
+    
+    <select sql-case-id="select_with_multiple_subquery">
+        <with start-index="0" stop-index="198">
+            <common-table-expression name="cte1" start-index="5" 
stop-index="100">
+                <subquery-expression start-index="5" stop-index="100">
+                    <select>
+                        <from>
+                            <simple-table name="employees" start-index="72" 
stop-index="80" />
+                        </from>
+                        <projections start-index="39" stop-index="65">
+                            <column-projection name="emp_no" start-index="39" 
stop-index="44" />
+                            <column-projection name="first_name" 
start-index="46" stop-index="55" />
+                            <column-projection name="last_name" 
start-index="57" stop-index="65" />
+                        </projections>
+                        <where start-index="82" stop-index="99">
+                            <expr>
+                                <binary-operation-expression start-index="88" 
stop-index="99">
+                                    <left>
+                                        <column name="emp_no" start-index="88" 
stop-index="93" />
+                                    </left>
+                                    <operator>=</operator>
+                                    <right>
+                                        <literal-expression value="10012" 
start-index="95" stop-index="99" />
+                                    </right>
+                                </binary-operation-expression>
+                            </expr>
+                        </where>
+                    </select>
+                </subquery-expression>
+                <column name="col1" start-index="10" stop-index="13" />
+                <column name="col2" start-index="16" stop-index="19" />
+                <column name="col3" start-index="22" stop-index="25" />
+            </common-table-expression>
+            <common-table-expression name="cte2" start-index="103" 
stop-index="198">
+                <subquery-expression start-index="103" stop-index="198">
+                    <select>
+                        <from>
+                            <simple-table name="employees" start-index="170" 
stop-index="178" />
+                        </from>
+                        <projections start-index="137" stop-index="163">
+                            <column-projection name="emp_no" start-index="137" 
stop-index="142" />
+                            <column-projection name="first_name" 
start-index="144" stop-index="153" />
+                            <column-projection name="last_name" 
start-index="155" stop-index="163" />
+                        </projections>
+                        <where start-index="180" stop-index="197">
+                            <expr>
+                                <binary-operation-expression start-index="186" 
stop-index="197">
+                                    <left>
+                                        <column name="emp_no" 
start-index="186" stop-index="191" />
+                                    </left>
+                                    <operator>=</operator>
+                                    <right>
+                                        <literal-expression value="10012" 
start-index="193" stop-index="197" />
+                                    </right>
+                                </binary-operation-expression>
+                            </expr>
+                        </where>
+                    </select>
+                </subquery-expression>
+                <column name="col1" start-index="108" stop-index="111" />
+                <column name="col2" start-index="114" stop-index="117" />
+                <column name="col3" start-index="120" stop-index="123" />
+            </common-table-expression>
+        </with>
+        <projections start-index="207" stop-index="222">
+            <column-projection name="col1" start-index="207" stop-index="210" 
/>
+            <column-projection name="col2" start-index="213" stop-index="216" 
/>
+            <column-projection name="col3" start-index="219" stop-index="222" 
/>
+        </projections>
+        <from>
+            <simple-table name="cte1" start-index="229" stop-index="232" />
+        </from>
+    </select>
+    
+    <select sql-case-id="select_with_recursive_union_all1">
+        <with start-index="0" stop-index="217">
+            <common-table-expression name="DirectoryCTE" start-index="15" 
stop-index="217">
+                <subquery-expression start-index="15" stop-index="217">
+                    <select>
+                        <from>
+                            <simple-table name="table1" start-index="46" 
stop-index="51" />
+                        </from>
+                        <projections start-index="39" stop-index="39">
+                            <shorthand-projection start-index="39" 
stop-index="39" />
+                        </projections>
+                        <combine combine-type="UNION_ALL" start-index="85" 
stop-index="216">
+                            <left>
+                                <projections start-index="39" stop-index="39">
+                                    <shorthand-projection start-index="39" 
stop-index="39" />
+                                </projections>
+                                <from>
+                                    <simple-table name="table1" 
start-index="46" stop-index="51" />
+                                </from>
+                                <where start-index="53" stop-index="83">
+                                    <expr>
+                                        <binary-operation-expression 
start-index="59" stop-index="83">
+                                            <left>
+                                                <binary-operation-expression 
start-index="59" stop-index="64">
+                                                    <left>
+                                                        <column name="id" 
start-index="59" stop-index="60" />
+                                                    </left>
+                                                    <operator>=</operator>
+                                                    <right>
+                                                        <literal-expression 
value="1" start-index="64" stop-index="64" />
+                                                    </right>
+                                                </binary-operation-expression>
+                                            </left>
+                                            <operator>AND</operator>
+                                            <right>
+                                                <binary-operation-expression 
start-index="70" stop-index="83">
+                                                    <left>
+                                                        <column 
name="project_id" start-index="70" stop-index="79" />
+                                                    </left>
+                                                    <operator>=</operator>
+                                                    <right>
+                                                        <literal-expression 
value="2" start-index="83" stop-index="83" />
+                                                    </right>
+                                                </binary-operation-expression>
+                                            </right>
+                                        </binary-operation-expression>
+                                    </expr>
+                                </where>
+                            </left>
+                            <right>
+                                <from>
+                                    <join-table join-type="INNER">
+                                        <left>
+                                            <simple-table 
name="project_file_catalog" alias="t" start-index="109" stop-index="130" />
+                                        </left>
+                                        <right>
+                                            <simple-table name="DirectoryCTE" 
alias="cte" start-index="143" stop-index="158" />
+                                        </right>
+                                        <on-condition>
+                                            <binary-operation-expression 
start-index="163" stop-index="216">
+                                                <left>
+                                                    
<binary-operation-expression start-index="163" stop-index="191">
+                                                        <left>
+                                                            <column 
name="project_id" start-index="163" stop-index="174">
+                                                                <owner 
name="t" start-index="163" stop-index="163" />
+                                                            </column>
+                                                        </left>
+                                                        <right>
+                                                            <column 
name="project_id" start-index="178" stop-index="191">
+                                                                <owner 
name="cte" start-index="178" stop-index="180" />
+                                                            </column>
+                                                        </right>
+                                                        <operator>=</operator>
+                                                    
</binary-operation-expression>
+                                                </left>
+                                                <operator>AND</operator>
+                                                <right>
+                                                    
<binary-operation-expression start-index="197" stop-index="216">
+                                                        <left>
+                                                            <column 
name="parent_id" start-index="197" stop-index="207">
+                                                                <owner 
name="t" start-index="197" stop-index="197" />
+                                                            </column>
+                                                        </left>
+                                                        <operator>=</operator>
+                                                        <right>
+                                                            <column name="id" 
start-index="211" stop-index="216">
+                                                                <owner 
name="cte" start-index="211" stop-index="213" />
+                                                            </column>
+                                                        </right>
+                                                    
</binary-operation-expression>
+                                                </right>
+                                            </binary-operation-expression>
+                                        </on-condition>
+                                    </join-table>
+                                </from>
+                                <projections start-index="102" 
stop-index="102">
+                                    <shorthand-projection start-index="102" 
stop-index="102" />
+                                </projections>
+                            </right>
+                        </combine>
+                    </select>
+                </subquery-expression>
+            </common-table-expression>
+        </with>
+        <projections start-index="226" stop-index="226">
+            <shorthand-projection start-index="226" stop-index="226" />
+        </projections>
+        <from>
+            <simple-table name="DirectoryCTE" start-index="233" 
stop-index="244" />
+        </from>
+        <order-by>
+            <column-item name="level" order-direction="ASC" start-index="255" 
stop-index="259" />
+        </order-by>
+    </select>
+    
+    <select sql-case-id="select_with_recursive_union_all2">
+        <with start-index="0" stop-index="62">
+            <common-table-expression name="cte" start-index="5" 
stop-index="62">
+                <subquery-expression start-index="5" stop-index="62">
+                    <select>
+                        <projections start-index="20" stop-index="39">
+                            <expression-projection text="1" alias="col1" 
start-index="20" stop-index="28">
+                                <expr>
+                                    <literal-expression value="1" 
start-index="20" stop-index="20" />
+                                </expr>
+                            </expression-projection>
+                            <expression-projection text="2" alias="col2" 
start-index="31" stop-index="39">
+                                <literal-expression value="2" start-index="31" 
stop-index="31" />
+                            </expression-projection>
+                        </projections>
+                        <combine combine-type="UNION_ALL" start-index="41" 
stop-index="61">
+                            <left>
+                                <projections start-index="20" stop-index="39">
+                                    <expression-projection text="1" 
alias="col1" start-index="20" stop-index="28">
+                                        <expr>
+                                            <literal-expression value="1" 
start-index="20" stop-index="20" />
+                                        </expr>
+                                    </expression-projection>
+                                    <expression-projection text="2" 
alias="col2" start-index="31" stop-index="39">
+                                        <literal-expression value="2" 
start-index="31" stop-index="31" />
+                                    </expression-projection>
+                                </projections>
+                            </left>
+                            <right>
+                                <projections start-index="58" stop-index="61">
+                                    <expression-projection text="3" 
start-index="58" stop-index="58">
+                                        <expr>
+                                            <literal-expression value="3" 
start-index="58" stop-index="58" />
+                                        </expr>
+                                    </expression-projection>
+                                    <expression-projection text="4" 
start-index="61" stop-index="61">
+                                        <literal-expression value="4" 
start-index="61" stop-index="61" />
+                                    </expression-projection>
+                                </projections>
+                            </right>
+                        </combine>
+                    </select>
+                </subquery-expression>
+            </common-table-expression>
+        </with>
+        <projections start-index="71" stop-index="80">
+            <column-projection name="col1" start-index="71" stop-index="74" />
+            <column-projection name="col2" start-index="77" stop-index="80" />
+        </projections>
+        <from>
+            <simple-table name="cte" start-index="87" stop-index="89" />
+        </from>
+    </select>
 </sql-parser-test-cases>
diff --git 
a/test/it/parser/src/main/resources/sql/supported/dml/select-with.xml 
b/test/it/parser/src/main/resources/sql/supported/dml/select-with.xml
index 75a1f7cdd3e..d6d7e917c3a 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select-with.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select-with.xml
@@ -23,4 +23,8 @@
     <sql-case 
id="select_with_subquery_factoring_with_search_depth_first_with_cycle" 
value="WITH dup_hiredate (eid, emp_last, mgr_id, reportLevel, hire_date, 
job_id) AS (SELECT employee_id, last_name, manager_id, reportLevel, hire_date, 
job_id FROM employees WHERE manager_id IS NULL) SEARCH DEPTH FIRST BY hire_date 
SET order1 CYCLE hire_date SET is_cycle TO 'Y' DEFAULT 'N' SELECT lpad(' 
',2*reportLevel)||emp_last emp_name, eid, mgr_id, hire_date, job_id, is_cycle 
FROM dup_hiredate ORDER  [...]
     <sql-case 
id="select_with_subquery_factoring_with_search_depth_first_with_having" 
value="WITH emp_count (eid, emp_last, mgr_id, mgrLevel, salary, cnt_employees) 
AS (SELECT employee_id, last_name, manager_id, mgrLevel, salary, cnt_employees 
FROM employees) SEARCH DEPTH FIRST BY emp_last SET order1 SELECT emp_last, eid, 
mgr_id, salary FROM emp_count GROUP BY emp_last, eid, mgr_id, salary HAVING 
salary > 24000 ORDER BY mgr_id NULLS FIRST, emp_last" db-types="Oracle" />
     <sql-case id="select_with_multiple_cte_definitions" value="WITH 
cte1(status, user_id) AS (SELECT status, user_id FROM t_order), cte2(item_id) 
AS (SELECT item_id FROM t_order_item) SELECT status, user_id, item_id FROM cte1 
INNER JOIN cte2 ON cte1.user_id = cte2.user_id" db-types="SQLServer" />
+    <sql-case id="select_with_single_subquery" value="WITH t AS (SELECT a+2 
c,b FROM t1) SELECT c,b FROM t" db-types="MySQL" />
+    <sql-case id="select_with_multiple_subquery" value="WITH cte1(col1, col2, 
col3) as (SELECT emp_no,first_name,last_name FROM employees WHERE 
emp_no=10012), cte2(col1, col2, col3) as (SELECT emp_no,first_name,last_name 
from employees WHERE emp_no=10012) SELECT col1, col2, col3 FROM cte1" 
db-types="MySQL" />
+    <sql-case id="select_with_recursive_union_all1" value="WITH RECURSIVE 
DirectoryCTE as (SELECT * FROM table1 WHERE id = 1 AND project_id = 2 UNION ALL 
SELECT * FROM project_file_catalog t INNER JOIN DirectoryCTE cte ON 
t.project_id = cte.project_id AND t.parent_id = cte.id) SELECT * FROM 
DirectoryCTE ORDER BY level" db-types="MySQL" />
+    <sql-case id="select_with_recursive_union_all2" value="WITH cte AS (SELECT 
1 AS col1, 2 AS col2 UNION ALL SELECT 3, 4) SELECT col1, col2 FROM cte" 
db-types="MySQL" />
 </sql-cases>


Reply via email to