diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplicateStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplicateStatement.java index b5e2d84d81..754b0422ea 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplicateStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplicateStatement.java @@ -22,7 +22,6 @@ import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; -import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; public class MySqlReplicateStatement extends MySqlStatementImpl { @@ -35,7 +34,6 @@ public class MySqlReplicateStatement extends MySqlStatementImpl { private SQLName tableName; private final List columns = new ArrayList(); private List valuesList = new ArrayList(); - private List setItems = new ArrayList(); private SQLQueryExpr query; public SQLName getTableName() { @@ -79,16 +77,11 @@ public class MySqlReplicateStatement extends MySqlStatementImpl { return valuesList; } - public List getSetItems() { - return setItems; - } - public void accept0(MySqlASTVisitor visitor) { if (visitor.visit(this)) { acceptChild(visitor, tableName); acceptChild(visitor, columns); acceptChild(visitor, valuesList); - acceptChild(visitor, setItems); acceptChild(visitor, query); } visitor.endVisit(this); 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 2e922da7f2..37468cd290 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 @@ -22,7 +22,6 @@ import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLOrderBy; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; -import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; @@ -32,11 +31,11 @@ import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLSetStatement; import com.alibaba.druid.sql.ast.statement.SQLTableSource; -import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; @@ -1356,6 +1355,17 @@ public class MySqlStatementParser extends SQLStatementParser { SQLName tableName = exprParser.name(); stmt.setTableName(tableName); + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + if (lexer.token() == Token.SELECT) { + SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); + stmt.setQuery(queryExpr); + } else { + this.exprParser.exprList(stmt.getColumns()); + } + accept(Token.RPAREN); + } + if (lexer.token() == Token.VALUES || identifierEquals("VALUE")) { lexer.nextToken(); @@ -1378,13 +1388,17 @@ public class MySqlStatementParser extends SQLStatementParser { stmt.setQuery(queryExpr); } else if (lexer.token() == Token.SET) { lexer.nextToken(); - for (;;) { - SQLUpdateSetItem item = new SQLUpdateSetItem(); - item.setColumn(this.exprParser.name()); - accept(Token.EQ); - item.setValue(this.exprParser.expr()); - stmt.getSetItems().add(item); + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(); + stmt.getValuesList().add(values); + for (;;) { + stmt.getColumns().add(this.exprParser.name()); + if (lexer.token() == Token.COLONEQ) { + lexer.nextToken(); + } else { + accept(Token.EQ); + } + values.getValues().add(this.exprParser.expr()); if (lexer.token() == (Token.COMMA)) { lexer.nextToken(); @@ -1393,6 +1407,11 @@ public class MySqlStatementParser extends SQLStatementParser { break; } + } else if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); + stmt.setQuery(queryExpr); + accept(Token.RPAREN); } return stmt; @@ -1628,7 +1647,13 @@ public class MySqlStatementParser extends SQLStatementParser { if (lexer.token() == (Token.LPAREN)) { lexer.nextToken(); - this.exprParser.exprList(insertStatement.getColumns()); + if (lexer.token() == (Token.SELECT)) { + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + } else { + this.exprParser.exprList(insertStatement.getColumns()); + } accept(Token.RPAREN); } @@ -1654,7 +1679,7 @@ public class MySqlStatementParser extends SQLStatementParser { SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(); insertStatement.getValuesList().add(values); - + for (;;) { SQLName name = this.exprParser.name(); insertStatement.getColumns().add(name); @@ -1664,18 +1689,25 @@ public class MySqlStatementParser extends SQLStatementParser { accept(Token.COLONEQ); } values.getValues().add(this.exprParser.expr()); - + if (lexer.token() == Token.COMMA) { lexer.nextToken(); continue; } - + break; } } else if (lexer.token() == (Token.SELECT)) { - SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); - insertStatement.setQuery(queryExpr.getSubQuery()); + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + } else if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + accept(Token.RPAREN); } if (lexer.token() == Token.ON) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index 003570f129..a0042cbbb7 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -795,7 +795,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } if (x.getQuery() != null) { - print(" "); + println(); x.getQuery().accept(this); } @@ -937,12 +937,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV x.getQuery().accept(this); } - if (x.getSetItems().size() != 0) { - println(); - print("SET "); - printAndAccept(x.getSetItems(), ", "); - } - return false; } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLInsertParserTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLInsertParserTest.java index 9fc67f169d..5a0c976949 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLInsertParserTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLInsertParserTest.java @@ -39,4 +39,67 @@ public class DMLInsertParserTest extends TestCase { String output = SQLUtils.toMySqlString(stmt); Assert.assertEquals("INSERT INTO t1\nVALUES (123, ?) ON 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); + } + + public void testInsert_4() throws Exception { + String sql = "insErt LOW_PRIORITY t1 select id from t1"; + 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", 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); + } + + 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); + } + + 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); + } + + 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); + } + + public void testInsert_9() throws Exception { + String sql = "insErt LOW_PRIORITY IGNORE intO t1 (col1) ( select id from t3) "; + 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 IGNORE INTO t1 (col1)\nSELECT id\nFROM t3", output); + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLReplaceParserTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLReplaceParserTest.java new file mode 100644 index 0000000000..bbeba32713 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLReplaceParserTest.java @@ -0,0 +1,112 @@ +package com.alibaba.druid.bvt.sql.cobar; + +import org.junit.Assert; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.parser.Token; + +import junit.framework.TestCase; + + +public class DMLReplaceParserTest extends TestCase { + public void testReplace_0() throws Exception { + String sql = "ReplaCe LOW_PRIORITY intO test.t1 seT t1.id1:=?, id2='123'"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE LOW_PRIORITY INTO test.t1 (t1.id1, id2)\nVALUES (?, '123')", output); + } + + public void testReplace_1() throws Exception { + String sql = "ReplaCe test.t1 seT t1.id1:=? "; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE INTO test.t1 (t1.id1)\nVALUES (?)", output); + } + + public void testReplace_2() throws Exception { + String sql = "ReplaCe t1 value (123,?) "; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE INTO t1\nVALUES (123, ?)", output); + } + + public void testReplace_3() throws Exception { + String sql = "ReplaCe LOW_PRIORITY t1 valueS (12e-2), (?)"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE LOW_PRIORITY INTO t1\nVALUES (0.12), (?)", output); + } + + public void testReplace_4() throws Exception { + String sql = "ReplaCe LOW_PRIORITY t1 select id from t1"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE LOW_PRIORITY INTO t1\n\tSELECT id\n\tFROM t1", output); + } + + public void testReplace_5() throws Exception { + String sql = "ReplaCe delayed t1 select id from t1"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE DELAYED INTO t1\n\tSELECT id\n\tFROM t1", output); + } + + public void testReplace_6() throws Exception { + String sql = "ReplaCe LOW_PRIORITY t1 (select id from t1) "; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE LOW_PRIORITY INTO t1\n\tSELECT id\n\tFROM t1", output); + } + + public void testReplace_7() throws Exception { + String sql = "ReplaCe 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("REPLACE LOW_PRIORITY INTO t1 (t1.col1)\nVALUES (123), ('12''34')", output); + } + + public void testReplace_8() throws Exception { + String sql = "ReplaCe LOW_PRIORITY t1 (col1, t1.col2) VALUE (123,'123\\'4') "; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE LOW_PRIORITY INTO t1 (col1, t1.col2)\nVALUES (123, '123''4')", output); + } + + public void testReplace_9() throws Exception { + String sql = "REPLACE LOW_PRIORITY t1 (col1, t1.col2) select id from t3 "; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE LOW_PRIORITY INTO t1 (col1, t1.col2)\n\tSELECT id\n\tFROM t3", output); + } + + public void testReplace_10() throws Exception { + String sql = "replace LOW_PRIORITY intO t1 (col1) ( select id from t3) "; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("REPLACE LOW_PRIORITY INTO t1 (col1)\n\tSELECT id\n\tFROM t3", output); + } +}