From be8be8561dc4b0efe03bf9fd653fc6be64e91571 Mon Sep 17 00:00:00 2001 From: minleejae Date: Sat, 12 Sep 2026 21:47:46 +0900 Subject: [PATCH] Reuse common JOIN traversal when discovering UPDATE tables --- .../sf/jsqlparser/util/TablesNamesFinder.java | 15 +----- .../jsqlparser/util/UpdateJoinTablesTest.java | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/util/UpdateJoinTablesTest.java diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 5931c2fa6..a78847037 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -1393,11 +1393,7 @@ public Void visit(Update update, S context) { visit(update.getTable(), context); } - if (update.getStartJoins() != null) { - for (Join join : update.getStartJoins()) { - join.getRightItem().accept(this, context); - } - } + visitJoins(update.getStartJoins(), context); if (update.getUpdateSets() != null) { for (UpdateSet updateSet : update.getUpdateSets()) { @@ -1410,14 +1406,7 @@ public Void visit(Update update, S context) { update.getFromItem().accept(this, context); } - if (update.getJoins() != null) { - for (Join join : update.getJoins()) { - join.getRightItem().accept(this, context); - for (Expression expression : join.getOnExpressions()) { - expression.accept(this, context); - } - } - } + visitJoins(update.getJoins(), context); if (update.getWhere() != null) { update.getWhere().accept(this, context); diff --git a/src/test/java/net/sf/jsqlparser/util/UpdateJoinTablesTest.java b/src/test/java/net/sf/jsqlparser/util/UpdateJoinTablesTest.java new file mode 100644 index 000000000..f2d505574 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/util/UpdateJoinTablesTest.java @@ -0,0 +1,54 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import java.util.Set; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.update.Update; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class UpdateJoinTablesTest { + @ParameterizedTest + @ValueSource(strings = { + "UPDATE target t JOIN source s ON s.id IN (SELECT id FROM hidden) SET t.a = 1", + "UPDATE target t LEFT JOIN source s ON EXISTS (SELECT 1 FROM hidden h WHERE h.id = s.id) SET t.a = 1", + "UPDATE target SET a = 1 FROM source s JOIN target t ON s.id IN (SELECT id FROM hidden)", + "WITH h AS (SELECT id FROM hidden) UPDATE target t JOIN source s ON s.id IN (SELECT id FROM h) SET t.a = 1"}) + void includesTablesInsideJoinConditions(String sql) throws Exception { + assertEquals(Set.of("target", "source", "hidden"), TablesNamesFinder.findTables(sql)); + } + + @Test + void preservesContextAndVisitsEachSourceOnce() throws Exception { + Update update = (Update) CCJSqlParserUtil.parse( + "UPDATE target t JOIN source s ON s.id IN (SELECT id FROM hidden) SET t.a = 1"); + Object context = new Object(); + java.util.List seen = new java.util.ArrayList<>(); + TablesNamesFinder finder = new TablesNamesFinder() { + { + init(false); + } + + @Override + public Void visit(Table table, S actual) { + assertSame(context, actual); + seen.add(table.getName()); + return null; + } + }; + update.accept(finder, context); + assertEquals(java.util.List.of("target", "source", "hidden"), seen); + } +}