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.DatabaseRuleCreateExecutor;
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.CreateShardingTableReferenceRuleStatement;
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.stream.Collectors;
42  
43  /**
44   * Create sharding table reference rule executor.
45   */
46  @DistSQLExecutorCurrentRuleRequired(ShardingRule.class)
47  @Setter
48  public final class CreateShardingTableReferenceRuleExecutor implements DatabaseRuleCreateExecutor<CreateShardingTableReferenceRuleStatement, ShardingRule, ShardingRuleConfiguration> {
49      
50      private ShardingSphereDatabase database;
51      
52      private ShardingRule rule;
53      
54      @Override
55      public void checkBeforeUpdate(final CreateShardingTableReferenceRuleStatement sqlStatement) {
56          if (!sqlStatement.isIfNotExists()) {
57              checkDuplicatedRuleNames(sqlStatement);
58          }
59          checkDuplicatedTablesInShardingTableReferenceRules(sqlStatement);
60          checkToBeReferencedShardingTablesExisted(sqlStatement);
61          checkShardingTableReferenceRulesValid(sqlStatement);
62      }
63      
64      private void checkDuplicatedRuleNames(final CreateShardingTableReferenceRuleStatement sqlStatement) {
65          Collection<String> duplicatedRuleNames = getDuplicatedRuleNames(sqlStatement);
66          ShardingSpherePreconditions.checkMustEmpty(duplicatedRuleNames, () -> new DuplicateRuleException("sharding table reference", database.getName(), duplicatedRuleNames));
67      }
68      
69      private void checkDuplicatedTablesInShardingTableReferenceRules(final CreateShardingTableReferenceRuleStatement sqlStatement) {
70          Collection<String> currentReferencedTableNames = getReferencedTableNames();
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 void checkToBeReferencedShardingTablesExisted(final CreateShardingTableReferenceRuleStatement sqlStatement) {
76          Collection<String> currentShardingTableNames = getCurrentShardingTableNames();
77          Collection<String> notExistedTableNames = sqlStatement.getTableNames().stream().filter(each -> !currentShardingTableNames.contains(each)).collect(Collectors.toSet());
78          ShardingSpherePreconditions.checkMustEmpty(notExistedTableNames, () -> new MissingRequiredRuleException("Sharding", database.getName(), notExistedTableNames));
79      }
80      
81      private Collection<String> getCurrentShardingTableNames() {
82          Collection<String> result = new CaseInsensitiveSet<>();
83          result.addAll(rule.getConfiguration().getTables().stream().map(ShardingTableRuleConfiguration::getLogicTable).collect(Collectors.toSet()));
84          result.addAll(rule.getConfiguration().getAutoTables().stream().map(ShardingAutoTableRuleConfiguration::getLogicTable).collect(Collectors.toSet()));
85          return result;
86      }
87      
88      private void checkShardingTableReferenceRulesValid(final CreateShardingTableReferenceRuleStatement sqlStatement) {
89          Collection<ShardingTableReferenceRuleConfiguration> bindingTableGroups = buildToBeCreatedRuleConfiguration(sqlStatement).getBindingTableGroups();
90          Collection<String> names = bindingTableGroups.stream().map(ShardingTableReferenceRuleConfiguration::getName).collect(Collectors.toList());
91          ShardingSpherePreconditions.checkState(ShardingTableRuleStatementChecker.isValidBindingTableGroups(bindingTableGroups, rule.getConfiguration()),
92                  () -> new InvalidRuleConfigurationException("sharding table", names, Collections.singleton("invalid sharding table reference.")));
93      }
94      
95      private Collection<String> getReferencedTableNames() {
96          return rule.getConfiguration().getBindingTableGroups().stream().flatMap(each -> Arrays.stream(each.getReference().split(","))).map(String::trim).collect(Collectors.toList());
97      }
98      
99      @Override
100     public ShardingRuleConfiguration buildToBeCreatedRuleConfiguration(final CreateShardingTableReferenceRuleStatement sqlStatement) {
101         Collection<TableReferenceRuleSegment> segments = sqlStatement.getRules();
102         if (sqlStatement.isIfNotExists()) {
103             Collection<String> duplicatedRuleNames = getDuplicatedRuleNames(sqlStatement);
104             segments.removeIf(each -> duplicatedRuleNames.contains(each.getName()));
105         }
106         ShardingRuleConfiguration result = new ShardingRuleConfiguration();
107         segments.forEach(each -> result.getBindingTableGroups().add(new ShardingTableReferenceRuleConfiguration(each.getName(), each.getReference())));
108         return result;
109     }
110     
111     private Collection<String> getDuplicatedRuleNames(final CreateShardingTableReferenceRuleStatement sqlStatement) {
112         Collection<String> currentRuleNames = rule.getConfiguration().getBindingTableGroups().stream().map(ShardingTableReferenceRuleConfiguration::getName).collect(Collectors.toSet());
113         return sqlStatement.getRules().stream().map(TableReferenceRuleSegment::getName).filter(currentRuleNames::contains).collect(Collectors.toSet());
114     }
115     
116     @Override
117     public Class<ShardingRule> getRuleClass() {
118         return ShardingRule.class;
119     }
120     
121     @Override
122     public Class<CreateShardingTableReferenceRuleStatement> getType() {
123         return CreateShardingTableReferenceRuleStatement.class;
124     }
125 }