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")));