This is an automated email from the ASF dual-hosted git repository. jianglongtao pushed a commit to branch fix-33341 in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
commit aa2cf5604cbdb41288a1c704bab1bf82ad642fa1 Author: Raigor <[email protected]> AuthorDate: Wed Sep 4 21:39:29 2024 +0800 Pick #32595, #32763, fix the generated key column name case insensitivity error (#8) * Pick #32595, #32763, fix the generated key column name case insensitivity error * Improve DML E2E to support destroy-sql * Optimize code style --- .../keygen/engine/GeneratedKeyContextEngine.java | 27 ++++----- .../statement/dml/InsertStatementContext.java | 21 ++++++- .../engine/GeneratedKeyContextEngineTest.java | 9 +-- .../schema/model/ShardingSphereSchema.java | 10 ++++ .../database/schema/model/ShardingSphereTable.java | 37 ++++++------ .../e2e/cases/assertion/IntegrationTestCase.java | 3 + .../e2e/engine/type/dml/AdditionalDMLE2EIT.java | 4 +- .../test/e2e/engine/type/dml/BaseDMLE2EIT.java | 68 ++++++++++++++++++++-- .../test/e2e/engine/type/dml/BatchDMLE2EIT.java | 5 ++ .../test/e2e/engine/type/dml/GeneralDMLE2EIT.java | 30 +++++++--- .../db/insert_single_with_generate_key_column.xml | 24 ++++++++ .../resources/cases/dml/dml-integration-insert.xml | 24 ++++++++ .../data/actual/init-sql/mysql/01-actual-init.sql | 1 + 13 files changed, 215 insertions(+), 48 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 9d801f98ea8..0604b39e6b7 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; @@ -31,6 +30,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.InsertState import org.apache.shardingsphere.sql.parser.sql.dialect.handler.dml.InsertStatementHandler; import java.util.List; +import java.util.Map; import java.util.Optional; /** @@ -46,15 +46,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)); } @@ -70,9 +71,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() { @@ -89,11 +90,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; @@ -108,8 +109,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 6e0227be195..b27a0f27aaf 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; @@ -53,6 +54,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; @@ -72,6 +74,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; private List<InsertValueContext> insertValueContexts; @@ -96,7 +100,20 @@ public final class InsertStatementContext extends CommonSQLStatementContext impl ShardingSphereSchema schema = getSchema(metaData, defaultDatabaseName); 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(insertColumnNames); + generatedKeyContext = new GeneratedKeyContextEngine(sqlStatement, schema).createGenerateKeyContext(insertColumnNamesAndIndexes, insertValueContexts, params).orElse(null); + } + + private Map<String, Integer> createInsertColumnNamesAndIndexes(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 ShardingSphereSchema getSchema(final ShardingSphereMetaData metaData, final String defaultDatabaseName) { @@ -276,6 +293,6 @@ public final class InsertStatementContext extends CommonSQLStatementContext impl insertSelectContext = getInsertSelectContext(metaData, params, parametersOffset, defaultDatabaseName).orElse(null); onDuplicateKeyUpdateValueContext = getOnDuplicateKeyUpdateValueContext(params, parametersOffset).orElse(null); ShardingSphereSchema schema = getSchema(metaData, defaultDatabaseName); - 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 467b57276de..ac20e87f9ba 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; @@ -95,7 +96,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()); } @@ -140,7 +141,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)); } @@ -180,13 +181,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 10bdac8ac12..7eeed72b903 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 @@ -197,4 +197,14 @@ public final class ShardingSphereSchema { public List<String> getVisibleColumnNames(final String tableName) { 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(); + } } 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 a7e37fdac86..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 @@ -17,6 +17,7 @@ package org.apache.shardingsphere.infra.metadata.database.schema.model; +import com.cedarsoftware.util.CaseInsensitiveMap; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; @@ -25,7 +26,6 @@ import org.apache.shardingsphere.infra.database.core.metadata.database.enums.Tab import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -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; @@ -63,7 +65,7 @@ public final class ShardingSphereTable { this.columns = createColumns(columns); this.indexes = createIndexes(indexes); this.constraints = createConstraints(constraints); - this.type = TableType.TABLE; + type = TableType.TABLE; } public ShardingSphereTable(final String name, final Collection<ShardingSphereColumn> columns, @@ -76,33 +78,34 @@ public final class ShardingSphereTable { } private Map<String, ShardingSphereColumn> createColumns(final Collection<ShardingSphereColumn> columns) { - Map<String, ShardingSphereColumn> result = new LinkedHashMap<>(columns.size(), 1F); + Map<String, ShardingSphereColumn> result = new CaseInsensitiveMap<>(columns.size(), 1F); + int index = 0; for (ShardingSphereColumn each : columns) { - String lowerColumnName = each.getName().toLowerCase(); - result.put(lowerColumnName, each); + result.put(each.getName(), each); columnNames.add(each.getName()); if (each.isPrimaryKey()) { - primaryKeyColumns.add(lowerColumnName); + primaryKeyColumns.add(each.getName()); } if (each.isVisible()) { visibleColumns.add(each.getName()); + visibleColumnsAndIndexes.put(each.getName(), index++); } } return result; } private Map<String, ShardingSphereIndex> createIndexes(final Collection<ShardingSphereIndex> indexes) { - Map<String, ShardingSphereIndex> result = new LinkedHashMap<>(indexes.size(), 1F); + Map<String, ShardingSphereIndex> result = new CaseInsensitiveMap<>(indexes.size(), 1F); for (ShardingSphereIndex each : indexes) { - result.put(each.getName().toLowerCase(), each); + result.put(each.getName(), each); } return result; } private Map<String, ShardingSphereConstraint> createConstraints(final Collection<ShardingSphereConstraint> constraints) { - Map<String, ShardingSphereConstraint> result = new LinkedHashMap<>(constraints.size(), 1F); + Map<String, ShardingSphereConstraint> result = new CaseInsensitiveMap<>(constraints.size(), 1F); for (ShardingSphereConstraint each : constraints) { - result.put(each.getName().toLowerCase(), each); + result.put(each.getName(), each); } return result; } @@ -113,7 +116,7 @@ public final class ShardingSphereTable { * @param column column meta data */ public void putColumn(final ShardingSphereColumn column) { - columns.put(column.getName().toLowerCase(), column); + columns.put(column.getName(), column); } /** @@ -123,7 +126,7 @@ public final class ShardingSphereTable { * @return column meta data */ public ShardingSphereColumn getColumn(final String columnName) { - return columns.get(columnName.toLowerCase()); + return columns.get(columnName); } /** @@ -142,7 +145,7 @@ public final class ShardingSphereTable { * @return whether contains column or not */ public boolean containsColumn(final String columnName) { - return null != columnName && columns.containsKey(columnName.toLowerCase()); + return null != columnName && columns.containsKey(columnName); } /** @@ -151,7 +154,7 @@ public final class ShardingSphereTable { * @param index index meta data */ public void putIndex(final ShardingSphereIndex index) { - indexes.put(index.getName().toLowerCase(), index); + indexes.put(index.getName(), index); } /** @@ -160,7 +163,7 @@ public final class ShardingSphereTable { * @param indexName index name */ public void removeIndex(final String indexName) { - indexes.remove(indexName.toLowerCase()); + indexes.remove(indexName); } /** @@ -170,7 +173,7 @@ public final class ShardingSphereTable { * @return index meta data */ public ShardingSphereIndex getIndex(final String indexName) { - return indexes.get(indexName.toLowerCase()); + return indexes.get(indexName); } /** @@ -189,7 +192,7 @@ public final class ShardingSphereTable { * @return whether contains index or not */ public boolean containsIndex(final String indexName) { - return null != indexName && indexes.containsKey(indexName.toLowerCase()); + return null != indexName && indexes.containsKey(indexName); } /** diff --git a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/cases/assertion/IntegrationTestCase.java b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/cases/assertion/IntegrationTestCase.java index 62e0365d2da..d451cd1d708 100644 --- a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/cases/assertion/IntegrationTestCase.java +++ b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/cases/assertion/IntegrationTestCase.java @@ -53,6 +53,9 @@ public final class IntegrationTestCase { @XmlAttribute(name = "delay-assertion-seconds") private Integer delayAssertionSeconds; + @XmlAttribute(name = "ignore-batch-test") + private Boolean ignoreBatchTest; + @XmlElement(name = "assertion") private Collection<IntegrationTestCaseAssertion> assertions = new LinkedList<>(); } diff --git a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/AdditionalDMLE2EIT.java b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/AdditionalDMLE2EIT.java index 93d42779c35..8db89093fdc 100644 --- a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/AdditionalDMLE2EIT.java +++ b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/AdditionalDMLE2EIT.java @@ -61,8 +61,10 @@ class AdditionalDMLE2EIT extends BaseDMLE2EIT { actualUpdateCount = SQLExecuteType.Literal == containerComposer.getSqlExecuteType() ? executeUpdateForStatementWithAutoGeneratedKeys(testParam, containerComposer, connection) : executeUpdateForPreparedStatementWithAutoGeneratedKeys(testParam, containerComposer, connection); + assertDataSet(containerComposer, actualUpdateCount, testParam); + } finally { + tearDown(); } - assertDataSet(containerComposer, actualUpdateCount, testParam); } // TODO support oracle insert statement return auto generated keys diff --git a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BaseDMLE2EIT.java b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BaseDMLE2EIT.java index d39bce3d24a..7f0f2f62773 100644 --- a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BaseDMLE2EIT.java +++ b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BaseDMLE2EIT.java @@ -17,6 +17,7 @@ package org.apache.shardingsphere.test.e2e.engine.type.dml; +import com.google.common.base.Splitter; import org.apache.shardingsphere.infra.database.core.type.DatabaseType; import org.apache.shardingsphere.infra.datanode.DataNode; import org.apache.shardingsphere.infra.expr.core.InlineExpressionParserFactory; @@ -35,7 +36,8 @@ import org.apache.shardingsphere.test.e2e.framework.database.DatabaseAssertionMe import org.apache.shardingsphere.test.e2e.framework.database.DatabaseAssertionMetaDataFactory; import org.apache.shardingsphere.test.e2e.framework.param.model.AssertionTestParameter; import org.apache.shardingsphere.test.e2e.framework.param.model.CaseTestParameter; -import org.junit.jupiter.api.AfterEach; +import org.apache.shardingsphere.test.e2e.framework.param.model.E2ETestParameter; +import org.testcontainers.shaded.org.awaitility.Awaitility; import javax.sql.DataSource; import javax.xml.bind.JAXBException; @@ -52,6 +54,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.TimeUnit; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -71,13 +74,26 @@ public abstract class BaseDMLE2EIT { * @throws IOException IO exception * @throws JAXBException JAXB exception */ - public final void init(final AssertionTestParameter testParam, final SingleE2EContainerComposer containerComposer) throws SQLException, IOException, JAXBException { + public void init(final E2ETestParameter testParam, final SingleE2EContainerComposer containerComposer) throws SQLException, IOException, JAXBException { dataSetEnvironmentManager = new DataSetEnvironmentManager(new ScenarioDataPath(testParam.getScenario()).getDataSetFile(Type.ACTUAL), containerComposer.getActualDataSourceMap()); dataSetEnvironmentManager.fillData(); } - @AfterEach - void tearDown() { + /** + * Init. + * + * @param testParam test parameter + * @param actualDataSourceMap actual data source map + * @throws SQLException SQL exception + * @throws IOException IO exception + * @throws JAXBException JAXB exception + */ + public void init(final E2ETestParameter testParam, Map<String, DataSource> actualDataSourceMap) throws SQLException, IOException, JAXBException { + dataSetEnvironmentManager = new DataSetEnvironmentManager(new ScenarioDataPath(testParam.getScenario()).getDataSetFile(Type.ACTUAL), actualDataSourceMap); + dataSetEnvironmentManager.fillData(); + } + + protected void tearDown() { // TODO make sure test case can not be null if (null != dataSetEnvironmentManager) { dataSetEnvironmentManager.cleanData(); @@ -203,4 +219,48 @@ public abstract class BaseDMLE2EIT { assertMetaData(generatedKeys.getMetaData(), containerComposer.getGeneratedKeyDataSet().getMetaDataList().get(0).getColumns()); assertRows(generatedKeys, containerComposer.getGeneratedKeyDataSet().getRows(), databaseType); } + + protected void executeDestroySQLs(final SingleE2EContainerComposer containerComposer) throws SQLException { + if (null != containerComposer.getAssertion().getDestroySQL()) { + try (Connection connection = containerComposer.getTargetDataSource().getConnection()) { + executeDestroySQLs(containerComposer, connection); + } + } + } + + protected void executeInitSQLs(final SingleE2EContainerComposer containerComposer) throws SQLException { + if (null != containerComposer.getAssertion().getInitialSQL()) { + try (Connection connection = containerComposer.getTargetDataSource().getConnection()) { + executeInitSQLs(containerComposer, connection); + } + } + } + + private void executeInitSQLs(final SingleE2EContainerComposer containerComposer, final Connection connection) throws SQLException { + if (null == containerComposer.getAssertion().getInitialSQL().getSql()) { + return; + } + for (String each : Splitter.on(";").trimResults().omitEmptyStrings().splitToList(containerComposer.getAssertion().getInitialSQL().getSql())) { + try (PreparedStatement preparedStatement = connection.prepareStatement(each)) { + preparedStatement.executeUpdate(); + } + waitCompleted(); + } + } + + private void executeDestroySQLs(final SingleE2EContainerComposer containerComposer, final Connection connection) throws SQLException { + if (null == containerComposer.getAssertion().getDestroySQL().getSql()) { + return; + } + for (String each : Splitter.on(";").trimResults().omitEmptyStrings().splitToList(containerComposer.getAssertion().getDestroySQL().getSql())) { + try (PreparedStatement preparedStatement = connection.prepareStatement(each)) { + preparedStatement.executeUpdate(); + } + waitCompleted(); + } + } + + private void waitCompleted() { + Awaitility.await().pollDelay(1500L, TimeUnit.MILLISECONDS).until(() -> true); + } } diff --git a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BatchDMLE2EIT.java b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BatchDMLE2EIT.java index 9e2974da0eb..befcb5c0a2f 100644 --- a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BatchDMLE2EIT.java +++ b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/BatchDMLE2EIT.java @@ -49,12 +49,17 @@ class BatchDMLE2EIT extends BaseDMLE2EIT { if (null == testParam.getTestCaseContext()) { return; } + if (Boolean.TRUE.equals(testParam.getTestCaseContext().getTestCase().getIgnoreBatchTest())) { + return; + } try (BatchE2EContainerComposer containerComposer = new BatchE2EContainerComposer(testParam)) { int[] actualUpdateCounts; try (Connection connection = containerComposer.getTargetDataSource().getConnection()) { actualUpdateCounts = executeBatchForPreparedStatement(testParam, connection); } assertDataSet(containerComposer, actualUpdateCounts, testParam); + } finally { + tearDown(); } } diff --git a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/GeneralDMLE2EIT.java b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/GeneralDMLE2EIT.java index 634d8895416..30ef856fc6f 100644 --- a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/GeneralDMLE2EIT.java +++ b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/engine/type/dml/GeneralDMLE2EIT.java @@ -51,13 +51,27 @@ class GeneralDMLE2EIT extends BaseDMLE2EIT { } SingleE2EContainerComposer containerComposer = new SingleE2EContainerComposer(testParam); init(testParam, containerComposer); - int actualUpdateCount; - try (Connection connection = containerComposer.getTargetDataSource().getConnection()) { - actualUpdateCount = SQLExecuteType.Literal == containerComposer.getSqlExecuteType() - ? executeUpdateForStatement(containerComposer, connection) - : executeUpdateForPreparedStatement(containerComposer, connection); + try { + int actualUpdateCount; + try (Connection connection = containerComposer.getTargetDataSource().getConnection()) { + actualUpdateCount = SQLExecuteType.Literal == containerComposer.getSqlExecuteType() + ? executeUpdateForStatement(containerComposer, connection) + : executeUpdateForPreparedStatement(containerComposer, connection); + } + assertDataSet(containerComposer, actualUpdateCount, testParam); + } finally { + tearDown(containerComposer); } - assertDataSet(containerComposer, actualUpdateCount, testParam); + } + + public void init(final AssertionTestParameter testParam, final SingleE2EContainerComposer containerComposer) throws SQLException, JAXBException, IOException { + super.init(testParam, containerComposer); + executeInitSQLs(containerComposer); + } + + void tearDown(final SingleE2EContainerComposer containerComposer) throws SQLException { + tearDown(); + executeDestroySQLs(containerComposer); } private int executeUpdateForStatement(final SingleE2EContainerComposer containerComposer, final Connection connection) throws SQLException { @@ -90,8 +104,10 @@ class GeneralDMLE2EIT extends BaseDMLE2EIT { actualUpdateCount = SQLExecuteType.Literal == containerComposer.getSqlExecuteType() ? executeForStatement(containerComposer, connection) : executeForPreparedStatement(containerComposer, connection); + assertDataSet(containerComposer, actualUpdateCount, testParam); + } finally { + tearDown(containerComposer); } - assertDataSet(containerComposer, actualUpdateCount, testParam); } private int executeForStatement(final SingleE2EContainerComposer containerComposer, final Connection connection) throws SQLException { 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/dml-integration-insert.xml b/test/e2e/sql/src/test/resources/cases/dml/dml-integration-insert.xml index e0eb93f550c..4b450edb44a 100644 --- a/test/e2e/sql/src/test/resources/cases/dml/dml-integration-insert.xml +++ b/test/e2e/sql/src/test/resources/cases/dml/dml-integration-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" ignore-batch-test="true"> + <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" ignore-batch-test="true"> + <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" ignore-batch-test="true"> + <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" ignore-batch-test="true"> + <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> </integration-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 4f204fd42a3..c2877821c58 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_t_order 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);
