Skip to content

Commit 1371418

Browse files
committed
Use one foreign-key state in ALTER TABLE
Delegate legacy FK accessors to the structured constraint, remove copied grammar state and the fallback renderer, and validate the current reference. Preserve quoted name parts and protect existing non-FK definitions. This follow-up is based on PR #2747 at 9be3636. Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 9be3636 commit 1371418

6 files changed

Lines changed: 482 additions & 92 deletions

File tree

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

Lines changed: 111 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@
1414
import java.util.Arrays;
1515
import java.util.Collection;
1616
import java.util.Collections;
17-
import java.util.LinkedHashSet;
1817
import java.util.List;
1918
import java.util.Optional;
20-
import java.util.Set;
2119
import java.util.function.Consumer;
2220
import java.util.stream.Collectors;
2321
import net.sf.jsqlparser.expression.Expression;
@@ -27,6 +25,7 @@
2725
import net.sf.jsqlparser.statement.ReferentialAction.Type;
2826
import net.sf.jsqlparser.statement.create.table.ColDataType;
2927
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
28+
import net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint;
3029
import net.sf.jsqlparser.statement.create.table.Index;
3130
import net.sf.jsqlparser.statement.create.table.NamedConstraint;
3231
import net.sf.jsqlparser.statement.create.table.KeyConstraint;
@@ -42,7 +41,6 @@ public enum TableRenameKeyword {
4241
NONE, TO, AS
4342
}
4443

45-
private final Set<ReferentialAction> referentialActions = new LinkedHashSet<>(2);
4644
private AlterOperation operation;
4745
private String optionalSpecifier;
4846
private Table newTable;
@@ -67,33 +65,6 @@ public enum TableRenameKeyword {
6765
private String constraintName;
6866
private boolean usingIfExists;
6967

70-
/**
71-
* @deprecated Use {@link #setConstraint(NamedConstraint)} with a
72-
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
73-
*/
74-
@Deprecated
75-
private List<String> fkColumns;
76-
77-
/**
78-
* @deprecated Use {@link #setConstraint(NamedConstraint)} with a
79-
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
80-
*/
81-
@Deprecated
82-
private String fkSourceSchema;
83-
84-
/**
85-
* @deprecated Use {@link #setConstraint(NamedConstraint)} with a
86-
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
87-
*/
88-
@Deprecated
89-
private String fkSourceTable;
90-
91-
/**
92-
* @deprecated Use {@link #setConstraint(NamedConstraint)} with a
93-
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
94-
*/
95-
@Deprecated
96-
private List<String> fkSourceColumns;
9768
private boolean uk;
9869
private boolean ukTypeSpecified;
9970
private boolean useEqual;
@@ -178,16 +149,20 @@ public void hasColumns(boolean hasColumns) {
178149
*/
179150
@Deprecated
180151
public String getFkSourceSchema() {
181-
return fkSourceSchema;
152+
Table table = getForeignKeyTable();
153+
return table == null ? null : table.getSchemaName();
182154
}
183155

184156
/**
157+
* Updates only the referenced schema identifier, preserving its quoting and the table's other
158+
* name parts. Uses the creation and replacement policy of {@link #setFkColumns(List)}.
159+
*
185160
* @deprecated Use {@link #setConstraint(NamedConstraint)} with a
186161
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
187162
*/
188163
@Deprecated
189164
public void setFkSourceSchema(String fkSourceSchema) {
190-
this.fkSourceSchema = fkSourceSchema;
165+
setForeignKeyTablePart(fkSourceSchema, 1);
191166
}
192167

193168
public String getCommentText() {
@@ -223,8 +198,13 @@ public void setOptionalSpecifier(String optionalSpecifier) {
223198
}
224199

225200
/**
201+
* Updates the stored foreign key's referential action without replacing its object or column
202+
* list. A null action removes it. Uses the creation and replacement policy of
203+
* {@link #setFkColumns(List)}.
204+
*
226205
* @param type
227206
* @param action
207+
* @throws IllegalStateException if a non-null action would replace a different definition
228208
* @deprecated Standalone FK fields are deprecated. Use a
229209
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} via
230210
* {@link #setConstraint(NamedConstraint)} instead.
@@ -253,28 +233,27 @@ public void removeReferentialAction(Type type) {
253233
}
254234

255235
/**
236+
* Returns the action owned by the stored foreign key, or null when absent. Changes to the
237+
* returned object are reflected in the constraint.
238+
*
256239
* @param type
257240
* @return
258241
* @deprecated Standalone FK fields are deprecated.
259242
*/
260243
@Deprecated
261244
public ReferentialAction getReferentialAction(Type type) {
262-
return referentialActions.stream()
263-
.filter(ra -> type.equals(ra.getType()))
264-
.findFirst()
265-
.orElse(null);
245+
ForeignKeyConstraint foreignKey = getForeignKeyConstraint();
246+
return foreignKey == null ? null : foreignKey.getReferentialAction(type);
266247
}
267248

268249
private void setReferentialAction(Type type, Action action, boolean set) {
269-
ReferentialAction found = getReferentialAction(type);
270-
if (set) {
271-
if (found == null) {
272-
referentialActions.add(new ReferentialAction(type, action));
250+
ForeignKeyConstraint foreignKey = foreignKeyForUpdate(set && action != null);
251+
if (foreignKey != null) {
252+
if (set && action != null) {
253+
foreignKey.setReferentialAction(type, action);
273254
} else {
274-
found.setAction(action);
255+
foreignKey.removeReferentialAction(type);
275256
}
276-
} else if (found != null) {
277-
referentialActions.remove(found);
278257
}
279258
}
280259

@@ -339,21 +318,41 @@ public void setOnDeleteSetNull(boolean onDeleteSetNull) {
339318
}
340319

341320
/**
342-
* @deprecated Use {@link #getConstraint()} with
343-
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
321+
* Returns a rendered snapshot of the stored foreign key's elements, or null when absent.
322+
* Changing the snapshot does not change the constraint; use {@link #setFkColumns(List)} to
323+
* replace its keys, or {@link ForeignKeyConstraint#getColumns()} for structured edits.
324+
*
325+
* @deprecated Use {@link #getConstraint()} with a {@link ForeignKeyConstraint} instead.
344326
*/
345327
@Deprecated
346328
public List<String> getFkColumns() {
347-
return fkColumns;
329+
ForeignKeyConstraint foreignKey = getForeignKeyConstraint();
330+
return foreignKey == null || foreignKey.getColumns() == null ? null
331+
: foreignKey.getColumnsNames();
348332
}
349333

350334
/**
335+
* Replaces the stored foreign key's elements with opaque names without parsing or retaining
336+
* element attributes. A non-null value creates a foreign key when no definition exists, but
337+
* never replaces a different constraint or an ordinary index; use
338+
* {@link #setConstraint(NamedConstraint)} to replace a definition explicitly. A null value
339+
* clears existing foreign-key elements without creating a constraint. Other actions and their
340+
* rendering precedence are unchanged.
341+
*
342+
* @throws IllegalStateException if a non-null value would replace a different definition
351343
* @deprecated Use {@link #setConstraint(NamedConstraint)} with a
352344
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
353345
*/
354346
@Deprecated
355347
public void setFkColumns(List<String> fkColumns) {
356-
this.fkColumns = fkColumns;
348+
ForeignKeyConstraint foreignKey = foreignKeyForUpdate(fkColumns != null);
349+
if (foreignKey != null) {
350+
if (fkColumns == null) {
351+
foreignKey.setColumns(null);
352+
} else {
353+
foreignKey.setColumnsNames(fkColumns);
354+
}
355+
}
357356
}
358357

359358
/**
@@ -362,16 +361,62 @@ public void setFkColumns(List<String> fkColumns) {
362361
*/
363362
@Deprecated
364363
public String getFkSourceTable() {
365-
return fkSourceTable;
364+
Table table = getForeignKeyTable();
365+
return table == null ? null : table.getName();
366366
}
367367

368368
/**
369+
* Updates only the referenced table identifier, preserving its quoting and the table's other
370+
* name parts. Uses the creation and replacement policy of {@link #setFkColumns(List)}.
371+
*
369372
* @deprecated Use {@link #setConstraint(NamedConstraint)} with a
370373
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
371374
*/
372375
@Deprecated
373376
public void setFkSourceTable(String fkSourceTable) {
374-
this.fkSourceTable = fkSourceTable;
377+
setForeignKeyTablePart(fkSourceTable, 0);
378+
}
379+
380+
private ForeignKeyConstraint getForeignKeyConstraint() {
381+
return constraint instanceof ForeignKeyConstraint ? (ForeignKeyConstraint) constraint
382+
: null;
383+
}
384+
385+
private ForeignKeyConstraint foreignKeyForUpdate(boolean create) {
386+
ForeignKeyConstraint foreignKey = getForeignKeyConstraint();
387+
if (foreignKey == null && create) {
388+
if (constraint != null || index != null || pkColumns != null || ukColumns != null) {
389+
throw new IllegalStateException(
390+
"Foreign-key setters cannot replace an existing definition; use setConstraint");
391+
}
392+
foreignKey = new ForeignKeyConstraint();
393+
setConstraint(foreignKey);
394+
}
395+
return foreignKey;
396+
}
397+
398+
private Table getForeignKeyTable() {
399+
ForeignKeyConstraint foreignKey = getForeignKeyConstraint();
400+
return foreignKey == null ? null : foreignKey.getTable();
401+
}
402+
403+
private void setForeignKeyTablePart(String value, int partIndex) {
404+
ForeignKeyConstraint foreignKey = foreignKeyForUpdate(value != null);
405+
if (foreignKey == null || foreignKey.getTable() == null && value == null) {
406+
return;
407+
}
408+
if (foreignKey.getTable() == null) {
409+
foreignKey.setTable(new Table());
410+
}
411+
Table table = foreignKey.getTable();
412+
// Table stores identifier parts in name-first order. Updating raw parts avoids splitting
413+
// quoted identifiers containing dots and leaves the existing Table object attached.
414+
List<String> parts = new ArrayList<>(table.getNameParts());
415+
while (parts.size() <= partIndex) {
416+
parts.add(null);
417+
}
418+
parts.set(partIndex, value);
419+
table.setNameParts(parts);
375420
}
376421

377422
public List<ColumnDataType> getColDataTypeList() {
@@ -451,21 +496,29 @@ public List<ColumnSetVisibility> getColumnSetVisibilityList() {
451496
}
452497

453498
/**
454-
* @deprecated Use {@link #getConstraint()} with
455-
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
499+
* Returns the referenced-column list owned by the stored foreign key, or null when absent.
500+
* Changes to the returned list are reflected in the constraint.
501+
*
502+
* @deprecated Use {@link #getConstraint()} with a {@link ForeignKeyConstraint} instead.
456503
*/
457504
@Deprecated
458505
public List<String> getFkSourceColumns() {
459-
return fkSourceColumns;
506+
ForeignKeyConstraint foreignKey = getForeignKeyConstraint();
507+
return foreignKey == null ? null : foreignKey.getReferencedColumnNames();
460508
}
461509

462510
/**
511+
* Uses the creation and replacement policy of {@link #setFkColumns(List)}.
512+
*
463513
* @deprecated Use {@link #setConstraint(NamedConstraint)} with a
464514
* {@link net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint} instead.
465515
*/
466516
@Deprecated
467517
public void setFkSourceColumns(List<String> fkSourceColumns) {
468-
this.fkSourceColumns = fkSourceColumns;
518+
ForeignKeyConstraint foreignKey = foreignKeyForUpdate(fkSourceColumns != null);
519+
if (foreignKey != null) {
520+
foreignKey.setReferencedColumnNames(fkSourceColumns);
521+
}
469522
}
470523

471524
public String getNewTableName() {
@@ -672,7 +725,7 @@ private ConstraintKind getAddedConstraintKind() {
672725
if (ukColumns != null) {
673726
return ConstraintKind.UNIQUE;
674727
}
675-
return fkColumns != null ? ConstraintKind.FOREIGN_KEY : ConstraintKind.OTHER;
728+
return ConstraintKind.OTHER;
676729
}
677730

678731
private boolean hasColumnOrNamedTarget() {
@@ -1446,7 +1499,7 @@ private void toStringGeneral(StringBuilder b, Consumer<ColumnDataType> columnPri
14461499
} else if (constraint != null) {
14471500
b.append(constraint);
14481501
} else if (index != null) {
1449-
// The structured index is canonical. Legacy PK/UK/FK fields may also be populated for
1502+
// The structured index is canonical. Legacy PK/UK fields may also be populated for
14501503
// source compatibility, but cannot represent names, expressions, or index options.
14511504
b.append(index);
14521505
} else if (pkColumns != null) {
@@ -1466,21 +1519,6 @@ private void toStringGeneral(StringBuilder b, Consumer<ColumnDataType> columnPri
14661519
b.append(ukName);
14671520
}
14681521
b.append(" (").append(PlainSelect.getStringList(ukColumns)).append(")");
1469-
} else if (fkColumns != null) {
1470-
// @deprecated path - kept for backward compatibility when ForeignKeyConstraint is not
1471-
// set
1472-
b.append("FOREIGN KEY (")
1473-
.append(PlainSelect.getStringList(fkColumns))
1474-
.append(") REFERENCES ")
1475-
.append(
1476-
fkSourceSchema != null && fkSourceSchema.trim().length() > 0
1477-
? fkSourceSchema + "."
1478-
: "")
1479-
.append(fkSourceTable)
1480-
.append(" (")
1481-
.append(PlainSelect.getStringList(fkSourceColumns))
1482-
.append(")");
1483-
referentialActions.forEach(b::append);
14841522
}
14851523

14861524
if (getConstraints() != null && !getConstraints().isEmpty()) {
@@ -1569,7 +1607,7 @@ public AlterExpression withFkColumns(List<String> fkColumns) {
15691607

15701608
@Deprecated
15711609
public AlterExpression withFkSourceSchema(String fkSourceSchema) {
1572-
this.setFkSourceTable(fkSourceSchema);
1610+
this.setFkSourceSchema(fkSourceSchema);
15731611
return this;
15741612
}
15751613

@@ -1638,13 +1676,15 @@ public AlterExpression addUkColumns(Collection<String> ukColumns) {
16381676
return this.withUkColumns(collection);
16391677
}
16401678

1679+
/** Adds strings using the replacement semantics of {@link #setFkColumns(List)}. */
16411680
@Deprecated
16421681
public AlterExpression addFkColumns(String... fkColumns) {
16431682
List<String> collection = Optional.ofNullable(getFkColumns()).orElseGet(ArrayList::new);
16441683
Collections.addAll(collection, fkColumns);
16451684
return this.withFkColumns(collection);
16461685
}
16471686

1687+
/** Adds strings using the replacement semantics of {@link #setFkColumns(List)}. */
16481688
@Deprecated
16491689
public AlterExpression addFkColumns(Collection<String> fkColumns) {
16501690
List<String> collection = Optional.ofNullable(getFkColumns()).orElseGet(ArrayList::new);

‎src/main/java/net/sf/jsqlparser/util/validation/validator/AlterValidator.java‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import net.sf.jsqlparser.statement.create.table.KeyColumnSource;
2424
import net.sf.jsqlparser.statement.create.table.KeyElement;
2525
import net.sf.jsqlparser.statement.create.table.ConstraintUsingIndex;
26+
import net.sf.jsqlparser.statement.create.table.ForeignKeyConstraint;
2627
import net.sf.jsqlparser.util.TableDefinitionTraversal;
2728
import net.sf.jsqlparser.util.validation.ValidationCapability;
2829
import net.sf.jsqlparser.util.validation.ValidationUtil;
@@ -76,12 +77,6 @@ public void validate(Alter alter, AlterExpression e) {
7677
validateOptionalColumnNames(c, e.getPkColumns());
7778
}
7879

79-
if (e.getFkColumns() != null) {
80-
validateName(c, NamedObject.table, e.getFkSourceTable());
81-
validateOptionalColumnNames(c, e.getFkColumns());
82-
validateOptionalColumnNames(c, e.getFkSourceColumns());
83-
}
84-
8580
if (e.getUk()) {
8681
validateName(c, NamedObject.uniqueConstraint, e.getUkName());
8782
validateOptionalColumnNames(c, e.getUkColumns(), NamedObject.uniqueConstraint);
@@ -91,6 +86,10 @@ public void validate(Alter alter, AlterExpression e) {
9186
if (constraint != null) {
9287
validateOptionalName(c, NamedObject.constraint, constraint.getName(), null, false,
9388
NamedObject.table);
89+
if (constraint instanceof ForeignKeyConstraint) {
90+
validateOptionalColumnNames(c,
91+
((ForeignKeyConstraint) constraint).getReferencedColumnNames());
92+
}
9493
if (constraint instanceof ConstraintUsingIndex) {
9594
validateName(c, NamedObject.index,
9695
((ConstraintUsingIndex) constraint).getExistingIndexName());

0 commit comments

Comments
 (0)