Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 35 additions & 24 deletions crates/squawk_ide/src/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl Binder {
symbols: Arena::new(),
search_path_changes: vec![SearchPathChange {
position: TextSize::from(0),
search_path: vec![Schema::new("pg_temp"), Schema::new("public")],
search_path: vec![Schema::new("public"), Schema::new("pg_temp")],
}],
}
}
Expand All @@ -40,6 +40,14 @@ impl Binder {
.expect("root scope must exist")
}

fn current_search_path(&self) -> &[Schema] {
&self
.search_path_changes
.last()
.expect("search_path_changes should never be empty")
.search_path
}

pub(crate) fn search_path_at(&self, position: TextSize) -> &[Schema] {
// We're assuming people don't actually use `set search_path` that much,
// so linear search is fine
Expand Down Expand Up @@ -84,7 +92,9 @@ fn bind_create_table(b: &mut Binder, create_table: ast::CreateTable) {
};
let name_ptr = path_to_ptr(&path);
let is_temp = create_table.temp_token().is_some() || create_table.temporary_token().is_some();
let schema = schema_name(&path, is_temp);
let Some(schema) = schema_name(b, &path, is_temp) else {
return;
};

let table_id = b.symbols.alloc(Symbol {
kind: SymbolKind::Table,
Expand Down Expand Up @@ -121,36 +131,34 @@ fn path_to_ptr(path: &ast::Path) -> SyntaxNodePtr {
SyntaxNodePtr::new(path.syntax())
}

fn schema_name(path: &ast::Path, is_temp: bool) -> Schema {
let default_schema = if is_temp { "pg_temp" } else { "public" };

let Some(segment) = path.qualifier().and_then(|q| q.segment()) else {
return Schema::new(default_schema);
};
fn schema_name(b: &Binder, path: &ast::Path, is_temp: bool) -> Option<Schema> {
if let Some(name_ref) = path
.qualifier()
.and_then(|q| q.segment())
.and_then(|s| s.name_ref())
{
return Some(Schema(Name::new(name_ref.syntax().text().to_string())));
}

let schema_name = if let Some(name) = segment.name() {
Name::new(name.syntax().text().to_string())
} else if let Some(name_ref) = segment.name_ref() {
Name::new(name_ref.syntax().text().to_string())
} else {
return Schema::new(default_schema);
};
if is_temp {
return Some(Schema::new("pg_temp"));
}

Schema(schema_name)
b.current_search_path().first().cloned()
}

fn bind_set(b: &mut Binder, set: ast::Set) {
let position = set.syntax().text_range().start();

// `set schema` is an alternative to `set search_path`
if set.schema_token().is_some() {
if let Some(literal) = set.literal() {
if let Some(string_value) = extract_string_literal(&literal) {
b.search_path_changes.push(SearchPathChange {
position,
search_path: vec![Schema::new(string_value)],
});
}
if let Some(literal) = set.literal()
&& let Some(string_value) = extract_string_literal(&literal)
{
b.search_path_changes.push(SearchPathChange {
position,
search_path: vec![Schema::new(string_value)],
});
}
return;
}
Expand Down Expand Up @@ -179,14 +187,17 @@ fn bind_set(b: &mut Binder, set: ast::Set) {
if set.default_token().is_some() {
b.search_path_changes.push(SearchPathChange {
position,
search_path: vec![Schema::new("pg_temp"), Schema::new("public")],
search_path: vec![Schema::new("public"), Schema::new("pg_temp")],
});
} else {
let mut search_path = vec![];
for config_value in set.config_values() {
match config_value {
ast::ConfigValue::Literal(literal) => {
if let Some(string_value) = extract_string_literal(&literal) {
// You can unset the search path via `set search_path = ''`
// so we want to skip over these, otherwise we'll
// have a schema of value `''` which isn't valid.
if !string_value.is_empty() {
search_path.push(Schema::new(string_value));
}
Expand Down
6 changes: 2 additions & 4 deletions crates/squawk_ide/src/find_references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ table users;
}

#[test]
fn temp_table_shadows_public() {
fn temp_table_do_not_shadows_public() {
assert_snapshot!(find_refs("
create table t();
create temp table t$0();
Expand All @@ -190,9 +190,7 @@ drop table t;
│ ┬
│ │
│ 0. query
│ 1. reference
4 │ drop table t;
╰╴ ─ 2. reference
╰╴ 1. reference
");
}

Expand Down
29 changes: 28 additions & 1 deletion crates/squawk_ide/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,9 @@ create temp table t();
drop table t$0;
"), @r"
╭▸
2 │ create table t();
│ ─ 2. destination
3 │ create temp table t();
│ ─ 2. destination
4 │ drop table t;
╰╴ ─ 1. source
");
Expand Down Expand Up @@ -474,6 +475,32 @@ drop table t$0;
");
}

#[test]
fn goto_with_search_path_and_unspecified_table() {
assert_snapshot!(goto(r#"
set search_path to foo,bar;
create table t();
drop table foo.t$0;
"#), @r"
╭▸
3 │ create table t();
│ ─ 2. destination
4 │ drop table foo.t;
╰╴ ─ 1. source
");
}

#[test]
fn goto_with_search_path_empty() {
goto_not_found(
r#"
set search_path = '';
create table t();
drop table t$0;
"#,
);
}

#[test]
fn goto_with_search_path_like_variable() {
// not actually search path
Expand Down
Loading