diff --git a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/context/condition/Conditions.java b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/context/condition/Conditions.java index 7259b373683de..d0632161ccff0 100644 --- a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/context/condition/Conditions.java +++ b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/context/condition/Conditions.java @@ -2,11 +2,13 @@ import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule; import com.google.common.base.Optional; +import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Map.Entry; /** * 条件对象集合. @@ -14,11 +16,18 @@ * @author zhangliang */ @RequiredArgsConstructor +@Getter @ToString public final class Conditions { private final Map conditions = new LinkedHashMap<>(); + public Conditions(final Conditions conditions) { + for (Entry entry : conditions.conditions.entrySet()) { + this.conditions.put(entry.getKey(), entry.getValue()); + } + } + /** * 添加条件对象. * diff --git a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/dml/insert/AbstractInsertParser.java b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/dml/insert/AbstractInsertParser.java index 0bc452d51aaee..2fff2cc3189a8 100644 --- a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/dml/insert/AbstractInsertParser.java +++ b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/dml/insert/AbstractInsertParser.java @@ -27,6 +27,7 @@ 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.context.condition.Conditions; 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; @@ -35,6 +36,7 @@ import com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.dml.DMLStatement; 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.parsing.parser.token.MultipleInsertValuesToken; import com.dangdang.ddframe.rdb.sharding.util.SQLUtil; import com.google.common.base.Optional; import lombok.AccessLevel; @@ -62,6 +64,8 @@ public abstract class AbstractInsertParser implements SQLStatementParser { private int columnsListLastPosition; + private int afterValuesPosition; + private int valuesListLastPosition; private int generateKeyColumnIndex = -1; @@ -78,10 +82,14 @@ public final DMLStatement parse() { parseInto(); parseColumns(); if (sqlParser.equalAny(DefaultKeyword.SELECT, Symbol.LEFT_PAREN)) { - throw new UnsupportedOperationException("Cannot support subquery"); + throw new UnsupportedOperationException("Cannot INSERT SELECT"); } if (sqlParser.skipIfEqual(getValuesKeywords())) { + afterValuesPosition = sqlParser.getLexer().getCurrentToken().getEndPosition() - sqlParser.getLexer().getCurrentToken().getLiterals().length(); parseValues(); + if (sqlParser.equalAny(Symbol.COMMA)) { + parseMultipleValues(); + } } else if (sqlParser.skipIfEqual(getCustomizedInsertKeywords())) { parseCustomizedInsert(); } @@ -143,30 +151,22 @@ protected Keyword[] getValuesKeywords() { } private void parseValues() { - boolean parsed = false; + sqlParser.accept(Symbol.LEFT_PAREN); + List sqlExpressions = new LinkedList<>(); do { - if (parsed) { - throw new UnsupportedOperationException("Cannot support multiple insert"); + sqlExpressions.add(sqlParser.parseExpression()); + } while (sqlParser.skipIfEqual(Symbol.COMMA)); + valuesListLastPosition = 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)); } - sqlParser.accept(Symbol.LEFT_PAREN); - List sqlExpressions = new LinkedList<>(); - do { - sqlExpressions.add(sqlParser.parseExpression()); - } while (sqlParser.skipIfEqual(Symbol.COMMA)); - valuesListLastPosition = 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; + count++; } - while (sqlParser.skipIfEqual(Symbol.COMMA)); + sqlParser.accept(Symbol.RIGHT_PAREN); } private GeneratedKey createGeneratedKey(final Column column, final SQLExpression sqlExpression) { @@ -181,6 +181,21 @@ private GeneratedKey createGeneratedKey(final Column column, final SQLExpression return result; } + private void parseMultipleValues() { + insertStatement.getMultipleConditions().add(new Conditions(insertStatement.getConditions())); + MultipleInsertValuesToken valuesToken = new MultipleInsertValuesToken(afterValuesPosition); + valuesToken.getValues().add(sqlParser.getLexer().getInput().substring(afterValuesPosition, sqlParser.getLexer().getCurrentToken().getEndPosition() - Symbol.COMMA.getLiterals().length())); + while (sqlParser.skipIfEqual(Symbol.COMMA)) { + int beginPosition = sqlParser.getLexer().getCurrentToken().getEndPosition() - sqlParser.getLexer().getCurrentToken().getLiterals().length(); + parseValues(); + insertStatement.getMultipleConditions().add(new Conditions(insertStatement.getConditions())); + int endPosition = sqlParser.equalAny(Symbol.COMMA) + ? sqlParser.getLexer().getCurrentToken().getEndPosition() - Symbol.COMMA.getLiterals().length() : sqlParser.getLexer().getCurrentToken().getEndPosition(); + valuesToken.getValues().add(sqlParser.getLexer().getInput().substring(beginPosition, endPosition)); + } + insertStatement.getSqlTokens().add(valuesToken); + } + protected Keyword[] getCustomizedInsertKeywords() { return new Keyword[0]; } diff --git a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/dml/insert/InsertStatement.java b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/dml/insert/InsertStatement.java index 959f50d0951a0..b1b21afe0c916 100644 --- a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/dml/insert/InsertStatement.java +++ b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/dml/insert/InsertStatement.java @@ -23,6 +23,7 @@ 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.context.condition.Conditions; 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.dml.DMLStatement; @@ -36,6 +37,7 @@ import java.util.Collection; import java.util.LinkedList; +import java.util.List; /** * Insert SQL语句对象. @@ -49,6 +51,8 @@ public final class InsertStatement extends DMLStatement { private final Collection columns = new LinkedList<>(); + private final List multipleConditions = new LinkedList<>(); + private GeneratedKey generatedKey; /** diff --git a/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/token/MultipleInsertValuesToken.java b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/token/MultipleInsertValuesToken.java new file mode 100644 index 0000000000000..bf43c05b4ed56 --- /dev/null +++ b/sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/token/MultipleInsertValuesToken.java @@ -0,0 +1,40 @@ +/* + * 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.token; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +import java.util.LinkedList; +import java.util.List; + +/** + * 批量插入标记对象. + * + * @author zhangliang + */ +@RequiredArgsConstructor +@Getter +@ToString +public final class MultipleInsertValuesToken implements SQLToken { + + private final int beginPosition; + + private final List values = new LinkedList<>(); +} diff --git a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/InsertStatementParserTest.java b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/InsertStatementParserTest.java index 575aec28276cc..e0e2f88f4735a 100644 --- a/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/InsertStatementParserTest.java +++ b/sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/parsing/parser/statement/InsertStatementParserTest.java @@ -142,10 +142,11 @@ private void parseWithSpecialSyntax(final DatabaseType dbType, final String actu assertThat(condition.getShardingValue(Collections.emptyList()).getValue(), is((Comparable) 1)); } - @Test(expected = UnsupportedOperationException.class) + @Test + // TODO assert public void parseMultipleInsertForMySQL() { ShardingRule shardingRule = createShardingRule(); - new SQLParsingEngine(DatabaseType.Oracle, "INSERT INTO TABLE_XXX (`field1`, `field2`) VALUES (1, 'value_char'), (2, 'value_char')", shardingRule).parse(); + new SQLParsingEngine(DatabaseType.MySQL, "INSERT INTO TABLE_XXX (`field1`, `field2`) VALUES (1, 'value_char'), (2, 'value_char')", shardingRule).parse(); } @Test(expected = SQLParsingUnsupportedException.class)