View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.sharding.route.engine.validator.ddl.impl;
19  
20  import com.cedarsoftware.util.CaseInsensitiveSet;
21  import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
22  import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
23  import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
24  import org.apache.shardingsphere.infra.datanode.DataNode;
25  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
26  import org.apache.shardingsphere.infra.hint.HintValueContext;
27  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
28  import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
29  import org.apache.shardingsphere.infra.route.context.RouteContext;
30  import org.apache.shardingsphere.infra.route.context.RouteMapper;
31  import org.apache.shardingsphere.sharding.exception.connection.ShardingDDLRouteException;
32  import org.apache.shardingsphere.sharding.exception.metadata.InUsedTablesException;
33  import org.apache.shardingsphere.sharding.exception.syntax.UnsupportedShardingOperationException;
34  import org.apache.shardingsphere.sharding.route.engine.validator.ddl.ShardingDDLStatementValidator;
35  import org.apache.shardingsphere.sharding.rule.ShardingRule;
36  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
37  import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DropTableStatement;
38  import org.apache.shardingsphere.sql.parser.sql.dialect.handler.ddl.DropTableStatementHandler;
39  
40  import java.util.Collection;
41  import java.util.List;
42  import java.util.Set;
43  import java.util.stream.Collectors;
44  
45  /**
46   * Sharding drop table statement validator.
47   */
48  public final class ShardingDropTableStatementValidator extends ShardingDDLStatementValidator {
49      
50      @Override
51      public void preValidate(final ShardingRule shardingRule, final SQLStatementContext sqlStatementContext,
52                              final List<Object> params, final ShardingSphereDatabase database, final ConfigurationProperties props) {
53          DropTableStatement dropTableStatement = (DropTableStatement) sqlStatementContext.getSqlStatement();
54          if (!DropTableStatementHandler.ifExists(dropTableStatement)) {
55              String defaultSchemaName = new DatabaseTypeRegistry(sqlStatementContext.getDatabaseType()).getDefaultSchemaName(database.getName());
56              ShardingSphereSchema schema = sqlStatementContext.getTablesContext().getSchemaName()
57                      .map(database::getSchema).orElseGet(() -> database.getSchema(defaultSchemaName));
58              validateTableExist(schema, sqlStatementContext.getTablesContext().getSimpleTableSegments());
59          }
60          if (DropTableStatementHandler.containsCascade(dropTableStatement)) {
61              throw new UnsupportedShardingOperationException("DROP TABLE ... CASCADE",
62                      sqlStatementContext.getTablesContext().getSimpleTableSegments().iterator().next().getTableName().getIdentifier().getValue());
63          }
64      }
65      
66      @Override
67      public void postValidate(final ShardingRule shardingRule, final SQLStatementContext sqlStatementContext, final HintValueContext hintValueContext, final List<Object> params,
68                               final ShardingSphereDatabase database, final ConfigurationProperties props, final RouteContext routeContext) {
69          DropTableStatement dropTableStatement = (DropTableStatement) sqlStatementContext.getSqlStatement();
70          checkTableInUsed(shardingRule, sqlStatementContext, routeContext);
71          for (SimpleTableSegment each : dropTableStatement.getTables()) {
72              if (isRouteUnitDataNodeDifferentSize(shardingRule, routeContext, each.getTableName().getIdentifier().getValue())) {
73                  throw new ShardingDDLRouteException("DROP", "TABLE", sqlStatementContext.getTablesContext().getTableNames());
74              }
75          }
76      }
77      
78      private void checkTableInUsed(final ShardingRule shardingRule, final SQLStatementContext sqlStatementContext, final RouteContext routeContext) {
79          Collection<String> dropTables = sqlStatementContext.getTablesContext().getTableNames();
80          Collection<String> otherRuleActualTables = shardingRule.getShardingTables().values().stream().filter(each -> !dropTables.contains(each.getLogicTable()))
81                  .flatMap(each -> each.getActualDataNodes().stream().map(DataNode::getTableName)).collect(Collectors.toCollection(CaseInsensitiveSet::new));
82          if (otherRuleActualTables.isEmpty()) {
83              return;
84          }
85          // TODO check actual tables not be used in multi rules, and remove this check logic
86          Set<String> actualTables = routeContext.getRouteUnits().stream().flatMap(each -> each.getTableMappers().stream().map(RouteMapper::getActualName)).collect(Collectors.toSet());
87          Collection<String> inUsedTables = actualTables.stream().filter(otherRuleActualTables::contains).collect(Collectors.toList());
88          ShardingSpherePreconditions.checkMustEmpty(inUsedTables, () -> new InUsedTablesException(inUsedTables));
89      }
90  }