/* * 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 com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.insert; import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule; import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException; import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.Assist; import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.DefaultKeyword; import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.Symbol; import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.TokenType; import com.dangdang.ddframe.rdb.sharding.parsing.parser.SQLParser; import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.GeneratedKey; import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.condition.Column; import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.condition.Condition; import com.dangdang.ddframe.rdb.sharding.parsing.parser.exception.SQLParsingUnsupportedException; import com.dangdang.ddframe.rdb.sharding.parsing.parser.expression.SQLExpression; import com.dangdang.ddframe.rdb.sharding.parsing.parser.expression.SQLNumberExpression; import com.dangdang.ddframe.rdb.sharding.parsing.parser.expression.SQLPlaceholderExpression; import com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.SQLStatementParser; import com.dangdang.ddframe.rdb.sharding.parsing.parser.token.GeneratedKeyToken; import com.dangdang.ddframe.rdb.sharding.parsing.parser.token.ItemsToken; import com.dangdang.ddframe.rdb.sharding.util.SQLUtil; import com.google.common.base.Optional; import com.google.common.collect.Sets; import lombok.AccessLevel; import lombok.Getter; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * Insert语句解析器. * * @author zhangliang */ @Getter(AccessLevel.PROTECTED) public abstract class AbstractInsertParser implements SQLStatementParser { private final SQLParser sqlParser; private final ShardingRule shardingRule; private final InsertStatement insertStatement; @Getter(AccessLevel.NONE) private int generateKeyColumnIndex = -1; public AbstractInsertParser(final ShardingRule shardingRule, final SQLParser sqlParser) { this.sqlParser = sqlParser; this.shardingRule = shardingRule; insertStatement = new InsertStatement(); } @Override public final InsertStatement parse() { sqlParser.getLexer().nextToken(); parseInto(); parseColumns(); if (sqlParser.equalAny(DefaultKeyword.SELECT, Symbol.LEFT_PAREN)) { throw new UnsupportedOperationException("Cannot support subquery"); } if (getValuesKeywords().contains(sqlParser.getLexer().getCurrentToken().getType())) { parseValues(); } else if (getCustomizedInsertKeywords().contains(sqlParser.getLexer().getCurrentToken().getType())) { parseCustomizedInsert(); } appendGenerateKey(); return insertStatement; } protected Set getUnsupportedKeywords() { return Collections.emptySet(); } private void parseInto() { if (getUnsupportedKeywords().contains(sqlParser.getLexer().getCurrentToken().getType())) { throw new SQLParsingUnsupportedException(sqlParser.getLexer().getCurrentToken().getType()); } sqlParser.skipUntil(DefaultKeyword.INTO); sqlParser.getLexer().nextToken(); sqlParser.parseSingleTable(insertStatement); skipBetweenTableAndValues(); } private void skipBetweenTableAndValues() { while (getSkippedKeywordsBetweenTableAndValues().contains(sqlParser.getLexer().getCurrentToken().getType())) { sqlParser.getLexer().nextToken(); if (sqlParser.equalAny(Symbol.LEFT_PAREN)) { sqlParser.skipParentheses(); } } } protected Set getSkippedKeywordsBetweenTableAndValues() { return Collections.emptySet(); } private void parseColumns() { Collection result = new LinkedList<>(); if (sqlParser.equalAny(Symbol.LEFT_PAREN)) { String tableName = insertStatement.getTables().getSingleTableName(); Optional generateKeyColumn = shardingRule.getGenerateKeyColumn(tableName); int count = 0; do { sqlParser.getLexer().nextToken(); String columnName = SQLUtil.getExactlyValue(sqlParser.getLexer().getCurrentToken().getLiterals()); result.add(new Column(columnName, tableName)); sqlParser.getLexer().nextToken(); if (generateKeyColumn.isPresent() && generateKeyColumn.get().equalsIgnoreCase(columnName)) { generateKeyColumnIndex = count; } count++; } while (!sqlParser.equalAny(Symbol.RIGHT_PAREN) && !sqlParser.equalAny(Assist.END)); insertStatement.setColumnsListLastPosition(sqlParser.getLexer().getCurrentToken().getEndPosition() - sqlParser.getLexer().getCurrentToken().getLiterals().length()); sqlParser.getLexer().nextToken(); } insertStatement.getColumns().addAll(result); } protected Set getValuesKeywords() { return Sets.newHashSet(DefaultKeyword.VALUES); } private void parseValues() { boolean parsed = false; do { if (parsed) { throw new UnsupportedOperationException("Cannot support multiple insert"); } sqlParser.getLexer().nextToken(); sqlParser.accept(Symbol.LEFT_PAREN); List sqlExpressions = new LinkedList<>(); do { sqlExpressions.add(sqlParser.parseExpression()); } while (sqlParser.skipIfEqual(Symbol.COMMA)); insertStatement.setValuesListLastPosition(sqlParser.getLexer().getCurrentToken().getEndPosition() - sqlParser.getLexer().getCurrentToken().getLiterals().length()); int count = 0; for (Column each : insertStatement.getColumns()) { SQLExpression sqlExpression = sqlExpressions.get(count); insertStatement.getConditions().add(new Condition(each, sqlExpression), shardingRule); if (generateKeyColumnIndex == count) { insertStatement.setGeneratedKey(createGeneratedKey(each, sqlExpression)); } count++; } sqlParser.accept(Symbol.RIGHT_PAREN); parsed = true; } while (sqlParser.equalAny(Symbol.COMMA)); } private GeneratedKey createGeneratedKey(final Column column, final SQLExpression sqlExpression) { GeneratedKey result; if (sqlExpression instanceof SQLPlaceholderExpression) { result = new GeneratedKey(column.getName(), ((SQLPlaceholderExpression) sqlExpression).getIndex(), null); } else if (sqlExpression instanceof SQLNumberExpression) { result = new GeneratedKey(column.getName(), -1, ((SQLNumberExpression) sqlExpression).getNumber()); } else { throw new ShardingJdbcException("Generated key only support number."); } return result; } protected Set getCustomizedInsertKeywords() { return Collections.emptySet(); } protected void parseCustomizedInsert() { } private void appendGenerateKey() { String tableName = insertStatement.getTables().getSingleTableName(); Optional generateKeyColumn = shardingRule.getGenerateKeyColumn(tableName); if (!generateKeyColumn.isPresent() || null != insertStatement.getGeneratedKey()) { return; } ItemsToken columnsToken = new ItemsToken(insertStatement.getColumnsListLastPosition()); columnsToken.getItems().add(generateKeyColumn.get()); insertStatement.getSqlTokens().add(columnsToken); insertStatement.getSqlTokens().add(new GeneratedKeyToken(insertStatement.getValuesListLastPosition())); } }