From e9390375598f97f7bfac2329da6c8968e0eb77cc Mon Sep 17 00:00:00 2001 From: Raigor Date: Wed, 25 Sep 2024 10:38:30 +0800 Subject: [PATCH] Pick #32700, fix alter view exception (#11) --- .../dal/show/ShowCreateTableMergedResult.java | 23 +++++++++++++++++++ .../ddl/ShardingDDLStatementValidator.java | 21 ++++++++++++++++- .../ShardingAlterViewStatementValidator.java | 17 +++++++++----- .../ShardingCreateViewStatementValidator.java | 21 ++--------------- ...ardingAlterViewStatementValidatorTest.java | 14 ++++++----- 5 files changed, 64 insertions(+), 32 deletions(-) diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dal/show/ShowCreateTableMergedResult.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dal/show/ShowCreateTableMergedResult.java index ebf27fa5c39705..e7d8250644b79e 100644 --- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dal/show/ShowCreateTableMergedResult.java +++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dal/show/ShowCreateTableMergedResult.java @@ -17,6 +17,7 @@ package org.apache.shardingsphere.sharding.merge.dal.show; +import com.cedarsoftware.util.CaseInsensitiveMap; import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext; import org.apache.shardingsphere.infra.datanode.DataNode; import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult; @@ -26,12 +27,17 @@ 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.BindingTableRule; 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.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; +import java.util.stream.Collectors; /** * Merged result for show create table. @@ -47,6 +53,7 @@ public ShowCreateTableMergedResult(final ShardingRule shardingRule, protected void setCellValue(final MemoryQueryResultRow memoryResultSetRow, final String logicTableName, final String actualTableName, final ShardingSphereTable table, final ShardingRule shardingRule) { memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replaceFirst(actualTableName, logicTableName)); + setViewCellValue(memoryResultSetRow, logicTableName, actualTableName, shardingRule); for (ShardingSphereIndex each : table.getIndexValues()) { String actualIndexName = IndexMetaDataUtils.getActualIndexName(each.getName(), actualTableName); memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replace(actualIndexName, each.getName())); @@ -63,4 +70,20 @@ protected void setCellValue(final MemoryQueryResultRow memoryResultSetRow, final } } } + + private void setViewCellValue(final MemoryQueryResultRow memoryResultSetRow, final String logicTableName, final String actualTableName, final ShardingRule shardingRule) { + Optional shardingTable = shardingRule.findShardingTable(logicTableName); + Optional bindingTableRule = shardingRule.findBindingTableRule(logicTableName); + if (shardingTable.isPresent() && bindingTableRule.isPresent()) { + Collection actualDataNodes = shardingTable.get().getActualDataNodes().stream().filter(each -> each.getTableName().equalsIgnoreCase(actualTableName)).collect(Collectors.toList()); + Map logicAndActualTablesFromBindingTables = new CaseInsensitiveMap<>(); + for (DataNode each : actualDataNodes) { + logicAndActualTablesFromBindingTables + .putAll(shardingRule.getLogicAndActualTablesFromBindingTable(each.getDataSourceName(), logicTableName, actualTableName, bindingTableRule.get().getAllLogicTables())); + } + for (Entry entry : logicAndActualTablesFromBindingTables.entrySet()) { + memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replaceFirst(entry.getValue(), entry.getKey())); + } + } + } } diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingDDLStatementValidator.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingDDLStatementValidator.java index 2b2aa2b793b8d2..aee3d14a37dfd8 100644 --- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingDDLStatementValidator.java +++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingDDLStatementValidator.java @@ -27,6 +27,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.index.IndexSegment; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment; +import java.util.Arrays; import java.util.Collection; /** @@ -85,7 +86,7 @@ protected void validateTableNotExist(final ShardingSphereSchema schema, final Co /** * Judge whether route unit and data node are different size. - * + * * @param shardingRule sharding rule * @param routeContext route context * @param tableName table name @@ -105,4 +106,22 @@ protected boolean isRouteUnitDataNodeDifferentSize(final ShardingRule shardingRu protected boolean isSchemaContainsIndex(final ShardingSphereSchema schema, final IndexSegment index) { return schema.getAllTableNames().stream().anyMatch(each -> schema.getTable(each).containsIndex(index.getIndexName().getIdentifier().getValue())); } + + /** + * Judge whether sharding tables not binding with view. + * + * @param tableSegments table segments + * @param shardingRule sharding rule + * @param viewName view name + * @return sharding tables not binding with view or not + */ + protected boolean isShardingTablesNotBindingWithView(final Collection tableSegments, final ShardingRule shardingRule, final String viewName) { + for (SimpleTableSegment each : tableSegments) { + String logicTable = each.getTableName().getIdentifier().getValue(); + if (shardingRule.isShardingTable(logicTable) && !shardingRule.isAllBindingTables(Arrays.asList(viewName, logicTable))) { + return true; + } + } + return false; + } } diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingAlterViewStatementValidator.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingAlterViewStatementValidator.java index 53da20cb23446e..37bbdfb79f8d02 100644 --- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingAlterViewStatementValidator.java +++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingAlterViewStatementValidator.java @@ -23,6 +23,7 @@ import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase; import org.apache.shardingsphere.infra.route.context.RouteContext; import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions; +import org.apache.shardingsphere.sharding.exception.metadata.EngagedViewException; import org.apache.shardingsphere.sharding.exception.syntax.RenamedViewWithoutSameConfigurationException; import org.apache.shardingsphere.sharding.route.engine.validator.ddl.ShardingDDLStatementValidator; import org.apache.shardingsphere.sharding.rule.ShardingRule; @@ -46,19 +47,23 @@ public void preValidate(final ShardingRule shardingRule, final SQLStatementConte final List params, final ShardingSphereDatabase database, final ConfigurationProperties props) { AlterViewStatement alterViewStatement = (AlterViewStatement) sqlStatementContext.getSqlStatement(); Optional selectStatement = AlterViewStatementHandler.getSelectStatement(alterViewStatement); - if (selectStatement.isPresent()) { - TableExtractor extractor = new TableExtractor(); - extractor.extractTablesFromSelect(selectStatement.get()); - validateShardingTable(shardingRule, "ALTER VIEW", extractor.getRewriteTables()); - } + String originView = alterViewStatement.getView().getTableName().getIdentifier().getValue(); + selectStatement.ifPresent(optional -> validateAlterViewShardingTables(shardingRule, optional, originView)); Optional renamedView = AlterViewStatementHandler.getRenameView(alterViewStatement); if (renamedView.isPresent()) { String targetView = renamedView.get().getTableName().getIdentifier().getValue(); - String originView = alterViewStatement.getView().getTableName().getIdentifier().getValue(); validateBroadcastShardingView(shardingRule, originView, targetView); } } + private void validateAlterViewShardingTables(final ShardingRule shardingRule, final SelectStatement selectStatement, final String viewName) { + TableExtractor extractor = new TableExtractor(); + extractor.extractTablesFromSelect(selectStatement); + if (isShardingTablesNotBindingWithView(extractor.getRewriteTables(), shardingRule, viewName)) { + throw new EngagedViewException("sharding"); + } + } + private void validateBroadcastShardingView(final ShardingRule shardingRule, final String originView, final String targetView) { ShardingSpherePreconditions.checkState(!shardingRule.isShardingTable(originView) && !shardingRule.isShardingTable(targetView) || shardingRule.isAllBindingTables(Arrays.asList(originView, targetView)), () -> new RenamedViewWithoutSameConfigurationException(originView, targetView)); diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingCreateViewStatementValidator.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingCreateViewStatementValidator.java index 0e80e1a5399cb4..3a4f2914af56b5 100644 --- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingCreateViewStatementValidator.java +++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingCreateViewStatementValidator.java @@ -37,7 +37,6 @@ import org.apache.shardingsphere.sql.parser.sql.dialect.handler.dml.SelectStatementHandler; import org.apache.shardingsphere.sqlfederation.rule.SQLFederationRule; -import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -56,7 +55,8 @@ public void preValidate(final ShardingRule shardingRule, final SQLStatementConte extractor.extractTablesFromSelect(((CreateViewStatement) sqlStatementContext.getSqlStatement()).getSelect()); Collection tableSegments = extractor.getRewriteTables(); boolean sqlFederationEnabled = globalRuleMetaData.getSingleRule(SQLFederationRule.class).getConfiguration().isSqlFederationEnabled(); - if (!sqlFederationEnabled && isShardingTablesWithoutBinding(shardingRule, sqlStatementContext, tableSegments)) { + String viewName = ((CreateViewStatement) sqlStatementContext.getSqlStatement()).getView().getTableName().getIdentifier().getValue(); + if (!sqlFederationEnabled && isShardingTablesNotBindingWithView(tableSegments, shardingRule, viewName)) { throw new EngagedViewException("sharding"); } } @@ -70,23 +70,6 @@ public void postValidate(final ShardingRule shardingRule, final SQLStatementCont } } - private boolean isShardingTablesWithoutBinding(final ShardingRule shardingRule, final SQLStatementContext sqlStatementContext, - final Collection tableSegments) { - for (SimpleTableSegment each : tableSegments) { - String logicTable = each.getTableName().getIdentifier().getValue(); - if (shardingRule.isShardingTable(logicTable) && !isBindingTables( - shardingRule, ((CreateViewStatement) sqlStatementContext.getSqlStatement()).getView().getTableName().getIdentifier().getValue(), logicTable)) { - return true; - } - } - return false; - } - - private boolean isBindingTables(final ShardingRule shardingRule, final String logicViewName, final String logicTable) { - Collection bindTables = Arrays.asList(logicTable, logicViewName); - return shardingRule.isAllBindingTables(bindTables); - } - private boolean isContainsNotSupportedViewStatement(final SelectStatement selectStatement, final RouteContext routeContext) { if (routeContext.getRouteUnits().size() <= 1) { return false; diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingAlterViewStatementValidatorTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingAlterViewStatementValidatorTest.java index 308999a27d933f..ad85024e834b5e 100644 --- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingAlterViewStatementValidatorTest.java +++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingAlterViewStatementValidatorTest.java @@ -21,7 +21,7 @@ import org.apache.shardingsphere.infra.binder.context.statement.ddl.AlterViewStatementContext; import org.apache.shardingsphere.infra.config.props.ConfigurationProperties; import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase; -import org.apache.shardingsphere.sharding.exception.syntax.UnsupportedShardingOperationException; +import org.apache.shardingsphere.sharding.exception.metadata.EngagedViewException; import org.apache.shardingsphere.sharding.route.engine.validator.ddl.impl.ShardingAlterViewStatementValidator; import org.apache.shardingsphere.sharding.rule.ShardingRule; import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment; @@ -53,6 +53,7 @@ void assertPreValidateAlterViewForMySQL() { MySQLSelectStatement selectStatement = new MySQLSelectStatement(); selectStatement.setFrom(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order")))); MySQLAlterViewStatement sqlStatement = new MySQLAlterViewStatement(); + sqlStatement.setView(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order_view")))); sqlStatement.setSelect(selectStatement); SQLStatementContext sqlStatementContext = new AlterViewStatementContext(sqlStatement); ShardingSphereDatabase database = mock(ShardingSphereDatabase.class); @@ -65,20 +66,21 @@ void assertPreValidateAlterViewWithShardingTableForMySQL() { MySQLSelectStatement selectStatement = new MySQLSelectStatement(); selectStatement.setFrom(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order")))); MySQLAlterViewStatement sqlStatement = new MySQLAlterViewStatement(); + sqlStatement.setView(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order_view")))); sqlStatement.setSelect(selectStatement); ShardingSphereDatabase database = mock(ShardingSphereDatabase.class); SQLStatementContext sqlStatementContext = new AlterViewStatementContext(sqlStatement); when(shardingRule.isShardingTable("t_order")).thenReturn(true); - assertThrows(UnsupportedShardingOperationException.class, + assertThrows(EngagedViewException.class, () -> new ShardingAlterViewStatementValidator().preValidate(shardingRule, sqlStatementContext, Collections.emptyList(), database, mock(ConfigurationProperties.class))); } @Test void assertPreValidateAlterRenamedView() { - OpenGaussAlterViewStatement selectStatement = new OpenGaussAlterViewStatement(); - selectStatement.setView(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order")))); - selectStatement.setRenameView(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order_new")))); - SQLStatementContext sqlStatementContext = new AlterViewStatementContext(selectStatement); + OpenGaussAlterViewStatement sqlStatement = new OpenGaussAlterViewStatement(); + sqlStatement.setView(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order_view")))); + sqlStatement.setRenameView(new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order_new")))); + SQLStatementContext sqlStatementContext = new AlterViewStatementContext(sqlStatement); ShardingSphereDatabase database = mock(ShardingSphereDatabase.class); assertDoesNotThrow(() -> new ShardingAlterViewStatementValidator().preValidate(shardingRule, sqlStatementContext, Collections.emptyList(), database, mock(ConfigurationProperties.class))); }