This is an automated email from the ASF dual-hosted git repository.
zhaojinchao 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 00bef892d9c support bind update set assignment (#28688)
00bef892d9c is described below
commit 00bef892d9c9faf3469e7f5f7f8e644206a2b692
Author: Chuxin Chen <[email protected]>
AuthorDate: Mon Oct 9 14:02:02 2023 +0800
support bind update set assignment (#28688)
* support bind update set assignment
* support bind update set assignment
* support bind update set assignment
---
.../checker/ShardingRouteCacheableCheckerTest.java | 5 +-
.../segment/assign/AssignmentSegmentBinder.java | 80 ++++++++++++++++++++++
.../expression/impl/ColumnSegmentBinder.java | 2 +-
.../projection/ProjectionsSegmentBinder.java | 10 +++
.../statement/dml/UpdateStatementBinder.java | 3 +-
.../assign/AssignmentSegmentBinderTest.java | 63 +++++++++++++++++
.../dml/item/ExpressionProjectionSegment.java | 9 +++
.../parse/PostgreSQLComParseExecutorTest.java | 3 +-
.../statement/ShardingPreparedStatementTest.java | 8 +--
9 files changed, 173 insertions(+), 10 deletions(-)
diff --git
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckerTest.java
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckerTest.java
index d05ec28ea72..cb2c40decf9 100644
---
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckerTest.java
+++
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckerTest.java
@@ -111,8 +111,9 @@ class ShardingRouteCacheableCheckerTest {
private ShardingSphereDatabase createDatabase(final ShardingRule
shardingRule, final TimestampServiceRule timestampServiceRule) {
ShardingSphereSchema schema = new ShardingSphereSchema();
- schema.getTables().put("t_warehouse", new
ShardingSphereTable("t_warehouse",
- Collections.singletonList(new ShardingSphereColumn("id",
Types.INTEGER, true, false, false, true, false, false)),
+ schema.getTables().put("t_warehouse", new
ShardingSphereTable("t_warehouse", Arrays.asList(
+ new ShardingSphereColumn("id", Types.INTEGER, true, false,
false, true, false, false),
+ new ShardingSphereColumn("warehouse_name", Types.VARCHAR,
false, false, false, true, false, false)),
Collections.emptyList(), Collections.emptyList()));
schema.getTables().put("t_order", new ShardingSphereTable("t_order",
Arrays.asList(
new ShardingSphereColumn("warehouse_id", Types.INTEGER, false,
false, false, true, false, false),
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/assign/AssignmentSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/assign/AssignmentSegmentBinder.java
new file mode 100644
index 00000000000..c5840b7f0a2
--- /dev/null
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/assign/AssignmentSegmentBinder.java
@@ -0,0 +1,80 @@
+/*
+ * 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.segment.assign;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.infra.binder.enums.SegmentType;
+import
org.apache.shardingsphere.infra.binder.segment.expression.ExpressionSegmentBinder;
+import
org.apache.shardingsphere.infra.binder.segment.expression.impl.ColumnSegmentBinder;
+import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
+import
org.apache.shardingsphere.infra.binder.statement.SQLStatementBinderContext;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.AssignmentSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.ColumnAssignmentSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.SetAssignmentSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Assignment segment binder.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class AssignmentSegmentBinder {
+
+ /**
+ * Bind assignment segment.
+ *
+ * @param segment assignment segment
+ * @param statementBinderContext statement binder context
+ * @param tableBinderContexts table binder contexts
+ * @param outerTableBinderContexts outer table binder contexts
+ * @return bound assignment segment
+ */
+ public static SetAssignmentSegment bind(final SetAssignmentSegment
segment, final SQLStatementBinderContext statementBinderContext,
+ final Map<String,
TableSegmentBinderContext> tableBinderContexts, final Map<String,
TableSegmentBinderContext> outerTableBinderContexts) {
+ Collection<AssignmentSegment> assignments = new LinkedList<>();
+ for (AssignmentSegment each : segment.getAssignments()) {
+ if (each instanceof ColumnAssignmentSegment) {
+ assignments.add(new
ColumnAssignmentSegment(each.getStartIndex(), each.getStopIndex(),
bindColumns(each.getColumns(), statementBinderContext, tableBinderContexts,
+ outerTableBinderContexts), bindValue(each.getValue(),
statementBinderContext, tableBinderContexts, outerTableBinderContexts)));
+ } else {
+ assignments.add(each);
+ }
+ }
+ return new SetAssignmentSegment(segment.getStartIndex(),
segment.getStopIndex(), assignments);
+ }
+
+ private static List<ColumnSegment> bindColumns(final List<ColumnSegment>
columns, final SQLStatementBinderContext statementBinderContext,
+ final Map<String,
TableSegmentBinderContext> tableBinderContexts, final Map<String,
TableSegmentBinderContext> outerTableBinderContexts) {
+ List<ColumnSegment> result = new LinkedList<>();
+ for (ColumnSegment each : columns) {
+ result.add(ColumnSegmentBinder.bind(each,
SegmentType.SET_ASSIGNMENT, statementBinderContext, tableBinderContexts,
outerTableBinderContexts));
+ }
+ return result;
+ }
+
+ private static ExpressionSegment bindValue(final ExpressionSegment value,
final SQLStatementBinderContext statementBinderContext,
+ final Map<String,
TableSegmentBinderContext> tableBinderContexts, final Map<String,
TableSegmentBinderContext> outerTableBinderContexts) {
+ return ExpressionSegmentBinder.bind(value, SegmentType.SET_ASSIGNMENT,
statementBinderContext, tableBinderContexts, outerTableBinderContexts);
+ }
+}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
index d59a8884b18..e2cd1ca9632 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/expression/impl/ColumnSegmentBinder.java
@@ -53,7 +53,7 @@ import java.util.Optional;
public final class ColumnSegmentBinder {
private static final Collection<String> EXCLUDE_BIND_COLUMNS = new
LinkedHashSet<>(Arrays.asList("ROWNUM", "ROW_NUMBER", "ROWNUM_", "SYSDATE",
"SYSTIMESTAMP", "CURRENT_TIMESTAMP",
- "LOCALTIMESTAMP", "UID", "USER", "NEXTVAL", "ROWID"));
+ "LOCALTIMESTAMP", "UID", "USER", "NEXTVAL", "ROWID", "LEVEL"));
private static final Map<SegmentType, String> SEGMENT_TYPE_MESSAGES =
Maps.of(SegmentType.PROJECTION, "field list", SegmentType.JOIN_ON, "on clause",
SegmentType.JOIN_USING, "from clause",
SegmentType.PREDICATE, "where clause", SegmentType.ORDER_BY,
"order clause", SegmentType.GROUP_BY, "group statement",
SegmentType.INSERT_COLUMNS, "field list");
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
index 62cd4b7e67f..407b6c5a35d 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
@@ -19,12 +19,15 @@ package
org.apache.shardingsphere.infra.binder.segment.projection;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.infra.binder.enums.SegmentType;
+import
org.apache.shardingsphere.infra.binder.segment.expression.ExpressionSegmentBinder;
import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
import
org.apache.shardingsphere.infra.binder.segment.projection.impl.ColumnProjectionSegmentBinder;
import
org.apache.shardingsphere.infra.binder.segment.projection.impl.ShorthandProjectionSegmentBinder;
import
org.apache.shardingsphere.infra.binder.segment.projection.impl.SubqueryProjectionSegmentBinder;
import
org.apache.shardingsphere.infra.binder.statement.SQLStatementBinderContext;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ExpressionProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionsSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
@@ -73,6 +76,13 @@ public final class ProjectionsSegmentBinder {
newOuterTableBinderContexts.putAll(tableBinderContexts);
return
SubqueryProjectionSegmentBinder.bind((SubqueryProjectionSegment)
projectionSegment, statementBinderContext, newOuterTableBinderContexts);
}
+ if (projectionSegment instanceof ExpressionProjectionSegment) {
+ ExpressionProjectionSegment result = new
ExpressionProjectionSegment(projectionSegment.getStartIndex(),
projectionSegment.getStopIndex(),
+ ((ExpressionProjectionSegment)
projectionSegment).getText(),
ExpressionSegmentBinder.bind(((ExpressionProjectionSegment)
projectionSegment).getExpr(), SegmentType.PROJECTION,
+ statementBinderContext, tableBinderContexts,
outerTableBinderContexts));
+ result.setAlias(((ExpressionProjectionSegment)
projectionSegment).getAliasSegment());
+ return result;
+ }
// TODO support more ProjectionSegment bind
return projectionSegment;
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/UpdateStatementBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/UpdateStatementBinder.java
index c2f6ad07a9d..6afaf19f3a1 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/UpdateStatementBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/UpdateStatementBinder.java
@@ -18,6 +18,7 @@
package org.apache.shardingsphere.infra.binder.statement.dml;
import lombok.SneakyThrows;
+import
org.apache.shardingsphere.infra.binder.segment.assign.AssignmentSegmentBinder;
import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinder;
import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
import org.apache.shardingsphere.infra.binder.segment.where.WhereSegmentBinder;
@@ -51,7 +52,7 @@ public final class UpdateStatementBinder implements
SQLStatementBinder<UpdateSta
statementBinderContext.getExternalTableBinderContexts().putAll(externalTableBinderContexts);
TableSegment boundedTableSegment =
TableSegmentBinder.bind(sqlStatement.getTable(), statementBinderContext,
tableBinderContexts, Collections.emptyMap());
result.setTable(boundedTableSegment);
- result.setSetAssignment(sqlStatement.getSetAssignment());
+ sqlStatement.getAssignmentSegment().ifPresent(optional ->
result.setSetAssignment(AssignmentSegmentBinder.bind(optional,
statementBinderContext, tableBinderContexts, Collections.emptyMap())));
sqlStatement.getWhere().ifPresent(optional ->
result.setWhere(WhereSegmentBinder.bind(optional, statementBinderContext,
tableBinderContexts, Collections.emptyMap())));
UpdateStatementHandler.getOrderBySegment(sqlStatement).ifPresent(optional ->
UpdateStatementHandler.setOrderBySegment(result, optional));
UpdateStatementHandler.getLimitSegment(sqlStatement).ifPresent(optional ->
UpdateStatementHandler.setLimitSegment(result, optional));
diff --git
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/assign/AssignmentSegmentBinderTest.java
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/assign/AssignmentSegmentBinderTest.java
new file mode 100644
index 00000000000..38971df6c15
--- /dev/null
+++
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/assign/AssignmentSegmentBinderTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.segment.assign;
+
+import
org.apache.shardingsphere.infra.binder.segment.from.SimpleTableSegmentBinderContext;
+import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
+import
org.apache.shardingsphere.infra.binder.statement.SQLStatementBinderContext;
+import org.apache.shardingsphere.infra.database.core.DefaultDatabase;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.AssignmentSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.ColumnAssignmentSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.SetAssignmentSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.bounded.ColumnSegmentBoundedInfo;
+import
org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.mockito.Mockito.mock;
+
+class AssignmentSegmentBinderTest {
+
+ @Test
+ void assertBindAssignmentSegment() {
+ Collection<AssignmentSegment> assignments = new LinkedList<>();
+ Map<String, TableSegmentBinderContext> tableBinderContexts = new
LinkedHashMap<>();
+ ColumnSegment boundedOrderIdColumn = new ColumnSegment(0, 0, new
IdentifierValue("order_id"));
+ boundedOrderIdColumn.setColumnBoundedInfo(new
ColumnSegmentBoundedInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new
IdentifierValue(DefaultDatabase.LOGIC_NAME),
+ new IdentifierValue("t_order"), new
IdentifierValue("order_id")));
+ tableBinderContexts.put("t_order", new
SimpleTableSegmentBinderContext(Collections.singleton(new
ColumnProjectionSegment(boundedOrderIdColumn))));
+ ColumnSegment columnSegment = new ColumnSegment(0, 0, new
IdentifierValue("order_id"));
+ assignments.add(new ColumnAssignmentSegment(0, 0,
Collections.singletonList(columnSegment), new LiteralExpressionSegment(0, 0,
1)));
+ SetAssignmentSegment setAssignmentSegment = new
SetAssignmentSegment(0, 0, assignments);
+ SetAssignmentSegment actual =
AssignmentSegmentBinder.bind(setAssignmentSegment,
mock(SQLStatementBinderContext.class), tableBinderContexts,
Collections.emptyMap());
+ assertThat(actual, not(setAssignmentSegment));
+ assertThat(actual.getAssignments().iterator().next(),
not(setAssignmentSegment.getAssignments().iterator().next()));
+
assertThat(actual.getAssignments().iterator().next().getColumns().iterator().next().getColumnBoundedInfo().getOriginalTable().getValue(),
is("t_order"));
+ }
+}
diff --git
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/ExpressionProjectionSegment.java
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/ExpressionProjectionSegment.java
index f031e60d12b..2373529a8e3 100644
---
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/ExpressionProjectionSegment.java
+++
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/item/ExpressionProjectionSegment.java
@@ -74,6 +74,15 @@ public final class ExpressionProjectionSegment implements
ProjectionSegment, Com
return Optional.ofNullable(alias).map(AliasSegment::getIdentifier);
}
+ /**
+ * Get alias segment.
+ *
+ * @return alias segment
+ */
+ public AliasSegment getAliasSegment() {
+ return alias;
+ }
+
@Override
public int getStopIndex() {
return null == alias ? stopIndex : alias.getStopIndex();
diff --git
a/proxy/frontend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/parse/PostgreSQLComParseExecutorTest.java
b/proxy/frontend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/parse/PostgreSQLComParseExecutorTest.java
index 8efe4f38e28..8e99c4e958b 100644
---
a/proxy/frontend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/parse/PostgreSQLComParseExecutorTest.java
+++
b/proxy/frontend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/parse/PostgreSQLComParseExecutorTest.java
@@ -189,7 +189,8 @@ class PostgreSQLComParseExecutorTest {
.thenReturn(new RuleMetaData(Collections.singleton(new
SQLParserRule(new DefaultSQLParserRuleConfigurationBuilder().build()))));
ShardingSphereTable testTable = new ShardingSphereTable("t_test",
Arrays.asList(new ShardingSphereColumn("id", Types.BIGINT, true, false, false,
false, true, false),
new ShardingSphereColumn("name", Types.VARCHAR, false, false,
false, false, false, false),
- new ShardingSphereColumn("age", Types.SMALLINT, false, false,
false, false, true, false)), Collections.emptyList(), Collections.emptyList());
+ new ShardingSphereColumn("age", Types.SMALLINT, false, false,
false, false, true, false),
+ new ShardingSphereColumn("enabled", Types.VARCHAR, false,
false, false, false, true, false)), Collections.emptyList(),
Collections.emptyList());
ShardingSphereTable sbTestTable = new ShardingSphereTable("sbtest1",
Arrays.asList(new ShardingSphereColumn("id", Types.BIGINT, true, false, false,
false, true, false),
new ShardingSphereColumn("k", Types.VARCHAR, false, false,
false, false, false, false),
new ShardingSphereColumn("c", Types.VARCHAR, false, false,
false, false, true, false),
diff --git
a/test/e2e/driver/src/test/java/org/apache/shardingsphere/test/e2e/driver/statement/ShardingPreparedStatementTest.java
b/test/e2e/driver/src/test/java/org/apache/shardingsphere/test/e2e/driver/statement/ShardingPreparedStatementTest.java
index 0cb5c99e55a..c4b59660d63 100644
---
a/test/e2e/driver/src/test/java/org/apache/shardingsphere/test/e2e/driver/statement/ShardingPreparedStatementTest.java
+++
b/test/e2e/driver/src/test/java/org/apache/shardingsphere/test/e2e/driver/statement/ShardingPreparedStatementTest.java
@@ -17,6 +17,7 @@
package org.apache.shardingsphere.test.e2e.driver.statement;
+import org.apache.shardingsphere.infra.exception.UnknownColumnException;
import org.apache.shardingsphere.test.e2e.driver.AbstractShardingDriverTest;
import
org.apache.shardingsphere.test.e2e.driver.fixture.keygen.ResetIncrementKeyGenerateAlgorithmFixture;
import org.junit.jupiter.api.Test;
@@ -606,10 +607,7 @@ class ShardingPreparedStatementTest extends
AbstractShardingDriverTest {
}
@Test
- void assertColumnNotFoundException() throws SQLException {
- try (PreparedStatement preparedStatement =
getShardingSphereDataSource().getConnection().prepareStatement(UPDATE_WITH_ERROR_COLUMN))
{
- preparedStatement.setString(1, "OK");
- assertThrows(SQLException.class, preparedStatement::executeUpdate);
- }
+ void assertColumnNotFoundException() {
+ assertThrows(UnknownColumnException.class, () ->
getShardingSphereDataSource().getConnection().prepareStatement(UPDATE_WITH_ERROR_COLUMN));
}
}