You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2025/07/02 04:39:17 UTC
(shardingsphere) branch master updated: Refactor PaginationContextEngine (#35854)
This is an automated email from the ASF dual-hosted git repository.
zhangliang 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 fd9aa85dd11 Refactor PaginationContextEngine (#35854)
fd9aa85dd11 is described below
commit fd9aa85dd11b18f940d66e6269df69196727c454
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Wed Jul 2 12:39:10 2025 +0800
Refactor PaginationContextEngine (#35854)
* Refactor PaginationContextEngine
* Refactor PaginationContextEngine
---
.../impl/ShardingRemoveTokenGeneratorTest.java | 5 +-
.../pagination/engine/PaginationContextEngine.java | 28 ++++++----
.../statement/type/dml/SelectStatementContext.java | 8 ++-
.../engine/PaginationContextEngineTest.java | 63 +++++++++++++++-------
4 files changed, 72 insertions(+), 32 deletions(-)
diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/generator/impl/ShardingRemoveTokenGeneratorTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/generator/impl/ShardingRemoveTokenGeneratorTest.java
index 0705eeb20d4..805b48a5028 100644
--- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/generator/impl/ShardingRemoveTokenGeneratorTest.java
+++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/generator/impl/ShardingRemoveTokenGeneratorTest.java
@@ -20,10 +20,12 @@ package org.apache.shardingsphere.sharding.rewrite.token.generator.impl;
import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
import org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
import org.apache.shardingsphere.infra.database.core.metadata.database.enums.NullsOrderType;
+import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.SQLToken;
import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.generic.RemoveToken;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.sql.parser.statement.core.enums.AggregationType;
import org.apache.shardingsphere.sql.parser.statement.core.enums.OrderDirection;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationDistinctProjectionSegment;
@@ -83,8 +85,9 @@ class ShardingRemoveTokenGeneratorTest {
selectStatement.setProjections(createProjectionsSegment());
ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS);
when(database.getName()).thenReturn("foo_db");
+ DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
return new SelectStatementContext(
- mock(), selectStatement, Collections.emptyList(), new ShardingSphereMetaData(Collections.singleton(database), mock(), mock(), mock()), "foo_db", Collections.emptyList());
+ databaseType, selectStatement, Collections.emptyList(), new ShardingSphereMetaData(Collections.singleton(database), mock(), mock(), mock()), "foo_db", Collections.emptyList());
}
private ProjectionsSegment createProjectionsSegment() {
diff --git a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/engine/PaginationContextEngine.java b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/engine/PaginationContextEngine.java
index 42830bdb13a..326d1860e23 100644
--- a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/engine/PaginationContextEngine.java
+++ b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/engine/PaginationContextEngine.java
@@ -21,10 +21,9 @@ import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.infra.binder.context.segment.select.pagination.PaginationContext;
import org.apache.shardingsphere.infra.binder.context.segment.select.projection.ProjectionsContext;
import org.apache.shardingsphere.infra.database.core.metadata.database.metadata.option.pagination.DialectPaginationOption;
-import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
-import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.limit.LimitSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.top.TopProjectionSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
@@ -44,7 +43,7 @@ import java.util.Optional;
@RequiredArgsConstructor
public final class PaginationContextEngine {
- private final DatabaseType databaseType;
+ private final DialectPaginationOption paginationOption;
/**
* Create pagination context.
@@ -61,24 +60,35 @@ public final class PaginationContextEngine {
if (limitSegment.isPresent()) {
return new LimitPaginationContextEngine().createPaginationContext(limitSegment.get(), params);
}
- Optional<TopProjectionSegment> topProjectionSegment = findTopProjection(selectStatement);
Collection<ExpressionSegment> expressions = new LinkedList<>();
for (WhereSegment each : whereSegments) {
expressions.add(each.getExpr());
}
+ Optional<TopProjectionSegment> topProjectionSegment = findTopProjection(selectStatement);
if (topProjectionSegment.isPresent()) {
return new TopPaginationContextEngine().createPaginationContext(topProjectionSegment.get(), expressions, params);
}
- if (!expressions.isEmpty()) {
- DialectPaginationOption paginationOption = new DatabaseTypeRegistry(databaseType).getDialectDatabaseMetaData().getPaginationOption();
- if (paginationOption.isContainsRowNumber()) {
- return new RowNumberPaginationContextEngine(paginationOption).createPaginationContext(expressions, projectionsContext, params);
- }
+ if (!expressions.isEmpty() && paginationOption.isContainsRowNumber()) {
+ return new RowNumberPaginationContextEngine(paginationOption).createPaginationContext(expressions, projectionsContext, params);
}
return new PaginationContext(null, null, params);
}
private Optional<TopProjectionSegment> findTopProjection(final SelectStatement selectStatement) {
+ for (ProjectionSegment each : selectStatement.getProjections().getProjections()) {
+ if (each instanceof SubqueryProjectionSegment) {
+ return findTopProjection0(((SubqueryProjectionSegment) each).getSubquery().getSelect());
+ }
+ }
+ return findTopProjection0(selectStatement);
+ }
+
+ private Optional<TopProjectionSegment> findTopProjection0(final SelectStatement selectStatement) {
+ for (ProjectionSegment each : selectStatement.getProjections().getProjections()) {
+ if (each instanceof TopProjectionSegment) {
+ return Optional.of((TopProjectionSegment) each);
+ }
+ }
List<SubqueryTableSegment> subqueryTableSegments = selectStatement.getFrom().map(SQLUtils::getSubqueryTableSegmentFromTableSegment).orElse(Collections.emptyList());
for (SubqueryTableSegment subquery : subqueryTableSegments) {
SelectStatement subquerySelect = subquery.getSubquery().getSelect();
diff --git a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementContext.java b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementContext.java
index 826a5a2f9fc..be283cb9fa0 100644
--- a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementContext.java
+++ b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/type/dml/SelectStatementContext.java
@@ -39,7 +39,9 @@ import org.apache.shardingsphere.infra.binder.context.segment.select.projection.
import org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.SubqueryProjection;
import org.apache.shardingsphere.infra.binder.context.segment.table.TablesContext;
import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
+import org.apache.shardingsphere.infra.database.core.metadata.database.metadata.option.pagination.DialectPaginationOption;
import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
import org.apache.shardingsphere.infra.exception.dialect.exception.syntax.database.NoDatabaseSelectedException;
import org.apache.shardingsphere.infra.exception.dialect.exception.syntax.database.UnknownDatabaseException;
@@ -130,7 +132,8 @@ public final class SelectStatementContext implements SQLStatementContext, WhereC
groupByContext = new GroupByContextEngine().createGroupByContext(sqlStatement);
orderByContext = new OrderByContextEngine(databaseType).createOrderBy(sqlStatement, groupByContext);
projectionsContext = new ProjectionsContextEngine(databaseType).createProjectionsContext(sqlStatement.getProjections(), groupByContext, orderByContext);
- paginationContext = new PaginationContextEngine(databaseType).createPaginationContext(sqlStatement, projectionsContext, params, whereSegments);
+ DialectPaginationOption paginationOption = new DatabaseTypeRegistry(databaseType).getDialectDatabaseMetaData().getPaginationOption();
+ paginationContext = new PaginationContextEngine(paginationOption).createPaginationContext(sqlStatement, projectionsContext, params, whereSegments);
containsEnhancedTable = isContainsEnhancedTable(metaData, tablesContext.getDatabaseNames(), currentDatabaseName);
}
@@ -420,6 +423,7 @@ public final class SelectStatementContext implements SQLStatementContext, WhereC
@Override
public void setUpParameters(final List<Object> params) {
- paginationContext = new PaginationContextEngine(getDatabaseType()).createPaginationContext(sqlStatement, projectionsContext, params, whereSegments);
+ DialectPaginationOption paginationOption = new DatabaseTypeRegistry(databaseType).getDialectDatabaseMetaData().getPaginationOption();
+ paginationContext = new PaginationContextEngine(paginationOption).createPaginationContext(sqlStatement, projectionsContext, params, whereSegments);
}
}
diff --git a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/engine/PaginationContextEngineTest.java b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/engine/PaginationContextEngineTest.java
index 29bbbd9948b..8e4887322e5 100644
--- a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/engine/PaginationContextEngineTest.java
+++ b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/select/pagination/engine/PaginationContextEngineTest.java
@@ -19,16 +19,21 @@ package org.apache.shardingsphere.infra.binder.context.segment.select.pagination
import org.apache.shardingsphere.infra.binder.context.segment.select.pagination.PaginationContext;
import org.apache.shardingsphere.infra.binder.context.segment.select.projection.ProjectionsContext;
-import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
-import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.infra.database.core.metadata.database.metadata.option.pagination.DialectPaginationOption;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
+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.subquery.SubquerySegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.limit.LimitSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.limit.LimitValueSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.limit.NumberLiteralLimitValueSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.rownum.NumberLiteralRowNumberValueSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.top.TopProjectionSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
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 java.util.Collections;
@@ -42,53 +47,71 @@ import static org.mockito.Mockito.mock;
class PaginationContextEngineTest {
@Test
- void assertCreatePaginationContextWhenLimitSegmentIsPresent() {
+ void assertCreatePaginationContextWithLimitSegment() {
SelectStatement selectStatement = new SelectStatement();
selectStatement.setLimit(new LimitSegment(0, 10, new NumberLiteralLimitValueSegment(0, 10, 100L),
- new NumberLiteralLimitValueSegment(0, 10, 100L)));
- PaginationContext paginationContext = new PaginationContextEngine(getDatabaseType("SQL92")).createPaginationContext(
- selectStatement, mock(ProjectionsContext.class), Collections.emptyList(), Collections.emptyList());
+ new NumberLiteralLimitValueSegment(11, 20, 200L)));
+ PaginationContext paginationContext = new PaginationContextEngine(
+ new DialectPaginationOption(false, "")).createPaginationContext(selectStatement, mock(ProjectionsContext.class), Collections.emptyList(), Collections.emptyList());
assertTrue(paginationContext.getOffsetSegment().isPresent());
+ assertThat(paginationContext.getOffsetSegment().get(), instanceOf(LimitValueSegment.class));
assertTrue(paginationContext.getRowCountSegment().isPresent());
+ assertThat(paginationContext.getRowCountSegment().get(), instanceOf(LimitValueSegment.class));
}
@Test
- void assertCreatePaginationContextWhenLimitSegmentAbsentAndTopSegmentPresent() {
+ void assertCreatePaginationContextWithTopSegment() {
SelectStatement subquerySelectStatement = new SelectStatement();
subquerySelectStatement.setProjections(new ProjectionsSegment(0, 0));
- subquerySelectStatement.getProjections().getProjections().add(new TopProjectionSegment(0, 10, null, "rowNumberAlias"));
+ subquerySelectStatement.getProjections().getProjections().add(new TopProjectionSegment(0, 10, null, ""));
SelectStatement selectStatement = new SelectStatement();
selectStatement.setProjections(new ProjectionsSegment(0, 0));
selectStatement.getProjections().getProjections().add(new SubqueryProjectionSegment(new SubquerySegment(0, 0, subquerySelectStatement, ""), ""));
- PaginationContext paginationContext = new PaginationContextEngine(getDatabaseType("SQLServer")).createPaginationContext(
- selectStatement, mock(ProjectionsContext.class), Collections.emptyList(), Collections.emptyList());
+ PaginationContext paginationContext = new PaginationContextEngine(
+ new DialectPaginationOption(false, "")).createPaginationContext(selectStatement, mock(ProjectionsContext.class), Collections.emptyList(), Collections.emptyList());
assertFalse(paginationContext.getOffsetSegment().isPresent());
assertFalse(paginationContext.getRowCountSegment().isPresent());
}
@Test
- void assertCreatePaginationContextWhenLimitSegmentTopSegmentAbsentAndWhereSegmentPresent() {
+ void assertCreatePaginationContextWithWhereAndRowNumberSegment() {
SelectStatement selectStatement = new SelectStatement();
selectStatement.setProjections(new ProjectionsSegment(0, 0));
- WhereSegment where = new WhereSegment(0, 10, null);
+ BinaryOperationExpression binaryOperationExpr = new BinaryOperationExpression(
+ 0, 5, new ColumnSegment(0, 5, new IdentifierValue("ROW_NUMBER")), new LiteralExpressionSegment(5, 10, 100), "<", "");
+ WhereSegment where = new WhereSegment(0, 10, binaryOperationExpr);
selectStatement.setWhere(where);
ProjectionsContext projectionsContext = new ProjectionsContext(0, 0, false, Collections.emptyList());
- PaginationContext paginationContext = new PaginationContextEngine(getDatabaseType("SQLServer")).createPaginationContext(
- selectStatement, projectionsContext, Collections.emptyList(), Collections.singletonList(where));
+ PaginationContext paginationContext = new PaginationContextEngine(
+ new DialectPaginationOption(true, "ROW_NUMBER")).createPaginationContext(selectStatement, projectionsContext, Collections.emptyList(), Collections.singletonList(where));
assertFalse(paginationContext.getOffsetSegment().isPresent());
- assertFalse(paginationContext.getRowCountSegment().isPresent());
+ assertTrue(paginationContext.getRowCountSegment().isPresent());
+ assertThat(paginationContext.getRowCountSegment().get(), instanceOf(NumberLiteralRowNumberValueSegment.class));
}
@Test
- void assertCreatePaginationContextWhenResultIsPaginationContext() {
+ void assertCreatePaginationContextWithWhereAndWithoutRowNumberSegment() {
SelectStatement selectStatement = new SelectStatement();
selectStatement.setProjections(new ProjectionsSegment(0, 0));
+ BinaryOperationExpression binaryOperationExpr = new BinaryOperationExpression(
+ 0, 5, new ColumnSegment(0, 5, new IdentifierValue("ROW_NUMBER")), new LiteralExpressionSegment(5, 10, 100), "<", "");
+ WhereSegment where = new WhereSegment(0, 10, binaryOperationExpr);
+ selectStatement.setWhere(where);
ProjectionsContext projectionsContext = new ProjectionsContext(0, 0, false, Collections.emptyList());
- assertThat(new PaginationContextEngine(getDatabaseType("SQL92")).createPaginationContext(
- selectStatement, projectionsContext, Collections.emptyList(), Collections.emptyList()), instanceOf(PaginationContext.class));
+ PaginationContext paginationContext = new PaginationContextEngine(
+ new DialectPaginationOption(false, "")).createPaginationContext(selectStatement, projectionsContext, Collections.emptyList(), Collections.singletonList(where));
+ assertFalse(paginationContext.getOffsetSegment().isPresent());
+ assertFalse(paginationContext.getRowCountSegment().isPresent());
}
- private DatabaseType getDatabaseType(final String databaseType) {
- return TypedSPILoader.getService(DatabaseType.class, databaseType);
+ @Test
+ void assertCreatePaginationContextWithEmpty() {
+ SelectStatement selectStatement = new SelectStatement();
+ selectStatement.setProjections(new ProjectionsSegment(0, 0));
+ ProjectionsContext projectionsContext = new ProjectionsContext(0, 0, false, Collections.emptyList());
+ PaginationContext paginationContext = new PaginationContextEngine(
+ new DialectPaginationOption(false, "")).createPaginationContext(selectStatement, projectionsContext, Collections.emptyList(), Collections.emptyList());
+ assertFalse(paginationContext.getOffsetSegment().isPresent());
+ assertFalse(paginationContext.getRowCountSegment().isPresent());
}
}