From 54c940b9b92a35123100d466093b3fa6c7d517aa Mon Sep 17 00:00:00 2001 From: Yako Date: Thu, 4 Sep 2014 13:19:55 +0800 Subject: [PATCH] improve sqlwall: update --- .../java/com/alibaba/druid/sql/SQLUtils.java | 4 + .../mysql/parser/MySqlStatementParser.java | 7 +- .../parser/SQLServerStatementParser.java | 5 ++ .../com/alibaba/druid/sql/parser/Lexer.java | 5 ++ .../druid/sql/parser/SQLStatementParser.java | 21 +++++ .../com/alibaba/druid/wall/WallConfig.java | 19 ++++ .../com/alibaba/druid/wall/WallProvider.java | 6 +- .../bvt/sql/mysql/MySqlInsertTest_10.java | 82 ++++++++++++++++++ .../sql/sqlserver/SQLServerInsertTest5.java | 86 +++++++++++++++++++ 9 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_10.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest5.java diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index d66c27af03..2328dca53c 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -117,6 +117,10 @@ public class SQLUtils { return format(sql, JdbcUtils.ODPS); } + public static String formatSQLServer(String sql) { + return format(sql, JdbcUtils.SQL_SERVER); + } + public static String toOracleString(SQLObject sqlObject) { StringBuilder out = new StringBuilder(); sqlObject.accept(new OracleOutputVisitor(out, false)); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index db27a022b2..56b3f29809 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -1994,10 +1994,15 @@ public class MySqlStatementParser extends SQLStatementParser { SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList(0)); valueClauseList.add(values); } - + if (lexer.token() != Token.RPAREN) { throw new ParserException("syntax error"); } + + if (!parseCompleteValues && valueClauseList.size() >= parseValuesSize) { + lexer.skipToEOF(); + break; + } lexer.nextTokenComma(); if (lexer.token() == Token.COMMA) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerStatementParser.java index f85241aaca..ab0fc58e10 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerStatementParser.java @@ -123,6 +123,11 @@ public class SQLServerStatementParser extends SQLStatementParser { insertStatement.getValuesList().add(values); accept(Token.RPAREN); + if (!parseCompleteValues && insertStatement.getValuesList().size() >= parseValuesSize) { + lexer.skipToEOF(); + break; + } + if (lexer.token() == Token.COMMA) { lexer.nextToken(); continue; diff --git a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java index a8174a78eb..7576eb8bd2 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -1053,4 +1053,9 @@ public class Lexer { public boolean isHasComment() { return hasComment; } + + public void skipToEOF() { + pos = text.length(); + this.token = Token.EOF; + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java index f971ee70d5..93b2ded1f0 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -85,6 +85,10 @@ public class SQLStatementParser extends SQLParser { protected SQLExprParser exprParser; + protected boolean parseCompleteValues = true; + + protected int parseValuesSize = 3; + public SQLStatementParser(String sql){ this(new SQLExprParser(sql)); } @@ -1569,4 +1573,21 @@ public class SQLStatementParser extends SQLParser { accept(Token.RPAREN); return item; } + + + public boolean isParseCompleteValues() { + return parseCompleteValues; + } + + public void setParseCompleteValues(boolean parseCompleteValues) { + this.parseCompleteValues = parseCompleteValues; + } + + public int getParseValuesSize() { + return parseValuesSize; + } + + public void setParseValuesSize(int parseValuesSize) { + this.parseValuesSize = parseValuesSize; + } } diff --git a/src/main/java/com/alibaba/druid/wall/WallConfig.java b/src/main/java/com/alibaba/druid/wall/WallConfig.java index c6ddc04353..87bf98a3f4 100644 --- a/src/main/java/com/alibaba/druid/wall/WallConfig.java +++ b/src/main/java/com/alibaba/druid/wall/WallConfig.java @@ -119,6 +119,9 @@ public class WallConfig implements WallConfigMBean { private boolean conditionOpBitwseAllow = true; private boolean caseConditionConstAllow = false; + + private boolean completeInsertValuesCheck = false; + private int insertValuesCheckSize = 3; public WallConfig(){ @@ -770,4 +773,20 @@ public class WallConfig implements WallConfigMBean { this.startTransactionAllow = startTransactionAllow; } + public boolean isCompleteInsertValuesCheck() { + return completeInsertValuesCheck; + } + + public void setCompleteInsertValuesCheck(boolean completeInsertValuesCheck) { + this.completeInsertValuesCheck = completeInsertValuesCheck; + } + + public int getInsertValuesCheckSize() { + return insertValuesCheckSize; + } + + public void setInsertValuesCheckSize(int insertValuesCheckSize) { + this.insertValuesCheckSize = insertValuesCheckSize; + } + } diff --git a/src/main/java/com/alibaba/druid/wall/WallProvider.java b/src/main/java/com/alibaba/druid/wall/WallProvider.java index 4b3f648d8b..cb7cc29194 100644 --- a/src/main/java/com/alibaba/druid/wall/WallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/WallProvider.java @@ -611,7 +611,11 @@ public abstract class WallProvider { if (!config.isCommentAllow()) { parser.getLexer().setAllowComment(false); // deny comment } - + if (!config.isCompleteInsertValuesCheck()) { + parser.setParseCompleteValues(false); + parser.setParseValuesSize(config.getInsertValuesCheckSize()); + } + parser.parseStatementList(statementList); final Token lastToken = parser.getLexer().token(); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_10.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_10.java new file mode 100644 index 0000000000..7a12ca5217 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_10.java @@ -0,0 +1,82 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * 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.alibaba.druid.bvt.sql.mysql; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; + +public class MySqlInsertTest_10 extends MysqlTest { + + public void test_parseCompleteValues_false() throws Exception { + String sql = "insert into t(a,b) values ('a1','b1'),('a2','b2'),('a3','b3'),('a4','b4');"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + parser.setParseCompleteValues(false); + parser.setParseValuesSize(3); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt; + + Assert.assertEquals(3, insertStmt.getValuesList().size()); + Assert.assertEquals(2, insertStmt.getValues().getValues().size()); + Assert.assertEquals(2, insertStmt.getColumns().size()); + Assert.assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + String formatSql = "INSERT INTO t (a, b)"// + + "\nVALUES ('a1', 'b1'),"// + + "\n\t('a2', 'b2'),"// + + "\n\t('a3', 'b3')"; + Assert.assertEquals(formatSql, SQLUtils.toMySqlString(insertStmt)); + } + + public void test_parseCompleteValues_true() throws Exception { + String sql = "insert into t(a,b) values ('a1','b1'),('a2','b2'),('a3','b3'),('a4','b4');"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + parser.setParseCompleteValues(true); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt; + + Assert.assertEquals(4, insertStmt.getValuesList().size()); + Assert.assertEquals(2, insertStmt.getValues().getValues().size()); + Assert.assertEquals(2, insertStmt.getColumns().size()); + Assert.assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + String formatSql = "INSERT INTO t (a, b)"// + + "\nVALUES ('a1', 'b1'),"// + + "\n\t('a2', 'b2'),"// + + "\n\t('a3', 'b3'),"// + + "\n\t('a4', 'b4')"; + Assert.assertEquals(formatSql, SQLUtils.toMySqlString(insertStmt)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest5.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest5.java new file mode 100644 index 0000000000..d92ff6824b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest5.java @@ -0,0 +1,86 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * 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.alibaba.druid.bvt.sql.sqlserver; + +import java.util.List; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; +import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; +import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor; + +public class SQLServerInsertTest5 extends TestCase { + + public void test_parseCompleteValues_false() throws Exception { + String sql = "insert into t(a,b) values ('a1','b1'),('a2','b2'),('a3','b3'),('a4','b4');"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + parser.setParseCompleteValues(false); + parser.setParseValuesSize(3); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + SQLServerInsertStatement insertStmt = (SQLServerInsertStatement) stmt; + + Assert.assertEquals(3, insertStmt.getValuesList().size()); + Assert.assertEquals(2, insertStmt.getValues().getValues().size()); + Assert.assertEquals(2, insertStmt.getColumns().size()); + Assert.assertEquals(1, statementList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + String formatSql = "INSERT INTO t"// + + "\n\t(a, b)"// + + "\nVALUES" + "\n('a1', 'b1'),"// + + "\n('a2', 'b2'),"// + + "\n('a3', 'b3')"; + Assert.assertEquals(formatSql, SQLUtils.toSQLServerString(insertStmt)); + } + + public void test_parseCompleteValues_true() throws Exception { + String sql = "insert into t(a,b) values ('a1','b1'),('a2','b2'),('a3','b3'),('a4','b4');"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + parser.setParseCompleteValues(true); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + SQLServerInsertStatement insertStmt = (SQLServerInsertStatement) stmt; + + Assert.assertEquals(4, insertStmt.getValuesList().size()); + Assert.assertEquals(2, insertStmt.getValues().getValues().size()); + Assert.assertEquals(2, insertStmt.getColumns().size()); + Assert.assertEquals(1, statementList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + String formatSql = "INSERT INTO t"// + + "\n\t(a, b)"// + + "\nVALUES"// + + "\n('a1', 'b1'),"// + + "\n('a2', 'b2'),"// + + "\n('a3', 'b3'),"// + + "\n('a4', 'b4')"; + Assert.assertEquals(formatSql, SQLUtils.toSQLServerString(insertStmt)); + } +}