From 8f63d503012b437c7510d828de75b2d53c5459ba Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 1 Apr 2018 19:55:24 +0800 Subject: [PATCH] sql parser support drds ddl, for issue #2433 --- .../druid/sql/ast/SQLPartitionByHash.java | 16 ++ .../statement/SQLCreateTableStatement.java | 1 + .../dialect/db2/visitor/DB2OutputVisitor.java | 1 + .../statement/MySqlCreateTableStatement.java | 47 +++- .../mysql/parser/MySqlCreateTableParser.java | 255 ++++++++++-------- .../mysql/visitor/MySqlOutputVisitor.java | 30 ++- .../oracle/visitor/OracleOutputVisitor.java | 7 +- .../postgresql/visitor/PGOutputVisitor.java | 6 +- .../druid/sql/parser/SQLParserUtils.java | 2 +- .../sql/visitor/SQLASTOutputVisitor.java | 9 +- .../druid/sql/visitor/SchemaStatVisitor.java | 9 +- .../java/com/alibaba/druid/util/FnvHash.java | 3 + .../MySqlCreateTableTest108_drds.java | 40 +++ 13 files changed, 285 insertions(+), 141 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/mysql/createTable/MySqlCreateTableTest108_drds.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLPartitionByHash.java b/src/main/java/com/alibaba/druid/sql/ast/SQLPartitionByHash.java index 99bd8b1f02..fd60059b15 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLPartitionByHash.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLPartitionByHash.java @@ -21,6 +21,7 @@ public class SQLPartitionByHash extends SQLPartitionBy { // for aliyun ads protected boolean key; + protected boolean unique; public boolean isKey() { return key; @@ -30,6 +31,14 @@ public class SQLPartitionByHash extends SQLPartitionBy { this.key = key; } + public boolean isUnique() { + return unique; + } + + public void setUnique(boolean unique) { + this.unique = unique; + } + @Override protected void accept0(SQLASTVisitor visitor) { if (visitor.visit(this)) { @@ -43,7 +52,10 @@ public class SQLPartitionByHash extends SQLPartitionBy { public SQLPartitionByHash clone() { SQLPartitionByHash x = new SQLPartitionByHash(); + cloneTo(x); + x.key = key; + x.unique = unique; for (SQLExpr column : columns) { SQLExpr c2 = column.clone(); @@ -53,4 +65,8 @@ public class SQLPartitionByHash extends SQLPartitionBy { return x; } + + public void cloneTo(SQLPartitionByHash x) { + super.cloneTo(x); + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java index 3f94798f92..5b8fec750b 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java @@ -1106,4 +1106,5 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS } this.rowFormat = x; } + } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java index 75a4d74f47..06553ad813 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java @@ -125,6 +125,7 @@ public class DB2OutputVisitor extends SQLASTOutputVisitor implements DB2ASTVisit SQLPartitionBy partitionBy = x.getPartitioning(); if (partitionBy != null) { println(); + print0(ucase ? "PARTITION BY " : "partition by "); partitionBy.accept(this); } 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 9669647d2e..e611ea7558 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 @@ -22,10 +22,7 @@ import java.util.List; import java.util.Map; import com.alibaba.druid.sql.SQLUtils; -import com.alibaba.druid.sql.ast.SQLCommentHint; -import com.alibaba.druid.sql.ast.SQLExpr; -import com.alibaba.druid.sql.ast.SQLName; -import com.alibaba.druid.sql.ast.SQLObject; +import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObjectImpl; @@ -39,15 +36,14 @@ import com.alibaba.druid.util.JdbcConstants; public class MySqlCreateTableStatement extends SQLCreateTableStatement implements MySqlStatement { private Map tableOptions = new LinkedHashMap(); - private List hints = new ArrayList(); - private List optionHints = new ArrayList(); - - - private SQLName tableGroup; + protected SQLPartitionBy dbPartitionBy; + protected SQLPartitionBy tablePartitionBy; + protected SQLExpr tbpartitions; + public MySqlCreateTableStatement(){ super (JdbcConstants.MYSQL); } @@ -392,4 +388,37 @@ public class MySqlCreateTableStatement extends SQLCreateTableStatement implement cloneTo(x); return x; } + + public SQLPartitionBy getDbPartitionBy() { + return dbPartitionBy; + } + + public void setDbPartitionBy(SQLPartitionBy x) { + if (x != null) { + x.setParent(this); + } + this.dbPartitionBy = x; + } + + public SQLPartitionBy getTablePartitionBy() { + return tablePartitionBy; + } + + public void setTablePartitionBy(SQLPartitionBy x) { + if (x != null) { + x.setParent(this); + } + this.tablePartitionBy = x; + } + + public SQLExpr getTbpartitions() { + return tbpartitions; + } + + public void setTbpartitions(SQLExpr x) { + if (x != null) { + x.setParent(this); + } + this.tbpartitions = x; + } } 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 30dce4ae6b..03dbc80cf8 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 @@ -529,124 +529,31 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } if (lexer.token() == Token.PARTITION) { - lexer.nextToken(); - accept(Token.BY); - - SQLPartitionBy partitionClause; - - boolean linera = false; - if (lexer.identifierEquals("LINEAR")) { - lexer.nextToken(); - linera = true; - } - - if (lexer.token() == Token.KEY) { - MySqlPartitionByKey clause = new MySqlPartitionByKey(); - lexer.nextToken(); - - if (linera) { - clause.setLinear(true); - } - - if (lexer.identifierEquals(FnvHash.Constants.ALGORITHM)) { - lexer.nextToken(); - accept(Token.EQ); - clause.setAlgorithm(lexer.integerValue().shortValue()); - lexer.nextToken(); - } - - accept(Token.LPAREN); - if (lexer.token() != Token.RPAREN) { - for (;;) { - clause.addColumn(this.exprParser.name()); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - } - accept(Token.RPAREN); - - partitionClause = clause; - - partitionClauseRest(clause); - } else if (lexer.identifierEquals("HASH")) { - lexer.nextToken(); - SQLPartitionByHash clause = new SQLPartitionByHash(); - - if (linera) { - clause.setLinear(true); - } - - if (lexer.token() == Token.KEY) { - lexer.nextToken(); - clause.setKey(true); - } - - accept(Token.LPAREN); - this.exprParser.exprList(clause.getColumns(), clause); - accept(Token.RPAREN); - partitionClause = clause; - - partitionClauseRest(clause); - - } else if (lexer.identifierEquals("RANGE")) { - SQLPartitionByRange clause = partitionByRange(); - partitionClause = clause; - - partitionClauseRest(clause); - - } else if (lexer.identifierEquals("LIST")) { - lexer.nextToken(); - SQLPartitionByList clause = new SQLPartitionByList(); - - if (lexer.token() == Token.LPAREN) { - lexer.nextToken(); - clause.addColumn(this.exprParser.expr()); - accept(Token.RPAREN); - } else { - acceptIdentifier("COLUMNS"); - accept(Token.LPAREN); - for (;;) { - clause.addColumn(this.exprParser.name()); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - accept(Token.RPAREN); - } - partitionClause = clause; - - partitionClauseRest(clause); - } else { - throw new ParserException("TODO. " + lexer.info()); - } - - if (lexer.token() == Token.LPAREN) { - lexer.nextToken(); - for (;;) { - SQLPartition partitionDef = this.getExprParser().parsePartition(); - - partitionClause.addPartition(partitionDef); - - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } else { - break; - } - } - accept(Token.RPAREN); - } - + SQLPartitionBy partitionClause = parsePartitionBy(); stmt.setPartitioning(partitionClause); continue; } + if (lexer.identifierEquals(FnvHash.Constants.DBPARTITION)) { + SQLPartitionBy partitionClause = parsePartitionBy(); + stmt.setDbPartitionBy(partitionClause); + continue; + } + + if (lexer.identifierEquals(FnvHash.Constants.TBPARTITION)) { + SQLPartitionBy partitionClause = parsePartitionBy(); + stmt.setTablePartitionBy(partitionClause); + continue; + } + + if (lexer.identifierEquals(FnvHash.Constants.TBPARTITIONS)) { + lexer.nextToken(); + SQLExpr tbpartitions = this.exprParser.expr(); + stmt.setTbpartitions(tbpartitions); + continue; + } + break; } @@ -669,7 +576,127 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { return stmt; } - + private SQLPartitionBy parsePartitionBy() { + lexer.nextToken(); + accept(Token.BY); + + SQLPartitionBy partitionClause; + + boolean linera = false; + if (lexer.identifierEquals("LINEAR")) { + lexer.nextToken(); + linera = true; + } + + if (lexer.token() == Token.KEY) { + MySqlPartitionByKey clause = new MySqlPartitionByKey(); + lexer.nextToken(); + + if (linera) { + clause.setLinear(true); + } + + if (lexer.identifierEquals(FnvHash.Constants.ALGORITHM)) { + lexer.nextToken(); + accept(Token.EQ); + clause.setAlgorithm(lexer.integerValue().shortValue()); + lexer.nextToken(); + } + + accept(Token.LPAREN); + if (lexer.token() != Token.RPAREN) { + for (;;) { + clause.addColumn(this.exprParser.name()); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + } + accept(Token.RPAREN); + + partitionClause = clause; + + partitionClauseRest(clause); + } else if (lexer.identifierEquals("HASH") || lexer.identifierEquals("UNI_HASH")) { + SQLPartitionByHash clause = new SQLPartitionByHash(); + + if (lexer.identifierEquals("UNI_HASH")) { + clause.setUnique(true); + } + + lexer.nextToken(); + + if (linera) { + clause.setLinear(true); + } + + if (lexer.token() == Token.KEY) { + lexer.nextToken(); + clause.setKey(true); + } + + accept(Token.LPAREN); + this.exprParser.exprList(clause.getColumns(), clause); + accept(Token.RPAREN); + partitionClause = clause; + + partitionClauseRest(clause); + + } else if (lexer.identifierEquals("RANGE")) { + SQLPartitionByRange clause = partitionByRange(); + partitionClause = clause; + + partitionClauseRest(clause); + + } else if (lexer.identifierEquals("LIST")) { + lexer.nextToken(); + SQLPartitionByList clause = new SQLPartitionByList(); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + clause.addColumn(this.exprParser.expr()); + accept(Token.RPAREN); + } else { + acceptIdentifier("COLUMNS"); + accept(Token.LPAREN); + for (;;) { + clause.addColumn(this.exprParser.name()); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + accept(Token.RPAREN); + } + partitionClause = clause; + + partitionClauseRest(clause); + } else { + throw new ParserException("TODO. " + lexer.info()); + } + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + for (;;) { + SQLPartition partitionDef = this.getExprParser().parsePartition(); + + partitionClause.addPartition(partitionDef); + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } else { + break; + } + } + accept(Token.RPAREN); + } + return partitionClause; + } + protected SQLPartitionByRange partitionByRange() { acceptIdentifier("RANGE"); 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 2a2420cd08..6604ce2122 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 @@ -489,9 +489,31 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV comment.accept(this); } - if (x.getPartitioning() != null) { + SQLPartitionBy partitionBy = x.getPartitioning(); + if (partitionBy != null) { println(); - x.getPartitioning().accept(this); + print0(ucase ? "PARTITION BY " : "partition by "); + partitionBy.accept(this); + } + + SQLPartitionBy dbPartitionBy = x.getDbPartitionBy(); + if (dbPartitionBy != null) { + println(); + print0(ucase ? "DBPARTITION BY " : "dbpartition by "); + dbPartitionBy.accept(this); + } + + SQLPartitionBy tbPartitionsBy = x.getTablePartitionBy(); + if (tbPartitionsBy != null) { + println(); + print0(ucase ? "TBPARTITION BY " : "tbpartition by "); + tbPartitionsBy.accept(this); + } + + if (x.getTbpartitions() != null) { + println(); + print0(ucase ? "TBPARTITIONS " : "tbpartitions "); + x.getTbpartitions().accept(this); } if (x.getTableGroup() != null) { @@ -1462,9 +1484,9 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlPartitionByKey x) { if (x.isLinear()) { - print0(ucase ? "PARTITION BY LINEAR KEY (" : "partition by linear key ("); + print0(ucase ? "LINEAR KEY (" : "linear key ("); } else { - print0(ucase ? "PARTITION BY KEY (" : "partition by key ("); + print0(ucase ? "KEY (" : "key ("); } printAndAccept(x.getColumns(), ", "); print(')'); 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 231b5ea2ec..159587c1b8 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 @@ -1747,6 +1747,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS for (SQLPartitionBy globalPartition : globalPartitions) { println(); print0(ucase ? "GLOBAL " : "global "); + print0(ucase ? "PARTITION BY " : "partition by "); globalPartition.accept(this); } @@ -2097,9 +2098,11 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS print0(ucase ? "MONITORING" : "monitoring"); } - if (x.getPartitioning() != null) { + SQLPartitionBy partitionBy = x.getPartitioning(); + if (partitionBy != null) { println(); - x.getPartitioning().accept(this); + print0(ucase ? "PARTITION BY " : "partition by "); + partitionBy.accept(this); } if (x.getCluster() != null) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java index 2787e78945..03363a5025 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java @@ -2245,9 +2245,11 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor print0(ucase ? "MONITORING" : "monitoring"); } - if (x.getPartitioning() != null) { + SQLPartitionBy partitionBy = x.getPartitioning(); + if (partitionBy != null) { println(); - x.getPartitioning().accept(this); + print0(ucase ? "PARTITION BY " : "partition by "); + partitionBy.accept(this); } if (x.getCluster() != null) { diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java b/src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java index 38a626b5e4..3d94c6e040 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java @@ -73,7 +73,7 @@ public class SQLParserUtils { return new OracleStatementParser(sql); } - if (JdbcUtils.MYSQL.equals(dbType)) { + if (JdbcUtils.MYSQL.equals(dbType) || JdbcUtils.ALIYUN_DRDS.equals(dbType)) { return new MySqlStatementParser(sql, features); } 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 2de225c01b..6b28b1aba8 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -5083,7 +5083,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet @Override public boolean visit(SQLPartitionByRange x) { - print0(ucase ? "PARTITION BY RANGE" : "partition by range"); + print0(ucase ? "RANGE" : "range"); if (x.getColumns().size() == 1) { print0(" ("); x.getColumns().get(0).accept(this); @@ -5125,7 +5125,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet @Override public boolean visit(SQLPartitionByList x) { - print0(ucase ? "PARTITION BY LIST " : "partition by list "); + print0(ucase ? "LIST " : "list "); if (x.getColumns().size() == 1) { print('('); x.getColumns().get(0).accept(this); @@ -5145,9 +5145,9 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet @Override public boolean visit(SQLPartitionByHash x) { if (x.isLinear()) { - print0(ucase ? "PARTITION BY LINEAR HASH " : "partition by linear hash "); + print0(ucase ? "LINEAR HASH " : "linear hash "); } else { - print0(ucase ? "PARTITION BY HASH " : "partition by hash "); + print0(ucase ? "HASH " : "hash "); } if (x.isKey()) { @@ -5939,6 +5939,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet SQLPartitionBy partitionBy = x.getPartitionBy(); if (partitionBy != null) { println(); + print0(ucase ? "PARTITION BY " : "partition by "); partitionBy.accept(this); } 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 24608413d3..6b5772e6e0 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -1158,11 +1158,10 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { } } } else if (tableSource instanceof SQLWithSubqueryClause.Entry - || tableSource instanceof SQLSubqueryTableSource) { - return false; - } else if (tableSource instanceof SQLUnionQueryTableSource) { - return false; - } else if (tableSource instanceof SQLLateralViewTableSource) { + || tableSource instanceof SQLSubqueryTableSource + || tableSource instanceof SQLUnionQueryTableSource + || tableSource instanceof SQLLateralViewTableSource + || tableSource instanceof SQLValuesTableSource) { return false; } else { if (x.getResolvedProcudure() != null) { diff --git a/src/main/java/com/alibaba/druid/util/FnvHash.java b/src/main/java/com/alibaba/druid/util/FnvHash.java index a8d233dfcb..f88ae629bc 100644 --- a/src/main/java/com/alibaba/druid/util/FnvHash.java +++ b/src/main/java/com/alibaba/druid/util/FnvHash.java @@ -641,5 +641,8 @@ public final class FnvHash { long CHECKSUM = fnv1a_64_lower("CHECKSUM"); long ROUTINE = fnv1a_64_lower("ROUTINE"); long DATE_FORMAT = fnv1a_64_lower("DATE_FORMAT"); + long DBPARTITION = fnv1a_64_lower("DBPARTITION"); + long TBPARTITION = fnv1a_64_lower("TBPARTITION"); + long TBPARTITIONS = fnv1a_64_lower("TBPARTITIONS"); } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/createTable/MySqlCreateTableTest108_drds.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/createTable/MySqlCreateTableTest108_drds.java new file mode 100644 index 0000000000..4c2707435d --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/createTable/MySqlCreateTableTest108_drds.java @@ -0,0 +1,40 @@ +package com.alibaba.druid.bvt.sql.mysql.createTable; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class MySqlCreateTableTest108_drds extends MysqlTest { + + public void test_0() throws Exception { + String sql = "create table ARCHIVE_ERR_RECORD\n" + + "(\n" + + "SUBS_ORDER_ID numeric(18,0) not null comment '订单编号',\n" + + "ERR_MSG text comment '失败的消息结构',\n" + + "ERR_REASON varchar(255) comment '失败原因',\n" + + "PART_ID integer not null comment '分区标识(取订单编号中的月份)'\n" + + ")\n" + + "DBPARTITION BY HASH(SUBS_ORDER_ID)\n" + + "TBPARTITION BY UNI_HASH(PART_ID) TBPARTITIONS 12;"; + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.ALIYUN_DRDS); + SQLCreateTableStatement stmt = (SQLCreateTableStatement) statementList.get(0); + + assertEquals(1, statementList.size()); + assertEquals(4, stmt.getTableElementList().size()); + + assertEquals("CREATE TABLE ARCHIVE_ERR_RECORD (\n" + + "\tSUBS_ORDER_ID numeric(18, 0) NOT NULL COMMENT '订单编号',\n" + + "\tERR_MSG text COMMENT '失败的消息结构',\n" + + "\tERR_REASON varchar(255) COMMENT '失败原因',\n" + + "\tPART_ID integer NOT NULL COMMENT '分区标识(取订单编号中的月份)'\n" + + ")\n" + + "DBPARTITION BY HASH (SUBS_ORDER_ID)\n" + + "TBPARTITION BY HASH (PART_ID)\n" + + "TBPARTITIONS 12;", stmt.toString()); + } +} \ No newline at end of file