All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.shardingjdbc.core.rewrite.SQLRewriteEngine Maven / Gradle / Ivy

There is a newer version: 2.0.3
Show newest version
/*
 * 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.rewrite; import io.shardingjdbc.core.constant.DatabaseType; import io.shardingjdbc.core.rule.BindingTableRule; import io.shardingjdbc.core.rule.ShardingRule; import io.shardingjdbc.core.parsing.lexer.token.DefaultKeyword; import io.shardingjdbc.core.parsing.parser.context.OrderItem; import io.shardingjdbc.core.parsing.parser.context.limit.Limit; import io.shardingjdbc.core.parsing.parser.sql.SQLStatement; import io.shardingjdbc.core.parsing.parser.sql.dql.select.SelectStatement; import io.shardingjdbc.core.parsing.parser.token.ItemsToken; import io.shardingjdbc.core.parsing.parser.token.OffsetToken; import io.shardingjdbc.core.parsing.parser.token.OrderByToken; import io.shardingjdbc.core.parsing.parser.token.RowCountToken; import io.shardingjdbc.core.parsing.parser.token.SQLToken; import io.shardingjdbc.core.parsing.parser.token.TableToken; import io.shardingjdbc.core.routing.type.TableUnit; import io.shardingjdbc.core.routing.type.complex.CartesianTableReference; import com.google.common.base.Optional; import io.shardingjdbc.core.util.SQLUtil; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * SQL rewrite engine. * *

Rewrite logic SQL to actual SQL, should rewrite table name and optimize something.

* * @author zhangliang */ public final class SQLRewriteEngine { private final ShardingRule shardingRule; private final String originalSQL; private final DatabaseType databaseType; private final List sqlTokens = new LinkedList<>(); private final SQLStatement sqlStatement; /** * Constructs SQL rewrite engine. * * @param shardingRule databases and tables sharding rule * @param originalSQL original SQL * @param databaseType database type * @param sqlStatement SQL statement */ public SQLRewriteEngine(final ShardingRule shardingRule, final String originalSQL, final DatabaseType databaseType, final SQLStatement sqlStatement) { this.shardingRule = shardingRule; this.originalSQL = originalSQL; this.databaseType = databaseType; this.sqlStatement = sqlStatement; sqlTokens.addAll(sqlStatement.getSqlTokens()); } /** * rewrite SQL. * * @param isRewriteLimit is rewrite limit * @return SQL builder */ public SQLBuilder rewrite(final boolean isRewriteLimit) { SQLBuilder result = new SQLBuilder(); if (sqlTokens.isEmpty()) { result.appendLiterals(originalSQL); return result; } int count = 0; sortByBeginPosition(); for (SQLToken each : sqlTokens) { if (0 == count) { result.appendLiterals(originalSQL.substring(0, each.getBeginPosition())); } if (each instanceof TableToken) { appendTableToken(result, (TableToken) each, count, sqlTokens); } else if (each instanceof ItemsToken) { appendItemsToken(result, (ItemsToken) each, count, sqlTokens); } else if (each instanceof RowCountToken) { appendLimitRowCount(result, (RowCountToken) each, count, sqlTokens, isRewriteLimit); } else if (each instanceof OffsetToken) { appendLimitOffsetToken(result, (OffsetToken) each, count, sqlTokens, isRewriteLimit); } else if (each instanceof OrderByToken) { appendOrderByToken(result, count, sqlTokens); } count++; } return result; } private void sortByBeginPosition() { Collections.sort(sqlTokens, new Comparator() { @Override public int compare(final SQLToken o1, final SQLToken o2) { return o1.getBeginPosition() - o2.getBeginPosition(); } }); } private void appendTableToken(final SQLBuilder sqlBuilder, final TableToken tableToken, final int count, final List sqlTokens) { String tableName = SQLUtil.getOriginalValue(sqlStatement.getTables().getTableNames().contains(tableToken.getTableName()) ? tableToken.getTableName() : tableToken.getOriginalLiterals(), databaseType); sqlBuilder.appendTable(tableName); int beginPosition = tableToken.getBeginPosition() + tableToken.getOriginalLiterals().length(); appendRest(sqlBuilder, count, sqlTokens, beginPosition); } private void appendItemsToken(final SQLBuilder sqlBuilder, final ItemsToken itemsToken, final int count, final List sqlTokens) { for (String item : itemsToken.getItems()) { sqlBuilder.appendLiterals(", "); sqlBuilder.appendLiterals(SQLUtil.getOriginalValue(item, databaseType)); } int beginPosition = itemsToken.getBeginPosition(); appendRest(sqlBuilder, count, sqlTokens, beginPosition); } private void appendLimitRowCount(final SQLBuilder sqlBuilder, final RowCountToken rowCountToken, final int count, final List sqlTokens, final boolean isRewrite) { SelectStatement selectStatement = (SelectStatement) sqlStatement; Limit limit = selectStatement.getLimit(); if (!isRewrite) { sqlBuilder.appendLiterals(String.valueOf(rowCountToken.getRowCount())); } else if ((!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) && !selectStatement.isSameGroupByAndOrderByItems()) { sqlBuilder.appendLiterals(String.valueOf(Integer.MAX_VALUE)); } else { sqlBuilder.appendLiterals(String.valueOf(limit.isNeedRewriteRowCount() ? rowCountToken.getRowCount() + limit.getOffsetValue() : rowCountToken.getRowCount())); } int beginPosition = rowCountToken.getBeginPosition() + String.valueOf(rowCountToken.getRowCount()).length(); appendRest(sqlBuilder, count, sqlTokens, beginPosition); } private void appendLimitOffsetToken(final SQLBuilder sqlBuilder, final OffsetToken offsetToken, final int count, final List sqlTokens, final boolean isRewrite) { sqlBuilder.appendLiterals(isRewrite ? "0" : String.valueOf(offsetToken.getOffset())); int beginPosition = offsetToken.getBeginPosition() + String.valueOf(offsetToken.getOffset()).length(); appendRest(sqlBuilder, count, sqlTokens, beginPosition); } private void appendOrderByToken(final SQLBuilder sqlBuilder, final int count, final List sqlTokens) { SelectStatement selectStatement = (SelectStatement) sqlStatement; StringBuilder orderByLiterals = new StringBuilder(); orderByLiterals.append(" ").append(DefaultKeyword.ORDER).append(" ").append(DefaultKeyword.BY).append(" "); int i = 0; for (OrderItem each : selectStatement.getOrderByItems()) { String columnLabel = SQLUtil.getOriginalValue(each.getColumnLabel(), databaseType); if (0 == i) { orderByLiterals.append(columnLabel).append(" ").append(each.getType().name()); } else { orderByLiterals.append(",").append(columnLabel).append(" ").append(each.getType().name()); } i++; } orderByLiterals.append(" "); sqlBuilder.appendLiterals(orderByLiterals.toString()); int beginPosition = ((SelectStatement) sqlStatement).getGroupByLastPosition(); appendRest(sqlBuilder, count, sqlTokens, beginPosition); } private void appendRest(final SQLBuilder sqlBuilder, final int count, final List sqlTokens, final int beginPosition) { int endPosition = sqlTokens.size() - 1 == count ? originalSQL.length() : sqlTokens.get(count + 1).getBeginPosition(); sqlBuilder.appendLiterals(originalSQL.substring(beginPosition, endPosition)); } /** * Generate SQL string. * * @param tableUnit route table unit * @param sqlBuilder SQL builder * @return SQL string */ public String generateSQL(final TableUnit tableUnit, final SQLBuilder sqlBuilder) { return sqlBuilder.toSQL(getTableTokens(tableUnit)); } /** * Generate SQL string. * * @param cartesianTableReference cartesian table reference * @param sqlBuilder SQL builder * @return SQL string */ public String generateSQL(final CartesianTableReference cartesianTableReference, final SQLBuilder sqlBuilder) { return sqlBuilder.toSQL(getTableTokens(cartesianTableReference)); } private Map getTableTokens(final TableUnit tableUnit) { Map tableTokens = new HashMap<>(); tableTokens.put(tableUnit.getLogicTableName(), tableUnit.getActualTableName()); Optional bindingTableRule = shardingRule.findBindingTableRule(tableUnit.getLogicTableName()); if (bindingTableRule.isPresent()) { tableTokens.putAll(getBindingTableTokens(tableUnit, bindingTableRule.get())); } return tableTokens; } private Map getTableTokens(final CartesianTableReference cartesianTableReference) { Map tableTokens = new HashMap<>(); for (TableUnit each : cartesianTableReference.getTableUnits()) { tableTokens.put(each.getLogicTableName(), each.getActualTableName()); Optional bindingTableRule = shardingRule.findBindingTableRule(each.getLogicTableName()); if (bindingTableRule.isPresent()) { tableTokens.putAll(getBindingTableTokens(each, bindingTableRule.get())); } } return tableTokens; } private Map getBindingTableTokens(final TableUnit tableUnit, final BindingTableRule bindingTableRule) { Map result = new HashMap<>(); for (String eachTable : sqlStatement.getTables().getTableNames()) { if (!eachTable.equalsIgnoreCase(tableUnit.getLogicTableName()) && bindingTableRule.hasLogicTable(eachTable)) { result.put(eachTable, bindingTableRule.getBindingActualTable(tableUnit.getDataSourceName(), eachTable, tableUnit.getActualTableName())); } } return result; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy