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 2026/06/22 10:30:17 UTC
(shardingsphere) branch master updated: Improve generated sharding index names to reduce name inflation (#38449)
This is an automated email from the ASF dual-hosted git repository.
terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 798a3bfe10e Improve generated sharding index names to reduce name inflation (#38449)
798a3bfe10e is described below
commit 798a3bfe10e3abc9d59d614d214889887edfe325
Author: ym0506 <at...@naver.com>
AuthorDate: Mon Jun 22 19:30:10 2026 +0900
Improve generated sharding index names to reduce name inflation (#38449)
* Improve sharding actual index naming to reduce name inflation
* Format MySQL sharding show create table merge test
* Adjust sharding rewriter expectations for shortened index names
* Address index naming compatibility and length limits
* Fix infra common style checks for index metadata utils
* Fix sharding core spotless formatting
* Fix pipeline decorator spotless formatting
* Fix reverse index lookup edge cases and schema-aware pipeline mapping
* Fix sharding index metadata revise recovery
* Fix sharding index revision candidates
* Add create table index revision candidates
---
.../reviser/index/EncryptIndexReviser.java | 4 +-
.../reviser/index/EncryptIndexReviserTest.java | 6 +-
.../reviser/index/ShardingIndexReviser.java | 69 +++++-
.../sharding/rewrite/token/pojo/IndexToken.java | 2 +-
.../reviser/index/ShardingIndexReviserTest.java | 117 +++++++++-
.../rewrite/token/pojo/IndexTokenTest.java | 18 +-
.../MySQLShardingShowCreateTableMergedResult.java | 6 +-
.../type/MySQLShardingShowIndexMergedResult.java | 11 +-
...SQLShardingShowCreateTableMergedResultTest.java | 43 ++++
.../MySQLShardingShowIndexMergedResultTest.java | 47 +++-
.../database/ShardingSphereDatabaseFactory.java | 34 ++-
.../builder/GenericSchemaBuilderMaterial.java | 22 +-
.../schema/reviser/MetaDataReviseEngine.java | 3 +-
.../schema/reviser/index/IndexReviseEngine.java | 36 ++-
.../schema/reviser/index/IndexReviser.java | 22 +-
.../reviser/schema/SchemaMetaDataReviseEngine.java | 43 +++-
.../reviser/table/TableMetaDataReviseEngine.java | 29 ++-
.../database/schema/util/IndexMetaDataUtils.java | 243 ++++++++++++++++++++-
.../ShardingSphereDatabaseFactoryTest.java | 23 ++
.../reviser/index/IndexReviseEngineTest.java | 32 ++-
.../schema/SchemaMetaDataReviseEngineTest.java | 38 ++++
.../schema/util/IndexMetaDataUtilsTest.java | 99 ++++++++-
.../metadata/generator/PipelineDDLDecorator.java | 39 +++-
.../datasource/PipelineJobDataSourcePreparer.java | 2 +-
.../generator/PipelineDDLDecoratorTest.java | 106 +++++++++
.../mode/manager/ContextManager.java | 6 +-
.../metadata/factory/MetaDataContextsFactory.java | 3 +-
.../metadata/DatabaseMetaDataPersistFacade.java | 4 +-
.../CreateTablePushDownMetaDataRefresher.java | 36 ++-
.../type/table/TableMetaDataRefresherLoader.java | 28 ++-
.../type/view/ViewMetaDataRefresherLoader.java | 4 +-
.../factory/MetaDataContextsFactoryTest.java | 19 ++
.../CreateTablePushDownMetaDataRefresherTest.java | 229 ++++++++++++++++++-
.../ClusterMetaDataManagerPersistService.java | 3 +-
.../StandaloneMetaDataManagerPersistService.java | 3 +-
.../resources/scenario/sharding/case/ddl/index.xml | 28 ++-
36 files changed, 1383 insertions(+), 74 deletions(-)
diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/metadata/reviser/index/EncryptIndexReviser.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/metadata/reviser/index/EncryptIndexReviser.java
index aa3e08ebb18..5e042121f7e 100644
--- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/metadata/reviser/index/EncryptIndexReviser.java
+++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/metadata/reviser/index/EncryptIndexReviser.java
@@ -19,6 +19,7 @@ package org.apache.shardingsphere.encrypt.metadata.reviser.index;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import org.apache.shardingsphere.encrypt.rule.EncryptRule;
import org.apache.shardingsphere.encrypt.rule.table.EncryptTable;
import org.apache.shardingsphere.infra.metadata.database.schema.reviser.index.IndexReviser;
@@ -36,7 +37,8 @@ public final class EncryptIndexReviser implements IndexReviser<EncryptRule> {
private final EncryptTable encryptTable;
@Override
- public Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final EncryptRule rule) {
+ public Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final Collection<TableMetaData> originalTableMetaDataList,
+ final EncryptRule rule) {
if (originalMetaData.getColumns().isEmpty()) {
return Optional.empty();
}
diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/metadata/reviser/index/EncryptIndexReviserTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/metadata/reviser/index/EncryptIndexReviserTest.java
index e55b3886d56..8101a8edfbd 100644
--- a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/metadata/reviser/index/EncryptIndexReviserTest.java
+++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/metadata/reviser/index/EncryptIndexReviserTest.java
@@ -23,6 +23,7 @@ import org.apache.shardingsphere.encrypt.rule.table.EncryptTable;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
+import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Optional;
@@ -37,13 +38,14 @@ class EncryptIndexReviserTest {
@Test
void assertReviseWithEmptyColumn() {
- assertFalse(new EncryptIndexReviser(mock(EncryptTable.class)).revise("foo_tbl", new IndexMetaData("foo_idx"), mock(EncryptRule.class)).isPresent());
+ assertFalse(new EncryptIndexReviser(mock(EncryptTable.class))
+ .revise("foo_tbl", new IndexMetaData("foo_idx"), Collections.emptyList(), mock(EncryptRule.class)).isPresent());
}
@Test
void assertReviseWithColumns() {
Optional<IndexMetaData> actual = new EncryptIndexReviser(mockEncryptTable())
- .revise("foo_tbl", new IndexMetaData("foo_idx", Arrays.asList("cipher_col", "assisted_col", "other_col")), mock(EncryptRule.class));
+ .revise("foo_tbl", new IndexMetaData("foo_idx", Arrays.asList("cipher_col", "assisted_col", "other_col")), Collections.emptyList(), mock(EncryptRule.class));
assertTrue(actual.isPresent());
assertThat(actual.get().getName(), is("foo_idx"));
assertThat(actual.get().getColumns(), is(new LinkedHashSet<>(Arrays.asList("col_1", "col_2", "other_col"))));
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviser.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviser.java
index aa906fd464e..fad32a7b728 100644
--- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviser.java
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviser.java
@@ -19,12 +19,18 @@ package org.apache.shardingsphere.sharding.metadata.reviser.index;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
+import org.apache.shardingsphere.infra.datanode.DataNode;
import org.apache.shardingsphere.infra.metadata.database.schema.reviser.index.IndexReviser;
import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
import org.apache.shardingsphere.sharding.rule.ShardingRule;
import org.apache.shardingsphere.sharding.rule.ShardingTable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.Optional;
+import java.util.stream.Collectors;
/**
* Sharding index reviser.
@@ -35,13 +41,72 @@ public final class ShardingIndexReviser implements IndexReviser<ShardingRule> {
private final ShardingTable shardingTable;
@Override
- public Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final ShardingRule rule) {
+ public Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final Collection<TableMetaData> originalTableMetaDataList,
+ final ShardingRule rule) {
+ return revise(tableName, originalMetaData, originalTableMetaDataList, Collections.emptyList(), rule);
+ }
+
+ @Override
+ public Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final Collection<TableMetaData> originalTableMetaDataList,
+ final Collection<TableMetaData> schemaMetaDataRevisionCandidateTableMetaDataList, final ShardingRule rule) {
if (shardingTable.getActualDataNodes().isEmpty()) {
return Optional.empty();
}
+ String actualTableName = tableName;
+ String logicIndexName = IndexMetaDataUtils.findGeneratedLogicIndexName(
+ originalMetaData.getName(), actualTableName,
+ findCandidateLogicIndexNames(originalMetaData, originalTableMetaDataList, schemaMetaDataRevisionCandidateTableMetaDataList)).orElse(originalMetaData.getName());
IndexMetaData result = new IndexMetaData(
- IndexMetaDataUtils.getLogicIndexName(originalMetaData.getName(), shardingTable.getActualDataNodes().iterator().next().getTableName()), originalMetaData.getColumns());
+ logicIndexName, originalMetaData.getColumns());
result.setUnique(originalMetaData.isUnique());
return Optional.of(result);
}
+
+ private Collection<String> findCandidateLogicIndexNames(final IndexMetaData originalMetaData, final Collection<TableMetaData> originalTableMetaDataList,
+ final Collection<TableMetaData> schemaMetaDataRevisionCandidateTableMetaDataList) {
+ Collection<String> result = new LinkedHashSet<>();
+ result.add(getGeneratedAnonymousIndexName(originalMetaData));
+ for (TableMetaData eachTable : originalTableMetaDataList) {
+ if (isActualTable(eachTable.getName())) {
+ result.addAll(findCandidateLogicIndexNames(eachTable));
+ }
+ }
+ for (TableMetaData each : schemaMetaDataRevisionCandidateTableMetaDataList) {
+ if (isLogicTable(each.getName())) {
+ result.addAll(findCandidateLogicIndexNamesFromRevisionCandidate(each));
+ }
+ }
+ return result;
+ }
+
+ private Collection<String> findCandidateLogicIndexNames(final TableMetaData tableMetaData) {
+ Collection<String> result = new LinkedHashSet<>();
+ for (IndexMetaData each : tableMetaData.getIndexes()) {
+ IndexMetaDataUtils.findGeneratedLogicIndexName(each.getName(), tableMetaData.getName(), Collections.emptyList())
+ .filter(optional -> !optional.equals(each.getName())).ifPresent(result::add);
+ result.add(getGeneratedAnonymousIndexName(each));
+ }
+ return result;
+ }
+
+ private Collection<String> findCandidateLogicIndexNamesFromRevisionCandidate(final TableMetaData tableMetaData) {
+ Collection<String> result = new LinkedHashSet<>();
+ for (IndexMetaData each : tableMetaData.getIndexes()) {
+ result.add(each.getName());
+ result.add(getGeneratedAnonymousIndexName(each));
+ }
+ return result;
+ }
+
+ private boolean isActualTable(final String tableName) {
+ return shardingTable.getActualDataNodes().stream().map(DataNode::getTableName).anyMatch(each -> each.equalsIgnoreCase(tableName));
+ }
+
+ private boolean isLogicTable(final String tableName) {
+ return shardingTable.getLogicTable().equalsIgnoreCase(tableName);
+ }
+
+ private String getGeneratedAnonymousIndexName(final IndexMetaData originalMetaData) {
+ return originalMetaData.getColumns().stream().map(each -> each + "_").collect(Collectors.joining("", "", "idx"));
+ }
}
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexToken.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexToken.java
index 7c14604f2af..1f2ece72d73 100644
--- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexToken.java
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexToken.java
@@ -76,7 +76,7 @@ public final class IndexToken extends SQLToken implements Substitutable, RouteUn
}
Map<String, String> logicAndActualTables = ShardingTokenUtils.getLogicAndActualTableMap(routeUnit, sqlStatementContext, rule);
String actualTableName = logicTableName.map(logicAndActualTables::get).orElseGet(() -> logicAndActualTables.isEmpty() ? null : logicAndActualTables.values().iterator().next());
- return IndexMetaDataUtils.getActualIndexName(identifier.getValue(), actualTableName);
+ return IndexMetaDataUtils.getActualIndexName(identifier.getValue(), actualTableName, sqlStatementContext.getSqlStatement().getDatabaseType());
}
private Optional<String> findLogicTableNameFromMetaData(final String logicIndexName) {
diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviserTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviserTest.java
index 56ae9aa7ef5..de6d13666e0 100644
--- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviserTest.java
+++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviserTest.java
@@ -17,13 +17,20 @@
package org.apache.shardingsphere.sharding.metadata.reviser.index;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import org.apache.shardingsphere.infra.datanode.DataNode;
+import org.apache.shardingsphere.infra.metadata.database.schema.reviser.MetaDataReviseEntry;
+import org.apache.shardingsphere.infra.metadata.database.schema.reviser.index.IndexReviseEngine;
+import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.sharding.rule.ShardingRule;
import org.apache.shardingsphere.sharding.rule.ShardingTable;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
@@ -35,21 +42,123 @@ import static org.mockito.Mockito.when;
class ShardingIndexReviserTest {
+ private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "PostgreSQL");
+
@Test
void assertReviseWithEmptyActualDataNode() {
- assertThat(new ShardingIndexReviser(mock(ShardingTable.class)).revise("foo_tbl", new IndexMetaData("foo_idx"), mock(ShardingRule.class)), is(Optional.empty()));
+ assertThat(new ShardingIndexReviser(mock(ShardingTable.class)).revise("foo_tbl", new IndexMetaData("foo_idx"), Collections.emptyList(), mock(ShardingRule.class)),
+ is(Optional.empty()));
}
@Test
- void assertReviseWithActualDataNodes() {
- Optional<IndexMetaData> actual = new ShardingIndexReviser(mockShardingTable()).revise("tbl_0", new IndexMetaData("foo_idx", Collections.singletonList("foo_col")), mock(ShardingRule.class));
+ void assertReviseWithHashedActualIndexName() {
+ Optional<IndexMetaData> actual = revise("tbl_0", new IndexMetaData(IndexMetaDataUtils.getActualIndexName(
+ "named_index_boundary_case_abcdefghijklmnopqrstuvwxyz", "tbl_0", databaseType), Collections.singletonList("foo_col")));
assertTrue(actual.isPresent());
- assertThat(actual.get().getName(), is("foo_idx"));
+ assertThat(actual.get().getName(), is("named_index_boundary_case_abcdefghijklmnopqrstuvwxyz"));
assertThat(actual.get().getColumns().size(), is(1));
}
+ @Test
+ void assertReviseWithTruncatedNamedActualIndexNameUsingCandidates() {
+ String logicIndexName = "named_index_boundary_case_abcdefghijklmnopqrstuvwxyz_0123456789";
+ IndexMetaData truncatedActualIndexMetaData = new IndexMetaData(
+ IndexMetaDataUtils.getActualIndexName(logicIndexName, "tbl_0", databaseType), Collections.singletonList("foo_col"));
+ IndexMetaData legacyActualIndexMetaData = new IndexMetaData(IndexMetaDataUtils.getLegacyActualIndexName(logicIndexName, "tbl_1"), Collections.singletonList("foo_col"));
+ Optional<IndexMetaData> actual = revise("tbl_0", truncatedActualIndexMetaData,
+ tableMetaData("tbl_0", truncatedActualIndexMetaData), tableMetaData("tbl_1", legacyActualIndexMetaData));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get().getName(), is(logicIndexName));
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ @Test
+ void assertReviseThroughSharedIndexReviseEngineWithTruncatedNamedActualIndexName() {
+ String logicIndexName = "named_index_boundary_case_abcdefghijklmnopqrstuvwxyz_0123456789";
+ IndexMetaData truncatedActualIndexMetaData = new IndexMetaData(
+ IndexMetaDataUtils.getActualIndexName(logicIndexName, "tbl_0", databaseType), Collections.singletonList("foo_col"));
+ IndexMetaData legacyActualIndexMetaData = new IndexMetaData(IndexMetaDataUtils.getLegacyActualIndexName(logicIndexName, "tbl_1"), Collections.singletonList("foo_col"));
+ ShardingRule rule = mock(ShardingRule.class);
+ MetaDataReviseEntry reviseEntry = mock(MetaDataReviseEntry.class);
+ ShardingIndexReviser indexReviser = new ShardingIndexReviser(mockShardingTable());
+ when(reviseEntry.getIndexReviser(rule, "tbl_0")).thenReturn(Optional.of(indexReviser));
+ Collection<IndexMetaData> actual = new IndexReviseEngine<>(rule, reviseEntry).revise("tbl_0", Collections.singleton(truncatedActualIndexMetaData),
+ Arrays.asList(tableMetaData("tbl_0", truncatedActualIndexMetaData), tableMetaData("tbl_1", legacyActualIndexMetaData)));
+ assertThat(actual.size(), is(1));
+ assertThat(actual.iterator().next().getName(), is(logicIndexName));
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ @Test
+ void assertReviseThroughSharedIndexReviseEngineWithAllTruncatedNamedActualIndexNamesUsingRevisionCandidates() {
+ String logicIndexName = "named_index_boundary_case_abcdefghijklmnopqrstuvwxyz_0123456789";
+ IndexMetaData firstTruncatedActualIndexMetaData = new IndexMetaData(
+ IndexMetaDataUtils.getActualIndexName(logicIndexName, "tbl_0", databaseType), Collections.singletonList("foo_col"));
+ IndexMetaData secondTruncatedActualIndexMetaData = new IndexMetaData(
+ IndexMetaDataUtils.getActualIndexName(logicIndexName, "tbl_1", databaseType), Collections.singletonList("foo_col"));
+ ShardingRule rule = mock(ShardingRule.class);
+ MetaDataReviseEntry reviseEntry = mock(MetaDataReviseEntry.class);
+ ShardingIndexReviser indexReviser = new ShardingIndexReviser(mockShardingTable());
+ when(reviseEntry.getIndexReviser(rule, "tbl_0")).thenReturn(Optional.of(indexReviser));
+ Collection<IndexMetaData> actual = new IndexReviseEngine<>(rule, reviseEntry).revise("tbl_0", Collections.singleton(firstTruncatedActualIndexMetaData),
+ Arrays.asList(tableMetaData("tbl_0", firstTruncatedActualIndexMetaData), tableMetaData("tbl_1", secondTruncatedActualIndexMetaData)),
+ Collections.singleton(tableMetaData("tbl", new IndexMetaData(logicIndexName, Collections.singletonList("foo_col")))));
+ assertThat(actual.size(), is(1));
+ assertThat(actual.iterator().next().getName(), is(logicIndexName));
+ }
+
+ @Test
+ void assertReviseWithExactHashLikeIndexName() {
+ Optional<IndexMetaData> actual = revise("tbl_0", new IndexMetaData("foo_h12345678", Collections.singletonList("foo_col")));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get().getName(), is("foo_h12345678"));
+ }
+
+ @Test
+ void assertReviseWithExactTruncationLikeIndexName() {
+ Optional<IndexMetaData> actual = revise("tbl_0", new IndexMetaData("foo_t12345678", Collections.singletonList("foo_col")));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get().getName(), is("foo_t12345678"));
+ }
+
+ @Test
+ void assertReviseWithLegacyActualIndexName() {
+ Optional<IndexMetaData> actual = revise("tbl_0",
+ new IndexMetaData(IndexMetaDataUtils.getLegacyActualIndexName("foo_idx", "tbl_0"), Collections.singletonList("foo_col")));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get().getName(), is("foo_idx"));
+ }
+
+ @Test
+ void assertReviseWithLegacyActualIndexNameForSecondActualTable() {
+ Optional<IndexMetaData> actual = revise("tbl_1",
+ new IndexMetaData(IndexMetaDataUtils.getLegacyActualIndexName("foo_idx", "tbl_1"), Collections.singletonList("foo_col")));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get().getName(), is("foo_idx"));
+ }
+
+ @Test
+ void assertReviseWithTruncatedAnonymousActualIndexName() {
+ String logicIndexName = "very_long_status_column_name_for_sharding_rewrite_validation_account_identifier_idx";
+ Optional<IndexMetaData> actual = revise("tbl_0", new IndexMetaData(IndexMetaDataUtils.getActualIndexName(logicIndexName, "tbl_0", databaseType),
+ Arrays.asList("very_long_status_column_name_for_sharding_rewrite_validation", "account_identifier")));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get().getName(), is(logicIndexName));
+ }
+
+ private Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final TableMetaData... originalTableMetaDataList) {
+ return new ShardingIndexReviser(mockShardingTable()).revise(tableName, originalMetaData,
+ 0 == originalTableMetaDataList.length ? Collections.singleton(tableMetaData(tableName, originalMetaData)) : Arrays.asList(originalTableMetaDataList),
+ mock(ShardingRule.class));
+ }
+
+ private static TableMetaData tableMetaData(final String tableName, final IndexMetaData... indexes) {
+ return new TableMetaData(tableName, Collections.emptyList(), Arrays.asList(indexes), Collections.emptyList());
+ }
+
private static ShardingTable mockShardingTable() {
ShardingTable result = mock(ShardingTable.class);
+ when(result.getLogicTable()).thenReturn("tbl");
when(result.getActualDataNodes()).thenReturn(Arrays.asList(new DataNode("foo_schema", (String) null, "tbl_0"), new DataNode("foo_schema", (String) null, "tbl_1")));
return result;
}
diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexTokenTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexTokenTest.java
index 1488e493606..267482f8110 100644
--- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexTokenTest.java
+++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexTokenTest.java
@@ -22,6 +22,7 @@ import org.apache.shardingsphere.infra.binder.context.statement.type.CommonSQLSt
import org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
+import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
import org.apache.shardingsphere.infra.route.context.RouteMapper;
import org.apache.shardingsphere.infra.route.context.RouteUnit;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
@@ -41,12 +42,13 @@ import static org.mockito.Mockito.when;
class IndexTokenTest {
- private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+ private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "PostgreSQL");
@Test
void assertToStringWithNotShardingTable() {
SelectStatementContext selectStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS);
when(selectStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
+ when(selectStatementContext.getSqlStatement().getDatabaseType()).thenReturn(databaseType);
IndexToken indexToken = new IndexToken(0, 0, new IdentifierValue("foo_idx"), selectStatementContext, mock(ShardingRule.class), mockSchema());
assertThat(indexToken.toString(mockRouteUnit()), is("foo_idx"));
}
@@ -55,10 +57,11 @@ class IndexTokenTest {
void assertToStringWithShardingTable() {
SelectStatementContext selectStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS);
when(selectStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
+ when(selectStatementContext.getSqlStatement().getDatabaseType()).thenReturn(databaseType);
ShardingRule rule = mock(ShardingRule.class);
when(rule.isShardingTable("foo_tbl")).thenReturn(true);
IndexToken indexToken = new IndexToken(0, 0, new IdentifierValue("foo_idx"), selectStatementContext, rule, mockSchema());
- assertThat(indexToken.toString(mockRouteUnit()), is("foo_idx_foo_tbl_0"));
+ assertThat(indexToken.toString(mockRouteUnit()), is(IndexMetaDataUtils.getActualIndexName("foo_idx", "foo_tbl_0", databaseType)));
}
@Test
@@ -66,7 +69,16 @@ class IndexTokenTest {
CreateIndexStatement sqlStatement = CreateIndexStatement.builder().databaseType(databaseType).build();
CommonSQLStatementContext sqlStatementContext = new CommonSQLStatementContext(sqlStatement);
IndexToken indexToken = new IndexToken(0, 0, new IdentifierValue("bar_idx"), sqlStatementContext, mock(ShardingRule.class), mockSchema());
- assertThat(indexToken.toString(mockRouteUnit()), is(" bar_idx_foo_tbl_0 "));
+ assertThat(indexToken.toString(mockRouteUnit()), is(" " + IndexMetaDataUtils.getActualIndexName("bar_idx", "foo_tbl_0", databaseType) + " "));
+ }
+
+ @Test
+ void assertToStringWithLongGeneratedIndex() {
+ CreateIndexStatement sqlStatement = CreateIndexStatement.builder().databaseType(databaseType).build();
+ CommonSQLStatementContext sqlStatementContext = new CommonSQLStatementContext(sqlStatement);
+ String logicIndexName = "very_long_generated_index_boundary_case_for_sharding_length_safety_validation";
+ IndexToken indexToken = new IndexToken(0, 0, new IdentifierValue(logicIndexName), sqlStatementContext, mock(ShardingRule.class), mockSchema());
+ assertThat(indexToken.toString(mockRouteUnit()), is(" " + IndexMetaDataUtils.getActualIndexName(logicIndexName, "foo_tbl_0", databaseType) + " "));
}
private ShardingSphereSchema mockSchema() {
diff --git a/features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResult.java b/features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResult.java
index 9c5c5b5736d..2464fdb7702 100644
--- a/features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResult.java
+++ b/features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResult.java
@@ -81,14 +81,16 @@ public final class MySQLShardingShowCreateTableMergedResult extends MySQLShardin
private void replaceIndexes(final MemoryQueryResultRow memoryResultSetRow, final String actualTableName, final ShardingSphereTable table) {
for (ShardingSphereIndex each : table.getAllIndexes()) {
- String actualIndexName = IndexMetaDataUtils.getActualIndexName(each.getName(), actualTableName);
+ String actualIndexName = IndexMetaDataUtils.getShortenedActualIndexName(each.getName(), actualTableName);
memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replace(actualIndexName, each.getName()));
+ String legacyActualIndexName = IndexMetaDataUtils.getLegacyActualIndexName(each.getName(), actualTableName);
+ memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replace(legacyActualIndexName, each.getName()));
}
}
private void replaceConstraints(final MemoryQueryResultRow memoryResultSetRow, final String actualTableName, final ShardingSphereTable table, final ShardingRule rule) {
for (ShardingSphereConstraint each : table.getAllConstraints()) {
- String actualIndexName = IndexMetaDataUtils.getActualIndexName(each.getName(), actualTableName);
+ String actualIndexName = IndexMetaDataUtils.getLegacyActualIndexName(each.getName(), actualTableName);
memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replace(actualIndexName, each.getName()));
Optional<ShardingTable> shardingTable = rule.findShardingTable(each.getReferencedTableName());
if (!shardingTable.isPresent()) {
diff --git a/features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResult.java b/features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResult.java
index 1b1e930f909..653894332e6 100644
--- a/features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResult.java
+++ b/features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResult.java
@@ -27,9 +27,11 @@ import org.apache.shardingsphere.sharding.rule.ShardingRule;
import org.apache.shardingsphere.sharding.rule.ShardingTable;
import java.sql.SQLException;
+import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
+import java.util.stream.Collectors;
/**
* Sharding merged result for show index for MySQL.
@@ -51,8 +53,13 @@ public final class MySQLShardingShowIndexMergedResult extends MemoryMergedResult
String actualTableName = memoryResultSetRow.getCell(1).toString();
String actualIndexName = memoryResultSetRow.getCell(3).toString();
Optional<ShardingTable> shardingTable = shardingRule.findShardingTableByActualTable(actualTableName);
- shardingTable.ifPresent(optional -> memoryResultSetRow.setCell(1, optional.getLogicTable()));
- memoryResultSetRow.setCell(3, IndexMetaDataUtils.getLogicIndexName(actualIndexName, actualTableName));
+ Collection<String> candidateLogicIndexNames = new LinkedList<>();
+ if (shardingTable.isPresent()) {
+ String logicTableName = shardingTable.get().getLogicTable();
+ memoryResultSetRow.setCell(1, logicTableName);
+ candidateLogicIndexNames = schema.getTable(logicTableName).getAllIndexes().stream().map(eachIndex -> eachIndex.getName()).collect(Collectors.toList());
+ }
+ memoryResultSetRow.setCell(3, IndexMetaDataUtils.findGeneratedLogicIndexName(actualIndexName, actualTableName, candidateLogicIndexNames).orElse(actualIndexName));
result.add(memoryResultSetRow);
}
}
diff --git a/features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResultTest.java b/features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResultTest.java
index e72aa5cde51..26e4d0cc201 100644
--- a/features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResultTest.java
+++ b/features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResultTest.java
@@ -23,8 +23,10 @@ import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementCont
import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereConstraint;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereIndex;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
+import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
import org.apache.shardingsphere.sharding.rule.ShardingRule;
@@ -132,6 +134,29 @@ class MySQLShardingShowCreateTableMergedResultTest {
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin"));
}
+ @Test
+ void assertGetValueWithLegacyIndexName() throws SQLException {
+ MySQLShardingShowCreateTableMergedResult actual = new MySQLShardingShowCreateTableMergedResult(
+ rule, mock(SQLStatementContext.class), createSchemaWithIndex(),
+ Collections.singletonList(mockQueryResultWithIndex(IndexMetaDataUtils.getLegacyActualIndexName("foo_idx", "foo_tbl_0"))));
+ assertTrue(actual.next());
+ assertThat(actual.getValue(2, String.class), is("CREATE TABLE `foo_tbl` (\n"
+ + " `id` int(11) NOT NULL,\n"
+ + " KEY `foo_idx` (`id`)\n"
+ + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin"));
+ }
+
+ @Test
+ void assertGetValueWithShortenedIndexName() throws SQLException {
+ MySQLShardingShowCreateTableMergedResult actual = new MySQLShardingShowCreateTableMergedResult(
+ rule, mock(SQLStatementContext.class), createSchemaWithIndex(), Collections.singletonList(mockQueryResultWithIndex(IndexMetaDataUtils.getActualIndexName("foo_idx", "foo_tbl_0"))));
+ assertTrue(actual.next());
+ assertThat(actual.getValue(2, String.class), is("CREATE TABLE `foo_tbl` (\n"
+ + " `id` int(11) NOT NULL,\n"
+ + " KEY `foo_idx` (`id`)\n"
+ + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin"));
+ }
+
private QueryResult mockQueryResultWithoutTableRule() throws SQLException {
QueryResult result = mock(QueryResult.class, RETURNS_DEEP_STUBS);
when(result.getMetaData().getColumnCount()).thenReturn(2);
@@ -148,4 +173,22 @@ class MySQLShardingShowCreateTableMergedResultTest {
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin");
return result;
}
+
+ private ShardingSphereSchema createSchemaWithIndex() {
+ ShardingSphereTable table =
+ new ShardingSphereTable("foo_tbl", Collections.emptyList(), Collections.singleton(new ShardingSphereIndex("foo_idx", Collections.emptyList(), false)), Collections.emptyList());
+ return new ShardingSphereSchema("foo_db", mock(DatabaseType.class), Collections.singleton(table), Collections.emptyList());
+ }
+
+ private QueryResult mockQueryResultWithIndex(final String actualIndexName) throws SQLException {
+ QueryResult result = mock(QueryResult.class, RETURNS_DEEP_STUBS);
+ when(result.getMetaData().getColumnCount()).thenReturn(2);
+ when(result.next()).thenReturn(true, false);
+ when(result.getValue(1, Object.class)).thenReturn("foo_tbl_0");
+ when(result.getValue(2, Object.class)).thenReturn("CREATE TABLE `foo_tbl_0` (\n"
+ + " `id` int(11) NOT NULL,\n"
+ + " KEY `" + actualIndexName + "` (`id`)\n"
+ + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin");
+ return result;
+ }
}
diff --git a/features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResultTest.java b/features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResultTest.java
index 165a17c5f44..ea2d05e434e 100644
--- a/features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResultTest.java
+++ b/features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResultTest.java
@@ -19,8 +19,12 @@ package org.apache.shardingsphere.sharding.merge.mysql.type;
import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereIndex;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
+import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import org.apache.shardingsphere.sharding.rule.ShardingTable;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
@@ -28,7 +32,10 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.sql.SQLException;
import java.util.Collections;
+import java.util.Optional;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -54,13 +61,51 @@ class MySQLShardingShowIndexMergedResultTest {
assertTrue(new MySQLShardingShowIndexMergedResult(rule, mock(SQLStatementContext.class), schema, Collections.singletonList(mockQueryResult())).next());
}
+ @Test
+ void assertGetValueWithShortenedIndexName() throws SQLException {
+ MySQLShardingShowIndexMergedResult actual = new MySQLShardingShowIndexMergedResult(rule, mock(SQLStatementContext.class), schema,
+ Collections.singletonList(mockQueryResult(IndexMetaDataUtils.getActualIndexName("t_order_index", "t_order_0"))));
+ assertTrue(actual.next());
+ assertThat(actual.getValue(3, String.class), is("t_order_index"));
+ }
+
+ @Test
+ void assertGetValueWithLogicalIndexNameEndingWithHashLikeSuffix() throws SQLException {
+ ShardingTable shardingTable = mock(ShardingTable.class);
+ when(rule.findShardingTableByActualTable("t_order_0")).thenReturn(Optional.of(shardingTable));
+ when(shardingTable.getLogicTable()).thenReturn("t_order");
+ when(schema.getTable("t_order")).thenReturn(new ShardingSphereTable("t_order", Collections.emptyList(),
+ Collections.singleton(new ShardingSphereIndex("foo_h12345678", Collections.emptyList(), false)), Collections.emptyList()));
+ MySQLShardingShowIndexMergedResult actual = new MySQLShardingShowIndexMergedResult(rule, mock(SQLStatementContext.class), schema,
+ Collections.singletonList(mockQueryResult("foo_h12345678")));
+ assertTrue(actual.next());
+ assertThat(actual.getValue(3, String.class), is("foo_h12345678"));
+ }
+
+ @Test
+ void assertGetValueWithLogicalIndexNameEndingWithTruncationLikeSuffix() throws SQLException {
+ ShardingTable shardingTable = mock(ShardingTable.class);
+ when(rule.findShardingTableByActualTable("t_order_0")).thenReturn(Optional.of(shardingTable));
+ when(shardingTable.getLogicTable()).thenReturn("t_order");
+ when(schema.getTable("t_order")).thenReturn(new ShardingSphereTable("t_order", Collections.emptyList(),
+ Collections.singleton(new ShardingSphereIndex("foo_t12345678", Collections.emptyList(), false)), Collections.emptyList()));
+ MySQLShardingShowIndexMergedResult actual = new MySQLShardingShowIndexMergedResult(rule, mock(SQLStatementContext.class), schema,
+ Collections.singletonList(mockQueryResult("foo_t12345678")));
+ assertTrue(actual.next());
+ assertThat(actual.getValue(3, String.class), is("foo_t12345678"));
+ }
+
private QueryResult mockQueryResult() throws SQLException {
+ return mockQueryResult("t_order_index_t_order_0");
+ }
+
+ private QueryResult mockQueryResult(final String actualIndexName) throws SQLException {
QueryResult result = mock(QueryResult.class, RETURNS_DEEP_STUBS);
when(result.getMetaData().getColumnCount()).thenReturn(3);
when(result.next()).thenReturn(true, false);
when(result.getValue(1, Object.class)).thenReturn("t_order_0");
when(result.getValue(2, Object.class)).thenReturn(1);
- when(result.getValue(3, Object.class)).thenReturn("t_order_index_t_order_0");
+ when(result.getValue(3, Object.class)).thenReturn(actualIndexName);
return result;
}
}
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabaseFactory.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabaseFactory.java
index 3f974f7b9e6..d42d3d8a4c2 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabaseFactory.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabaseFactory.java
@@ -38,6 +38,7 @@ import org.apache.shardingsphere.infra.rule.builder.database.DatabaseRulesBuilde
import java.sql.SQLException;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
@@ -82,13 +83,7 @@ public final class ShardingSphereDatabaseFactory {
*/
public static ShardingSphereDatabase create(final String name, final DatabaseType protocolType, final DatabaseConfiguration databaseConfig,
final ConfigurationProperties props, final ComputeNodeInstanceContext computeNodeInstanceContext) throws SQLException {
- ResourceMetaData resourceMetaData = new ResourceMetaData(databaseConfig.getDataSources(), databaseConfig.getStorageUnits());
- DatabaseIdentifierContext identifierContext = DatabaseIdentifierContextFactory.create(protocolType, resourceMetaData, props);
- Collection<ShardingSphereRule> databaseRules = DatabaseRulesBuilder.build(name, protocolType, databaseConfig, computeNodeInstanceContext, resourceMetaData);
- Map<String, ShardingSphereSchema> schemas = new ConcurrentHashMap<>(GenericSchemaBuilder.build(protocolType,
- new GenericSchemaBuilderMaterial(resourceMetaData.getStorageUnits(), databaseRules, props, new DatabaseTypeRegistry(protocolType).getDefaultSchemaName(name), identifierContext)));
- SystemSchemaBuilder.build(name, protocolType, props).forEach(schemas::putIfAbsent);
- return new ShardingSphereDatabase(name, protocolType, resourceMetaData, new RuleMetaData(databaseRules), schemas.values(), props);
+ return createWithSchemaMetaDataRevisionCandidates(name, protocolType, databaseConfig, props, computeNodeInstanceContext, Collections.emptyList());
}
/**
@@ -124,4 +119,29 @@ public final class ShardingSphereDatabaseFactory {
Collection<ShardingSphereRule> rules = DatabaseRulesBuilder.build(name, protocolType, databaseConfig, computeNodeInstanceContext, resourceMetaData);
return new ShardingSphereDatabase(name, protocolType, resourceMetaData, new RuleMetaData(rules), schemas, props);
}
+
+ /**
+ * Create database with schema meta data revision candidate schemas.
+ *
+ * @param name database name
+ * @param protocolType database protocol type
+ * @param databaseConfig database configuration
+ * @param props configuration properties
+ * @param computeNodeInstanceContext compute node instance context
+ * @param schemaMetaDataRevisionCandidateSchemas schema meta data revision candidate schemas
+ * @return created database
+ * @throws SQLException SQL exception
+ */
+ public static ShardingSphereDatabase createWithSchemaMetaDataRevisionCandidates(final String name, final DatabaseType protocolType, final DatabaseConfiguration databaseConfig,
+ final ConfigurationProperties props, final ComputeNodeInstanceContext computeNodeInstanceContext,
+ final Collection<ShardingSphereSchema> schemaMetaDataRevisionCandidateSchemas) throws SQLException {
+ ResourceMetaData resourceMetaData = new ResourceMetaData(databaseConfig.getDataSources(), databaseConfig.getStorageUnits());
+ DatabaseIdentifierContext identifierContext = DatabaseIdentifierContextFactory.create(protocolType, resourceMetaData, props);
+ Collection<ShardingSphereRule> databaseRules = DatabaseRulesBuilder.build(name, protocolType, databaseConfig, computeNodeInstanceContext, resourceMetaData);
+ Map<String, ShardingSphereSchema> schemas = new ConcurrentHashMap<>(GenericSchemaBuilder.build(protocolType,
+ new GenericSchemaBuilderMaterial(resourceMetaData.getStorageUnits(), databaseRules, props, new DatabaseTypeRegistry(protocolType).getDefaultSchemaName(name),
+ identifierContext, schemaMetaDataRevisionCandidateSchemas)));
+ SystemSchemaBuilder.build(name, protocolType, props).forEach(schemas::putIfAbsent);
+ return new ShardingSphereDatabase(name, protocolType, resourceMetaData, new RuleMetaData(databaseRules), schemas.values(), props);
+ }
}
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/GenericSchemaBuilderMaterial.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/GenericSchemaBuilderMaterial.java
index 4ea14362620..19deec6a6fd 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/GenericSchemaBuilderMaterial.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/GenericSchemaBuilderMaterial.java
@@ -18,19 +18,19 @@
package org.apache.shardingsphere.infra.metadata.database.schema.builder;
import lombok.Getter;
-import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
import org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
import org.apache.shardingsphere.infra.metadata.identifier.DatabaseIdentifierContext;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import java.util.Collection;
+import java.util.Collections;
import java.util.Map;
/**
* ShardingSphere schema builder material.
*/
-@RequiredArgsConstructor
@Getter
public final class GenericSchemaBuilderMaterial {
@@ -43,4 +43,22 @@ public final class GenericSchemaBuilderMaterial {
private final String defaultSchemaName;
private final DatabaseIdentifierContext identifierContext;
+
+ private final Collection<ShardingSphereSchema> schemaMetaDataRevisionCandidateSchemas;
+
+ public GenericSchemaBuilderMaterial(final Map<String, StorageUnit> storageUnits, final Collection<ShardingSphereRule> rules, final ConfigurationProperties props,
+ final String defaultSchemaName, final DatabaseIdentifierContext identifierContext) {
+ this(storageUnits, rules, props, defaultSchemaName, identifierContext, Collections.emptyList());
+ }
+
+ public GenericSchemaBuilderMaterial(final Map<String, StorageUnit> storageUnits, final Collection<ShardingSphereRule> rules, final ConfigurationProperties props,
+ final String defaultSchemaName, final DatabaseIdentifierContext identifierContext,
+ final Collection<ShardingSphereSchema> schemaMetaDataRevisionCandidateSchemas) {
+ this.storageUnits = storageUnits;
+ this.rules = rules;
+ this.props = props;
+ this.defaultSchemaName = defaultSchemaName;
+ this.identifierContext = identifierContext;
+ this.schemaMetaDataRevisionCandidateSchemas = schemaMetaDataRevisionCandidateSchemas;
+ }
}
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/MetaDataReviseEngine.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/MetaDataReviseEngine.java
index d1d510d7f3d..ea91c641b70 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/MetaDataReviseEngine.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/MetaDataReviseEngine.java
@@ -64,7 +64,8 @@ public final class MetaDataReviseEngine {
}
Map<String, ShardingSphereSchema> result = new HashMap<>(schemaMetaDataMap.size(), 1F);
for (Entry<String, SchemaMetaData> entry : schemaMetaDataMap.entrySet()) {
- SchemaMetaData schemaMetaData = new SchemaMetaDataReviseEngine(rules, material.getProps()).revise(entry.getValue());
+ SchemaMetaData schemaMetaData = new SchemaMetaDataReviseEngine(
+ rules, material.getProps(), material.getSchemaMetaDataRevisionCandidateSchemas()).revise(entry.getValue());
result.put(entry.getKey(), new ShardingSphereSchema(entry.getKey(), protocolType, convertToTables(schemaMetaData.getTables()), new LinkedList<>()));
}
return result;
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviseEngine.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviseEngine.java
index d04155ebd84..a1ace5193f8 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviseEngine.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviseEngine.java
@@ -19,16 +19,18 @@ package org.apache.shardingsphere.infra.metadata.database.schema.reviser.index;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import org.apache.shardingsphere.infra.metadata.database.schema.reviser.MetaDataReviseEntry;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import java.util.Collection;
+import java.util.Collections;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Index revise engine.
- *
+ *
* @param <T> type of rule
*/
@RequiredArgsConstructor
@@ -46,10 +48,40 @@ public final class IndexReviseEngine<T extends ShardingSphereRule> {
* @return revised index meta data
*/
public Collection<IndexMetaData> revise(final String tableName, final Collection<IndexMetaData> originalMetaDataList) {
+ return revise(tableName, originalMetaDataList,
+ Collections.singleton(new TableMetaData(tableName, Collections.emptyList(), originalMetaDataList, Collections.emptyList())));
+ }
+
+ /**
+ * Revise index meta data.
+ *
+ * @param tableName table name
+ * @param originalMetaDataList original index meta data list
+ * @param originalTableMetaDataList original table meta data list
+ * @return revised index meta data
+ */
+ public Collection<IndexMetaData> revise(final String tableName, final Collection<IndexMetaData> originalMetaDataList,
+ final Collection<TableMetaData> originalTableMetaDataList) {
+ return revise(tableName, originalMetaDataList, originalTableMetaDataList, Collections.emptyList());
+ }
+
+ /**
+ * Revise index meta data.
+ *
+ * @param tableName table name
+ * @param originalMetaDataList original index meta data list
+ * @param originalTableMetaDataList original table meta data list
+ * @param schemaMetaDataRevisionCandidateTableMetaDataList schema meta data revision candidate table meta data list
+ * @return revised index meta data
+ */
+ public Collection<IndexMetaData> revise(final String tableName, final Collection<IndexMetaData> originalMetaDataList,
+ final Collection<TableMetaData> originalTableMetaDataList,
+ final Collection<TableMetaData> schemaMetaDataRevisionCandidateTableMetaDataList) {
Optional<? extends IndexReviser<T>> reviser = reviseEntry.getIndexReviser(rule, tableName);
return reviser.isPresent()
? originalMetaDataList.stream()
- .map(each -> reviser.get().revise(tableName, each, rule)).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList())
+ .map(each -> reviser.get().revise(tableName, each, originalTableMetaDataList, schemaMetaDataRevisionCandidateTableMetaDataList, rule))
+ .filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList())
: originalMetaDataList;
}
}
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviser.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviser.java
index 40e20c193bf..035a63aa4f5 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviser.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviser.java
@@ -18,13 +18,15 @@
package org.apache.shardingsphere.infra.metadata.database.schema.reviser.index;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import java.util.Collection;
import java.util.Optional;
/**
* Index reviser.
- *
+ *
* @param <T> type of rule
*/
public interface IndexReviser<T extends ShardingSphereRule> {
@@ -34,8 +36,24 @@ public interface IndexReviser<T extends ShardingSphereRule> {
*
* @param tableName table name
* @param originalMetaData original index meta data
+ * @param originalTableMetaDataList original table meta data list
+ * @param schemaMetaDataRevisionCandidateTableMetaDataList schema meta data revision candidate table meta data list
+ * @param rule rule
+ * @return revised index meta data
+ */
+ default Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final Collection<TableMetaData> originalTableMetaDataList,
+ final Collection<TableMetaData> schemaMetaDataRevisionCandidateTableMetaDataList, final T rule) {
+ return revise(tableName, originalMetaData, originalTableMetaDataList, rule);
+ }
+
+ /**
+ * Revise index meta data.
+ *
+ * @param tableName table name
+ * @param originalMetaData original index meta data
+ * @param originalTableMetaDataList original table meta data list
* @param rule rule
* @return revised index meta data
*/
- Optional<IndexMetaData> revise(String tableName, IndexMetaData originalMetaData, T rule);
+ Optional<IndexMetaData> revise(String tableName, IndexMetaData originalMetaData, Collection<TableMetaData> originalTableMetaDataList, T rule);
}
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/schema/SchemaMetaDataReviseEngine.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/schema/SchemaMetaDataReviseEngine.java
index 6d6be090085..3de3069497a 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/schema/SchemaMetaDataReviseEngine.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/schema/SchemaMetaDataReviseEngine.java
@@ -17,16 +17,20 @@
package org.apache.shardingsphere.infra.metadata.database.schema.reviser.schema;
-import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereIndex;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
import org.apache.shardingsphere.infra.metadata.database.schema.reviser.MetaDataReviseEntry;
import org.apache.shardingsphere.infra.metadata.database.schema.reviser.table.TableMetaDataReviseEngine;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPILoader;
import java.util.Collection;
+import java.util.Collections;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -34,13 +38,25 @@ import java.util.stream.Collectors;
/**
* Schema meta data revise engine.
*/
-@RequiredArgsConstructor
public final class SchemaMetaDataReviseEngine {
private final Collection<ShardingSphereRule> rules;
private final ConfigurationProperties props;
+ private final Collection<ShardingSphereSchema> schemaMetaDataRevisionCandidateSchemas;
+
+ public SchemaMetaDataReviseEngine(final Collection<ShardingSphereRule> rules, final ConfigurationProperties props) {
+ this(rules, props, Collections.emptyList());
+ }
+
+ public SchemaMetaDataReviseEngine(final Collection<ShardingSphereRule> rules, final ConfigurationProperties props,
+ final Collection<ShardingSphereSchema> schemaMetaDataRevisionCandidateSchemas) {
+ this.rules = rules;
+ this.props = props;
+ this.schemaMetaDataRevisionCandidateSchemas = schemaMetaDataRevisionCandidateSchemas;
+ }
+
/**
* Revise schema meta data.
*
@@ -58,13 +74,32 @@ public final class SchemaMetaDataReviseEngine {
private <T extends ShardingSphereRule> SchemaMetaData revise(final SchemaMetaData originalMetaData, final T rule, final MetaDataReviseEntry<T> reviseEntry) {
TableMetaDataReviseEngine<T> tableMetaDataReviseEngine = new TableMetaDataReviseEngine<>(rule, reviseEntry);
+ Collection<TableMetaData> schemaMetaDataRevisionCandidateTableMetaDataList = createSchemaMetaDataRevisionCandidateTableMetaDataList(originalMetaData);
Optional<? extends SchemaTableAggregationReviser<T>> aggregationReviser = reviseEntry.getSchemaTableAggregationReviser(props);
if (!aggregationReviser.isPresent()) {
- return new SchemaMetaData(originalMetaData.getName(), originalMetaData.getTables().stream().map(tableMetaDataReviseEngine::revise).collect(Collectors.toList()));
+ return new SchemaMetaData(originalMetaData.getName(), originalMetaData.getTables().stream()
+ .map(each -> tableMetaDataReviseEngine.revise(each, originalMetaData.getTables(), schemaMetaDataRevisionCandidateTableMetaDataList)).collect(Collectors.toList()));
}
for (TableMetaData each : originalMetaData.getTables()) {
- aggregationReviser.get().add(tableMetaDataReviseEngine.revise(each));
+ aggregationReviser.get().add(tableMetaDataReviseEngine.revise(each, originalMetaData.getTables(), schemaMetaDataRevisionCandidateTableMetaDataList));
}
return new SchemaMetaData(originalMetaData.getName(), aggregationReviser.get().aggregate(rule));
}
+
+ private Collection<TableMetaData> createSchemaMetaDataRevisionCandidateTableMetaDataList(final SchemaMetaData originalMetaData) {
+ return schemaMetaDataRevisionCandidateSchemas.stream().filter(each -> each.getName().equalsIgnoreCase(originalMetaData.getName()))
+ .flatMap(each -> each.getAllTables().stream()).map(SchemaMetaDataReviseEngine::convertToTableMetaData).collect(Collectors.toList());
+ }
+
+ private static TableMetaData convertToTableMetaData(final ShardingSphereTable table) {
+ return new TableMetaData(table.getName(), Collections.emptyList(), convertToIndexMetaData(table.getAllIndexes()), Collections.emptyList(), table.getType());
+ }
+
+ private static Collection<IndexMetaData> convertToIndexMetaData(final Collection<ShardingSphereIndex> indexes) {
+ return indexes.stream().map(each -> {
+ IndexMetaData result = new IndexMetaData(each.getName(), each.getColumns());
+ result.setUnique(each.isUnique());
+ return result;
+ }).collect(Collectors.toList());
+ }
}
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/table/TableMetaDataReviseEngine.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/table/TableMetaDataReviseEngine.java
index b304ea62d70..fc43829c2e4 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/table/TableMetaDataReviseEngine.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/table/TableMetaDataReviseEngine.java
@@ -25,6 +25,8 @@ import org.apache.shardingsphere.infra.metadata.database.schema.reviser.constrai
import org.apache.shardingsphere.infra.metadata.database.schema.reviser.index.IndexReviseEngine;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Optional;
/**
@@ -46,10 +48,35 @@ public final class TableMetaDataReviseEngine<T extends ShardingSphereRule> {
* @return revised table meta data
*/
public TableMetaData revise(final TableMetaData originalMetaData) {
+ return revise(originalMetaData, Collections.singleton(originalMetaData));
+ }
+
+ /**
+ * Revise table meta data.
+ *
+ * @param originalMetaData original table meta data
+ * @param originalMetaDataList original table meta data list
+ * @return revised table meta data
+ */
+ public TableMetaData revise(final TableMetaData originalMetaData, final Collection<TableMetaData> originalMetaDataList) {
+ return revise(originalMetaData, originalMetaDataList, Collections.emptyList());
+ }
+
+ /**
+ * Revise table meta data.
+ *
+ * @param originalMetaData original table meta data
+ * @param originalMetaDataList original table meta data list
+ * @param schemaMetaDataRevisionCandidateTableMetaDataList schema meta data revision candidate table meta data list
+ * @return revised table meta data
+ */
+ public TableMetaData revise(final TableMetaData originalMetaData, final Collection<TableMetaData> originalMetaDataList,
+ final Collection<TableMetaData> schemaMetaDataRevisionCandidateTableMetaDataList) {
Optional<? extends TableNameReviser<T>> tableNameReviser = reviseEntry.getTableNameReviser();
String revisedTableName = tableNameReviser.map(optional -> optional.revise(originalMetaData.getName(), rule)).orElse(originalMetaData.getName());
return new TableMetaData(revisedTableName, new ColumnReviseEngine<>(rule, reviseEntry).revise(originalMetaData.getName(), originalMetaData.getColumns()),
- new IndexReviseEngine<>(rule, reviseEntry).revise(originalMetaData.getName(), originalMetaData.getIndexes()),
+ new IndexReviseEngine<>(rule, reviseEntry).revise(originalMetaData.getName(), originalMetaData.getIndexes(), originalMetaDataList,
+ schemaMetaDataRevisionCandidateTableMetaDataList),
new ConstraintReviseEngine<>(rule, reviseEntry).revise(originalMetaData.getName(), originalMetaData.getConstraints()), originalMetaData.getType());
}
}
diff --git a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtils.java b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtils.java
index ef9c401faf9..44fb15f8848 100644
--- a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtils.java
+++ b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtils.java
@@ -29,9 +29,13 @@ import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSp
import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.IndexSegment;
import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Optional;
+import java.util.regex.Pattern;
/**
* Index meta data utility class.
@@ -41,6 +45,28 @@ public final class IndexMetaDataUtils {
private static final String UNDERLINE = "_";
+ private static final String SHORTENED_INDEX_SUFFIX_PREFIX = "_s";
+
+ private static final String HASHED_INDEX_SUFFIX_PREFIX = "_h";
+
+ private static final String TRUNCATED_INDEX_SUFFIX_PREFIX = "_t";
+
+ private static final String HASH_ALGORITHM = "SHA-256";
+
+ private static final int SHORTENED_INDEX_SUFFIX_HASH_BYTES = 5;
+
+ private static final int LENGTH_SAFE_INDEX_SUFFIX_HASH_LENGTH = 8;
+
+ private static final Pattern HASHED_INDEX_NAME_SUFFIX_PATTERN = Pattern.compile("_h[0-9a-z]{8}$");
+
+ private static final Pattern TRUNCATED_INDEX_NAME_SUFFIX_PATTERN = Pattern.compile("_t[0-9a-z]{8}$");
+
+ private static final int POSTGRESQL_INDEX_NAME_MAX_LENGTH = 63;
+
+ private static final int OPENGAUSS_INDEX_NAME_MAX_LENGTH = 63;
+
+ private static final int ORACLE_INDEX_NAME_MAX_LENGTH = 30;
+
/**
* Get logic index name.
*
@@ -49,8 +75,7 @@ public final class IndexMetaDataUtils {
* @return logic index name
*/
public static String getLogicIndexName(final String actualIndexName, final String actualTableName) {
- String indexNameSuffix = UNDERLINE + actualTableName;
- return actualIndexName.endsWith(indexNameSuffix) ? actualIndexName.substring(0, actualIndexName.lastIndexOf(indexNameSuffix)) : actualIndexName;
+ return stripActualIndexNameSuffix(actualIndexName, getLegacyActualIndexNameSuffix(actualTableName));
}
/**
@@ -61,7 +86,110 @@ public final class IndexMetaDataUtils {
* @return actual index name
*/
public static String getActualIndexName(final String logicIndexName, final String actualTableName) {
- return Strings.isNullOrEmpty(actualTableName) ? logicIndexName : logicIndexName + UNDERLINE + actualTableName;
+ return getLegacyActualIndexName(logicIndexName, actualTableName);
+ }
+
+ /**
+ * Get actual index name with database identifier budget.
+ *
+ * @param logicIndexName logic index name
+ * @param actualTableName actual table name
+ * @param databaseType database type
+ * @return actual index name
+ */
+ public static String getActualIndexName(final String logicIndexName, final String actualTableName, final DatabaseType databaseType) {
+ if (Strings.isNullOrEmpty(actualTableName)) {
+ return logicIndexName;
+ }
+ String legacyActualIndexName = getLegacyActualIndexName(logicIndexName, actualTableName);
+ int maxLength = getIndexNameMaxLength(databaseType);
+ if (getUtf8Length(legacyActualIndexName) <= maxLength) {
+ return legacyActualIndexName;
+ }
+ String hashedActualIndexName = logicIndexName + getHashedActualIndexNameSuffix(logicIndexName, actualTableName);
+ if (getUtf8Length(hashedActualIndexName) <= maxLength) {
+ return hashedActualIndexName;
+ }
+ String truncatedSuffix = getTruncatedActualIndexNameSuffix(logicIndexName, actualTableName);
+ return truncateToUtf8Bytes(logicIndexName, Math.max(0, maxLength - getUtf8Length(truncatedSuffix))) + truncatedSuffix;
+ }
+
+ /**
+ * Get shortened actual index name for compatibility with the previous shortened suffix format.
+ *
+ * @param logicIndexName logic index name
+ * @param actualTableName actual table name
+ * @return shortened actual index name
+ */
+ public static String getShortenedActualIndexName(final String logicIndexName, final String actualTableName) {
+ return Strings.isNullOrEmpty(actualTableName) ? logicIndexName : logicIndexName + getShortenedActualIndexNameSuffix(actualTableName);
+ }
+
+ /**
+ * Get legacy actual index name.
+ *
+ * @param logicIndexName logic index name
+ * @param actualTableName actual table name
+ * @return legacy actual index name
+ */
+ public static String getLegacyActualIndexName(final String logicIndexName, final String actualTableName) {
+ return Strings.isNullOrEmpty(actualTableName) ? logicIndexName : logicIndexName + getLegacyActualIndexNameSuffix(actualTableName);
+ }
+
+ /**
+ * Get logic index name from generated actual index name.
+ *
+ * @param actualIndexName actual index name
+ * @param actualTableName actual table name
+ * @return logic index name
+ */
+ public static String getGeneratedLogicIndexName(final String actualIndexName, final String actualTableName) {
+ if (HASHED_INDEX_NAME_SUFFIX_PATTERN.matcher(actualIndexName).find()) {
+ return actualIndexName.substring(0, actualIndexName.length() - getLengthSafeGeneratedSuffixLength());
+ }
+ if (TRUNCATED_INDEX_NAME_SUFFIX_PATTERN.matcher(actualIndexName).find()) {
+ return actualIndexName.substring(0, actualIndexName.length() - getLengthSafeGeneratedSuffixLength());
+ }
+ String result = stripActualIndexNameSuffix(actualIndexName, getShortenedActualIndexNameSuffix(actualTableName));
+ return result.equals(actualIndexName) ? getLogicIndexName(actualIndexName, actualTableName) : result;
+ }
+
+ /**
+ * Find logic index name from generated actual index name.
+ *
+ * @param actualIndexName actual index name
+ * @param actualTableName actual table name
+ * @param candidateLogicIndexNames candidate logic index names
+ * @return matched logic index name
+ */
+ public static Optional<String> findGeneratedLogicIndexName(final String actualIndexName, final String actualTableName, final Collection<String> candidateLogicIndexNames) {
+ if (candidateLogicIndexNames.contains(actualIndexName)) {
+ return Optional.of(actualIndexName);
+ }
+ Optional<String> result = candidateLogicIndexNames.stream().filter(each -> isGeneratedActualIndexNameMatch(actualIndexName, each, actualTableName)).findFirst();
+ if (result.isPresent()) {
+ return result;
+ }
+ String generatedLogicIndexName = getGeneratedLogicIndexName(actualIndexName, actualTableName);
+ if (isProvablyGeneratedActualIndexName(actualIndexName, generatedLogicIndexName, actualTableName)) {
+ return Optional.of(generatedLogicIndexName);
+ }
+ return Optional.of(actualIndexName);
+ }
+
+ /**
+ * Check whether actual index name matches generated format of the logic index.
+ *
+ * @param actualIndexName actual index name
+ * @param logicIndexName logic index name
+ * @param actualTableName actual table name
+ * @return whether actual index name matches generated format or not
+ */
+ public static boolean isGeneratedActualIndexNameMatch(final String actualIndexName, final String logicIndexName, final String actualTableName) {
+ return actualIndexName.equals(getLegacyActualIndexName(logicIndexName, actualTableName))
+ || actualIndexName.equals(getShortenedActualIndexName(logicIndexName, actualTableName))
+ || (logicIndexName + getHashedActualIndexNameSuffix(logicIndexName, actualTableName)).equals(actualIndexName)
+ || isTruncatedActualIndexNameMatch(actualIndexName, logicIndexName, actualTableName);
}
/**
@@ -86,4 +214,113 @@ public final class IndexMetaDataUtils {
private static Optional<String> findLogicTableNameFromMetaData(final ShardingSphereSchema schema, final IdentifierValue logicIndexName) {
return schema.getAllTables().stream().filter(table -> table.containsIndex(logicIndexName)).findFirst().map(ShardingSphereTable::getName);
}
+
+ private static String getLegacyActualIndexNameSuffix(final String actualTableName) {
+ return Strings.isNullOrEmpty(actualTableName) ? "" : UNDERLINE + actualTableName;
+ }
+
+ private static String getShortenedActualIndexNameSuffix(final String actualTableName) {
+ return Strings.isNullOrEmpty(actualTableName) ? "" : SHORTENED_INDEX_SUFFIX_PREFIX + shortenActualTableName(actualTableName);
+ }
+
+ private static String getHashedActualIndexNameSuffix(final String logicIndexName, final String actualTableName) {
+ return HASHED_INDEX_SUFFIX_PREFIX + shortenIndexIdentity(logicIndexName, actualTableName);
+ }
+
+ private static String getTruncatedActualIndexNameSuffix(final String logicIndexName, final String actualTableName) {
+ return TRUNCATED_INDEX_SUFFIX_PREFIX + shortenIndexIdentity(logicIndexName, actualTableName);
+ }
+
+ private static String stripActualIndexNameSuffix(final String actualIndexName, final String indexNameSuffix) {
+ return Strings.isNullOrEmpty(indexNameSuffix) || !actualIndexName.endsWith(indexNameSuffix)
+ ? actualIndexName
+ : actualIndexName.substring(0, actualIndexName.length() - indexNameSuffix.length());
+ }
+
+ private static String shortenActualTableName(final String actualTableName) {
+ return toVariableLengthRadixHash(digest(actualTableName));
+ }
+
+ private static String shortenIndexIdentity(final String logicIndexName, final String actualTableName) {
+ return toFixedLengthRadixHash(digest(logicIndexName + '\0' + actualTableName));
+ }
+
+ private static String toVariableLengthRadixHash(final byte[] digest) {
+ long result = 0L;
+ for (int i = 0; i < SHORTENED_INDEX_SUFFIX_HASH_BYTES; i++) {
+ result = result << Byte.SIZE | digest[i] & 0xFF;
+ }
+ return Long.toString(result, Character.MAX_RADIX);
+ }
+
+ private static String toFixedLengthRadixHash(final byte[] digest) {
+ long result = 0L;
+ for (int i = 0; i < SHORTENED_INDEX_SUFFIX_HASH_BYTES; i++) {
+ result = result << Byte.SIZE | digest[i] & 0xFF;
+ }
+ String value = Long.toString(result, Character.MAX_RADIX);
+ return Strings.padStart(value, LENGTH_SAFE_INDEX_SUFFIX_HASH_LENGTH, '0');
+ }
+
+ private static boolean isTruncatedActualIndexNameMatch(final String actualIndexName, final String logicIndexName, final String actualTableName) {
+ String suffix = getTruncatedActualIndexNameSuffix(logicIndexName, actualTableName);
+ if (!actualIndexName.endsWith(suffix)) {
+ return false;
+ }
+ String actualPrefix = actualIndexName.substring(0, actualIndexName.length() - suffix.length());
+ return actualPrefix.equals(truncateToUtf8Bytes(logicIndexName, getUtf8Length(actualPrefix)));
+ }
+
+ private static boolean isProvablyGeneratedActualIndexName(final String actualIndexName, final String generatedLogicIndexName, final String actualTableName) {
+ return !generatedLogicIndexName.equals(actualIndexName) && (getLegacyActualIndexName(generatedLogicIndexName, actualTableName).equals(actualIndexName)
+ || getShortenedActualIndexName(generatedLogicIndexName, actualTableName).equals(actualIndexName)
+ || (generatedLogicIndexName + getHashedActualIndexNameSuffix(generatedLogicIndexName, actualTableName)).equals(actualIndexName));
+ }
+
+ private static int getIndexNameMaxLength(final DatabaseType databaseType) {
+ if (null == databaseType) {
+ return Integer.MAX_VALUE;
+ }
+ switch (databaseType.getType()) {
+ case "PostgreSQL":
+ return POSTGRESQL_INDEX_NAME_MAX_LENGTH;
+ case "openGauss":
+ return OPENGAUSS_INDEX_NAME_MAX_LENGTH;
+ case "Oracle":
+ return ORACLE_INDEX_NAME_MAX_LENGTH;
+ default:
+ return Integer.MAX_VALUE;
+ }
+ }
+
+ private static int getLengthSafeGeneratedSuffixLength() {
+ return HASHED_INDEX_SUFFIX_PREFIX.length() + LENGTH_SAFE_INDEX_SUFFIX_HASH_LENGTH;
+ }
+
+ private static String truncateToUtf8Bytes(final String value, final int maxBytes) {
+ if (Strings.isNullOrEmpty(value) || maxBytes <= 0 || getUtf8Length(value) <= maxBytes) {
+ return maxBytes <= 0 ? "" : value;
+ }
+ int endIndex = 0;
+ while (endIndex < value.length()) {
+ int nextEndIndex = value.offsetByCodePoints(endIndex, 1);
+ if (getUtf8Length(value.substring(0, nextEndIndex)) > maxBytes) {
+ break;
+ }
+ endIndex = nextEndIndex;
+ }
+ return value.substring(0, endIndex);
+ }
+
+ private static int getUtf8Length(final String value) {
+ return value.getBytes(StandardCharsets.UTF_8).length;
+ }
+
+ private static byte[] digest(final String value) {
+ try {
+ return MessageDigest.getInstance(HASH_ALGORITHM).digest(value.getBytes(StandardCharsets.UTF_8));
+ } catch (final NoSuchAlgorithmException ex) {
+ throw new IllegalStateException(String.format("Could not find message digest algorithm `%s`.", HASH_ALGORITHM), ex);
+ }
+ }
}
diff --git a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabaseFactoryTest.java b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabaseFactoryTest.java
index 5b2128a6bd4..7b65c6fed65 100644
--- a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabaseFactoryTest.java
+++ b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabaseFactoryTest.java
@@ -50,6 +50,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockConstruction;
@@ -103,6 +104,28 @@ class ShardingSphereDatabaseFactoryTest {
}
}
+ @Test
+ void assertCreateWithDatabaseConfigurationAndSchemaMetaDataRevisionCandidates() throws SQLException {
+ DatabaseType protocolType = mock(DatabaseType.class);
+ ShardingSphereSchema candidateSchema = new ShardingSphereSchema("candidate_schema", protocolType);
+ try (
+ MockedConstruction<DatabaseTypeRegistry> ignored = mockConstruction(DatabaseTypeRegistry.class, (mock, context) -> when(mock.getDefaultSchemaName("foo_db")).thenReturn("foo_schema"));
+ MockedStatic<DatabaseRulesBuilder> mockedRulesBuilder = mockStatic(DatabaseRulesBuilder.class);
+ MockedStatic<GenericSchemaBuilder> mockedGenericSchemaBuilder = mockStatic(GenericSchemaBuilder.class);
+ MockedStatic<SystemSchemaBuilder> mockedSystemSchemaBuilder = mockStatic(SystemSchemaBuilder.class)) {
+ ComputeNodeInstanceContext computeNodeInstanceContext = mock(ComputeNodeInstanceContext.class);
+ mockedRulesBuilder.when(() -> DatabaseRulesBuilder.build(eq("foo_db"), eq(protocolType), eq(databaseConfig), eq(computeNodeInstanceContext), any(ResourceMetaData.class)))
+ .thenReturn(Collections.singleton(mock(ShardingSphereRule.class)));
+ mockedGenericSchemaBuilder.when(() -> GenericSchemaBuilder.build(eq(protocolType),
+ argThat(material -> material.getSchemaMetaDataRevisionCandidateSchemas().contains(candidateSchema))))
+ .thenReturn(Collections.singletonMap("foo_schema", new ShardingSphereSchema("foo_schema", protocolType)));
+ mockedSystemSchemaBuilder.when(() -> SystemSchemaBuilder.build("foo_db", protocolType, props)).thenReturn(Collections.emptyMap());
+ ShardingSphereDatabase actual = ShardingSphereDatabaseFactory.createWithSchemaMetaDataRevisionCandidates(
+ "foo_db", protocolType, databaseConfig, props, computeNodeInstanceContext, Collections.singleton(candidateSchema));
+ assertTrue(actual.containsSchema("foo_schema"));
+ }
+ }
+
@Test
void assertCreateWithSchemas() {
ShardingSphereDatabase actual = ShardingSphereDatabaseFactory.create(
diff --git a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviseEngineTest.java b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviseEngineTest.java
index eb677d88bf6..2e57cb89dc4 100644
--- a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviseEngineTest.java
+++ b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/index/IndexReviseEngineTest.java
@@ -18,6 +18,7 @@
package org.apache.shardingsphere.infra.metadata.database.schema.reviser.index;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import org.apache.shardingsphere.infra.metadata.database.schema.reviser.MetaDataReviseEntry;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -33,6 +34,7 @@ import java.util.Optional;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -58,7 +60,7 @@ class IndexReviseEngineTest {
@Test
void assertReviseWithIndexReviser() {
IndexReviser reviser = mock(IndexReviser.class);
- when(reviser.revise(eq("foo_tbl"), any(), any())).thenReturn(Optional.of(new IndexMetaData("foo_idx")));
+ when(reviser.revise(eq("foo_tbl"), any(), any(), anyCollection(), any())).thenReturn(Optional.of(new IndexMetaData("foo_idx")));
when(metaDataReviseEntry.getIndexReviser(any(), eq("foo_tbl"))).thenReturn(Optional.of(reviser));
Collection<IndexMetaData> actual = indexReviseEngine.revise("foo_tbl", Arrays.asList(new IndexMetaData("idx_0"), new IndexMetaData("idx_1")));
assertThat(actual.size(), is(2));
@@ -66,6 +68,34 @@ class IndexReviseEngineTest {
assertIndexMetaData(actual.iterator().next(), new IndexMetaData("foo_idx"));
}
+ @Test
+ void assertReviseWithOriginalTableMetaDataList() {
+ IndexReviser reviser = mock(IndexReviser.class);
+ Collection<IndexMetaData> originalIndexes = Arrays.asList(new IndexMetaData("idx_0"), new IndexMetaData("idx_1"));
+ Collection<TableMetaData> originalTables = Collections.singleton(new TableMetaData("foo_tbl", Collections.emptyList(), originalIndexes, Collections.emptyList()));
+ when(reviser.revise(eq("foo_tbl"), any(), eq(originalTables), anyCollection(), any())).thenReturn(Optional.of(new IndexMetaData("foo_idx")));
+ when(metaDataReviseEntry.getIndexReviser(any(), eq("foo_tbl"))).thenReturn(Optional.of(reviser));
+ Collection<IndexMetaData> actual = indexReviseEngine.revise("foo_tbl", originalIndexes, originalTables);
+ assertThat(actual.size(), is(2));
+ assertIndexMetaData(actual.iterator().next(), new IndexMetaData("foo_idx"));
+ assertIndexMetaData(actual.iterator().next(), new IndexMetaData("foo_idx"));
+ }
+
+ @Test
+ void assertReviseWithSchemaMetaDataRevisionCandidateTableMetaDataList() {
+ IndexReviser reviser = mock(IndexReviser.class);
+ Collection<IndexMetaData> originalIndexes = Arrays.asList(new IndexMetaData("idx_0"), new IndexMetaData("idx_1"));
+ Collection<TableMetaData> originalTables = Collections.singleton(new TableMetaData("foo_tbl", Collections.emptyList(), originalIndexes, Collections.emptyList()));
+ Collection<TableMetaData> candidates =
+ Collections.singleton(new TableMetaData("logic_tbl", Collections.emptyList(), Collections.singleton(new IndexMetaData("logic_idx")), Collections.emptyList()));
+ when(reviser.revise(eq("foo_tbl"), any(), eq(originalTables), eq(candidates), any())).thenReturn(Optional.of(new IndexMetaData("foo_idx")));
+ when(metaDataReviseEntry.getIndexReviser(any(), eq("foo_tbl"))).thenReturn(Optional.of(reviser));
+ Collection<IndexMetaData> actual = indexReviseEngine.revise("foo_tbl", originalIndexes, originalTables, candidates);
+ assertThat(actual.size(), is(2));
+ assertIndexMetaData(actual.iterator().next(), new IndexMetaData("foo_idx"));
+ assertIndexMetaData(actual.iterator().next(), new IndexMetaData("foo_idx"));
+ }
+
private void assertIndexMetaData(final IndexMetaData actual, final IndexMetaData expected) {
assertThat(actual.getName(), is(expected.getName()));
assertThat(actual.getColumns(), is(expected.getColumns()));
diff --git a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/schema/SchemaMetaDataReviseEngineTest.java b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/schema/SchemaMetaDataReviseEngineTest.java
index 24006a8ce8c..b6f23a3b4ba 100644
--- a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/schema/SchemaMetaDataReviseEngineTest.java
+++ b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/reviser/schema/SchemaMetaDataReviseEngineTest.java
@@ -23,7 +23,11 @@ import org.apache.shardingsphere.database.connector.core.metadata.data.model.Ind
import org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereIndex;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
import org.apache.shardingsphere.infra.metadata.database.schema.reviser.MetaDataReviseEntry;
+import org.apache.shardingsphere.infra.metadata.database.schema.reviser.index.IndexReviser;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import org.apache.shardingsphere.infra.rule.builder.fixture.FixtureGlobalRule;
import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPILoader;
@@ -37,10 +41,15 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
+import java.util.Optional;
import java.util.Properties;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
@@ -81,6 +90,35 @@ class SchemaMetaDataReviseEngineTest {
}
}
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Test
+ void assertRevisePassesSameSchemaRevisionCandidateTableMetaDataToIndexReviser() {
+ TableMetaData actualTableMetaData = new TableMetaData("actual_tbl", Collections.emptyList(),
+ Collections.singleton(new IndexMetaData("actual_idx")), Collections.emptyList());
+ SchemaMetaData schemaMetaData = new SchemaMetaData("foo_schema", Collections.singleton(actualTableMetaData));
+ ShardingSphereTable candidateTable = new ShardingSphereTable(
+ "logic_tbl", Collections.emptyList(), Collections.singleton(new ShardingSphereIndex("logic_idx", Collections.singleton("foo_col"), true)), Collections.emptyList());
+ ShardingSphereSchema candidateSchema = new ShardingSphereSchema("foo_schema", mock(), Collections.singleton(candidateTable), Collections.emptyList());
+ ShardingSphereSchema ignoredCandidateSchema = new ShardingSphereSchema("bar_schema", mock(), Collections.singleton(candidateTable), Collections.emptyList());
+ FixtureGlobalRule rule = new FixtureGlobalRule();
+ MetaDataReviseEntry<FixtureGlobalRule> reviseEntry = mock(MetaDataReviseEntry.class);
+ IndexReviser<FixtureGlobalRule> indexReviser = mock(IndexReviser.class);
+ when(reviseEntry.getTypeClass()).thenReturn(FixtureGlobalRule.class);
+ doReturn(Optional.of(indexReviser)).when(reviseEntry).getIndexReviser(rule, "actual_tbl");
+ when(indexReviser.revise(eq("actual_tbl"), any(), eq(schemaMetaData.getTables()), argThat(candidates -> {
+ TableMetaData candidate = candidates.iterator().next();
+ IndexMetaData index = candidate.getIndexes().iterator().next();
+ return 1 == candidates.size() && "logic_tbl".equals(candidate.getName()) && "logic_idx".equals(index.getName()) && index.isUnique();
+ }), eq(rule))).thenReturn(Optional.of(new IndexMetaData("revised_idx")));
+ Map<ShardingSphereRule, MetaDataReviseEntry<?>> entries = Collections.singletonMap(rule, reviseEntry);
+ try (MockedStatic<OrderedSPILoader> mocked = mockStatic(OrderedSPILoader.class)) {
+ mocked.when(() -> OrderedSPILoader.getServices(MetaDataReviseEntry.class, Collections.singleton(rule))).thenReturn(entries);
+ SchemaMetaData actual = new SchemaMetaDataReviseEngine(
+ Collections.singleton(rule), new ConfigurationProperties(new Properties()), Arrays.asList(candidateSchema, ignoredCandidateSchema)).revise(schemaMetaData);
+ assertThat(actual.getTables().iterator().next().getIndexes().iterator().next().getName(), is("revised_idx"));
+ }
+ }
+
private TableMetaData createTableMetaData() {
Collection<ColumnMetaData> columns = new LinkedHashSet<>(Arrays.asList(new ColumnMetaData("id", Types.INTEGER, true, true, true, true, false, false),
new ColumnMetaData("pwd_cipher", Types.VARCHAR, false, false, true, true, false, false),
diff --git a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtilsTest.java b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtilsTest.java
index a65563e4394..15aec39871a 100644
--- a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtilsTest.java
+++ b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtilsTest.java
@@ -33,16 +33,26 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.Ind
import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
import org.junit.jupiter.api.Test;
+import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.Properties;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThan;
+import static org.hamcrest.Matchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
class IndexMetaDataUtilsTest {
+ private final DatabaseType fixtureDatabaseType = TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+
+ private final DatabaseType postgreSQLDatabaseType = TypedSPILoader.getService(DatabaseType.class, "PostgreSQL");
+
+ private final DatabaseType oracleDatabaseType = TypedSPILoader.getService(DatabaseType.class, "Oracle");
+
@Test
void assertGetLogicIndexNameWithIndexNameSuffix() {
assertThat(IndexMetaDataUtils.getLogicIndexName("order_index_t_order", "t_order"), is("order_index"));
@@ -63,15 +73,102 @@ class IndexMetaDataUtilsTest {
assertThat(IndexMetaDataUtils.getActualIndexName("order_index", "t_order"), is("order_index_t_order"));
}
+ @Test
+ void assertGetShortenedActualIndexNameReducesLengthForLongActualTableName() {
+ String actualTableName = "order_detail_archive_20260316_0001";
+ assertThat(IndexMetaDataUtils.getShortenedActualIndexName("order_index", actualTableName).length(),
+ lessThan(IndexMetaDataUtils.getLegacyActualIndexName("order_index", actualTableName).length()));
+ }
+
+ @Test
+ void assertGetLegacyActualIndexNameWithActualTableName() {
+ assertThat(IndexMetaDataUtils.getLegacyActualIndexName("order_index", "t_order"), is("order_index_t_order"));
+ }
+
@Test
void assertGetActualIndexNameWithoutActualTableName() {
assertThat(IndexMetaDataUtils.getActualIndexName("order_index", null), is("order_index"));
}
+ @Test
+ void assertGetGeneratedLogicIndexNameWithShortenedIndexNameSuffix() {
+ String actualIndexName = IndexMetaDataUtils.getShortenedActualIndexName("order_index", "t_order");
+ assertThat(IndexMetaDataUtils.getGeneratedLogicIndexName(actualIndexName, "t_order"), is("order_index"));
+ }
+
+ @Test
+ void assertGetGeneratedLogicIndexNameWithLegacyIndexNameSuffix() {
+ assertThat(IndexMetaDataUtils.getGeneratedLogicIndexName("order_index_t_order", "t_order"), is("order_index"));
+ }
+
+ @Test
+ void assertGetActualIndexNameKeepsLegacyFormatWhenLegacyNameFitsWithinBudget() {
+ assertThat(IndexMetaDataUtils.getActualIndexName("status_idx", "t_account_0", postgreSQLDatabaseType), is("status_idx_t_account_0"));
+ }
+
+ @Test
+ void assertGetActualIndexNameUsesHashedSuffixWhenLegacyNameExceedsBudget() {
+ String logicIndexName = "named_index_boundary_case_abcdefghijklmnopqrstuvwxyz";
+ String actual = IndexMetaDataUtils.getActualIndexName(logicIndexName, "t_account_0", postgreSQLDatabaseType);
+ assertThat(actual, startsWith(logicIndexName));
+ assertTrue(actual.matches(".*_h[0-9a-z]{8}$"));
+ assertThat(IndexMetaDataUtils.getGeneratedLogicIndexName(actual, "t_account_0"), is(logicIndexName));
+ assertThat(actual.getBytes(StandardCharsets.UTF_8).length, is(62));
+ }
+
+ @Test
+ void assertGetActualIndexNameTruncatesPrefixWhenHashedNameStillExceedsBudget() {
+ String logicIndexName = "very_long_named_index_boundary_case_for_sharding_length_safety_validation";
+ String actual = IndexMetaDataUtils.getActualIndexName(logicIndexName, "t_account_0", postgreSQLDatabaseType);
+ assertTrue(actual.matches(".*_t[0-9a-z]{8}$"));
+ assertThat(actual.getBytes(StandardCharsets.UTF_8).length, is(63));
+ assertTrue(IndexMetaDataUtils.isGeneratedActualIndexNameMatch(actual, logicIndexName, "t_account_0"));
+ }
+
+ @Test
+ void assertGetActualIndexNameUsesDialectSpecificBudget() {
+ String logicIndexName = "oracle_length_budget";
+ String actual = IndexMetaDataUtils.getActualIndexName(logicIndexName, "t_account_0", oracleDatabaseType);
+ assertTrue(actual.matches(".*_h[0-9a-z]{8}$"));
+ assertThat(actual.getBytes(StandardCharsets.UTF_8).length, is(30));
+ }
+
+ @Test
+ void assertFindGeneratedLogicIndexNameWithTruncatedActualIndexName() {
+ String logicIndexName = "very_long_named_index_boundary_case_for_sharding_length_safety_validation";
+ String actualIndexName = IndexMetaDataUtils.getActualIndexName(logicIndexName, "t_account_0", postgreSQLDatabaseType);
+ assertThat(IndexMetaDataUtils.findGeneratedLogicIndexName(actualIndexName, "t_account_0", Collections.singleton(logicIndexName)).orElse(""),
+ is(logicIndexName));
+ }
+
+ @Test
+ void assertFindGeneratedLogicIndexNameKeepsExactCandidateWithHashLikeSuffix() {
+ assertThat(IndexMetaDataUtils.findGeneratedLogicIndexName("foo_h12345678", "t_account_0", Collections.singleton("foo_h12345678")).orElse(""),
+ is("foo_h12345678"));
+ }
+
+ @Test
+ void assertFindGeneratedLogicIndexNameKeepsExactCandidateWithTruncationLikeSuffix() {
+ assertThat(IndexMetaDataUtils.findGeneratedLogicIndexName("foo_t12345678", "t_account_0", Collections.singleton("foo_t12345678")).orElse(""),
+ is("foo_t12345678"));
+ }
+
+ @Test
+ void assertFindGeneratedLogicIndexNameKeepsUnprovableHashLikeSuffixWithoutCandidate() {
+ assertThat(IndexMetaDataUtils.findGeneratedLogicIndexName("foo_h12345678", "t_account_0", Collections.emptyList()).orElse(""),
+ is("foo_h12345678"));
+ }
+
+ @Test
+ void assertFindGeneratedLogicIndexNameKeepsUnprovableTruncationLikeSuffixWithoutCandidate() {
+ assertThat(IndexMetaDataUtils.findGeneratedLogicIndexName("foo_t12345678", "t_account_0", Collections.emptyList()).orElse(""),
+ is("foo_t12345678"));
+ }
+
@Test
void assertGetTableNames() {
IndexSegment indexSegment = new IndexSegment(0, 0, new IndexNameSegment(0, 0, new IdentifierValue("foo_idx")));
- Collection<QualifiedTable> actual = IndexMetaDataUtils.getTableNames(buildDatabase(), TypedSPILoader.getService(DatabaseType.class, "FIXTURE"), Collections.singleton(indexSegment));
+ Collection<QualifiedTable> actual = IndexMetaDataUtils.getTableNames(buildDatabase(), fixtureDatabaseType, Collections.singleton(indexSegment));
assertThat(actual.size(), is(1));
assertThat(actual.iterator().next().getSchemaName(), is("foo_db"));
assertThat(actual.iterator().next().getTableName(), is("foo_tbl"));
diff --git a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/metadata/generator/PipelineDDLDecorator.java b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/metadata/generator/PipelineDDLDecorator.java
index 72edeb7558b..a5101fdfbfa 100644
--- a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/metadata/generator/PipelineDDLDecorator.java
+++ b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/metadata/generator/PipelineDDLDecorator.java
@@ -23,6 +23,8 @@ import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.binder.context.SQLStatementContextFactory;
import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
import org.apache.shardingsphere.infra.parser.SQLParserEngine;
import org.apache.shardingsphere.sql.parser.statement.core.extractor.TableExtractor;
@@ -40,12 +42,14 @@ import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.in
import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.table.AlterTableStatement;
import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.table.CreateTableStatement;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.TreeMap;
+import java.util.stream.Collectors;
/**
* Pipeline DDL decorator.
@@ -73,7 +77,7 @@ public final class PipelineDDLDecorator {
if (Strings.isNullOrEmpty(sql)) {
return Optional.empty();
}
- String result = decorateActualSQL(targetDatabaseName, targetTableName, parserEngine, sql.trim());
+ String result = decorateActualSQL(targetDatabaseName, schemaName, targetTableName, parserEngine, sql.trim());
// TODO remove it after set search_path is supported.
if ("openGauss".equals(databaseType.getType())) {
return decorateOpenGauss(schemaName, result, parserEngine);
@@ -81,11 +85,11 @@ public final class PipelineDDLDecorator {
return Optional.of(result);
}
- private String decorateActualSQL(final String databaseName, final String targetTableName, final SQLParserEngine parserEngine, final String sql) {
+ private String decorateActualSQL(final String databaseName, final String schemaName, final String targetTableName, final SQLParserEngine parserEngine, final String sql) {
SQLStatementContext sqlStatementContext = parseSQL(databaseName, parserEngine, sql);
Map<SQLSegment, String> replaceMap = new TreeMap<>(Comparator.comparing(SQLSegment::getStartIndex));
if (sqlStatementContext.getSqlStatement() instanceof CreateTableStatement) {
- appendFromIndexAndConstraint(replaceMap, targetTableName, sqlStatementContext);
+ appendFromIndexAndConstraint(replaceMap, databaseName, schemaName, targetTableName, sqlStatementContext);
appendFromTable(replaceMap, targetTableName, sqlStatementContext);
}
if (sqlStatementContext.getSqlStatement() instanceof CommentStatement) {
@@ -93,10 +97,10 @@ public final class PipelineDDLDecorator {
}
if (sqlStatementContext.getSqlStatement() instanceof CreateIndexStatement) {
appendFromTable(replaceMap, targetTableName, sqlStatementContext);
- appendFromIndexAndConstraint(replaceMap, targetTableName, sqlStatementContext);
+ appendFromIndexAndConstraint(replaceMap, databaseName, schemaName, targetTableName, sqlStatementContext);
}
if (sqlStatementContext.getSqlStatement() instanceof AlterTableStatement) {
- appendFromIndexAndConstraint(replaceMap, targetTableName, sqlStatementContext);
+ appendFromIndexAndConstraint(replaceMap, databaseName, schemaName, targetTableName, sqlStatementContext);
appendFromTable(replaceMap, targetTableName, sqlStatementContext);
}
return doDecorateActualTable(replaceMap, sql);
@@ -106,15 +110,18 @@ public final class PipelineDDLDecorator {
return SQLStatementContextFactory.newInstance(metaData, parserEngine.parse(sql, true), currentDatabaseName);
}
- private void appendFromIndexAndConstraint(final Map<SQLSegment, String> replaceMap, final String targetTableName, final SQLStatementContext sqlStatementContext) {
+ private void appendFromIndexAndConstraint(final Map<SQLSegment, String> replaceMap, final String databaseName, final String schemaName,
+ final String targetTableName, final SQLStatementContext sqlStatementContext) {
if (sqlStatementContext.getTablesContext().getSimpleTables().isEmpty()) {
return;
}
TableNameSegment tableNameSegment = sqlStatementContext.getTablesContext().getSimpleTables().iterator().next().getTableName();
if (!tableNameSegment.getIdentifier().getValue().equals(targetTableName)) {
SQLStatementAttributes attributes = sqlStatementContext.getSqlStatement().getAttributes();
+ Collection<String> candidateLogicIndexNames = findCandidateLogicIndexNames(databaseName, schemaName, targetTableName);
for (IndexSegment each : attributes.findAttribute(IndexSQLStatementAttribute.class).map(IndexSQLStatementAttribute::getIndexes).orElse(Collections.emptyList())) {
- String logicIndexName = IndexMetaDataUtils.getLogicIndexName(each.getIndexName().getIdentifier().getValue(), tableNameSegment.getIdentifier().getValue());
+ String logicIndexName = IndexMetaDataUtils.findGeneratedLogicIndexName(
+ each.getIndexName().getIdentifier().getValue(), tableNameSegment.getIdentifier().getValue(), candidateLogicIndexNames).orElse(each.getIndexName().getIdentifier().getValue());
replaceMap.put(each.getIndexName(), logicIndexName);
}
for (ConstraintSegment each : attributes.findAttribute(ConstraintSQLStatementAttribute.class).map(ConstraintSQLStatementAttribute::getConstraints).orElse(Collections.emptyList())) {
@@ -124,6 +131,24 @@ public final class PipelineDDLDecorator {
}
}
+ private Collection<String> findCandidateLogicIndexNames(final String databaseName, final String schemaName, final String targetTableName) {
+ if (Strings.isNullOrEmpty(databaseName)) {
+ return Collections.emptyList();
+ }
+ ShardingSphereDatabase database = metaData.getDatabase(databaseName);
+ if (null == database) {
+ return Collections.emptyList();
+ }
+ if (!Strings.isNullOrEmpty(schemaName)) {
+ return database.containsSchema(schemaName) && database.getSchema(schemaName).containsTable(targetTableName)
+ ? database.getSchema(schemaName).getTable(targetTableName).getAllIndexes().stream().map(each -> each.getName()).collect(Collectors.toList())
+ : Collections.emptyList();
+ }
+ Collection<ShardingSphereSchema> matchedSchemas = database.getAllSchemas().stream().filter(each -> each.containsTable(targetTableName)).collect(Collectors.toList());
+ return 1 == matchedSchemas.size() ? matchedSchemas.iterator().next().getTable(targetTableName).getAllIndexes().stream()
+ .map(each -> each.getName()).collect(Collectors.toList()) : Collections.emptyList();
+ }
+
private void appendFromTable(final Map<SQLSegment, String> replaceMap, final String targetTableName, final SQLStatementContext sqlStatementContext) {
for (SimpleTableSegment each : sqlStatementContext.getTablesContext().getSimpleTables()) {
if (!targetTableName.equals(each.getTableName().getIdentifier().getValue())) {
diff --git a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/preparer/datasource/PipelineJobDataSourcePreparer.java b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/preparer/datasource/PipelineJobDataSourcePreparer.java
index a5638f53a61..a0070324ec5 100644
--- a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/preparer/datasource/PipelineJobDataSourcePreparer.java
+++ b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/preparer/datasource/PipelineJobDataSourcePreparer.java
@@ -142,7 +142,7 @@ public final class PipelineJobDataSourcePreparer {
private Optional<String> decorateTargetTableSQL(final CreateTableConfiguration createTableConfig, final SQLParserEngine sqlParserEngine,
final ShardingSphereMetaData metaData, final String targetDatabaseName, final String sql) {
- String schemaName = createTableConfig.getSourceName().getSchemaName();
+ String schemaName = createTableConfig.getTargetName().getSchemaName();
String targetTableName = createTableConfig.getTargetName().getTableName();
Optional<String> decoratedSQL = new PipelineDDLDecorator(metaData).decorate(databaseType, targetDatabaseName, schemaName, targetTableName, sqlParserEngine, sql);
return decoratedSQL.map(String::trim).filter(trimmedSql -> !Strings.isNullOrEmpty(trimmedSql));
diff --git a/kernel/data-pipeline/core/src/test/java/org/apache/shardingsphere/data/pipeline/core/metadata/generator/PipelineDDLDecoratorTest.java b/kernel/data-pipeline/core/src/test/java/org/apache/shardingsphere/data/pipeline/core/metadata/generator/PipelineDDLDecoratorTest.java
new file mode 100644
index 00000000000..42d572f41ff
--- /dev/null
+++ b/kernel/data-pipeline/core/src/test/java/org/apache/shardingsphere/data/pipeline/core/metadata/generator/PipelineDDLDecoratorTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.data.pipeline.core.metadata.generator;
+
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereIndex;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
+import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
+import org.apache.shardingsphere.infra.parser.SQLParserEngine;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.IndexNameSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.IndexSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.index.CreateIndexStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class PipelineDDLDecoratorTest {
+
+ private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "PostgreSQL");
+
+ @Test
+ void assertDecorateUsesSchemaSpecificCandidatesForSameNamedTables() {
+ String logicIndexName = "very_long_named_index_boundary_case_for_sharding_length_safety_validation";
+ String actualIndexName = IndexMetaDataUtils.getActualIndexName(logicIndexName, "t_order_0", databaseType);
+ assertTrue(actualIndexName.matches(".*_t[0-9a-z]{8}$"));
+ String actualSQL = String.format("CREATE INDEX %s ON t_order_0 (order_id)", actualIndexName);
+ String expected = String.format("CREATE INDEX %s ON t_order (order_id)", logicIndexName);
+ assertThat(
+ new PipelineDDLDecorator(mockMetaData(logicIndexName)).decorate(databaseType, "foo_db", "schema_b", "t_order", createParserEngine(actualSQL, actualIndexName), actualSQL).orElse(""),
+ is(expected));
+ }
+
+ private ShardingSphereMetaData mockMetaData(final String logicIndexName) {
+ ShardingSphereMetaData result = mock(ShardingSphereMetaData.class);
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+ ShardingSphereSchema schemaA = new ShardingSphereSchema("schema_a", databaseType, Collections.singleton(
+ new ShardingSphereTable("t_order", Collections.emptyList(),
+ Collections.singleton(new ShardingSphereIndex("another_very_long_named_index_for_schema_a_validation", Collections.emptyList(), false)), Collections.emptyList())),
+ Collections.emptyList());
+ ShardingSphereSchema schemaB = new ShardingSphereSchema("schema_b", databaseType, Collections.singleton(
+ new ShardingSphereTable("t_order", Collections.emptyList(),
+ Collections.singleton(new ShardingSphereIndex(logicIndexName, Collections.emptyList(), false)), Collections.emptyList())),
+ Collections.emptyList());
+ when(result.getDatabase("foo_db")).thenReturn(database);
+ when(database.containsSchema("schema_b")).thenReturn(true);
+ when(database.getSchema("schema_b")).thenReturn(schemaB);
+ when(database.getAllSchemas()).thenReturn(Arrays.asList(schemaA, schemaB));
+ return result;
+ }
+
+ private SQLParserEngine createParserEngine(final String actualSQL, final String actualIndexName) {
+ SQLParserEngine result = mock(SQLParserEngine.class);
+ when(result.parse(actualSQL, true)).thenReturn(CreateIndexStatement.builder()
+ .databaseType(databaseType)
+ .index(new IndexSegment(getIndexStartIndex(), getIndexStopIndex(actualIndexName),
+ new IndexNameSegment(getIndexStartIndex(), getIndexStopIndex(actualIndexName), new IdentifierValue(actualIndexName))))
+ .table(new SimpleTableSegment(new TableNameSegment(getTableStartIndex(actualSQL), getTableStopIndex(actualSQL), new IdentifierValue("t_order_0"))))
+ .build());
+ return result;
+ }
+
+ private int getIndexStartIndex() {
+ return "CREATE INDEX ".length();
+ }
+
+ private int getIndexStopIndex(final String actualIndexName) {
+ return getIndexStartIndex() + actualIndexName.length() - 1;
+ }
+
+ private int getTableStartIndex(final String actualSQL) {
+ return actualSQL.indexOf("t_order_0");
+ }
+
+ private int getTableStopIndex(final String actualSQL) {
+ return getTableStartIndex(actualSQL) + "t_order_0".length() - 1;
+ }
+}
diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
index 4eabfe64fe3..509fe78f026 100644
--- a/mode/core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
+++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
@@ -204,7 +204,7 @@ public final class ContextManager implements AutoCloseable {
private ShardingSphereSchema loadSchema(final ShardingSphereDatabase database, final String schemaName, final String dataSourceName) throws SQLException {
database.reloadRules();
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(Collections.singletonMap(dataSourceName, database.getResourceMetaData().getStorageUnits().get(dataSourceName)),
- database.getRuleMetaData().getRules(), metaDataContexts.getMetaData().getProps(), schemaName, database.getIdentifierContext());
+ database.getRuleMetaData().getRules(), metaDataContexts.getMetaData().getProps(), schemaName, database.getIdentifierContext(), database.getAllSchemas());
ShardingSphereSchema result = GenericSchemaBuilder.build(database.getProtocolType(), material).get(schemaName);
persistServiceFacade.getMetaDataFacade().getDatabaseMetaDataFacade().getView().load(database.getName(), schemaName).forEach(result::putView);
return result;
@@ -231,7 +231,7 @@ public final class ContextManager implements AutoCloseable {
public void reloadTable(final ShardingSphereDatabase database, final String schemaName, final IdentifierValue tableName) {
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(
database.getResourceMetaData().getStorageUnits(), database.getRuleMetaData().getRules(), metaDataContexts.getMetaData().getProps(), schemaName,
- database.getIdentifierContext());
+ database.getIdentifierContext(), database.getAllSchemas());
try {
persistTable(database, schemaName, tableName, material);
} catch (final SQLException ex) {
@@ -263,7 +263,7 @@ public final class ContextManager implements AutoCloseable {
StorageUnit storageUnit = database.getResourceMetaData().getStorageUnits().get(dataSourceName);
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(
Collections.singletonMap(dataSourceName, storageUnit), database.getRuleMetaData().getRules(), metaDataContexts.getMetaData().getProps(), schemaName,
- database.getIdentifierContext());
+ database.getIdentifierContext(), database.getAllSchemas());
try {
persistTable(database, schemaName, tableName, material);
} catch (final SQLException ex) {
diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/factory/MetaDataContextsFactory.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/factory/MetaDataContextsFactory.java
index f9edbb60785..eee666b978d 100644
--- a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/factory/MetaDataContextsFactory.java
+++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/factory/MetaDataContextsFactory.java
@@ -172,7 +172,8 @@ public final class MetaDataContextsFactory {
final MetaDataContexts originalMetaDataContext) throws SQLException {
ConfigurationProperties props = originalMetaDataContext.getMetaData().getProps();
DatabaseType protocolType = DatabaseTypeEngine.getProtocolType(databaseConfig, props);
- return ShardingSphereDatabaseFactory.create(databaseName, protocolType, databaseConfig, props, instanceContext);
+ return ShardingSphereDatabaseFactory.createWithSchemaMetaDataRevisionCandidates(databaseName, protocolType, databaseConfig, props, instanceContext,
+ originalMetaDataContext.getMetaData().getDatabase(databaseName).getAllSchemas());
}
private ResourceMetaData getEffectiveResourceMetaData(final ShardingSphereDatabase database, final SwitchingResource switchingResource) {
diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/persist/metadata/DatabaseMetaDataPersistFacade.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/persist/metadata/DatabaseMetaDataPersistFacade.java
index 8322b168074..08a92298998 100644
--- a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/persist/metadata/DatabaseMetaDataPersistFacade.java
+++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/persist/metadata/DatabaseMetaDataPersistFacade.java
@@ -106,7 +106,7 @@ public final class DatabaseMetaDataPersistFacade {
ShardingSphereDatabase database = reloadMetaDataContexts.getMetaData().getDatabase(databaseName);
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getResourceMetaData().getStorageUnits(),
database.getRuleMetaData().getRules(), reloadMetaDataContexts.getMetaData().getProps(), new DatabaseTypeRegistry(database.getProtocolType()).getDefaultSchemaName(databaseName),
- database.getIdentifierContext());
+ database.getIdentifierContext(), database.getAllSchemas());
try {
Map<String, ShardingSphereSchema> schemas = GenericSchemaBuilder.build(database.getProtocolType(), material);
for (Entry<String, ShardingSphereSchema> entry : schemas.entrySet()) {
@@ -130,7 +130,7 @@ public final class DatabaseMetaDataPersistFacade {
ShardingSphereDatabase database = reloadMetaDataContexts.getMetaData().getDatabase(databaseName);
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getResourceMetaData().getStorageUnits(),
database.getRuleMetaData().getRules(), reloadMetaDataContexts.getMetaData().getProps(),
- new DatabaseTypeRegistry(database.getProtocolType()).getDefaultSchemaName(databaseName), database.getIdentifierContext());
+ new DatabaseTypeRegistry(database.getProtocolType()).getDefaultSchemaName(databaseName), database.getIdentifierContext(), database.getAllSchemas());
try {
Map<String, ShardingSphereSchema> schemas = GenericSchemaBuilder.build(needReloadTables, database.getProtocolType(), material);
Map<String, Collection<ShardingSphereTable>> result = new HashMap<>(schemas.size(), 1F);
diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/CreateTablePushDownMetaDataRefresher.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/CreateTablePushDownMetaDataRefresher.java
index 1bd58c4346e..ff926da6e4b 100644
--- a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/CreateTablePushDownMetaDataRefresher.java
+++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/CreateTablePushDownMetaDataRefresher.java
@@ -20,12 +20,21 @@ package org.apache.shardingsphere.mode.metadata.refresher.pushdown.type.table;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereIndex;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
import org.apache.shardingsphere.mode.metadata.refresher.pushdown.PushDownMetaDataRefresher;
+import org.apache.shardingsphere.mode.metadata.refresher.util.TableRefreshUtils;
import org.apache.shardingsphere.mode.persist.service.MetaDataManagerPersistService;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.constraint.ConstraintDefinitionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.table.CreateTableStatement;
import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.stream.Collectors;
/**
* Create table push down meta data refresher.
@@ -37,7 +46,8 @@ public final class CreateTablePushDownMetaDataRefresher implements PushDownMetaD
@Override
public void refresh(final MetaDataManagerPersistService metaDataManagerPersistService, final ShardingSphereDatabase database, final String logicDataSourceName,
final String schemaName, final DatabaseType databaseType, final CreateTableStatement sqlStatement, final ConfigurationProperties props) throws SQLException {
- ShardingSphereTable loadedTable = metaDataLoader.loadCreatedTable(database, logicDataSourceName, schemaName, sqlStatement.getTable().getTableName().getIdentifier(), props);
+ ShardingSphereTable loadedTable = metaDataLoader.loadCreatedTable(database, logicDataSourceName, schemaName, sqlStatement.getTable().getTableName().getIdentifier(), props,
+ createSchemaMetaDataRevisionCandidateSchemas(database, schemaName, sqlStatement, props));
metaDataManagerPersistService.createTable(database, schemaName, loadedTable);
}
@@ -45,4 +55,28 @@ public final class CreateTablePushDownMetaDataRefresher implements PushDownMetaD
public Class<CreateTableStatement> getType() {
return CreateTableStatement.class;
}
+
+ private Collection<ShardingSphereSchema> createSchemaMetaDataRevisionCandidateSchemas(final ShardingSphereDatabase database, final String schemaName,
+ final CreateTableStatement sqlStatement, final ConfigurationProperties props) {
+ Collection<ShardingSphereIndex> indexes = createIndexMetaDataRevisionCandidates(sqlStatement);
+ if (indexes.isEmpty()) {
+ return database.getAllSchemas();
+ }
+ Collection<ShardingSphereSchema> result = new LinkedList<>(database.getAllSchemas());
+ String tableName = TableRefreshUtils.getTableLoadCandidateName(database, sqlStatement.getTable().getTableName().getIdentifier(), props);
+ result.add(new ShardingSphereSchema(schemaName, database.getProtocolType(),
+ Collections.singleton(new ShardingSphereTable(tableName, Collections.emptyList(), indexes, Collections.emptyList())), Collections.emptyList()));
+ return result;
+ }
+
+ private Collection<ShardingSphereIndex> createIndexMetaDataRevisionCandidates(final CreateTableStatement sqlStatement) {
+ Collection<ShardingSphereIndex> result = new LinkedList<>();
+ for (ConstraintDefinitionSegment each : sqlStatement.getConstraintDefinitions()) {
+ each.getIndexName().ifPresent(optional -> result.add(new ShardingSphereIndex(
+ optional.getIndexName().getIdentifier().getValue(), each.getIndexColumns().stream()
+ .map(ColumnSegment::getIdentifier).map(optionalColumn -> optionalColumn.getValue()).collect(Collectors.toList()),
+ each.isUniqueKey() || optional.isUniqueKey())));
+ }
+ return result;
+ }
}
diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/TableMetaDataRefresherLoader.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/TableMetaDataRefresherLoader.java
index 3a20f9d7e98..f0c88f60ca0 100644
--- a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/TableMetaDataRefresherLoader.java
+++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/TableMetaDataRefresherLoader.java
@@ -29,6 +29,7 @@ import org.apache.shardingsphere.mode.metadata.refresher.util.TableRefreshUtils;
import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
import java.sql.SQLException;
+import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Map;
@@ -52,7 +53,25 @@ public final class TableMetaDataRefresherLoader {
*/
public ShardingSphereTable loadCreatedTable(final ShardingSphereDatabase database, final String logicDataSourceName,
final String schemaName, final IdentifierValue tableIdentifierValue, final ConfigurationProperties props) throws SQLException {
- return loadTable(database, logicDataSourceName, schemaName, tableIdentifierValue, props, false);
+ return loadCreatedTable(database, logicDataSourceName, schemaName, tableIdentifierValue, props, database.getAllSchemas());
+ }
+
+ /**
+ * Load created table meta data.
+ *
+ * @param database database
+ * @param logicDataSourceName logic data source name
+ * @param schemaName schema name
+ * @param tableIdentifierValue table identifier value
+ * @param props configuration properties
+ * @param schemaMetaDataRevisionCandidateSchemas schema meta data revision candidate schemas
+ * @return loaded table meta data
+ * @throws SQLException SQL exception
+ */
+ public ShardingSphereTable loadCreatedTable(final ShardingSphereDatabase database, final String logicDataSourceName, final String schemaName,
+ final IdentifierValue tableIdentifierValue, final ConfigurationProperties props,
+ final Collection<ShardingSphereSchema> schemaMetaDataRevisionCandidateSchemas) throws SQLException {
+ return loadTable(database, logicDataSourceName, schemaName, tableIdentifierValue, props, false, schemaMetaDataRevisionCandidateSchemas);
}
/**
@@ -68,11 +87,12 @@ public final class TableMetaDataRefresherLoader {
*/
public ShardingSphereTable loadAlteredTable(final ShardingSphereDatabase database, final String logicDataSourceName,
final String schemaName, final IdentifierValue tableIdentifierValue, final ConfigurationProperties props) throws SQLException {
- return loadTable(database, logicDataSourceName, schemaName, tableIdentifierValue, props, true);
+ return loadTable(database, logicDataSourceName, schemaName, tableIdentifierValue, props, true, database.getAllSchemas());
}
private ShardingSphereTable loadTable(final ShardingSphereDatabase database, final String logicDataSourceName, final String schemaName,
- final IdentifierValue tableIdentifierValue, final ConfigurationProperties props, final boolean fallbackWhenMissing) throws SQLException {
+ final IdentifierValue tableIdentifierValue, final ConfigurationProperties props, final boolean fallbackWhenMissing,
+ final Collection<ShardingSphereSchema> schemaMetaDataRevisionCandidateSchemas) throws SQLException {
String candidateTableName = TableRefreshUtils.getTableLoadCandidateName(database, tableIdentifierValue, props);
RuleMetaData ruleMetaData = new RuleMetaData(new LinkedList<>(database.getRuleMetaData().getRules()));
boolean singleTable = TableRefreshUtils.isSingleTable(candidateTableName, database);
@@ -80,7 +100,7 @@ public final class TableMetaDataRefresherLoader {
ruleMetaData.getAttributes(MutableDataNodeRuleAttribute.class).forEach(each -> each.put(logicDataSourceName, schemaName, candidateTableName));
}
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getResourceMetaData().getStorageUnits(), ruleMetaData.getRules(), props, schemaName,
- database.getIdentifierContext());
+ database.getIdentifierContext(), schemaMetaDataRevisionCandidateSchemas);
Map<String, ShardingSphereSchema> schemas = GenericSchemaBuilder.build(Collections.singletonList(candidateTableName), database.getProtocolType(), material);
ShardingSphereTable result = Optional.ofNullable(schemas.get(schemaName)).map(optional -> optional.getTable(candidateTableName))
.orElseGet(() -> fallbackWhenMissing ? new ShardingSphereTable(candidateTableName, Collections.emptyList(), Collections.emptyList(), Collections.emptyList()) : null);
diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/view/ViewMetaDataRefresherLoader.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/view/ViewMetaDataRefresherLoader.java
index 8162040e1ce..4858e749805 100644
--- a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/view/ViewMetaDataRefresherLoader.java
+++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/view/ViewMetaDataRefresherLoader.java
@@ -61,7 +61,7 @@ public final class ViewMetaDataRefresherLoader {
ruleMetaData.getAttributes(MutableDataNodeRuleAttribute.class).forEach(each -> each.put(logicDataSourceName, schemaName, candidateViewName));
}
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getResourceMetaData().getStorageUnits(), ruleMetaData.getRules(), props, schemaName,
- database.getIdentifierContext());
+ database.getIdentifierContext(), database.getAllSchemas());
Map<String, ShardingSphereSchema> schemas = GenericSchemaBuilder.build(Collections.singletonList(candidateViewName), database.getProtocolType(), material);
Optional<ShardingSphereTable> actualTableMetaData = Optional.ofNullable(schemas.get(schemaName)).map(optional -> optional.getTable(candidateViewName));
Preconditions.checkState(actualTableMetaData.isPresent(), "Load actual view metadata '%s' failed.", candidateViewName);
@@ -96,7 +96,7 @@ public final class ViewMetaDataRefresherLoader {
ruleMetaData.getAttributes(MutableDataNodeRuleAttribute.class).forEach(each -> each.put(logicDataSourceName, schemaName, candidateViewName));
}
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getResourceMetaData().getStorageUnits(), ruleMetaData.getRules(), props, schemaName,
- database.getIdentifierContext());
+ database.getIdentifierContext(), database.getAllSchemas());
Map<String, ShardingSphereSchema> schemas = GenericSchemaBuilder.build(Collections.singletonList(candidateViewName), database.getProtocolType(), material);
Optional<ShardingSphereTable> actualViewMetaData = Optional.ofNullable(schemas.get(schemaName)).map(optional -> optional.getTable(candidateViewName));
ShardingSphereSchema result = new ShardingSphereSchema(schemaName, database.getProtocolType());
diff --git a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/factory/MetaDataContextsFactoryTest.java b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/factory/MetaDataContextsFactoryTest.java
index 545a7e650ff..d53d9f49e5e 100644
--- a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/factory/MetaDataContextsFactoryTest.java
+++ b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/factory/MetaDataContextsFactoryTest.java
@@ -109,6 +109,9 @@ class MetaDataContextsFactoryTest {
when(ShardingSphereDatabaseFactory.create(anyString(), any(DatabaseType.class), any(DatabaseConfiguration.class),
any(ConfigurationProperties.class), any(ComputeNodeInstanceContext.class), anyCollection()))
.thenAnswer(invocation -> createDatabaseFromConfiguration(invocation.getArgument(0), invocation.getArgument(1), invocation.getArgument(2), invocation.getArgument(5)));
+ when(ShardingSphereDatabaseFactory.createWithSchemaMetaDataRevisionCandidates(anyString(), any(DatabaseType.class), any(DatabaseConfiguration.class),
+ any(ConfigurationProperties.class), any(ComputeNodeInstanceContext.class), anyCollection()))
+ .thenAnswer(invocation -> createDatabaseFromConfiguration(invocation.getArgument(0), invocation.getArgument(1), invocation.getArgument(2), invocation.getArgument(5)));
when(GlobalRulesBuilder.buildRules(anyCollection(), anyCollection(), any(ConfigurationProperties.class))).thenReturn(Collections.singleton(new MockedRule()));
when(DatabaseTypeEngine.getProtocolType(any(DatabaseConfiguration.class), any(ConfigurationProperties.class))).thenReturn(databaseType);
when(DatabaseTypeFactory.get(anyString())).thenReturn(databaseType);
@@ -208,6 +211,22 @@ class MetaDataContextsFactoryTest {
assertTrue(actual.getMetaData().containsDatabase("foo_db"));
}
+ @Test
+ void assertCreateByAlterRuleWithReloadedSchemasPassesCurrentSchemasAsRevisionCandidates() throws SQLException {
+ ShardingSphereSchema currentSchema = createSchemaWithTable("foo_schema", "current_table");
+ ShardingSphereDatabase database = new ShardingSphereDatabase(
+ "foo_db", databaseType, createResourceMetaDataWithSingleUnit(), new RuleMetaData(Collections.emptyList()), Collections.singleton(currentSchema),
+ new ConfigurationProperties(new Properties()));
+ ShardingSphereMetaData metaData = new ShardingSphereMetaData(
+ Collections.singleton(database), new ResourceMetaData(Collections.emptyMap(), Collections.emptyMap()), new RuleMetaData(Collections.emptyList()),
+ new ConfigurationProperties(new Properties()));
+ MetaDataContexts originalMetaDataContexts = new MetaDataContexts(metaData, new ShardingSphereStatistics());
+ ShardingSphereDatabase actualDatabase = new MetaDataContextsFactory(metaDataPersistFacade, mock())
+ .createChangedDatabaseByRebuild("foo_db", null, Collections.singleton(new MockedRuleConfiguration("alter_rule")), originalMetaDataContexts);
+ assertTrue(actualDatabase.containsSchema("foo_schema"));
+ assertTrue(actualDatabase.getSchema("foo_schema").containsTable("current_table"));
+ }
+
@Test
void assertCreateWithProxyInstanceMetaData() throws SQLException {
ComputeNodeInstanceContext computeNodeInstanceContext = mock(ComputeNodeInstanceContext.class, RETURNS_DEEP_STUBS);
diff --git a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/CreateTablePushDownMetaDataRefresherTest.java b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/CreateTablePushDownMetaDataRefresherTest.java
index fe3db02acfb..19588f005ad 100644
--- a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/CreateTablePushDownMetaDataRefresherTest.java
+++ b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/refresher/pushdown/type/table/CreateTablePushDownMetaDataRefresherTest.java
@@ -17,28 +17,61 @@
package org.apache.shardingsphere.mode.metadata.refresher.pushdown.type.table;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
+import org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
+import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
+import org.apache.shardingsphere.infra.datanode.DataNode;
import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
import org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
+import org.apache.shardingsphere.infra.metadata.database.schema.reviser.MetaDataReviseEntry;
+import org.apache.shardingsphere.infra.metadata.database.schema.reviser.index.IndexReviser;
+import org.apache.shardingsphere.infra.metadata.database.schema.reviser.table.TableNameReviser;
+import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import org.apache.shardingsphere.infra.rule.attribute.RuleAttributes;
+import org.apache.shardingsphere.infra.rule.attribute.datanode.DataNodeRuleAttribute;
+import org.apache.shardingsphere.infra.rule.attribute.table.TableMapperRuleAttribute;
+import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPILoader;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.mode.metadata.refresher.pushdown.PushDownMetaDataManagerPersistServiceFixture;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.constraint.ConstraintDefinitionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.IndexNameSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.IndexSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment;
import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.table.CreateTableStatement;
import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
import org.h2.jdbcx.JdbcDataSource;
import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Properties;
+import java.util.stream.Collectors;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
+import static org.mockito.ArgumentMatchers.anyCollection;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
class CreateTablePushDownMetaDataRefresherTest {
@@ -64,9 +97,44 @@ class CreateTablePushDownMetaDataRefresherTest {
assertThat(persistService.getCreatedTable().getName(), is("Foo_Tbl"));
}
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Test
+ void assertRefreshCreatedShardingTableRestoresTruncatedNamedIndexFromCreateTableStatementCandidate() throws SQLException {
+ String logicTableName = "tbl";
+ String firstActualTableName = "tbl_0";
+ String secondActualTableName = "tbl_1";
+ String logicIndexName = "named_index_boundary_case_abcdefghijklmnopqrstuvwxyz_0123456789";
+ DatabaseType postgreSQLDatabaseType = mock(DatabaseType.class);
+ when(postgreSQLDatabaseType.getType()).thenReturn("PostgreSQL");
+ String firstActualIndexName = IndexMetaDataUtils.getActualIndexName(logicIndexName, firstActualTableName, postgreSQLDatabaseType);
+ String secondActualIndexName = IndexMetaDataUtils.getActualIndexName(logicIndexName, secondActualTableName, postgreSQLDatabaseType);
+ JdbcDataSource dataSource = createDataSource("create_sharding_table_with_truncated_index");
+ executeUpdate(dataSource,
+ String.format("CREATE TABLE \"%s\" (\"foo_col\" INT)", firstActualTableName),
+ String.format("CREATE INDEX \"%s\" ON \"%s\" (\"foo_col\")", firstActualIndexName, firstActualTableName),
+ String.format("CREATE TABLE \"%s\" (\"foo_col\" INT)", secondActualTableName),
+ String.format("CREATE INDEX \"%s\" ON \"%s\" (\"foo_col\")", secondActualIndexName, secondActualTableName));
+ CreateTableCandidateRule rule = new CreateTableCandidateRule(logicTableName, Arrays.asList(
+ new DataNode(LOGIC_DATA_SOURCE_NAME, SCHEMA_NAME, firstActualTableName), new DataNode(LOGIC_DATA_SOURCE_NAME, SCHEMA_NAME, secondActualTableName)));
+ Map<ShardingSphereRule, MetaDataReviseEntry<?>> reviseEntries = Collections.singletonMap(rule, new CreateTableCandidateMetaDataReviseEntry());
+ PushDownMetaDataManagerPersistServiceFixture persistService = new PushDownMetaDataManagerPersistServiceFixture();
+ try (MockedStatic<OrderedSPILoader> mockedLoader = mockStatic(OrderedSPILoader.class, CALLS_REAL_METHODS)) {
+ mockedLoader.when(() -> OrderedSPILoader.getServices(eq(MetaDataReviseEntry.class), anyCollection())).thenReturn((Map) reviseEntries);
+ new CreateTablePushDownMetaDataRefresher().refresh(persistService, createDatabase(dataSource, new RuleMetaData(Collections.singleton(rule))), LOGIC_DATA_SOURCE_NAME, SCHEMA_NAME,
+ databaseType, createCreateTableStatement(logicTableName, logicIndexName), createPropertiesWithCheckMetaDataEnabled());
+ }
+ assertThat(persistService.getCreatedTableSchemaName(), is(SCHEMA_NAME));
+ assertThat(persistService.getCreatedTable().getName(), is(logicTableName));
+ assertThat(persistService.getCreatedTable().getAllIndexes().iterator().next().getName(), is(logicIndexName));
+ }
+
private ShardingSphereDatabase createDatabase(final JdbcDataSource dataSource) {
+ return createDatabase(dataSource, new RuleMetaData(Collections.emptyList()));
+ }
+
+ private ShardingSphereDatabase createDatabase(final JdbcDataSource dataSource, final RuleMetaData ruleMetaData) {
return new ShardingSphereDatabase("foo_db", databaseType, new ResourceMetaData(Collections.singletonMap(LOGIC_DATA_SOURCE_NAME, dataSource)),
- new RuleMetaData(Collections.emptyList()), Collections.emptyList(), new ConfigurationProperties(new Properties()));
+ ruleMetaData, Collections.emptyList(), new ConfigurationProperties(new Properties()));
}
private JdbcDataSource createDataSource(final String databaseName) {
@@ -86,4 +154,163 @@ class CreateTablePushDownMetaDataRefresherTest {
}
}
}
+
+ private CreateTableStatement createCreateTableStatement(final String logicTableName, final String logicIndexName) {
+ ConstraintDefinitionSegment constraintDefinition = new ConstraintDefinitionSegment(0, 0);
+ constraintDefinition.setIndexName(new IndexSegment(0, 0, new IndexNameSegment(0, 0, new IdentifierValue(logicIndexName))));
+ constraintDefinition.getIndexColumns().add(new ColumnSegment(0, 0, new IdentifierValue("foo_col")));
+ return CreateTableStatement.builder()
+ .databaseType(databaseType)
+ .table(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue(logicTableName))))
+ .constraintDefinitions(Collections.singleton(constraintDefinition))
+ .build();
+ }
+
+ private ConfigurationProperties createPropertiesWithCheckMetaDataEnabled() {
+ Properties result = new Properties();
+ result.setProperty(ConfigurationPropertyKey.CHECK_TABLE_METADATA_ENABLED.getKey(), Boolean.TRUE.toString());
+ return new ConfigurationProperties(result);
+ }
+
+ private static final class CreateTableCandidateRule implements ShardingSphereRule {
+
+ private final String logicTableName;
+
+ private final CreateTableCandidateRuleAttribute ruleAttribute;
+
+ private CreateTableCandidateRule(final String logicTableName, final Collection<DataNode> dataNodes) {
+ this.logicTableName = logicTableName;
+ ruleAttribute = new CreateTableCandidateRuleAttribute(logicTableName, dataNodes);
+ }
+
+ @Override
+ public RuleConfiguration getConfiguration() {
+ return new CreateTableCandidateRuleConfiguration();
+ }
+
+ @Override
+ public RuleAttributes getAttributes() {
+ return new RuleAttributes(ruleAttribute);
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+
+ private String reviseTableName(final String tableName) {
+ return ruleAttribute.findLogicTableByActualTable(tableName).orElse(tableName);
+ }
+ }
+
+ private static final class CreateTableCandidateRuleConfiguration implements RuleConfiguration {
+ }
+
+ private static final class CreateTableCandidateRuleAttribute implements TableMapperRuleAttribute, DataNodeRuleAttribute {
+
+ private final String logicTableName;
+
+ private final Map<String, Collection<DataNode>> dataNodes;
+
+ private CreateTableCandidateRuleAttribute(final String logicTableName, final Collection<DataNode> dataNodes) {
+ this.logicTableName = logicTableName;
+ this.dataNodes = new LinkedHashMap<>(1, 1F);
+ this.dataNodes.put(logicTableName, dataNodes);
+ }
+
+ @Override
+ public Collection<String> getLogicTableNames() {
+ return Collections.singleton(logicTableName);
+ }
+
+ @Override
+ public Collection<String> getDistributedTableNames() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection<String> getEnhancedTableNames() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Map<String, Collection<DataNode>> getAllDataNodes() {
+ return dataNodes;
+ }
+
+ @Override
+ public Collection<DataNode> getDataNodesByTableName(final String tableName) {
+ return dataNodes.getOrDefault(tableName, Collections.emptyList());
+ }
+
+ @Override
+ public Optional<String> findFirstActualTable(final String logicTable) {
+ return getDataNodesByTableName(logicTable).stream().findFirst().map(DataNode::getTableName);
+ }
+
+ @Override
+ public boolean isNeedAccumulate(final Collection<String> tables) {
+ return false;
+ }
+
+ @Override
+ public Optional<String> findLogicTableByActualTable(final String actualTable) {
+ return dataNodes.entrySet().stream().filter(entry -> entry.getValue().stream().map(DataNode::getTableName).anyMatch(each -> each.equalsIgnoreCase(actualTable)))
+ .map(Entry::getKey).findFirst();
+ }
+
+ @Override
+ public Optional<String> findActualTableByCatalog(final String catalog, final String logicTable) {
+ return findFirstActualTable(logicTable);
+ }
+
+ @Override
+ public boolean isReplicaBasedDistribution() {
+ return false;
+ }
+ }
+
+ private static final class CreateTableCandidateMetaDataReviseEntry implements MetaDataReviseEntry<CreateTableCandidateRule> {
+
+ @Override
+ public Optional<TableNameReviser<CreateTableCandidateRule>> getTableNameReviser() {
+ return Optional.of((originalName, rule) -> rule.reviseTableName(originalName));
+ }
+
+ @Override
+ public Optional<IndexReviser<CreateTableCandidateRule>> getIndexReviser(final CreateTableCandidateRule rule, final String tableName) {
+ return Optional.of(new CreateTableCandidateIndexReviser());
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+
+ @Override
+ public Class<CreateTableCandidateRule> getTypeClass() {
+ return CreateTableCandidateRule.class;
+ }
+ }
+
+ private static final class CreateTableCandidateIndexReviser implements IndexReviser<CreateTableCandidateRule> {
+
+ @Override
+ public Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final Collection<TableMetaData> originalTableMetaDataList,
+ final CreateTableCandidateRule rule) {
+ return revise(tableName, originalMetaData, originalTableMetaDataList, Collections.emptyList(), rule);
+ }
+
+ @Override
+ public Optional<IndexMetaData> revise(final String tableName, final IndexMetaData originalMetaData, final Collection<TableMetaData> originalTableMetaDataList,
+ final Collection<TableMetaData> schemaMetaDataRevisionCandidateTableMetaDataList, final CreateTableCandidateRule rule) {
+ Collection<String> candidateIndexNames = schemaMetaDataRevisionCandidateTableMetaDataList.stream()
+ .filter(each -> rule.logicTableName.equalsIgnoreCase(each.getName())).flatMap(each -> each.getIndexes().stream()).map(IndexMetaData::getName)
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+ IndexMetaData result = new IndexMetaData(IndexMetaDataUtils.findGeneratedLogicIndexName(
+ originalMetaData.getName(), tableName, candidateIndexNames).orElse(originalMetaData.getName()), originalMetaData.getColumns());
+ result.setUnique(originalMetaData.isUnique());
+ return Optional.of(result);
+ }
+ }
}
diff --git a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/persist/service/ClusterMetaDataManagerPersistService.java b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/persist/service/ClusterMetaDataManagerPersistService.java
index 19de9d7d056..31baf237ac6 100644
--- a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/persist/service/ClusterMetaDataManagerPersistService.java
+++ b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/persist/service/ClusterMetaDataManagerPersistService.java
@@ -268,7 +268,8 @@ public final class ClusterMetaDataManagerPersistService implements MetaDataManag
private ShardingSphereDatabase rebuildDatabaseSchemaIndex(final String databaseName, final MetaDataContexts reloadMetaDataContexts) {
ShardingSphereDatabase database = reloadMetaDataContexts.getMetaData().getDatabase(databaseName);
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getResourceMetaData().getStorageUnits(), database.getRuleMetaData().getRules(),
- reloadMetaDataContexts.getMetaData().getProps(), new DatabaseTypeRegistry(database.getProtocolType()).getDefaultSchemaName(databaseName), database.getIdentifierContext());
+ reloadMetaDataContexts.getMetaData().getProps(), new DatabaseTypeRegistry(database.getProtocolType()).getDefaultSchemaName(databaseName), database.getIdentifierContext(),
+ database.getAllSchemas());
Collection<ShardingSphereSchema> schemas = new LinkedList<>(GenericSchemaBuilder.build(database.getProtocolType(), material).values());
return new ShardingSphereDatabase(database.getName(), database.getProtocolType(), database.getResourceMetaData(),
database.getRuleMetaData(), schemas, reloadMetaDataContexts.getMetaData().getProps());
diff --git a/mode/type/standalone/core/src/main/java/org/apache/shardingsphere/mode/manager/standalone/persist/service/StandaloneMetaDataManagerPersistService.java b/mode/type/standalone/core/src/main/java/org/apache/shardingsphere/mode/manager/standalone/persist/service/StandaloneMetaDataManagerPersistService.java
index 514f7cc1251..f8ba591c4da 100644
--- a/mode/type/standalone/core/src/main/java/org/apache/shardingsphere/mode/manager/standalone/persist/service/StandaloneMetaDataManagerPersistService.java
+++ b/mode/type/standalone/core/src/main/java/org/apache/shardingsphere/mode/manager/standalone/persist/service/StandaloneMetaDataManagerPersistService.java
@@ -334,7 +334,8 @@ public final class StandaloneMetaDataManagerPersistService implements MetaDataMa
private ShardingSphereDatabase rebuildDatabaseSchemaIndex(final String databaseName, final MetaDataContexts metaDataContexts) {
ShardingSphereDatabase database = metaDataContexts.getMetaData().getDatabase(databaseName);
GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getResourceMetaData().getStorageUnits(), database.getRuleMetaData().getRules(),
- metaDataContexts.getMetaData().getProps(), new DatabaseTypeRegistry(database.getProtocolType()).getDefaultSchemaName(databaseName), database.getIdentifierContext());
+ metaDataContexts.getMetaData().getProps(), new DatabaseTypeRegistry(database.getProtocolType()).getDefaultSchemaName(databaseName), database.getIdentifierContext(),
+ database.getAllSchemas());
Collection<ShardingSphereSchema> schemas = new LinkedList<>(GenericSchemaBuilder.build(database.getProtocolType(), material).values());
return new ShardingSphereDatabase(database.getName(), database.getProtocolType(), database.getResourceMetaData(), database.getRuleMetaData(), schemas,
metaDataContexts.getMetaData().getProps());
diff --git a/test/it/rewriter/src/test/resources/scenario/sharding/case/ddl/index.xml b/test/it/rewriter/src/test/resources/scenario/sharding/case/ddl/index.xml
index d1c86054bec..b5a9f5d78a2 100644
--- a/test/it/rewriter/src/test/resources/scenario/sharding/case/ddl/index.xml
+++ b/test/it/rewriter/src/test/resources/scenario/sharding/case/ddl/index.xml
@@ -22,7 +22,7 @@
<output sql="CREATE INDEX status_idx ON t_account_0 (status)" />
<output sql="CREATE INDEX status_idx ON t_account_1 (status)" />
</rewrite-assertion>
-
+
<rewrite-assertion id="create_index_for_schema_uniqueness_level_db" db-types="PostgreSQL,openGauss">
<input sql="CREATE INDEX status_idx ON t_account (status)" />
<output sql="CREATE INDEX status_idx_t_account_0 ON t_account_0 (status)" />
@@ -34,7 +34,13 @@
<output sql="CREATE INDEX status_idx_t_account_0 ON public.t_account_0 (status)" />
<output sql="CREATE INDEX status_idx_t_account_1 ON public.t_account_1 (status)" />
</rewrite-assertion>
-
+
+ <rewrite-assertion id="create_index_near_identifier_limit_with_named_index" db-types="PostgreSQL,openGauss">
+ <input sql="CREATE INDEX named_index_boundary_case_abcdefghijklmnopqrstuvwxyz ON t_account (status)" />
+ <output sql="CREATE INDEX named_index_boundary_case_abcdefghijklmnopqrstuvwxyz_h5n59w5zl ON t_account_0 (status)" />
+ <output sql="CREATE INDEX named_index_boundary_case_abcdefghijklmnopqrstuvwxyz_h11kmgp1d ON t_account_1 (status)" />
+ </rewrite-assertion>
+
<rewrite-assertion id="create_index_without_index_name_with_single_column" db-types="PostgreSQL,openGauss">
<input sql="/* SHARDINGSPHERE_HINT: SKIP_METADATA_VALIDATE=true */ CREATE INDEX ON t_account (status)" />
<output sql="CREATE INDEX status_idx_t_account_0 ON t_account_0 (status)" />
@@ -59,6 +65,12 @@
<output sql="CREATE INDEX status_account_id_idx_t_account_1 ON public.t_account_1 (status, account_id)" />
</rewrite-assertion>
+ <rewrite-assertion id="create_index_without_index_name_near_identifier_limit" db-types="PostgreSQL,openGauss">
+ <input sql="/* SHARDINGSPHERE_HINT: SKIP_METADATA_VALIDATE=true */ CREATE INDEX ON t_account (status, status, status, status, status, status, status, status, status)" />
+ <output sql="CREATE INDEX status_status_status_status_status_status_status_stat_t0dgoa155 ON t_account_0 (status, status, status, status, status, status, status, status, status)" />
+ <output sql="CREATE INDEX status_status_status_status_status_status_status_stat_t6hp20jb3 ON t_account_1 (status, status, status, status, status, status, status, status, status)" />
+ </rewrite-assertion>
+
<rewrite-assertion id="alter_index_rename" db-types="PostgreSQL,openGauss">
<input sql="ALTER INDEX status_idx_exist RENAME TO status_idx_new" />
<output sql="ALTER INDEX status_idx_exist_t_account_0 RENAME TO status_idx_new_t_account_0" />
@@ -70,34 +82,34 @@
<output sql="ALTER INDEX public.status_idx_exist_t_account_0 RENAME TO status_idx_new_t_account_0" />
<output sql="ALTER INDEX public.status_idx_exist_t_account_1 RENAME TO status_idx_new_t_account_1" />
</rewrite-assertion>
-
+
<rewrite-assertion id="drop_index_for_table_uniqueness_level_db" db-types="MySQL">
<input sql="DROP INDEX status_idx_exist ON t_account" />
<output sql="DROP INDEX status_idx_exist ON t_account_0" />
<output sql="DROP INDEX status_idx_exist ON t_account_1" />
</rewrite-assertion>
-
+
<rewrite-assertion id="drop_index_with_single_table_for_table_uniqueness_level_db" db-types="MySQL">
<input sql="DROP INDEX single_id_idx ON t_single" />
<output sql="DROP INDEX single_id_idx ON t_single" />
</rewrite-assertion>
-
+
<rewrite-assertion id="drop_index_with_broadcast_table_for_table_uniqueness_level_db" db-types="MySQL">
<input sql="DROP INDEX broadcast_id_idx ON t_config" />
<output sql="DROP INDEX broadcast_id_idx ON t_config" />
</rewrite-assertion>
-
+
<rewrite-assertion id="drop_index_for_schema_uniqueness_level_db" db-types="PostgreSQL,openGauss">
<input sql="DROP INDEX status_idx_exist" />
<output sql="DROP INDEX status_idx_exist_t_account_0" />
<output sql="DROP INDEX status_idx_exist_t_account_1" />
</rewrite-assertion>
-
+
<rewrite-assertion id="drop_index_with_single_table_for_schema_uniqueness_level_db" db-types="PostgreSQL,openGauss">
<input sql="DROP INDEX single_id_idx" />
<output sql="DROP INDEX single_id_idx" />
</rewrite-assertion>
-
+
<rewrite-assertion id="drop_index_with_broadcast_table_for_schema_uniqueness_level_db" db-types="PostgreSQL,openGauss">
<input sql="DROP INDEX broadcast_id_idx" />
<output sql="DROP INDEX broadcast_id_idx" />