Line data Source code
1 : //! Name resolution.
2 : //!
3 : //! The visit collects table references, derived tables, column references, result targets, CTEs and
4 : //! declarations bottom-up and groups them into name scopes. Finish resolves the names of all scopes,
5 : //! populates derived tables, assigns statement ids and runs the schema inference.
6 : //!
7 : //! Column refs resolve against the FROM items of a scope (tables, CTEs, derived tables), each with
8 : //! its ordered columns. Expression subqueries see the FROM items of their parents, derived tables and
9 : //! CTEs only those above their parent, lateral derived tables also the FROM items before them.
10 : //!
11 : //! The node states hold vectors of ids, and merging a child moves its entries to the end.
12 :
13 : use super::sql_types::read_sql_type;
14 : use super::state::{quote_identifier, AnalysisState};
15 : use super::types::*;
16 : use crate::catalog::*;
17 : use crate::table_parameters::{TableParameterLookup, TABLE_PARAMETERS_ENTRY_ID};
18 : use dashql_buffers::analyzer::{AnalyzerErrorSeverity, AnalyzerErrorType, NameTag, SemanticNodeMarkerType};
19 : use dashql_buffers::parser::{AttributeKey as K, JoinType, Node, NodeType, StatementType, SymbolSpan};
20 : use dashql_parser::attrs;
21 : use crate::hash::{HashMap, HashSet};
22 : use std::ops::Range;
23 : use std::sync::Arc;
24 :
25 : /// The maximum number of tables a reference may resolve to
26 : const MAX_TABLE_REF_AMBIGUITY: usize = 100;
27 :
28 : /// A table column collected from a column definition
29 : #[derive(Clone)]
30 : struct PendingColumn {
31 : /// The AST node id of the column definition
32 : ast_node_id: u32,
33 : /// The column name
34 : column_name: Name,
35 : /// The text of the declared type
36 : column_type: Option<Arc<str>>,
37 : }
38 :
39 : /// The state of a node during name resolution
40 : #[derive(Default)]
41 : struct NodeState {
42 : /// The scopes created in the subtree that have no parent scope yet
43 : child_scopes: Vec<ScopeId>,
44 : /// The column definitions of a CREATE TABLE
45 : table_columns: Vec<PendingColumn>,
46 : /// The table references not yet attached to a scope
47 : table_references: Vec<TableRefId>,
48 : /// The column ref expressions not yet attached to a scope
49 : column_references: Vec<ExprId>,
50 : /// The result targets of the enclosing SELECT
51 : result_targets: Vec<ResultTarget>,
52 : /// The CTE definitions of the enclosing WITH clause
53 : ctes: Vec<CteDefinition>,
54 : /// The derived tables, the FROM items of the next scope
55 : derived_tables: Vec<ScopeSource>,
56 : /// The joins with USING or NATURAL of the next scope
57 : using_joins: Vec<UsingJoin>,
58 : }
59 :
60 : /// Move the entries of a list to the end of another one. Takes over the buffer if the destination is
61 : /// empty, so states move up the tree without copying.
62 : #[inline]
63 527376 : fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
64 527376 : if dst.is_empty() {
65 510232 : std::mem::swap(dst, src);
66 510232 : } else {
67 17144 : dst.append(src);
68 17144 : }
69 527376 : }
70 :
71 : impl NodeState {
72 65922 : fn merge(&mut self, other: &mut NodeState) {
73 65922 : append(&mut self.child_scopes, &mut other.child_scopes);
74 65922 : append(&mut self.table_columns, &mut other.table_columns);
75 65922 : append(&mut self.table_references, &mut other.table_references);
76 65922 : append(&mut self.column_references, &mut other.column_references);
77 65922 : append(&mut self.result_targets, &mut other.result_targets);
78 65922 : append(&mut self.ctes, &mut other.ctes);
79 65922 : append(&mut self.derived_tables, &mut other.derived_tables);
80 65922 : append(&mut self.using_joins, &mut other.using_joins);
81 65922 : }
82 :
83 5830 : fn clear(&mut self) {
84 5830 : *self = NodeState::default();
85 5830 : }
86 : }
87 :
88 : /// A join with USING, or NATURAL that uses all common columns. The USING columns of both inputs
89 : /// are one column of the join.
90 : struct UsingJoin {
91 : /// The AST node id of the joined table
92 : ast_node_id: u32,
93 : /// The USING columns, all common columns of a NATURAL join if None
94 : using: Option<Vec<Arc<str>>>,
95 : }
96 :
97 : impl UsingJoin {
98 9 : fn uses(&self, column_name: &str) -> bool {
99 9 : self.using.as_ref().is_none_or(|using| using.iter().any(|c| &**c == column_name))
100 9 : }
101 : }
102 :
103 : /// The result of looking up a column ref in the FROM items of a scope
104 : #[derive(Clone, Copy, PartialEq, Eq)]
105 : enum Lookup {
106 : Resolved,
107 : Ambiguous,
108 : Missing,
109 : }
110 :
111 : /// How a column ref sees the output columns of its own scope
112 : #[derive(Clone, Copy, PartialEq, Eq)]
113 : enum OutputNames {
114 : Invisible,
115 : /// A bare name in ORDER BY refers to an output column before a FROM item column
116 : Preferred,
117 : /// A bare name in GROUP BY refers to an output column if no FROM item has the column
118 : Fallback,
119 : }
120 :
121 : /// A declaration whose columns are derived after its SELECT scope is resolved
122 : struct PendingDerivedTable {
123 : /// The table declaration (index into the table declarations of the script)
124 : table: u32,
125 : /// The AST node id of the SELECT that defines the columns
126 : select_node_id: u32,
127 : /// The declared column names, they rename the leading output columns
128 : column_aliases: Vec<Name>,
129 : }
130 :
131 : /// The root scopes.
132 : ///
133 : /// The set iterates in insertion order, and erasing moves the last element into the hole (see
134 : /// docs/design/core_quirks.md).
135 : #[derive(Default)]
136 : struct RootScopes {
137 : /// The root scopes in insertion order
138 : values: Vec<ScopeId>,
139 : /// The position of every root scope in the values
140 : positions: HashMap<ScopeId, usize>,
141 : }
142 :
143 : impl RootScopes {
144 5774 : fn insert(&mut self, scope: ScopeId) {
145 5774 : if self.positions.contains_key(&scope) {
146 0 : return;
147 5774 : }
148 5774 : self.positions.insert(scope, self.values.len());
149 5774 : self.values.push(scope);
150 5774 : }
151 :
152 610 : fn erase(&mut self, scope: ScopeId) {
153 610 : let Some(pos) = self.positions.remove(&scope) else { return };
154 610 : let last = self.values.pop().unwrap();
155 610 : if pos < self.values.len() {
156 82 : self.values[pos] = last;
157 82 : self.positions.insert(last, pos);
158 528 : }
159 610 : }
160 : }
161 :
162 : /// The pass that groups names into scopes and resolves tables and columns
163 : pub(super) struct NameResolutionPass {
164 : /// The state of every AST node
165 : node_states: Vec<NodeState>,
166 : /// Does the script contain property graph syntax?
167 : has_graph_syntax: bool,
168 : /// The scopes without a parent scope
169 : root_scopes: RootScopes,
170 : /// The table declarations whose columns are derived after resolution
171 : pending_derived_tables: Vec<PendingDerivedTable>,
172 : /// The column actions of `ALTER` statements on tables of `CREATE TABLE AS`: the table and the action
173 : pending_alters: Vec<(u32, u32)>,
174 : /// The joins with USING or NATURAL of the scopes
175 : using_joins: HashMap<ScopeId, Vec<UsingJoin>>,
176 : /// The column refs that were reported as ambiguous
177 : ambiguous_column_refs: HashSet<ExprId>,
178 : }
179 :
180 : impl NameResolutionPass {
181 4003 : pub fn new(state: &AnalysisState) -> Self {
182 4003 : let mut node_states = Vec::with_capacity(state.ast.len());
183 4003 : node_states.resize_with(state.ast.len(), NodeState::default);
184 4003 : let has_graph_syntax = state
185 4003 : .ast
186 4003 : .iter()
187 83811 : .any(|n| matches!(n.node_type(), NodeType::OBJECT_SQL_PROPERTY_GRAPH | NodeType::OBJECT_SQL_GRAPH_TABLE));
188 4003 : Self {
189 4003 : node_states,
190 4003 : has_graph_syntax,
191 4003 : root_scopes: RootScopes::default(),
192 4003 : pending_derived_tables: Vec::new(),
193 4003 : pending_alters: Vec::new(),
194 4003 : using_joins: HashMap::default(),
195 4003 : ambiguous_column_refs: HashSet::default(),
196 4003 : }
197 4003 : }
198 :
199 : /// Merge the states of all children of a node
200 77839 : fn merge_child_states(&mut self, dst: &mut NodeState, node: &Node) {
201 77839 : let begin = node.children_begin_or_value() as usize;
202 77839 : for child in begin..begin + node.children_count() as usize {
203 64145 : dst.merge(&mut self.node_states[child]);
204 64145 : }
205 77839 : }
206 :
207 : /// Create a naming scope
208 5774 : fn create_scope(&mut self, state: &mut AnalysisState, target: &mut NodeState, scope_root: u32) -> ScopeId {
209 5774 : let scope_id = state.out.name_scopes.len() as ScopeId;
210 5774 : state.out.name_scopes_by_root_node.entry(scope_root).or_insert(scope_id);
211 5774 : for &child in &target.child_scopes {
212 610 : state.out.name_scopes[child as usize].parent_scope = Some(scope_id);
213 610 : self.root_scopes.erase(child);
214 610 : }
215 5790 : for &expr in &target.column_references {
216 2704 : if let Some(column_ref) = state.out.expressions[expr as usize].column_ref_mut() {
217 2704 : column_ref.ast_scope_root = Some(scope_root);
218 2704 : }
219 : }
220 5776 : for &table_ref in &target.table_references {
221 2568 : state.out.table_references[table_ref as usize].ast_scope_root = Some(scope_root);
222 2568 : }
223 5774 : let using_joins = std::mem::take(&mut target.using_joins);
224 5774 : if !using_joins.is_empty() {
225 46 : self.using_joins.insert(scope_id, using_joins);
226 5728 : }
227 5774 : state.out.name_scopes.push(NameScope {
228 5774 : name_scope_id: scope_id,
229 5774 : ast_node_id: scope_root,
230 5774 : child_scopes: std::mem::take(&mut target.child_scopes),
231 5774 : expressions: std::mem::take(&mut target.column_references),
232 5774 : table_references: std::mem::take(&mut target.table_references),
233 5774 : // The table refs are added when they are resolved
234 5774 : sources: std::mem::take(&mut target.derived_tables),
235 5774 : ..Default::default()
236 5774 : });
237 : // Start a new scope
238 5774 : target.clear();
239 5774 : target.child_scopes.push(scope_id);
240 5774 : self.root_scopes.insert(scope_id);
241 5774 : scope_id
242 5774 : }
243 :
244 : /// Register a schema and its database
245 1979 : fn register_schema(state: &mut AnalysisState, database_name: &Name, schema_name: &Name) -> QualifiedCatalogObjectId {
246 1979 : let db_id = match state.out.entry.databases_by_name.get(&database_name.text) {
247 680 : Some(&i) => state.out.entry.database_references[i].object_id,
248 : None => {
249 1299 : let db_id = state.catalog.reserve_database_id(&database_name.text);
250 1299 : let index = state.out.entry.database_references.len();
251 1299 : state.entry_mut().database_references.push(DatabaseReference {
252 1299 : object_id: db_id,
253 1299 : database_name: database_name.text.clone(),
254 1299 : database_alias: Arc::from(""),
255 1299 : });
256 1299 : state.entry_mut().databases_by_name.insert(database_name.text.clone(), index);
257 1299 : state.resolve_name(database_name, CatalogObjectRef::Database(state.loc(index)));
258 1299 : db_id
259 : }
260 : };
261 1979 : let key = (database_name.text.clone(), schema_name.text.clone());
262 1979 : match state.out.entry.schemas_by_qualified_name.get(&key) {
263 663 : Some(&i) => state.out.entry.schema_references[i].object_id,
264 : None => {
265 1316 : let schema_id = state.catalog.reserve_schema_id(&database_name.text, &schema_name.text, db_id);
266 1316 : let index = state.out.entry.schema_references.len();
267 1316 : state.entry_mut().schema_references.push(SchemaReference {
268 1316 : object_id: schema_id,
269 1316 : database_name: database_name.text.clone(),
270 1316 : schema_name: schema_name.text.clone(),
271 1316 : });
272 1316 : state.entry_mut().schemas_by_qualified_name.insert(key, index);
273 1316 : state.resolve_name(schema_name, CatalogObjectRef::Schema(state.loc(index)));
274 1316 : schema_id
275 : }
276 : }
277 1979 : }
278 :
279 1996 : fn is_explain(state: &AnalysisState, statement_id: Option<u32>) -> bool {
280 1996 : statement_id
281 1996 : .and_then(|id| state.parsed.statements.get(id as usize))
282 1996 : .is_some_and(|s| s.statement_type == StatementType::EXPLAIN)
283 1996 : }
284 :
285 : /// Apply an `ALTER` to the declaration of the script, later statements read the table as the statement leaves it. A
286 : /// table that the script doesn't declare stays what the catalog says, the connection answers once the statement ran. A
287 : /// table of `CREATE TABLE AS` gets its columns later, its actions wait for them.
288 41 : fn visit_alter(&mut self, state: &mut AnalysisState, node: &Node, node_id: u32) {
289 41 : let [name_node, actions] = attrs!(state.children(node), [K::SQL_ALTER_TABLE_NAME, K::SQL_ALTER_TABLE_ACTIONS]);
290 41 : let Some(name) = state.read_qualified_table_name(name_node) else { return };
291 41 : let Some(actions) = actions.filter(|n| n.node_type() == NodeType::ARRAY) else { return };
292 : // The parts that a name leaves out match any, as in a reference to the table
293 64 : let part = |named: &Name, declared: &Name| named.text.is_empty() || named.text == declared.text;
294 41 : let declared = state.out.entry.table_declarations.iter().rposition(|t| {
295 34 : t.table_name.table_name.text == name.table_name.text
296 32 : && part(&name.schema_name, &t.table_name.schema_name)
297 30 : && part(&name.database_name, &t.table_name.database_name)
298 34 : });
299 41 : let Some(mut table) = declared.map(|index| index as u32) else { return };
300 33 : for action in state.children(actions) {
301 33 : match action.node_type() {
302 : NodeType::OBJECT_SQL_ALTER_RENAME_TABLE | NodeType::OBJECT_SQL_ALTER_SET_SCHEMA => {
303 13 : let [new_table, new_schema] = attrs!(state.children(action), [K::SQL_ALTER_ACTION_NEW_TABLE, K::SQL_ALTER_ACTION_NEW_NAME]);
304 13 : let source = state.out.entry.table_declarations[table as usize].table_name.clone();
305 13 : let moved = match new_table {
306 11 : Some(new_table) => state.read_qualified_table_name(Some(new_table)),
307 2 : None => Some(source.clone()),
308 : };
309 13 : let Some(mut moved) = moved else { continue };
310 : // What a new name leaves out stays as it is
311 13 : if let Some(new_schema) = new_schema.filter(|n| n.node_type() == NodeType::NAME) {
312 2 : moved.schema_name = state.node_name(new_schema);
313 11 : } else if moved.schema_name.text.is_empty() {
314 9 : moved.schema_name = source.schema_name.clone();
315 9 : }
316 13 : if moved.database_name.text.is_empty() {
317 12 : moved.database_name = source.database_name.clone();
318 12 : }
319 13 : table = self.move_declaration(state, table, &moved, node_id);
320 : }
321 20 : _ => match self.pending_derived_tables.iter().find(|p| p.table == table) {
322 4 : Some(_) => self.pending_alters.push((table, state.node_id(action))),
323 16 : None => Self::apply_column_action(state, table, action),
324 : },
325 : }
326 : }
327 41 : }
328 :
329 : /// The declaration of a relation under its new name, the old one stays for the statements before the `ALTER`
330 13 : fn move_declaration(&mut self, state: &mut AnalysisState, table: u32, name: &QualifiedTableName, node_id: u32) -> u32 {
331 13 : let schema_id = Self::register_schema(state, &name.database_name, &name.schema_name);
332 13 : let table_id = state.reserve_table_id(name);
333 13 : let source = &state.out.entry.table_declarations[table as usize];
334 13 : let (is_view, source_columns) = (source.is_view, source.table_columns.clone());
335 13 : let index = state.out.entry.table_declarations.len() as u32;
336 13 : let mut moved = TableDeclaration::new(schema_id, table_id, name.clone());
337 13 : moved.ast_node_id = Some(node_id);
338 13 : moved.ast_statement_id = state.find_statement_id(node_id);
339 13 : moved.is_view = is_view;
340 13 : let column_ids = state.reserve_column_ids(table_id, source_columns.iter().map(|c| &c.column_name.text));
341 14 : for (column_index, source) in source_columns.iter().enumerate() {
342 12 : moved.table_columns_by_name.entry(source.column_name.text.clone()).or_insert(column_index);
343 12 : moved.table_columns.push(TableColumn {
344 12 : object_id: QualifiedCatalogObjectId::table_column(table_id, column_ids[column_index]),
345 12 : table: Some(table_id),
346 12 : ..source.clone()
347 12 : });
348 12 : state.resolve_name(&source.column_name, CatalogObjectRef::Column(ColumnLoc { table: TableLoc { entry: state.entry_id, index }, column: column_index as u32 }));
349 12 : }
350 13 : state.entry_mut().table_declarations.push(moved);
351 13 : state.resolve_name(&name.table_name, CatalogObjectRef::Table(TableLoc { entry: state.entry_id, index }));
352 : // A table of `CREATE TABLE AS` gets its columns from the same query
353 13 : if let Some(pending) = self.pending_derived_tables.iter().find(|p| p.table == table) {
354 2 : let pending = PendingDerivedTable { table: index, select_node_id: pending.select_node_id, column_aliases: pending.column_aliases.clone() };
355 2 : self.pending_derived_tables.push(pending);
356 2 : let queued: Vec<(u32, u32)> = self.pending_alters.iter().filter(|(t, _)| *t == table).map(|(_, action)| (index, *action)).collect();
357 2 : self.pending_alters.extend(queued);
358 11 : }
359 13 : index
360 13 : }
361 :
362 : /// Apply an action that changes the columns of a declared table
363 21 : fn apply_column_action(state: &mut AnalysisState, table: u32, action: &Node) {
364 21 : let table_id = state.out.entry.table_declarations[table as usize].table_id();
365 21 : let entry_id = state.entry_id;
366 21 : let loc = move |column: u32| ColumnLoc { table: TableLoc { entry: entry_id, index: table }, column };
367 21 : let [column, new_name, column_type] =
368 21 : attrs!(state.children(action), [K::SQL_ALTER_ACTION_COLUMN, K::SQL_ALTER_ACTION_NEW_NAME, K::SQL_ALTER_ACTION_TYPE]);
369 21 : let Some(column) = column else { return };
370 21 : match action.node_type() {
371 : NodeType::OBJECT_SQL_ALTER_ADD_COLUMN => {
372 10 : let [name, declared_type] = attrs!(state.children(column), [K::SQL_COLUMN_DEF_NAME, K::SQL_COLUMN_DEF_TYPE]);
373 10 : let Some(name) = name.filter(|n| n.node_type() == NodeType::NAME) else { return };
374 10 : let name = state.node_name(name);
375 10 : state.tag(&name, NameTag::COLUMN_NAME);
376 10 : if state.out.entry.table_declarations[table as usize].table_columns_by_name.contains_key(&name.text) {
377 1 : return;
378 9 : }
379 9 : let column_id = state.reserve_column_ids(table_id, std::iter::once(&name.text))[0];
380 9 : let column_type = declared_type.and_then(|t| read_sql_type(state.parsed, t)).map(|t| Arc::from(t.to_string()));
381 9 : let ast_node_id = state.node_id(column);
382 9 : let location = state.text_span(*column.symbol_span());
383 9 : let table_declaration = &mut state.entry_mut().table_declarations[table as usize];
384 9 : let column_index = table_declaration.table_columns.len();
385 9 : table_declaration.table_columns_by_name.insert(name.text.clone(), column_index);
386 9 : table_declaration.table_columns.push(TableColumn {
387 9 : object_id: QualifiedCatalogObjectId::table_column(table_id, column_id),
388 9 : table: Some(table_id),
389 9 : ast_node_id: Some(ast_node_id),
390 9 : column_name: name.clone(),
391 9 : column_type,
392 9 : location: Some(location),
393 9 : });
394 9 : let object = CatalogObjectRef::Column(loc(column_index as u32));
395 9 : state.resolve_name(&name, object);
396 : }
397 : NodeType::OBJECT_SQL_ALTER_DROP_COLUMN | NodeType::OBJECT_SQL_ALTER_RENAME_COLUMN | NodeType::OBJECT_SQL_ALTER_COLUMN_TYPE => {
398 11 : if column.node_type() != NodeType::NAME {
399 0 : return;
400 11 : }
401 11 : let name = state.node_name(column);
402 11 : let Some(&column_index) = state.out.entry.table_declarations[table as usize].table_columns_by_name.get(&name.text) else { return };
403 11 : match action.node_type() {
404 : NodeType::OBJECT_SQL_ALTER_DROP_COLUMN => {
405 7 : let table_declaration = &mut state.entry_mut().table_declarations[table as usize];
406 7 : table_declaration.table_columns.remove(column_index);
407 7 : table_declaration.table_columns_by_name.clear();
408 8 : for (i, column) in table_declaration.table_columns.iter().enumerate() {
409 7 : let text = column.column_name.text.clone();
410 7 : table_declaration.table_columns_by_name.entry(text).or_insert(i);
411 7 : }
412 : // The name index holds positions of columns
413 7 : let entry = state.entry_id;
414 19 : state.out.name_objects.retain_mut(|(_, _, object)| match object {
415 19 : CatalogObjectRef::Column(c) if c.table.entry == entry && c.table.index == table => {
416 14 : if c.column as usize == column_index {
417 7 : return false;
418 7 : }
419 7 : if c.column as usize > column_index {
420 7 : c.column -= 1;
421 7 : }
422 7 : true
423 : }
424 29 : _ => true,
425 43 : });
426 : }
427 : NodeType::OBJECT_SQL_ALTER_RENAME_COLUMN => {
428 3 : let Some(new_name) = new_name.filter(|n| n.node_type() == NodeType::NAME) else { return };
429 3 : let new_name = state.node_name(new_name);
430 3 : state.tag(&new_name, NameTag::COLUMN_NAME);
431 3 : let column_id = state.reserve_column_ids(table_id, std::iter::once(&new_name.text))[0];
432 3 : let table_declaration = &mut state.entry_mut().table_declarations[table as usize];
433 3 : table_declaration.table_columns_by_name.remove(&name.text);
434 3 : table_declaration.table_columns_by_name.insert(new_name.text.clone(), column_index);
435 3 : let declared = &mut table_declaration.table_columns[column_index];
436 3 : declared.object_id = QualifiedCatalogObjectId::table_column(table_id, column_id);
437 3 : declared.column_name = new_name.clone();
438 3 : let (entry, object) = (state.entry_id, CatalogObjectRef::Column(loc(column_index as u32)));
439 4 : state.out.name_objects.retain(|(_, _, o)| !matches!(o, CatalogObjectRef::Column(c) if c.table.entry == entry && c.table.index == table && c.column as usize == column_index));
440 3 : state.resolve_name(&new_name, object);
441 : }
442 : _ => {
443 1 : let declared_type = column_type.and_then(|t| read_sql_type(state.parsed, t)).map(|t| Arc::from(t.to_string()));
444 1 : state.entry_mut().table_declarations[table as usize].table_columns[column_index].column_type = declared_type;
445 : }
446 : }
447 : }
448 0 : _ => {}
449 : }
450 21 : }
451 :
452 : /// Register a table-like declaration backed by a SELECT scope
453 177 : fn register_derived_table(
454 177 : &mut self,
455 177 : state: &mut AnalysisState,
456 177 : declaration_node: &Node,
457 177 : name_node: Option<&Node>,
458 177 : columns_node: Option<&Node>,
459 177 : select_node: &Node,
460 177 : ) {
461 177 : let declaration_id = state.node_id(declaration_node);
462 : // EXPLAIN describes a declaration, publishing it would create a phantom catalog producer
463 177 : if Self::is_explain(state, state.find_statement_id(declaration_id)) {
464 24 : return;
465 153 : }
466 153 : let Some(table_name) = state.read_qualified_table_name(name_node) else { return };
467 153 : let schema_id = Self::register_schema(state, &table_name.database_name, &table_name.schema_name);
468 153 : let index = state.out.entry.table_declarations.len() as u32;
469 153 : let table_id = state.reserve_table_id(&table_name);
470 153 : let name = table_name.table_name.clone();
471 153 : let mut table = TableDeclaration::new(schema_id, table_id, table_name);
472 153 : table.ast_node_id = Some(declaration_id);
473 153 : table.ast_statement_id = state.find_statement_id(declaration_id);
474 153 : table.ast_scope_root = Some(state.node_id(select_node));
475 153 : table.is_view = declaration_node.node_type() == NodeType::OBJECT_SQL_VIEW;
476 153 : table.location = name_node.map(|n| state.text_span(*n.symbol_span()));
477 153 : state.entry_mut().table_declarations.push(table);
478 153 : state.resolve_name(&name, CatalogObjectRef::Table(TableLoc { entry: state.entry_id, index }));
479 :
480 153 : let mut column_aliases = Vec::new();
481 153 : if let Some(columns) = columns_node.filter(|n| n.node_type() == NodeType::ARRAY) {
482 7 : for column in state.children(columns) {
483 7 : if column.node_type() != NodeType::NAME {
484 0 : continue;
485 7 : }
486 7 : let name = state.node_name(column);
487 7 : state.tag(&name, NameTag::COLUMN_NAME);
488 7 : column_aliases.push(name);
489 : }
490 149 : }
491 153 : self.pending_derived_tables.push(PendingDerivedTable {
492 153 : table: index,
493 153 : select_node_id: state.node_id(select_node),
494 153 : column_aliases,
495 153 : });
496 177 : }
497 :
498 : /// Materialize a pending declaration after its SELECT scope has output columns
499 155 : fn populate_derived_table(state: &mut AnalysisState, pending: &PendingDerivedTable, scope: ScopeId) {
500 155 : let mut output_scope = scope;
501 : {
502 155 : let s = &state.out.name_scopes[scope as usize];
503 155 : if s.output_columns.is_empty() && !s.child_scopes.is_empty() {
504 0 : output_scope = s.child_scopes[0];
505 155 : }
506 : }
507 155 : let outputs = &state.out.name_scopes[output_scope as usize].output_columns;
508 : // The names of the columns with their output columns
509 155 : let columns: Vec<(Name, u32)> = if !pending.column_aliases.is_empty() {
510 4 : let count = pending.column_aliases.len().min(outputs.len());
511 4 : pending.column_aliases[..count].iter().cloned().zip(0..).collect()
512 : } else {
513 : // A declared table has unique column names
514 151 : let mut seen = HashSet::default();
515 151 : outputs
516 151 : .iter()
517 151 : .zip(0..)
518 175 : .filter(|(o, _)| !o.column_name.text.is_empty() && seen.insert(o.column_name.text.clone()))
519 173 : .map(|(o, output)| (o.column_name.clone(), output))
520 151 : .collect()
521 : };
522 155 : let table_index = pending.table;
523 155 : let table_id = state.out.entry.table_declarations[table_index as usize].table_id();
524 155 : let column_ids = state.reserve_column_ids(table_id, columns.iter().map(|(n, _)| &n.text));
525 180 : for (column_index, (column_name, output)) in columns.into_iter().enumerate() {
526 : // Only a column that is passed through keeps a known type, expressions have no type in the analyzer
527 136 : let source = Self::resolved_table_column(state, ColumnResolution::ScopeColumn { scope: output_scope, column: output });
528 136 : let column_type = source.and_then(|loc| state.table(loc.table)?.table_columns.get(loc.column as usize)?.column_type.clone());
529 136 : let table = &mut state.entry_mut().table_declarations[table_index as usize];
530 136 : table.table_columns_by_name.entry(column_name.text.clone()).or_insert(column_index);
531 136 : table.table_columns.push(TableColumn {
532 136 : object_id: QualifiedCatalogObjectId::table_column(table_id, column_ids[column_index]),
533 136 : table: Some(table_id),
534 136 : ast_node_id: None,
535 136 : column_name: column_name.clone(),
536 136 : column_type,
537 136 : location: None,
538 136 : });
539 136 : let loc = ColumnLoc {
540 136 : table: TableLoc { entry: state.entry_id, index: table_index },
541 136 : column: column_index as u32,
542 136 : };
543 136 : state.resolve_name(&column_name, CatalogObjectRef::Column(loc));
544 : }
545 155 : }
546 :
547 : /// The alias under which a table reference is registered in its scope
548 2556 : fn table_ref_alias(table_ref: &TableReference, fallback: &Arc<str>) -> Arc<str> {
549 2556 : match &table_ref.alias {
550 193 : Some((alias, _)) => alias.text.clone(),
551 2363 : None => fallback.clone(),
552 : }
553 2556 : }
554 :
555 : /// Read an alias clause, the alias name with its location and the column names
556 2640 : fn read_alias(state: &mut AnalysisState, alias: Option<&Node>) -> (Option<(Name, SymbolSpan)>, Vec<Name>) {
557 266 : let (name, columns) = match alias {
558 266 : Some(alias) if alias.node_type() == NodeType::NAME => (Some(alias), None),
559 9 : Some(alias) if alias.node_type() == NodeType::OBJECT_SQL_ALIAS => {
560 9 : let [name, columns] = attrs!(state.children(alias), [K::SQL_ALIAS_NAME, K::SQL_ALIAS_COLUMN_NAMES]);
561 9 : (name.filter(|n| n.node_type() == NodeType::NAME), columns.filter(|n| n.node_type() == NodeType::ARRAY))
562 : }
563 2374 : _ => return (None, Vec::new()),
564 : };
565 266 : let name = name.map(|node| {
566 266 : let name = state.node_name(node);
567 266 : state.tag(&name, NameTag::TABLE_ALIAS);
568 266 : (name, *node.symbol_span())
569 266 : });
570 266 : let mut column_aliases = Vec::new();
571 266 : for column in columns.map(|c| state.children(c)).unwrap_or_default() {
572 13 : if column.node_type() == NodeType::NAME {
573 13 : let column_name = state.node_name(column);
574 13 : state.tag(&column_name, NameTag::COLUMN_NAME);
575 13 : column_aliases.push(column_name);
576 13 : }
577 : }
578 266 : (name, column_aliases)
579 2640 : }
580 :
581 : /// The FROM item of a table parameter `:foo` that reads the result of the script `foo.sql` or the attachment
582 : /// `foo.parquet`, None if the parameter is positional, the target of a write, ambiguous, or names no table parameter
583 : /// with columns
584 870 : fn table_parameter_source(state: &mut AnalysisState, node_id: u32, node: &Node, table_node: Option<&Node>, alias_node: Option<&Node>) -> Option<(ScopeSource, TableRefId)> {
585 870 : let parameter = table_node.filter(|n| n.node_type() == NodeType::OBJECT_SQL_PARAMETER_REF)?;
586 717 : if matches!(node.attribute_key(), K::SQL_INSERT_TARGET | K::SQL_DELETE_TARGET) {
587 21 : return None;
588 696 : }
589 696 : let results = state.out.table_parameters.clone()?;
590 17 : let [name] = attrs!(state.children(parameter), [K::SQL_PARAMETER_NAME]);
591 17 : let name = name.and_then(|n| state.read_name_path(n).last().map(|&id| state.name(id).text))?;
592 17 : let name: Arc<str> = match name.strip_prefix('\'').and_then(|n| n.strip_suffix('\'')) {
593 0 : Some(inner) => inner.into(),
594 17 : None => name,
595 : };
596 17 : let TableParameterLookup::Found(index) = results.find(&name) else { return None };
597 13 : let table = results.entries[index].table.as_ref()?;
598 12 : let (alias, column_aliases) = Self::read_alias(state, alias_node);
599 : // A table reference that is resolved already, the cursor, the focus and the semantic spans see the parameter
600 : // like a table. Scope resolution, the planner and the script references skip it.
601 12 : let id = state.out.table_references.len() as TableRefId;
602 12 : state.out.table_references.push(TableReference {
603 12 : table_reference_id: ExternalObjectId::new(state.entry_id, id),
604 12 : ast_node_id: node_id,
605 12 : location: Some(*node.symbol_span()),
606 12 : ast_statement_id: None,
607 12 : ast_scope_root: None,
608 12 : alias: alias.clone(),
609 12 : column_aliases: column_aliases.clone(),
610 12 : inner: Some(RelationExpression {
611 12 : table_name: table.table_name.clone(),
612 12 : resolved_table: Some(ResolvedTableEntry {
613 12 : table_name: table.table_name.clone(),
614 12 : catalog_schema_id: table.catalog_schema_id,
615 12 : catalog_table_id: table.object_id,
616 12 : referenced_catalog_version: table.catalog_version,
617 12 : }),
618 12 : resolved_alternatives: Vec::new(),
619 12 : }),
620 12 : role: TableRole::Read,
621 12 : });
622 12 : state.mark(node_id, SemanticNodeMarkerType::TABLE_REFERENCE);
623 12 : let source = ScopeSource {
624 12 : ast_node_id: node_id,
625 12 : name: Some(alias.map(|(alias, _)| alias.text).unwrap_or(name)),
626 12 : column_aliases,
627 12 : table: ReferencedTable::Table(TableLoc { entry: TABLE_PARAMETERS_ENTRY_ID, index: index as u32 }),
628 : };
629 12 : Some((source, id))
630 870 : }
631 :
632 : /// Is a FROM item a table parameter?
633 5276 : fn is_table_parameter(source: &ScopeSource) -> bool {
634 4040 : matches!(source.table, ReferencedTable::Table(loc) if loc.entry == TABLE_PARAMETERS_ENTRY_ID)
635 5276 : }
636 :
637 : /// Add a FROM item to a scope, unless its name is taken
638 2638 : fn add_source(state: &mut AnalysisState, scope: ScopeId, source: ScopeSource) {
639 2638 : if let Some(name) = &source.name {
640 2633 : if state.out.name_scopes[scope as usize].source(name).is_some() {
641 8 : let message = format!("duplicate table alias {}", quote_identifier(name));
642 8 : state.add_error(AnalyzerErrorType::DUPLICATE_TABLE_ALIAS, AnalyzerErrorSeverity::ERROR, source.ast_node_id, message);
643 8 : return;
644 2625 : }
645 5 : }
646 2630 : state.out.name_scopes[scope as usize].sources.push(source);
647 2638 : }
648 :
649 : /// Resolve all table refs in a scope and register the FROM items
650 5774 : fn resolve_table_refs_in_scope(state: &mut AnalysisState, scope: ScopeId) {
651 : // The derived tables were added when the scope was created
652 5774 : let mut sources = std::mem::take(&mut state.out.name_scopes[scope as usize].sources);
653 5774 : let table_refs = state.out.name_scopes[scope as usize].table_references.clone();
654 5776 : for table_ref_id in table_refs {
655 2568 : let table_ref = &state.out.table_references[table_ref_id as usize];
656 2568 : let Some(relation) = &table_ref.inner else { continue };
657 : // The result of a script is a FROM item already
658 2568 : if table_ref.reads_table_parameter() {
659 12 : continue;
660 2556 : }
661 2556 : if relation.resolved_table.is_some() {
662 0 : continue;
663 2556 : }
664 2556 : let table_name = relation.table_name.clone();
665 2556 : let ref_name = table_name.table_name.text.clone();
666 2556 : let role = table_ref.role;
667 2556 : let reference_offset = state.ast[table_ref.ast_node_id as usize].symbol_span().offset();
668 2556 : let source = |table_ref: &TableReference, name: Arc<str>, table: ReferencedTable| ScopeSource {
669 2556 : ast_node_id: table_ref.ast_node_id,
670 2556 : name: Some(name),
671 2556 : column_aliases: table_ref.column_aliases.clone(),
672 2556 : table,
673 2556 : };
674 :
675 : // Does the table ref match a CTE definition in this or any parent scope?
676 2556 : let mut matched_cte = None;
677 2556 : let mut s = Some(scope);
678 5250 : while let Some(sid) = s {
679 2842 : let candidate = &state.out.name_scopes[sid as usize];
680 2842 : if let Some(index) = candidate.cte_definitions.get_index(&ref_name) {
681 152 : let mut visible = true;
682 152 : if !candidate.ctes_recursive {
683 123 : let definition = &state.ast[candidate.cte_definitions.at(index).definition_node_id as usize];
684 123 : let span = definition.symbol_span();
685 123 : let definition_end = span.offset() + span.length();
686 123 : visible = reference_offset > definition_end;
687 123 : }
688 152 : if visible {
689 148 : matched_cte = Some(CteLoc {
690 148 : scope: sid,
691 148 : index: index as u32,
692 148 : });
693 148 : break;
694 4 : }
695 2690 : }
696 2694 : s = candidate.parent_scope;
697 : }
698 2556 : if let (Some(cte), TableRole::Read) = (matched_cte, role) {
699 147 : let table_ref = &state.out.table_references[table_ref_id as usize];
700 147 : sources.push(source(table_ref, Self::table_ref_alias(table_ref, &ref_name), ReferencedTable::Cte(cte)));
701 147 : continue;
702 2409 : }
703 :
704 : // Resolve as a table of the own script, then through the catalog
705 2409 : let mut resolved = Vec::new();
706 2409 : state.out.entry.resolve_table(&table_name, &mut resolved, MAX_TABLE_REF_AMBIGUITY);
707 2409 : if resolved.is_empty() {
708 2224 : state.catalog.resolve_table(&table_name, state.entry_id, &mut resolved, MAX_TABLE_REF_AMBIGUITY);
709 2225 : }
710 2409 : if let Some(&best_loc) = resolved.first() {
711 2008 : let entries: Vec<ResolvedTableEntry> = resolved
712 2008 : .iter()
713 2021 : .filter_map(|&loc| state.table(loc))
714 2008 : .map(|t| ResolvedTableEntry {
715 2021 : table_name: t.table_name.clone(),
716 2021 : catalog_schema_id: t.catalog_schema_id,
717 2021 : catalog_table_id: t.object_id,
718 2021 : referenced_catalog_version: t.catalog_version,
719 2021 : })
720 2008 : .collect();
721 2008 : let best_name = entries[0].table_name.table_name.text.clone();
722 2008 : let relation = state.out.table_references[table_ref_id as usize].inner.as_mut().unwrap();
723 2008 : let mut entries = entries.into_iter();
724 2008 : relation.resolved_table = entries.next();
725 2008 : relation.resolved_alternatives.extend(entries);
726 2008 : let table_ref = &state.out.table_references[table_ref_id as usize];
727 2008 : sources.push(source(table_ref, Self::table_ref_alias(table_ref, &best_name), ReferencedTable::Table(best_loc)));
728 2008 : continue;
729 401 : }
730 :
731 : // Neither a CTE nor in the catalog. Register an unresolved relation so that columns used
732 : // against it can be associated for schema inference.
733 401 : let table_ref = &state.out.table_references[table_ref_id as usize];
734 401 : let unresolved = ReferencedTable::Unresolved(UnresolvedRelation {
735 401 : table_ref: table_ref_id,
736 401 : table_name,
737 401 : });
738 401 : sources.push(source(table_ref, Self::table_ref_alias(table_ref, &ref_name), unresolved));
739 : }
740 : // Register the FROM items in FROM order, table refs follow the nodes of earlier FROM items in
741 : // the post-order AST
742 5774 : sources.sort_by_key(|s| s.ast_node_id);
743 : // The result of a script yields its name to the other FROM items, the planner renames its common table
744 : // expression as well
745 5776 : let taken: HashSet<Arc<str>> = sources.iter().filter(|s| !Self::is_table_parameter(s)).filter_map(|s| s.name.clone()).collect();
746 5776 : for source in sources.iter_mut().filter(|s| Self::is_table_parameter(s)) {
747 12 : if source.name.as_ref().is_some_and(|n| taken.contains(n)) {
748 1 : source.name = None;
749 11 : }
750 : }
751 5776 : for source in sources {
752 2638 : Self::add_source(state, scope, source);
753 2638 : }
754 5774 : }
755 :
756 : /// Find a column among the columns of a FROM item, the column aliases rename the leading columns
757 3346 : fn find_column(aliases: &[Name], column_count: usize, column_name: &str, by_name: Option<usize>) -> Option<usize> {
758 3346 : match aliases.iter().position(|a| &*a.text == column_name) {
759 71 : Some(column) => (column < column_count).then_some(column),
760 3275 : None => by_name.filter(|&column| column >= aliases.len()),
761 : }
762 3346 : }
763 :
764 : /// Resolve a column against the output columns of a scope
765 233 : fn resolve_scope_column(state: &AnalysisState, scope: ScopeId, aliases: &[Name], column_name: &str) -> ColumnResolution {
766 233 : let s = &state.out.name_scopes[scope as usize];
767 233 : let by_name = s.output_columns_by_name.get(column_name).copied();
768 233 : match Self::find_column(aliases, s.output_columns.len(), column_name, by_name) {
769 149 : Some(column) => ColumnResolution::ScopeColumn {
770 149 : scope,
771 149 : column: column as u32,
772 149 : },
773 84 : None => ColumnResolution::Unresolved,
774 : }
775 233 : }
776 :
777 : /// Resolve a column against a FROM item
778 3752 : fn resolve_column(state: &AnalysisState, source: &ScopeSource, column_name: &str) -> ColumnResolution {
779 3752 : match &source.table {
780 3113 : ReferencedTable::Table(loc) => {
781 3113 : let Some(table) = state.table(*loc) else { return ColumnResolution::Unresolved };
782 3113 : let by_name = table.table_columns_by_name.get(column_name).copied();
783 3113 : match Self::find_column(&source.column_aliases, table.table_columns.len(), column_name, by_name) {
784 1940 : Some(column) => ColumnResolution::TableColumn(ColumnLoc {
785 1940 : table: *loc,
786 1940 : column: column as u32,
787 1940 : }),
788 1173 : None => ColumnResolution::Unresolved,
789 : }
790 : }
791 : // An unresolved relation has an unknown schema
792 406 : ReferencedTable::Unresolved(_) => ColumnResolution::Unresolved,
793 135 : ReferencedTable::Cte(loc) => {
794 135 : let cte = state.out.name_scopes[loc.scope as usize].cte_definitions.at(loc.index as usize);
795 135 : let Some(child) = cte.child_scope else {
796 0 : return ColumnResolution::Unresolved;
797 : };
798 135 : let aliases = if source.column_aliases.is_empty() { &cte.column_aliases } else { &source.column_aliases };
799 135 : Self::resolve_scope_column(state, child, aliases, column_name)
800 : }
801 98 : ReferencedTable::Subquery(child) => Self::resolve_scope_column(state, *child, &source.column_aliases, column_name),
802 : }
803 3752 : }
804 :
805 : /// Is a node within the subtree of another one?
806 15 : fn is_within(state: &AnalysisState, mut node_id: u32, ancestor: u32) -> bool {
807 : // Parents follow their children in the post-order AST
808 43 : while node_id < ancestor {
809 28 : let parent = state.ast[node_id as usize].parent();
810 : // Statement roots are their own parents
811 28 : if parent == node_id || parent as usize >= state.ast.len() {
812 0 : return false;
813 28 : }
814 28 : node_id = parent;
815 : }
816 15 : node_id == ancestor
817 15 : }
818 :
819 : /// Do the FROM items that have a column all lie within a join that uses it?
820 40 : fn is_using_column(&self, state: &AnalysisState, scope: ScopeId, source_nodes: &[u32], column_name: &str) -> bool {
821 40 : let Some(joins) = self.using_joins.get(&scope) else { return false };
822 9 : joins.iter().any(|join| {
823 15 : join.uses(column_name) && source_nodes.iter().all(|&node_id| Self::is_within(state, node_id, join.ast_node_id))
824 9 : })
825 40 : }
826 :
827 : /// Look up a column ref in the visible FROM items of a scope
828 3527 : fn try_resolve_column_in_scope(&mut self, state: &mut AnalysisState, expr: ExprId, target: ScopeId, visibility: SourceVisibility) -> Lookup {
829 3527 : let Some(column_ref) = state.out.expressions[expr as usize].column_ref() else { return Lookup::Missing };
830 3527 : let column_name = column_ref.column_name.column_name.text.clone();
831 3527 : let alias = column_ref.column_name.table_alias.as_ref().map(|a| a.text.clone());
832 3527 : let scope = &state.out.name_scopes[target as usize];
833 4583 : let mut sources = scope.sources.iter().filter(|s| visibility.sees(s));
834 :
835 3527 : if let Some(alias) = alias {
836 614 : let Some(source) = sources.find(|s| s.name.as_deref() == Some(&*alias)) else { return Lookup::Missing };
837 309 : let resolution = Self::resolve_column(state, source, &column_name);
838 309 : if !resolution.is_resolved() {
839 108 : return Lookup::Missing;
840 201 : }
841 201 : state.out.expressions[expr as usize].column_ref_mut().unwrap().resolved = resolution;
842 201 : return Lookup::Resolved;
843 2997 : }
844 :
845 : // No table alias, scan all FROM items for the column and check for ambiguity
846 2997 : let mut candidates = Vec::new();
847 3953 : for source in sources {
848 3443 : let resolution = Self::resolve_column(state, source, &column_name);
849 3443 : if resolution.is_resolved() {
850 1888 : candidates.push((source.ast_node_id, source.name.clone(), resolution));
851 2567 : }
852 : }
853 2997 : let resolution = match candidates.as_slice() {
854 2997 : [] => return Lookup::Missing,
855 1807 : [(_, _, resolution)] => *resolution,
856 : // A USING column resolves to the column of the first input
857 40 : [(_, _, resolution), ..]
858 40 : if self.is_using_column(state, target, &candidates.iter().map(|c| c.0).collect::<Vec<_>>(), &column_name) =>
859 : {
860 6 : *resolution
861 : }
862 : _ => {
863 34 : let mut message = String::from("column reference is ambiguous, candidates: ");
864 69 : for (i, (_, table_name, _)) in candidates.iter().enumerate() {
865 69 : if i > 0 {
866 35 : message.push_str(", ");
867 35 : }
868 69 : match table_name {
869 68 : Some(table_name) => message.push_str("e_identifier(table_name)),
870 1 : None => message.push_str("(subquery)"),
871 : }
872 69 : message.push('.');
873 69 : message.push_str("e_identifier(&column_name));
874 : }
875 34 : let node_id = state.out.expressions[expr as usize].ast_node_id;
876 34 : state.add_error(AnalyzerErrorType::COLUMN_REF_AMBIGUOUS, AnalyzerErrorSeverity::ERROR, node_id, message);
877 34 : self.ambiguous_column_refs.insert(expr);
878 34 : return Lookup::Ambiguous;
879 : }
880 : };
881 1813 : state.out.expressions[expr as usize].column_ref_mut().unwrap().resolved = resolution;
882 1813 : Lookup::Resolved
883 3527 : }
884 :
885 : /// Try to resolve a column ref against the output columns of a scope
886 60 : fn try_resolve_column_from_outputs(state: &mut AnalysisState, expr: ExprId, target: ScopeId) -> bool {
887 60 : let Some(column_ref) = state.out.expressions[expr as usize].column_ref() else { return false };
888 60 : if column_ref.column_name.table_alias.is_some() {
889 0 : return false;
890 60 : }
891 60 : let scope = &state.out.name_scopes[target as usize];
892 60 : match scope.output_columns_by_name.get(&column_ref.column_name.column_name.text) {
893 57 : Some(&column) => {
894 57 : state.out.expressions[expr as usize].column_ref_mut().unwrap().resolved = ColumnResolution::ScopeColumn {
895 57 : scope: target,
896 57 : column: column as u32,
897 57 : };
898 57 : true
899 : }
900 3 : None => false,
901 : }
902 60 : }
903 :
904 8112 : fn is_unresolved_column_ref(state: &AnalysisState, expr: ExprId) -> bool {
905 8112 : state.out.expressions[expr as usize].column_ref().is_some_and(|c| !c.resolved.is_resolved())
906 8112 : }
907 :
908 : /// How a column ref sees the output columns of its scope
909 2704 : fn output_names(state: &AnalysisState, expr: ExprId) -> OutputNames {
910 2704 : let node = &state.ast[state.out.expressions[expr as usize].ast_node_id as usize];
911 2704 : let (output_names, list_key) = match node.attribute_key() {
912 49 : K::SQL_ORDER_VALUE => (OutputNames::Preferred, K::SQL_SELECT_ORDER),
913 59 : K::SQL_GROUP_BY_ITEM_ARG => (OutputNames::Fallback, K::SQL_SELECT_GROUPS),
914 2596 : _ => return OutputNames::Invisible,
915 : };
916 : // The item must be in the clause of the SELECT, not in a window or an aggregate
917 108 : let list = state.ast.get(node.parent() as usize).and_then(|item| state.ast.get(item.parent() as usize));
918 108 : if list.is_some_and(|list| list.attribute_key() == list_key) {
919 104 : output_names
920 : } else {
921 4 : OutputNames::Invisible
922 : }
923 2704 : }
924 :
925 : /// Resolve column refs against the FROM items and the output columns of the own scope
926 5774 : fn resolve_column_refs_locally(&mut self, state: &mut AnalysisState, scope: ScopeId) {
927 5774 : let exprs = state.out.name_scopes[scope as usize].expressions.clone();
928 5790 : for expr in exprs {
929 2704 : if !Self::is_unresolved_column_ref(state, expr) {
930 0 : continue;
931 2704 : }
932 2704 : match Self::output_names(state, expr) {
933 2600 : OutputNames::Invisible => {
934 2600 : self.try_resolve_column_in_scope(state, expr, scope, SourceVisibility::All);
935 2600 : }
936 : OutputNames::Preferred => {
937 45 : if !Self::try_resolve_column_from_outputs(state, expr, scope) {
938 1 : self.try_resolve_column_in_scope(state, expr, scope, SourceVisibility::All);
939 44 : }
940 : }
941 : OutputNames::Fallback => {
942 59 : if self.try_resolve_column_in_scope(state, expr, scope, SourceVisibility::All) == Lookup::Missing {
943 15 : Self::try_resolve_column_from_outputs(state, expr, scope);
944 54 : }
945 : }
946 : }
947 : }
948 5774 : }
949 :
950 : /// Resolve column refs by walking up the parent scopes
951 5774 : fn resolve_column_refs_from_parents(&mut self, state: &mut AnalysisState, scope: ScopeId) {
952 5774 : let exprs = state.out.name_scopes[scope as usize].expressions.clone();
953 5790 : for expr in exprs {
954 2704 : if Self::is_unresolved_column_ref(state, expr) && !self.ambiguous_column_refs.contains(&expr) {
955 646 : self.resolve_from_parent_chain(state, expr, scope);
956 2109 : }
957 : }
958 5774 : }
959 :
960 : /// Try the FROM items that a scope sees in its parent scopes, stopping at correlation barriers
961 722 : fn resolve_from_parent_chain(&mut self, state: &mut AnalysisState, expr: ExprId, scope: ScopeId) -> bool {
962 722 : let mut current = scope;
963 : loop {
964 792 : let s = &state.out.name_scopes[current as usize];
965 792 : let (Some(parent), false) = (s.parent_scope, s.column_correlation_barrier) else { return false };
966 115 : match self.try_resolve_column_in_scope(state, expr, parent, s.parent_visibility) {
967 45 : Lookup::Resolved => return true,
968 0 : Lookup::Ambiguous => return false,
969 70 : Lookup::Missing => current = parent,
970 : }
971 : }
972 722 : }
973 :
974 : /// Attach parsed CTE definitions to a scope
975 3991 : fn attach_ctes(state: &mut AnalysisState, scope: ScopeId, ctes: Vec<CteDefinition>) {
976 3991 : for cte in ctes {
977 141 : let Some(&child_scope) = state.out.name_scopes_by_root_node.get(&cte.select_node_id) else { continue };
978 : // A CTE cannot correlate with the FROM items of the statement it is attached to
979 141 : state.out.name_scopes[child_scope as usize].parent_visibility = SourceVisibility::None;
980 141 : let mut column_aliases = Vec::new();
981 141 : if let Some(columns_node_id) = cte.columns_node_id.filter(|_| cte.columns_count > 0) {
982 19 : let columns = &state.ast[columns_node_id as usize];
983 24 : for ci in 0..cte.columns_count as u32 {
984 24 : let column = &state.ast[(columns.children_begin_or_value() + ci) as usize];
985 24 : if column.node_type() == NodeType::NAME {
986 24 : column_aliases.push(state.node_name(column));
987 24 : }
988 : }
989 122 : }
990 141 : let definition = ResolvedCte {
991 141 : cte_name: cte.cte_name.clone(),
992 141 : child_scope: Some(child_scope),
993 141 : definition_node_id: cte.ast_node_id,
994 141 : column_aliases,
995 141 : };
996 141 : let s = &mut state.out.name_scopes[scope as usize];
997 141 : s.cte_definitions.insert(cte.cte_name.text.clone(), definition);
998 141 : s.cte_definition_nodes.entry(cte.cte_name.text.clone()).or_insert(cte.ast_node_id);
999 : }
1000 3991 : }
1001 :
1002 : /// Look up a FROM item by name in a scope and in the parent scopes it sees
1003 263 : fn lookup_source_in_scope_chain<'s>(state: &'s AnalysisState, scope: ScopeId, name: &str) -> Option<&'s ScopeSource> {
1004 263 : let mut current = scope;
1005 263 : let mut visibility = SourceVisibility::All;
1006 : loop {
1007 296 : let s = &state.out.name_scopes[current as usize];
1008 308 : if let Some(source) = s.sources.iter().find(|x| visibility.sees(x) && x.name.as_deref() == Some(name)) {
1009 110 : return Some(source);
1010 186 : }
1011 186 : let (Some(parent), false) = (s.parent_scope, s.column_correlation_barrier) else { return None };
1012 33 : visibility = s.parent_visibility;
1013 33 : current = parent;
1014 : }
1015 263 : }
1016 :
1017 : /// Resolve qualified column refs whose qualifier is not a table in scope as field accesses of
1018 : /// row-typed columns
1019 5774 : fn resolve_row_field_accesses(&mut self, state: &mut AnalysisState, scope: ScopeId) {
1020 5774 : let exprs = state.out.name_scopes[scope as usize].expressions.clone();
1021 5790 : for expr in exprs {
1022 2704 : let Some(column_ref) = state.out.expressions[expr as usize].column_ref() else { continue };
1023 2704 : if column_ref.resolved.is_resolved() {
1024 2068 : continue;
1025 636 : }
1026 636 : let Some(qualifier) = column_ref.column_name.table_alias.clone() else { continue };
1027 133 : if Self::lookup_source_in_scope_chain(state, scope, &qualifier.text).is_some() {
1028 55 : continue;
1029 78 : }
1030 : // In p.x, p is not a table in scope but may be a row-typed column with a field x
1031 78 : let qualified = column_ref.column_name.clone();
1032 78 : {
1033 78 : let column_ref = state.out.expressions[expr as usize].column_ref_mut().unwrap();
1034 78 : column_ref.column_name.table_alias = None;
1035 78 : column_ref.column_name.column_name = qualifier.clone();
1036 78 : }
1037 78 : let resolved = self.try_resolve_column_in_scope(state, expr, scope, SourceVisibility::All) == Lookup::Resolved
1038 76 : || self.resolve_from_parent_chain(state, expr, scope);
1039 78 : if resolved {
1040 3 : state.tag(&qualifier, NameTag::COLUMN_NAME);
1041 75 : } else {
1042 75 : state.out.expressions[expr as usize].column_ref_mut().unwrap().column_name = qualified;
1043 75 : }
1044 : }
1045 5774 : }
1046 :
1047 : /// Associate still-unresolved column refs with unresolved tables in scope
1048 5774 : fn associate_unresolved_columns(state: &mut AnalysisState, scope: ScopeId) {
1049 5774 : let s = &state.out.name_scopes[scope as usize];
1050 : // The unresolved relations of this scope in FROM order
1051 5774 : let local_unresolved: Vec<InferenceCandidate> = s
1052 5774 : .sources
1053 5774 : .iter()
1054 5776 : .filter_map(|source| match &source.table {
1055 400 : ReferencedTable::Unresolved(rel) => Some(InferenceCandidate {
1056 400 : table_name: rel.table_name.clone(),
1057 400 : table_ref: rel.table_ref,
1058 400 : }),
1059 2230 : _ => None,
1060 2630 : })
1061 5774 : .collect();
1062 :
1063 5790 : for expr in s.expressions.clone() {
1064 2704 : let expression = &state.out.expressions[expr as usize];
1065 2704 : let Some(column_ref) = expression.column_ref() else { continue };
1066 2704 : if column_ref.resolved.is_resolved() || column_ref.inferred.is_some() {
1067 2071 : continue;
1068 633 : }
1069 633 : let column_name = column_ref.column_name.column_name.clone();
1070 633 : let constraint = match &column_ref.column_name.table_alias {
1071 : // Alias-qualified, the owner is pinned to whatever the alias refers to
1072 130 : Some(alias) => {
1073 34 : let Some(ReferencedTable::Unresolved(rel)) =
1074 130 : Self::lookup_source_in_scope_chain(state, scope, &alias.text).map(|s| &s.table)
1075 : else {
1076 96 : continue;
1077 : };
1078 34 : InferenceConstraint {
1079 34 : kind: InferenceConstraintKind::Forced,
1080 34 : expression_id: expression.expression_id,
1081 34 : column_name,
1082 34 : candidates: vec![InferenceCandidate {
1083 34 : table_name: rel.table_name.clone(),
1084 34 : table_ref: rel.table_ref,
1085 34 : }],
1086 34 : }
1087 : }
1088 : // Unqualified, the candidates are the unresolved tables in scope
1089 : None => {
1090 503 : if local_unresolved.is_empty() {
1091 352 : continue;
1092 151 : }
1093 : InferenceConstraint {
1094 151 : kind: if local_unresolved.len() == 1 {
1095 140 : InferenceConstraintKind::Forced
1096 : } else {
1097 11 : InferenceConstraintKind::Disjunctive
1098 : },
1099 151 : expression_id: expression.expression_id,
1100 151 : column_name,
1101 151 : candidates: local_unresolved.clone(),
1102 : }
1103 : }
1104 : };
1105 185 : state.out.inference_constraints.push(constraint);
1106 : }
1107 5774 : }
1108 :
1109 : /// The columns of a FROM item, as a star forwards them
1110 1019 : fn source_columns(state: &AnalysisState, source: &ScopeSource) -> Vec<ScopeColumn> {
1111 1019 : let scope_columns = |scope: ScopeId| state.out.name_scopes[scope as usize].output_columns.clone();
1112 1019 : let mut columns = match &source.table {
1113 646 : ReferencedTable::Table(loc) => match state.table(*loc) {
1114 646 : Some(table) => table
1115 646 : .table_columns
1116 646 : .iter()
1117 646 : .enumerate()
1118 646 : .map(|(ci, column)| ScopeColumn {
1119 848 : column_name: column.column_name.clone(),
1120 848 : source: ScopeColumnSource::TableColumn(ColumnLoc {
1121 848 : table: *loc,
1122 848 : column: ci as u32,
1123 848 : }),
1124 848 : })
1125 646 : .collect(),
1126 0 : None => Vec::new(),
1127 : },
1128 : // An unresolved relation has an unknown schema
1129 267 : ReferencedTable::Unresolved(_) => Vec::new(),
1130 86 : ReferencedTable::Cte(loc) => {
1131 86 : let cte = state.out.name_scopes[loc.scope as usize].cte_definitions.at(loc.index as usize);
1132 86 : let mut columns = cte.child_scope.map(scope_columns).unwrap_or_default();
1133 86 : for (column, alias) in columns.iter_mut().zip(&cte.column_aliases) {
1134 14 : column.column_name = alias.clone();
1135 14 : }
1136 86 : columns
1137 : }
1138 20 : ReferencedTable::Subquery(child) => scope_columns(*child),
1139 : };
1140 1019 : for (column, alias) in columns.iter_mut().zip(&source.column_aliases) {
1141 0 : column.column_name = alias.clone();
1142 0 : }
1143 1019 : columns
1144 1019 : }
1145 :
1146 : /// Populate the output columns of a scope from its result targets
1147 5774 : fn populate_output_columns(state: &mut AnalysisState, scope: ScopeId) {
1148 5774 : let mut columns = Vec::new();
1149 5774 : let scope_node = &state.ast[state.out.name_scopes[scope as usize].ast_node_id as usize];
1150 5774 : let [combine_inputs, values] = attrs!(state.children(scope_node), [K::SQL_COMBINE_INPUT, K::SQL_SELECT_VALUES]);
1151 5774 : if let Some(combine_inputs) = combine_inputs.filter(|n| n.children_count() > 0) {
1152 : // Set operations expose the column names of the left input
1153 32 : if let Some(&left) = state.out.name_scopes_by_root_node.get(&combine_inputs.children_begin_or_value()) {
1154 32 : columns = state.out.name_scopes[left as usize].output_columns.clone();
1155 32 : }
1156 5742 : }
1157 : // The columns of VALUES are unnamed, aliases of a derived table can name them
1158 5774 : if let Some(row) = values.and_then(|v| state.children(v).first()).filter(|r| r.node_type() == NodeType::ARRAY) {
1159 251 : for value in state.children(row) {
1160 251 : columns.push(ScopeColumn {
1161 251 : column_name: state.empty_name(),
1162 251 : source: match state.expression_of(state.node_id(value)) {
1163 251 : Some(expr) => ScopeColumnSource::Expression(expr),
1164 0 : None => ScopeColumnSource::Computed,
1165 : },
1166 : });
1167 : }
1168 5558 : }
1169 5774 : let mut result_targets = std::mem::take(&mut state.out.name_scopes[scope as usize].result_targets);
1170 5796 : for rt in result_targets.iter_mut() {
1171 4020 : if rt.is_star {
1172 : // Forward the columns of all FROM items, or of the qualified one
1173 1324 : let s = &state.out.name_scopes[scope as usize];
1174 1368 : for source in &s.sources {
1175 1022 : if rt.star_qualifier.as_ref().is_none_or(|q| source.name.as_deref() == Some(q.text())) {
1176 1019 : columns.extend(Self::source_columns(state, source));
1177 1019 : }
1178 : }
1179 1324 : continue;
1180 2696 : }
1181 2696 : let mut expr = rt.expression_id;
1182 2696 : if expr.is_none() {
1183 1134 : let rt_node = &state.ast[rt.ast_node_id as usize];
1184 1134 : let [value] = attrs!(state.children(rt_node), [K::SQL_RESULT_TARGET_VALUE]);
1185 1134 : if let Some(value) = value {
1186 1134 : expr = state.expression_of(state.node_id(value));
1187 1134 : rt.expression_id = expr;
1188 1134 : }
1189 1562 : }
1190 2696 : columns.push(ScopeColumn {
1191 2696 : column_name: rt.column_name.clone().unwrap_or_else(|| state.empty_name()),
1192 : // Computed columns keep their position for column aliases
1193 2696 : source: match expr {
1194 2593 : Some(expr) => ScopeColumnSource::Expression(expr),
1195 103 : None => ScopeColumnSource::Computed,
1196 : },
1197 : });
1198 : }
1199 5774 : let s = &mut state.out.name_scopes[scope as usize];
1200 5774 : s.result_targets = result_targets;
1201 : // A name refers to its first column, references to later ones would be ambiguous
1202 5797 : for column in columns {
1203 3942 : if !column.column_name.text.is_empty() {
1204 2906 : s.output_columns_by_name.entry(column.column_name.text.clone()).or_insert(s.output_columns.len());
1205 2917 : }
1206 3942 : s.output_columns.push(column);
1207 : }
1208 5774 : }
1209 :
1210 : /// Resolve all names
1211 4003 : fn resolve_names(&mut self, state: &mut AnalysisState) {
1212 4003 : let roots = self.root_scopes.values.clone();
1213 :
1214 : // Pass 1, bottom-up: resolve the table refs, populate the output columns for the parent, then
1215 : // resolve the column refs against the own scope
1216 5253 : let mut dfs: Vec<(ScopeId, bool)> = roots.iter().map(|&r| (r, false)).collect();
1217 15551 : while let Some(top) = dfs.last_mut() {
1218 11548 : let scope = top.0;
1219 11548 : if !top.1 {
1220 5774 : top.1 = true;
1221 : // Push children in reverse order so that earlier siblings are processed first
1222 5774 : let children = state.out.name_scopes[scope as usize].child_scopes.clone();
1223 5774 : dfs.extend(children.iter().rev().map(|&c| (c, false)));
1224 5774 : } else {
1225 5774 : dfs.pop();
1226 5774 : Self::resolve_table_refs_in_scope(state, scope);
1227 5774 : Self::populate_output_columns(state, scope);
1228 5774 : self.resolve_column_refs_locally(state, scope);
1229 5774 : }
1230 : }
1231 :
1232 : // Pass 2, top-down: resolve the remaining column refs through the parent scopes
1233 4003 : let mut dfs: Vec<ScopeId> = roots.clone();
1234 9777 : while let Some(scope) = dfs.pop() {
1235 : // Recursive CTE outputs are available only after the bottom-up pass
1236 5790 : for expr in state.out.name_scopes[scope as usize].expressions.clone() {
1237 2704 : if Self::is_unresolved_column_ref(state, expr) && !self.ambiguous_column_refs.contains(&expr) {
1238 674 : self.try_resolve_column_in_scope(state, expr, scope, SourceVisibility::All);
1239 2081 : }
1240 : }
1241 5774 : self.resolve_column_refs_from_parents(state, scope);
1242 5774 : self.resolve_row_field_accesses(state, scope);
1243 5774 : dfs.extend(state.out.name_scopes[scope as usize].child_scopes.iter().copied());
1244 : }
1245 :
1246 : // Pass 3: associate the remaining unresolved columns with unresolved tables, in scope order
1247 5857 : for scope in 0..state.out.name_scopes.len() {
1248 5774 : Self::associate_unresolved_columns(state, scope as ScopeId);
1249 5774 : }
1250 4003 : }
1251 :
1252 : /// Is the node nested inside syntax-only property graph syntax?
1253 13889 : fn is_inside_graph_syntax(&self, state: &AnalysisState, ast_node_id: u32) -> bool {
1254 13889 : if !self.has_graph_syntax {
1255 13816 : return false;
1256 73 : }
1257 73 : let mut node_id = ast_node_id;
1258 73 : for _ in 0..state.ast.len() {
1259 212 : let parent = state.ast[node_id as usize].parent();
1260 212 : if parent as usize >= state.ast.len() {
1261 0 : return false;
1262 212 : }
1263 212 : match state.ast[parent as usize].node_type() {
1264 46 : NodeType::OBJECT_SQL_PROPERTY_GRAPH | NodeType::OBJECT_SQL_GRAPH_TABLE => return true,
1265 : // Statement roots are their own parents
1266 166 : _ if parent == node_id => return false,
1267 139 : _ => node_id = parent,
1268 : }
1269 : }
1270 0 : false
1271 13889 : }
1272 :
1273 3855 : pub fn visit(&mut self, state: &mut AnalysisState, morsel: Range<usize>) {
1274 84087 : for node_id in morsel {
1275 84087 : let node = &state.ast[node_id];
1276 84087 : let mut node_state = std::mem::take(&mut self.node_states[node_id]);
1277 84087 : self.visit_node(state, node, node_id as u32, &mut node_state);
1278 84087 : self.node_states[node_id] = node_state;
1279 84087 : }
1280 3855 : }
1281 :
1282 84087 : fn visit_node(&mut self, state: &mut AnalysisState, node: &Node, node_id: u32, node_state: &mut NodeState) {
1283 84087 : match node.node_type() {
1284 : NodeType::OBJECT_SQL_COLUMN_DEF => {
1285 4383 : let parent = node.parent() as usize;
1286 4383 : if parent < state.ast.len() {
1287 : // Fields of descriptors and row types are not table columns
1288 4383 : let key = state.ast[parent].attribute_key();
1289 4383 : if key == K::SQL_DESCRIPTOR_COLUMNS || key == K::SQL_ROW_TYPE_FIELDS {
1290 13 : return;
1291 4370 : }
1292 0 : }
1293 4370 : let [name, column_type] = attrs!(state.children(node), [K::SQL_COLUMN_DEF_NAME, K::SQL_COLUMN_DEF_TYPE]);
1294 4370 : if let Some(name) = name.filter(|n| n.node_type() == NodeType::NAME) {
1295 4370 : let name = state.node_name(name);
1296 4370 : state.tag(&name, NameTag::COLUMN_NAME);
1297 4370 : node_state.table_columns.push(PendingColumn {
1298 4370 : ast_node_id: node_id,
1299 4370 : column_name: name,
1300 4370 : column_type: column_type.and_then(|t| read_sql_type(state.parsed, t)).map(|t| Arc::from(t.to_string())),
1301 : });
1302 0 : }
1303 : }
1304 :
1305 : NodeType::OBJECT_SQL_COLUMN_REF => {
1306 2737 : if self.is_inside_graph_syntax(state, node_id) {
1307 16 : return;
1308 2721 : }
1309 : // The qualifier of t.* names a FROM item, the result target reads it
1310 2721 : if Self::is_star_qualifier(state, node) {
1311 6 : return;
1312 2715 : }
1313 2715 : let [path] = attrs!(state.children(node), [K::SQL_COLUMN_REF_PATH]);
1314 2715 : if let Some(column_name) = state.read_qualified_column_name(path) {
1315 2715 : let column_ref = ColumnRef {
1316 2715 : column_name,
1317 2715 : ast_scope_root: None,
1318 2715 : resolved: ColumnResolution::Unresolved,
1319 2715 : resolved_ids: None,
1320 2715 : inferred: None,
1321 2715 : };
1322 2715 : let expr = state.add_expression(node_id, *node.symbol_span(), ExpressionInner::ColumnRef(column_ref));
1323 2715 : node_state.column_references.push(expr);
1324 2715 : state.expression_index[node_id as usize] = Some(expr);
1325 2715 : state.mark(node_id, SemanticNodeMarkerType::COLUMN_REFERENCE);
1326 2715 : }
1327 : // Column refs may be recursive
1328 2715 : self.merge_child_states(node_state, node);
1329 : }
1330 :
1331 : NodeType::OBJECT_SQL_TABLEREF => {
1332 3443 : if self.is_inside_graph_syntax(state, node_id) {
1333 15 : return;
1334 3428 : }
1335 3428 : let [name_node, alias_node, table_node, lateral] = attrs!(state.children(node), [
1336 : K::SQL_TABLEREF_NAME,
1337 : K::SQL_TABLEREF_ALIAS,
1338 : K::SQL_TABLEREF_TABLE,
1339 : K::SQL_TABLEREF_LATERAL,
1340 : ]);
1341 3428 : if let Some(name) = state.read_qualified_table_name(name_node) {
1342 2558 : let (alias, column_aliases) = Self::read_alias(state, alias_node);
1343 2558 : let id = state.out.table_references.len() as TableRefId;
1344 2558 : state.out.table_references.push(TableReference {
1345 2558 : table_reference_id: ExternalObjectId::new(state.entry_id, id),
1346 2558 : ast_node_id: node_id,
1347 2558 : location: Some(*node.symbol_span()),
1348 2558 : ast_statement_id: None,
1349 2558 : ast_scope_root: None,
1350 2558 : alias,
1351 2558 : column_aliases,
1352 2558 : inner: Some(RelationExpression {
1353 2558 : table_name: name,
1354 2558 : resolved_table: None,
1355 2558 : resolved_alternatives: Vec::new(),
1356 2558 : }),
1357 2558 : role: TableRole::Read,
1358 2558 : });
1359 2558 : node_state.table_references.push(id);
1360 2558 : state.mark(node_id, SemanticNodeMarkerType::TABLE_REFERENCE);
1361 2576 : } else if let Some((source, table_ref)) = Self::table_parameter_source(state, node_id, node, table_node, alias_node) {
1362 12 : // A table parameter that reads the result of a script of the session
1363 12 : node_state.derived_tables.push(source);
1364 12 : node_state.table_references.push(table_ref);
1365 860 : } else if let Some(select) = table_node.filter(|n| n.node_type() == NodeType::OBJECT_SQL_SELECT) {
1366 : // A derived table, the scope of its SELECT is a FROM item
1367 70 : if let Some(&child) = state.out.name_scopes_by_root_node.get(&state.node_id(select)) {
1368 70 : let (alias, column_aliases) = Self::read_alias(state, alias_node);
1369 70 : state.out.name_scopes[child as usize].parent_visibility = match lateral {
1370 4 : Some(_) => SourceVisibility::Before(node_id),
1371 66 : None => SourceVisibility::None,
1372 : };
1373 70 : node_state.derived_tables.push(ScopeSource {
1374 70 : ast_node_id: node_id,
1375 70 : name: alias.map(|(name, _)| name.text),
1376 70 : column_aliases,
1377 70 : table: ReferencedTable::Subquery(child),
1378 : });
1379 0 : }
1380 788 : }
1381 : // Table refs may be recursive
1382 3428 : self.merge_child_states(node_state, node);
1383 : }
1384 :
1385 : NodeType::OBJECT_SQL_RESULT_TARGET => {
1386 4036 : if self.is_inside_graph_syntax(state, node_id) {
1387 14 : return;
1388 4022 : }
1389 4022 : self.merge_child_states(node_state, node);
1390 4022 : let [value, name, star] = attrs!(state.children(node), [
1391 : K::SQL_RESULT_TARGET_VALUE,
1392 : K::SQL_RESULT_TARGET_NAME,
1393 : K::SQL_RESULT_TARGET_STAR,
1394 : ]);
1395 4022 : let mut rt = ResultTarget {
1396 4022 : ast_node_id: node_id,
1397 4022 : ..Default::default()
1398 4022 : };
1399 4022 : if star.is_some() {
1400 1326 : rt.is_star = true;
1401 1326 : let [path] = value.map(|v| attrs!(state.children(v), [K::SQL_COLUMN_REF_PATH])).unwrap_or([None]);
1402 1326 : if let Some(&qualifier) = path.map(|p| state.read_name_path(p)).unwrap_or_default().last() {
1403 6 : let qualifier = state.name(qualifier);
1404 6 : state.tag(&qualifier, NameTag::TABLE_ALIAS);
1405 6 : rt.star_qualifier = Some(qualifier);
1406 1320 : }
1407 : } else {
1408 2696 : if let Some(name) = name.filter(|n| n.node_type() == NodeType::NAME) {
1409 427 : rt.column_name = Some(state.node_name(name));
1410 2279 : }
1411 2696 : if let Some(expr) = value.and_then(|v| state.expression_of(state.node_id(v))) {
1412 1562 : rt.expression_id = Some(expr);
1413 1562 : if rt.column_name.is_none() {
1414 1508 : if let Some(column_ref) = state.out.expressions[expr as usize].column_ref() {
1415 1508 : rt.column_name = Some(column_ref.column_name.column_name.clone());
1416 1508 : }
1417 54 : }
1418 1134 : }
1419 : }
1420 4022 : node_state.result_targets.push(rt);
1421 : }
1422 :
1423 : NodeType::OBJECT_SQL_CTE => {
1424 149 : let [name, columns, statement] =
1425 149 : attrs!(state.children(node), [K::SQL_CTE_NAME, K::SQL_CTE_COLUMNS, K::SQL_CTE_STATEMENT]);
1426 149 : self.merge_child_states(node_state, node);
1427 149 : if let (Some(name), Some(statement)) = (name.filter(|n| n.node_type() == NodeType::NAME), statement) {
1428 141 : node_state.ctes.push(CteDefinition {
1429 141 : cte_name: state.node_name(name),
1430 141 : select_node_id: state.node_id(statement),
1431 141 : columns_node_id: columns.map(|c| state.node_id(c)),
1432 141 : columns_count: columns.map(|c| c.children_count() as u16).unwrap_or(0),
1433 141 : ast_node_id: node_id,
1434 : });
1435 8 : }
1436 : }
1437 :
1438 : NodeType::OBJECT_SQL_SELECT => {
1439 3673 : if self.is_inside_graph_syntax(state, node_id) {
1440 1 : return;
1441 3672 : }
1442 3672 : self.merge_child_states(node_state, node);
1443 3672 : let result_targets = std::mem::take(&mut node_state.result_targets);
1444 3672 : let ctes = std::mem::take(&mut node_state.ctes);
1445 3672 : let scope = self.create_scope(state, node_state, node_id);
1446 3672 : let [recursive] = attrs!(state.children(node), [K::SQL_SELECT_WITH_RECURSIVE]);
1447 3672 : {
1448 3672 : let s = &mut state.out.name_scopes[scope as usize];
1449 3672 : s.result_targets.extend(result_targets);
1450 3672 : // Completion needs the declaration order and the recursive visibility of CTEs
1451 3672 : s.ctes_recursive = recursive.is_some();
1452 3672 : }
1453 3672 : Self::attach_ctes(state, scope, ctes);
1454 3672 : let [into] = attrs!(state.children(node), [K::SQL_SELECT_INTO]);
1455 3672 : if let Some(into) = into.filter(|n| n.node_type() == NodeType::OBJECT_SQL_INTO) {
1456 19 : let [into_name] = attrs!(state.children(into), [K::SQL_TEMP_NAME]);
1457 19 : self.register_derived_table(state, into, into_name, None, node);
1458 3653 : }
1459 : }
1460 :
1461 : NodeType::OBJECT_SQL_INSERT => {
1462 267 : let [target, columns, source, default_values, returning, recursive] = attrs!(state.children(node), [
1463 : K::SQL_INSERT_TARGET,
1464 : K::SQL_INSERT_COLUMNS,
1465 : K::SQL_INSERT_SOURCE,
1466 : K::SQL_INSERT_DEFAULT_VALUES,
1467 : K::SQL_INSERT_RETURNING,
1468 : K::SQL_SELECT_WITH_RECURSIVE,
1469 : ]);
1470 267 : let target_ref = target.and_then(|t| self.node_states[state.node_id(t) as usize].table_references.first().copied());
1471 267 : let Some(target_ref) = target_ref else {
1472 14 : self.merge_child_states(node_state, node);
1473 14 : return;
1474 : };
1475 253 : state.out.table_references[target_ref as usize].role = TableRole::Write;
1476 :
1477 253 : self.merge_child_states(node_state, node);
1478 253 : let result_targets = std::mem::take(&mut node_state.result_targets);
1479 253 : let ctes = std::mem::take(&mut node_state.ctes);
1480 253 : let scope = self.create_scope(state, node_state, node_id);
1481 253 : {
1482 253 : let s = &mut state.out.name_scopes[scope as usize];
1483 253 : s.result_targets.extend(result_targets);
1484 253 : s.ctes_recursive = recursive.is_some();
1485 253 : }
1486 253 : Self::attach_ctes(state, scope, ctes);
1487 253 : if let Some(source) = source {
1488 252 : if let Some(&source_scope) = state.out.name_scopes_by_root_node.get(&state.node_id(source)) {
1489 252 : state.out.name_scopes[source_scope as usize].column_correlation_barrier = true;
1490 252 : }
1491 1 : }
1492 253 : self.set_cte_correlation_barriers(state, scope);
1493 :
1494 253 : let mut insert = InsertStatement {
1495 253 : ast_node_id: node_id,
1496 253 : ast_statement_id: state.find_statement_id(node_id),
1497 253 : target: target_ref,
1498 253 : source_ast_node_id: source.map(|s| state.node_id(s)),
1499 253 : default_values: default_values.is_some(),
1500 253 : returning: returning.is_some(),
1501 253 : target_columns: Vec::new(),
1502 : };
1503 253 : if let Some(columns) = columns.filter(|n| n.node_type() == NodeType::ARRAY) {
1504 13 : for column in state.children(columns) {
1505 13 : if column.node_type() != NodeType::NAME {
1506 0 : continue;
1507 13 : }
1508 13 : let name = state.node_name(column);
1509 13 : state.tag(&name, NameTag::COLUMN_NAME);
1510 13 : insert.target_columns.push(InsertTargetColumn {
1511 13 : ast_node_id: state.node_id(column),
1512 13 : column_name: name,
1513 13 : resolved: None,
1514 13 : });
1515 : }
1516 244 : }
1517 253 : state.out.insert_statements.push(insert);
1518 : }
1519 :
1520 : NodeType::OBJECT_SQL_DELETE => {
1521 66 : let [target, recursive] = attrs!(state.children(node), [K::SQL_DELETE_TARGET, K::SQL_SELECT_WITH_RECURSIVE]);
1522 66 : if let Some(target) = target {
1523 66 : for &table_ref in &self.node_states[state.node_id(target) as usize].table_references {
1524 59 : state.out.table_references[table_ref as usize].role = TableRole::Write;
1525 59 : }
1526 0 : }
1527 66 : self.merge_child_states(node_state, node);
1528 66 : let result_targets = std::mem::take(&mut node_state.result_targets);
1529 66 : let ctes = std::mem::take(&mut node_state.ctes);
1530 66 : let scope = self.create_scope(state, node_state, node_id);
1531 66 : {
1532 66 : let s = &mut state.out.name_scopes[scope as usize];
1533 66 : s.result_targets.extend(result_targets);
1534 66 : s.ctes_recursive = recursive.is_some();
1535 66 : }
1536 66 : Self::attach_ctes(state, scope, ctes);
1537 : // CTE definitions cannot correlate to the DELETE target or USING relations
1538 66 : self.set_cte_correlation_barriers(state, scope);
1539 : }
1540 :
1541 : NodeType::OBJECT_SQL_JOINED_TABLE => {
1542 70 : self.merge_child_states(node_state, node);
1543 70 : let [join_type, using] = attrs!(state.children(node), [K::SQL_JOIN_TYPE, K::SQL_JOIN_USING]);
1544 70 : if let Some(using) = using.filter(|n| n.node_type() == NodeType::ARRAY) {
1545 44 : let mut columns = Vec::new();
1546 44 : for column in state.children(using) {
1547 44 : if column.node_type() == NodeType::NAME {
1548 44 : let name = state.node_name(column);
1549 44 : state.tag(&name, NameTag::COLUMN_NAME);
1550 44 : columns.push(name.text);
1551 44 : }
1552 : }
1553 44 : node_state.using_joins.push(UsingJoin {
1554 44 : ast_node_id: node_id,
1555 44 : using: Some(columns),
1556 44 : });
1557 26 : } else if join_type.is_some_and(|t| t.children_begin_or_value() as u8 & JoinType::NATURAL_.0 != 0) {
1558 2 : node_state.using_joins.push(UsingJoin {
1559 2 : ast_node_id: node_id,
1560 2 : using: None,
1561 2 : });
1562 25 : }
1563 : }
1564 :
1565 : NodeType::OBJECT_SQL_CREATE => {
1566 1783 : if Self::is_explain(state, state.find_statement_id(node_id)) {
1567 6 : self.merge_child_states(node_state, node);
1568 6 : self.create_scope(state, node_state, node_id);
1569 6 : return;
1570 1777 : }
1571 1777 : let [name_node, elements] =
1572 1777 : attrs!(state.children(node), [K::SQL_CREATE_TABLE_NAME, K::SQL_CREATE_TABLE_ELEMENTS]);
1573 1777 : let Some(table_name) = state.read_qualified_table_name(name_node) else { return };
1574 1777 : let schema_id = Self::register_schema(state, &table_name.database_name, &table_name.schema_name);
1575 1777 : let index = state.out.entry.table_declarations.len() as u32;
1576 1777 : let table_id = state.reserve_table_id(&table_name);
1577 : // Only the elements are merged
1578 1777 : if let Some(elements) = elements {
1579 1777 : let elements_id = state.node_id(elements) as usize;
1580 1777 : node_state.merge(&mut self.node_states[elements_id]);
1581 1777 : }
1582 1777 : let mut columns = std::mem::take(&mut node_state.table_columns);
1583 : // Sort the columns by name.
1584 : // The sort is stable, duplicate names keep their declaration order.
1585 7338 : columns.sort_by(|l, r| l.column_name.text.as_bytes().cmp(r.column_name.text.as_bytes()));
1586 1777 : self.create_scope(state, node_state, node_id);
1587 :
1588 1777 : let name = table_name.table_name.clone();
1589 1777 : let mut table = TableDeclaration::new(schema_id, table_id, table_name);
1590 1777 : table.ast_node_id = Some(node_id);
1591 1777 : table.ast_statement_id = state.find_statement_id(node_id);
1592 1777 : table.location = name_node.map(|n| state.text_span(*n.symbol_span()));
1593 1777 : let column_ids = state.reserve_column_ids(table_id, columns.iter().map(|c| &c.column_name.text));
1594 4347 : for (column_index, column) in columns.iter().enumerate() {
1595 4347 : table.table_columns_by_name.entry(column.column_name.text.clone()).or_insert(column_index);
1596 4347 : table.table_columns.push(TableColumn {
1597 4347 : object_id: QualifiedCatalogObjectId::table_column(table_id, column_ids[column_index]),
1598 4347 : table: Some(table_id),
1599 4347 : ast_node_id: Some(column.ast_node_id),
1600 4347 : column_name: column.column_name.clone(),
1601 4347 : column_type: column.column_type.clone(),
1602 4347 : location: Some(state.text_span(*state.ast[column.ast_node_id as usize].symbol_span())),
1603 4347 : });
1604 4347 : }
1605 1777 : state.entry_mut().table_declarations.push(table);
1606 1777 : state.resolve_name(&name, CatalogObjectRef::Table(TableLoc { entry: state.entry_id, index }));
1607 4347 : for (column_index, column) in columns.iter().enumerate() {
1608 4347 : let loc = ColumnLoc {
1609 4347 : table: TableLoc { entry: state.entry_id, index },
1610 4347 : column: column_index as u32,
1611 4347 : };
1612 4347 : state.resolve_name(&column.column_name, CatalogObjectRef::Column(loc));
1613 4347 : }
1614 : }
1615 :
1616 : NodeType::OBJECT_SQL_CREATE_FUNCTION => {
1617 36 : if Self::is_explain(state, state.find_statement_id(node_id)) {
1618 0 : self.merge_child_states(node_state, node);
1619 0 : return;
1620 36 : }
1621 36 : let [name_node, params, returns, is_aggregate] = attrs!(state.children(node), [
1622 : K::SQL_CREATE_FUNCTION_NAME,
1623 : K::SQL_CREATE_FUNCTION_PARAMS,
1624 : K::SQL_CREATE_FUNCTION_RETURNS,
1625 : K::SQL_CREATE_FUNCTION_IS_AGGREGATE,
1626 : ]);
1627 36 : let Some(function_name) = state.read_qualified_function_name(name_node) else { return };
1628 36 : let schema_id = Self::register_schema(state, &function_name.database_name, &function_name.schema_name);
1629 36 : let index = state.out.entry.function_declarations.len() as u32;
1630 36 : let function_id = state.reserve_function_id(&function_name);
1631 36 : let return_type: Arc<str> = returns.map(|r| Arc::from(state.text_at(*r.symbol_span()))).unwrap_or_else(|| Arc::from(""));
1632 36 : let mut declaration = FunctionDeclaration {
1633 36 : object_id: QualifiedCatalogObjectId::function(function_id),
1634 36 : catalog_schema_id: schema_id,
1635 36 : is_aggregate: is_aggregate.is_some(),
1636 36 : ast_node_id: Some(node_id),
1637 36 : ast_statement_id: None,
1638 36 : function_name: function_name.clone(),
1639 36 : params: Vec::new(),
1640 36 : return_type,
1641 36 : location: name_node.map(|n| state.text_span(*n.symbol_span())),
1642 : };
1643 36 : if let Some(params) = params.filter(|n| n.node_type() == NodeType::ARRAY) {
1644 34 : for param in state.children(params) {
1645 34 : if param.node_type() != NodeType::OBJECT_SQL_FUNCTION_PARAM {
1646 0 : continue;
1647 34 : }
1648 34 : let [param_name, param_type] =
1649 34 : attrs!(state.children(param), [K::SQL_FUNCTION_PARAM_NAME, K::SQL_FUNCTION_PARAM_TYPE]);
1650 34 : let Some(param_name) = param_name.filter(|n| n.node_type() == NodeType::NAME) else { continue };
1651 34 : let param_type = param_type.map(|t| state.text_at(*t.symbol_span())).unwrap_or("");
1652 34 : declaration.params.push(FunctionParam {
1653 34 : ast_node_id: Some(state.node_id(param)),
1654 34 : param_name: state.node_name(param_name),
1655 34 : param_type: Arc::from(param_type),
1656 34 : });
1657 : }
1658 5 : }
1659 36 : state.entry_mut().function_declarations.push(declaration);
1660 36 : state.tag(&function_name.function_name, NameTag::FUNCTION_NAME);
1661 36 : state.resolve_name(&function_name.function_name, CatalogObjectRef::Function(state.loc(index as usize)));
1662 : }
1663 :
1664 : NodeType::OBJECT_SQL_CREATE_AS | NodeType::OBJECT_SQL_VIEW => {
1665 158 : let [name, columns, statement] = if node.node_type() == NodeType::OBJECT_SQL_CREATE_AS {
1666 82 : attrs!(state.children(node), [K::SQL_CREATE_AS_NAME, K::SQL_CREATE_AS_COLUMNS, K::SQL_CREATE_AS_STATEMENT])
1667 : } else {
1668 76 : attrs!(state.children(node), [K::SQL_VIEW_NAME, K::SQL_VIEW_COLUMNS, K::SQL_VIEW_STATEMENT])
1669 : };
1670 158 : if let Some(statement) = statement.filter(|n| n.node_type() == NodeType::OBJECT_SQL_SELECT) {
1671 158 : self.register_derived_table(state, node, name, columns, statement);
1672 158 : }
1673 158 : self.merge_child_states(node_state, node);
1674 : }
1675 :
1676 41 : NodeType::OBJECT_SQL_ALTER_TABLE | NodeType::OBJECT_SQL_ALTER_VIEW => {
1677 41 : // The columns of the actions belong to the table, not to a scope
1678 41 : self.merge_child_states(node_state, node);
1679 41 : node_state.clear();
1680 41 : self.visit_alter(state, node, node_id);
1681 41 : }
1682 :
1683 15 : NodeType::OBJECT_SQL_PROPERTY_GRAPH | NodeType::OBJECT_SQL_GRAPH_TABLE => {
1684 15 : // Property graph analysis is syntax-only. Keep graph-local references in the
1685 15 : // analyzed buffers, but prevent them from entering or affecting an SQL scope.
1686 15 : self.merge_child_states(node_state, node);
1687 15 : node_state.clear();
1688 15 : }
1689 :
1690 : // By default, merge child states into the node state
1691 63230 : _ => self.merge_child_states(node_state, node),
1692 : }
1693 84087 : }
1694 :
1695 : /// Is a column ref the qualifier of a star result target (`t.*`)?
1696 2721 : fn is_star_qualifier(state: &AnalysisState, node: &Node) -> bool {
1697 2721 : if node.attribute_key() != K::SQL_RESULT_TARGET_VALUE {
1698 1152 : return false;
1699 1569 : }
1700 1569 : let Some(target) = state.ast.get(node.parent() as usize) else { return false };
1701 1569 : let [star] = attrs!(state.children(target), [K::SQL_RESULT_TARGET_STAR]);
1702 1569 : target.node_type() == NodeType::OBJECT_SQL_RESULT_TARGET && star.is_some()
1703 2721 : }
1704 :
1705 : /// Mark the CTEs of a scope as correlation barriers
1706 319 : fn set_cte_correlation_barriers(&self, state: &mut AnalysisState, scope: ScopeId) {
1707 319 : let children: Vec<ScopeId> = state.out.name_scopes[scope as usize]
1708 319 : .cte_definitions
1709 319 : .iter()
1710 319 : .filter_map(|(_, cte)| cte.child_scope)
1711 319 : .collect();
1712 319 : for child in children {
1713 18 : state.out.name_scopes[child as usize].column_correlation_barrier = true;
1714 18 : }
1715 319 : }
1716 :
1717 4003 : pub fn finish(&mut self, state: &mut AnalysisState) {
1718 : // Index the tables and functions
1719 4003 : state.entry_mut().index_declarations();
1720 :
1721 : // Assign statement ids to scopes before resolving ordered script-local names
1722 5857 : for i in 0..state.out.name_scopes.len() {
1723 5774 : let node_id = state.out.name_scopes[i].ast_node_id;
1724 5774 : state.out.name_scopes[i].ast_statement_id = state.find_statement_id(node_id);
1725 5774 : }
1726 :
1727 : // Resolve all names
1728 4003 : self.resolve_names(state);
1729 :
1730 4003 : for pending in std::mem::take(&mut self.pending_derived_tables) {
1731 155 : if let Some(&scope) = state.out.name_scopes_by_root_node.get(&pending.select_node_id) {
1732 155 : Self::populate_derived_table(state, &pending, scope);
1733 155 : }
1734 : }
1735 4003 : for (table, action) in std::mem::take(&mut self.pending_alters) {
1736 5 : let action = state.ast[action as usize];
1737 5 : Self::apply_column_action(state, table, &action);
1738 5 : }
1739 :
1740 : // Assign statement ids, the objects are ordered by their AST nodes
1741 4003 : if !state.parsed.statements.is_empty() {
1742 3767 : let statements = &state.parsed.statements;
1743 15068 : let assign = |nodes: &mut dyn Iterator<Item = (u32, &mut Option<u32>)>| {
1744 15068 : let mut statement_id = 0usize;
1745 15068 : let mut statement_begin = statements[0].nodes_begin;
1746 15068 : let mut statement_end = statement_begin + statements[0].node_count;
1747 17283 : for (ast_node_id, statement) in nodes {
1748 18191 : while statement_end <= ast_node_id && statement_id < statements.len() {
1749 3514 : statement_id += 1;
1750 3514 : if statement_id == statements.len() {
1751 0 : break;
1752 3514 : }
1753 3514 : statement_begin = statements[statement_id].nodes_begin;
1754 3514 : statement_end = statement_begin + statements[statement_id].node_count;
1755 : }
1756 14677 : if statement_id == statements.len() {
1757 0 : break;
1758 14677 : }
1759 14677 : if statement_begin <= ast_node_id {
1760 14535 : *statement = Some(statement_id as u32);
1761 14535 : }
1762 : }
1763 15068 : };
1764 3776 : assign(&mut state.out.table_references.iter_mut().map(|r| (r.ast_node_id, &mut r.ast_statement_id)));
1765 6468 : assign(&mut state.out.expressions.iter_mut().map(|e| (e.ast_node_id, &mut e.ast_statement_id)));
1766 3767 : let mut scope_statements: Vec<Option<u32>> = vec![None; state.out.name_scopes.len()];
1767 3767 : assign(
1768 3767 : &mut state
1769 3767 : .out
1770 3767 : .name_scopes
1771 3767 : .iter()
1772 3767 : .zip(scope_statements.iter_mut())
1773 5768 : .map(|(s, statement)| (s.ast_node_id, statement)),
1774 : );
1775 5768 : for (scope, statement) in state.out.name_scopes.iter_mut().zip(scope_statements) {
1776 5765 : if statement.is_some() {
1777 5765 : scope.ast_statement_id = statement;
1778 5765 : }
1779 : }
1780 3767 : assign(
1781 3767 : &mut Arc::make_mut(&mut state.out.entry)
1782 3767 : .function_declarations
1783 3767 : .iter_mut()
1784 3767 : .filter_map(|f| Some((f.ast_node_id?, &mut f.ast_statement_id))),
1785 : );
1786 236 : }
1787 :
1788 : // Index the columns of the table declarations
1789 4003 : state.entry_mut().index_table_columns();
1790 :
1791 : // Solve the schema-inference constraints
1792 4003 : Self::run_schema_inference(state);
1793 4003 : Self::resolve_insert_target_columns(state);
1794 4003 : Self::compute_resolved_column_ids(state);
1795 4003 : }
1796 :
1797 : /// Bind explicit INSERT target columns after target-table resolution
1798 4003 : fn resolve_insert_target_columns(state: &mut AnalysisState) {
1799 4003 : for i in 0..state.out.insert_statements.len() {
1800 253 : let target = state.out.insert_statements[i].target;
1801 253 : let Some(resolved) = state.out.table_references[target as usize].inner.as_ref().and_then(|r| r.resolved_table.as_ref()) else {
1802 3 : continue;
1803 : };
1804 250 : let table_id = resolved.catalog_table_id.unpack_table_id();
1805 250 : let loc = if table_id.origin == state.entry_id {
1806 29 : state.out.entry.table_loc_by_id(table_id)
1807 : } else {
1808 221 : state.catalog.entry(table_id.origin).and_then(|e| e.data().table_loc_by_id(table_id))
1809 : };
1810 250 : let Some(loc) = loc else { continue };
1811 250 : let Some(table) = state.table(loc) else { continue };
1812 250 : let resolved: Vec<Option<ColumnLoc>> = state.out.insert_statements[i]
1813 250 : .target_columns
1814 250 : .iter()
1815 251 : .map(|c| {
1816 12 : table.table_columns_by_name.get(&c.column_name.text).map(|&column| ColumnLoc {
1817 10 : table: loc,
1818 10 : column: column as u32,
1819 10 : })
1820 12 : })
1821 250 : .collect();
1822 251 : for (column, resolved) in state.out.insert_statements[i].target_columns.iter_mut().zip(resolved) {
1823 12 : if resolved.is_some() {
1824 10 : column.resolved = resolved;
1825 11 : }
1826 : }
1827 : }
1828 4003 : }
1829 :
1830 : /// The table column behind a resolved column, scope columns are followed through their source expressions
1831 2851 : fn resolved_table_column(state: &AnalysisState, resolution: ColumnResolution) -> Option<ColumnLoc> {
1832 2851 : let mut current = resolution;
1833 2851 : for _ in 0..256 {
1834 2989 : match current {
1835 671 : ColumnResolution::Unresolved => return None,
1836 1966 : ColumnResolution::TableColumn(loc) => return Some(loc),
1837 352 : ColumnResolution::ScopeColumn { scope, column } => {
1838 352 : let column = state.out.name_scopes[scope as usize].output_columns.get(column as usize)?;
1839 352 : match column.source {
1840 117 : ScopeColumnSource::TableColumn(loc) => return Some(loc),
1841 11 : ScopeColumnSource::Computed => return None,
1842 224 : ScopeColumnSource::Expression(expr) => {
1843 224 : current = state.out.expressions[expr as usize].column_ref()?.resolved;
1844 : }
1845 : }
1846 : }
1847 : }
1848 : }
1849 0 : None
1850 2851 : }
1851 :
1852 : /// The catalog ids of a resolved column
1853 2715 : fn resolved_column_ids(state: &AnalysisState, resolution: ColumnResolution) -> Option<ResolvedColumnIds> {
1854 2715 : let loc = Self::resolved_table_column(state, resolution)?;
1855 1972 : let table = state.table(loc.table)?;
1856 1972 : let column = table.table_columns.get(loc.column as usize)?;
1857 1972 : Some(ResolvedColumnIds {
1858 1972 : catalog_schema_id: table.catalog_schema_id,
1859 1972 : catalog_table_column_id: column.object_id,
1860 1972 : referenced_catalog_version: table.catalog_version,
1861 1972 : })
1862 2715 : }
1863 :
1864 4003 : fn compute_resolved_column_ids(state: &mut AnalysisState) {
1865 6599 : for i in 0..state.out.expressions.len() {
1866 6332 : let Some(column_ref) = state.out.expressions[i].column_ref() else { continue };
1867 2715 : let ids = Self::resolved_column_ids(state, column_ref.resolved);
1868 2715 : state.out.expressions[i].column_ref_mut().unwrap().resolved_ids = ids;
1869 : }
1870 4003 : }
1871 :
1872 : /// Solve the schema-inference constraints into inferred table schemas
1873 4003 : fn run_schema_inference(state: &mut AnalysisState) {
1874 4003 : let constraints = std::mem::take(&mut state.out.inference_constraints);
1875 4003 : if constraints.is_empty() {
1876 3887 : return;
1877 116 : }
1878 116 : let out = &mut state.out;
1879 :
1880 184 : fn get_or_create_schema(out: &mut super::AnalyzedScript, table_name: &QualifiedTableName) -> usize {
1881 184 : let key = table_name.key();
1882 184 : if let Some(&i) = out.inferred_table_schemas_by_name.get(&key) {
1883 60 : return i;
1884 124 : }
1885 124 : out.inferred_table_schemas.push(InferredTableSchema {
1886 124 : table_name: table_name.clone(),
1887 124 : confidence: InferenceConfidence::None,
1888 124 : columns: Vec::new(),
1889 124 : columns_by_name: HashMap::default(),
1890 124 : });
1891 124 : let i = out.inferred_table_schemas.len() - 1;
1892 124 : out.inferred_table_schemas_by_name.insert(key, i);
1893 124 : i
1894 184 : }
1895 184 : fn add_column(schema: &mut InferredTableSchema, column: &Name, confidence: InferenceConfidence) -> usize {
1896 184 : if let Some(&i) = schema.columns_by_name.get(&column.text) {
1897 16 : let c = &mut schema.columns[i];
1898 16 : c.confidence = c.confidence.max(confidence);
1899 16 : schema.confidence = schema.confidence.max(confidence);
1900 16 : return i;
1901 168 : }
1902 168 : let i = schema.columns.len();
1903 168 : schema.columns_by_name.insert(column.text.clone(), i);
1904 168 : schema.columns.push(InferredColumn {
1905 168 : column_name: column.clone(),
1906 168 : confidence,
1907 168 : candidate_table_names: Vec::new(),
1908 168 : });
1909 168 : schema.confidence = schema.confidence.max(confidence);
1910 168 : i
1911 184 : }
1912 117 : let has_confident_column = |out: &super::AnalyzedScript, table_name: &QualifiedTableName, column: &str| {
1913 22 : let Some(&i) = out.inferred_table_schemas_by_name.get(&table_name.key()) else { return false };
1914 2 : let schema = &out.inferred_table_schemas[i];
1915 2 : schema
1916 2 : .columns_by_name
1917 2 : .get(column)
1918 2 : .is_some_and(|&c| schema.columns[c].confidence == InferenceConfidence::Confident)
1919 22 : };
1920 185 : let write_owner = |out: &mut super::AnalyzedScript, expr: u32, owner: &InferenceCandidate, confidence| {
1921 185 : if let Some(column_ref) = out.expressions.get_mut(expr as usize).and_then(|e| e.column_ref_mut()) {
1922 185 : column_ref.inferred = Some(InferredOwner {
1923 185 : table_ref: owner.table_ref,
1924 185 : table_name: owner.table_name.clone(),
1925 185 : confidence,
1926 185 : });
1927 185 : }
1928 185 : };
1929 :
1930 116 : let mut resolved = vec![false; constraints.len()];
1931 :
1932 : // Step 1: seed the forced constraints
1933 185 : for (i, c) in constraints.iter().enumerate() {
1934 185 : if c.kind == InferenceConstraintKind::Forced && !c.candidates.is_empty() {
1935 174 : let candidate = &c.candidates[0];
1936 174 : let schema = get_or_create_schema(out, &candidate.table_name);
1937 174 : add_column(&mut out.inferred_table_schemas[schema], &c.column_name, InferenceConfidence::Confident);
1938 174 : write_owner(out, c.expression_id, candidate, InferenceConfidence::Confident);
1939 174 : resolved[i] = true;
1940 174 : }
1941 : }
1942 :
1943 : // Step 2: propagate over disjunctive constraints to a fixpoint. A disjunction is explained
1944 : // when exactly one candidate confidently owns its column.
1945 116 : let mut changed = true;
1946 233 : while changed {
1947 117 : changed = false;
1948 187 : for (i, c) in constraints.iter().enumerate() {
1949 187 : if resolved[i] || c.kind != InferenceConstraintKind::Disjunctive {
1950 176 : continue;
1951 11 : }
1952 11 : let owners: Vec<&InferenceCandidate> = c
1953 11 : .candidates
1954 11 : .iter()
1955 22 : .filter(|candidate| has_confident_column(out, &candidate.table_name, &c.column_name.text))
1956 11 : .collect();
1957 11 : if owners.is_empty() {
1958 10 : continue;
1959 1 : }
1960 : // Several owners make the use ambiguous, record a best guess
1961 1 : let confidence = if owners.len() == 1 {
1962 1 : InferenceConfidence::Confident
1963 : } else {
1964 0 : InferenceConfidence::Candidate
1965 : };
1966 1 : write_owner(out, c.expression_id, owners[0], confidence);
1967 1 : resolved[i] = true;
1968 1 : changed = true;
1969 : }
1970 : }
1971 :
1972 : // Step 3: assign the residual disjunctions to the candidate with the most inferred columns
1973 185 : for (i, c) in constraints.iter().enumerate() {
1974 185 : if resolved[i] || c.kind != InferenceConstraintKind::Disjunctive {
1975 175 : continue;
1976 10 : }
1977 10 : if c.candidates.is_empty() || c.candidates.len() > MAX_TABLE_REF_AMBIGUITY {
1978 0 : resolved[i] = true;
1979 0 : continue;
1980 10 : }
1981 10 : let mut best = 0;
1982 10 : let mut best_columns = 0;
1983 20 : for (ci, candidate) in c.candidates.iter().enumerate() {
1984 20 : let n = out
1985 20 : .inferred_table_schemas_by_name
1986 20 : .get(&candidate.table_name.key())
1987 20 : .map(|&s| out.inferred_table_schemas[s].columns.len())
1988 20 : .unwrap_or(0);
1989 20 : if n > best_columns {
1990 3 : best_columns = n;
1991 3 : best = ci;
1992 17 : }
1993 : }
1994 10 : let schema = get_or_create_schema(out, &c.candidates[best].table_name);
1995 10 : let schema = &mut out.inferred_table_schemas[schema];
1996 10 : let column = add_column(schema, &c.column_name, InferenceConfidence::Candidate);
1997 20 : for (ci, candidate) in c.candidates.iter().enumerate() {
1998 20 : if ci != best {
1999 10 : schema.columns[column].candidate_table_names.push(candidate.table_name.clone());
2000 10 : }
2001 : }
2002 10 : write_owner(out, c.expression_id, &c.candidates[best], InferenceConfidence::Candidate);
2003 10 : resolved[i] = true;
2004 : }
2005 116 : state.out.inference_constraints = constraints;
2006 4003 : }
2007 : }
|