Merge pull request #207 from wenshao/master

增强mysql sql parser
This commit is contained in:
温高铁
2012-11-26 02:32:57 -08:00
10 changed files with 379 additions and 27 deletions
@@ -154,6 +154,12 @@ public class MySqlExprParser extends SQLExprParser {
lexer.nextToken();
}
return primaryRest(varRefExpr);
case VALUES:
lexer.nextToken();
if (lexer.token() != Token.LPAREN) {
throw new ParserException("syntax error, illegal values clause");
}
return this.methodRest(new SQLIdentifierExpr("VALUES"), true);
default:
return super.primary();
}
@@ -812,13 +812,19 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
if (x.getValuesList().size() != 0) {
println();
print("VALUES ");
if (x.getValuesList().size() > 1) {
incrementIndent();
}
for (int i = 0, size = x.getValuesList().size(); i < size; ++i) {
if (i != 0) {
print(", ");
print(",");
println();
}
x.getValuesList().get(i).accept(this);
}
if (x.getValuesList().size() > 1) {
decrementIndent();
}
}
if (x.getQuery() != null) {
@@ -827,8 +833,17 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
if (x.getDuplicateKeyUpdate().size() != 0) {
print(" ON DUPLICATE KEY UPDATE ");
printAndAccept(x.getDuplicateKeyUpdate(), ", ");
println();
print("ON DUPLICATE KEY UPDATE ");
for (int i = 0, size = x.getDuplicateKeyUpdate().size(); i < size; ++i) {
if (i != 0) {
if (i % 5 == 0) {
println();
}
print(", ");
}
x.getDuplicateKeyUpdate().get(i).accept(this);
}
}
return false;
@@ -24,8 +24,8 @@ import com.alibaba.druid.sql.parser.Token;
import junit.framework.TestCase;
public class DMLInsertParserTest extends TestCase {
public void testInsert_0() throws Exception {
String sql = "insErt HIGH_PRIORITY intO test.t1 seT t1.id1=?, id2 := '123'";
MySqlStatementParser parser = new MySqlStatementParser(sql);
@@ -33,37 +33,39 @@ public class DMLInsertParserTest extends TestCase {
parser.match(Token.EOF);
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT HIGH_PRIORITY INTO test.t1 (t1.id1, id2)\n" + //
"VALUES (?, '123')", output);
"VALUES (?, '123')", output);
}
public void testInsert_1() throws Exception {
String sql = "insErt IGNORE test.t1 seT t1.id1:=? oN dupLicatE key UPDATE ex.col1=?, col2=12";
MySqlStatementParser parser = new MySqlStatementParser(sql);
SQLStatement stmt = parser.parseStatementList().get(0);
parser.match(Token.EOF);
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT IGNORE INTO test.t1 (t1.id1)\nVALUES (?) " + //
"ON DUPLICATE KEY UPDATE ex.col1 = ?, col2 = 12", output);
Assert.assertEquals("INSERT IGNORE INTO test.t1 (t1.id1)\nVALUES (?)" + //
"\nON DUPLICATE KEY UPDATE ex.col1 = ?, col2 = 12", output);
}
public void testInsert_2() throws Exception {
String sql = "insErt t1 value (123,?) oN dupLicatE key UPDATE ex.col1=?";
MySqlStatementParser parser = new MySqlStatementParser(sql);
SQLStatement stmt = parser.parseStatementList().get(0);
parser.match(Token.EOF);
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT INTO t1\nVALUES (123, ?) ON DUPLICATE KEY UPDATE ex.col1 = ?", output);
Assert.assertEquals("INSERT INTO t1\nVALUES (123, ?)\nON DUPLICATE KEY UPDATE ex.col1 = ?", output);
}
public void testInsert_3() throws Exception {
String sql = "insErt LOW_PRIORITY t1 valueS (12e-2,1,2), (?),(default)";
MySqlStatementParser parser = new MySqlStatementParser(sql);
SQLStatement stmt = parser.parseStatementList().get(0);
parser.match(Token.EOF);
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1\nVALUES (0.12, 1, 2), (?), (DEFAULT)", output);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1\nVALUES (0.12, 1, 2)," + //
"\n\t(?)," + //
"\n\t(DEFAULT)", output);
}
public void testInsert_4() throws Exception {
String sql = "insErt LOW_PRIORITY t1 select id from t1";
MySqlStatementParser parser = new MySqlStatementParser(sql);
@@ -72,43 +74,50 @@ public class DMLInsertParserTest extends TestCase {
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1\nSELECT id\nFROM t1", output);
}
public void testInsert_5() throws Exception {
String sql = "insErt LOW_PRIORITY t1 (select id from t1) oN dupLicatE key UPDATE ex.col1=?, col2=12";
MySqlStatementParser parser = new MySqlStatementParser(sql);
SQLStatement stmt = parser.parseStatementList().get(0);
parser.match(Token.EOF);
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1\nSELECT id\nFROM t1 ON DUPLICATE KEY UPDATE ex.col1 = ?, col2 = 12", output);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1\nSELECT id\nFROM t1" + //
"\nON DUPLICATE KEY UPDATE ex.col1 = ?, col2 = 12",
output);
}
public void testInsert_6() throws Exception {
String sql = "insErt LOW_PRIORITY t1 (t1.col1) valueS (123),('12''34')";
MySqlStatementParser parser = new MySqlStatementParser(sql);
SQLStatement stmt = parser.parseStatementList().get(0);
parser.match(Token.EOF);
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1 (t1.col1)\nVALUES (123), ('12''34')", output);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1 (t1.col1)\nVALUES (123)," + //
"\n\t('12''34')", output);
}
public void testInsert_7() throws Exception {
String sql = "insErt LOW_PRIORITY t1 (col1, t1.col2) VALUE (123,'123\\'4') oN dupLicatE key UPDATE ex.col1=?";
MySqlStatementParser parser = new MySqlStatementParser(sql);
SQLStatement stmt = parser.parseStatementList().get(0);
parser.match(Token.EOF);
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1 (col1, t1.col2)\nVALUES (123, '123''4') ON DUPLICATE KEY UPDATE ex.col1 = ?", output);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1 (col1, t1.col2)\nVALUES (123, '123''4')" + //
"\nON DUPLICATE KEY UPDATE ex.col1 = ?",
output);
}
public void testInsert_8() throws Exception {
String sql = "insErt LOW_PRIORITY t1 (col1, t1.col2) select id from t3 oN dupLicatE key UPDATE ex.col1=?";
MySqlStatementParser parser = new MySqlStatementParser(sql);
SQLStatement stmt = parser.parseStatementList().get(0);
parser.match(Token.EOF);
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1 (col1, t1.col2)\nSELECT id\nFROM t3 ON DUPLICATE KEY UPDATE ex.col1 = ?", output);
Assert.assertEquals("INSERT LOW_PRIORITY INTO t1 (col1, t1.col2)\nSELECT id\nFROM t3" + //
"\nON DUPLICATE KEY UPDATE ex.col1 = ?",
output);
}
public void testInsert_9() throws Exception {
String sql = "insErt LOW_PRIORITY IGNORE intO t1 (col1) ( select id from t3) ";
MySqlStatementParser parser = new MySqlStatementParser(sql);
@@ -68,7 +68,9 @@ public class InsertSyntaxTest extends TestCase {
String text = output(stmtList);
Assert.assertEquals("INSERT INTO tbl_name (a, b, c)\nVALUES (1, 2, 3), (4, 5, 6), (7, 8, 9);", text);
Assert.assertEquals("INSERT INTO tbl_name (a, b, c)\nVALUES (1, 2, 3)," + //
"\n\t(4, 5, 6)," + //
"\n\t(7, 8, 9);", text);
}
public void test_4() throws Exception {
@@ -79,7 +81,9 @@ public class InsertSyntaxTest extends TestCase {
String text = output(stmtList);
Assert.assertEquals("INSERT INTO tbl_name (a, b, c)\nVALUES (1, 2, 3, 4, 5\n\t, 6, 7, 8, 9);", text);
Assert.assertEquals("INSERT INTO tbl_name (a, b, c)" + //
"\nVALUES (1, 2, 3, 4, 5" + //
"\n\t, 6, 7, 8, 9);", text);
}
public void test_5() throws Exception {
@@ -102,8 +106,9 @@ public class InsertSyntaxTest extends TestCase {
String text = output(stmtList);
Assert.assertEquals("INSERT INTO tbl_name (a, b, c)\nVALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = c + 1;",
text);
Assert.assertEquals("INSERT INTO tbl_name (a, b, c)" + //
"\nVALUES (1, 2, 3)" + //
"\nON DUPLICATE KEY UPDATE c = c + 1;", text);
}
private String output(List<SQLStatement> stmtList) {
@@ -0,0 +1,50 @@
/*
* 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 junit.framework.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.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
public class MySqlInsertTest_1 extends MysqlTest {
public void test_0() throws Exception {
String sql = "INSERT INTO tbl_name () VALUES();";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
SQLInsertStatement insertStmt = (SQLInsertStatement) stmt;
Assert.assertEquals(0, insertStmt.getValues().getValues().size());
Assert.assertEquals(0, insertStmt.getColumns().size());
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
stmt.accept(visitor);
Assert.assertEquals("INSERT INTO tbl_name" + //
"\nVALUES ()", SQLUtils.toMySqlString(insertStmt));
}
}
@@ -0,0 +1,50 @@
/*
* 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 junit.framework.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.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
public class MySqlInsertTest_2 extends MysqlTest {
public void test_0() throws Exception {
String sql = "INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
SQLInsertStatement insertStmt = (SQLInsertStatement) stmt;
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);
Assert.assertEquals("INSERT INTO tbl_name (col1, col2)" + //
"\nVALUES (15, col1 * 2)", SQLUtils.toMySqlString(insertStmt));
}
}
@@ -0,0 +1,50 @@
/*
* 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 junit.framework.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.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
public class MySqlInsertTest_3 extends MysqlTest {
public void test_0() throws Exception {
String sql = "INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
SQLInsertStatement insertStmt = (SQLInsertStatement) stmt;
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);
Assert.assertEquals("INSERT INTO tbl_name (col1, col2)" + //
"\nVALUES (col2 * 2, 15)", SQLUtils.toMySqlString(insertStmt));
}
}
@@ -0,0 +1,56 @@
/*
* 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 junit.framework.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_4 extends MysqlTest {
public void test_0() throws Exception {
String sql = "INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt;
Assert.assertEquals(3, insertStmt.getColumns().size());
Assert.assertEquals(3, insertStmt.getValuesList().size());
Assert.assertEquals(3, insertStmt.getValuesList().get(0).getValues().size());
Assert.assertEquals(3, insertStmt.getValuesList().get(1).getValues().size());
Assert.assertEquals(3, insertStmt.getValuesList().get(2).getValues().size());
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
stmt.accept(visitor);
Assert.assertEquals("INSERT INTO tbl_name (a, b, c)" + //
"\nVALUES (1, 2, 3)," +
"\n\t(4, 5, 6)," +
"\n\t(7, 8, 9)", SQLUtils.toMySqlString(insertStmt));
}
}
@@ -0,0 +1,53 @@
/*
* 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 junit.framework.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_5 extends MysqlTest {
public void test_0() throws Exception {
String sql = "INSERT INTO tbl_name (a,b,c) VALUES(1,2,3,4,5,6,7,8,9);";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt;
Assert.assertEquals(3, insertStmt.getColumns().size());
Assert.assertEquals(1, insertStmt.getValuesList().size());
Assert.assertEquals(9, insertStmt.getValuesList().get(0).getValues().size());
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
stmt.accept(visitor);
Assert.assertEquals("INSERT INTO tbl_name (a, b, c)" + //
"\nVALUES (1, 2, 3, 4, 5" + //
"\n\t, 6, 7, 8, 9)", SQLUtils.toMySqlString(insertStmt));
}
}
@@ -0,0 +1,58 @@
/*
* 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 junit.framework.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_6 extends MysqlTest {
public void test_0() throws Exception {
String sql = "insert into document(the_key,the_namespace,Gmt_create,Gmt_modify,Expired_time,the_value) " + //
"values (?,?,now(),now(),date_add(now(),interval ? second),?) " + //
"on duplicate key update Gmt_modify = values(Gmt_modify),Expired_time = values(Expired_time),the_value = values(the_value)";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt;
Assert.assertEquals(6, insertStmt.getColumns().size());
Assert.assertEquals(1, insertStmt.getValuesList().size());
Assert.assertEquals(6, insertStmt.getValuesList().get(0).getValues().size());
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
stmt.accept(visitor);
Assert.assertEquals("INSERT INTO document (the_key, the_namespace, Gmt_create, Gmt_modify, Expired_time" + //
"\n\t, the_value)" + //
"\nVALUES (?, ?, now(), now(), date_add(now(), INTERVAL ? SECOND)" + //
"\n\t, ?)" + //
"\nON DUPLICATE KEY UPDATE Gmt_modify = VALUES(Gmt_modify), Expired_time = VALUES(Expired_time), the_value = VALUES(the_value)",
SQLUtils.toMySqlString(insertStmt));
}
}