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

terrymanu 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 c5102c6814e Simplify binder predicates and statement copying (#40337)
c5102c6814e is described below

commit c5102c6814e8ebc069ee9eb0a85f51f3e6dfb851
Author: Liang Zhang <[email protected]>
AuthorDate: Thu Oct 22 19:12:27 2026 +0800

    Simplify binder predicates and statement copying (#40337)
---
 .../select/pagination/PaginationContext.java       |  3 +-
 .../type/dml/SelectStatementBaseContext.java       | 26 +++++---
 .../dml/expression/type/ColumnSegmentBinder.java   |  2 +-
 .../dml/projection/ProjectionsSegmentBinder.java   |  6 +-
 .../statement/dml/InsertStatementBinder.java       | 28 +++-----
 .../statement/dml/SelectStatementBinder.java       | 22 ++-----
 .../type/dml/SelectStatementContextTest.java       | 77 ++++++++++++++++++++++
 .../statement/dml/InsertStatementBinderTest.java   | 24 +++++++
 .../statement/dml/SelectStatementBinderTest.java   | 60 +++++++++++++++++
 9 files changed, 202 insertions(+), 46 deletions(-)

diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/PaginationContext.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/PaginationContext.java
index bc5b9820365..1e228625caf 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/PaginationContext.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/PaginationContext.java
@@ -72,8 +72,7 @@ public final class PaginationContext {
             return ((ExpressionRowNumberValueSegment) 
paginationValueSegment).getValue(params);
         }
         if (paginationValueSegment instanceof 
ExpressionPaginationValueSegment) {
-            Long result = 
getValueFromExpression(((ExpressionPaginationValueSegment) 
paginationValueSegment).getExpression(), params);
-            return result;
+            return getValueFromExpression(((ExpressionPaginationValueSegment) 
paginationValueSegment).getExpression(), params);
         }
         return ((NumberLiteralPaginationValueSegment) 
paginationValueSegment).getValue();
     }
diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementBaseContext.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementBaseContext.java
index d6909a17635..1807f55eb30 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementBaseContext.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementBaseContext.java
@@ -408,11 +408,17 @@ public final class SelectStatementBaseContext implements 
SQLStatementContext {
         ColumnSegmentBoundInfo orderByBoundInfo = 
orderByColumn.getColumnBoundInfo();
         ColumnSegmentBoundInfo groupByOtherUsingBoundInfo = 
groupByColumn.getOtherUsingColumnBoundInfo();
         ColumnSegmentBoundInfo orderByOtherUsingBoundInfo = 
orderByColumn.getOtherUsingColumnBoundInfo();
-        return 
groupByColumn.getQualifiedName().equals(orderByColumn.getQualifiedName()) && 
null != groupByBoundInfo && null != orderByBoundInfo
-                && isSameColumnBoundInfo(groupByBoundInfo, orderByBoundInfo)
-                && (null == groupByOtherUsingBoundInfo ? null == 
orderByOtherUsingBoundInfo
-                        : null != orderByOtherUsingBoundInfo && 
isSameColumnBoundInfo(groupByOtherUsingBoundInfo, orderByOtherUsingBoundInfo))
-                && !isAmbiguousProjectionReference(groupByColumn);
+        if 
(!groupByColumn.getQualifiedName().equals(orderByColumn.getQualifiedName()) || 
null == groupByBoundInfo || null == orderByBoundInfo
+                || !isSameColumnBoundInfo(groupByBoundInfo, orderByBoundInfo)) 
{
+            return false;
+        }
+        if (null == groupByOtherUsingBoundInfo && null != 
orderByOtherUsingBoundInfo) {
+            return false;
+        }
+        if (null != groupByOtherUsingBoundInfo && (null == 
orderByOtherUsingBoundInfo || 
!isSameColumnBoundInfo(groupByOtherUsingBoundInfo, 
orderByOtherUsingBoundInfo))) {
+            return false;
+        }
+        return !isAmbiguousProjectionReference(groupByColumn);
     }
     
     private boolean isAmbiguousProjectionReference(final ColumnSegment column) 
{
@@ -436,9 +442,13 @@ public final class SelectStatementBaseContext implements 
SQLStatementContext {
     }
     
     private boolean isSameColumnBoundInfo(final ColumnSegmentBoundInfo left, 
final ColumnSegmentBoundInfo right) {
-        return null != left && null != right && left.getTableSourceType() == 
right.getTableSourceType()
-                && Objects.equals(left.getOriginalDatabase(), 
right.getOriginalDatabase()) && Objects.equals(left.getOriginalSchema(), 
right.getOriginalSchema())
-                && Objects.equals(left.getOriginalTable(), 
right.getOriginalTable()) && Objects.equals(left.getOriginalColumn(), 
right.getOriginalColumn());
+        if (null == left || null == right || left.getTableSourceType() != 
right.getTableSourceType()) {
+            return false;
+        }
+        if (!Objects.equals(left.getOriginalDatabase(), 
right.getOriginalDatabase()) || !Objects.equals(left.getOriginalSchema(), 
right.getOriginalSchema())) {
+            return false;
+        }
+        return Objects.equals(left.getOriginalTable(), 
right.getOriginalTable()) && Objects.equals(left.getOriginalColumn(), 
right.getOriginalColumn());
     }
     
     /**
diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/ColumnSegmentBinder.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/ColumnSegmentBinder.java
index 63d4c5235f6..baf0dce1f5c 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/ColumnSegmentBinder.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/ColumnSegmentBinder.java
@@ -100,7 +100,6 @@ public final class ColumnSegmentBinder {
             return segment;
         }
         ColumnSegment columnSegment = createNestedObjectColumnSegment(segment, 
parentSegmentType, binderContext, tableBinderContexts, 
outerTableBinderContexts).orElse(segment);
-        ColumnSegment result = copy(columnSegment);
         Collection<TableSegmentBinderContext> tableSegmentBinderContexts =
                 getTableSegmentBinderContexts(columnSegment, 
parentSegmentType, binderContext, tableBinderContexts, 
outerTableBinderContexts);
         ColumnSegmentInfo columnSegmentInfo = 
getColumnSegmentInfo(columnSegment, parentSegmentType, 
tableSegmentBinderContexts, outerTableBinderContexts, binderContext);
@@ -110,6 +109,7 @@ public final class ColumnSegmentBinder {
         }
         ShardingSpherePreconditions.checkState(inputColumnSegment.isPresent() 
|| isSkipColumnBind(tableSegmentBinderContexts, 
outerTableBinderContexts.values()),
                 () -> new ColumnNotFoundException(segment.getExpression(), 
SEGMENT_TYPE_MESSAGES.getOrDefault(parentSegmentType, 
UNKNOWN_SEGMENT_TYPE_MESSAGE)));
+        ColumnSegment result = copy(columnSegment);
         inputColumnSegment.ifPresent(optional -> 
result.setVariable(optional.isVariable()));
         columnSegment.getOwner().ifPresent(optional -> 
result.setOwner(bindOwnerTableContext(optional, 
inputColumnSegment.orElse(null))));
         result.setColumnBoundInfo(createColumnSegmentBoundInfo(columnSegment, 
inputColumnSegment.orElse(null), columnSegmentInfo.getTableSourceType()));
diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/projection/ProjectionsSegmentBinder.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/projection/ProjectionsSegmentBinder.java
index a60385cdb54..a8ad7a12ad6 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/projection/ProjectionsSegmentBinder.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/projection/ProjectionsSegmentBinder.java
@@ -176,8 +176,10 @@ public final class ProjectionsSegmentBinder {
         }
         ColumnSegment columnSegment = ((ColumnProjectionSegment) 
projectionSegment).getColumn();
         String columnName = columnSegment.getIdentifier().getValue();
-        return !columnSegment.getOwner().isPresent() && (null == 
columnSegment.getNestedObjectAttributes() || 
columnSegment.getNestedObjectAttributes().isEmpty())
-                && (isTableAliasOrName(boundTableSegment, columnName) || 
tableBinderContexts.containsKey(CaseInsensitiveString.of(columnName)));
+        if (columnSegment.getOwner().isPresent() || null != 
columnSegment.getNestedObjectAttributes() && 
!columnSegment.getNestedObjectAttributes().isEmpty()) {
+            return false;
+        }
+        return isTableAliasOrName(boundTableSegment, columnName) || 
tableBinderContexts.containsKey(CaseInsensitiveString.of(columnName));
     }
     
     private static boolean isSupportWholeRowProjection(final 
SQLStatementBinderContext binderContext) {
diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinder.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinder.java
index ec71a3d1771..5ac19877f55 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinder.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinder.java
@@ -69,7 +69,16 @@ public final class InsertStatementBinder implements 
SQLStatementBinder<InsertSta
         SubquerySegment boundInsertSelect = 
sqlStatement.getInsertSelect().map(optional -> 
SubquerySegmentBinder.bind(optional, binderContext, 
tableBinderContexts)).orElse(null);
         OnDuplicateKeyColumnsSegment boundOnDuplicateKeyColumns = 
sqlStatement.getOnDuplicateKeyColumns()
                 .map(optional -> AssignmentSegmentBinder.bind(optional, 
binderContext, tableBinderContexts, outerTableBinderContexts)).orElse(null);
-        InsertStatement result = copy(sqlStatement, boundWith, boundTable, 
boundInsertColumns, boundSetAssignment, boundInsertSelect, 
boundOnDuplicateKeyColumns, boundValues);
+        InsertStatement result = 
InsertStatement.builder().databaseType(sqlStatement.getDatabaseType()).table(boundTable).insertColumns(boundInsertColumns)
+                
.insertSelect(boundInsertSelect).setAssignment(boundSetAssignment).onDuplicateKeyColumns(boundOnDuplicateKeyColumns)
+                
.valueReference(sqlStatement.getValueReference().orElse(null)).returning(sqlStatement.getReturning().orElse(null))
+                .errorLogging(sqlStatement.getErrorLogging().orElse(null))
+                
.output(sqlStatement.getOutput().orElse(null)).with(boundWith).multiTableInsertType(sqlStatement.getMultiTableInsertType().orElse(null))
+                
.multiTableInsertInto(sqlStatement.getMultiTableInsertInto().orElse(null)).multiTableConditionalInto(sqlStatement.getMultiTableConditionalInto().orElse(null))
+                
.where(sqlStatement.getWhere().orElse(null)).exec(sqlStatement.getExec().orElse(null)).withTableHint(sqlStatement.getWithTableHint().orElse(null))
+                
.rowSetFunction(sqlStatement.getRowSetFunction().orElse(null)).ignore(sqlStatement.isIgnore()).replace(sqlStatement.isReplace())
+                .overwrite(sqlStatement.isOverwrite()).values(new 
LinkedList<>(boundValues)).build();
+        SQLStatementCopyUtils.copyAttributes(sqlStatement, result);
         if (!sqlStatement.getInsertColumns().isPresent() || 
sqlStatement.getInsertColumns().get().getColumns().isEmpty()) {
             tableBinderContexts.values().forEach(each -> 
result.getDerivedInsertColumns().addAll(getVisibleColumns(each.getProjectionSegments())));
         }
@@ -90,23 +99,6 @@ public final class InsertStatementBinder implements 
SQLStatementBinder<InsertSta
         return result;
     }
     
-    private InsertStatement copy(final InsertStatement sqlStatement, final 
WithSegment boundWith, final SimpleTableSegment boundTable,
-                                 final InsertColumnsSegment 
boundInsertColumns, final SetAssignmentSegment boundSetAssignment, final 
SubquerySegment boundInsertSelect,
-                                 final OnDuplicateKeyColumnsSegment 
boundOnDuplicateKeyColumns,
-                                 final Collection<InsertValuesSegment> 
boundValues) {
-        InsertStatement result = 
InsertStatement.builder().databaseType(sqlStatement.getDatabaseType()).table(boundTable).insertColumns(boundInsertColumns)
-                
.insertSelect(boundInsertSelect).setAssignment(boundSetAssignment).onDuplicateKeyColumns(boundOnDuplicateKeyColumns)
-                
.valueReference(sqlStatement.getValueReference().orElse(null)).returning(sqlStatement.getReturning().orElse(null))
-                .errorLogging(sqlStatement.getErrorLogging().orElse(null))
-                
.output(sqlStatement.getOutput().orElse(null)).with(boundWith).multiTableInsertType(sqlStatement.getMultiTableInsertType().orElse(null))
-                
.multiTableInsertInto(sqlStatement.getMultiTableInsertInto().orElse(null)).multiTableConditionalInto(sqlStatement.getMultiTableConditionalInto().orElse(null))
-                
.where(sqlStatement.getWhere().orElse(null)).exec(sqlStatement.getExec().orElse(null)).withTableHint(sqlStatement.getWithTableHint().orElse(null))
-                
.rowSetFunction(sqlStatement.getRowSetFunction().orElse(null)).ignore(sqlStatement.isIgnore()).replace(sqlStatement.isReplace())
-                .overwrite(sqlStatement.isOverwrite()).values(new 
LinkedList<>(boundValues)).build();
-        SQLStatementCopyUtils.copyAttributes(sqlStatement, result);
-        return result;
-    }
-    
     private Collection<ColumnSegment> getVisibleColumns(final 
Collection<ProjectionSegment> projectionSegments) {
         return projectionSegments.stream().filter(each -> each instanceof 
ColumnProjectionSegment
                 && each.isVisible()).map(each -> ((ColumnProjectionSegment) 
each).getColumn()).collect(Collectors.toList());
diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
index 2db9faa44be..748c09aa52c 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
@@ -99,8 +99,13 @@ public final class SelectStatementBinder implements 
SQLStatementBinder<SelectSta
                 sqlStatement.getHaving().map(optional -> 
HavingSegmentBinder.bind(optional, binderContext, currentTableBinderContexts, 
tableBinderContexts, outerTableBinderContexts)).orElse(null);
         WindowSegment boundWindow = sqlStatement.getWindow().map(optional -> 
bindWindowSegment(optional, binderContext, tableBinderContexts, 
outerTableBinderContexts)).orElse(null);
         Collection<FunctionSegment> boundTransformSegments = 
bindTransformSegments(sqlStatement, binderContext, tableBinderContexts, 
outerTableBinderContexts);
-        return copy(sqlStatement, boundWith, boundFrom.orElse(null), 
boundProjections, boundWhere,
-                boundHierarchicalQuery, boundCombine, boundLock, boundGroupBy, 
boundOrderBy, boundHaving, boundModel, boundWindow, boundTransformSegments);
+        SelectStatement result = 
SelectStatement.builder().databaseType(sqlStatement.getDatabaseType()).with(boundWith).from(boundFrom.orElse(null)).projections(boundProjections)
+                
.where(boundWhere).hierarchicalQuery(boundHierarchicalQuery).combine(boundCombine).lock(boundLock).groupBy(boundGroupBy).orderBy(boundOrderBy).having(boundHaving)
+                
.limit(sqlStatement.getLimit().orElse(null)).window(boundWindow).model(boundModel)
+                
.subqueryType(sqlStatement.getSubqueryType().orElse(null)).build();
+        result.getTransformSegments().addAll(boundTransformSegments);
+        SQLStatementCopyUtils.copyAttributes(sqlStatement, result);
+        return result;
     }
     
     private ModelSegment bindModelSegment(final ModelSegment segment, final 
SQLStatementBinderContext binderContext,
@@ -185,19 +190,6 @@ public final class SelectStatementBinder implements 
SQLStatementBinder<SelectSta
         return result;
     }
     
-    private SelectStatement copy(final SelectStatement sqlStatement, final 
WithSegment boundWith, final TableSegment boundFrom, final ProjectionsSegment 
boundProjections,
-                                 final WhereSegment boundWhere, final 
HierarchicalQuerySegment boundHierarchicalQuery, final CombineSegment 
boundCombine,
-                                 final LockSegment boundLock, final 
GroupBySegment boundGroupBy, final OrderBySegment boundOrderBy, final 
HavingSegment boundHaving,
-                                 final ModelSegment boundModel, final 
WindowSegment boundWindow, final Collection<FunctionSegment> 
boundTransformSegments) {
-        SelectStatement result = 
SelectStatement.builder().databaseType(sqlStatement.getDatabaseType()).with(boundWith).from(boundFrom).projections(boundProjections)
-                
.where(boundWhere).hierarchicalQuery(boundHierarchicalQuery).combine(boundCombine).lock(boundLock).groupBy(boundGroupBy).orderBy(boundOrderBy).having(boundHaving)
-                
.limit(sqlStatement.getLimit().orElse(null)).window(boundWindow).model(boundModel)
-                
.subqueryType(sqlStatement.getSubqueryType().orElse(null)).build();
-        result.getTransformSegments().addAll(boundTransformSegments);
-        SQLStatementCopyUtils.copyAttributes(sqlStatement, result);
-        return result;
-    }
-    
     private Collection<FunctionSegment> bindTransformSegments(final 
SelectStatement sqlStatement, final SQLStatementBinderContext binderContext,
                                                               final 
Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
                                                               final 
Multimap<CaseInsensitiveString, TableSegmentBinderContext> 
outerTableBinderContexts) {
diff --git 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementContextTest.java
 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementContextTest.java
index 02e9c029f36..c1a90873df4 100644
--- 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementContextTest.java
+++ 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementContextTest.java
@@ -33,6 +33,7 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.enums.CombineType;
 import 
org.apache.shardingsphere.sql.parser.statement.core.enums.OrderDirection;
 import 
org.apache.shardingsphere.sql.parser.statement.core.enums.ParameterMarkerType;
 import org.apache.shardingsphere.sql.parser.statement.core.enums.SubqueryType;
+import 
org.apache.shardingsphere.sql.parser.statement.core.enums.TableSourceType;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.combine.CombineSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
@@ -70,12 +71,16 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Optional;
 import java.util.Properties;
+import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -193,6 +198,78 @@ class SelectStatementContextTest {
         assertTrue(selectStatementContext.isSameGroupByAndOrderByItems());
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("getDifferentColumnBoundInfos")
+    void 
assertIsNotSameGroupByAndOrderByItemsWithDifferentColumnBoundInfo(final String 
scenario, final ColumnSegmentBoundInfo groupByBoundInfo, final 
ColumnSegmentBoundInfo orderByBoundInfo) {
+        ColumnSegment groupByColumn = new ColumnSegment(0, 0, new 
IdentifierValue("id"));
+        groupByColumn.setColumnBoundInfo(groupByBoundInfo);
+        ColumnSegment orderByColumn = new ColumnSegment(0, 0, new 
IdentifierValue("id"));
+        orderByColumn.setColumnBoundInfo(orderByBoundInfo);
+        SelectStatementContext selectStatementContext = 
createColumnOrderByContext(groupByColumn, orderByColumn);
+        assertFalse(selectStatementContext.isSameGroupByAndOrderByItems(), 
scenario);
+    }
+    
+    private SelectStatementContext createColumnOrderByContext(final 
ColumnSegment groupByColumn, final ColumnSegment orderByColumn) {
+        SelectStatement selectStatement = 
SelectStatement.builder().databaseType(databaseType).projections(new 
ProjectionsSegment(0, 0))
+                .groupBy(new GroupBySegment(0, 0, 
Collections.singletonList(new ColumnOrderByItemSegment(groupByColumn, 
OrderDirection.ASC, NullsOrderType.LAST))))
+                .orderBy(new OrderBySegment(0, 0, 
Collections.singletonList(new ColumnOrderByItemSegment(orderByColumn, 
OrderDirection.DESC, NullsOrderType.LAST)))).build();
+        return createSelectStatementContext(selectStatement);
+    }
+    
+    private static Stream<Arguments> getDifferentColumnBoundInfos() {
+        ColumnSegmentBoundInfo boundInfo = 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "foo_db", "foo_schema", 
"foo_table", "foo_column");
+        return Stream.of(
+                Arguments.of("source", boundInfo, 
createColumnBoundInfo(TableSourceType.TEMPORARY_TABLE, "foo_db", "foo_schema", 
"foo_table", "foo_column")),
+                Arguments.of("database", boundInfo, 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "bar_db", "foo_schema", 
"foo_table", "foo_column")),
+                Arguments.of("schema", boundInfo, 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "foo_db", "bar_schema", 
"foo_table", "foo_column")),
+                Arguments.of("table", boundInfo, 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "foo_db", "foo_schema", 
"bar_table", "foo_column")),
+                Arguments.of("column", boundInfo, 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "foo_db", "foo_schema", 
"foo_table", "bar_column")),
+                Arguments.of("quoted database", boundInfo, 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "\"foo_db\"", 
"foo_schema", "foo_table", "foo_column")),
+                Arguments.of("quoted schema", boundInfo, 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "foo_db", 
"\"foo_schema\"", "foo_table", "foo_column")),
+                Arguments.of("quoted table", boundInfo, 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "foo_db", "foo_schema", 
"\"foo_table\"", "foo_column")),
+                Arguments.of("quoted column", boundInfo, 
createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE, "foo_db", "foo_schema", 
"foo_table", "\"foo_column\"")),
+                Arguments.of("missing group by binding", null, boundInfo),
+                Arguments.of("missing order by binding", boundInfo, null),
+                Arguments.of("missing both bindings", null, null));
+    }
+    
+    private static ColumnSegmentBoundInfo createColumnBoundInfo(final 
TableSourceType sourceType, final String databaseName, final String schemaName, 
final String tableName, final String columnName) {
+        return new ColumnSegmentBoundInfo(new TableSegmentBoundInfo(new 
IdentifierValue(databaseName), new IdentifierValue(schemaName)),
+                new IdentifierValue(tableName), new 
IdentifierValue(columnName), sourceType);
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("getDifferentOtherUsingColumnBoundInfos")
+    void 
assertIsNotSameGroupByAndOrderByItemsWithDifferentOtherUsingColumnBoundInfo(final
 String scenario,
+                                                                               
      final ColumnSegmentBoundInfo groupByBoundInfo, final 
ColumnSegmentBoundInfo orderByBoundInfo) {
+        ColumnSegment groupByColumn = new ColumnSegment(0, 0, new 
IdentifierValue("id"));
+        groupByColumn.setOtherUsingColumnBoundInfo(groupByBoundInfo);
+        ColumnSegment orderByColumn = new ColumnSegment(0, 0, new 
IdentifierValue("id"));
+        orderByColumn.setOtherUsingColumnBoundInfo(orderByBoundInfo);
+        SelectStatementContext selectStatementContext = 
createColumnOrderByContext(groupByColumn, orderByColumn);
+        assertFalse(selectStatementContext.isSameGroupByAndOrderByItems(), 
scenario);
+    }
+    
+    private static Stream<Arguments> getDifferentOtherUsingColumnBoundInfos() {
+        ColumnSegmentBoundInfo boundInfo = new ColumnSegmentBoundInfo(new 
IdentifierValue("foo_column"));
+        return Stream.of(
+                Arguments.of("only group by has other using binding", 
boundInfo, null),
+                Arguments.of("only order by has other using binding", null, 
boundInfo),
+                Arguments.of("different other using column", boundInfo, new 
ColumnSegmentBoundInfo(new IdentifierValue("bar_column"))));
+    }
+    
+    @Test
+    void assertIsSameGroupByAndOrderByItemsWithSameOtherUsingColumnBoundInfo() 
{
+        ColumnSegment groupByColumn = new ColumnSegment(0, 0, new 
IdentifierValue("id"));
+        
groupByColumn.setColumnBoundInfo(createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE,
 "\"foo_db\"", "\"foo_schema\"", "\"foo_table\"", "\"foo_column\""));
+        groupByColumn.setOtherUsingColumnBoundInfo(new 
ColumnSegmentBoundInfo(new IdentifierValue("foo_column")));
+        ColumnSegment orderByColumn = new ColumnSegment(0, 0, new 
IdentifierValue("id"));
+        
orderByColumn.setColumnBoundInfo(createColumnBoundInfo(TableSourceType.PHYSICAL_TABLE,
 "\"foo_db\"", "\"foo_schema\"", "\"foo_table\"", "\"foo_column\""));
+        orderByColumn.setOtherUsingColumnBoundInfo(new 
ColumnSegmentBoundInfo(new IdentifierValue("foo_column")));
+        SelectStatementContext selectStatementContext = 
createColumnOrderByContext(groupByColumn, orderByColumn);
+        assertTrue(selectStatementContext.isSameGroupByAndOrderByItems());
+    }
+    
     @Test
     void assertIsSameGroupByAndOrderByItemsWithGeneratedOrderBy() {
         SelectStatement selectStatement = 
SelectStatement.builder().databaseType(databaseType).projections(new 
ProjectionsSegment(0, 0))
diff --git 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinderTest.java
 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinderTest.java
index e7d6bb3504d..8e2e9d6a2d0 100644
--- 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinderTest.java
+++ 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinderTest.java
@@ -32,12 +32,14 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.In
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.OnDuplicateKeyColumnsSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
 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.ProjectionsSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.CommentSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment;
@@ -53,6 +55,7 @@ import java.util.Collections;
 import java.util.Iterator;
 
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.isA;
 import static org.hamcrest.Matchers.not;
@@ -108,6 +111,27 @@ class InsertStatementBinderTest {
         
assertThat(statusColumnSegment.getColumnBoundInfo().getOriginalColumn().getValue(),
 is("status"));
     }
     
+    @Test
+    void assertBindWithStatementAttributes() {
+        ParameterMarkerExpressionSegment parameterMarker = new 
ParameterMarkerExpressionSegment(0, 0, 0);
+        InsertStatement insertStatement = 
InsertStatement.builder().databaseType(databaseType)
+                .table(new SimpleTableSegment(new TableNameSegment(0, 0, new 
IdentifierValue("t_order"))))
+                .insertColumns(new InsertColumnsSegment(0, 0, 
Arrays.asList(new ColumnSegment(0, 0, new IdentifierValue("order_id")),
+                        new ColumnSegment(0, 0, new 
IdentifierValue("user_id")), new ColumnSegment(0, 0, new 
IdentifierValue("status")))))
+                .values(Collections.singletonList(new InsertValuesSegment(0, 0,
+                        Arrays.asList(parameterMarker, new ColumnSegment(0, 0, 
new IdentifierValue("foo_variable")), new LiteralExpressionSegment(0, 0, 
"OK")))))
+                .build();
+        CommentSegment comment = new CommentSegment("/* foo_comment */", 0, 
16);
+        
insertStatement.addParameterMarkers(Collections.singletonList(parameterMarker));
+        insertStatement.getVariableNames().add("foo_variable");
+        insertStatement.getComments().add(comment);
+        InsertStatement actual = new 
InsertStatementBinder().bind(insertStatement, new 
SQLStatementBinderContext(createMetaData(), "foo_db", new HintValueContext(), 
insertStatement));
+        assertThat(actual.getParameterMarkers(), contains(parameterMarker));
+        assertThat(actual.getParameterCount(), is(1));
+        assertThat(actual.getVariableNames(), contains("foo_variable"));
+        assertThat(actual.getComments(), contains(comment));
+    }
+    
     @Test
     void assertBindInsertSelectWithColumns() {
         ProjectionsSegment projections = new ProjectionsSegment(0, 0);
diff --git 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinderTest.java
 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinderTest.java
index fcdc716e627..581054f2c01 100644
--- 
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinderTest.java
+++ 
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinderTest.java
@@ -23,6 +23,7 @@ import 
org.apache.shardingsphere.database.connector.core.metadata.database.metad
 import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
+import 
org.apache.shardingsphere.infra.exception.kernel.metadata.ColumnNotFoundException;
 import org.apache.shardingsphere.infra.hint.HintValueContext;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
@@ -40,6 +41,7 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.Func
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ListExpression;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonTableExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
@@ -54,6 +56,7 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.ite
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.HierarchicalQuerySegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.CommentSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WindowItemSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WindowSegment;
@@ -65,6 +68,8 @@ import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
 import org.mockito.MockedStatic;
 
 import java.sql.Types;
@@ -75,9 +80,11 @@ import java.util.LinkedList;
 import java.util.List;
 
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.isA;
 import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.CALLS_REAL_METHODS;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -130,6 +137,25 @@ class SelectStatementBinderTest {
                 .getColumnBoundInfo().getOriginalTable().getValue(), 
is("t_order"));
     }
     
+    @Test
+    void assertBindWithStatementAttributes() {
+        ParameterMarkerExpressionSegment parameterMarker = new 
ParameterMarkerExpressionSegment(0, 0, 0);
+        ProjectionsSegment projections = new ProjectionsSegment(0, 0);
+        projections.getProjections().add(new ColumnProjectionSegment(new 
ColumnSegment(0, 0, new IdentifierValue("foo_variable"))));
+        BinaryOperationExpression predicate = new BinaryOperationExpression(0, 
0, new ColumnSegment(0, 0, new IdentifierValue("order_id")), parameterMarker, 
"=", "order_id = ?");
+        SelectStatement selectStatement = 
SelectStatement.builder().databaseType(databaseType).projections(projections)
+                .from(new SimpleTableSegment(new TableNameSegment(0, 0, new 
IdentifierValue("t_order")))).where(new WhereSegment(0, 0, predicate)).build();
+        CommentSegment comment = new CommentSegment("/* foo_comment */", 0, 
16);
+        
selectStatement.addParameterMarkers(Collections.singletonList(parameterMarker));
+        selectStatement.getVariableNames().add("foo_variable");
+        selectStatement.getComments().add(comment);
+        SelectStatement actual = new 
SelectStatementBinder().bind(selectStatement, new 
SQLStatementBinderContext(mockMetaData(), "foo_db", new HintValueContext(), 
selectStatement));
+        assertThat(actual.getParameterMarkers(), contains(parameterMarker));
+        assertThat(actual.getParameterCount(), is(1));
+        assertThat(actual.getVariableNames(), contains("foo_variable"));
+        assertThat(actual.getComments(), contains(comment));
+    }
+    
     @Test
     void assertBindWholeRowProjection() {
         DatabaseType protocolType = mock(DatabaseType.class);
@@ -151,6 +177,40 @@ class SelectStatementBinderTest {
         }
     }
     
+    @ParameterizedTest(name = "{0}: qualified={1}, nested={2}")
+    @CsvSource({"PostgreSQL, true, false", "PostgreSQL, false, true", 
"FIXTURE, false, false"})
+    void assertBindWholeRowProjectionExclusions(final String databaseTypeName, 
final boolean qualified, final boolean nested) {
+        ColumnSegment column = new ColumnSegment(0, 0, new 
IdentifierValue("o"));
+        if (qualified) {
+            column.setOwner(new OwnerSegment(0, 0, new IdentifierValue("o")));
+        }
+        if (nested) {
+            column.setNestedObjectAttributes(Collections.singletonList(new 
IdentifierValue("foo_attribute")));
+        }
+        ProjectionsSegment projections = new ProjectionsSegment(0, 0);
+        projections.getProjections().add(new ColumnProjectionSegment(column));
+        SimpleTableSegment table = createAliasedSimpleTableSegment("t_order", 
"o");
+        table.setOwner(new OwnerSegment(0, 0, new IdentifierValue("foo_db")));
+        SelectStatement selectStatement = 
SelectStatement.builder().databaseType(TypedSPILoader.getService(DatabaseType.class,
 databaseTypeName)).projections(projections).from(table).build();
+        SQLStatementBinderContext binderContext = new 
SQLStatementBinderContext(mockMetaData(), "foo_db", new HintValueContext(), 
selectStatement);
+        assertThrows(ColumnNotFoundException.class, () -> new 
SelectStatementBinder().bind(selectStatement, binderContext));
+    }
+    
+    @Test
+    void assertBindWholeRowProjectionWithSameNameColumn() {
+        ProjectionsSegment projections = new ProjectionsSegment(0, 0);
+        projections.getProjections().add(new ColumnProjectionSegment(new 
ColumnSegment(0, 0, new IdentifierValue("order_id"))));
+        SimpleTableSegment table = createAliasedSimpleTableSegment("t_order", 
"order_id");
+        table.setOwner(new OwnerSegment(0, 0, new IdentifierValue("foo_db")));
+        SelectStatement selectStatement = 
SelectStatement.builder().databaseType(TypedSPILoader.getService(DatabaseType.class,
 "PostgreSQL")).projections(projections).from(table).build();
+        SelectStatement actual = new 
SelectStatementBinder().bind(selectStatement, new 
SQLStatementBinderContext(mockMetaData(), "foo_db", new HintValueContext(), 
selectStatement));
+        ProjectionSegment actualProjection = 
actual.getProjections().getProjections().iterator().next();
+        assertThat(actualProjection, isA(ColumnProjectionSegment.class));
+        ColumnSegment actualColumn = ((ColumnProjectionSegment) 
actualProjection).getColumn();
+        
assertThat(actualColumn.getColumnBoundInfo().getOriginalTable().getValue(), 
is("t_order"));
+        
assertThat(actualColumn.getColumnBoundInfo().getOriginalColumn().getValue(), 
is("order_id"));
+    }
+    
     @Test
     void assertBindHierarchicalQuery() {
         ProjectionsSegment projections = new ProjectionsSegment(0, 0);

Reply via email to