From f43f6aaf2e7c0118c7c3daf82bc500436cb57eae Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 7 Apr 2013 23:13:12 +0800 Subject: [PATCH] sql parser support alter table add foreign key --- .../statement/SQLAlterTableAddForeignKey.java | 50 +++++++++++++++++ .../mysql/parser/MySqlCreateTableParser.java | 18 +------ .../dialect/mysql/parser/MySqlExprParser.java | 21 ++++++++ .../mysql/parser/MySqlStatementParser.java | 12 +++++ .../mysql/visitor/MySqlOutputVisitor.java | 16 +++--- .../sql/visitor/SQLASTOutputVisitor.java | 8 +++ .../druid/sql/visitor/SQLASTVisitor.java | 5 ++ .../sql/visitor/SQLASTVisitorAdapter.java | 11 ++++ .../bvt/sql/mysql/MySqlAlterTableTest8.java | 4 +- .../sql/mysql/MySqlAlterTableTest_addFk.java | 53 +++++++++++++++++++ 10 files changed, 170 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableAddForeignKey.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest_addFk.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableAddForeignKey.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableAddForeignKey.java new file mode 100644 index 0000000000..ce3c438c94 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableAddForeignKey.java @@ -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.sql.ast.statement; + +import com.alibaba.druid.sql.ast.SQLObjectImpl; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class SQLAlterTableAddForeignKey extends SQLObjectImpl implements SQLAlterTableItem { + + private static final long serialVersionUID = 1L; + private SQLForeignKeyConstraint foreignKey; + + public SQLAlterTableAddForeignKey() { + + } + + public SQLAlterTableAddForeignKey(SQLForeignKeyConstraint foreignKey) { + this.foreignKey = foreignKey; + } + + public SQLForeignKeyConstraint getForeignKey() { + return foreignKey; + } + + public void setForeignKey(SQLForeignKeyConstraint foreignKey) { + this.foreignKey = foreignKey; + } + + @Override + protected void accept0(SQLASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, foreignKey); + } + visitor.endVisit(this); + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java index 8a065445fb..ae86884da1 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java @@ -118,23 +118,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } else if (lexer.token() == (Token.PRIMARY)) { stmt.getTableElementList().add(parseConstraint()); } else if (lexer.token() == (Token.FOREIGN)) { - lexer.nextToken(); - accept(Token.KEY); - - MySqlForeignKey fk = new MySqlForeignKey(); - - accept(Token.LPAREN); - this.exprParser.names(fk.getReferencingColumns()); - accept(Token.RPAREN); - - accept(Token.REFERENCES); - - fk.setReferencedTableName(this.exprParser.name()); - - accept(Token.LPAREN); - this.exprParser.names(fk.getReferencedColumns()); - accept(Token.RPAREN); - + MySqlForeignKey fk = this.getExprParser().parseForeignKey(); stmt.getTableElementList().add(fk); } else if (lexer.token() == Token.CHECK) { lexer.nextToken(); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java index 43c2c9813d..ca7d89cb05 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java @@ -30,6 +30,7 @@ import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForeignKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlBinaryExpr; @@ -692,4 +693,24 @@ public class MySqlExprParser extends SQLExprParser { return primaryKey; } + + public MySqlForeignKey parseForeignKey() { + accept(Token.FOREIGN); + accept(Token.KEY); + + MySqlForeignKey fk = new MySqlForeignKey(); + + accept(Token.LPAREN); + this.names(fk.getReferencingColumns()); + accept(Token.RPAREN); + + accept(Token.REFERENCES); + + fk.setReferencedTableName(this.name()); + + accept(Token.LPAREN); + this.names(fk.getReferencedColumns()); + accept(Token.RPAREN); + return fk; + } } 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 9a53f962e1..ad87bf6853 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 @@ -29,6 +29,7 @@ import com.alibaba.druid.sql.ast.expr.SQLListExpr; 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.SQLAlterTableAddForeignKey; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddPrimaryKey; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAlterColumn; import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableKeys; @@ -52,6 +53,7 @@ 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.MySqlForeignKey; 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.MySqlAlterTableAddIndex; @@ -2256,6 +2258,12 @@ public class MySqlStatementParser extends SQLStatementParser { SQLAlterTableAddPrimaryKey item = new SQLAlterTableAddPrimaryKey(); item.setPrimaryKey(primaryKey); stmt.getItems().add(item); + } else if (lexer.token() == Token.FOREIGN) { + MySqlForeignKey fk = this.getExprParser().parseForeignKey(); + fk.setName(constraintName); + + SQLAlterTableAddForeignKey item = new SQLAlterTableAddForeignKey(fk); + stmt.getItems().add(item); } else { throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } @@ -2538,4 +2546,8 @@ public class MySqlStatementParser extends SQLStatementParser { lexer.nextToken(); } } + + public MySqlExprParser getExprParser() { + return (MySqlExprParser) exprParser; + } } 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 fd70b69674..a9331d3ff6 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 @@ -2766,21 +2766,13 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlForeignKey x) { - // TODO Auto-generated method stub - return false; - } - - @Override - public void endVisit(MySqlForeignKey x) { if (x.getName() != null) { print("CONSTRAINT "); x.getName().accept(this); print(' '); } - print("FOREIGN KEY "); - - print(" ("); + print("FOREIGN KEY ("); printAndAccept(x.getReferencedColumns(), ", "); print(")"); @@ -2790,6 +2782,12 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV print(" ("); printAndAccept(x.getReferencedColumns(), ", "); print(")"); + return false; + } + + @Override + public void endVisit(MySqlForeignKey x) { + } @Override 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 d82c9c3a89..64ff6967f6 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -66,6 +66,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.SQLAlterTableAddForeignKey; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddPrimaryKey; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAlterColumn; import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableKeys; @@ -1415,4 +1416,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { print("DISABLE KEYS"); return false; } + + @Override + public boolean visit(SQLAlterTableAddForeignKey x) { + print("ADD "); + x.getForeignKey().accept(this); + return false; + } } 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 f1cefe8b41..2c45501a97 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java @@ -54,6 +54,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.SQLAlterTableAddForeignKey; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddPrimaryKey; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAlterColumn; import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableKeys; @@ -454,4 +455,8 @@ public interface SQLASTVisitor { boolean visit(SQLAlterTableStatement x); void endVisit(SQLAlterTableStatement x); + + boolean visit(SQLAlterTableAddForeignKey x); + + void endVisit(SQLAlterTableAddForeignKey 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 afe0b2ad3b..7c0bdbccf9 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java @@ -54,6 +54,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.SQLAlterTableAddForeignKey; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddPrimaryKey; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAlterColumn; import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableKeys; @@ -842,4 +843,14 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor { public void endVisit(SQLAlterTableStatement x) { } + + @Override + public boolean visit(SQLAlterTableAddForeignKey x) { + return true; + } + + @Override + public void endVisit(SQLAlterTableAddForeignKey x) { + + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest8.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest8.java index bc879c3c51..d5cd590161 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest8.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest8.java @@ -15,15 +15,15 @@ */ package com.alibaba.druid.bvt.sql.mysql; -import junit.framework.Assert; 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.dialect.mysql.visitor.MySqlSchemaStatVisitor; import com.alibaba.druid.sql.parser.Token; -import com.alibaba.druid.stat.TableStat.Column; public class MySqlAlterTableTest8 extends TestCase { diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest_addFk.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest_addFk.java new file mode 100644 index 0000000000..306de56e6a --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest_addFk.java @@ -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 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.dialect.mysql.visitor.MySqlSchemaStatVisitor; +import com.alibaba.druid.sql.parser.Token; + +public class MySqlAlterTableTest_addFk extends TestCase { + + public void test_alter_first() throws Exception { + String sql = "alter table Test2 add index FK4CF5DC0F5DD7C31 (test1_name), " + // + "add constraint FK4CF5DC0F5DD7C31 foreign key (test1_name) references Test1 (name)"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("ALTER TABLE Test2" + // + "\n\tADD INDEX FK4CF5DC0F5DD7C31 (test1_name)," + // + "\n\tADD CONSTRAINT FK4CF5DC0F5DD7C31 FOREIGN KEY (name) REFERENCES Test1 (name)", output); + + Assert.assertEquals(1, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + } +}