diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLPartitionByRange.java b/src/main/java/com/alibaba/druid/sql/ast/SQLPartitionByRange.java index f94bdf5ab3..a8d8aae5b6 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLPartitionByRange.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLPartitionByRange.java @@ -15,10 +15,17 @@ */ package com.alibaba.druid.sql.ast; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLPartitionByRange extends SQLPartitionBy { protected SQLExpr interval; + protected boolean isColumns = false; + protected SQLExpr startWith; + protected SQLIntegerExpr expireAfter; + protected SQLIntegerExpr preAllocate; + protected SQLExpr pivotDateExpr; + protected boolean disableSchedule = false; public SQLPartitionByRange() { } @@ -35,11 +42,60 @@ public class SQLPartitionByRange extends SQLPartitionBy { this.interval = interval; } + public SQLExpr getStartWith() { + return this.startWith; + } + + public void setStartWith(final SQLExpr startWith) { + if (startWith != null) { + startWith.setParent(this); + } + + this.startWith = startWith; + } + + public SQLIntegerExpr getExpireAfter() { + return this.expireAfter; + } + + public void setExpireAfter(final SQLIntegerExpr expireAfter) { + if (expireAfter != null) { + expireAfter.setParent(this); + } + this.expireAfter = expireAfter; + } + + public SQLIntegerExpr getPreAllocate() { + return this.preAllocate; + } + + public void setPreAllocate(final SQLIntegerExpr preAllocate) { + if (preAllocate != null) { + preAllocate.setParent(this); + } + this.preAllocate = preAllocate; + } + + public SQLExpr getPivotDateExpr() { + return this.pivotDateExpr; + } + + public void setPivotDateExpr(final SQLExpr pivotDateExpr) { + if (pivotDateExpr != null) { + pivotDateExpr.setParent(this); + } + this.pivotDateExpr = pivotDateExpr; + } + @Override protected void accept0(SQLASTVisitor visitor) { if (visitor.visit(this)) { acceptChild(visitor, columns); acceptChild(visitor, interval); + acceptChild(visitor, expireAfter); + acceptChild(visitor, preAllocate); + acceptChild(visitor, pivotDateExpr); + acceptChild(visitor, columns); acceptChild(visitor, storeIn); acceptChild(visitor, partitions); acceptChild(visitor, subPartitionBy); @@ -56,16 +112,43 @@ public class SQLPartitionByRange extends SQLPartitionBy { x.setInterval(interval.clone()); } + if (startWith != null) { + x.setStartWith(startWith.clone()); + } + + if (expireAfter != null) { + x.setExpireAfter(expireAfter.clone()); + } + for (SQLExpr column : columns) { SQLExpr c2 = column.clone(); c2.setParent(x); x.columns.add(c2); } + x.setColumns(this.isColumns); + x.setDisableSchedule(this.disableSchedule); + return x; } public void cloneTo(SQLPartitionByRange x) { super.cloneTo(x); } + + public boolean isColumns() { + return isColumns; + } + + public void setColumns(boolean columns) { + isColumns = columns; + } + + public boolean isDisableSchedule() { + return this.disableSchedule; + } + + public void setDisableSchedule(final boolean disableSchedule) { + this.disableSchedule = disableSchedule; + } } 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 040b74c94d..91caa13a38 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 @@ -50,6 +50,7 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS protected SQLName tablespace; protected SQLPartitionBy partitioning; + protected SQLPartitionBy localPartitioning; protected SQLExpr storedAs; protected SQLExpr location; @@ -99,6 +100,7 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS this.acceptChild(v, tablespace); this.acceptChild(v, partitioning); + this.acceptChild(v, localPartitioning); this.acceptChild(v, storedAs); this.acceptChild(v, location); @@ -348,6 +350,10 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS return partitioning; } + public SQLPartitionBy getLocalPartitioning() { + return this.localPartitioning; + } + public void setPartitioning(SQLPartitionBy partitioning) { if (partitioning != null) { partitioning.setParent(this); @@ -356,6 +362,14 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS this.partitioning = partitioning; } + public void setLocalPartitioning(SQLPartitionBy localPartitioning) { + if (localPartitioning != null) { + localPartitioning.setParent(this); + } + + this.localPartitioning = localPartitioning; + } + @Override public List getChildren() { List children = new ArrayList(); @@ -1224,6 +1238,10 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS x.setPartitioning(partitioning.clone()); } + if (localPartitioning != null) { + x.setLocalPartitioning(localPartitioning.clone()); + } + if (storedAs != null) { x.setStoredAs(storedAs.clone()); } 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 a01224d287..bb98be73d7 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 @@ -486,6 +486,9 @@ public class MySqlCreateTableStatement extends SQLCreateTableStatement implement if (partitioning != null) { x.setPartitioning(partitioning.clone()); } + if (localPartitioning != null) { + x.setLocalPartitioning(localPartitioning.clone()); + } for (SQLCommentHint hint : hints) { SQLCommentHint h2 = hint.clone(); h2.setParent(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 b32b40768b..ba814f10df 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 @@ -119,6 +119,88 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } } + boolean local = false; + if (lexer.identifierEquals(FnvHash.Constants.LOCAL)) { + final Lexer.SavePoint mark = lexer.mark(); + lexer.nextToken(); + if (lexer.token() == Token.INDEX || lexer.token() == Token.KEY + || lexer.token() == Token.UNIQUE) { + local = true; + } else if (lexer.token() == Token.FULLTEXT) { + lexer.nextToken(); + + if (lexer.token() == Token.KEY) { + MySqlKey fulltextKey = new MySqlKey(); + this.exprParser.parseIndex(fulltextKey.getIndexDefinition()); + fulltextKey.setIndexType("FULLTEXT"); + fulltextKey.setParent(stmt); + stmt.getTableElementList().add(fulltextKey); + + while (lexer.token() == Token.HINT) { + lexer.nextToken(); + } + + if (lexer.token() == Token.RPAREN) { + break; + } else if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + } else if (lexer.token() == Token.INDEX) { + MySqlTableIndex idx = new MySqlTableIndex(); + this.exprParser.parseIndex(idx.getIndexDefinition()); + idx.setIndexType("FULLTEXT"); + idx.setParent(stmt); + stmt.getTableElementList().add(idx); + + if (lexer.token() == Token.RPAREN) { + break; + } else if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + } else if (lexer.token() == Token.IDENTIFIER && MySqlUtils.isBuiltinDataType( + lexer.stringVal())) { + lexer.reset(mark); + } else { + MySqlTableIndex idx = new MySqlTableIndex(); + this.exprParser.parseIndex(idx.getIndexDefinition()); + idx.setIndexType("FULLTEXT"); + idx.setParent(stmt); + stmt.getTableElementList().add(idx); + + if (lexer.token() == Token.RPAREN) { + break; + } else if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + } + + } else if (lexer.identifierEquals(FnvHash.Constants.SPATIAL)) { + lexer.nextToken(); + if (lexer.token() == Token.INDEX || lexer.token() == Token.KEY || + lexer.token() != Token.IDENTIFIER || !MySqlUtils.isBuiltinDataType(lexer.stringVal())) { + MySqlTableIndex idx = new MySqlTableIndex(); + this.exprParser.parseIndex(idx.getIndexDefinition()); + idx.setIndexType("SPATIAL"); + idx.setParent(stmt); + stmt.getTableElementList().add(idx); + + if (lexer.token() == Token.RPAREN) { + break; + } else if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + } else { + lexer.reset(mark); + } + } else { + lexer.reset(mark); + } + } + if (lexer.token() == Token.FULLTEXT) { Lexer.SavePoint mark = lexer.mark(); lexer.nextToken(); @@ -286,6 +368,9 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { if (global) { unique.setGlobal(true); } + if(local){ + unique.setLocal(true); + } } stmt.getTableElementList().add(constraint); @@ -297,6 +382,10 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { idx.getIndexDefinition().setGlobal(true); } + if (local) { + idx.getIndexDefinition().setLocal(true); + } + idx.setParent(stmt); stmt.getTableElementList().add(idx); } else if (lexer.token() == (Token.KEY)) { @@ -836,6 +925,12 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } + if (lexer.identifierEquals(FnvHash.Constants.LOCAL)) { + SQLPartitionBy localPartitionClause = parseLocalPartitionBy(); + stmt.setLocalPartitioning(localPartitionClause); + continue; + } + if (lexer.identifierEquals(FnvHash.Constants.BROADCAST)) { lexer.nextToken(); stmt.setBroadCast(true); @@ -1060,6 +1155,51 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { return stmt; } + public SQLPartitionBy parseLocalPartitionBy() { + lexer.nextToken(); + accept(Token.PARTITION); + accept(Token.BY); + acceptIdentifier("RANGE"); + + SQLPartitionByRange partitionClause = new SQLPartitionByRange(); + + accept(Token.LPAREN); + partitionClause.addColumn(this.exprParser.name()); + accept(Token.RPAREN); + + if (lexer.identifierEquals(FnvHash.Constants.STARTWITH)) { + lexer.nextToken(); + partitionClause.setStartWith(exprParser.expr()); + } + + partitionClause.setInterval(getExprParser().parseInterval()); + + if (lexer.identifierEquals("EXPIRE")) { + acceptIdentifier("EXPIRE"); + acceptIdentifier("AFTER"); + partitionClause.setExpireAfter((SQLIntegerExpr) exprParser.expr()); + } + + if (lexer.identifierEquals("PRE")) { + acceptIdentifier("PRE"); + acceptIdentifier("ALLOCATE"); + partitionClause.setPreAllocate((SQLIntegerExpr) exprParser.expr()); + } + + if (lexer.identifierEquals("PIVOTDATE")) { + acceptIdentifier("PIVOTDATE"); + partitionClause.setPivotDateExpr(exprParser.expr()); + } + + if (lexer.token() == Token.DISABLE) { + lexer.nextToken(); + acceptIdentifier("SCHEDULE"); + partitionClause.setDisableSchedule(true); + } + + return partitionClause; + } + public SQLPartitionBy parsePartitionBy() { lexer.nextToken(); accept(Token.BY); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/polardbx/PolarDBXTest.java b/src/test/java/com/alibaba/druid/bvt/sql/polardbx/PolarDBXTest.java index 26abac34fd..7bfdc2ac7f 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/polardbx/PolarDBXTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/polardbx/PolarDBXTest.java @@ -20,6 +20,7 @@ public class PolarDBXTest extends TestCase { // repository.setDefaultSchema("test1"); SchemaObject table = repository.findTable("test1"); Assert.assertTrue(table != null); + System.out.println(table.getStatement()); } public void test_polardb_x_2() throws Throwable { @@ -33,7 +34,7 @@ public class PolarDBXTest extends TestCase { // repository.setDefaultSchema("test2"); SchemaObject table = repository.findTable("test2"); Assert.assertTrue(table != null); - + System.out.println(table.getStatement()); } public void test_polardb_x_3() throws Throwable { @@ -47,6 +48,7 @@ public class PolarDBXTest extends TestCase { // repository.setDefaultSchema("test3"); SchemaObject table = repository.findTable("test3"); Assert.assertTrue(table != null); + System.out.println(table.getStatement()); } public void test_polardb_x_4() throws Throwable { @@ -74,4 +76,33 @@ public class PolarDBXTest extends TestCase { Assert.assertTrue(table != null); System.out.println(table.getStatement()); } + + public void test_polardb_x_5() throws Throwable { + SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL); + String sql5 = " CREATE TABLE `test5` (\n" + + " `id` bigint(20) NOT NULL DEFAULT '0' COMMENT '',\n" + + " `dksl` varchar(36) NOT NULL DEFAULT '' COMMENT '',\n" + + " `dlsc` varchar(36) NOT NULL DEFAULT '' COMMENT '',\n" + + " `chw` smallint(6) NOT NULL DEFAULT '0' COMMENT '',\n" + + " `co2o` varchar(5000) NOT NULL DEFAULT '' COMMENT '',\n" + + " `cnx` varchar(200) NOT NULL DEFAULT '' COMMENT '',\n" + + " `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '',\n" + + " `dow` varchar(36) NOT NULL DEFAULT '' COMMENT '',\n" + + " PRIMARY KEY USING BTREE (`id`, `create_time`),\n" + + " LOCAL KEY `_local_idx_xdfd` USING BTREE (`dksl`) COMMENT '',\n" + + " LOCAL KEY `_local_idx_kdfs` USING BTREE (`create_time`) COMMENT ''\n" + + ") ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 ROW_FORMAT = COMPACT COMMENT ''\n" + + "LOCAL PARTITION BY RANGE (create_time)\n" + + "STARTWITH '2022-01-01'\n" + + "INTERVAL 1 MONTH\n" + + "EXPIRE AFTER 12\n" + + "PRE ALLOCATE 3\n" + + "PIVOTDATE NOW()\n" + + "DISABLE SCHEDULE\u0000"; + repository.console(sql5); +// repository.setDefaultSchema("test4"); + SchemaObject table = repository.findTable("test5"); + Assert.assertTrue(table != null); + System.out.println(table.getStatement()); + } }