Skip to content

Commit 220d0ed

Browse files
authored
fix: parse MySQL ADD PARTITION PARTITIONS and partition binlog modifiers (#2848)
ALTER TABLE t ADD PARTITION PARTITIONS n, which adds partitions to a HASH or KEY partitioned table, parsed as an ADD COLUMN named PARTITION with PARTITIONS and n as column options. NO_WRITE_TO_BINLOG and LOCAL (MySQL's opt_no_write_to_binlog) failed on every partition operation that accepts them, and MODIFY or ALTER PARTITION (...) was accepted and rewritten to ADD PARTITION. Parse ADD PARTITION [NO_WRITE_TO_BINLOG | LOCAL] {(definitions) | PARTITIONS n} only after ADD, and accept the modifier on COALESCE, REORGANIZE, ANALYZE, OPTIMIZE, REBUILD and REPAIR PARTITION. The name list operations share one alternative. Before a comma, INTO or the end of the statement, LOCAL remains a partition name as before. AlterExpressionPartition keeps the ADD and COALESCE count in one partitionCount, reuses TableMaintenanceStatement.Modifier, and renders these operations itself. The COALESCE accessors delegate to the shared count. Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 90ac3a7 commit 220d0ed

3 files changed

Lines changed: 265 additions & 45 deletions

File tree

‎src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionPartition.java‎

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
2323
import net.sf.jsqlparser.schema.Column;
2424
import net.sf.jsqlparser.schema.Table;
25+
import net.sf.jsqlparser.statement.TableMaintenanceStatement;
2526
import net.sf.jsqlparser.statement.create.table.PartitionBound;
2627
import net.sf.jsqlparser.statement.create.table.PartitionDefinition;
2728
import net.sf.jsqlparser.statement.create.table.TablePartitioning;
@@ -35,7 +36,9 @@
3536
* MySQL partition names and definitions remain available through the inherited
3637
* {@link #getPartitions()} and {@link #getPartitionDefinitions()} methods. This subtype adds
3738
* structured access to the complete {@code PARTITION BY} clause, the table used by
38-
* {@code EXCHANGE PARTITION}, and its validation mode. It also models PostgreSQL
39+
* {@code EXCHANGE PARTITION}, and its validation mode, the partition count of
40+
* {@code ADD PARTITION PARTITIONS n} and {@code COALESCE PARTITION n}, and the
41+
* {@code NO_WRITE_TO_BINLOG}/{@code LOCAL} modifier. It also models PostgreSQL
3942
* {@code ATTACH/DETACH PARTITION} operations.
4043
*/
4144
public class AlterExpressionPartition extends AlterExpression {
@@ -52,7 +55,8 @@ public enum ExchangeValidationMode {
5255
private PartitionBound partitionBound;
5356
private DetachMode detachMode;
5457
private TablePartitioning partitioning;
55-
private Integer coalescePartitionCount;
58+
private Integer partitionCount;
59+
private TableMaintenanceStatement.Modifier modifier;
5660
private Table exchangeTable;
5761
private ExchangeValidationMode exchangeValidationMode;
5862

@@ -251,18 +255,38 @@ public void setAllPartitions(boolean allPartitions) {
251255
}
252256

253257
/**
254-
* Returns the number of partitions added by a MySQL {@code COALESCE PARTITION} operation.
255-
* Unlike the legacy primitive accessor, this is {@code null} when no count was supplied.
258+
* Returns the number of partitions added by MySQL {@code ADD PARTITION PARTITIONS n} or removed
259+
* by {@code COALESCE PARTITION n}, or {@code null} when no count was supplied. An
260+
* {@code ADD PARTITION} with a count renders the count instead of partition definitions.
261+
*/
262+
public Integer getPartitionCount() {
263+
return partitionCount;
264+
}
265+
266+
public void setPartitionCount(Integer partitionCount) {
267+
this.partitionCount = partitionCount;
268+
}
269+
270+
/**
271+
* Returns the number of partitions removed by a MySQL {@code COALESCE PARTITION} operation.
272+
* This is the same value as {@link #getPartitionCount()}. Unlike the legacy primitive accessor,
273+
* this is {@code null} when no count was supplied.
256274
*/
257275
public Integer getCoalescePartitionCount() {
258-
return coalescePartitionCount;
276+
return partitionCount;
259277
}
260278

261279
public void setCoalescePartitionCount(Integer coalescePartitionCount) {
262-
this.coalescePartitionCount = coalescePartitionCount;
263-
if (coalescePartitionCount != null) {
264-
super.setCoalescePartitionNumber(coalescePartitionCount);
265-
}
280+
setPartitionCount(coalescePartitionCount);
281+
}
282+
283+
/** Returns the MySQL {@code NO_WRITE_TO_BINLOG} or {@code LOCAL} modifier, if any. */
284+
public TableMaintenanceStatement.Modifier getModifier() {
285+
return modifier;
286+
}
287+
288+
public void setModifier(TableMaintenanceStatement.Modifier modifier) {
289+
this.modifier = modifier;
266290
}
267291

268292
@Override
@@ -285,10 +309,14 @@ protected boolean usesGeneralBody() {
285309
return false;
286310
}
287311

312+
@Override
313+
public int getCoalescePartitionNumber() {
314+
return partitionCount != null ? partitionCount : 0;
315+
}
316+
288317
@Override
289318
public void setCoalescePartitionNumber(int coalescePartitionNumber) {
290-
super.setCoalescePartitionNumber(coalescePartitionNumber);
291-
this.coalescePartitionCount = coalescePartitionNumber;
319+
setPartitionCount(coalescePartitionNumber);
292320
}
293321

294322
public Table getExchangeTable() {
@@ -384,6 +412,16 @@ public AlterExpressionPartition withCoalescePartitionCount(Integer coalesceParti
384412
return this;
385413
}
386414

415+
public AlterExpressionPartition withPartitionCount(Integer partitionCount) {
416+
setPartitionCount(partitionCount);
417+
return this;
418+
}
419+
420+
public AlterExpressionPartition withModifier(TableMaintenanceStatement.Modifier modifier) {
421+
setModifier(modifier);
422+
return this;
423+
}
424+
387425
public AlterExpressionPartition withExchangeTable(Table exchangeTable) {
388426
setExchangeTable(exchangeTable);
389427
return this;
@@ -449,12 +487,33 @@ public void appendTo(StringBuilder b, Consumer<Expression> expressionPrinter) {
449487
private void appendBody(StringBuilder b, Consumer<Expression> expressionPrinter) {
450488
switch (getOperation()) {
451489
case ADD_PARTITION:
452-
b.append("ADD PARTITION ")
490+
appendOperationKeywords(b);
491+
if (partitionCount != null) {
492+
b.append(" PARTITIONS ").append(partitionCount);
493+
} else {
494+
b.append(' ').append(
495+
PlainSelect.getStringList(getPartitionDefinitions(), true, true));
496+
}
497+
break;
498+
case COALESCE_PARTITION:
499+
appendOperationKeywords(b);
500+
b.append(' ').append(getCoalescePartitionNumber());
501+
break;
502+
case REORGANIZE_PARTITION:
503+
appendOperationKeywords(b);
504+
b.append(' ').append(PlainSelect.getStringList(getPartitionNames()))
505+
.append(" INTO ")
453506
.append(PlainSelect.getStringList(getPartitionDefinitions(), true, true));
454507
break;
455508
case DROP_PARTITION:
456-
b.append("DROP PARTITION ")
457-
.append(PlainSelect.getStringList(getPartitionNames()));
509+
case TRUNCATE_PARTITION:
510+
case ANALYZE_PARTITION:
511+
case CHECK_PARTITION:
512+
case OPTIMIZE_PARTITION:
513+
case REBUILD_PARTITION:
514+
case REPAIR_PARTITION:
515+
appendOperationKeywords(b);
516+
b.append(' ').append(PlainSelect.getStringList(getPartitionNames()));
458517
break;
459518
case ATTACH_PARTITION:
460519
b.append("ATTACH PARTITION ").append(partitionTable).append(' ');
@@ -493,4 +552,13 @@ private void appendBody(StringBuilder b, Consumer<Expression> expressionPrinter)
493552
break;
494553
}
495554
}
555+
556+
/** Appends {@code <operation> PARTITION} and the binlog modifier, if any. */
557+
private void appendOperationKeywords(StringBuilder b) {
558+
String operation = getOperation().name();
559+
b.append(operation, 0, operation.length() - "_PARTITION".length()).append(" PARTITION");
560+
if (modifier != null) {
561+
b.append(' ').append(modifier);
562+
}
563+
}
496564
}

‎src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt‎

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2404,6 +2404,20 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
24042404
return table == K_TABLE || table == K_TABLES;
24052405
}
24062406

2407+
/**
2408+
* Whether NO_WRITE_TO_BINLOG or LOCAL modifies a MySQL partition operation. Followed by a
2409+
* comma, INTO or the end of the statement, the word remains a partition name.
2410+
*/
2411+
private boolean isPartitionBinlogModifierAhead() {
2412+
int kind = getToken(1).kind;
2413+
if (kind != K_NO_WRITE_TO_BINLOG && kind != K_LOCAL) {
2414+
return false;
2415+
}
2416+
Token next = getToken(2);
2417+
return next.kind != EOF && next.kind != ST_SEMICOLON && next.kind != K_INTO
2418+
&& !",".equals(next.image);
2419+
}
2420+
24072421
/** Whether a PostgreSQL REINDEX statement starts here; REINDEX stays an identifier elsewhere. */
24082422
private boolean isReindexAhead() {
24092423
if (getToken(1).kind != K_REINDEX) {
@@ -20901,6 +20915,7 @@ void MySqlDropNamedConstraint(AlterExpression alterExp):
2090120915
AlterExpression AlterExpressionPartitionOp():
2090220916
{
2090320917
AlterExpressionPartition alterExp = new AlterExpressionPartition();
20918+
AlterOperation operation;
2090420919
Token tk;
2090520920
List<String> partitions = null;
2090620921
List<PartitionDefinition> partitionDefinition = null;
@@ -20909,15 +20924,29 @@ AlterExpression AlterExpressionPartitionOp():
2090920924
}
2091020925
{
2091120926
(
20912-
LOOKAHEAD(2) <K_TRUNCATE> <K_PARTITION> { alterExp.setOperation(AlterOperation.TRUNCATE_PARTITION); }
20927+
LOOKAHEAD(2) (
20928+
<K_TRUNCATE> { operation = AlterOperation.TRUNCATE_PARTITION; }
20929+
| <K_ANALYZE> { operation = AlterOperation.ANALYZE_PARTITION; }
20930+
| <K_CHECK> { operation = AlterOperation.CHECK_PARTITION; }
20931+
| <K_OPTIMIZE> { operation = AlterOperation.OPTIMIZE_PARTITION; }
20932+
| <K_REBUILD> { operation = AlterOperation.REBUILD_PARTITION; }
20933+
| <K_REPAIR> { operation = AlterOperation.REPAIR_PARTITION; }
20934+
)
20935+
<K_PARTITION> { alterExp.setOperation(operation); }
20936+
[
20937+
LOOKAHEAD({ operation != AlterOperation.TRUNCATE_PARTITION
20938+
&& operation != AlterOperation.CHECK_PARTITION
20939+
&& isPartitionBinlogModifierAhead() })
20940+
PartitionBinlogModifier(alterExp)
20941+
]
2091320942
partitions=PartitionNamesList() { alterExp.setPartitions(partitions); }
2091420943
|
20915-
LOOKAHEAD(2) <K_COALESCE> <K_PARTITION> tk=<S_LONG> {
20916-
alterExp.setOperation(AlterOperation.COALESCE_PARTITION);
20917-
alterExp.setCoalescePartitionCount(Integer.valueOf(tk.image));
20918-
}
20944+
LOOKAHEAD(2) <K_COALESCE> <K_PARTITION> { alterExp.setOperation(AlterOperation.COALESCE_PARTITION); }
20945+
[ PartitionBinlogModifier(alterExp) ]
20946+
tk=<S_LONG> { alterExp.setPartitionCount(Integer.valueOf(tk.image)); }
2091920947
|
2092020948
LOOKAHEAD(2) <K_REORGANIZE> <K_PARTITION>
20949+
[ LOOKAHEAD({ isPartitionBinlogModifierAhead() }) PartitionBinlogModifier(alterExp) ]
2092120950
partitions=PartitionNamesList() <K_INTO> partitionDefinition=PartitionDefinitions() {
2092220951
alterExp.setOperation(AlterOperation.REORGANIZE_PARTITION);
2092320952
alterExp.setPartitions(partitions);
@@ -20942,21 +20971,6 @@ AlterExpression AlterExpressionPartitionOp():
2094220971
alterExp.setPartitions(partitions);
2094320972
alterExp.setExchangeTable(exchangeTable);
2094420973
}
20945-
|
20946-
LOOKAHEAD(2) <K_ANALYZE> <K_PARTITION> { alterExp.setOperation(AlterOperation.ANALYZE_PARTITION); }
20947-
partitions=PartitionNamesList() { alterExp.setPartitions(partitions); }
20948-
|
20949-
LOOKAHEAD(2) <K_CHECK> <K_PARTITION> { alterExp.setOperation(AlterOperation.CHECK_PARTITION); }
20950-
partitions=PartitionNamesList() { alterExp.setPartitions(partitions); }
20951-
|
20952-
LOOKAHEAD(2) <K_OPTIMIZE> <K_PARTITION> { alterExp.setOperation(AlterOperation.OPTIMIZE_PARTITION); }
20953-
partitions=PartitionNamesList() { alterExp.setPartitions(partitions); }
20954-
|
20955-
LOOKAHEAD(2) <K_REBUILD> <K_PARTITION> { alterExp.setOperation(AlterOperation.REBUILD_PARTITION); }
20956-
partitions=PartitionNamesList() { alterExp.setPartitions(partitions); }
20957-
|
20958-
LOOKAHEAD(2) <K_REPAIR> <K_PARTITION> { alterExp.setOperation(AlterOperation.REPAIR_PARTITION); }
20959-
partitions=PartitionNamesList() { alterExp.setPartitions(partitions); }
2096020974
|
2096120975
LOOKAHEAD(2) <K_REMOVE> <K_PARTITIONING> { alterExp.setOperation(AlterOperation.REMOVE_PARTITIONING); }
2096220976
|
@@ -20968,6 +20982,42 @@ AlterExpression AlterExpressionPartitionOp():
2096820982
{ return alterExp; }
2096920983
}
2097020984

20985+
/**
20986+
* Parses MySQL ADD PARTITION [NO_WRITE_TO_BINLOG | LOCAL] {(definitions) | PARTITIONS n}
20987+
* after ADD.
20988+
*/
20989+
AlterExpressionPartition AddPartition():
20990+
{
20991+
AlterExpressionPartition alterExp = new AlterExpressionPartition();
20992+
List<PartitionDefinition> partitionDefinitions;
20993+
Token tk;
20994+
}
20995+
{
20996+
<K_PARTITION> { alterExp.setOperation(AlterOperation.ADD_PARTITION); }
20997+
[ PartitionBinlogModifier(alterExp) ]
20998+
(
20999+
partitionDefinitions=PartitionDefinitions() {
21000+
alterExp.setPartitionDefinitions(partitionDefinitions);
21001+
}
21002+
|
21003+
<K_PARTITIONS> tk=<S_LONG> { alterExp.setPartitionCount(Integer.valueOf(tk.image)); }
21004+
)
21005+
{ return alterExp; }
21006+
}
21007+
21008+
/** Parses MySQL's opt_no_write_to_binlog of a partition operation. */
21009+
void PartitionBinlogModifier(AlterExpressionPartition alterExp):
21010+
{
21011+
Token tk;
21012+
}
21013+
{
21014+
( tk=<K_NO_WRITE_TO_BINLOG> | tk=<K_LOCAL> )
21015+
{
21016+
alterExp.setModifier(TableMaintenanceStatement.Modifier.valueOf(
21017+
tk.image.toUpperCase(Locale.ROOT)));
21018+
}
21019+
}
21020+
2097121021
/**
2097221022
* Parses ADD/ALTER/MODIFY operations within ALTER TABLE.
2097321023
* Handles: PRIMARY KEY, INDEX/KEY, SPATIAL/FULLTEXT, column COMMENT,
@@ -20989,7 +21039,6 @@ AlterExpression AlterExpressionAddAlterModify():
2098921039
AlterExpression.ColumnDataType alterExpressionColumnDataType = null;
2099021040
AlterExpression.ColumnDropNotNull alterExpressionColumnDropNotNull = null;
2099121041
List<IndexSpecOption> indexSpec = new ArrayList<IndexSpecOption>();
20992-
List<PartitionDefinition> partitionDefinition = null;
2099321042
}
2099421043
{
2099521044
(
@@ -21052,15 +21101,10 @@ AlterExpression AlterExpressionAddAlterModify():
2105221101
sk3=RelObjectName() <K_COMMENT> tk=<S_CHAR_LITERAL> { alterExp.withColumnName(sk3).withCommentText(tk.image); }
2105321102
)
2105421103
|
21055-
LOOKAHEAD(3) (
21056-
<K_PARTITION> {
21057-
alterExp = new AlterExpressionPartition();
21058-
alterExp.setOperation(AlterOperation.ADD_PARTITION);
21059-
}
21060-
partitionDefinition=PartitionDefinitions() {
21061-
alterExp.setPartitionDefinitions(partitionDefinition);
21062-
}
21063-
)
21104+
LOOKAHEAD(<K_PARTITION> [ <K_NO_WRITE_TO_BINLOG> | <K_LOCAL> ]
21105+
( "(" <K_PARTITION> | <K_PARTITIONS> <S_LONG> ),
21106+
{ alterExp.getOperation() == AlterOperation.ADD })
21107+
alterExp=AddPartition()
2106421108
|
2106521109
LOOKAHEAD(3) (
2106621110
( LOOKAHEAD(2)

0 commit comments

Comments
 (0)