diff --git a/crates/squawk_ide/src/goto_definition.rs b/crates/squawk_ide/src/goto_definition.rs index f848f41b..705f9e6d 100644 --- a/crates/squawk_ide/src/goto_definition.rs +++ b/crates/squawk_ide/src/goto_definition.rs @@ -669,6 +669,31 @@ cross join ((((select u$0.n * 10 as val)))) x; ); } + #[test] + fn goto_lateral_cte_ref_after_lateral_not_found() { + // c is defined after the lateral it isn't visible to the subquery + // Query 1 ERROR at Line 10: : ERROR: missing FROM-clause entry for table "c" + // LINE 10: where d.id = c.id + // ^ + goto_not_found( + " +with + d as (select 1 id, 2 amount), + c as (select 2 id) +select r.amount +from + d, + lateral ( + select d.amount + from d + where d.id = c$0.id + limit 1 + ) r, + c; +", + ); + } + #[test] fn goto_drop_sequence() { assert_snapshot!(goto(" diff --git a/crates/squawk_ide/src/resolve.rs b/crates/squawk_ide/src/resolve.rs index 41ffbb41..ce10bde5 100644 --- a/crates/squawk_ide/src/resolve.rs +++ b/crates/squawk_ide/src/resolve.rs @@ -1795,9 +1795,13 @@ fn find_from_item_for_select_qualified_name_ref( ast::FromItem::cast(ancestor).filter(|from_item| from_item.lateral_token().is_some()) })?; + let lateral_start = lateral_from_item.syntax().text_range().start(); + for ancestor in lateral_from_item.syntax().ancestors() { if let Some(from_clause) = ast::Select::cast(ancestor).and_then(|x| x.from_clause()) - && let Some(outer_from_item) = find_from_item_in_from_clause(&from_clause, table_name) + && let Some(outer_from_item) = ast_nav::iter_from_clause(&from_clause) + .filter(|item| item.syntax().text_range().start() < lateral_start) + .find(|item| is_from_item_match(item, table_name)) { return Some(outer_from_item); }