77#include " duckdb/parser/statement/select_statement.hpp"
88#include " duckdb/parser/query_node/select_node.hpp"
99#include " duckdb/parser/query_node/cte_node.hpp"
10+ #include " duckdb/parser/query_node/set_operation_node.hpp"
11+ #include " duckdb/parser/result_modifier.hpp"
1012#include " duckdb/parser/tableref/basetableref.hpp"
1113#include " duckdb/parser/tableref/joinref.hpp"
1214#include " duckdb/parser/tableref/subqueryref.hpp"
15+ #include " duckdb/parser/expression/subquery_expression.hpp"
16+ #include " duckdb/parser/parsed_expression_iterator.hpp"
1317#include " duckdb/function/scalar/nested_functions.hpp"
1418
1519namespace duckdb {
@@ -73,6 +77,13 @@ static unique_ptr<GlobalTableFunctionState> ParseTablesInit(ClientContext &conte
7377 return make_uniq<ParseTablesState>();
7478}
7579
80+ // Forward declaration for mutual recursion
81+ static void ExtractTablesFromExpression (
82+ const duckdb::ParsedExpression &expr,
83+ std::vector<TableRefResult> &results,
84+ const duckdb::CommonTableExpressionMap *cte_map
85+ );
86+
7687static void ExtractTablesFromRef (
7788 const duckdb::TableRef &ref,
7889 std::vector<TableRefResult> &results,
@@ -104,6 +115,10 @@ static void ExtractTablesFromRef(
104115 auto &join = (JoinRef &)ref;
105116 ExtractTablesFromRef (*join.left , results, TableContext::JoinLeft, is_top_level, cte_map);
106117 ExtractTablesFromRef (*join.right , results, TableContext::JoinRight, false , cte_map);
118+ // Process JOIN condition for subqueries
119+ if (join.condition ) {
120+ ExtractTablesFromExpression (*join.condition , results, cte_map);
121+ }
107122 break ;
108123 }
109124 case TableReferenceType::SUBQUERY: {
@@ -118,6 +133,33 @@ static void ExtractTablesFromRef(
118133 }
119134}
120135
136+ // Extract tables from expressions that may contain subqueries (WHERE, HAVING, SELECT list, etc.)
137+ static void ExtractTablesFromExpression (
138+ const duckdb::ParsedExpression &expr,
139+ std::vector<TableRefResult> &results,
140+ const duckdb::CommonTableExpressionMap *cte_map
141+ ) {
142+ using namespace duckdb ;
143+
144+ // Check if this is a subquery expression
145+ if (expr.GetExpressionClass () == ExpressionClass::SUBQUERY) {
146+ auto &subquery_expr = (const SubqueryExpression &)expr;
147+ if (subquery_expr.subquery && subquery_expr.subquery ->node ) {
148+ ExtractTablesFromQueryNode (*subquery_expr.subquery ->node , results, TableContext::Subquery, cte_map);
149+ }
150+ // Also process the child expression (e.g., the left side of IN)
151+ if (subquery_expr.child ) {
152+ ExtractTablesFromExpression (*subquery_expr.child , results, cte_map);
153+ }
154+ return ;
155+ }
156+
157+ // Recursively process child expressions
158+ ParsedExpressionIterator::EnumerateChildren (expr,
159+ [&](const ParsedExpression &child) {
160+ ExtractTablesFromExpression (child, results, cte_map);
161+ });
162+ }
121163
122164static void ExtractTablesFromQueryNode (
123165 const duckdb::QueryNode &node,
@@ -144,7 +186,36 @@ static void ExtractTablesFromQueryNode(
144186 if (select_node.from_table ) {
145187 ExtractTablesFromRef (*select_node.from_table , results, context, true , &select_node.cte_map );
146188 }
147- }
189+
190+ // Extract tables from WHERE clause subqueries
191+ if (select_node.where_clause ) {
192+ ExtractTablesFromExpression (*select_node.where_clause , results, &select_node.cte_map );
193+ }
194+
195+ // Extract tables from SELECT list subqueries
196+ for (const auto &expr : select_node.select_list ) {
197+ if (expr) {
198+ ExtractTablesFromExpression (*expr, results, &select_node.cte_map );
199+ }
200+ }
201+
202+ // Extract tables from HAVING clause subqueries
203+ if (select_node.having ) {
204+ ExtractTablesFromExpression (*select_node.having , results, &select_node.cte_map );
205+ }
206+
207+ // Extract tables from QUALIFY clause subqueries
208+ if (select_node.qualify ) {
209+ ExtractTablesFromExpression (*select_node.qualify , results, &select_node.cte_map );
210+ }
211+
212+ // Extract tables from GROUP BY expressions
213+ for (const auto &expr : select_node.groups .group_expressions ) {
214+ if (expr) {
215+ ExtractTablesFromExpression (*expr, results, &select_node.cte_map );
216+ }
217+ }
218+ }
148219 // additional step necessary for duckdb v1.4.0: unwrap CTE node
149220 else if (node.type == QueryNodeType::CTE_NODE) {
150221 auto &cte_node = (CTENode &)node;
@@ -153,6 +224,37 @@ static void ExtractTablesFromQueryNode(
153224 ExtractTablesFromQueryNode (*cte_node.child , results, context, cte_map);
154225 }
155226 }
227+ // Handle UNION/INTERSECT/EXCEPT (set operations)
228+ else if (node.type == QueryNodeType::SET_OPERATION_NODE) {
229+ auto &set_node = (SetOperationNode &)node;
230+
231+ if (set_node.left ) {
232+ ExtractTablesFromQueryNode (*set_node.left , results, context, cte_map);
233+ }
234+ if (set_node.right ) {
235+ ExtractTablesFromQueryNode (*set_node.right , results, context, cte_map);
236+ }
237+ }
238+
239+ // Process result modifiers (ORDER BY, LIMIT) for all node types
240+ for (const auto &modifier : node.modifiers ) {
241+ if (modifier->type == ResultModifierType::ORDER_MODIFIER) {
242+ auto &order_modifier = (OrderModifier &)*modifier;
243+ for (const auto &order : order_modifier.orders ) {
244+ if (order.expression ) {
245+ ExtractTablesFromExpression (*order.expression , results, cte_map);
246+ }
247+ }
248+ } else if (modifier->type == ResultModifierType::LIMIT_MODIFIER) {
249+ auto &limit_modifier = (LimitModifier &)*modifier;
250+ if (limit_modifier.limit ) {
251+ ExtractTablesFromExpression (*limit_modifier.limit , results, cte_map);
252+ }
253+ if (limit_modifier.offset ) {
254+ ExtractTablesFromExpression (*limit_modifier.offset , results, cte_map);
255+ }
256+ }
257+ }
156258}
157259
158260static void ExtractTablesFromSQL (const std::string &sql, std::vector<TableRefResult> &results) {
0 commit comments