-
Notifications
You must be signed in to change notification settings - Fork 8.6k
fix: support SUBPARTITION TEMPLATE for OceanBase composite partitioning #6630
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| package com.alibaba.druid.bvt.sql.oceanbase.issues; | ||
|
|
||
| import com.alibaba.druid.DbType; | ||
| import com.alibaba.druid.sql.ast.SQLStatement; | ||
| import com.alibaba.druid.sql.parser.SQLParserUtils; | ||
| import com.alibaba.druid.sql.parser.SQLStatementParser; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
||
| /** | ||
| * Fix OceanBase/Oracle SUBPARTITION TEMPLATE parsing in CREATE TABLE. | ||
| * <p> | ||
| * The MySQL parser (used by OceanBase) only recognized SUBPARTITION OPTIONS | ||
| * after the subpartition-by clause, but not SUBPARTITION TEMPLATE which is | ||
| * used to define template subpartitions for composite partitioning. | ||
| * | ||
| * @see <a href="https://github.com/alibaba/druid/issues/6160">Issue #6160</a> | ||
| */ | ||
| public class Issue6160 { | ||
| @Test | ||
| public void test_subpartition_template_list_range() { | ||
| // Exact SQL from the issue | ||
| String sql = "CREATE TABLE t2_m_lr(col1 INT, col2 INT)\n" | ||
| + "PARTITION BY LIST (col1)\n" | ||
| + "SUBPARTITION BY RANGE(col2)\n" | ||
| + "SUBPARTITION TEMPLATE\n" | ||
| + " (SUBPARTITION mp0 VALUES LESS THAN(100),\n" | ||
| + " SUBPARTITION mp1 VALUES LESS THAN(200),\n" | ||
| + " SUBPARTITION mp2 VALUES LESS THAN(300))\n" | ||
| + " (PARTITION p0 VALUES IN(1,3),\n" | ||
| + " PARTITION p1 VALUES IN(4,6),\n" | ||
| + " PARTITION p2 VALUES IN(7,9))"; | ||
|
|
||
| for (DbType dbType : new DbType[]{DbType.oceanbase, DbType.mysql}) { | ||
| SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType); | ||
| List<SQLStatement> stmtList = parser.parseStatementList(); | ||
| assertEquals(1, stmtList.size()); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void test_subpartition_template_range_hash() { | ||
| String sql = "CREATE TABLE t_range_hash(col1 INT, col2 INT)\n" | ||
| + "PARTITION BY RANGE(col1)\n" | ||
| + "SUBPARTITION BY HASH(col2)\n" | ||
| + "SUBPARTITION TEMPLATE\n" | ||
| + " (SUBPARTITION sp0,\n" | ||
| + " SUBPARTITION sp1,\n" | ||
| + " SUBPARTITION sp2)\n" | ||
| + " (PARTITION p0 VALUES LESS THAN(100),\n" | ||
| + " PARTITION p1 VALUES LESS THAN(200))"; | ||
|
|
||
| SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, DbType.oceanbase); | ||
| List<SQLStatement> stmtList = parser.parseStatementList(); | ||
| assertEquals(1, stmtList.size()); | ||
| } | ||
|
|
||
| @Test | ||
| public void test_subpartition_template_with_values_in() { | ||
| String sql = "CREATE TABLE t_range_list(col1 INT, col2 INT)\n" | ||
| + "PARTITION BY RANGE(col1)\n" | ||
| + "SUBPARTITION BY LIST(col2)\n" | ||
| + "SUBPARTITION TEMPLATE\n" | ||
| + " (SUBPARTITION sp0 VALUES IN(1,2,3),\n" | ||
| + " SUBPARTITION sp1 VALUES IN(4,5,6))\n" | ||
| + " (PARTITION p0 VALUES LESS THAN(100),\n" | ||
| + " PARTITION p1 VALUES LESS THAN(200))"; | ||
|
|
||
| SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, DbType.oceanbase); | ||
| List<SQLStatement> stmtList = parser.parseStatementList(); | ||
| assertEquals(1, stmtList.size()); | ||
| } | ||
|
|
||
| @Test | ||
| public void test_subpartition_options_still_works() { | ||
| // Ensure existing SUBPARTITION OPTIONS parsing is not broken | ||
| String sql = "CREATE TABLE t_opt(id INT)\n" | ||
| + "PARTITION BY HASH(id)\n" | ||
| + "SUBPARTITION BY KEY(id)\n" | ||
| + "SUBPARTITIONS 4"; | ||
|
|
||
| SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, DbType.mysql); | ||
| List<SQLStatement> stmtList = parser.parseStatementList(); | ||
| assertEquals(1, stmtList.size()); | ||
| } | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] All 4 test cases assert Suggested fix: Add AST-level assertions (after fixing output visitors for round-trip support): SQLCreateTableStatement stmt = (SQLCreateTableStatement) stmtList.get(0);
SQLSubPartitionBy spBy = stmt.getPartitionBy().getSubPartitionBy();
List<SQLSubPartition> template = spBy.getSubPartitionTemplate();
assertEquals(3, template.size());
assertEquals("mp0", template.get(0).getName().getSimpleName());Or use |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] Template subpartitions are manually constructed with only
name+VALUES, skipping per-subpartition properties (TABLESPACE, COMMENT, ENGINE, DATA DIRECTORY, etc.) thatthis.exprParser.parseSubPartition()handles. The Oracle parser's equivalent code correctly callsparseSubPartition().Suggested fix: Replace the manual construction with a call to the existing parser method: