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.distsql.handler.update;
19  
20  import com.cedarsoftware.util.CaseInsensitiveSet;
21  import lombok.Setter;
22  import org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleAlterExecutor;
23  import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.DuplicateRuleException;
24  import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.InvalidRuleConfigurationException;
25  import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.MissingRequiredRuleException;
26  import org.apache.shardingsphere.distsql.handler.required.DistSQLExecutorCurrentRuleRequired;
27  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
28  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
29  import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
30  import org.apache.shardingsphere.sharding.api.config.rule.ShardingAutoTableRuleConfiguration;
31  import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableReferenceRuleConfiguration;
32  import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
33  import org.apache.shardingsphere.sharding.distsql.handler.checker.ShardingTableRuleStatementChecker;
34  import org.apache.shardingsphere.sharding.distsql.segment.table.TableReferenceRuleSegment;
35  import org.apache.shardingsphere.sharding.distsql.statement.AlterShardingTableReferenceRuleStatement;
36  import org.apache.shardingsphere.sharding.rule.ShardingRule;
37  
38  import java.util.Arrays;
39  import java.util.Collection;
40  import java.util.Collections;
41  import java.util.HashSet;
42  import java.util.stream.Collectors;
43  
44  /**
45   * Alter sharding table reference rule executor.
46   */
47  @DistSQLExecutorCurrentRuleRequired(ShardingRule.class)
48  @Setter
49  public final class AlterShardingTableReferenceRuleExecutor implements DatabaseRuleAlterExecutor<AlterShardingTableReferenceRuleStatement, ShardingRule, ShardingRuleConfiguration> {
50      
51      private ShardingSphereDatabase database;
52      
53      private ShardingRule rule;
54      
55      @Override
56      public void checkBeforeUpdate(final AlterShardingTableReferenceRuleStatement sqlStatement) {
57          checkToBeAlteredRulesExisted(sqlStatement);
58          checkDuplicatedTablesInShardingTableReferenceRules(sqlStatement);
59          checkToBeReferencedShardingTablesExisted(sqlStatement);
60          checkShardingTableReferenceRulesValid(sqlStatement);
61      }
62      
63      private void checkToBeAlteredRulesExisted(final AlterShardingTableReferenceRuleStatement sqlStatement) {
64          Collection<String> currentRuleNames = rule.getConfiguration().getBindingTableGroups().stream().map(ShardingTableReferenceRuleConfiguration::getName).collect(Collectors.toSet());
65          Collection<String> notExistedRuleNames = sqlStatement.getRules().stream().map(TableReferenceRuleSegment::getName).filter(each -> !currentRuleNames.contains(each)).collect(Collectors.toSet());
66          ShardingSpherePreconditions.checkMustEmpty(notExistedRuleNames, () -> new MissingRequiredRuleException("Sharding table reference", database.getName(), notExistedRuleNames));
67      }
68      
69      private void checkDuplicatedTablesInShardingTableReferenceRules(final AlterShardingTableReferenceRuleStatement sqlStatement) {
70          Collection<String> currentReferencedTableNames = getReferencedTableNames(getToBeAlteredRuleNames(sqlStatement));
71          Collection<String> duplicatedTableNames = sqlStatement.getTableNames().stream().filter(currentReferencedTableNames::contains).collect(Collectors.toSet());
72          ShardingSpherePreconditions.checkMustEmpty(duplicatedTableNames, () -> new DuplicateRuleException("sharding table reference", database.getName(), duplicatedTableNames));
73      }
74      
75      private Collection<String> getReferencedTableNames(final Collection<String> getToBeAlteredRuleNames) {
76          Collection<String> result = new HashSet<>();
77          rule.getConfiguration().getBindingTableGroups().forEach(each -> {
78              if (!getToBeAlteredRuleNames.contains(each.getName())) {
79                  result.addAll(Arrays.stream(each.getReference().split(",")).map(String::trim).collect(Collectors.toSet()));
80              }
81          });
82          return result;
83      }
84      
85      private Collection<String> getToBeAlteredRuleNames(final AlterShardingTableReferenceRuleStatement sqlStatement) {
86          return sqlStatement.getRules().stream().map(TableReferenceRuleSegment::getName).collect(Collectors.toSet());
87      }
88      
89      private void checkToBeReferencedShardingTablesExisted(final AlterShardingTableReferenceRuleStatement sqlStatement) {
90          Collection<String> currentShardingTableNames = getCurrentShardingTableNames();
91          Collection<String> notExistedTableNames = sqlStatement.getTableNames().stream().filter(each -> !currentShardingTableNames.contains(each)).collect(Collectors.toSet());
92          ShardingSpherePreconditions.checkMustEmpty(notExistedTableNames, () -> new MissingRequiredRuleException("Sharding", database.getName(), notExistedTableNames));
93      }
94      
95      private Collection<String> getCurrentShardingTableNames() {
96          Collection<String> result = new CaseInsensitiveSet<>();
97          result.addAll(rule.getConfiguration().getTables().stream().map(ShardingTableRuleConfiguration::getLogicTable).collect(Collectors.toSet()));
98          result.addAll(rule.getConfiguration().getAutoTables().stream().map(ShardingAutoTableRuleConfiguration::getLogicTable).collect(Collectors.toSet()));
99          return result;
100     }
101     
102     private void checkShardingTableReferenceRulesValid(final AlterShardingTableReferenceRuleStatement sqlStatement) {
103         Collection<ShardingTableReferenceRuleConfiguration> toBeAlteredShardingTableReferenceRules = buildToBeAlteredRuleConfiguration(sqlStatement).getBindingTableGroups();
104         Collection<String> ruleNames = toBeAlteredShardingTableReferenceRules.stream().map(ShardingTableReferenceRuleConfiguration::getName).collect(Collectors.toList());
105         ShardingSpherePreconditions.checkState(ShardingTableRuleStatementChecker.isValidBindingTableGroups(toBeAlteredShardingTableReferenceRules, rule.getConfiguration()),
106                 () -> new InvalidRuleConfigurationException("sharding table", ruleNames, Collections.singleton("invalid sharding table reference.")));
107     }
108     
109     @Override
110     public ShardingRuleConfiguration buildToBeAlteredRuleConfiguration(final AlterShardingTableReferenceRuleStatement sqlStatement) {
111         ShardingRuleConfiguration result = new ShardingRuleConfiguration();
112         sqlStatement.getRules().forEach(each -> result.getBindingTableGroups().add(new ShardingTableReferenceRuleConfiguration(each.getName(), each.getReference())));
113         return result;
114     }
115     
116     @Override
117     public ShardingRuleConfiguration buildToBeDroppedRuleConfiguration(final ShardingRuleConfiguration toBeAlteredRuleConfig) {
118         return null;
119     }
120     
121     @Override
122     public Class<ShardingRule> getRuleClass() {
123         return ShardingRule.class;
124     }
125     
126     @Override
127     public Class<AlterShardingTableReferenceRuleStatement> getType() {
128         return AlterShardingTableReferenceRuleStatement.class;
129     }
130 }