diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateIndexStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateIndexStatement.java new file mode 100644 index 0000000000..56e4ba40f4 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateIndexStatement.java @@ -0,0 +1,56 @@ +package com.alibaba.druid.sql.ast.statement; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLStatementImpl; + +public class SQLCreateIndexStatement extends SQLStatementImpl implements SQLDDLStatement { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private SQLName name; + + private SQLName table; + + private List items = new ArrayList(); + + private String type; + + public SQLName getTable() { + return table; + } + + public void setTable(SQLName table) { + this.table = table; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public SQLName getName() { + return name; + } + + public void setName(SQLName name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateIndexStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateIndexStatement.java new file mode 100644 index 0000000000..f8e2610edf --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateIndexStatement.java @@ -0,0 +1,37 @@ +package com.alibaba.druid.sql.dialect.mysql.ast.statement; + +import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class MySqlCreateIndexStatement extends SQLCreateIndexStatement implements MySqlStatement { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private String using; + + public String getUsing() { + return using; + } + + public void setUsing(String using) { + this.using = using; + } + + protected void accept0(SQLASTVisitor visitor) { + accept0((MySqlASTVisitor) visitor); + } + + @Override + public void accept0(MySqlASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, getName()); + acceptChild(visitor, getTable()); + acceptChild(visitor, getItems()); + } + 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 086086e862..1b8030f34f 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 @@ -31,6 +31,7 @@ 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; +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; @@ -41,6 +42,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColum 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.MySqlCreateIndexStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDescribeStatement; @@ -212,6 +214,10 @@ public class MySqlStatementParser extends SQLStatementParser { MySqlCreateTableParser parser = new MySqlCreateTableParser(lexer); return parser.parseCrateTable(false); } + + if (lexer.token() == Token.UNIQUE || lexer.token() == Token.INDEX || identifierEquals("FULLTEXT") || identifierEquals("SPATIAL")) { + return parseCreateIndex(); + } if (identifierEquals("USER")) { return parseCreateUser(); @@ -219,8 +225,64 @@ public class MySqlStatementParser extends SQLStatementParser { throw new ParserException("TODO " + lexer.token()); } + + public SQLStatement parseCreateIndex() throws ParserException { + MySqlCreateIndexStatement stmt = new MySqlCreateIndexStatement(); + + if (lexer.token() == Token.UNIQUE) { + stmt.setType("UNIQUE"); + lexer.nextToken(); + } else if (identifierEquals("FULLTEXT")) { + stmt.setType("FULLTEXT"); + lexer.nextToken(); + } else if (identifierEquals("SPATIAL")) { + stmt.setType("SPATIAL"); + lexer.nextToken(); + } + + accept(Token.INDEX); + + stmt.setName(this.exprParser.name()); + + if (identifierEquals("USING")) { + lexer.nextToken(); + + if (identifierEquals("BTREE")) { + stmt.setType("BTREE"); + lexer.nextToken(); + } else if (identifierEquals("HASH")) { + stmt.setType("HASH"); + lexer.nextToken(); + } else { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } + } + + accept(Token.ON); + + stmt.setTable(this.exprParser.name()); + + accept(Token.LPAREN); + + for (;;) { + SQLSelectOrderByItem item = this.exprParser.parseSelectOrderByItem(); + stmt.getItems().add(item); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + accept(Token.RPAREN); + + return stmt; + } public SQLStatement parseCreateUser() throws ParserException { + if (lexer.token() == Token.CREATE) { + lexer.nextToken(); + } + acceptIdentifier("USER"); MySqlCreateUserStatement stmt = new MySqlCreateUserStatement(); 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 2fa9f61f45..0082a32886 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 @@ -29,6 +29,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColum 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.MySqlCreateIndexStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDescribeStatement; @@ -426,4 +427,8 @@ public interface MySqlASTVisitor extends SQLASTVisitor { boolean visit(MySqlAlterTableAddColumn x); void endVisit(MySqlAlterTableAddColumn x); + + boolean visit(MySqlCreateIndexStatement x); + + void endVisit(MySqlCreateIndexStatement 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 07868ae046..ec5491f906 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 @@ -14,6 +14,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColum 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.MySqlCreateIndexStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement.UserSpecification; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; @@ -926,4 +927,14 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements public void endVisit(MySqlAlterTableAddColumn x) { } + + @Override + public boolean visit(MySqlCreateIndexStatement x) { + return true; + } + + @Override + public void endVisit(MySqlCreateIndexStatement 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 c45919cdbd..9fd0ffea6f 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 @@ -46,6 +46,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColum 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.MySqlCreateIndexStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement.UserSpecification; @@ -2210,4 +2211,34 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } + @Override + public boolean visit(MySqlCreateIndexStatement x) { + print("CREATE "); + if (x.getType() != null) { + print(x.getType()); + print(" "); + } + + print("INDEX "); + + if (x.getUsing() != null) { + print("USING "); + print(x.getUsing()); + print(' '); + } + + x.getName().accept(this); + print(" ON "); + x.getTable().accept(this); + print(" ("); + printAndAccept(x.getItems(), ", "); + print(")"); + return false; + } + + @Override + public void endVisit(MySqlCreateIndexStatement 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 58753acd28..28141a1d7a 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 @@ -23,6 +23,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColum 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.MySqlCreateIndexStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement.UserSpecification; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; @@ -989,4 +990,14 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS public void endVisit(MySqlAlterTableAddColumn x) { } + + @Override + public boolean visit(MySqlCreateIndexStatement x) { + return false; + } + + @Override + public void endVisit(MySqlCreateIndexStatement x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleCreateIndexStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleCreateIndexStatement.java index ea6e1a6233..9f71a16b4d 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleCreateIndexStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleCreateIndexStatement.java @@ -1,34 +1,32 @@ package com.alibaba.druid.sql.dialect.oracle.ast.stmt; -import java.util.ArrayList; -import java.util.List; - import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; -import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; +import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class OracleCreateIndexStatement extends OracleStatementImpl { +public class OracleCreateIndexStatement extends SQLCreateIndexStatement implements OracleDDLStatement { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private SQLName name; + private boolean online = false; - private SQLName table; + private boolean indexOnlyTopLevel = false; - private List items = new ArrayList(); + private boolean noParallel; - private SQLName tablespace; + private SQLExpr parallel; - private Type type; + private SQLName tablespace; - private boolean online = false; + public SQLName getTablespace() { + return tablespace; + } - private boolean indexOnlyTopLevel = false; - - private boolean noParallel; - - private SQLExpr parallel; + public void setTablespace(SQLName tablespace) { + this.tablespace = tablespace; + } public SQLExpr getParallel() { return parallel; @@ -46,14 +44,6 @@ public class OracleCreateIndexStatement extends OracleStatementImpl { this.noParallel = noParallel; } - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } - public boolean isIndexOnlyTopLevel() { return indexOnlyTopLevel; } @@ -62,53 +52,25 @@ public class OracleCreateIndexStatement extends OracleStatementImpl { this.indexOnlyTopLevel = indexOnlyTopLevel; } + protected void accept0(SQLASTVisitor visitor) { + accept0((OracleASTVisitor) visitor); + } + @Override public void accept0(OracleASTVisitor visitor) { if (visitor.visit(this)) { - acceptChild(visitor, name); - acceptChild(visitor, table); - acceptChild(visitor, items); - acceptChild(visitor, tablespace); + acceptChild(visitor, getName()); + acceptChild(visitor, getTable()); + acceptChild(visitor, getItems()); + acceptChild(visitor, getTablespace()); acceptChild(visitor, parallel); } visitor.endVisit(this); } - public static enum Type { - UNIQUE, BITMAP - } - - public SQLName getName() { - return name; - } - - public void setName(SQLName name) { - this.name = name; - } - - public SQLName getTable() { - return table; - } - - public void setTable(SQLName table) { - this.table = table; - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } - - public SQLName getTablespace() { - return tablespace; - } - - public void setTablespace(SQLName tablespace) { - this.tablespace = tablespace; - } + // public static enum Type { + // UNIQUE, BITMAP + // } public boolean isOnline() { return online; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java index b4b089fc11..fbc63e2522 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java @@ -1483,10 +1483,10 @@ public class OracleStatementParser extends SQLStatementParser { OracleCreateIndexStatement stmt = new OracleCreateIndexStatement(); if (lexer.token() == Token.UNIQUE) { - stmt.setType(OracleCreateIndexStatement.Type.UNIQUE); + stmt.setType("UNIQUE"); lexer.nextToken(); } else if (identifierEquals("BITMAP")) { - stmt.setType(OracleCreateIndexStatement.Type.BITMAP); + stmt.setType("BITMAP"); lexer.nextToken(); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java index 376e0dc6ac..5a915762c6 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java @@ -16,7 +16,6 @@ package com.alibaba.druid.sql.dialect.oracle.visitor; import com.alibaba.druid.sql.ast.expr.SQLObjectCreateExpr; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint; import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy; import com.alibaba.druid.sql.dialect.oracle.ast.clause.CycleClause; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java index 559747344b..4aff9453ec 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java @@ -2180,11 +2180,13 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS @Override public boolean visit(OracleCreateIndexStatement x) { - print("CREATE INDEX "); + print("CREATE "); if (x.getType() != null) { - print(x.getType().name()); + print(x.getType()); print(" "); } + + print("INDEX "); x.getName().accept(this); print(" ON "); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java index 3597b27c12..5275185ddf 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java @@ -11,7 +11,6 @@ import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLObjectCreateExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; 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 2389e4de65..bfba0f7248 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 @@ -81,6 +81,24 @@ public class DDLParserTest extends TestCase { String output = SQLUtils.toMySqlString(stmt); Assert.assertEquals("CREATE TEMPORARY TABLE IF NOT EXISTS tb_name (\n\tfid int\n)", output); } + + public void test_createTable_1() throws Exception { + String sql = "crEate tabLe if not exists tb_name (fid int)"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("CREATE TABLE IF NOT EXISTS tb_name (\n\tfid int\n)", output); + } + + public void test_createIndex_0() throws Exception { + String sql = "create index `idx1` ON tb1 (`fname` ASC) ;"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("CREATE INDEX `idx1` ON tb1 (`fname` ASC)", output); + } // public void testDDLStmt() throws Exception { // String sql = "alTer ignore table tb_name";