Skip to content

Commit 25d2f36

Browse files
committed
fix(parser): model MySQL ALTER TABLE partition operations
1 parent bb2f269 commit 25d2f36

4 files changed

Lines changed: 476 additions & 43 deletions

File tree

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

Lines changed: 267 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,44 @@
99
*/
1010
package net.sf.jsqlparser.statement.alter;
1111

12+
import java.util.ArrayList;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.List;
16+
import java.util.Optional;
1217
import net.sf.jsqlparser.schema.Table;
1318
import net.sf.jsqlparser.statement.create.table.PartitionBound;
19+
import net.sf.jsqlparser.statement.create.table.PartitionDefinition;
20+
import net.sf.jsqlparser.statement.create.table.TablePartitioning;
21+
import net.sf.jsqlparser.statement.select.PlainSelect;
1422

1523
/**
16-
* Internal subclass for partition maintenance operations within ALTER TABLE. Handles TRUNCATE,
17-
* COALESCE, REORGANIZE, EXCHANGE, ANALYZE, CHECK, OPTIMIZE, REBUILD, REPAIR PARTITION, PARTITION
18-
* BY, and REMOVE PARTITIONING.
24+
* Structured model for partition operations within {@code ALTER TABLE}.
25+
*
26+
* <p>
27+
* MySQL partition names and definitions remain available through the inherited
28+
* {@link #getPartitions()} and {@link #getPartitionDefinitions()} methods. This subtype adds
29+
* structured access to the complete {@code PARTITION BY} clause, the table used by
30+
* {@code EXCHANGE PARTITION}, and its validation mode. It also models PostgreSQL
31+
* {@code ATTACH/DETACH PARTITION} operations.
1932
*/
2033
public class AlterExpressionPartition extends AlterExpression {
2134

2235
public enum DetachMode {
2336
CONCURRENTLY, FINALIZE
2437
}
2538

39+
public enum ExchangeValidationMode {
40+
WITH, WITHOUT
41+
}
42+
2643
private Table partitionTable;
2744
private PartitionBound partitionBound;
2845
private DetachMode detachMode;
46+
private TablePartitioning partitioning;
47+
private Integer coalescePartitionCount;
48+
private Table exchangeTable;
49+
private ExchangeValidationMode exchangeValidationMode;
2950

3051
public Table getPartitionTable() {
3152
return partitionTable;
@@ -51,6 +72,136 @@ public void setDetachMode(DetachMode detachMode) {
5172
this.detachMode = detachMode;
5273
}
5374

75+
/**
76+
* Returns the full MySQL partitioning clause for a {@link AlterOperation#PARTITION_BY}
77+
* operation.
78+
*/
79+
public TablePartitioning getPartitioning() {
80+
return partitioning;
81+
}
82+
83+
public void setPartitioning(TablePartitioning partitioning) {
84+
this.partitioning = partitioning;
85+
if (partitioning != null) {
86+
setPartitionType(partitioning.getType() != null
87+
? partitioning.getType().toString()
88+
: null);
89+
setPartitionExpression(partitioning.getExpression() != null
90+
? partitioning.getExpression()
91+
: partitioning.getExpressionList());
92+
if (partitioning.getColumns() != null) {
93+
List<String> partitionColumns = new ArrayList<>();
94+
partitioning.getColumns().forEach(
95+
column -> partitionColumns.add(column.getFullyQualifiedName()));
96+
setPartitionColumns(partitionColumns);
97+
} else {
98+
setPartitionColumns(null);
99+
}
100+
setPartitionDefinitions(partitioning.getPartitionDefinitions());
101+
}
102+
}
103+
104+
/**
105+
* Convenience alias that names the inherited MySQL partition-name list explicitly.
106+
*/
107+
public List<String> getPartitionNames() {
108+
return getPartitions();
109+
}
110+
111+
public void setPartitionNames(List<String> partitionNames) {
112+
setPartitions(partitionNames);
113+
}
114+
115+
/**
116+
* Returns whether the operation targets every partition rather than named partitions.
117+
*/
118+
public boolean isAllPartitions() {
119+
List<String> partitionNames = getPartitionNames();
120+
return partitionNames != null && partitionNames.size() == 1
121+
&& "ALL".equalsIgnoreCase(partitionNames.get(0));
122+
}
123+
124+
public void setAllPartitions(boolean allPartitions) {
125+
if (allPartitions) {
126+
setPartitionNames(Collections.singletonList("ALL"));
127+
} else if (isAllPartitions()) {
128+
setPartitionNames(null);
129+
}
130+
}
131+
132+
/**
133+
* Returns the number of partitions added by a MySQL {@code COALESCE PARTITION} operation.
134+
* Unlike the legacy primitive accessor, this is {@code null} when no count was supplied.
135+
*/
136+
public Integer getCoalescePartitionCount() {
137+
return coalescePartitionCount;
138+
}
139+
140+
public void setCoalescePartitionCount(Integer coalescePartitionCount) {
141+
this.coalescePartitionCount = coalescePartitionCount;
142+
if (coalescePartitionCount != null) {
143+
super.setCoalescePartitionNumber(coalescePartitionCount);
144+
}
145+
}
146+
147+
@Override
148+
public void setCoalescePartitionNumber(int coalescePartitionNumber) {
149+
super.setCoalescePartitionNumber(coalescePartitionNumber);
150+
this.coalescePartitionCount = coalescePartitionNumber;
151+
}
152+
153+
public Table getExchangeTable() {
154+
return exchangeTable;
155+
}
156+
157+
public void setExchangeTable(Table exchangeTable) {
158+
this.exchangeTable = exchangeTable;
159+
super.setExchangePartitionTableName(
160+
exchangeTable != null ? exchangeTable.getFullyQualifiedName() : null);
161+
}
162+
163+
@Override
164+
public void setExchangePartitionTableName(String exchangePartitionTableName) {
165+
super.setExchangePartitionTableName(exchangePartitionTableName);
166+
this.exchangeTable = exchangePartitionTableName != null
167+
? new Table(exchangePartitionTableName)
168+
: null;
169+
}
170+
171+
public ExchangeValidationMode getExchangeValidationMode() {
172+
return exchangeValidationMode;
173+
}
174+
175+
public void setExchangeValidationMode(ExchangeValidationMode exchangeValidationMode) {
176+
this.exchangeValidationMode = exchangeValidationMode;
177+
super.setExchangePartitionWithValidation(
178+
exchangeValidationMode == ExchangeValidationMode.WITH);
179+
super.setExchangePartitionWithoutValidation(
180+
exchangeValidationMode == ExchangeValidationMode.WITHOUT);
181+
}
182+
183+
@Override
184+
public void setExchangePartitionWithValidation(boolean exchangePartitionWithValidation) {
185+
super.setExchangePartitionWithValidation(exchangePartitionWithValidation);
186+
if (exchangePartitionWithValidation) {
187+
exchangeValidationMode = ExchangeValidationMode.WITH;
188+
super.setExchangePartitionWithoutValidation(false);
189+
} else if (exchangeValidationMode == ExchangeValidationMode.WITH) {
190+
exchangeValidationMode = null;
191+
}
192+
}
193+
194+
@Override
195+
public void setExchangePartitionWithoutValidation(boolean exchangePartitionWithoutValidation) {
196+
super.setExchangePartitionWithoutValidation(exchangePartitionWithoutValidation);
197+
if (exchangePartitionWithoutValidation) {
198+
exchangeValidationMode = ExchangeValidationMode.WITHOUT;
199+
super.setExchangePartitionWithValidation(false);
200+
} else if (exchangeValidationMode == ExchangeValidationMode.WITHOUT) {
201+
exchangeValidationMode = null;
202+
}
203+
}
204+
54205
public AlterExpressionPartition withPartitionTable(Table partitionTable) {
55206
setPartitionTable(partitionTable);
56207
return this;
@@ -66,18 +217,121 @@ public AlterExpressionPartition withDetachMode(DetachMode detachMode) {
66217
return this;
67218
}
68219

220+
@Override
221+
public AlterExpressionPartition withOperation(AlterOperation operation) {
222+
setOperation(operation);
223+
return this;
224+
}
225+
226+
public AlterExpressionPartition withPartitioning(TablePartitioning partitioning) {
227+
setPartitioning(partitioning);
228+
return this;
229+
}
230+
231+
public AlterExpressionPartition withPartitionNames(List<String> partitionNames) {
232+
setPartitionNames(partitionNames);
233+
return this;
234+
}
235+
236+
public AlterExpressionPartition withAllPartitions(boolean allPartitions) {
237+
setAllPartitions(allPartitions);
238+
return this;
239+
}
240+
241+
public AlterExpressionPartition withCoalescePartitionCount(Integer coalescePartitionCount) {
242+
setCoalescePartitionCount(coalescePartitionCount);
243+
return this;
244+
}
245+
246+
public AlterExpressionPartition withExchangeTable(Table exchangeTable) {
247+
setExchangeTable(exchangeTable);
248+
return this;
249+
}
250+
251+
public AlterExpressionPartition withExchangeValidationMode(
252+
ExchangeValidationMode exchangeValidationMode) {
253+
setExchangeValidationMode(exchangeValidationMode);
254+
return this;
255+
}
256+
257+
public AlterExpressionPartition withPartitionDefinitions(
258+
List<PartitionDefinition> partitionDefinitions) {
259+
setPartitionDefinitions(partitionDefinitions);
260+
return this;
261+
}
262+
263+
public AlterExpressionPartition addPartitionNames(String... partitionNames) {
264+
List<String> collection =
265+
Optional.ofNullable(getPartitionNames()).orElseGet(ArrayList::new);
266+
Collections.addAll(collection, partitionNames);
267+
return withPartitionNames(collection);
268+
}
269+
270+
public AlterExpressionPartition addPartitionNames(Collection<String> partitionNames) {
271+
List<String> collection =
272+
Optional.ofNullable(getPartitionNames()).orElseGet(ArrayList::new);
273+
collection.addAll(partitionNames);
274+
return withPartitionNames(collection);
275+
}
276+
277+
public AlterExpressionPartition addPartitionDefinitions(
278+
PartitionDefinition... partitionDefinitions) {
279+
List<PartitionDefinition> collection = Optional.ofNullable(getPartitionDefinitions())
280+
.orElseGet(ArrayList::new);
281+
Collections.addAll(collection, partitionDefinitions);
282+
return withPartitionDefinitions(collection);
283+
}
284+
285+
public AlterExpressionPartition addPartitionDefinitions(
286+
Collection<? extends PartitionDefinition> partitionDefinitions) {
287+
List<PartitionDefinition> collection = Optional.ofNullable(getPartitionDefinitions())
288+
.orElseGet(ArrayList::new);
289+
collection.addAll(partitionDefinitions);
290+
return withPartitionDefinitions(collection);
291+
}
292+
69293
@Override
70294
protected void appendBody(StringBuilder b) {
71-
if (getOperation() == AlterOperation.ATTACH_PARTITION) {
72-
b.append("ATTACH PARTITION ").append(partitionTable).append(" ")
73-
.append(partitionBound);
74-
} else if (getOperation() == AlterOperation.DETACH_PARTITION) {
75-
b.append("DETACH PARTITION ").append(partitionTable);
76-
if (detachMode != null) {
77-
b.append(" ").append(detachMode);
78-
}
79-
} else {
80-
toStringPartition(b);
295+
switch (getOperation()) {
296+
case ADD_PARTITION:
297+
b.append("ADD PARTITION ")
298+
.append(PlainSelect.getStringList(getPartitionDefinitions(), true, true));
299+
break;
300+
case DROP_PARTITION:
301+
b.append("DROP PARTITION ")
302+
.append(PlainSelect.getStringList(getPartitionNames()));
303+
break;
304+
case ATTACH_PARTITION:
305+
b.append("ATTACH PARTITION ").append(partitionTable).append(" ")
306+
.append(partitionBound);
307+
break;
308+
case DETACH_PARTITION:
309+
b.append("DETACH PARTITION ").append(partitionTable);
310+
if (detachMode != null) {
311+
b.append(" ").append(detachMode);
312+
}
313+
break;
314+
case PARTITION_BY:
315+
if (partitioning != null) {
316+
b.append(partitioning);
317+
} else {
318+
toStringPartition(b);
319+
}
320+
break;
321+
case EXCHANGE_PARTITION:
322+
if (exchangeTable != null) {
323+
b.append("EXCHANGE PARTITION ").append(getPartitionNames().get(0))
324+
.append(" WITH TABLE ").append(exchangeTable);
325+
if (exchangeValidationMode != null) {
326+
b.append(" ").append(exchangeValidationMode).append(" VALIDATION");
327+
}
328+
} else {
329+
toStringPartition(b);
330+
}
331+
break;
332+
default:
333+
toStringPartition(b);
334+
break;
81335
}
82336
}
83337
}

src/main/java/net/sf/jsqlparser/statement/create/table/TablePartitioning.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import net.sf.jsqlparser.statement.select.PlainSelect;
2222

2323
/**
24-
* MySQL table partitioning options used by {@code CREATE TABLE}.
24+
* MySQL table partitioning options used by {@code CREATE TABLE} and {@code ALTER TABLE}.
2525
*/
2626
public class TablePartitioning implements Serializable {
2727

0 commit comments

Comments
 (0)