Repository navigation
[BUG] TablesNamesFinder misses tables or throws for piped queries, DML statements and analytic clauses #2478
Copy link
Copy link
Closed
Description
Failing SQL Feature:
TablesNamesFinder misses tables silently or throws for six statement / expression families. Since it is the documented entry point for SQL auditing / firewall use cases, a silently incomplete table list is a security relevant defect.
| # | SQL family | Result on master |
|---|---|---|
| 1 | Piped query | [], every table missing |
| 2 | DELETE with a WITH list |
CTE tables missing, the CTE alias leaks as a phantom table |
| 3 | MERGE |
tables inside the ON condition and the WHEN branches missing |
| 4 | INSERT with SET list, ON DUPLICATE KEY UPDATE or ON CONFLICT ... DO UPDATE; OUTPUT / RETURNING clauses of INSERT / UPDATE / DELETE |
clause subqueries missing |
| 5 | Data modifying CTE (WITH del AS (DELETE FROM ...)) |
ClassCastException |
| 6 | Analytic function with function level ORDER BY, window ORDER BY or FILTER clause |
NullPointerException / silently skipped |
Root causes in TablesNamesFinder.java @ f41c0b8:
visit(FromQuery)returnsnullwithout traversing anything: piped queries were never wired upvisit(Delete)does not traversewithItemsList(Update and Insert do)visit(Merge)does not traverseonConditionandoperationsvisit(Insert)does not traversesetUpdateSets,duplicateAction,conflictAction,outputClause,returningClause;visit(Update)/visit(Delete)skipoutputClause/returningClauseas wellvisit(WithItem)dispatches the payload throughgetSelect(), which assumes a Select, while data modifying CTE payloads (ParenthesedDelete/ParenthesedUpdate/ParenthesedInsert) are legalvisit(AnalyticExpression)guards ongetFuncOrderBy()but iteratesgetOrderByElements(), and skipsfilterExpression; [BUG] NPE in TableNamesFinder in AnalyticExpression visitor #2443 fixed a sibling NPE (window element range / offset) in the same method, this guard went unnoticed
SQL Example:
// 1. piped query: returns []
TablesNamesFinder.findTables("FROM MY_TABLE1 "
+ "|> WHERE id IN (SELECT id FROM MY_TABLE2) "
+ "|> LEFT JOIN (SELECT item FROM MY_TABLE3) AS t3 ON t3.item = item "
+ "|> UNION ALL (SELECT * FROM MY_TABLE4) "
+ "|> SELECT item");
// 2. DELETE with WITH: returns [cte, MY_TABLE1]
TablesNamesFinder.findTables(
"WITH cte AS (SELECT * FROM MY_TABLE2) DELETE FROM MY_TABLE1 WHERE id IN (SELECT id FROM cte)");
// 3. MERGE: returns [src, MY_TABLE1]
TablesNamesFinder.findTables("MERGE INTO MY_TABLE1 USING src "
+ "ON id IN (SELECT id FROM MY_TABLE3) "
+ "WHEN MATCHED THEN UPDATE SET v = (SELECT MAX(v) FROM MY_TABLE4)");
// 4. INSERT actions / clauses: returns [MY_TABLE1]
TablesNamesFinder.findTables(
"INSERT INTO MY_TABLE1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = (SELECT x FROM MY_TABLE2)");
TablesNamesFinder.findTables("UPDATE MY_TABLE1 SET a = 1 RETURNING (SELECT x FROM MY_TABLE2)");
// 5. data modifying CTE: ClassCastException (ParenthesedDelete cannot be cast to ParenthesedSelect)
TablesNamesFinder.findTables(
"WITH del AS (DELETE FROM MY_TABLE2) INSERT INTO MY_TABLE1 SELECT * FROM del");
// 6. analytic function with function level ORDER BY: NullPointerException
// ("...getOrderByElements()" is null because the return value of ...")
TablesNamesFinder.findTables(
"SELECT string_agg(name, ',' ORDER BY id) OVER (PARTITION BY grp) FROM MY_TABLE1");Software Information:
- JSqlParser version: 5.4-SNAPSHOT (master f41c0b8)
- Database: vendor neutral (piped queries: BigQuery / ZetaSQL; data modifying CTEs and FILTER: PostgreSQL; ON DUPLICATE KEY UPDATE: MySQL; OUTPUT: SQL Server)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
fix: complete TablesNamesFinder traversal for piped queries, DML side…