diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/TidbSplitTableStatement.java b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/TidbSplitTableStatement.java
new file mode 100644
index 0000000000..c711e8ee10
--- /dev/null
+++ b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/TidbSplitTableStatement.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 1999-2017 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.dialect.mysql.ast.statement;
+
+import com.alibaba.druid.sql.ast.SQLExpr;
+import com.alibaba.druid.sql.ast.SQLName;
+import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
+import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author lizongbo
+ * @see ...
+ */
+public class TidbSplitTableStatement extends MySqlStatementImpl {
+ //region for
+ private boolean splitSyntaxOptionRegionFor;
+ //partition
+ private boolean splitSyntaxOptionPartition;
+
+ private SQLExprTableSource tableName;
+
+ private List partitionNameListOptions = new ArrayList<>();
+
+ private SQLName indexName;
+
+ private List> splitOptionBys = new ArrayList<>();
+ private List splitOptionBetween;
+ private List splitOptionAnd;
+ private long splitOptionRegions;
+
+ public boolean isSplitSyntaxOptionRegionFor() {
+ return splitSyntaxOptionRegionFor;
+ }
+
+ public void setSplitSyntaxOptionRegionFor(boolean splitSyntaxOptionRegionFor) {
+ this.splitSyntaxOptionRegionFor = splitSyntaxOptionRegionFor;
+ }
+
+ public boolean isSplitSyntaxOptionPartition() {
+ return splitSyntaxOptionPartition;
+ }
+
+ public void setSplitSyntaxOptionPartition(boolean splitSyntaxOptionPartition) {
+ this.splitSyntaxOptionPartition = splitSyntaxOptionPartition;
+ }
+
+ public SQLExprTableSource getTableName() {
+ return tableName;
+ }
+
+ public void setTableName(SQLExprTableSource tableName) {
+ this.tableName = tableName;
+ }
+
+ public List getPartitionNameListOptions() {
+ return partitionNameListOptions;
+ }
+
+ public void setPartitionNameListOptions(List partitionNameListOptions) {
+ this.partitionNameListOptions = partitionNameListOptions;
+ }
+
+ public SQLName getIndexName() {
+ return indexName;
+ }
+
+ public void setIndexName(SQLName indexName) {
+ this.indexName = indexName;
+ }
+
+ public List> getSplitOptionBys() {
+ return splitOptionBys;
+ }
+
+ public void setSplitOptionBys(List> splitOptionBys) {
+ this.splitOptionBys = splitOptionBys;
+ }
+
+ public List getSplitOptionBetween() {
+ return splitOptionBetween;
+ }
+
+ public void setSplitOptionBetween(List splitOptionBetween) {
+ this.splitOptionBetween = splitOptionBetween;
+ }
+
+ public List getSplitOptionAnd() {
+ return splitOptionAnd;
+ }
+
+ public void setSplitOptionAnd(List splitOptionAnd) {
+ this.splitOptionAnd = splitOptionAnd;
+ }
+
+ public long getSplitOptionRegions() {
+ return splitOptionRegions;
+ }
+
+ public void setSplitOptionRegions(long splitOptionRegions) {
+ this.splitOptionRegions = splitOptionRegions;
+ }
+
+ public void accept0(MySqlASTVisitor visitor) {
+ if (visitor.visit(this)) {
+ this.getTableName().accept(visitor);
+ }
+ visitor.endVisit(this);
+ }
+}
diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java
index 35720c785d..a3b9aedbaa 100644
--- a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java
+++ b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java
@@ -1805,10 +1805,89 @@ public boolean parseStatementListDialect(List statementList) {
}
return true;
}
+ String strVal = lexer.stringVal();
+ if (strVal.equalsIgnoreCase("SPLIT")) {
+ TidbSplitTableStatement stmt = this.parseTiDBSplitTableStatement();
+ statementList.add(stmt);
+ return true;
+ }
return false;
}
+ private TidbSplitTableStatement parseTiDBSplitTableStatement() {
+ TidbSplitTableStatement stmt = new TidbSplitTableStatement();
+ lexer.nextToken();
+ Lexer.SavePoint mark = lexer.mark();
+ String strVal = lexer.stringVal();
+ if (lexer.token() == PARTITION) {
+ accept(PARTITION);
+ stmt.setSplitSyntaxOptionPartition(true);
+ } else if (strVal.equalsIgnoreCase("REGION")) {
+ acceptIdentifier("REGION");
+ accept(FOR);
+ stmt.setSplitSyntaxOptionRegionFor(true);
+ } else {
+ lexer.reset(mark);
+ }
+ strVal = lexer.stringVal();
+ accept(TABLE);
+ SQLName tableNameTmp = this.exprParser.name();
+ SQLExprTableSource sqlExprTableSource = new SQLExprTableSource(tableNameTmp);
+ stmt.setTableName(sqlExprTableSource);
+ strVal = lexer.stringVal();
+ if (lexer.token() == INDEX) {
+ accept(INDEX);
+ SQLName indexName = this.exprParser.name();
+ stmt.setIndexName(indexName);
+ } else if (lexer.token() == PARTITION) {
+ accept(PARTITION);
+ accept(LPAREN);
+ this.exprParser.exprList(stmt.getPartitionNameListOptions(), stmt);
+ accept(RPAREN);
+ if (lexer.token() == INDEX) {
+ accept(INDEX);
+ SQLName indexName = this.exprParser.name();
+ stmt.setIndexName(indexName);
+ }
+ }
+ if (lexer.token() == BETWEEN) {
+ accept(BETWEEN);
+ accept(LPAREN);
+ List sqlExprBetweens = new ArrayList<>();
+ this.exprParser.exprList(sqlExprBetweens, stmt);
+ stmt.setSplitOptionBetween(sqlExprBetweens);
+ accept(RPAREN);
+ accept(AND);
+ accept(LPAREN);
+ List sqlExprAnds = new ArrayList<>();
+ this.exprParser.exprList(sqlExprAnds, stmt);
+ stmt.setSplitOptionAnd(sqlExprAnds);
+ accept(RPAREN);
+ acceptIdentifier("REGIONS");
+ SQLIntegerExpr num = this.exprParser.integerExpr();
+ stmt.setSplitOptionRegions(num.getNumber().longValue());
+ } else if (lexer.token() == BY) {
+ accept(BY);
+ accept(LPAREN);
+ List byItems = new ArrayList<>();
+ this.exprParser.exprList(byItems, stmt);
+ accept(RPAREN);
+ stmt.getSplitOptionBys().add(byItems);
+ while (lexer.token() == COMMA) {
+ accept(COMMA);
+ accept(LPAREN);
+ byItems = new ArrayList<>();
+ this.exprParser.exprList(byItems, stmt);
+ accept(RPAREN);
+ stmt.getSplitOptionBys().add(byItems);
+ }
+
+ } else if (lexer.token() == PARTITION) {
+ accept(PARTITION);
+ }
+ return stmt;
+ }
private SQLStatement parseArchive() {
lexer.nextToken();
accept(Token.TABLE);
diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java
index 7d2e8dc71c..8d048e2a91 100644
--- a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java
+++ b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java
@@ -1274,4 +1274,11 @@ default boolean visit(MySqlXAStatement x) {
default void endVisit(MySqlXAStatement x) {
}
+ default boolean visit(TidbSplitTableStatement x) {
+ return true;
+ }
+
+ default void endVisit(TidbSplitTableStatement x) {
+ }
+
} //
diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java
index 539e51b8f2..ab0641b50f 100644
--- a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java
+++ b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java
@@ -5442,6 +5442,56 @@ public boolean visit(MySqlJSONTableExpr x) {
return false;
}
+ public boolean visit(TidbSplitTableStatement x) {
+ print0(ucase ? "SPLIT " : "split ");
+ if (x.isSplitSyntaxOptionRegionFor()) {
+ print0(ucase ? "REGION FOR " : "region for ");
+ }
+ if (x.isSplitSyntaxOptionPartition()) {
+ print0(ucase ? "PARTITION " : "partition ");
+ }
+ print0(ucase ? "TABLE " : "table ");
+ x.getTableName().accept(this);
+ print(' ');
+
+ if (!x.getPartitionNameListOptions().isEmpty()) {
+ print0(ucase ? "PARTITION (" : "partition (");
+ printAndAccept(x.getPartitionNameListOptions(), ",");
+ print(") ");
+ }
+ if (x.getIndexName() != null) {
+ print0(ucase ? "INDEX " : "index ");
+ x.getIndexName().accept(this);
+ print(' ');
+ }
+ if (!x.getSplitOptionBys().isEmpty()) {
+ print0(ucase ? "BY " : "by ");
+ boolean needCommon = false;
+ for (List list : x.getSplitOptionBys()) {
+ if (!needCommon) {
+ needCommon = true;
+ } else {
+ print0(", ");
+ }
+ print0("(");
+ printlnAndAccept(list, ", ");
+ print0(")");
+ }
+ }
+ if (x.getSplitOptionBetween() != null) {
+ print0(ucase ? "BETWEEN (" : " between (");
+ printAndAccept(x.getSplitOptionBetween(), ", ");
+ print0(ucase ? ") AND (" : ") and (");
+ printAndAccept(x.getSplitOptionAnd(), ", ");
+ print0(") ");
+ print0(ucase ? "REGIONS " : "regions ");
+ print(x.getSplitOptionRegions());
+ }
+
+ return false;
+ }
+
+
public boolean visit(MySqlJSONTableExpr.Column x) {
x.getName().accept(this);
diff --git a/core/src/test/java/com/alibaba/druid/bvt/sql/mysql/issues/Issue5219.java b/core/src/test/java/com/alibaba/druid/bvt/sql/mysql/issues/Issue5219.java
new file mode 100644
index 0000000000..6f758a020e
--- /dev/null
+++ b/core/src/test/java/com/alibaba/druid/bvt/sql/mysql/issues/Issue5219.java
@@ -0,0 +1,68 @@
+package com.alibaba.druid.bvt.sql.mysql.issues;
+
+import java.util.Map;
+
+import com.alibaba.druid.DbType;
+import com.alibaba.druid.sql.SQLUtils;
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.druid.sql.parser.SQLParserUtils;
+import com.alibaba.druid.sql.parser.SQLStatementParser;
+import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
+import com.alibaba.druid.stat.TableStat;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author lizongbo
+ * @see Split Region 使用文档
+ * @see Issue来源
+ */
+public class Issue5219 {
+
+ @Test
+ public void test_split_table() throws Exception {
+ // for (DbType dbType : new DbType[]{DbType.mysql, DbType.tidb}) {
+ for (DbType dbType : new DbType[]{DbType.tidb}) {
+ for (String sql : new String[]{
+ "split TABLE t BETWEEN (-9223372036854775808) AND (9223372036854775807) REGIONS 16;",
+ "split partition TABLE t BETWEEN (-9223372036854775808) AND (9223372036854775807) REGIONS 16;",
+ "split region for TABLE t BETWEEN (-9223372036854775808) AND (9223372036854775807) REGIONS 16;",
+ "SPLIT TABLE t INDEX idx BETWEEN (-9223372036854775808) AND (9223372036854775807) REGIONS 16;",
+ "SPLIT TABLE t1 INDEX idx4 BY (\"a\", \"2000-01-01 00:00:01\"), (\"b\", \"2019-04-17 14:26:19\"), (\"c\", \"\");",
+ "split partition table t partition (p1,p3) between (0) and (10000) regions 2;",
+ "split TABLE t BETWEEN (0) AND (1000000000) REGIONS 16;",
+ "split TABLE t BY (10000), (90000);",
+ "SPLIT TABLE t INDEX idx1 BETWEEN (\"a\") AND (\"z\") REGIONS 25;",
+ "SPLIT TABLE t INDEX idx1 BETWEEN (\"a\") AND (\"{\") REGIONS 26;",
+ "SPLIT TABLE t INDEX idx2 BETWEEN (\"2010-01-01 00:00:00\") AND (\"2020-01-01 00:00:00\") REGIONS 10;",
+ "SPLIT TABLE t INDEX idx2 BETWEEN (\"2020-06-01 00:00:00\") AND (\"2020-07-01 00:00:00\") REGIONS 30;",
+ "SPLIT TABLE t INDEX idx3 BETWEEN (\"2010-01-01 00:00:00\") AND (\"2020-01-01 00:00:00\") REGIONS 10;",
+ "SPLIT TABLE t INDEX idx3 BETWEEN (\"2010-01-01 00:00:00\", \"a\") AND (\"2010-01-01 00:00:00\", \"z\") REGIONS 10;",
+ "SPLIT TABLE t INDEX `PRIMARY` BETWEEN (-9223372036854775808) AND (9223372036854775807) REGIONS 16;",
+ "SPLIT TABLE t1 INDEX idx4 BY (\"a\", \"2000-01-01 00:00:01\"), (\"b\", \"2019-04-17 14:26:19\"), (\"c\", \"\");",
+ "split partition table t between (0) and (10000) regions 4;",
+ "split region for table t index idx between (1000) and (10000) regions 2;",
+ "split partition table t index idx between (1000) and (10000) regions 2;",
+ "split partition table t partition (p1) between (0) and (10000) regions 2;",
+ "split partition table t partition (p2) between (10000) and (20000) regions 2;",
+ "split partition table t partition (p1,p2) index idx between (0) and (20000) regions 2;",
+ }) {
+ SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType);
+ SQLStatement statement = parser.parseStatement();
+ System.out.println("原始的sql===" + sql);
+ String newSql=statement.toString().replace("\n","").replace('\'','"')+";";
+ System.out.println("生成的sql===" + newSql);
+ assertTrue(newSql.equalsIgnoreCase(sql));
+ SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType);
+ statement.accept(visitor);
+ System.out.println("getTables==" + visitor.getTables());
+ Map tableMap = visitor.getTables();
+ assertFalse(tableMap.isEmpty());
+
+ }
+ }
+ }
+}