Skip to content

Commit f993e84

Browse files
committed
feat: share PostgreSQL relation targets and complete TRUNCATE options
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 78d3de8 commit f993e84

10 files changed

Lines changed: 393 additions & 160 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.schema;
11+
12+
import java.io.Serializable;
13+
14+
/** A relation target with optional PostgreSQL inheritance scope, shared by LOCK and TRUNCATE. */
15+
public class TableReference implements Serializable {
16+
private Table table;
17+
private boolean only;
18+
private boolean includeDescendants;
19+
private boolean parenthesized;
20+
21+
public TableReference(Table table) {
22+
this.table = table;
23+
}
24+
25+
public Table getTable() {
26+
return table;
27+
}
28+
29+
public void setTable(Table table) {
30+
this.table = table;
31+
}
32+
33+
public boolean isOnly() {
34+
return only;
35+
}
36+
37+
public void setOnly(boolean only) {
38+
this.only = only;
39+
if (only) {
40+
includeDescendants = false;
41+
} else {
42+
parenthesized = false;
43+
}
44+
}
45+
46+
public boolean isIncludeDescendants() {
47+
return includeDescendants;
48+
}
49+
50+
public void setIncludeDescendants(boolean includeDescendants) {
51+
this.includeDescendants = includeDescendants;
52+
if (includeDescendants) {
53+
only = false;
54+
parenthesized = false;
55+
}
56+
}
57+
58+
public boolean isParenthesized() {
59+
return parenthesized;
60+
}
61+
62+
public void setParenthesized(boolean parenthesized) {
63+
this.parenthesized = parenthesized;
64+
if (parenthesized) {
65+
only = true;
66+
includeDescendants = false;
67+
}
68+
}
69+
70+
public StringBuilder appendTo(StringBuilder builder) {
71+
if (only) {
72+
builder.append("ONLY ");
73+
}
74+
if (parenthesized) {
75+
builder.append('(');
76+
}
77+
builder.append(table.getFullyQualifiedName());
78+
if (parenthesized) {
79+
builder.append(')');
80+
}
81+
if (includeDescendants) {
82+
builder.append(" *");
83+
}
84+
return builder;
85+
}
86+
87+
@Override
88+
public String toString() {
89+
return appendTo(new StringBuilder()).toString();
90+
}
91+
}

‎src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java‎

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,34 +34,20 @@ public enum Scope {
3434
DEFAULT, ONLY, INCLUDING_DESCENDANTS
3535
}
3636

37-
public static class Target {
38-
private Table table;
39-
private Scope scope = Scope.DEFAULT;
40-
37+
public static class Target extends net.sf.jsqlparser.schema.TableReference {
4138
public Target(Table table) {
42-
this.table = table;
43-
}
44-
45-
public Table getTable() {
46-
return table;
47-
}
48-
49-
public void setTable(Table table) {
50-
this.table = table;
39+
super(table);
5140
}
5241

5342
public Scope getScope() {
54-
return scope;
43+
return isOnly() ? Scope.ONLY
44+
: isIncludeDescendants() ? Scope.INCLUDING_DESCENDANTS : Scope.DEFAULT;
5545
}
5646

5747
public void setScope(Scope scope) {
58-
this.scope = Objects.requireNonNull(scope);
59-
}
60-
61-
@Override
62-
public String toString() {
63-
return (scope == Scope.ONLY ? "ONLY " : "") + table.getFullyQualifiedName()
64-
+ (scope == Scope.INCLUDING_DESCENDANTS ? " *" : "");
48+
Objects.requireNonNull(scope);
49+
setOnly(scope == Scope.ONLY);
50+
setIncludeDescendants(scope == Scope.INCLUDING_DESCENDANTS);
6551
}
6652
}
6753

‎src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java‎

Lines changed: 126 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,113 +9,186 @@
99
*/
1010
package net.sf.jsqlparser.statement.truncate;
1111

12-
import static java.util.stream.Collectors.joining;
13-
12+
import java.util.AbstractList;
13+
import java.util.ArrayList;
1414
import java.util.List;
1515
import net.sf.jsqlparser.schema.Table;
16+
import net.sf.jsqlparser.schema.TableReference;
1617
import net.sf.jsqlparser.statement.Statement;
1718
import net.sf.jsqlparser.statement.StatementVisitor;
1819

1920
public class Truncate implements Statement {
21+
public enum IdentityOption {
22+
RESTART, CONTINUE
23+
}
24+
public enum DropBehavior {
25+
CASCADE, RESTRICT
26+
}
2027

21-
boolean cascade; // to support TRUNCATE TABLE ... CASCADE
22-
boolean tableToken; // to support TRUNCATE without TABLE
23-
boolean only; // to support TRUNCATE with ONLY
24-
private Table table;
25-
private List<Table> tables;
28+
private boolean tableToken;
29+
private boolean only;
30+
private final List<TableReference> targets = new ArrayList<>();
31+
private IdentityOption identityOption;
32+
private DropBehavior dropBehavior;
2633

2734
@Override
2835
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
2936
return statementVisitor.visit(this, context);
3037
}
3138

32-
public Table getTable() {
33-
return table;
39+
public List<TableReference> getTargets() {
40+
return targets;
3441
}
3542

36-
public List<Table> getTables() {
37-
return tables;
43+
public void setTargets(List<TableReference> references) {
44+
List<TableReference> replacement = new ArrayList<>(references);
45+
targets.clear();
46+
targets.addAll(replacement);
47+
}
48+
49+
/** Preserves the legacy parser's singular accessor for the last target. */
50+
public Table getTable() {
51+
return targets.isEmpty() ? null : targets.get(targets.size() - 1).getTable();
3852
}
3953

4054
public void setTable(Table table) {
41-
this.table = table;
55+
if (targets.isEmpty()) {
56+
TableReference target = new TableReference(table);
57+
target.setOnly(only);
58+
targets.add(target);
59+
} else {
60+
targets.get(targets.size() - 1).setTable(table);
61+
}
62+
}
63+
64+
/** Mutable table projection; replacing a table preserves its target's inheritance scope. */
65+
public List<Table> getTables() {
66+
return new AbstractList<Table>() {
67+
@Override
68+
public Table get(int index) {
69+
return targets.get(index).getTable();
70+
}
71+
72+
@Override
73+
public int size() {
74+
return targets.size();
75+
}
76+
77+
@Override
78+
public Table set(int index, Table table) {
79+
Table previous = get(index);
80+
targets.get(index).setTable(table);
81+
return previous;
82+
}
83+
84+
@Override
85+
public void add(int index, Table table) {
86+
targets.add(index, new TableReference(table));
87+
}
88+
89+
@Override
90+
public Table remove(int index) {
91+
return targets.remove(index).getTable();
92+
}
93+
};
4294
}
4395

4496
public void setTables(List<Table> tables) {
45-
this.tables = tables;
97+
List<Table> replacement = tables == null ? new ArrayList<>() : new ArrayList<>(tables);
98+
boolean firstOnly = isOnly();
99+
targets.clear();
100+
replacement.forEach(table -> targets.add(new TableReference(table)));
101+
setOnly(firstOnly);
46102
}
47103

48-
public boolean getCascade() {
49-
return cascade;
104+
public IdentityOption getIdentityOption() {
105+
return identityOption;
50106
}
51107

52-
public void setCascade(boolean c) {
53-
cascade = c;
108+
public void setIdentityOption(IdentityOption option) {
109+
identityOption = option;
54110
}
55111

56-
@Override
57-
public String toString() {
58-
StringBuilder sb = new StringBuilder();
59-
sb.append("TRUNCATE");
60-
if (tableToken) {
61-
sb.append(" TABLE");
62-
}
63-
if (only) {
64-
sb.append(" ONLY");
65-
}
66-
sb.append(" ");
67-
if (tables != null && !tables.isEmpty()) {
68-
sb.append(tables.stream()
69-
.map(Table::toString)
70-
.collect(joining(", ")));
71-
} else {
72-
sb.append(table);
73-
}
74-
if (cascade) {
75-
sb.append(" CASCADE");
76-
}
77-
return sb.toString();
112+
public DropBehavior getDropBehavior() {
113+
return dropBehavior;
114+
}
115+
116+
public void setDropBehavior(DropBehavior behavior) {
117+
dropBehavior = behavior;
118+
}
119+
120+
public boolean getCascade() {
121+
return dropBehavior == DropBehavior.CASCADE;
122+
}
123+
124+
public void setCascade(boolean cascade) {
125+
dropBehavior = cascade ? DropBehavior.CASCADE : null;
78126
}
79127

80128
public boolean isTableToken() {
81129
return tableToken;
82130
}
83131

84-
public void setTableToken(boolean hasTable) {
85-
this.tableToken = hasTable;
132+
public void setTableToken(boolean tableToken) {
133+
this.tableToken = tableToken;
86134
}
87135

136+
/** Legacy ONLY accessor describes the first target. */
88137
public boolean isOnly() {
89-
return only;
138+
return targets.isEmpty() ? only : targets.get(0).isOnly();
90139
}
91140

92141
public void setOnly(boolean only) {
93142
this.only = only;
143+
if (!targets.isEmpty()) {
144+
targets.get(0).setOnly(only);
145+
}
94146
}
95147

96-
public Truncate withTableToken(boolean hasTableToken) {
97-
this.setTableToken(hasTableToken);
148+
public StringBuilder appendTo(StringBuilder builder) {
149+
builder.append(tableToken ? "TRUNCATE TABLE " : "TRUNCATE ");
150+
for (int i = 0; i < targets.size(); i++) {
151+
if (i > 0) {
152+
builder.append(", ");
153+
}
154+
targets.get(i).appendTo(builder);
155+
}
156+
if (identityOption != null) {
157+
builder.append(' ').append(identityOption).append(" IDENTITY");
158+
}
159+
if (dropBehavior != null) {
160+
builder.append(' ').append(dropBehavior);
161+
}
162+
return builder;
163+
}
164+
165+
@Override
166+
public String toString() {
167+
return appendTo(new StringBuilder()).toString();
168+
}
169+
170+
public Truncate withTableToken(boolean value) {
171+
setTableToken(value);
98172
return this;
99173
}
100174

101-
public Truncate withTable(Table table) {
102-
this.setTable(table);
175+
public Truncate withTable(Table value) {
176+
setTable(value);
103177
return this;
104178
}
105179

106-
public Truncate withTables(List<Table> tables) {
107-
this.setTables(tables);
180+
public Truncate withTables(List<Table> value) {
181+
setTables(value);
108182
return this;
109183
}
110184

111-
public Truncate withCascade(boolean cascade) {
112-
this.setCascade(cascade);
185+
public Truncate withCascade(boolean value) {
186+
setCascade(value);
113187
return this;
114188
}
115189

116-
public Truncate withOnly(boolean only) {
117-
this.setOnly(only);
190+
public Truncate withOnly(boolean value) {
191+
setOnly(value);
118192
return this;
119193
}
120194
}
121-

‎src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1612,7 +1612,7 @@ public void visit(Drop drop) {
16121612

16131613
@Override
16141614
public <S> Void visit(Truncate truncate, S context) {
1615-
visit(truncate.getTable(), context);
1615+
truncate.getTables().forEach(table -> visit(table, context));
16161616
return null;
16171617
}
16181618

0 commit comments

Comments
 (0)