Skip to content

feat: support MySQL ALTER TABLE ... PARTITION BY syntax #2210

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

Merged
merged 1 commit into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
package net.sf.jsqlparser.statement.alter;

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.ReferentialAction;
import net.sf.jsqlparser.statement.ReferentialAction.Action;
import net.sf.jsqlparser.statement.ReferentialAction.Type;
Expand Down Expand Up @@ -75,6 +76,11 @@ public class AlterExpression implements Serializable {

private boolean useIfNotExists = false;

private String partitionType;
private Expression partitionExpression;
private List<String> partitionColumns;


public Index getOldIndex() {
return oldIndex;
}
Expand Down Expand Up @@ -494,6 +500,30 @@ public AlterExpression withUserIfNotExists(boolean userIfNotExists) {
return this;
}

public void setPartitionType(String partitionType) {
this.partitionType = partitionType;
}

public String getPartitionType() {
return partitionType;
}

public void setPartitionExpression(Expression partitionExpression) {
this.partitionExpression = partitionExpression;
}

public Expression getPartitionExpression() {
return partitionExpression;
}

public void setPartitionColumns(List<String> partitionColumns) {
this.partitionColumns = partitionColumns;
}

public List<String> getPartitionColumns() {
return partitionColumns;
}

@Override
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity",
"PMD.ExcessiveMethodLength", "PMD.SwitchStmtsShouldHaveDefault"})
Expand Down Expand Up @@ -601,6 +631,28 @@ public String toString() {
} else if (operation == AlterOperation.TRUNCATE_PARTITION
&& partitions != null) {
b.append("TRUNCATE PARTITION ").append(PlainSelect.getStringList(partitions));
} else if (operation == AlterOperation.PARTITION_BY) {
b.append("PARTITION BY ").append(partitionType).append(" ");
if (partitionExpression != null) {
b.append("(").append(partitionExpression).append(") ");
} else if (partitionColumns != null && !partitionColumns.isEmpty()) {
b.append("COLUMNS(").append(String.join(", ", partitionColumns)).append(") ");
}
b.append("(");
for (int i = 0; i < partitionDefinitions.size(); i++) {
PartitionDefinition partition = partitionDefinitions.get(i);
b.append("PARTITION ").append(partition.getPartitionName())
.append(" ").append(partition.getPartitionOperation())
.append(" (").append(PlainSelect.getStringList(partition.getValues()))
.append(")");
if (partition.getStorageEngine() != null) {
b.append(" ENGINE = ").append(partition.getStorageEngine());
}
if (i < partitionDefinitions.size() - 1) {
b.append(", ");
}
}
b.append(")");
} else {
if (operation == AlterOperation.COMMENT_WITH_EQUAL_SIGN) {
b.append("COMMENT =").append(" ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
package net.sf.jsqlparser.statement.alter;

public enum AlterOperation {
ADD, ALTER, DROP, DROP_PRIMARY_KEY, DROP_UNIQUE, DROP_FOREIGN_KEY, MODIFY, CHANGE, CONVERT, COLLATE, ALGORITHM, RENAME, RENAME_TABLE, RENAME_INDEX, RENAME_KEY, RENAME_CONSTRAINT, COMMENT, COMMENT_WITH_EQUAL_SIGN, UNSPECIFIC, ADD_PARTITION, DROP_PARTITION, TRUNCATE_PARTITION, SET_TABLE_OPTION, ENGINE, FORCE, LOCK, DISCARD_TABLESPACE, IMPORT_TABLESPACE, DISABLE_KEYS, ENABLE_KEYS;
ADD, ALTER, DROP, DROP_PRIMARY_KEY, DROP_UNIQUE, DROP_FOREIGN_KEY, MODIFY, CHANGE, CONVERT, COLLATE, ALGORITHM, RENAME, RENAME_TABLE, RENAME_INDEX, RENAME_KEY, RENAME_CONSTRAINT, COMMENT, COMMENT_WITH_EQUAL_SIGN, UNSPECIFIC, ADD_PARTITION, DROP_PARTITION, PARTITION_BY, TRUNCATE_PARTITION, SET_TABLE_OPTION, ENGINE, FORCE, LOCK, DISCARD_TABLESPACE, IMPORT_TABLESPACE, DISABLE_KEYS, ENABLE_KEYS;

public static AlterOperation from(String operation) {
return Enum.valueOf(AlterOperation.class, operation.toUpperCase());
Expand Down
31 changes: 26 additions & 5 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -7638,6 +7638,7 @@ List<PartitionDefinition> PartitionDefinitions():
String partitionName = null;
String partitionOperation = null;
String storageEngine = null;
Expression exp = null;
}
{
"("
Expand All @@ -7651,10 +7652,9 @@ List<PartitionDefinition> PartitionDefinitions():
(
<K_LESS> <K_THAN>
(
"("
( tk=<S_CHAR_LITERAL> { values.add(tk.image); }
| tk=<S_LONG> { values.add(tk.image); }
[ "," ] )* ")"
"(" exp = Expression() ")"{
values.add(exp.toString());
}
| <K_MAXVALUE> { values.add("MAXVALUE"); }
) {
partitionOperation = "VALUES LESS THAN";
Expand All @@ -7673,7 +7673,6 @@ List<PartitionDefinition> PartitionDefinitions():
}
}


List<String> PartitionNamesList() :
{
Token tk;
Expand Down Expand Up @@ -8134,6 +8133,28 @@ AlterExpression AlterExpression():
}
}
)
|
LOOKAHEAD(2) (
<K_PARTITION> <K_BY> {
alterExp.setOperation(AlterOperation.PARTITION_BY);
}
<K_RANGE> {
alterExp.setPartitionType("RANGE");
Expression exp = null;
}
(
"(" exp=Expression() ")" {
alterExp.setPartitionExpression(exp);
}
|
<K_COLUMNS> columnNames=ColumnsNamesList() {
alterExp.setPartitionColumns(columnNames);
}
)
partitionDefinition=PartitionDefinitions() {
alterExp.setPartitionDefinitions(partitionDefinition);
}
)
|
LOOKAHEAD(2)
(<K_RENAME> ((<K_INDEX> {alterExp.setOperation(AlterOperation.RENAME_INDEX);}
Expand Down
105 changes: 105 additions & 0 deletions src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1500,4 +1500,109 @@ public void testAlterTableKeys() throws JSQLParserException {
AlterExpression alterExpEnable = alterEnable.getAlterExpressions().get(0);
assertEquals(AlterOperation.ENABLE_KEYS, alterExpEnable.getOperation());
}

@Test
public void testAlterTablePartitionByRangeColumns() throws JSQLParserException {
String sql = "ALTER TABLE `payment_lock` " +
"PARTITION BY RANGE COLUMNS(`created_at`) (" +
"PARTITION p20210217 VALUES LESS THAN ('20210218') ENGINE = InnoDB, " +
"PARTITION p20210218 VALUES LESS THAN ('20210219') ENGINE = InnoDB);";
Statement stmt = CCJSqlParserUtil.parse(sql);
assertInstanceOf(Alter.class, stmt);
Alter alter = (Alter) stmt;
assertEquals("`payment_lock`", alter.getTable().getFullyQualifiedName());

List<AlterExpression> alterExpressions = alter.getAlterExpressions();
assertNotNull(alterExpressions);
assertEquals(1, alterExpressions.size());

AlterExpression partitionExp = alterExpressions.get(0);
assertEquals(AlterOperation.PARTITION_BY, partitionExp.getOperation());
List<PartitionDefinition> partitions = partitionExp.getPartitionDefinitions();
assertNotNull(partitions);
assertEquals(2, partitions.size());

assertEquals("p20210217", partitions.get(0).getPartitionName());
assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation());
assertEquals(Collections.singletonList("'20210218'"), partitions.get(0).getValues());

assertEquals("p20210218", partitions.get(1).getPartitionName());
assertEquals("VALUES LESS THAN", partitions.get(1).getPartitionOperation());
assertEquals(Collections.singletonList("'20210219'"), partitions.get(1).getValues());

assertSqlCanBeParsedAndDeparsed(sql);
}

@Test
public void testAlterTablePartitionByRangeUnixTimestamp() throws JSQLParserException {
String sql = "ALTER TABLE `test`.`pipeline_service_metadata_history` " +
"PARTITION BY RANGE (FLOOR(UNIX_TIMESTAMP(requested_at))) (" +
"PARTITION p202104 VALUES LESS THAN (UNIX_TIMESTAMP('2021-05-01 00:00:00')) ENGINE = InnoDB, "
+
"PARTITION p202105 VALUES LESS THAN (UNIX_TIMESTAMP('2021-06-01 00:00:00')) ENGINE = InnoDB);";
Statement stmt = CCJSqlParserUtil.parse(sql);
assertInstanceOf(Alter.class, stmt);
Alter alter = (Alter) stmt;
assertEquals("`test`.`pipeline_service_metadata_history`",
alter.getTable().getFullyQualifiedName());

List<AlterExpression> alterExpressions = alter.getAlterExpressions();
assertNotNull(alterExpressions);
assertEquals(1, alterExpressions.size());

AlterExpression partitionExp = alterExpressions.get(0);
assertEquals(AlterOperation.PARTITION_BY, partitionExp.getOperation());
List<PartitionDefinition> partitions = partitionExp.getPartitionDefinitions();
assertNotNull(partitions);
assertEquals(2, partitions.size());

assertEquals("p202104", partitions.get(0).getPartitionName());
assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation());
assertEquals(Collections.singletonList("UNIX_TIMESTAMP('2021-05-01 00:00:00')"),
partitions.get(0).getValues());

assertEquals("p202105", partitions.get(1).getPartitionName());
assertEquals("VALUES LESS THAN", partitions.get(1).getPartitionOperation());
assertEquals(Collections.singletonList("UNIX_TIMESTAMP('2021-06-01 00:00:00')"),
partitions.get(1).getValues());

assertSqlCanBeParsedAndDeparsed(sql);
}

@Test
public void testAlterTablePartitionByRangeUnixTimestamp2() throws JSQLParserException {
String sql = "ALTER TABLE MP_MNEWS.PUR_MNEWS_CONTS " +
"PARTITION BY RANGE (UNIX_TIMESTAMP(REG_DATE_TS)) (" +
"PARTITION p202007 VALUES LESS THAN (1596207600) ENGINE = InnoDB, " +
"PARTITION p202008 VALUES LESS THAN (1598886000) ENGINE = InnoDB, " +
"PARTITION p202009 VALUES LESS THAN (1601478000) ENGINE = InnoDB);";
Statement stmt = CCJSqlParserUtil.parse(sql);
assertInstanceOf(Alter.class, stmt);
Alter alter = (Alter) stmt;
assertEquals("MP_MNEWS.PUR_MNEWS_CONTS", alter.getTable().getFullyQualifiedName());

List<AlterExpression> alterExpressions = alter.getAlterExpressions();
assertNotNull(alterExpressions);
assertEquals(1, alterExpressions.size());

AlterExpression partitionExp = alterExpressions.get(0);
assertEquals(AlterOperation.PARTITION_BY, partitionExp.getOperation());
List<PartitionDefinition> partitions = partitionExp.getPartitionDefinitions();
assertNotNull(partitions);
assertEquals(3, partitions.size());

assertEquals("p202007", partitions.get(0).getPartitionName());
assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation());
assertEquals(Collections.singletonList("1596207600"), partitions.get(0).getValues());

assertEquals("p202008", partitions.get(1).getPartitionName());
assertEquals("VALUES LESS THAN", partitions.get(1).getPartitionOperation());
assertEquals(Collections.singletonList("1598886000"), partitions.get(1).getValues());

assertEquals("p202009", partitions.get(2).getPartitionName());
assertEquals("VALUES LESS THAN", partitions.get(2).getPartitionOperation());
assertEquals(Collections.singletonList("1601478000"), partitions.get(2).getValues());

assertSqlCanBeParsedAndDeparsed(sql);
}
}
Loading