Skip to content

Commit 71d254b

Browse files
committed
fix: collect tables from all SELECT clauses in TablesNamesFinder
TablesNamesFinder visited only a subset of the Expression/Table-bearing children of PlainSelect, ParenthesedSelect, SetOperationList, Values and FromItem-attached pivots, silently dropping tables located in INTO and INTO TEMP targets, DISTINCT ON, LATERAL VIEW generator functions, PREFERRING, GROUP BY (incl. GROUPING SETS), QUALIFY, WINDOW definitions, SETTINGS, PIVOT/UNPIVOT/PIVOT XML and the ORDER BY / LIMIT / LIMIT BY / OFFSET / FETCH clauses shared by every Select subclass. Complete the traversal reusing the same ExpressionVisitor and FromItemVisitor default helpers used by SelectVisitorAdapter, and implement PivotVisitor so pivot contents (incl. the PivotXml IN subquery) are reached through dispatch. Signed-off-by: fudianchn <fudian@users.noreply.github.com>
1 parent e7167cc commit 71d254b

2 files changed

Lines changed: 259 additions & 1 deletion

File tree

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

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,17 +154,22 @@
154154
import net.sf.jsqlparser.statement.select.FunctionAllColumns;
155155
import net.sf.jsqlparser.statement.select.Join;
156156
import net.sf.jsqlparser.statement.select.LateralSubSelect;
157+
import net.sf.jsqlparser.statement.select.LateralView;
157158
import net.sf.jsqlparser.statement.select.OrderByElement;
158159
import net.sf.jsqlparser.statement.select.ParenthesedFromItem;
159160
import net.sf.jsqlparser.statement.select.ParenthesedSelect;
161+
import net.sf.jsqlparser.statement.select.Pivot;
160162
import net.sf.jsqlparser.statement.select.PivotQuery;
163+
import net.sf.jsqlparser.statement.select.PivotVisitor;
164+
import net.sf.jsqlparser.statement.select.PivotXml;
161165
import net.sf.jsqlparser.statement.select.PlainSelect;
162166
import net.sf.jsqlparser.statement.select.Select;
163167
import net.sf.jsqlparser.statement.select.SelectItem;
164168
import net.sf.jsqlparser.statement.select.SelectItemVisitor;
165169
import net.sf.jsqlparser.statement.select.SelectVisitor;
166170
import net.sf.jsqlparser.statement.select.SetOperationList;
167171
import net.sf.jsqlparser.statement.select.TableFunction;
172+
import net.sf.jsqlparser.statement.select.UnPivot;
168173
import net.sf.jsqlparser.statement.select.TableStatement;
169174
import net.sf.jsqlparser.statement.select.Values;
170175
import net.sf.jsqlparser.statement.select.WithItem;
@@ -187,7 +192,7 @@
187192
public class TablesNamesFinder<Void>
188193
implements SelectVisitor<Void>, FromItemVisitor<Void>, ExpressionVisitor<Void>,
189194
SelectItemVisitor<Void>, StatementVisitor<Void>, MergeOperationVisitor<Void>,
190-
PipeOperatorVisitor<Void, Void> {
195+
PipeOperatorVisitor<Void, Void>, PivotVisitor<Void> {
191196

192197
private Set<String> tables;
193198
private boolean allowColumnProcessing = false;
@@ -330,6 +335,20 @@ public <S> Void visit(ParenthesedSelect select, S context) {
330335
}
331336
}
332337
select.getSelect().accept((SelectVisitor<?>) this, context);
338+
visitOrderBy(select.getOrderByElements(), context);
339+
if (select.getPivot() != null) {
340+
select.getPivot().accept(this, context);
341+
}
342+
if (select.getUnPivot() != null) {
343+
select.getUnPivot().accept(this, context);
344+
}
345+
visitLimit(select.getLimit(), context);
346+
if (select.getOffset() != null) {
347+
select.getOffset().getOffset().accept(this, context);
348+
}
349+
if (select.getFetch() != null) {
350+
select.getFetch().getExpression().accept(this, context);
351+
}
333352
return null;
334353
}
335354

@@ -346,6 +365,11 @@ public <S> Void visit(PlainSelect plainSelect, S context) {
346365
withItem.accept((SelectVisitor<?>) this, context);
347366
}
348367
}
368+
if (plainSelect.getDistinct() != null) {
369+
visitSelectItems(plainSelect.getDistinct().getOnSelectItems(), context);
370+
}
371+
visitTables(plainSelect.getIntoTables(), context);
372+
349373
if (plainSelect.getSelectItems() != null) {
350374
for (SelectItem<?> item : plainSelect.getSelectItems()) {
351375
item.accept(this, context);
@@ -356,6 +380,12 @@ public <S> Void visit(PlainSelect plainSelect, S context) {
356380
plainSelect.getFromItem().accept(this, context);
357381
}
358382

383+
if (plainSelect.getLateralViews() != null) {
384+
for (LateralView lateralView : plainSelect.getLateralViews()) {
385+
lateralView.getGeneratorFunction().accept(this, context);
386+
}
387+
}
388+
359389
visitJoins(plainSelect.getJoins(), context);
360390
if (plainSelect.getPreWhere() != null) {
361391
plainSelect.getPreWhere().accept(this, context);
@@ -364,13 +394,46 @@ public <S> Void visit(PlainSelect plainSelect, S context) {
364394
plainSelect.getWhere().accept(this, context);
365395
}
366396

397+
visitPreferringClause(plainSelect.getPreferringClause(), context);
398+
visit(plainSelect.getGroupBy(), context);
399+
367400
if (plainSelect.getHaving() != null) {
368401
plainSelect.getHaving().accept(this, context);
369402
}
370403

404+
if (plainSelect.getQualify() != null) {
405+
plainSelect.getQualify().accept(this, context);
406+
}
407+
371408
if (plainSelect.getOracleHierarchical() != null) {
372409
plainSelect.getOracleHierarchical().accept(this, context);
373410
}
411+
412+
if (plainSelect.getWindowDefinitions() != null) {
413+
for (WindowDefinition windowDefinition : plainSelect.getWindowDefinitions()) {
414+
visitExpressions(windowDefinition.getPartitionExpressionList(), context);
415+
visitOrderBy(windowDefinition.getOrderByElements(), context);
416+
}
417+
}
418+
419+
if (plainSelect.getPivot() != null) {
420+
plainSelect.getPivot().accept(this, context);
421+
}
422+
if (plainSelect.getUnPivot() != null) {
423+
plainSelect.getUnPivot().accept(this, context);
424+
}
425+
426+
visitOrderBy(plainSelect.getOrderByElements(), context);
427+
visitLimit(plainSelect.getLimit(), context);
428+
visitLimit(plainSelect.getLimitBy(), context);
429+
if (plainSelect.getOffset() != null) {
430+
plainSelect.getOffset().getOffset().accept(this, context);
431+
}
432+
if (plainSelect.getFetch() != null) {
433+
plainSelect.getFetch().getExpression().accept(this, context);
434+
}
435+
visitUpdateSets(plainSelect.getSettings(), context);
436+
visitFromItem(plainSelect.getIntoTempTable(), context);
374437
return null;
375438
}
376439

@@ -431,6 +494,12 @@ public <S> Void visit(Table table, S context) {
431494
if (!otherItemNames.contains(tableWholeName)) {
432495
tables.add(tableWholeName);
433496
}
497+
if (table.getPivot() != null) {
498+
table.getPivot().accept(this, context);
499+
}
500+
if (table.getUnPivot() != null) {
501+
table.getUnPivot().accept(this, context);
502+
}
434503
return null;
435504
}
436505

@@ -883,6 +952,14 @@ public <S> Void visit(SetOperationList list, S context) {
883952
for (Select selectBody : list.getSelects()) {
884953
selectBody.accept((SelectVisitor<?>) this, context);
885954
}
955+
visitOrderBy(list.getOrderByElements(), context);
956+
visitLimit(list.getLimit(), context);
957+
if (list.getOffset() != null) {
958+
list.getOffset().getOffset().accept(this, context);
959+
}
960+
if (list.getFetch() != null) {
961+
list.getFetch().getExpression().accept(this, context);
962+
}
886963
return null;
887964
}
888965

@@ -941,6 +1018,36 @@ public <S> Void visit(FromQuery fromQuery, S context) {
9411018
return null;
9421019
}
9431020

1021+
@Override
1022+
public <S> Void visit(Pivot pivot, S context) {
1023+
visitSelectItems(pivot.getFunctionItems(), context);
1024+
visitExpressions(pivot.getForColumns(), context);
1025+
visitSelectItems(pivot.getSingleInItems(), context);
1026+
visitSelectItems(pivot.getMultiInItems(), context);
1027+
return null;
1028+
}
1029+
1030+
@Override
1031+
public <S> Void visit(PivotXml pivotXml, S context) {
1032+
visit((Pivot) pivotXml, context);
1033+
if (pivotXml.getInSelect() != null) {
1034+
pivotXml.getInSelect().accept((SelectVisitor<?>) this, context);
1035+
}
1036+
return null;
1037+
}
1038+
1039+
@Override
1040+
public <S> Void visit(UnPivot unpivot, S context) {
1041+
for (Column column : unpivot.getUnPivotClause()) {
1042+
column.accept(this, context);
1043+
}
1044+
for (Column column : unpivot.getUnPivotForClause()) {
1045+
column.accept(this, context);
1046+
}
1047+
visitSelectItems(unpivot.getUnPivotInClause(), context);
1048+
return null;
1049+
}
1050+
9441051
@Override
9451052
public Void visit(AggregatePipeOperator aggregate, Void context) {
9461053
for (SelectItem<?> selectItem : aggregate.getSelectItems()) {
@@ -1790,6 +1897,14 @@ public void visit(Comment comment) {
17901897
@Override
17911898
public <S> Void visit(Values values, S context) {
17921899
values.getExpressions().accept(this, context);
1900+
visitOrderBy(values.getOrderByElements(), context);
1901+
visitLimit(values.getLimit(), context);
1902+
if (values.getOffset() != null) {
1903+
values.getOffset().getOffset().accept(this, context);
1904+
}
1905+
if (values.getFetch() != null) {
1906+
values.getFetch().getExpression().accept(this, context);
1907+
}
17931908
return null;
17941909
}
17951910

src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,4 +907,147 @@ void testAnalyticFunctionsWithFilterClause() throws JSQLParserException {
907907
"MY_TABLE2");
908908
}
909909

910+
@Test
911+
void testSelectIntoTables() throws JSQLParserException {
912+
String sqlStr = "SELECT * INTO MY_TABLE1 FROM MY_TABLE2";
913+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
914+
"MY_TABLE2");
915+
}
916+
917+
@Test
918+
void testSelectIntoTempTable() throws JSQLParserException {
919+
String sqlStr = "SELECT * FROM MY_TABLE2 INTO TEMP MY_TABLE1";
920+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
921+
"MY_TABLE2");
922+
}
923+
924+
@Test
925+
void testGroupBySubquery() throws JSQLParserException {
926+
String sqlStr =
927+
"SELECT A FROM MY_TABLE1 GROUP BY A, (SELECT B FROM MY_TABLE2)";
928+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
929+
"MY_TABLE2");
930+
}
931+
932+
@Test
933+
void testGroupByGroupingSetsSubquery() throws JSQLParserException {
934+
String sqlStr =
935+
"SELECT A FROM MY_TABLE1 GROUP BY GROUPING SETS ((A, (SELECT B FROM MY_TABLE2)), (C))";
936+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
937+
"MY_TABLE2");
938+
}
939+
940+
@Test
941+
void testSelectQualifySubquery() throws JSQLParserException {
942+
String sqlStr = "SELECT * FROM MY_TABLE1 QUALIFY (SELECT B FROM MY_TABLE2) = 1";
943+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
944+
"MY_TABLE2");
945+
}
946+
947+
@Test
948+
void testWindowDefinitionSubquery() throws JSQLParserException {
949+
String sqlStr =
950+
"SELECT * FROM MY_TABLE1 WINDOW W AS (PARTITION BY (SELECT B FROM MY_TABLE2))";
951+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
952+
"MY_TABLE2");
953+
}
954+
955+
@Test
956+
void testSelectOrderBySubquery() throws JSQLParserException {
957+
String sqlStr = "SELECT A FROM MY_TABLE1 ORDER BY A, (SELECT B FROM MY_TABLE2)";
958+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
959+
"MY_TABLE2");
960+
}
961+
962+
@Test
963+
void testSelectLimitSubquery() throws JSQLParserException {
964+
String sqlStr = "SELECT A FROM MY_TABLE1 LIMIT (SELECT B FROM MY_TABLE2)";
965+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
966+
"MY_TABLE2");
967+
}
968+
969+
@Test
970+
void testSelectLimitBySubquery() throws JSQLParserException {
971+
String sqlStr = "SELECT A FROM MY_TABLE1 LIMIT 2 BY (SELECT B FROM MY_TABLE2)";
972+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
973+
"MY_TABLE2");
974+
}
975+
976+
@Test
977+
void testSelectOffsetSubquery() throws JSQLParserException {
978+
String sqlStr =
979+
"SELECT A FROM MY_TABLE1 LIMIT 1 OFFSET (SELECT B FROM MY_TABLE2)";
980+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
981+
"MY_TABLE2");
982+
}
983+
984+
@Test
985+
void testSelectFetchSubquery() throws JSQLParserException {
986+
String sqlStr =
987+
"SELECT A FROM MY_TABLE1 OFFSET 1 ROWS FETCH NEXT (SELECT B FROM MY_TABLE2) ROWS ONLY";
988+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
989+
"MY_TABLE2");
990+
}
991+
992+
@Test
993+
void testSelectDistinctOnSubquery() throws JSQLParserException {
994+
String sqlStr = "SELECT DISTINCT ON ((SELECT B FROM MY_TABLE2)) A FROM MY_TABLE1";
995+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
996+
"MY_TABLE2");
997+
}
998+
999+
@Test
1000+
void testLateralViewSubquery() throws JSQLParserException {
1001+
String sqlStr =
1002+
"SELECT * FROM MY_TABLE1 LATERAL VIEW EXPLODE(ARRAY((SELECT B FROM MY_TABLE2))) V AS X";
1003+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
1004+
"MY_TABLE2");
1005+
}
1006+
1007+
@Test
1008+
void testTablePivotXmlSubquery() throws JSQLParserException {
1009+
String sqlStr =
1010+
"SELECT * FROM MY_TABLE1 PIVOT XML (SUM(X) FOR Y IN (SELECT Z FROM MY_TABLE2))";
1011+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
1012+
"MY_TABLE2");
1013+
}
1014+
1015+
@Test
1016+
void testTablePivotSimple() throws JSQLParserException {
1017+
String sqlStr = "SELECT * FROM MY_TABLE1 PIVOT (SUM(X) FOR Y IN ('a', 'b'))";
1018+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1");
1019+
}
1020+
1021+
@Test
1022+
void testParenthesedOrderByLimitSubquery() throws JSQLParserException {
1023+
String sqlStr =
1024+
"(SELECT A FROM MY_TABLE1) ORDER BY (SELECT B FROM MY_TABLE2) LIMIT (SELECT C FROM MY_TABLE3)";
1025+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
1026+
"MY_TABLE2", "MY_TABLE3");
1027+
}
1028+
1029+
@Test
1030+
void testSetOperationOrderByLimitSubquery() throws JSQLParserException {
1031+
String sqlStr =
1032+
"SELECT A FROM MY_TABLE1 UNION SELECT B FROM MY_TABLE2 ORDER BY (SELECT C FROM MY_TABLE3) LIMIT (SELECT D FROM MY_TABLE4)";
1033+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
1034+
"MY_TABLE2", "MY_TABLE3", "MY_TABLE4");
1035+
}
1036+
1037+
@Test
1038+
void testSelectSettingsSubquery() throws JSQLParserException {
1039+
String sqlStr =
1040+
"SELECT A FROM MY_TABLE1 SETTINGS X = (SELECT B FROM MY_TABLE2)";
1041+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
1042+
"MY_TABLE2");
1043+
}
1044+
1045+
@Test
1046+
void testValuesOrderByLimitSubquery() throws JSQLParserException {
1047+
String sqlStr =
1048+
"VALUES (1), (2) ORDER BY (SELECT A FROM MY_TABLE1) LIMIT (SELECT B FROM MY_TABLE2)";
1049+
assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1",
1050+
"MY_TABLE2");
1051+
}
1052+
9101053
}

0 commit comments

Comments
 (0)