This is an automated email from the ASF dual-hosted git repository.
menghaoran 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 484332cfa1d Fix the generated key column name case insensitivity
error(#32756) (#32763)
484332cfa1d is described below
commit 484332cfa1db442de6ace8956f1d49051047ef4a
Author: ZhangCheng <[email protected]>
AuthorDate: Mon Sep 2 14:52:21 2024 +0800
Fix the generated key column name case insensitivity error(#32756) (#32763)
* Fix the generated key column name case insensitivity error
* Fix the generated key column name case insensitivity error
* Fix the generated key column name case insensitivity error
* Fix the generated key column name case insensitivity error
* Fix the generated key column name case insensitivity error
* Fix the generated key column name case insensitivity error
* Fix the generated key column name case insensitivity error
---
.../keygen/engine/GeneratedKeyContextEngine.java | 27 +++++++++++-----------
.../statement/dml/InsertStatementContext.java | 21 +++++++++++++++--
.../engine/GeneratedKeyContextEngineTest.java | 9 ++++----
.../schema/model/ShardingSphereSchema.java | 10 ++++++++
.../database/schema/model/ShardingSphereTable.java | 4 ++++
.../db/insert_single_with_generate_key_column.xml | 24 +++++++++++++++++++
.../test/resources/cases/dml/e2e-dml-insert.xml | 24 +++++++++++++++++++
.../data/actual/init-sql/mysql/01-actual-init.sql | 1 +
8 files changed, 101 insertions(+), 19 deletions(-)
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/insert/keygen/engine/GeneratedKeyContextEngine.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/insert/keygen/engine/GeneratedKeyContextEngine.java
index 1814c368352..83aa7d0c89b 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/insert/keygen/engine/GeneratedKeyContextEngine.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/insert/keygen/engine/GeneratedKeyContextEngine.java
@@ -17,7 +17,6 @@
package
org.apache.shardingsphere.infra.binder.context.segment.insert.keygen.engine;
-import com.cedarsoftware.util.CaseInsensitiveSet;
import lombok.RequiredArgsConstructor;
import
org.apache.shardingsphere.infra.binder.context.segment.insert.keygen.GeneratedKeyContext;
import
org.apache.shardingsphere.infra.binder.context.segment.insert.values.InsertValueContext;
@@ -30,6 +29,7 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simp
import
org.apache.shardingsphere.sql.parser.statement.core.statement.dml.InsertStatement;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
/**
@@ -45,15 +45,16 @@ public final class GeneratedKeyContextEngine {
/**
* Create generate key context.
*
- * @param insertColumnNames insert column names
+ * @param insertColumnNamesAndIndexes insert column names and indexes
* @param insertValueContexts insert value contexts
* @param params SQL parameters
* @return generate key context
*/
- public Optional<GeneratedKeyContext> createGenerateKeyContext(final
List<String> insertColumnNames, final List<InsertValueContext>
insertValueContexts, final List<Object> params) {
+ public Optional<GeneratedKeyContext> createGenerateKeyContext(final
Map<String, Integer> insertColumnNamesAndIndexes, final
List<InsertValueContext> insertValueContexts,
+ final
List<Object> params) {
String tableName =
Optional.ofNullable(insertStatement.getTable()).map(optional ->
optional.getTableName().getIdentifier().getValue()).orElse("");
- return findGenerateKeyColumn(tableName).map(optional ->
containsGenerateKey(insertColumnNames, optional)
- ? findGeneratedKey(insertColumnNames, insertValueContexts,
params, optional)
+ return findGenerateKeyColumn(tableName).map(optional ->
containsGenerateKey(insertColumnNamesAndIndexes, optional)
+ ? findGeneratedKey(insertColumnNamesAndIndexes,
insertValueContexts, params, optional)
: new GeneratedKeyContext(optional, true));
}
@@ -69,9 +70,9 @@ public final class GeneratedKeyContextEngine {
return Optional.empty();
}
- private boolean containsGenerateKey(final List<String> insertColumnNames,
final String generateKeyColumnName) {
- return insertColumnNames.isEmpty() ?
schema.getVisibleColumnNames(insertStatement.getTable().getTableName().getIdentifier().getValue()).size()
== getValueCountForPerGroup()
- : new
CaseInsensitiveSet<>(insertColumnNames).contains(generateKeyColumnName);
+ private boolean containsGenerateKey(final Map<String, Integer>
insertColumnNamesAndIndexes, final String generateKeyColumnName) {
+ return insertColumnNamesAndIndexes.isEmpty() ?
schema.getVisibleColumnNames(insertStatement.getTable().getTableName().getIdentifier().getValue()).size()
== getValueCountForPerGroup()
+ :
insertColumnNamesAndIndexes.containsKey(generateKeyColumnName);
}
private int getValueCountForPerGroup() {
@@ -88,11 +89,11 @@ public final class GeneratedKeyContextEngine {
return 0;
}
- private GeneratedKeyContext findGeneratedKey(final List<String>
insertColumnNames, final List<InsertValueContext> insertValueContexts,
+ private GeneratedKeyContext findGeneratedKey(final Map<String, Integer>
insertColumnNamesAndIndexes, final List<InsertValueContext> insertValueContexts,
final List<Object> params,
final String generateKeyColumnName) {
GeneratedKeyContext result = new
GeneratedKeyContext(generateKeyColumnName, false);
for (InsertValueContext each : insertValueContexts) {
- ExpressionSegment expression =
each.getValueExpressions().get(findGenerateKeyIndex(insertColumnNames,
generateKeyColumnName.toLowerCase()));
+ ExpressionSegment expression =
each.getValueExpressions().get(findGenerateKeyIndex(insertColumnNamesAndIndexes,
generateKeyColumnName));
if (expression instanceof ParameterMarkerExpressionSegment) {
if (params.isEmpty()) {
continue;
@@ -107,8 +108,8 @@ public final class GeneratedKeyContextEngine {
return result;
}
- private int findGenerateKeyIndex(final List<String> insertColumnNames,
final String generateKeyColumnName) {
- return insertColumnNames.isEmpty() ?
schema.getVisibleColumnNames(insertStatement.getTable().getTableName().getIdentifier().getValue()).indexOf(generateKeyColumnName)
- : insertColumnNames.indexOf(generateKeyColumnName);
+ private int findGenerateKeyIndex(final Map<String, Integer>
insertColumnNamesAndIndexes, final String generateKeyColumnName) {
+ return insertColumnNamesAndIndexes.isEmpty() ?
schema.getVisibleColumnNamesAndIndexes(insertStatement.getTable().getTableName().getIdentifier().getValue()).get(generateKeyColumnName)
+ : insertColumnNamesAndIndexes.get(generateKeyColumnName);
}
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/InsertStatementContext.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/InsertStatementContext.java
index 1c286242341..f86867aa3d7 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/InsertStatementContext.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/InsertStatementContext.java
@@ -17,6 +17,7 @@
package org.apache.shardingsphere.infra.binder.context.statement.dml;
+import com.cedarsoftware.util.CaseInsensitiveMap;
import lombok.Getter;
import org.apache.shardingsphere.infra.binder.context.aware.ParameterAware;
import
org.apache.shardingsphere.infra.binder.context.segment.insert.keygen.GeneratedKeyContext;
@@ -52,6 +53,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
@@ -66,6 +68,8 @@ public final class InsertStatementContext extends
CommonSQLStatementContext impl
private final List<String> insertColumnNames;
+ private final Map<String, Integer> insertColumnNamesAndIndexes;
+
private final List<List<ExpressionSegment>> valueExpressions;
@Getter
@@ -99,7 +103,20 @@ public final class InsertStatementContext extends
CommonSQLStatementContext impl
ShardingSphereSchema schema = getSchema(metaData, currentDatabaseName);
columnNames = containsInsertColumns() ? insertColumnNames
: Optional.ofNullable(sqlStatement.getTable()).map(optional ->
schema.getVisibleColumnNames(optional.getTableName().getIdentifier().getValue())).orElseGet(Collections::emptyList);
- generatedKeyContext = new GeneratedKeyContextEngine(sqlStatement,
schema).createGenerateKeyContext(insertColumnNames, insertValueContexts,
params).orElse(null);
+ insertColumnNamesAndIndexes =
createInsertColumnNamesAndIndexes(sqlStatement, schema, insertColumnNames);
+ generatedKeyContext = new GeneratedKeyContextEngine(sqlStatement,
schema).createGenerateKeyContext(insertColumnNamesAndIndexes,
insertValueContexts, params).orElse(null);
+ }
+
+ private Map<String, Integer> createInsertColumnNamesAndIndexes(final
InsertStatement sqlStatement, final ShardingSphereSchema schema, final
List<String> insertColumnNames) {
+ if (containsInsertColumns()) {
+ Map<String, Integer> result = new
CaseInsensitiveMap<>(insertColumnNames.size(), 1F);
+ int index = 0;
+ for (String each : insertColumnNames) {
+ result.put(each, index++);
+ }
+ return result;
+ }
+ return Collections.emptyMap();
}
private List<InsertValueContext> getInsertValueContexts(final List<Object>
params, final AtomicInteger paramsOffset, final List<List<ExpressionSegment>>
valueExpressions) {
@@ -273,6 +290,6 @@ public final class InsertStatementContext extends
CommonSQLStatementContext impl
insertSelectContext = getInsertSelectContext(metaData, params,
parametersOffset, currentDatabaseName).orElse(null);
onDuplicateKeyUpdateValueContext =
getOnDuplicateKeyUpdateValueContext(params, parametersOffset).orElse(null);
ShardingSphereSchema schema = getSchema(metaData, currentDatabaseName);
- generatedKeyContext = new GeneratedKeyContextEngine(getSqlStatement(),
schema).createGenerateKeyContext(insertColumnNames, insertValueContexts,
params).orElse(null);
+ generatedKeyContext = new GeneratedKeyContextEngine(getSqlStatement(),
schema).createGenerateKeyContext(insertColumnNamesAndIndexes,
insertValueContexts, params).orElse(null);
}
}
diff --git
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/insert/keygen/engine/GeneratedKeyContextEngineTest.java
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/insert/keygen/engine/GeneratedKeyContextEngineTest.java
index 659070cb4b0..ede9e8f3e9d 100644
---
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/insert/keygen/engine/GeneratedKeyContextEngineTest.java
+++
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/context/segment/insert/keygen/engine/GeneratedKeyContextEngineTest.java
@@ -17,6 +17,7 @@
package
org.apache.shardingsphere.infra.binder.context.segment.insert.keygen.engine;
+import com.cedarsoftware.util.CaseInsensitiveMap;
import com.google.common.collect.ImmutableMap;
import
org.apache.shardingsphere.infra.binder.context.segment.insert.keygen.GeneratedKeyContext;
import
org.apache.shardingsphere.infra.binder.context.segment.insert.values.InsertValueContext;
@@ -96,7 +97,7 @@ class GeneratedKeyContextEngineTest {
private void
assertCreateGenerateKeyContextWithoutGenerateKeyColumnConfiguration(final
InsertStatement insertStatement) {
insertStatement.setTable(new SimpleTableSegment(new
TableNameSegment(0, 0, new IdentifierValue("tbl1"))));
insertStatement.setInsertColumns(new InsertColumnsSegment(0, 0,
Collections.singletonList(new ColumnSegment(0, 0, new IdentifierValue("id")))));
- assertFalse(new GeneratedKeyContextEngine(insertStatement,
schema).createGenerateKeyContext(Collections.emptyList(),
+ assertFalse(new GeneratedKeyContextEngine(insertStatement,
schema).createGenerateKeyContext(Collections.emptyMap(),
Collections.emptyList(),
Collections.singletonList(1)).isPresent());
}
@@ -141,7 +142,7 @@ class GeneratedKeyContextEngineTest {
InsertValueContext insertValueContext = new
InsertValueContext(expressionSegments, Collections.emptyList(), 0);
insertStatement.getValues().add(new InsertValuesSegment(0, 0,
expressionSegments));
Optional<GeneratedKeyContext> actual = new
GeneratedKeyContextEngine(insertStatement, schema)
- .createGenerateKeyContext(Collections.singletonList("id"),
Collections.singletonList(insertValueContext), Collections.singletonList(1));
+ .createGenerateKeyContext(new
CaseInsensitiveMap<>(Collections.singletonMap("id", 0)),
Collections.singletonList(insertValueContext), Collections.singletonList(1));
assertTrue(actual.isPresent());
assertThat(actual.get().getGeneratedValues().size(), is(1));
}
@@ -181,13 +182,13 @@ class GeneratedKeyContextEngineTest {
List<InsertValueContext> insertValueContexts =
insertStatement.getValues().stream()
.map(each -> new InsertValueContext(each.getValues(),
Collections.emptyList(), 0)).collect(Collectors.toList());
Optional<GeneratedKeyContext> actual = new
GeneratedKeyContextEngine(insertStatement, schema)
- .createGenerateKeyContext(Collections.singletonList("id"),
insertValueContexts, Collections.singletonList(1));
+ .createGenerateKeyContext(Collections.singletonMap("id", 0),
insertValueContexts, Collections.singletonList(1));
assertTrue(actual.isPresent());
assertThat(actual.get().getGeneratedValues().size(), is(3));
Iterator<Comparable<?>> generatedValuesIterator =
actual.get().getGeneratedValues().iterator();
assertThat(generatedValuesIterator.next(), is(1));
assertThat(generatedValuesIterator.next(), is(100));
assertThat(generatedValuesIterator.next(), is("value"));
- assertTrue(new GeneratedKeyContextEngine(insertStatement,
schema).createGenerateKeyContext(Collections.emptyList(),
Collections.emptyList(), Collections.singletonList(1)).isPresent());
+ assertTrue(new GeneratedKeyContextEngine(insertStatement,
schema).createGenerateKeyContext(Collections.emptyMap(),
Collections.emptyList(), Collections.singletonList(1)).isPresent());
}
}
diff --git
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchema.java
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchema.java
index d19254dee17..3d748287706 100644
---
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchema.java
+++
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchema.java
@@ -202,6 +202,16 @@ public final class ShardingSphereSchema {
return containsTable(tableName) ?
getTable(tableName).getVisibleColumns() : Collections.emptyList();
}
+ /**
+ * Get visible column names and indexes via table.
+ *
+ * @param tableName table name
+ * @return visible column names and indexes
+ */
+ public Map<String, Integer> getVisibleColumnNamesAndIndexes(final String
tableName) {
+ return containsTable(tableName) ?
getTable(tableName).getVisibleColumnsAndIndexes() : Collections.emptyMap();
+ }
+
/**
* Schema is empty or not.
* @return true if tables and views are all empty, else false
diff --git
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereTable.java
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereTable.java
index bd5eb1db5a5..b87cf50b9c6 100644
---
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereTable.java
+++
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereTable.java
@@ -49,6 +49,8 @@ public final class ShardingSphereTable {
private final List<String> visibleColumns = new ArrayList<>();
+ private final Map<String, Integer> visibleColumnsAndIndexes = new
CaseInsensitiveMap<>();
+
private final List<String> primaryKeyColumns = new ArrayList<>();
private final TableType type;
@@ -77,6 +79,7 @@ public final class ShardingSphereTable {
private Map<String, ShardingSphereColumn> createColumns(final
Collection<ShardingSphereColumn> columns) {
Map<String, ShardingSphereColumn> result = new
CaseInsensitiveMap<>(columns.size(), 1F);
+ int index = 0;
for (ShardingSphereColumn each : columns) {
result.put(each.getName(), each);
columnNames.add(each.getName());
@@ -85,6 +88,7 @@ public final class ShardingSphereTable {
}
if (each.isVisible()) {
visibleColumns.add(each.getName());
+ visibleColumnsAndIndexes.put(each.getName(), index++);
}
}
return result;
diff --git
a/test/e2e/sql/src/test/resources/cases/dml/dataset/db/insert_single_with_generate_key_column.xml
b/test/e2e/sql/src/test/resources/cases/dml/dataset/db/insert_single_with_generate_key_column.xml
new file mode 100644
index 00000000000..4c811b81cd2
--- /dev/null
+++
b/test/e2e/sql/src/test/resources/cases/dml/dataset/db/insert_single_with_generate_key_column.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<dataset update-count="1">
+ <metadata data-nodes="db_0.t_single">
+ <column name="id" type="numeric" />
+ <column name="name" type="varchar" />
+ </metadata>
+ <row data-node="db_0.t_single" values="1, 1" />
+</dataset>
diff --git a/test/e2e/sql/src/test/resources/cases/dml/e2e-dml-insert.xml
b/test/e2e/sql/src/test/resources/cases/dml/e2e-dml-insert.xml
index a582af0ec59..eff31f59f11 100644
--- a/test/e2e/sql/src/test/resources/cases/dml/e2e-dml-insert.xml
+++ b/test/e2e/sql/src/test/resources/cases/dml/e2e-dml-insert.xml
@@ -233,4 +233,28 @@
<test-case sql="/* SHARDINGSPHERE_HINT: DATA_SOURCE_NAME=encrypt_ds_0
*/INSERT INTO t_order_0 values (1, 1, 'ok', 1, 'mark', '2021-01-01')"
db-types="MySQL,PostgreSQL" scenario-types="sharding_and_encrypt">
<assertion expected-data-file="insert_into_t_order_0.xml" />
</test-case>
+
+ <test-case sql="INSERT INTO t_single values (?, ?)" db-types="MySQL"
scenario-types="db">
+ <assertion parameters="1:int, 1:int"
expected-data-file="insert_single_with_generate_key_column.xml" >
+ <destroy-sql sql="DELETE FROM t_single WHERE id = 1" />
+ </assertion>
+ </test-case>
+
+ <test-case sql="INSERT INTO t_single(Id, Name) values (?, ?)"
db-types="MySQL" scenario-types="db">
+ <assertion parameters="1:int, 1:int"
expected-data-file="insert_single_with_generate_key_column.xml" >
+ <destroy-sql sql="DELETE FROM t_single WHERE id = 1" />
+ </assertion>
+ </test-case>
+
+ <test-case sql="INSERT INTO t_single(id, name) values (?, ?)"
db-types="MySQL" scenario-types="db">
+ <assertion parameters="1:int, 1:int"
expected-data-file="insert_single_with_generate_key_column.xml" >
+ <destroy-sql sql="DELETE FROM t_single WHERE id = 1" />
+ </assertion>
+ </test-case>
+
+ <test-case sql="INSERT INTO t_single(ID, NAME) values (?, ?)"
db-types="MySQL" scenario-types="db">
+ <assertion parameters="1:int, 1:int"
expected-data-file="insert_single_with_generate_key_column.xml" >
+ <destroy-sql sql="DELETE FROM t_single WHERE id = 1" />
+ </assertion>
+ </test-case>
</e2e-test-cases>
diff --git
a/test/e2e/sql/src/test/resources/env/scenario/db/data/actual/init-sql/mysql/01-actual-init.sql
b/test/e2e/sql/src/test/resources/env/scenario/db/data/actual/init-sql/mysql/01-actual-init.sql
index ae1f7965b83..0c853234d86 100644
---
a/test/e2e/sql/src/test/resources/env/scenario/db/data/actual/init-sql/mysql/01-actual-init.sql
+++
b/test/e2e/sql/src/test/resources/env/scenario/db/data/actual/init-sql/mysql/01-actual-init.sql
@@ -46,6 +46,7 @@ CREATE TABLE db_0.t_user (user_id INT PRIMARY KEY, user_name
VARCHAR(50) NOT NUL
CREATE TABLE db_0.t_product (product_id INT PRIMARY KEY, product_name
VARCHAR(50) NOT NULL, category_id INT NOT NULL, price DECIMAL NOT NULL, status
VARCHAR(50) NOT NULL, creation_date DATE NOT NULL);
CREATE TABLE db_0.t_product_category (category_id INT PRIMARY KEY,
category_name VARCHAR(50) NOT NULL, parent_id INT NOT NULL, level TINYINT NOT
NULL, creation_date DATE NOT NULL);
CREATE TABLE db_0.t_country (country_id SMALLINT PRIMARY KEY, country_name
VARCHAR(50), continent_name VARCHAR(50), creation_date DATE NOT NULL);
+CREATE TABLE db_0.t_single (ID BIGINT PRIMARY KEY, NAME VARCHAR(50));
CREATE INDEX order_index ON db_0.t_order (order_id);
CREATE TABLE db_1.t_order (order_id BIGINT PRIMARY KEY, user_id INT NOT NULL,
status VARCHAR(50) NOT NULL, merchant_id INT, remark VARCHAR(50) NOT NULL,
creation_date DATE NOT NULL);