From e8050f6f19b5940c9ee872c2dd4e554f3576c7ac Mon Sep 17 00:00:00 2001 From: terrymanu Date: Sun, 29 Apr 2018 00:44:52 +0800 Subject: [PATCH] for #768, move sharding router to sharding package --- .../sharding/DatabaseHintSQLRouter.java | 69 +++++++ .../routing/router/sharding/GeneratedKey.java | 51 +++++ .../router/sharding/ParsingSQLRouter.java | 182 ++++++++++++++++++ .../router/sharding/ShardingRouter.java | 50 +++++ .../sharding/ShardingRouterFactory.java | 48 +++++ .../jdbc/core/datasource/NamedDataSource.java | 15 -- 6 files changed, 400 insertions(+), 15 deletions(-) create mode 100644 sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/DatabaseHintSQLRouter.java create mode 100644 sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/GeneratedKey.java create mode 100644 sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ParsingSQLRouter.java create mode 100644 sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ShardingRouter.java create mode 100644 sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ShardingRouterFactory.java diff --git a/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/DatabaseHintSQLRouter.java b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/DatabaseHintSQLRouter.java new file mode 100644 index 0000000000000..1662a07a99b81 --- /dev/null +++ b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/DatabaseHintSQLRouter.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2015 dangdang.com. + *

+ * Licensed 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 io.shardingjdbc.core.routing.router.sharding; + +import io.shardingjdbc.core.parsing.SQLJudgeEngine; +import io.shardingjdbc.core.parsing.parser.sql.SQLStatement; +import io.shardingjdbc.core.routing.SQLExecutionUnit; +import io.shardingjdbc.core.routing.SQLRouteResult; +import io.shardingjdbc.core.routing.SQLUnit; +import io.shardingjdbc.core.routing.strategy.hint.HintShardingStrategy; +import io.shardingjdbc.core.routing.type.RoutingResult; +import io.shardingjdbc.core.routing.type.TableUnit; +import io.shardingjdbc.core.routing.type.hint.DatabaseHintRoutingEngine; +import io.shardingjdbc.core.rule.ShardingRule; +import io.shardingjdbc.core.util.SQLLogger; +import lombok.RequiredArgsConstructor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Sharding router for hint database only. + * + * @author zhangiang + * @author maxiaoguang + */ +@RequiredArgsConstructor +public final class DatabaseHintSQLRouter implements ShardingRouter { + + private final ShardingRule shardingRule; + + private final boolean showSQL; + + @Override + public SQLStatement parse(final String logicSQL, final boolean useCache) { + return new SQLJudgeEngine(logicSQL).judge(); + } + + @Override + // TODO insert SQL need parse gen key + public SQLRouteResult route(final String logicSQL, final List parameters, final SQLStatement sqlStatement) { + SQLRouteResult result = new SQLRouteResult(sqlStatement, null); + RoutingResult routingResult = new DatabaseHintRoutingEngine( + shardingRule.getShardingDataSourceNames().getDataSourceNames(), (HintShardingStrategy) shardingRule.getDefaultDatabaseShardingStrategy()).route(); + for (TableUnit each : routingResult.getTableUnits().getTableUnits()) { + result.getExecutionUnits().add(new SQLExecutionUnit(each.getDataSourceName(), new SQLUnit(logicSQL, new ArrayList<>(Collections.singleton(parameters))))); + } + if (showSQL) { + SQLLogger.logSQL(logicSQL, sqlStatement, result.getExecutionUnits()); + } + return result; + } +} diff --git a/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/GeneratedKey.java b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/GeneratedKey.java new file mode 100644 index 0000000000000..bad4afb32a84f --- /dev/null +++ b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/GeneratedKey.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2015 dangdang.com. + *

+ * Licensed 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 io.shardingjdbc.core.routing.router.sharding; + +import io.shardingjdbc.core.parsing.parser.context.condition.Column; +import io.shardingjdbc.core.parsing.parser.context.condition.GeneratedKeyCondition; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.LinkedList; +import java.util.List; + +/** + * Generated key. + * + * @author zhangliang + * @author maxiaoguang + */ +@RequiredArgsConstructor +@Getter +public final class GeneratedKey { + + private final Column column; + + private final int index; + + private final Number value; + + private final List generatedKeys = new LinkedList<>(); + + public GeneratedKey(final GeneratedKeyCondition generatedKeyCondition) { + column = generatedKeyCondition.getColumn(); + index = generatedKeyCondition.getIndex(); + value = generatedKeyCondition.getValue(); + } +} diff --git a/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ParsingSQLRouter.java b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ParsingSQLRouter.java new file mode 100644 index 0000000000000..c9655242262c4 --- /dev/null +++ b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ParsingSQLRouter.java @@ -0,0 +1,182 @@ +/* + * Copyright 1999-2015 dangdang.com. + *

+ * Licensed 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 io.shardingjdbc.core.routing.router.sharding; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import io.shardingjdbc.core.constant.DatabaseType; +import io.shardingjdbc.core.metadata.ShardingMetaData; +import io.shardingjdbc.core.optimizer.OptimizeEngineFactory; +import io.shardingjdbc.core.optimizer.condition.ShardingConditions; +import io.shardingjdbc.core.parsing.SQLParsingEngine; +import io.shardingjdbc.core.parsing.parser.context.condition.Column; +import io.shardingjdbc.core.parsing.parser.dialect.mysql.statement.ShowDatabasesStatement; +import io.shardingjdbc.core.parsing.parser.dialect.mysql.statement.ShowTablesStatement; +import io.shardingjdbc.core.parsing.parser.dialect.mysql.statement.UseStatement; +import io.shardingjdbc.core.parsing.parser.sql.SQLStatement; +import io.shardingjdbc.core.parsing.parser.sql.dal.DALStatement; +import io.shardingjdbc.core.parsing.parser.sql.ddl.DDLStatement; +import io.shardingjdbc.core.parsing.parser.sql.dml.insert.InsertStatement; +import io.shardingjdbc.core.parsing.parser.sql.dql.select.SelectStatement; +import io.shardingjdbc.core.parsing.parser.token.GeneratedKeyToken; +import io.shardingjdbc.core.rewrite.SQLBuilder; +import io.shardingjdbc.core.rewrite.SQLRewriteEngine; +import io.shardingjdbc.core.routing.SQLExecutionUnit; +import io.shardingjdbc.core.routing.SQLRouteResult; +import io.shardingjdbc.core.routing.type.RoutingEngine; +import io.shardingjdbc.core.routing.type.RoutingResult; +import io.shardingjdbc.core.routing.type.TableUnit; +import io.shardingjdbc.core.routing.type.broadcast.DatabaseBroadcastRoutingEngine; +import io.shardingjdbc.core.routing.type.broadcast.TableBroadcastRoutingEngine; +import io.shardingjdbc.core.routing.type.complex.ComplexRoutingEngine; +import io.shardingjdbc.core.routing.type.ignore.IgnoreRoutingEngine; +import io.shardingjdbc.core.routing.type.standard.StandardRoutingEngine; +import io.shardingjdbc.core.routing.type.unicast.UnicastRoutingEngine; +import io.shardingjdbc.core.rule.ShardingRule; +import io.shardingjdbc.core.rule.TableRule; +import io.shardingjdbc.core.util.SQLLogger; +import lombok.RequiredArgsConstructor; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +/** + * Sharding router with parse. + * + * @author zhangiang + * @author maxiaoguang + * @author panjuan + */ +@RequiredArgsConstructor +public final class ParsingSQLRouter implements ShardingRouter { + + private final ShardingRule shardingRule; + + private final ShardingMetaData shardingMetaData; + + private final DatabaseType databaseType; + + private final boolean showSQL; + + private final List generatedKeys = new LinkedList<>(); + + @Override + public SQLStatement parse(final String logicSQL, final boolean useCache) { + return new SQLParsingEngine(databaseType, logicSQL, shardingRule, shardingMetaData).parse(useCache); + } + + @Override + public SQLRouteResult route(final String logicSQL, final List parameters, final SQLStatement sqlStatement) { + GeneratedKey generatedKey = null; + if (sqlStatement instanceof InsertStatement) { + generatedKey = getGenerateKey(shardingRule, (InsertStatement) sqlStatement); + } + SQLRouteResult result = new SQLRouteResult(sqlStatement, generatedKey); + if (null != generatedKey) { + processGeneratedKey(parameters, generatedKey, sqlStatement.getTables().getSingleTableName(), result); + } + RoutingResult routingResult = route(parameters, sqlStatement, generatedKey); + SQLRewriteEngine rewriteEngine = new SQLRewriteEngine(shardingRule, logicSQL, databaseType, sqlStatement, parameters, generatedKey); + boolean isSingleRouting = routingResult.isSingleRouting(); + if (sqlStatement instanceof SelectStatement && null != ((SelectStatement) sqlStatement).getLimit()) { + processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting); + } + SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting); + for (TableUnit each : routingResult.getTableUnits().getTableUnits()) { + result.getExecutionUnits().add(new SQLExecutionUnit(each.getDataSourceName(), rewriteEngine.generateSQL(each, sqlBuilder))); + } + if (showSQL) { + SQLLogger.logSQL(logicSQL, sqlStatement, result.getExecutionUnits()); + } + return result; + } + + private RoutingResult route(final List parameters, final SQLStatement sqlStatement, final GeneratedKey generatedKey) { + Collection tableNames = sqlStatement.getTables().getTableNames(); + ShardingConditions shardingConditions = OptimizeEngineFactory.newInstance(sqlStatement, parameters, generatedKey).optimize(); + RoutingEngine routingEngine; + if (sqlStatement instanceof UseStatement) { + routingEngine = new IgnoreRoutingEngine(); + } else if (sqlStatement instanceof DDLStatement) { + routingEngine = new TableBroadcastRoutingEngine(shardingRule, sqlStatement); + } else if (sqlStatement instanceof ShowDatabasesStatement || sqlStatement instanceof ShowTablesStatement) { + routingEngine = new DatabaseBroadcastRoutingEngine(shardingRule); + } else if (shardingConditions.isAlwaysFalse()) { + routingEngine = new UnicastRoutingEngine(shardingRule, tableNames); + } else if (sqlStatement instanceof DALStatement) { + routingEngine = new UnicastRoutingEngine(shardingRule, tableNames); + } else if (tableNames.isEmpty() && sqlStatement instanceof SelectStatement) { + routingEngine = new UnicastRoutingEngine(shardingRule, tableNames); + } else if (tableNames.isEmpty()) { + routingEngine = new DatabaseBroadcastRoutingEngine(shardingRule); + } else if (1 == tableNames.size() || shardingRule.isAllBindingTables(tableNames) || shardingRule.isAllInDefaultDataSource(tableNames)) { + routingEngine = new StandardRoutingEngine(shardingRule, tableNames.iterator().next(), shardingConditions); + } else { + // TODO config for cartesian set + routingEngine = new ComplexRoutingEngine(shardingRule, parameters, tableNames, shardingConditions); + } + return routingEngine.route(); + } + + private GeneratedKey getGenerateKey(final ShardingRule shardingRule, final InsertStatement insertStatement) { + if (null != insertStatement.getGeneratedKeyCondition()) { + return new GeneratedKey(insertStatement.getGeneratedKeyCondition()); + } + String logicTableName = insertStatement.getTables().getSingleTableName(); + Optional tableRule = shardingRule.tryFindTableRuleByLogicTable(logicTableName); + if (!tableRule.isPresent()) { + return null; + } + Optional generatedKeysToken = insertStatement.findGeneratedKeyToken(); + if (!generatedKeysToken.isPresent()) { + return null; + } + Optional generateKeyColumn = shardingRule.getGenerateKeyColumn(logicTableName); + Preconditions.checkState(generateKeyColumn.isPresent()); + return 0 == insertStatement.getParametersIndex() + ? new GeneratedKey(generateKeyColumn.get(), -1, shardingRule.generateKey(logicTableName)) : new GeneratedKey(generateKeyColumn.get(), insertStatement.getParametersIndex(), null); + } + + private void processGeneratedKey(final List parameters, final GeneratedKey generatedKey, final String logicTableName, final SQLRouteResult sqlRouteResult) { + if (parameters.isEmpty()) { + sqlRouteResult.getGeneratedKey().getGeneratedKeys().add(generatedKey.getValue()); + } else if (parameters.size() == generatedKey.getIndex()) { + Number key = shardingRule.generateKey(logicTableName); + parameters.add(key); + setGeneratedKeys(sqlRouteResult, key); + } else if (-1 != generatedKey.getIndex()) { + setGeneratedKeys(sqlRouteResult, (Number) parameters.get(generatedKey.getIndex())); + } + } + + private void setGeneratedKeys(final SQLRouteResult sqlRouteResult, final Number generatedKey) { + generatedKeys.add(generatedKey); + sqlRouteResult.getGeneratedKey().getGeneratedKeys().clear(); + sqlRouteResult.getGeneratedKey().getGeneratedKeys().addAll(generatedKeys); + } + + private void processLimit(final List parameters, final SelectStatement selectStatement, final boolean isSingleRouting) { + if (isSingleRouting) { + selectStatement.setLimit(null); + return; + } + boolean isNeedFetchAll = (!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) && !selectStatement.isSameGroupByAndOrderByItems(); + selectStatement.getLimit().processParameters(parameters, isNeedFetchAll); + } +} diff --git a/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ShardingRouter.java b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ShardingRouter.java new file mode 100644 index 0000000000000..825ffdd2ecffc --- /dev/null +++ b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ShardingRouter.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2015 dangdang.com. + *

+ * Licensed 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 io.shardingjdbc.core.routing.router.sharding; + +import io.shardingjdbc.core.parsing.parser.sql.SQLStatement; +import io.shardingjdbc.core.routing.SQLRouteResult; + +import java.util.List; + +/** + * Sharding router. + * + * @author zhangiang + */ +public interface ShardingRouter { + + /** + * Parse SQL. + * + * @param logicSQL logic SQL + * @param useCache use cache to save SQL parse result or not + * @return parse result + */ + SQLStatement parse(String logicSQL, boolean useCache); + + /** + * Route SQL. + * + * @param logicSQL logic SQL + * @param sqlStatement SQL statement + * @param parameters parameters + * @return parse result + */ + SQLRouteResult route(String logicSQL, List parameters, SQLStatement sqlStatement); +} diff --git a/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ShardingRouterFactory.java b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ShardingRouterFactory.java new file mode 100644 index 0000000000000..83762c5298721 --- /dev/null +++ b/sharding-core/src/main/java/io/shardingjdbc/core/routing/router/sharding/ShardingRouterFactory.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2015 dangdang.com. + *

+ * Licensed 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 io.shardingjdbc.core.routing.router.sharding; + +import io.shardingjdbc.core.constant.DatabaseType; +import io.shardingjdbc.core.hint.HintManagerHolder; +import io.shardingjdbc.core.metadata.ShardingMetaData; +import io.shardingjdbc.core.rule.ShardingRule; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * Sharding router factory. + * + * @author zhangiang + * @author panjuan + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ShardingRouterFactory { + + /** + * Create sharding router. + * + * @param shardingRule sharding rule + * @param shardingMetaData sharding meta data + * @param databaseType database type + * @param showSQL show SQL or not + * @return sharding router instance + */ + public static ShardingRouter createSQLRouter(final ShardingRule shardingRule, final ShardingMetaData shardingMetaData, final DatabaseType databaseType, final boolean showSQL) { + return HintManagerHolder.isDatabaseShardingOnly() ? new DatabaseHintSQLRouter(shardingRule, showSQL) : new ParsingSQLRouter(shardingRule, shardingMetaData, databaseType, showSQL); + } +} diff --git a/sharding-jdbc-core/src/main/java/io/shardingjdbc/core/jdbc/core/datasource/NamedDataSource.java b/sharding-jdbc-core/src/main/java/io/shardingjdbc/core/jdbc/core/datasource/NamedDataSource.java index 5b3dd8d74e2e8..65d3bbe07b20a 100644 --- a/sharding-jdbc-core/src/main/java/io/shardingjdbc/core/jdbc/core/datasource/NamedDataSource.java +++ b/sharding-jdbc-core/src/main/java/io/shardingjdbc/core/jdbc/core/datasource/NamedDataSource.java @@ -21,8 +21,6 @@ import lombok.RequiredArgsConstructor; import javax.sql.DataSource; -import java.util.HashMap; -import java.util.Map; /** * Data source with name. @@ -36,17 +34,4 @@ public final class NamedDataSource { private final String name; private final DataSource dataSource; - - /** - * Transfer to map. - * - *

Key is data source name, value is data source.

- * - * @return map - */ - public Map toMap() { - Map result = new HashMap<>(1, 1); - result.put(name, dataSource); - return result; - } }