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 56117f45091 Support select with statement sql bind and add bind test 
case (#34141)
56117f45091 is described below

commit 56117f45091aefdb26dec82a96c039c462d8f9bb
Author: Zhengqiang Duan <duanzhengqi...@apache.org>
AuthorDate: Wed Dec 25 07:42:30 2024 +0800

    Support select with statement sql bind and add bind test case (#34141)
    
    * Remove TablesContext#findTableNames method and use sql bind info to 
replace
    
    * fix unit test
    
    * optimize select statement binder
    
    * update release note
    
    * Support select with statement sql bind and add bind test case
    
    * update release note
    
    * fix build error
---
 RELEASE-NOTES.md                                   |   1 +
 .../sql/EncryptSupportedSQLCheckersBuilder.java    |   4 +-
 .../from/type/SimpleTableSegmentBinder.java        |   7 +
 .../with/CommonTableExpressionSegmentBinder.java   |  62 +++++++
 .../engine/segment/with/WithSegmentBinder.java     | 125 +++++++++++++
 .../statement/dml/SelectStatementBinder.java       |   4 +-
 .../statement/dml/UpdateStatementBinder.java       |   3 +-
 .../binder/src/test/resources/cases/dml/select.xml | 206 +++++++++++++++++++++
 .../binder/src/test/resources/sqls/dml/select.xml  |   2 +
 .../asserts/segment/orderby/OrderByItemAssert.java |   2 +
 .../item/impl/ExpectedColumnOrderByItem.java       |   4 +
 11 files changed, 415 insertions(+), 5 deletions(-)

diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 318dd2e0892..37fad67b255 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -38,6 +38,7 @@
 1. SQL Binder: Support create index statement sql bind - 
[#34112](https://github.com/apache/shardingsphere/pull/34112)
 1. SQL Parser: Support MySQL update with statement parse - 
[#34126](https://github.com/apache/shardingsphere/pull/34126)
 1. SQL Binder: Remove TablesContext#findTableNames method and implement select 
order by, group by bind logic - 
[#34123](https://github.com/apache/shardingsphere/pull/34123)
+1. SQL Binder: Support select with statement sql bind and add bind test case - 
[#34141](https://github.com/apache/shardingsphere/pull/34141)
 
 ### Bug Fixes
 
diff --git 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java
 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java
index 7a661c2e926..fce03c66f10 100644
--- 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java
+++ 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java
@@ -17,10 +17,10 @@
 
 package org.apache.shardingsphere.encrypt.checker.sql;
 
-import 
org.apache.shardingsphere.encrypt.checker.sql.projection.EncryptInsertSelectProjectionSupportedChecker;
-import 
org.apache.shardingsphere.encrypt.checker.sql.projection.EncryptSelectProjectionSupportedChecker;
 import 
org.apache.shardingsphere.encrypt.checker.sql.orderby.EncryptOrderByItemSupportedChecker;
 import 
org.apache.shardingsphere.encrypt.checker.sql.predicate.EncryptPredicateColumnSupportedChecker;
+import 
org.apache.shardingsphere.encrypt.checker.sql.projection.EncryptInsertSelectProjectionSupportedChecker;
+import 
org.apache.shardingsphere.encrypt.checker.sql.projection.EncryptSelectProjectionSupportedChecker;
 import org.apache.shardingsphere.encrypt.constant.EncryptOrder;
 import org.apache.shardingsphere.encrypt.rule.EncryptRule;
 import org.apache.shardingsphere.infra.checker.SupportedSQLChecker;
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinder.java
index eb57d97f828..d471cb8cf01 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinder.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinder.java
@@ -24,6 +24,7 @@ import lombok.NoArgsConstructor;
 import 
org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import 
org.apache.shardingsphere.infra.binder.engine.segment.from.context.type.SimpleTableSegmentBinderContext;
 import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
+import 
org.apache.shardingsphere.infra.binder.engine.util.SubqueryTableBindUtils;
 import 
org.apache.shardingsphere.infra.database.core.metadata.database.DialectDatabaseMetaData;
 import 
org.apache.shardingsphere.infra.database.core.metadata.database.enums.QuoteCharacter;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
@@ -150,6 +151,12 @@ public final class SimpleTableSegmentBinder {
         if (binderContext.getSqlStatement() instanceof CreateTableStatement) {
             return new 
SimpleTableSegmentBinderContext(createProjectionSegments((CreateTableStatement) 
binderContext.getSqlStatement(), databaseName, schemaName, tableName));
         }
+        CaseInsensitiveString caseInsensitiveTableName = new 
CaseInsensitiveString(tableName.getValue());
+        if 
(binderContext.getExternalTableBinderContexts().containsKey(caseInsensitiveTableName))
 {
+            TableSegmentBinderContext tableSegmentBinderContext = 
binderContext.getExternalTableBinderContexts().get(caseInsensitiveTableName).iterator().next();
+            return new SimpleTableSegmentBinderContext(
+                    
SubqueryTableBindUtils.createSubqueryProjections(tableSegmentBinderContext.getProjectionSegments(),
 tableName, binderContext.getSqlStatement().getDatabaseType()));
+        }
         return new SimpleTableSegmentBinderContext(Collections.emptyList());
     }
     
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/with/CommonTableExpressionSegmentBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/with/CommonTableExpressionSegmentBinder.java
new file mode 100644
index 00000000000..136c33e7fbd
--- /dev/null
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/with/CommonTableExpressionSegmentBinder.java
@@ -0,0 +1,62 @@
+/*
+ * 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.infra.binder.engine.segment.with;
+
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import 
org.apache.shardingsphere.infra.binder.engine.segment.from.context.type.SimpleTableSegmentBinderContext;
+import 
org.apache.shardingsphere.infra.binder.engine.segment.from.type.SubqueryTableSegmentBinder;
+import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonTableExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SubqueryTableSegment;
+
+import java.util.stream.Collectors;
+
+/**
+ * Common table expression segment binder.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class CommonTableExpressionSegmentBinder {
+    
+    /**
+     * Bind common table expression segment.
+     *
+     * @param segment common table expression segment
+     * @param binderContext SQL statement binder context
+     * @param recursive recursive
+     * @return bound common table expression segment
+     */
+    public static CommonTableExpressionSegment bind(final 
CommonTableExpressionSegment segment, final SQLStatementBinderContext 
binderContext, final boolean recursive) {
+        if (recursive && segment.getAliasName().isPresent()) {
+            binderContext.getExternalTableBinderContexts().put(new 
CaseInsensitiveString(segment.getAliasName().get()),
+                    new 
SimpleTableSegmentBinderContext(segment.getColumns().stream().map(ColumnProjectionSegment::new).collect(Collectors.toList())));
+        }
+        SubqueryTableSegment subqueryTableSegment = new 
SubqueryTableSegment(segment.getStartIndex(), segment.getStopIndex(), 
segment.getSubquery());
+        subqueryTableSegment.setAlias(segment.getAliasSegment());
+        SubqueryTableSegment boundSubquerySegment =
+                SubqueryTableSegmentBinder.bind(subqueryTableSegment, 
binderContext, LinkedHashMultimap.create(), 
binderContext.getExternalTableBinderContexts());
+        CommonTableExpressionSegment result = new CommonTableExpressionSegment(
+                segment.getStartIndex(), segment.getStopIndex(), 
boundSubquerySegment.getAliasSegment().orElse(null), 
boundSubquerySegment.getSubquery());
+        // TODO bind with columns
+        result.getColumns().addAll(segment.getColumns());
+        return result;
+    }
+}
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/with/WithSegmentBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/with/WithSegmentBinder.java
new file mode 100644
index 00000000000..ca4af9da753
--- /dev/null
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/with/WithSegmentBinder.java
@@ -0,0 +1,125 @@
+/*
+ * 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.infra.binder.engine.segment.with;
+
+import com.cedarsoftware.util.CaseInsensitiveMap;
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.base.Strings;
+import com.google.common.collect.Multimap;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import 
org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
+import 
org.apache.shardingsphere.infra.binder.engine.segment.from.context.type.SimpleTableSegmentBinderContext;
+import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonTableExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ShorthandProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WithSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo;
+import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * With segment binder.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class WithSegmentBinder {
+    
+    /**
+     * Bind with segment.
+     *
+     * @param segment with segment
+     * @param binderContext SQL statement binder context
+     * @param externalTableBinderContexts external table binder contexts
+     * @return bound with segment
+     */
+    public static WithSegment bind(final WithSegment segment, final 
SQLStatementBinderContext binderContext,
+                                   final Multimap<CaseInsensitiveString, 
TableSegmentBinderContext> externalTableBinderContexts) {
+        Collection<CommonTableExpressionSegment> boundCommonTableExpressions = 
new LinkedList<>();
+        for (CommonTableExpressionSegment each : 
segment.getCommonTableExpressions()) {
+            CommonTableExpressionSegment boundCommonTableExpression = 
CommonTableExpressionSegmentBinder.bind(each, binderContext, 
segment.isRecursive());
+            boundCommonTableExpressions.add(boundCommonTableExpression);
+            if (segment.isRecursive() && each.getAliasName().isPresent()) {
+                externalTableBinderContexts.removeAll(new 
CaseInsensitiveString(each.getAliasName().get()));
+            }
+            bindWithColumns(each.getColumns(), boundCommonTableExpression);
+            each.getAliasName().ifPresent(optional -> 
externalTableBinderContexts.put(new CaseInsensitiveString(optional), 
createWithTableBinderContext(boundCommonTableExpression)));
+        }
+        return new WithSegment(segment.getStartIndex(), 
segment.getStopIndex(), boundCommonTableExpressions);
+    }
+    
+    private static SimpleTableSegmentBinderContext 
createWithTableBinderContext(final CommonTableExpressionSegment 
commonTableExpressionSegment) {
+        return new 
SimpleTableSegmentBinderContext(commonTableExpressionSegment.getSubquery().getSelect().getProjections().getProjections());
+    }
+    
+    private static void bindWithColumns(final Collection<ColumnSegment> 
columns, final CommonTableExpressionSegment boundCommonTableExpression) {
+        if (columns.isEmpty()) {
+            return;
+        }
+        Map<String, ColumnProjectionSegment> columnProjections = 
extractWithSubqueryColumnProjections(boundCommonTableExpression);
+        columns.forEach(each -> {
+            ColumnProjectionSegment projectionSegment = 
columnProjections.get(each.getIdentifier().getValue());
+            if (null != projectionSegment) {
+                each.setColumnBoundInfo(createColumnSegmentBoundInfo(each, 
projectionSegment.getColumn()));
+            }
+        });
+    }
+    
+    private static Map<String, ColumnProjectionSegment> 
extractWithSubqueryColumnProjections(final CommonTableExpressionSegment 
boundCommonTableExpression) {
+        Map<String, ColumnProjectionSegment> result = new 
CaseInsensitiveMap<>();
+        Collection<ProjectionSegment> projections = 
boundCommonTableExpression.getSubquery().getSelect().getProjections().getProjections();
+        projections.forEach(each -> extractWithSubqueryColumnProjections(each, 
result));
+        return result;
+    }
+    
+    private static void extractWithSubqueryColumnProjections(final 
ProjectionSegment projectionSegment, final Map<String, ColumnProjectionSegment> 
result) {
+        if (projectionSegment instanceof ColumnProjectionSegment) {
+            result.put(getColumnName((ColumnProjectionSegment) 
projectionSegment), (ColumnProjectionSegment) projectionSegment);
+        }
+        if (projectionSegment instanceof ShorthandProjectionSegment) {
+            ((ShorthandProjectionSegment) 
projectionSegment).getActualProjectionSegments().forEach(eachProjection -> {
+                if (eachProjection instanceof ColumnProjectionSegment) {
+                    result.put(getColumnName((ColumnProjectionSegment) 
eachProjection), (ColumnProjectionSegment) eachProjection);
+                }
+            });
+        }
+    }
+    
+    private static String getColumnName(final ColumnProjectionSegment 
columnProjection) {
+        return 
columnProjection.getAliasName().orElse(columnProjection.getColumn().getIdentifier().getValue());
+    }
+    
+    private static ColumnSegmentBoundInfo createColumnSegmentBoundInfo(final 
ColumnSegment segment, final ColumnSegment inputColumnSegment) {
+        IdentifierValue originalDatabase = null == inputColumnSegment ? null : 
inputColumnSegment.getColumnBoundInfo().getOriginalDatabase();
+        IdentifierValue originalSchema = null == inputColumnSegment ? null : 
inputColumnSegment.getColumnBoundInfo().getOriginalSchema();
+        IdentifierValue segmentOriginalTable = 
segment.getColumnBoundInfo().getOriginalTable();
+        IdentifierValue originalTable = 
Strings.isNullOrEmpty(segmentOriginalTable.getValue())
+                ? Optional.ofNullable(inputColumnSegment).map(optional -> 
optional.getColumnBoundInfo().getOriginalTable()).orElse(segmentOriginalTable)
+                : segmentOriginalTable;
+        IdentifierValue segmentOriginalColumn = 
segment.getColumnBoundInfo().getOriginalColumn();
+        IdentifierValue originalColumn = 
Optional.ofNullable(inputColumnSegment).map(optional -> 
optional.getColumnBoundInfo().getOriginalColumn()).orElse(segmentOriginalColumn);
+        return new ColumnSegmentBoundInfo(new 
TableSegmentBoundInfo(originalDatabase, originalSchema), originalTable, 
originalColumn);
+    }
+}
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
index 521d949a899..3f0cf8244b2 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
@@ -32,6 +32,7 @@ import 
org.apache.shardingsphere.infra.binder.engine.segment.order.OrderBySegmen
 import 
org.apache.shardingsphere.infra.binder.engine.segment.predicate.HavingSegmentBinder;
 import 
org.apache.shardingsphere.infra.binder.engine.segment.predicate.WhereSegmentBinder;
 import 
org.apache.shardingsphere.infra.binder.engine.segment.projection.ProjectionsSegmentBinder;
+import 
org.apache.shardingsphere.infra.binder.engine.segment.with.WithSegmentBinder;
 import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinder;
 import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import 
org.apache.shardingsphere.infra.binder.engine.util.SubqueryTableBindUtils;
@@ -59,6 +60,7 @@ public final class SelectStatementBinder implements 
SQLStatementBinder<SelectSta
     public SelectStatement bind(final SelectStatement sqlStatement, final 
SQLStatementBinderContext binderContext) {
         SelectStatement result = copy(sqlStatement);
         Multimap<CaseInsensitiveString, TableSegmentBinderContext> 
tableBinderContexts = LinkedHashMultimap.create();
+        sqlStatement.getWithSegment().ifPresent(optional -> 
result.setWithSegment(WithSegmentBinder.bind(optional, binderContext, 
binderContext.getExternalTableBinderContexts())));
         Optional<TableSegment> boundTableSegment = 
sqlStatement.getFrom().map(optional -> TableSegmentBinder.bind(optional, 
binderContext, tableBinderContexts, outerTableBinderContexts));
         boundTableSegment.ifPresent(result::setFrom);
         
result.setProjections(ProjectionsSegmentBinder.bind(sqlStatement.getProjections(),
 binderContext, boundTableSegment.orElse(null), tableBinderContexts, 
outerTableBinderContexts));
@@ -71,7 +73,6 @@ public final class SelectStatementBinder implements 
SQLStatementBinder<SelectSta
         sqlStatement.getOrderBy().ifPresent(optional -> result.setOrderBy(
                 OrderBySegmentBinder.bind(optional, binderContext, 
currentTableBinderContexts, tableBinderContexts, outerTableBinderContexts)));
         sqlStatement.getHaving().ifPresent(optional -> 
result.setHaving(HavingSegmentBinder.bind(optional, binderContext, 
currentTableBinderContexts, outerTableBinderContexts)));
-        // TODO support other segment bind in select statement
         return result;
     }
     
@@ -90,7 +91,6 @@ public final class SelectStatementBinder implements 
SQLStatementBinder<SelectSta
         sqlStatement.getWindow().ifPresent(result::setWindow);
         sqlStatement.getModelSegment().ifPresent(result::setModelSegment);
         sqlStatement.getSubqueryType().ifPresent(result::setSubqueryType);
-        sqlStatement.getWithSegment().ifPresent(result::setWithSegment);
         
result.addParameterMarkerSegments(sqlStatement.getParameterMarkerSegments());
         result.getCommentSegments().addAll(sqlStatement.getCommentSegments());
         result.getVariableNames().addAll(sqlStatement.getVariableNames());
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java
index 1de69236fdd..ba4744cc5db 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java
@@ -25,6 +25,7 @@ import 
org.apache.shardingsphere.infra.binder.engine.segment.assign.AssignmentSe
 import 
org.apache.shardingsphere.infra.binder.engine.segment.from.TableSegmentBinder;
 import 
org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import 
org.apache.shardingsphere.infra.binder.engine.segment.predicate.WhereSegmentBinder;
+import 
org.apache.shardingsphere.infra.binder.engine.segment.with.WithSegmentBinder;
 import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinder;
 import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.dml.UpdateStatement;
@@ -38,6 +39,7 @@ public final class UpdateStatementBinder implements 
SQLStatementBinder<UpdateSta
     public UpdateStatement bind(final UpdateStatement sqlStatement, final 
SQLStatementBinderContext binderContext) {
         UpdateStatement result = copy(sqlStatement);
         Multimap<CaseInsensitiveString, TableSegmentBinderContext> 
tableBinderContexts = LinkedHashMultimap.create();
+        sqlStatement.getWithSegment().ifPresent(optional -> 
result.setWithSegment(WithSegmentBinder.bind(optional, binderContext, 
binderContext.getExternalTableBinderContexts())));
         result.setTable(TableSegmentBinder.bind(sqlStatement.getTable(), 
binderContext, tableBinderContexts, LinkedHashMultimap.create()));
         sqlStatement.getFrom().ifPresent(optional -> 
result.setFrom(TableSegmentBinder.bind(optional, binderContext, 
tableBinderContexts, LinkedHashMultimap.create())));
         sqlStatement.getAssignmentSegment().ifPresent(optional -> 
result.setSetAssignment(AssignmentSegmentBinder.bind(optional, binderContext, 
tableBinderContexts, LinkedHashMultimap.create())));
@@ -50,7 +52,6 @@ public final class UpdateStatementBinder implements 
SQLStatementBinder<UpdateSta
         UpdateStatement result = 
sqlStatement.getClass().getDeclaredConstructor().newInstance();
         sqlStatement.getOrderBy().ifPresent(result::setOrderBy);
         sqlStatement.getLimit().ifPresent(result::setLimit);
-        sqlStatement.getWithSegment().ifPresent(result::setWithSegment);
         
result.addParameterMarkerSegments(sqlStatement.getParameterMarkerSegments());
         result.getCommentSegments().addAll(sqlStatement.getCommentSegments());
         return result;
diff --git a/test/it/binder/src/test/resources/cases/dml/select.xml 
b/test/it/binder/src/test/resources/cases/dml/select.xml
index 7f03799f5f7..8caabdcb4d9 100644
--- a/test/it/binder/src/test/resources/cases/dml/select.xml
+++ b/test/it/binder/src/test/resources/cases/dml/select.xml
@@ -87,4 +87,210 @@
             </simple-table>
         </from>
     </select>
+
+    <select sql-case-id="select_with_group_by_order_by">
+        <projections start-index="7" stop-index="30">
+            <column-projection name="order_id" start-index="7" stop-index="14">
+                <column-bound>
+                    <original-database name="foo_db_1" />
+                    <original-schema name="foo_db_1" />
+                    <original-table name="t_order" />
+                    <original-column name="order_id" start-delimiter="`" 
end-delimiter="`" />
+                </column-bound>
+            </column-projection>
+            <aggregation-projection type="COUNT" expression="COUNT(1)" 
start-index="17" stop-index="24" alias="count">
+                <parameter>
+                    <literal-expression value="1" start-index="23" 
stop-index="23" />
+                </parameter>
+            </aggregation-projection>
+        </projections>
+        <from start-index="37" stop-index="45">
+            <simple-table name="t_order" start-index="37" stop-index="45" 
alias="o">
+                <table-bound>
+                    <original-database name="foo_db_1" />
+                    <original-schema name="foo_db_1" />
+                </table-bound>
+            </simple-table>
+        </from>
+        <group-by>
+            <column-item name="order_id" start-index="56" stop-index="63" >
+                <column-bound>
+                    <original-database name="foo_db_1" />
+                    <original-schema name="foo_db_1" />
+                    <original-table name="t_order" />
+                    <original-column name="order_id" start-delimiter="`" 
end-delimiter="`" />
+                </column-bound>
+            </column-item>
+        </group-by>
+        <having start-index="65" stop-index="80">
+            <expr>
+                <binary-operation-expression start-index="72" stop-index="80">
+                    <left>
+                        <column name="count" start-index="72" stop-index="76" 
/>
+                    </left>
+                    <operator>&gt;</operator>
+                    <right>
+                        <literal-expression start-index="80" stop-index="80" 
value="1" />
+                    </right>
+                </binary-operation-expression>
+            </expr>
+        </having>
+        <order-by>
+            <column-item name="order_id" start-index="91" stop-index="98">
+                <column-bound>
+                    <original-database name="foo_db_1" />
+                    <original-schema name="foo_db_1" />
+                    <original-table name="t_order" />
+                    <original-column name="order_id" start-delimiter="`" 
end-delimiter="`" />
+                </column-bound>
+            </column-item>
+        </order-by>
+    </select>
+
+    <select sql-case-id="select_with_with_clause">
+        <with start-index="0" stop-index="44">
+            <common-table-expression name="t_order_tmp" start-index="5" 
stop-index="44">
+                <subquery-expression start-index="5" stop-index="44">
+                    <select>
+                        <projections start-index="28" stop-index="28">
+                            <shorthand-projection start-index="28" 
stop-index="28">
+                                <actual-projections>
+                                    <column-projection name="order_id" 
start-index="0" stop-index="0" start-delimiter="`" end-delimiter="`">
+                                        <owner name="o" start-index="0" 
stop-index="0" />
+                                        <column-bound>
+                                            <original-database name="foo_db_1" 
/>
+                                            <original-schema name="foo_db_1" />
+                                            <original-table name="t_order" />
+                                            <original-column name="order_id" 
start-delimiter="`" end-delimiter="`" />
+                                        </column-bound>
+                                    </column-projection>
+                                    <column-projection name="user_id" 
start-index="0" stop-index="0" start-delimiter="`" end-delimiter="`">
+                                        <owner name="o" start-index="0" 
stop-index="0" />
+                                        <column-bound>
+                                            <original-database name="foo_db_1" 
/>
+                                            <original-schema name="foo_db_1" />
+                                            <original-table name="t_order" />
+                                            <original-column name="user_id" 
start-delimiter="`" end-delimiter="`" />
+                                        </column-bound>
+                                    </column-projection>
+                                    <column-projection name="status" 
start-index="0" stop-index="0" start-delimiter="`" end-delimiter="`">
+                                        <owner name="o" start-index="0" 
stop-index="0" />
+                                        <column-bound>
+                                            <original-database name="foo_db_1" 
/>
+                                            <original-schema name="foo_db_1" />
+                                            <original-table name="t_order" />
+                                            <original-column name="status" 
start-delimiter="`" end-delimiter="`" />
+                                        </column-bound>
+                                    </column-projection>
+                                    <column-projection name="merchant_id" 
start-index="0" stop-index="0" start-delimiter="`" end-delimiter="`">
+                                        <owner name="o" start-index="0" 
stop-index="0" />
+                                        <column-bound>
+                                            <original-database name="foo_db_1" 
/>
+                                            <original-schema name="foo_db_1" />
+                                            <original-table name="t_order" />
+                                            <original-column 
name="merchant_id" start-delimiter="`" end-delimiter="`" />
+                                        </column-bound>
+                                    </column-projection>
+                                    <column-projection name="remark" 
start-index="0" stop-index="0" start-delimiter="`" end-delimiter="`">
+                                        <owner name="o" start-index="0" 
stop-index="0" />
+                                        <column-bound>
+                                            <original-database name="foo_db_1" 
/>
+                                            <original-schema name="foo_db_1" />
+                                            <original-table name="t_order" />
+                                            <original-column name="remark" 
start-delimiter="`" end-delimiter="`" />
+                                        </column-bound>
+                                    </column-projection>
+                                    <column-projection name="creation_date" 
start-index="0" stop-index="0" start-delimiter="`" end-delimiter="`">
+                                        <owner name="o" start-index="0" 
stop-index="0" />
+                                        <column-bound>
+                                            <original-database name="foo_db_1" 
/>
+                                            <original-schema name="foo_db_1" />
+                                            <original-table name="t_order" />
+                                            <original-column 
name="creation_date" start-delimiter="`" end-delimiter="`" />
+                                        </column-bound>
+                                    </column-projection>
+                                </actual-projections>
+                            </shorthand-projection>
+                        </projections>
+                        <from>
+                            <simple-table name="t_order" alias="o" 
start-index="35" stop-index="43">
+                                <table-bound>
+                                    <original-database name="foo_db_1" />
+                                    <original-schema name="foo_db_1" />
+                                </table-bound>
+                            </simple-table>
+                        </from>
+                    </select>
+                </subquery-expression>
+            </common-table-expression>
+        </with>
+        <projections start-index="53" stop-index="53">
+            <shorthand-projection start-index="53" stop-index="53">
+                <actual-projections>
+                    <column-projection name="order_id" start-index="0" 
stop-index="0" start-delimiter="`" end-delimiter="`">
+                        <owner name="t_order_tmp" start-index="0" 
stop-index="0" />
+                        <column-bound>
+                            <original-database name="foo_db_1" />
+                            <original-schema name="foo_db_1" />
+                            <original-table name="t_order" />
+                            <original-column name="order_id" 
start-delimiter="`" end-delimiter="`" />
+                        </column-bound>
+                    </column-projection>
+                    <column-projection name="user_id" start-index="0" 
stop-index="0" start-delimiter="`" end-delimiter="`">
+                        <owner name="t_order_tmp" start-index="0" 
stop-index="0" />
+                        <column-bound>
+                            <original-database name="foo_db_1" />
+                            <original-schema name="foo_db_1" />
+                            <original-table name="t_order" />
+                            <original-column name="user_id" 
start-delimiter="`" end-delimiter="`" />
+                        </column-bound>
+                    </column-projection>
+                    <column-projection name="status" start-index="0" 
stop-index="0" start-delimiter="`" end-delimiter="`">
+                        <owner name="t_order_tmp" start-index="0" 
stop-index="0" />
+                        <column-bound>
+                            <original-database name="foo_db_1" />
+                            <original-schema name="foo_db_1" />
+                            <original-table name="t_order" />
+                            <original-column name="status" start-delimiter="`" 
end-delimiter="`" />
+                        </column-bound>
+                    </column-projection>
+                    <column-projection name="merchant_id" start-index="0" 
stop-index="0" start-delimiter="`" end-delimiter="`">
+                        <owner name="t_order_tmp" start-index="0" 
stop-index="0" />
+                        <column-bound>
+                            <original-database name="foo_db_1" />
+                            <original-schema name="foo_db_1" />
+                            <original-table name="t_order" />
+                            <original-column name="merchant_id" 
start-delimiter="`" end-delimiter="`" />
+                        </column-bound>
+                    </column-projection>
+                    <column-projection name="remark" start-index="0" 
stop-index="0" start-delimiter="`" end-delimiter="`">
+                        <owner name="t_order_tmp" start-index="0" 
stop-index="0" />
+                        <column-bound>
+                            <original-database name="foo_db_1" />
+                            <original-schema name="foo_db_1" />
+                            <original-table name="t_order" />
+                            <original-column name="remark" start-delimiter="`" 
end-delimiter="`" />
+                        </column-bound>
+                    </column-projection>
+                    <column-projection name="creation_date" start-index="0" 
stop-index="0" start-delimiter="`" end-delimiter="`">
+                        <owner name="t_order_tmp" start-index="0" 
stop-index="0" />
+                        <column-bound>
+                            <original-database name="foo_db_1" />
+                            <original-schema name="foo_db_1" />
+                            <original-table name="t_order" />
+                            <original-column name="creation_date" 
start-delimiter="`" end-delimiter="`" />
+                        </column-bound>
+                    </column-projection>
+                </actual-projections>
+            </shorthand-projection>
+        </projections>
+        <from start-index="55" stop-index="70">
+            <simple-table name="t_order_tmp" start-index="60" stop-index="70">
+                <table-bound>
+                    <original-database name="foo_db_1" />
+                    <original-schema name="foo_db_1" />
+                </table-bound>
+            </simple-table>
+        </from>
+    </select>
 </sql-parser-test-cases>
diff --git a/test/it/binder/src/test/resources/sqls/dml/select.xml 
b/test/it/binder/src/test/resources/sqls/dml/select.xml
index aa09790e7ad..cca532f1c5f 100644
--- a/test/it/binder/src/test/resources/sqls/dml/select.xml
+++ b/test/it/binder/src/test/resources/sqls/dml/select.xml
@@ -18,4 +18,6 @@
 
 <sql-cases>
     <sql-case id="select_with_shorthand_projection" value="SELECT * FROM 
t_order o" db-types="MySQL"/>
+    <sql-case id="select_with_group_by_order_by" value="SELECT order_id, 
COUNT(1) count FROM t_order o GROUP BY order_id HAVING count > 1 ORDER BY 
order_id" db-types="MySQL"/>
+    <sql-case id="select_with_with_clause" value="WITH t_order_tmp AS (SELECT 
* FROM t_order o) SELECT * FROM t_order_tmp" db-types="MySQL"/>
 </sql-cases>
diff --git 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/orderby/OrderByItemAssert.java
 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/orderby/OrderByItemAssert.java
index af1be821b57..6a6df5f5aab 100644
--- 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/orderby/OrderByItemAssert.java
+++ 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/orderby/OrderByItemAssert.java
@@ -25,6 +25,7 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.ite
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.SQLCaseAssertContext;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.SQLSegmentAssert;
+import 
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.bound.ColumnBoundAssert;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.expression.ExpressionAssert;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.identifier.IdentifierValueAssert;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.owner.OwnerAssert;
@@ -106,6 +107,7 @@ public final class OrderByItemAssert {
     private static void assertColumnOrderByItem(final SQLCaseAssertContext 
assertContext,
                                                 final ColumnOrderByItemSegment 
actual, final ExpectedColumnOrderByItem expected, final String type) {
         IdentifierValueAssert.assertIs(assertContext, 
actual.getColumn().getIdentifier(), expected, String.format("%s item", type));
+        ColumnBoundAssert.assertIs(assertContext, 
actual.getColumn().getColumnBoundInfo(), expected.getColumnBound());
         if (null == expected.getOwner()) {
             assertFalse(actual.getColumn().getOwner().isPresent(), 
assertContext.getText("Actual owner should not exist."));
         } else {
diff --git 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/orderby/item/impl/ExpectedColumnOrderByItem.java
 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/orderby/item/impl/ExpectedColumnOrderByItem.java
index f150058e9f4..f000d2b5234 100644
--- 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/orderby/item/impl/ExpectedColumnOrderByItem.java
+++ 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/orderby/item/impl/ExpectedColumnOrderByItem.java
@@ -20,6 +20,7 @@ package 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.
 import lombok.Getter;
 import lombok.Setter;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.ExpectedIdentifierSQLSegment;
+import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.bound.ExpectedColumnBoundInfo;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.orderby.item.ExpectedOrderByItem;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.table.ExpectedOwner;
 
@@ -38,4 +39,7 @@ public final class ExpectedColumnOrderByItem extends 
ExpectedOrderByItem impleme
     
     @XmlElement
     private ExpectedOwner owner;
+    
+    @XmlElement(name = "column-bound")
+    private ExpectedColumnBoundInfo columnBound;
 }


Reply via email to