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 359c22f449f Fix recursive CTE binding when anchor query uses shorthand 
projection (#40073)
359c22f449f is described below

commit 359c22f449f13f7b77c3cdfe7354181575e8be54
Author: Eunbin Son <[email protected]>
AuthorDate: Fri Oct 16 15:15:34 2026 +0900

    Fix recursive CTE binding when anchor query uses shorthand projection 
(#40073)
    
    * Fix recursive CTE binding when anchor query uses shorthand projection
    
    * Simplify recursive CTE shorthand projection binder test
    
    Pass Collections.singleton directly to WithSegment because binding only 
iterates the common table expressions, and keep the bind invocation on one line 
since it fits within 200 characters.
---
 RELEASE-NOTES.md                                   |  1 +
 .../with/CommonTableExpressionSegmentBinder.java   | 20 ++++-------------
 .../statement/dml/SelectStatementBinderTest.java   | 25 ++++++++++++++++++++++
 3 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index c99eca3b9a9..0f60230e23a 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -50,6 +50,7 @@
 1. SQL Binder: Fix wrong column label case for PostgreSQL and openGauss 
function projections - 
[#39393](https://github.com/apache/shardingsphere/pull/39393)
 1. SQL Binder: Bind PostgreSQL SYSTEM_USER as a niladic function instead of a 
column - [#39385](https://github.com/apache/shardingsphere/pull/39385)
 1. SQL Binder: Preserve RETURNING clause when binding UPDATE and DELETE 
statements - [#40070](https://github.com/apache/shardingsphere/pull/40070)
+1. SQL Binder: Fix recursive CTE binding when anchor query uses shorthand 
projection - [#40073](https://github.com/apache/shardingsphere/pull/40073)
 1. Metadata: Fix MySQL metadata loading fallback when JDBC catalog is null for 
named tables - [#38855](https://github.com/apache/shardingsphere/pull/38855)
 1. Metadata: Fix Oracle metadata version comparison skipping identity and 
collation columns on 18c and later - 
[#39104](https://github.com/apache/shardingsphere/pull/39104)
 1. Metadata: Fix wrong logic table metadata when config same actual table name 
in different storage unit - 
[#39157](https://github.com/apache/shardingsphere/pull/39157)
diff --git 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/with/CommonTableExpressionSegmentBinder.java
 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/with/CommonTableExpressionSegmentBinder.java
index 765c2134928..841060696d5 100644
--- 
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/with/CommonTableExpressionSegmentBinder.java
+++ 
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/with/CommonTableExpressionSegmentBinder.java
@@ -131,23 +131,11 @@ public final class CommonTableExpressionSegmentBinder {
     }
     
     private static Collection<ProjectionSegment> 
createRecursiveWithProjections(final CommonTableExpressionSegment segment, 
final SQLStatementBinderContext binderContext) {
-        Collection<ColumnSegment> definitionColumns = 
getDefinitionColumns(segment.getColumns(), segment.getSubquery());
-        if (!definitionColumns.isEmpty()) {
-            SelectStatement boundAnchorSelect = bindAnchorSelect(segment, 
binderContext);
-            Collection<ProjectionSegment> subqueryProjections = 
SubqueryTableBindUtils.createSubqueryProjections(
-                    boundAnchorSelect.getProjections().getProjections(), new 
IdentifierValue(""), binderContext.getSqlStatement().getDatabaseType(), 
TableSourceType.TEMPORARY_TABLE);
-            return createBoundDefinitionColumns(definitionColumns, 
subqueryProjections);
-        }
-        Collection<ProjectionSegment> result = new LinkedList<>();
         SelectStatement boundAnchorSelect = bindAnchorSelect(segment, 
binderContext);
-        for (ProjectionSegment each : 
boundAnchorSelect.getProjections().getProjections()) {
-            if (each instanceof ColumnProjectionSegment) {
-                result.add(new 
ColumnProjectionSegment(((ColumnProjectionSegment) each).getColumn()));
-            } else {
-                result.add(new ColumnProjectionSegment(new 
ColumnSegment(each.getStartIndex(), each.getStopIndex(), new 
IdentifierValue(each.getColumnLabel()))));
-            }
-        }
-        return result;
+        Collection<ProjectionSegment> subqueryProjections = 
SubqueryTableBindUtils.createSubqueryProjections(
+                boundAnchorSelect.getProjections().getProjections(), new 
IdentifierValue(""), binderContext.getSqlStatement().getDatabaseType(), 
TableSourceType.TEMPORARY_TABLE);
+        Collection<ColumnSegment> definitionColumns = 
getDefinitionColumns(segment.getColumns(), segment.getSubquery());
+        return definitionColumns.isEmpty() ? subqueryProjections : 
createBoundDefinitionColumns(definitionColumns, subqueryProjections);
     }
     
     private static SelectStatement bindAnchorSelect(final 
CommonTableExpressionSegment segment, final SQLStatementBinderContext 
binderContext) {
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 1d6a6d38365..a5521e5f34a 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
@@ -495,6 +495,31 @@ class SelectStatementBinderTest {
         
assertThat(actualCycleColumn.getColumnBoundInfo().getTableSourceType().name(), 
is("TEMPORARY_TABLE"));
     }
     
+    @Test
+    void assertBindRecursiveCteWithShorthandAnchorProjection() {
+        ProjectionsSegment anchorProjections = new ProjectionsSegment(0, 0);
+        anchorProjections.getProjections().add(new 
ShorthandProjectionSegment(0, 0));
+        SelectStatement anchorSelect = 
SelectStatement.builder().databaseType(databaseType).projections(anchorProjections)
+                .from(new SimpleTableSegment(new TableNameSegment(0, 0, new 
IdentifierValue("t_order")))).build();
+        SelectStatement recursiveSelect = 
SelectStatement.builder().databaseType(databaseType).projections(createOrderProjections())
+                .from(new SimpleTableSegment(new TableNameSegment(0, 0, new 
IdentifierValue("product_tree")))).build();
+        SelectStatement withSelectStatement = 
SelectStatement.builder().databaseType(databaseType).projections(anchorProjections)
+                .combine(new CombineSegment(0, 0, new SubquerySegment(0, 0, 
anchorSelect, ""), CombineType.UNION_ALL, new SubquerySegment(0, 0, 
recursiveSelect, ""))).build();
+        WithSegment withSegment = new WithSegment(0, 0, 
Collections.singleton(createCommonTableExpression("product_tree", 
withSelectStatement)), true);
+        SelectStatement selectStatement = 
SelectStatement.builder().databaseType(databaseType).with(withSegment).projections(createOrderProjections())
+                .from(new SimpleTableSegment(new TableNameSegment(0, 0, new 
IdentifierValue("product_tree")))).build();
+        SelectStatement actual = new 
SelectStatementBinder().bind(selectStatement, new 
SQLStatementBinderContext(mockMetaData(), "foo_db", new HintValueContext(), 
selectStatement));
+        CommonTableExpressionSegment actualCommonTableExpression = 
actual.getWith().get().getCommonTableExpressions().iterator().next();
+        SelectStatement actualRecursiveSelect = 
actualCommonTableExpression.getSubquery().getSelect().getCombine().get().getRight().getSelect();
+        ColumnSegment actualRecursiveUserIdColumn = ((ColumnProjectionSegment) 
actualRecursiveSelect.getProjections().getProjections().iterator().next()).getColumn();
+        
assertThat(actualRecursiveUserIdColumn.getColumnBoundInfo().getOriginalTable().getValue(),
 is("t_order"));
+        
assertThat(actualRecursiveUserIdColumn.getColumnBoundInfo().getOriginalColumn().getValue(),
 is("user_id"));
+        
assertThat(actualRecursiveUserIdColumn.getColumnBoundInfo().getTableSourceType(),
 is(TableSourceType.TEMPORARY_TABLE));
+        List<ProjectionSegment> actualProjections = new 
ArrayList<>(actual.getProjections().getProjections());
+        assertThat(((ColumnProjectionSegment) 
actualProjections.get(0)).getColumn().getColumnBoundInfo().getOriginalTable().getValue(),
 is("t_order"));
+        assertThat(((ColumnProjectionSegment) 
actualProjections.get(1)).getColumn().getColumnBoundInfo().getOriginalColumn().getValue(),
 is("order_id"));
+    }
+    
     private WhereSegment createWhereSegment() {
         FunctionSegment functionSegment = new FunctionSegment(0, 0, "nvl", 
"nvl(status, 0)");
         functionSegment.getParameters().add(new ColumnSegment(0, 0, new 
IdentifierValue("status")));

Reply via email to