From f616dbfebee06e50d9596d8abce1c062830683a9 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 7 Jun 2015 17:04:15 +0800 Subject: [PATCH] improved mysql parser support alter table add multicolumns --- .../mysql/parser/MySqlStatementParser.java | 111 ++++++++++-------- .../mysql/visitor/MySqlOutputVisitor.java | 8 ++ .../bvt/sql/mysql/MySqlAlterTableTest20.java | 38 ++++++ 3 files changed, 110 insertions(+), 47 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest20.java 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 d964b3ce37..dc5c9c7840 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 @@ -352,7 +352,7 @@ public class MySqlStatementParser extends SQLStatementParser { return parseCreateView(); } - + if (lexer.token() == Token.TRIGGER) { if (replace) { lexer.reset(markBp, markChar, Token.CREATE); @@ -663,7 +663,7 @@ public class MySqlStatementParser extends SQLStatementParser { stmt.setLockType(LockType.LOW_PRIORITY_WRITE); } - if(lexer.token() == Token.HINT) { + if (lexer.token() == Token.HINT) { stmt.setHints(this.exprParser.parseHints()); } statementList.add(stmt); @@ -676,12 +676,12 @@ public class MySqlStatementParser extends SQLStatementParser { statementList.add(new MySqlUnlockTablesStatement()); return true; } - - if(lexer.token() == Token.HINT) { + + if (lexer.token() == Token.HINT) { statementList.add(this.parseHint()); return true; } - + if (lexer.token() == Token.BEGIN) { statementList.add(this.parseBlock()); return true; @@ -689,7 +689,7 @@ public class MySqlStatementParser extends SQLStatementParser { return false; } - + public MySqlBlockStatement parseBlock() { MySqlBlockStatement block = new MySqlBlockStatement(); @@ -1132,7 +1132,7 @@ public class MySqlStatementParser extends SQLStatementParser { stmt.setDatabase(database); } } - + if (lexer.token() == Token.HINT) { stmt.setHints(this.exprParser.parseHints()); } @@ -1527,8 +1527,8 @@ public class MySqlStatementParser extends SQLStatementParser { stmt.setWork(true); } } - - if(lexer.token() == Token.HINT) { + + if (lexer.token() == Token.HINT) { stmt.setHints(this.exprParser.parseHints()); } @@ -1862,7 +1862,7 @@ public class MySqlStatementParser extends SQLStatementParser { if (identifierEquals(IGNORE)) { lexer.nextToken(); - stmt.setIgnoreLinesNumber( this.exprParser.expr()); + stmt.setIgnoreLinesNumber(this.exprParser.expr()); acceptIdentifier("LINES"); } @@ -1879,7 +1879,6 @@ public class MySqlStatementParser extends SQLStatementParser { return stmt; - } public MySqlPrepareStatement parsePrepare() { @@ -2052,10 +2051,10 @@ public class MySqlStatementParser extends SQLStatementParser { break; } else { expr = this.exprParser.primaryRest(expr); - if(lexer.token() != Token.COMMA && lexer.token() != Token.RPAREN) { + if (lexer.token() != Token.COMMA && lexer.token() != Token.RPAREN) { expr = this.exprParser.exprRest(expr); } - + valueExprList.add(expr); if (lexer.token() == Token.COMMA) { lexer.nextToken(); @@ -2072,11 +2071,11 @@ 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; @@ -2127,9 +2126,9 @@ public class MySqlStatementParser extends SQLStatementParser { if (identifierEquals("TRANSACTION")) { MySqlSetTransactionStatement stmt = new MySqlSetTransactionStatement(); stmt.setGlobal(global); - + lexer.nextToken(); - if(identifierEquals("ISOLATION")) { + if (identifierEquals("ISOLATION")) { lexer.nextToken(); acceptIdentifier("LEVEL"); @@ -2230,8 +2229,8 @@ public class MySqlStatementParser extends SQLStatementParser { SQLVariantRefExpr varRef = (SQLVariantRefExpr) stmt.getItems().get(0).getTarget(); varRef.setGlobal(true); } - - if(lexer.token() == Token.HINT) { + + if (lexer.token() == Token.HINT) { stmt.setHints(this.exprParser.parseHints()); } @@ -2272,21 +2271,7 @@ public class MySqlStatementParser extends SQLStatementParser { if (lexer.token() == Token.COLUMN) { lexer.nextToken(); - MySqlAlterTableAddColumn item = new MySqlAlterTableAddColumn(); - SQLColumnDefinition columnDef = this.exprParser.parseColumn(); - item.getColumns().add(columnDef); - if (identifierEquals("AFTER")) { - lexer.nextToken(); - item.setAfterColumn(this.exprParser.name()); - } else if (identifierEquals("FIRST")) { - lexer.nextToken(); - if (lexer.token() == Token.IDENTIFIER) { - item.setFirstColumn(this.exprParser.name()); - } else { - item.setFirst(true); - } - } - stmt.getItems().add(item); + parseAlterTableAddColumn(stmt); } else if (lexer.token() == Token.INDEX) { SQLAlterTableAddIndex item = parseAlterTableAddIndex(); item.setParent(stmt); @@ -2336,14 +2321,7 @@ public class MySqlStatementParser extends SQLStatementParser { } else if (identifierEquals(SPATIAL)) { throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } else { - MySqlAlterTableAddColumn item = new MySqlAlterTableAddColumn(); - SQLColumnDefinition columnDef = this.exprParser.parseColumn(); - item.getColumns().add(columnDef); - if (identifierEquals("AFTER")) { - lexer.nextToken(); - item.setAfterColumn(this.exprParser.name()); - } - stmt.getItems().add(item); + parseAlterTableAddColumn(stmt); } } else if (lexer.token() == Token.ALTER) { lexer.nextToken(); @@ -2516,12 +2494,12 @@ public class MySqlStatementParser extends SQLStatementParser { stmt.getItems().add(item); } else if (lexer.token() == Token.COMMENT) { lexer.nextToken(); - if(lexer.token() == Token.EQ) { + if (lexer.token() == Token.EQ) { accept(Token.EQ); } stmt.getItems().add(new MySqlAlterTableOption("COMMENT", '\'' + lexer.stringVal() + '\'')); lexer.nextToken(); - }else { + } else { break; } @@ -2538,6 +2516,45 @@ public class MySqlStatementParser extends SQLStatementParser { throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } + protected void parseAlterTableAddColumn(MySqlAlterTableStatement stmt) { + boolean parenFlag = false; + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + parenFlag = true; + } + + MySqlAlterTableAddColumn item = new MySqlAlterTableAddColumn(); + for (;;) { + + SQLColumnDefinition columnDef = this.exprParser.parseColumn(); + item.getColumns().add(columnDef); + if (identifierEquals("AFTER")) { + lexer.nextToken(); + item.setAfterColumn(this.exprParser.name()); + } else if (identifierEquals("FIRST")) { + lexer.nextToken(); + if (lexer.token() == Token.IDENTIFIER) { + item.setFirstColumn(this.exprParser.name()); + } else { + item.setFirst(true); + } + } + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + + break; + } + + stmt.getItems().add(item); + + if (parenFlag) { + accept(Token.RPAREN); + } + } + public void parseAlterDrop(SQLAlterTableStatement stmt) { lexer.nextToken(); if (lexer.token() == Token.INDEX) { @@ -2637,7 +2654,7 @@ public class MySqlStatementParser extends SQLStatementParser { if (lexer.token() == Token.DEFAULT) { lexer.nextToken(); } - + if (lexer.token() == Token.HINT) { stmt.setHints(this.exprParser.parseHints()); } @@ -2699,9 +2716,9 @@ public class MySqlStatementParser extends SQLStatementParser { public MySqlExprParser getExprParser() { return (MySqlExprParser) exprParser; } - + public MySqlHintStatement parseHint() { - //accept(Token.HINT); + // accept(Token.HINT); MySqlHintStatement stmt = new MySqlHintStatement(); stmt.setHints(this.exprParser.parseHints()); 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 d64b58c04b..0e4654cff0 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 @@ -2509,6 +2509,10 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlAlterTableAddColumn x) { print("ADD COLUMN "); + + if (x.getColumns().size() > 1) { + print("("); + } printAndAccept(x.getColumns(), ", "); if (x.getFirstColumn() != null) { print(" FIRST "); @@ -2519,6 +2523,10 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } else if (x.isFirst()) { print(" FIRST"); } + + if (x.getColumns().size() > 1) { + print(")"); + } return false; } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest20.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest20.java new file mode 100644 index 0000000000..42c0f229d8 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest20.java @@ -0,0 +1,38 @@ +/* + * 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 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.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.parser.Token; + +public class MySqlAlterTableTest20 extends TestCase { + + public void test_alter_add_key() throws Exception { + String sql = "ALTER TABLE score1 ADD ( test3 int(11),test4 int(11))"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("ALTER TABLE score1" + + "\n\tADD COLUMN (test3 int(11), test4 int(11))", output); + } +}