Repository navigation
fix: resolve WITH items by scope in TablesNamesFinder - #2881
Merged
manticore-projects merged 1 commit intoOct 31, 2026
Merged
manticore-projects merged 1 commit into
manticore-projects merged 1 commit into
Conversation
getTables removed every alias and WITH name from its result wherever it was declared, so a real table with such a name went missing: SELECT * FROM (SELECT * FROM secrets) AS secrets found no tables. A name is now left out only where it resolves to a WITH item in scope, and the target of a DML statement never does. WITH lists on VALUES and TABLE selects are now walked too.
Contributor
|
Thank you for fixing this! Appreciated. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TablesNamesFinderdrops a table when its name matches any alias orWITHitem anywhere in the statement:visit(Table)skips names inotherItemNames, andgetTablesthen subtracts that whole set from the result, whatever the scope (the@todothere already doubts it). SoSELECT * FROM (SELECT * FROM secrets) AS secretsreturns no tables, and neither doSELECT (SELECT max(pw) FROM secrets) FROM (SELECT 1) AS secrets,WITH secrets AS (SELECT * FROM secrets) SELECT * FROM secrets,SELECT * FROM secrets WHERE EXISTS (WITH secrets AS (SELECT 1 AS a) SELECT a FROM secrets),DELETE FROM secrets WHERE id IN (SELECT id FROM (SELECT 1 AS id) AS secrets)orWITH secrets AS (SELECT 1 AS id) DELETE FROM secrets, although each one reads or writes the real table. The reporter of #1987 uses the finder to "see if user get access to certain tables", and with a check like that anyone who can submit SQL gets past a table allowlist by reusing the table's name as an alias.WITHonVALUESandTABLEselects was also never walked, soSELECT * FROM (WITH a AS (SELECT * FROM secrets) TABLE a) AS sreportedaand missedsecrets.A reference is now dropped only if it resolves to a
WITHitem in scope at that position. An item becomes visible after its own body, or all at once underRECURSIVE, which the parser sets on the first item but which covers the list, and it leaves scope with its query. DML targets resolve with nothing in scope. Aliases no longer hide table references, but still hide column qualifiers infindTablesInExpression. I comparedfindTableswith the relations in PostgreSQL 16'sEXPLAIN (FORMAT JSON)for 54 statements: it missed a touched table in 25 before and in none after (3 statements still report a table from aWITHitem the planner prunes because nothing references it).Two results change on purpose:
testSubqueryAliasesIssue1987andtestSubqueryAliasesIssue2035pinned the old behaviour, so I updated them. [BUG] JSQLParser Version: 5.0 RDBMS: ANY, TablesNamesFinder.getTables missing table when using same alias #2035 asked forA, B, C, which is now returned. The [BUG] The TablesNamesFinder mistakenly treat nested SELECT in FROM as table #1987 statements, such asSELECT * FROM b, (SELECT * FROM a) AS a1 WHERE b.id IN (SELECT id FROM a1), have the same shape as the bypass, so the finder cannot keep leavinga1out. PostgreSQL, H2 and SQLite all reject them unlessa1is a real table, and read that table when it is.WITH t AS (SELECT 1 AS n UNION ALL SELECT n FROM t) ...withoutRECURSIVEnow reportst, and so do the Oracle recursive statements in the test corpus. PostgreSQL reads a base table there while SQLite recurses, and the finder has no dialect to tell them apart. AWITHitem as a DML target is reported the same way: PostgreSQL resolves it to the base table, while SQL Server can update through a CTE. I could not run Oracle or SQL Server here. Over-reporting is the safe side: as was said on [BUG] The TablesNamesFinder mistakenly treat nested SELECT in FROM as table #1987, "you are supposed to filter the returned list against the actual Meta Data", and that removes a spurious name but cannot bring back a missing one.getTablesOrOtherSourcesreturns the same for all 6,446 statements harvested from the test suite.getTableschanges for 19: 8 alias statements like those in point 1, 8 recursive ones as in point 2, and 3 withWITHonVALUESthat no longer report their item as a table. 31 cases inTablesNamesFinderTestfail before the change and pass after;./gradlew checkandmvn verifypass.