diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLPartitioningClause.java b/src/main/java/com/alibaba/druid/sql/ast/SQLPartitioningClause.java index 0af62e02fd..f18848bf57 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLPartitioningClause.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLPartitioningClause.java @@ -1,8 +1,7 @@ package com.alibaba.druid.sql.ast; -import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObject; -public interface SQLPartitioningClause extends OracleSQLObject { +public interface SQLPartitioningClause extends SQLObject { } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java index 3d431b5485..487f1ebc68 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java @@ -18,22 +18,33 @@ package com.alibaba.druid.sql.dialect.mysql.ast.statement; import java.util.HashMap; import java.util.Map; +import com.alibaba.druid.sql.ast.SQLPartitioningClause; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLSelect; @SuppressWarnings("serial") public class MySqlCreateTableStatement extends SQLCreateTableStatement { - private boolean ifNotExiists = false; + private boolean ifNotExiists = false; - private Map tableOptions = new HashMap(); + private Map tableOptions = new HashMap(); - protected SQLSelect query; + protected SQLSelect query; + + private SQLPartitioningClause partitioning; public MySqlCreateTableStatement(){ } + public SQLPartitioningClause getPartitioning() { + return partitioning; + } + + public void setPartitioning(SQLPartitioningClause partitioning) { + this.partitioning = partitioning; + } + public Map getTableOptions() { return tableOptions; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlPartitionByKey.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlPartitionByKey.java new file mode 100644 index 0000000000..b223bd4493 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlPartitionByKey.java @@ -0,0 +1,45 @@ +package com.alibaba.druid.sql.dialect.mysql.ast.statement; + +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.SQLPartitioningClause; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObjectImpl; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; + +public class MySqlPartitionByKey extends MySqlObjectImpl implements SQLPartitioningClause { + + private static final long serialVersionUID = 1L; + + private List columns = new ArrayList(); + + private SQLExpr partitionCount; + + @Override + public void accept0(MySqlASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, columns); + acceptChild(visitor, partitionCount); + } + visitor.endVisit(this); + } + + public SQLExpr getPartitionCount() { + return partitionCount; + } + + public void setPartitionCount(SQLExpr partitionCount) { + this.partitionCount = partitionCount; + } + + public List getColumns() { + return columns; + } + + public void setColumns(List columns) { + this.columns = columns; + } + +} 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 2a662b680c..40f2d53d87 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 @@ -23,6 +23,7 @@ import com.alibaba.druid.sql.ast.statement.SQLTableConstaint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlTableIndex; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; @@ -49,11 +50,11 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { if (acceptCreate) { accept(Token.CREATE); } - MySqlCreateTableStatement createTable = new MySqlCreateTableStatement(); + MySqlCreateTableStatement stmt = new MySqlCreateTableStatement(); if (identifierEquals("TEMPORARY")) { lexer.nextToken(); - createTable.setType(SQLCreateTableStatement.Type.GLOBAL_TEMPORARY); + stmt.setType(SQLCreateTableStatement.Type.GLOBAL_TEMPORARY); } accept(Token.TABLE); @@ -63,10 +64,10 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { accept(Token.NOT); accept(Token.EXISTS); - createTable.setIfNotExiists(true); + stmt.setIfNotExiists(true); } - createTable.setName(this.exprParser.name()); + stmt.setName(this.exprParser.name()); if (lexer.token() == (Token.LPAREN)) { lexer.nextToken(); @@ -74,9 +75,9 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { for (;;) { if (lexer.token() == Token.IDENTIFIER) { SQLColumnDefinition column = this.exprParser.parseColumn(); - createTable.getTableElementList().add(column); + stmt.getTableElementList().add(column); } else if (lexer.token() == (Token.CONSTRAINT)) { - createTable.getTableElementList().add(parseConstraint()); + stmt.getTableElementList().add(parseConstraint()); } else if (lexer.token() == (Token.INDEX)) { lexer.nextToken(); @@ -105,11 +106,11 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } accept(Token.RPAREN); - createTable.getTableElementList().add(idx); + stmt.getTableElementList().add(idx); } else if (lexer.token() == (Token.KEY)) { - createTable.getTableElementList().add(parseConstraint()); + stmt.getTableElementList().add(parseConstraint()); } else if (lexer.token() == (Token.PRIMARY)) { - createTable.getTableElementList().add(parseConstraint()); + stmt.getTableElementList().add(parseConstraint()); } if (!(lexer.token() == (Token.COMMA))) { @@ -126,7 +127,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { if (identifierEquals("ENGINE")) { lexer.nextToken(); accept(Token.EQ); - createTable.getTableOptions().put("ENGINE", lexer.stringVal()); + stmt.getTableOptions().put("ENGINE", lexer.stringVal()); lexer.nextToken(); continue; } @@ -134,11 +135,39 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { if (identifierEquals("TYPE")) { lexer.nextToken(); accept(Token.EQ); - createTable.getTableOptions().put("TYPE", lexer.stringVal()); + stmt.getTableOptions().put("TYPE", lexer.stringVal()); lexer.nextToken(); continue; } + if (identifierEquals("PARTITION")) { + lexer.nextToken(); + accept(Token.BY); + + if (lexer.token() == Token.KEY) { + MySqlPartitionByKey clause = new MySqlPartitionByKey(); + lexer.nextToken(); + accept(Token.LPAREN); + for (;;) { + clause.getColumns().add(this.exprParser.name()); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + accept(Token.RPAREN); + stmt.setPartitioning(clause); + + if (identifierEquals("PARTITIONS")) { + lexer.nextToken(); + clause.setPartitionCount(this.exprParser.expr()); + } + } else { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } + } + break; } @@ -148,10 +177,10 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { if (lexer.token() == (Token.SELECT)) { SQLSelect query = new MySqlSelectParser(this.lexer).select(); - createTable.setQuery(query); + stmt.setQuery(query); } - return createTable; + return stmt; } @SuppressWarnings("unused") 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 24ddd9b367..eafd822812 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 @@ -439,7 +439,10 @@ public class MySqlExprParser extends SQLExprParser { } return parseColumnRest(column); } - + + if (identifierEquals("PARTITION")) { + throw new ParserException("syntax error " + lexer.token() + " " + lexer.stringVal()); + } super.parseColumnRest(column); return column; 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 5ceafd41eb..12e382ca59 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 @@ -34,6 +34,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadDataInFileStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadXmlStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplicateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement; @@ -182,4 +183,8 @@ public interface MySqlASTVisitor extends SQLASTVisitor { void endVisit(MySqlDropTableStatement x); boolean visit(MySqlDropTableStatement x); + + void endVisit(MySqlPartitionByKey x); + + boolean visit(MySqlPartitionByKey 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 8ff08a901d..87cd27f764 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 @@ -20,6 +20,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadDataInFileStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadXmlStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplicateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement; @@ -389,4 +390,14 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements return true; } + @Override + public void endVisit(MySqlPartitionByKey x) { + + } + + @Override + public boolean visit(MySqlPartitionByKey x) { + return true; + } + } 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 c76540d658..3395ff53c9 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 @@ -49,6 +49,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadDataInFileStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadXmlStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplicateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement; @@ -1324,4 +1325,22 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV printAndAccept(x.getTableNames(), ", "); return false; } + + @Override + public void endVisit(MySqlPartitionByKey x) { + + } + + @Override + public boolean visit(MySqlPartitionByKey x) { + print("PARTITION BY KEY ("); + printAndAccept(x.getColumns(), ", "); + print(")"); + + if (x.getPartitionCount() != null) { + print(" PARTITIONS "); + x.getPartitionCount().accept(this); + } + return false; + } } 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 fb366ad4f3..4e4f72c3f3 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 @@ -26,6 +26,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadDataInFileStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadXmlStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplicateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement; @@ -443,4 +444,13 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS public boolean visit(MySqlDropTableStatement x) { return visit((SQLDropTableStatement) x); } + @Override + public void endVisit(MySqlPartitionByKey x) { + + } + @Override + public boolean visit(MySqlPartitionByKey x) { + accept(x.getColumns()); + return false; + } } 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 7f98ef2ced..2808049a00 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 @@ -149,6 +149,8 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle public OracleSchemaStatVisitor(){ this.variants.put("DUAL", null); this.variants.put("NOTFOUND", null); + this.variants.put("TRUE", null); + this.variants.put("FALSE", null); } protected Column getColumn(SQLExpr expr) { 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 121a27aab3..7f67fa595b 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -217,6 +217,7 @@ public class SQLExprParser extends SQLParser { case SCHEMA: case AT: case COLUMN: + case IF: sqlExpr = new SQLIdentifierExpr(lexer.stringVal()); lexer.nextToken(); break; @@ -1090,10 +1091,6 @@ public class SQLExprParser extends SQLParser { SQLCharactorDataType charType = new SQLCharactorDataType(dataType.getName()); charType.getArguments().addAll(dataType.getArguments()); - if (lexer.token() != Token.IDENTIFIER) { - throw new ParserException("syntax error " + lexer.token() + " " + lexer.stringVal()); - } - if (identifierEquals("CHARACTER")) { lexer.nextToken(); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java index fa6c5507f1..12c46ff580 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -14,6 +14,7 @@ import com.alibaba.druid.sql.ast.SQLOrderBy; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLCurrentOfCursorExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLInListExpr; import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr; @@ -867,4 +868,8 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { public boolean visit(SQLCommentStatement x) { return false; } + + public boolean visit(SQLCurrentOfCursorExpr x) { + return false; + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest3.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest3.java index d23d6e7b1e..4cc93fe77e 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest3.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest3.java @@ -32,11 +32,13 @@ public class MySqlCreateTableTest3 extends MysqlTest { System.out.println("orderBy : " + visitor.getOrderByColumns()); Assert.assertEquals(1, visitor.getTables().size()); - Assert.assertEquals(1, visitor.getColumns().size()); + Assert.assertEquals(3, visitor.getColumns().size()); Assert.assertEquals(0, visitor.getConditions().size()); - Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("test"))); + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("tk"))); - Assert.assertTrue(visitor.getColumns().contains(new Column("test", "blob_col"))); + Assert.assertTrue(visitor.getColumns().contains(new Column("tk", "col1"))); + Assert.assertTrue(visitor.getColumns().contains(new Column("tk", "col2"))); + Assert.assertTrue(visitor.getColumns().contains(new Column("tk", "col3"))); } }