From 4b0b51656e8dc6896cb77201aaa1a3231752abd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A9=E5=B0=91?= Date: Wed, 16 May 2012 16:13:50 +0800 Subject: [PATCH] mysql parser refactor --- .../SQLAlterTableDropColumnItem.java | 28 ++ .../statement/MySqlAlterTableAddColumn.java | 38 +++ .../statement/MySqlAlterTableStatement.java | 20 +- .../mysql/parser/MySqlStatementParser.java | 136 ++++++++-- .../mysql/visitor/MySqlASTVisitor.java | 138 +++++----- .../mysql/visitor/MySqlASTVisitorAdapter.java | 22 ++ .../mysql/visitor/MySqlOutputVisitor.java | 54 +++- .../mysql/visitor/MySqlSchemaStatVisitor.java | 22 ++ .../druid/sql/parser/SQLExprParser.java | 6 + .../druid/sql/parser/SQLStatementParser.java | 2 +- .../sql/visitor/SQLASTOutputVisitor.java | 8 + .../druid/sql/visitor/SQLASTVisitor.java | 5 + .../sql/visitor/SQLASTVisitorAdapter.java | 11 + .../druid/bvt/sql/cobar/DDLParserTest.java | 241 ++++++++++-------- 14 files changed, 533 insertions(+), 198 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableDropColumnItem.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableAddColumn.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableDropColumnItem.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableDropColumnItem.java new file mode 100644 index 0000000000..e01564bdde --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableDropColumnItem.java @@ -0,0 +1,28 @@ +package com.alibaba.druid.sql.ast.statement; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLObjectImpl; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class SQLAlterTableDropColumnItem extends SQLObjectImpl implements SQLAlterTableItem { + + private static final long serialVersionUID = 1L; + private SQLName columnName; + + @Override + protected void accept0(SQLASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, columnName); + } + visitor.endVisit(this); + } + + public SQLName getColumnName() { + return columnName; + } + + public void setColumnName(SQLName columnName) { + this.columnName = columnName; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableAddColumn.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableAddColumn.java new file mode 100644 index 0000000000..76c6416e17 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableAddColumn.java @@ -0,0 +1,38 @@ +package com.alibaba.druid.sql.dialect.mysql.ast.statement; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObject; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class MySqlAlterTableAddColumn extends SQLAlterTableAddColumn implements MySqlObject { + + private static final long serialVersionUID = 1L; + + private SQLName after; + + public SQLName getAfter() { + return after; + } + + public void setAfter(SQLName after) { + this.after = after; + } + + @Override + protected void accept0(SQLASTVisitor visitor) { + if (visitor instanceof MySqlASTVisitor) { + accept0((MySqlASTVisitor) visitor); + } else { + throw new IllegalArgumentException("not support visitor type : " + visitor.getClass().getName()); + } + } + + public void accept0(MySqlASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, getColumns()); + } + visitor.endVisit(this); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableStatement.java index 865d0b3470..b445e1b944 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableStatement.java @@ -4,11 +4,12 @@ import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; - public class MySqlAlterTableStatement extends SQLAlterTableStatement { private static final long serialVersionUID = 1L; + private boolean ignore = false; + @Override protected void accept0(SQLASTVisitor visitor) { if (visitor instanceof MySqlASTVisitor) { @@ -17,8 +18,21 @@ public class MySqlAlterTableStatement extends SQLAlterTableStatement { throw new IllegalArgumentException("not support visitor type : " + visitor.getClass().getName()); } } - + public void accept0(MySqlASTVisitor visitor) { - throw new UnsupportedOperationException(this.getClass().getName()); + if (visitor.visit(this)) { + acceptChild(visitor, getTableSource()); + acceptChild(visitor, getItems()); + } + visitor.endVisit(this); } + + public boolean isIgnore() { + return ignore; + } + + public void setIgnore(boolean ignore) { + this.ignore = ignore; + } + } 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 961842d6fc..086086e862 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 @@ -26,6 +26,8 @@ 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; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; @@ -35,6 +37,8 @@ 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; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; @@ -506,12 +510,12 @@ public class MySqlStatementParser extends SQLStatementParser { return stmt; } - + if (identifierEquals("VARIABLES")) { lexer.nextToken(); - + MySqlShowVariantsStatement stmt = parseShowVariants(); - + return stmt; } @@ -524,7 +528,7 @@ public class MySqlStatementParser extends SQLStatementParser { stmt.setGlobal(true); return stmt; } - + if (identifierEquals("VARIABLES")) { lexer.nextToken(); MySqlShowVariantsStatement stmt = parseShowVariants(); @@ -542,7 +546,7 @@ public class MySqlStatementParser extends SQLStatementParser { stmt.setSession(true); return stmt; } - + if (identifierEquals("VARIABLES")) { lexer.nextToken(); MySqlShowVariantsStatement stmt = parseShowVariants(); @@ -970,24 +974,24 @@ public class MySqlStatementParser extends SQLStatementParser { return stmt; } - + if (identifierEquals("RELAYLOG")) { lexer.nextToken(); acceptIdentifier("EVENTS"); MySqlShowRelayLogEventsStatement stmt = new MySqlShowRelayLogEventsStatement(); - + if (lexer.token() == Token.IN) { lexer.nextToken(); stmt.setLogName(this.exprParser.primary()); } - + if (lexer.token() == Token.FROM) { lexer.nextToken(); stmt.setFrom(this.exprParser.primary()); } - + stmt.setLimit(this.parseLimit()); - + return stmt; } @@ -1022,7 +1026,7 @@ public class MySqlStatementParser extends SQLStatementParser { return stmt; } } - + if (lexer.token() == Token.TABLE) { lexer.nextToken(); acceptIdentifier("STATUS"); @@ -1031,7 +1035,7 @@ public class MySqlStatementParser extends SQLStatementParser { lexer.nextToken(); stmt.setDatabase(this.exprParser.name()); } - + if (lexer.token() == Token.LIKE) { lexer.nextToken(); stmt.setLike(this.exprParser.expr()); @@ -1041,10 +1045,10 @@ public class MySqlStatementParser extends SQLStatementParser { lexer.nextToken(); stmt.setWhere(this.exprParser.expr()); } - + return stmt; } - + if (identifierEquals("TRIGGERS")) { lexer.nextToken(); MySqlShowTriggersStatement stmt = new MySqlShowTriggersStatement(); @@ -1091,22 +1095,22 @@ public class MySqlStatementParser extends SQLStatementParser { return stmt; } - + private MySqlShowVariantsStatement parseShowVariants() throws ParserException { MySqlShowVariantsStatement stmt = new MySqlShowVariantsStatement(); - + if (lexer.token() == Token.LIKE) { lexer.nextToken(); SQLExpr like = exprParser.expr(); stmt.setLike(like); } - + if (lexer.token() == Token.WHERE) { lexer.nextToken(); SQLExpr where = exprParser.expr(); stmt.setWhere(where); } - + return stmt; } @@ -1785,9 +1789,101 @@ public class MySqlStatementParser extends SQLStatementParser { return null; } - - public SQLSetStatement parseAlter() { + + public SQLStatement parseAlter() { accept(Token.ALTER); + + boolean ignore = false; + + if (identifierEquals("IGNORE")) { + ignore = true; + lexer.nextToken(); + } + + if (lexer.token() == Token.TABLE) { + lexer.nextToken(); + + MySqlAlterTableStatement stmt = new MySqlAlterTableStatement(); + stmt.setIgnore(ignore); + stmt.setName(this.exprParser.name()); + + for (;;) { + if (identifierEquals("ADD")) { + lexer.nextToken(); + + if (identifierEquals("COLUMN")) { + lexer.nextToken(); + MySqlAlterTableAddColumn item = new MySqlAlterTableAddColumn(); + SQLColumnDefinition columnDef = this.exprParser.parseColumn(); + item.getColumns().add(columnDef); + if (identifierEquals("AFTER")) { + lexer.nextToken(); + item.setAfter(this.exprParser.name()); + } + stmt.getItems().add(item); + } else { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } + } else if (identifierEquals("ALTER")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("CHANGE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("MODIFY")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (lexer.token() == Token.DROP) { + lexer.nextToken(); + if (identifierEquals("COLUMN")) { + lexer.nextToken(); + } + SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem(); + item.setColumnName(this.exprParser.name()); + stmt.getItems().add(item); + } else if (identifierEquals("DISABLE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("ENABLE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("RENAME")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (lexer.token() == Token.ORDER) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("CONVERT")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (lexer.token() == Token.DEFAULT) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("DISCARD")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("IMPORT")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("FORCE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("TRUNCATE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("COALESCE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + + } else if (identifierEquals("REORGANIZE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("EXCHANGE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("ANALYZE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("CHECK")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("OPTIMIZE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("REBUILD")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("REPAIR")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("REMOVE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else { + break; + } + } + + return stmt; + } throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java index d90c1600a2..2fa9f61f45 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java @@ -25,6 +25,8 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; @@ -288,132 +290,140 @@ public interface MySqlASTVisitor extends SQLASTVisitor { boolean visit(MySqlShowContributorsStatement x); void endVisit(MySqlShowContributorsStatement x); - + boolean visit(MySqlShowCreateDatabaseStatement x); - + void endVisit(MySqlShowCreateDatabaseStatement x); - + boolean visit(MySqlShowCreateEventStatement x); - + void endVisit(MySqlShowCreateEventStatement x); - + boolean visit(MySqlShowCreateFunctionStatement x); - + void endVisit(MySqlShowCreateFunctionStatement x); - + boolean visit(MySqlShowCreateProcedureStatement x); - + void endVisit(MySqlShowCreateProcedureStatement x); - + boolean visit(MySqlShowCreateTableStatement x); - + void endVisit(MySqlShowCreateTableStatement x); - + boolean visit(MySqlShowCreateTriggerStatement x); - + void endVisit(MySqlShowCreateTriggerStatement x); - + boolean visit(MySqlShowCreateViewStatement x); - + void endVisit(MySqlShowCreateViewStatement x); - + boolean visit(MySqlShowEngineStatement x); - + void endVisit(MySqlShowEngineStatement x); - + boolean visit(MySqlShowEnginesStatement x); - + void endVisit(MySqlShowEnginesStatement x); - + boolean visit(MySqlShowErrorsStatement x); - + void endVisit(MySqlShowErrorsStatement x); - + boolean visit(MySqlShowEventsStatement x); - + void endVisit(MySqlShowEventsStatement x); - + boolean visit(MySqlShowFunctionCodeStatement x); - + void endVisit(MySqlShowFunctionCodeStatement x); - + boolean visit(MySqlShowFunctionStatusStatement x); - + void endVisit(MySqlShowFunctionStatusStatement x); - + boolean visit(MySqlShowGrantsStatement x); - + void endVisit(MySqlShowGrantsStatement x); - + boolean visit(MySqlUserName x); - + void endVisit(MySqlUserName x); - + boolean visit(MySqlShowIndexesStatement x); - + void endVisit(MySqlShowIndexesStatement x); - + boolean visit(MySqlShowKeysStatement x); - + void endVisit(MySqlShowKeysStatement x); - + boolean visit(MySqlShowMasterStatusStatement x); - + void endVisit(MySqlShowMasterStatusStatement x); - + boolean visit(MySqlShowOpenTablesStatement x); - + void endVisit(MySqlShowOpenTablesStatement x); - + boolean visit(MySqlShowPluginsStatement x); - + void endVisit(MySqlShowPluginsStatement x); - + boolean visit(MySqlShowPrivilegesStatement x); - + void endVisit(MySqlShowPrivilegesStatement x); - + boolean visit(MySqlShowProcedureCodeStatement x); - + void endVisit(MySqlShowProcedureCodeStatement x); - + boolean visit(MySqlShowProcedureStatusStatement x); - + void endVisit(MySqlShowProcedureStatusStatement x); - + boolean visit(MySqlShowProcessListStatement x); - + void endVisit(MySqlShowProcessListStatement x); - + boolean visit(MySqlShowProfileStatement x); - + void endVisit(MySqlShowProfileStatement x); - + boolean visit(MySqlShowProfilesStatement x); - + void endVisit(MySqlShowProfilesStatement x); - + boolean visit(MySqlShowRelayLogEventsStatement x); - + void endVisit(MySqlShowRelayLogEventsStatement x); - + boolean visit(MySqlShowSlaveHostsStatement x); - + void endVisit(MySqlShowSlaveHostsStatement x); - + boolean visit(MySqlShowSlaveStatusStatement x); - + void endVisit(MySqlShowSlaveStatusStatement x); - + boolean visit(MySqlShowTableStatusStatement x); - + void endVisit(MySqlShowTableStatusStatement x); - + boolean visit(MySqlShowTriggersStatement x); - + void endVisit(MySqlShowTriggersStatement x); - + boolean visit(MySqlShowVariantsStatement x); - + void endVisit(MySqlShowVariantsStatement x); + + boolean visit(MySqlAlterTableStatement x); + + void endVisit(MySqlAlterTableStatement x); + + boolean visit(MySqlAlterTableAddColumn x); + + void endVisit(MySqlAlterTableAddColumn x); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java index 20fb42b45a..07868ae046 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java @@ -10,6 +10,8 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; @@ -904,4 +906,24 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements public void endVisit(MySqlShowVariantsStatement x) { } + + @Override + public boolean visit(MySqlAlterTableStatement x) { + return true; + } + + @Override + public void endVisit(MySqlAlterTableStatement x) { + + } + + @Override + public boolean visit(MySqlAlterTableAddColumn x) { + return true; + } + + @Override + public void endVisit(MySqlAlterTableAddColumn x) { + + } } 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 2593499298..896c4efdcb 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 @@ -22,7 +22,9 @@ import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLSetQuantifier; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; +import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; import com.alibaba.druid.sql.ast.statement.SQLCharactorDataType; import com.alibaba.druid.sql.ast.statement.SQLColumnConstraint; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; @@ -40,6 +42,8 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; @@ -250,8 +254,12 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV x.getDataType().accept(this); if (x.getDefaultExpr() != null) { - print(" DEFAULT "); - x.getDefaultExpr().accept(this); + if (x.getDefaultExpr() instanceof SQLNullExpr) { + print(" NULL"); + } else { + print(" DEFAULT"); + x.getDefaultExpr().accept(this); + } } if (mysqlColumn != null && mysqlColumn.isAutoIncrement()) { @@ -2155,12 +2163,50 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV x.getWhere().setParent(x); x.getWhere().accept(this); } - + return false; } @Override public void endVisit(MySqlShowVariantsStatement x) { - + + } + + @Override + public boolean visit(MySqlAlterTableStatement x) { + if (x.isIgnore()) { + print("ALTER IGNORE TABLE "); + } else { + print("ALTER TABLE "); + } + x.getName().accept(this); + incrementIndent(); + for (SQLAlterTableItem item : x.getItems()) { + println(); + item.accept(this); + } + decrementIndent(); + return false; + } + + @Override + public void endVisit(MySqlAlterTableStatement x) { + + } + + @Override + public boolean visit(MySqlAlterTableAddColumn x) { + print("ADD COLUMN "); + printAndAccept(x.getColumns(), ", "); + if (x.getAfter() != null) { + print(" AFTER "); + x.getAfter().accept(this); + } + return false; + } + + @Override + public void endVisit(MySqlAlterTableAddColumn x) { + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java index ce44fdede5..58753acd28 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java @@ -19,6 +19,8 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; @@ -967,4 +969,24 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS public void endVisit(MySqlShowVariantsStatement x) { } + + @Override + public boolean visit(MySqlAlterTableStatement x) { + return false; + } + + @Override + public void endVisit(MySqlAlterTableStatement x) { + + } + + @Override + public boolean visit(MySqlAlterTableAddColumn x) { + return false; + } + + @Override + public void endVisit(MySqlAlterTableAddColumn x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 6933ac8f53..e601b9996d 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1163,6 +1163,12 @@ public class SQLExprParser extends SQLParser { column.getConstaints().add(new NotNullConstraint()); return parseColumnRest(column); } + + if (lexer.token() == Token.NULL) { + lexer.nextToken(); + column.setDefaultExpr(new SQLNullExpr()); + return parseColumnRest(column); + } return column; } 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 2955108ffd..ee43707757 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -164,7 +164,7 @@ public class SQLStatementParser extends SQLParser { return stmt; } - public SQLSetStatement parseAlter() { + public SQLStatement parseAlter() { accept(Token.ALTER); throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index 2571a3c00f..807f221c70 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -69,6 +69,7 @@ import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; @@ -1013,6 +1014,13 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { print(")"); return false; } + + @Override + public boolean visit(SQLAlterTableDropColumnItem x) { + print("DROP COLUMN "); + x.getColumnName().accept(this); + return false; + } @Override public void endVisit(SQLAlterTableAddColumn x) { diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java index 54cd4b89db..7e14b14f29 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java @@ -52,6 +52,7 @@ import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.ast.statement.NotNullConstraint; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLCallStatement; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; @@ -340,4 +341,8 @@ public interface SQLASTVisitor { boolean visit(SQLAlterTableAddColumn x); void endVisit(SQLAlterTableAddColumn x); + + boolean visit(SQLAlterTableDropColumnItem x); + + void endVisit(SQLAlterTableDropColumnItem x); } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java index 8d9a6de033..0e1ff28120 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java @@ -51,6 +51,7 @@ import com.alibaba.druid.sql.ast.expr.SQLSomeExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.ast.statement.NotNullConstraint; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLCallStatement; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; @@ -595,4 +596,14 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor { public void endVisit(SQLAlterTableAddColumn x) { } + + @Override + public boolean visit(SQLAlterTableDropColumnItem x) { + return true; + } + + @Override + public void endVisit(SQLAlterTableDropColumnItem x) { + + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DDLParserTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DDLParserTest.java index 5836f3aed4..4a0c11b020 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DDLParserTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DDLParserTest.java @@ -25,7 +25,7 @@ public class DDLParserTest extends TestCase { String output = SQLUtils.toMySqlString(stmt); Assert.assertEquals("TRUNCATE TABLE tb1", output); } - + public void testTruncate_1() throws Exception { String sql = "Truncate tb1"; MySqlStatementParser parser = new MySqlStatementParser(sql); @@ -34,116 +34,145 @@ public class DDLParserTest extends TestCase { String output = SQLUtils.toMySqlString(stmt); Assert.assertEquals("TRUNCATE TABLE tb1", output); } - - public void testAlterTable0() throws Exception { + + public void testAlterTable_0() throws Exception { String sql = "alTer ignore table tb_name"; MySqlStatementParser parser = new MySqlStatementParser(sql); SQLStatement stmt = parser.parseStatementList().get(0); parser.match(Token.EOF); String output = SQLUtils.toMySqlString(stmt); - Assert.assertEquals("ALTER ignore table tb_name", output); + Assert.assertEquals("ALTER IGNORE TABLE tb_name", output); } -// public void testDDLStmt() throws Exception { -// String sql = "alTer ignore table tb_name"; -// SQLLexer lexer = new SQLLexer(sql); -// DDLParser parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// DDLStatement dst = parser.ddlStmt(); -// -// sql = "alTeR table tb_name"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// -// sql = "crEate temporary tabLe if not exists tb_name"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// -// sql = "crEate tabLe if not exists tb_name"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// -// sql = "crEate temporary tabLe tb_name"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// -// sql = "crEate unique index index_name on tb(col(id)) desc"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// -// sql = "crEate fulltext index index_name on tb(col(id))"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// -// sql = "crEate spatial index index_name on tb(col(id))"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// -// sql = "crEate index index_name using hash on tb(col(id))"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// -// sql = "drop index index_name on tb1"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// String output = output2MySQL(dst, sql); -// Assert.assertEquals("DROP INDEX index_name ON tb1", output); -// -// sql = "drop temporary tabLe if exists tb1,tb2,tb3 restrict"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// output = output2MySQL(dst, sql); -// Assert.assertEquals("DROP TEMPORARY TABLE IF EXISTS tb1, tb2, tb3 RESTRICT", output); -// -// sql = "drop temporary tabLe if exists tb1,tb2,tb3 cascade"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// output = output2MySQL(dst, sql); -// Assert.assertEquals("DROP TEMPORARY TABLE IF EXISTS tb1, tb2, tb3 CASCADE", output); -// -// sql = "drop temporary tabLe if exists tb1 cascade"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// output = output2MySQL(dst, sql); -// Assert.assertEquals("DROP TEMPORARY TABLE IF EXISTS tb1 CASCADE", output); -// -// sql = "drop tabLe if exists tb1 cascade"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// output = output2MySQL(dst, sql); -// Assert.assertEquals("DROP TABLE IF EXISTS tb1 CASCADE", output); -// -// sql = "drop temporary tabLe tb1 cascade"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// output = output2MySQL(dst, sql); -// Assert.assertEquals("DROP TEMPORARY TABLE tb1 CASCADE", output); -// -// sql = "rename table tb1 to ntb1,tb2 to ntb2"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// output = output2MySQL(dst, sql); -// Assert.assertEquals("RENAME TABLE tb1 TO ntb1, tb2 TO ntb2", output); -// -// sql = "rename table tb1 to ntb1"; -// lexer = new SQLLexer(sql); -// parser = new DDLParser(lexer, new SQLExprParser(lexer)); -// dst = parser.ddlStmt(); -// output = output2MySQL(dst, sql); -// Assert.assertEquals("RENAME TABLE tb1 TO ntb1", output); -// } + public void testAlterTable_1() throws Exception { + String sql = "alTer table tb_name"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("ALTER TABLE tb_name", output); + } + + public void testAlterTable_2() throws Exception { + String sql = "ALTER TABLE `test`.`tb1` ADD COLUMN `name` VARCHAR(45) NULL AFTER `fid` ;"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("ALTER TABLE `test`.`tb1`" + // + "\n\tADD COLUMN `name` VARCHAR(45) NULL AFTER `fid`", output); + } + + public void testAlterTable_3() throws Exception { + String sql = "ALTER TABLE `test`.`tb1` DROP COLUMN `name` ;"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("ALTER TABLE `test`.`tb1`" + // + "\n\tDROP COLUMN `name`", output); + } + + // public void testDDLStmt() throws Exception { + // String sql = "alTer ignore table tb_name"; + // SQLLexer lexer = new SQLLexer(sql); + // DDLParser parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // DDLStatement dst = parser.ddlStmt(); + // + // sql = "alTeR table tb_name"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // + // sql = "crEate temporary tabLe if not exists tb_name"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // + // sql = "crEate tabLe if not exists tb_name"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // + // sql = "crEate temporary tabLe tb_name"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // + // sql = "crEate unique index index_name on tb(col(id)) desc"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // + // sql = "crEate fulltext index index_name on tb(col(id))"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // + // sql = "crEate spatial index index_name on tb(col(id))"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // + // sql = "crEate index index_name using hash on tb(col(id))"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // + // sql = "drop index index_name on tb1"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // String output = output2MySQL(dst, sql); + // Assert.assertEquals("DROP INDEX index_name ON tb1", output); + // + // sql = "drop temporary tabLe if exists tb1,tb2,tb3 restrict"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // output = output2MySQL(dst, sql); + // Assert.assertEquals("DROP TEMPORARY TABLE IF EXISTS tb1, tb2, tb3 RESTRICT", output); + // + // sql = "drop temporary tabLe if exists tb1,tb2,tb3 cascade"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // output = output2MySQL(dst, sql); + // Assert.assertEquals("DROP TEMPORARY TABLE IF EXISTS tb1, tb2, tb3 CASCADE", output); + // + // sql = "drop temporary tabLe if exists tb1 cascade"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // output = output2MySQL(dst, sql); + // Assert.assertEquals("DROP TEMPORARY TABLE IF EXISTS tb1 CASCADE", output); + // + // sql = "drop tabLe if exists tb1 cascade"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // output = output2MySQL(dst, sql); + // Assert.assertEquals("DROP TABLE IF EXISTS tb1 CASCADE", output); + // + // sql = "drop temporary tabLe tb1 cascade"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // output = output2MySQL(dst, sql); + // Assert.assertEquals("DROP TEMPORARY TABLE tb1 CASCADE", output); + // + // sql = "rename table tb1 to ntb1,tb2 to ntb2"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // output = output2MySQL(dst, sql); + // Assert.assertEquals("RENAME TABLE tb1 TO ntb1, tb2 TO ntb2", output); + // + // sql = "rename table tb1 to ntb1"; + // lexer = new SQLLexer(sql); + // parser = new DDLParser(lexer, new SQLExprParser(lexer)); + // dst = parser.ddlStmt(); + // output = output2MySQL(dst, sql); + // Assert.assertEquals("RENAME TABLE tb1 TO ntb1", output); + // } }