Skip to content

Commit 157988d

Browse files
zhangconanzhangkenan
andauthored
Added new features to support the complete delete using syntax of pg database, such as subqueries, etc. (#2316)
Co-authored-by: zhangkenan <zhangkenan@hexadb.com>
1 parent 528dd72 commit 157988d

File tree

5 files changed

+133
-16
lines changed

5 files changed

+133
-16
lines changed

src/main/java/net/sf/jsqlparser/statement/delete/Delete.java

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import net.sf.jsqlparser.statement.ReturningClause;
1818
import net.sf.jsqlparser.statement.Statement;
1919
import net.sf.jsqlparser.statement.StatementVisitor;
20+
import net.sf.jsqlparser.statement.select.FromItem;
2021
import net.sf.jsqlparser.statement.select.Join;
2122
import net.sf.jsqlparser.statement.select.Limit;
2223
import net.sf.jsqlparser.statement.select.OrderByElement;
@@ -29,6 +30,7 @@
2930
import java.util.Iterator;
3031
import java.util.List;
3132
import java.util.Optional;
33+
import java.util.stream.Collectors;
3234

3335
import static java.util.stream.Collectors.joining;
3436

@@ -38,7 +40,7 @@ public class Delete implements Statement {
3840
private Table table;
3941
private OracleHint oracleHint = null;
4042
private List<Table> tables;
41-
private List<Table> usingList;
43+
private List<FromItem> usingFromItemList;
4244
private List<Join> joins;
4345
private Expression where;
4446
private PreferringClause preferringClause;
@@ -157,12 +159,29 @@ public void setTables(List<Table> tables) {
157159
this.tables = tables;
158160
}
159161

162+
/**
163+
* This is compatible with the old logic. When calling this method, you need to ensure that the
164+
* specific table is used after using.
165+
*
166+
* @return Table collection used in using.
167+
*/
168+
@Deprecated
160169
public List<Table> getUsingList() {
161-
return usingList;
170+
if (usingFromItemList == null || usingFromItemList.isEmpty()) {
171+
return new ArrayList<>();
172+
}
173+
return usingFromItemList.stream().map(ele -> (Table) ele).collect(Collectors.toList());
162174
}
163175

176+
/**
177+
* This is compatible with the old logic. When calling this method, you need to ensure that the
178+
* specific table is used after using.
179+
*
180+
* @param usingList Table collection used in using.
181+
*/
182+
@Deprecated
164183
public void setUsingList(List<Table> usingList) {
165-
this.usingList = usingList;
184+
this.usingFromItemList = new ArrayList<>(usingList);
166185
}
167186

168187
public List<Join> getJoins() {
@@ -228,10 +247,10 @@ public String toString() {
228247
}
229248
b.append(" ").append(table);
230249

231-
if (usingList != null && usingList.size() > 0) {
250+
if (usingFromItemList != null && !usingFromItemList.isEmpty()) {
232251
b.append(" USING ");
233-
b.append(usingList.stream()
234-
.map(Table::toString)
252+
b.append(usingFromItemList.stream()
253+
.map(Object::toString)
235254
.collect(joining(", ")));
236255
}
237256

@@ -273,11 +292,30 @@ public Delete withTables(List<Table> tables) {
273292
return this;
274293
}
275294

295+
/**
296+
* The old method has been replaced by withUsingFromItemList.
297+
*
298+
* @param usingList
299+
* @return
300+
* @see Delete#withUsingFromItemList
301+
*/
302+
@Deprecated
276303
public Delete withUsingList(List<Table> usingList) {
277304
this.setUsingList(usingList);
278305
return this;
279306
}
280307

308+
/**
309+
* New using syntax method.Supports the complete using syntax of pg, such as subqueries, etc.
310+
*
311+
* @param usingFromItemList
312+
* @return
313+
*/
314+
public Delete withUsingFromItemList(List<FromItem> usingFromItemList) {
315+
this.setUsingFromItemList(usingFromItemList);
316+
return this;
317+
}
318+
281319
public Delete withJoins(List<Join> joins) {
282320
this.setJoins(joins);
283321
return this;
@@ -364,18 +402,60 @@ public Delete addTables(Collection<? extends Table> tables) {
364402
return this.withTables(collection);
365403
}
366404

405+
/**
406+
* The old method has been replaced by addUsingFromItemList.
407+
*
408+
* @param usingList
409+
* @return
410+
* @see Delete#addUsingFromItemList
411+
*/
412+
@Deprecated
367413
public Delete addUsingList(Table... usingList) {
368414
List<Table> collection = Optional.ofNullable(getUsingList()).orElseGet(ArrayList::new);
369415
Collections.addAll(collection, usingList);
370416
return this.withUsingList(collection);
371417
}
372418

419+
/**
420+
* New using syntax method.Supports the complete using syntax of pg, such as subqueries, etc.
421+
*
422+
* @param usingFromItemList
423+
* @return
424+
*/
425+
public Delete addUsingFromItemList(FromItem... usingFromItemList) {
426+
List<FromItem> collection =
427+
Optional.ofNullable(getUsingFromItemList()).orElseGet(ArrayList::new);
428+
Collections.addAll(collection, usingFromItemList);
429+
return this.withUsingFromItemList(collection);
430+
}
431+
432+
/**
433+
* The old method has been replaced by addUsingFromItemList.
434+
*
435+
* @param usingList
436+
* @return
437+
* @see Delete#addUsingFromItemList
438+
*/
439+
@Deprecated
373440
public Delete addUsingList(Collection<? extends Table> usingList) {
374441
List<Table> collection = Optional.ofNullable(getUsingList()).orElseGet(ArrayList::new);
375442
collection.addAll(usingList);
376443
return this.withUsingList(collection);
377444
}
378445

446+
/**
447+
* New using syntax method. Supports the complete using syntax of pg, such as subqueries, etc.
448+
*
449+
* @param usingFromItemList
450+
* @return
451+
*/
452+
public Delete addUsingFromItemList(Collection<? extends Table> usingFromItemList) {
453+
List<FromItem> collection =
454+
Optional.ofNullable(getUsingFromItemList()).orElseGet(ArrayList::new);
455+
collection.addAll(usingFromItemList);
456+
return this.withUsingFromItemList(collection);
457+
}
458+
379459
public Delete addJoins(Join... joins) {
380460
List<Join> collection = Optional.ofNullable(getJoins()).orElseGet(ArrayList::new);
381461
Collections.addAll(collection, joins);
@@ -405,4 +485,23 @@ public Delete addOrderByElements(Collection<? extends OrderByElement> orderByEle
405485
public <E extends Expression> E getWhere(Class<E> type) {
406486
return type.cast(getWhere());
407487
}
488+
489+
/**
490+
* Return the content after using. Supports the complete using syntax of pg, such as subqueries,
491+
* etc.
492+
*
493+
* @return
494+
*/
495+
public List<FromItem> getUsingFromItemList() {
496+
return usingFromItemList;
497+
}
498+
499+
/**
500+
* Supports the complete using syntax of pg, such as subqueries, etc.
501+
*
502+
* @param usingFromItemList The content after using.
503+
*/
504+
public void setUsingFromItemList(List<FromItem> usingFromItemList) {
505+
this.usingFromItemList = usingFromItemList;
506+
}
408507
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement;
168168
import net.sf.jsqlparser.statement.select.AllColumns;
169169
import net.sf.jsqlparser.statement.select.AllTableColumns;
170+
import net.sf.jsqlparser.statement.select.FromItem;
170171
import net.sf.jsqlparser.statement.select.FromItemVisitor;
171172
import net.sf.jsqlparser.statement.select.FunctionAllColumns;
172173
import net.sf.jsqlparser.statement.select.Join;
@@ -1014,9 +1015,9 @@ public <S> Void visit(MySQLGroupConcat groupConcat, S context) {
10141015
public <S> Void visit(Delete delete, S context) {
10151016
visit(delete.getTable(), context);
10161017

1017-
if (delete.getUsingList() != null) {
1018-
for (Table using : delete.getUsingList()) {
1019-
visit(using, context);
1018+
if (delete.getUsingFromItemList() != null) {
1019+
for (FromItem usingFromItem : delete.getUsingFromItemList()) {
1020+
usingFromItem.accept(this, context);
10201021
}
10211022
}
10221023

src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ public void deParse(Delete delete) {
7878
}
7979
builder.append(" ").append(delete.getTable().toString());
8080

81-
if (delete.getUsingList() != null && !delete.getUsingList().isEmpty()) {
81+
if (delete.getUsingFromItemList() != null && !delete.getUsingFromItemList().isEmpty()) {
8282
builder.append(" USING").append(
83-
delete.getUsingList().stream().map(Table::toString)
83+
delete.getUsingFromItemList().stream().map(Object::toString)
8484
.collect(joining(", ", " ", "")));
8585
}
8686
if (delete.getJoins() != null) {

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3012,8 +3012,8 @@ Delete Delete():
30123012
Table table = null;
30133013
List<Table> tables = new ArrayList<Table>();
30143014
List<WithItem<?>> with = null;
3015-
Table usingTable = null;
3016-
List<Table> usingList = new ArrayList<Table>();
3015+
FromItem usingFromItem = null;
3016+
List<FromItem> usingFromItemList = new ArrayList<FromItem>();
30173017
List<Join> joins = null;
30183018
Expression where = null;
30193019
PreferringClause preferringClause = null;
@@ -3039,8 +3039,8 @@ Delete Delete():
30393039
<K_FROM> | <K_FROM>) { hasFrom = true; }]
30403040

30413041
[ LOOKAHEAD(3) table=TableWithAlias() [ LOOKAHEAD(2) joins=JoinsList() ] ]
3042-
[ <K_USING> usingTable=TableWithAlias() { usingList.add(usingTable); }
3043-
("," usingTable=TableWithAlias() { usingList.add(usingTable); } )*]
3042+
[ <K_USING> usingFromItem=FromItem() { usingFromItemList.add(usingFromItem); }
3043+
("," usingFromItem=FromItem() { usingFromItemList.add(usingFromItem); } )*]
30443044
[where=WhereClause() { delete.setWhere(where); } ]
30453045
[preferringClause=PreferringClause() { delete.setPreferringClause(preferringClause);} ]
30463046
[orderByElements = OrderByElements() { delete.setOrderByElements(orderByElements); } ]
@@ -3055,7 +3055,7 @@ Delete Delete():
30553055
.withTables(tables)
30563056
.withTable(table)
30573057
.withHasFrom(hasFrom)
3058-
.withUsingList(usingList)
3058+
.withUsingFromItemList(usingFromItemList)
30593059
.withModifierPriority(modifierPriority)
30603060
.withModifierIgnore(modifierIgnore)
30613061
.withModifierQuick(modifierQuick);

src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import static org.junit.jupiter.api.Assertions.assertThrows;
2626
import static org.junit.jupiter.api.Assertions.assertTrue;
2727

28+
import net.sf.jsqlparser.schema.Table;
2829
import net.sf.jsqlparser.statement.insert.Insert;
30+
import net.sf.jsqlparser.statement.select.ParenthesedSelect;
2931
import net.sf.jsqlparser.statement.select.PlainSelect;
3032
import net.sf.jsqlparser.statement.select.SelectItem;
3133
import net.sf.jsqlparser.statement.select.WithItem;
@@ -397,4 +399,19 @@ public void testDeleteWithSkylineKeywords() throws JSQLParserException {
397399
delete.getWhere().toString());
398400
}
399401

402+
@Test
403+
public void testDeleteUsingFromItem() throws JSQLParserException {
404+
String statement =
405+
"DELETE A USING B.C D,(SELECT id FROM producers WHERE active = false) p WHERE D.Z = 1 and p.id = D.id";
406+
Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(statement);
407+
assertEquals("B.C",
408+
((Table) delete.getUsingFromItemList().get(0)).getFullyQualifiedName());
409+
assertEquals("D",
410+
((Table) delete.getUsingFromItemList().get(0)).getAlias().getName());
411+
assertEquals("producers",
412+
((Table) ((ParenthesedSelect) delete.getUsingFromItemList().get(1)).getPlainSelect()
413+
.getFromItem()).getFullyQualifiedName());
414+
assertEquals("p",
415+
delete.getUsingFromItemList().get(1).getAlias().getName());
416+
}
400417
}

0 commit comments

Comments
 (0)