Line data Source code
1 : //! The declarations of a catalog entry.
2 : //!
3 : //! Analyzed scripts and descriptor pools both expose their declarations through [`CatalogEntryData`].
4 : //! Names are shared strings, so qualified names stay valid across entries without borrowing the name
5 : //! registries of other entries.
6 :
7 : use super::ids::*;
8 : use dashql_parser::span::TextSpan;
9 : use crate::hash::HashMap;
10 : use std::collections::BTreeMap;
11 : use std::sync::Arc;
12 :
13 : /// The id of a name within the names of its catalog entry
14 : pub type NameId = u32;
15 :
16 : /// A name of a catalog entry
17 : #[derive(Clone, Debug)]
18 : pub struct Name {
19 : /// The catalog entry that registered the name
20 : pub entry: CatalogEntryId,
21 : /// The name id within that entry
22 : pub id: NameId,
23 : /// The text
24 : pub text: Arc<str>,
25 : }
26 :
27 : impl Name {
28 464 : pub fn text(&self) -> &str {
29 464 : &self.text
30 464 : }
31 : }
32 :
33 : /// A qualified table name
34 : #[derive(Clone, Debug)]
35 : pub struct QualifiedTableName {
36 : /// The AST node id in the declaring script
37 : pub ast_node_id: Option<u32>,
38 : /// The database name, empty when not qualified
39 : pub database_name: Name,
40 : /// The schema name, empty when not qualified
41 : pub schema_name: Name,
42 : /// The table name
43 : pub table_name: Name,
44 : }
45 :
46 : /// The lookup key of a qualified name: (database, schema, table)
47 : pub type QualifiedKey = (Arc<str>, Arc<str>, Arc<str>);
48 :
49 : impl QualifiedTableName {
50 9383 : pub fn key(&self) -> QualifiedKey {
51 9383 : (self.database_name.text.clone(), self.schema_name.text.clone(), self.table_name.text.clone())
52 9383 : }
53 :
54 : /// The qualified name for debug output
55 84 : pub fn debug_string(&self) -> String {
56 84 : debug_string(&self.database_name.text, &self.schema_name.text, &self.table_name.text)
57 84 : }
58 : }
59 :
60 159 : fn debug_string(database: &str, schema: &str, name: &str) -> String {
61 159 : let mut out = String::new();
62 159 : if !database.is_empty() {
63 20 : out.push_str(database);
64 20 : out.push('.');
65 20 : out.push_str(schema);
66 20 : out.push('.');
67 139 : } else if !schema.is_empty() {
68 7 : out.push_str(schema);
69 7 : out.push('.');
70 132 : }
71 159 : out.push_str(name);
72 159 : out
73 159 : }
74 :
75 : /// A qualified column name
76 : #[derive(Clone, Debug)]
77 : pub struct QualifiedColumnName {
78 : /// The AST node id in the declaring script
79 : pub ast_node_id: Option<u32>,
80 : /// The table alias qualifying the column, if any
81 : pub table_alias: Option<Name>,
82 : /// The column name
83 : pub column_name: Name,
84 : }
85 :
86 : /// A qualified function name
87 : #[derive(Clone, Debug)]
88 : pub struct QualifiedFunctionName {
89 : /// The AST node id in the declaring script
90 : pub ast_node_id: Option<u32>,
91 : /// The database name, empty when not qualified
92 : pub database_name: Name,
93 : /// The schema name, empty when not qualified
94 : pub schema_name: Name,
95 : /// The function name
96 : pub function_name: Name,
97 : }
98 :
99 : impl QualifiedFunctionName {
100 89 : pub fn key(&self) -> QualifiedKey {
101 89 : (self.database_name.text.clone(), self.schema_name.text.clone(), self.function_name.text.clone())
102 89 : }
103 :
104 : /// The qualified name for debug output
105 75 : pub fn debug_string(&self) -> String {
106 75 : debug_string(&self.database_name.text, &self.schema_name.text, &self.function_name.text)
107 75 : }
108 : }
109 :
110 : /// A table column
111 : #[derive(Clone, Debug)]
112 : pub struct TableColumn {
113 : /// The qualified object id, packs the table id and the column index
114 : pub object_id: QualifiedCatalogObjectId,
115 : /// The table of the column
116 : pub table: Option<CatalogTableId>,
117 : /// The AST node id in the declaring script
118 : pub ast_node_id: Option<u32>,
119 : /// The column name
120 : pub column_name: Name,
121 : /// The text of the declared type, None if a column has no declaration or nothing tells the type.
122 : /// It's text because nothing reads more than that, and a packed catalog would have to parse every column again.
123 : pub column_type: Option<Arc<str>>,
124 : /// The text of the column definition in the declaring script, None for derived columns
125 : pub location: Option<TextSpan>,
126 : }
127 :
128 : impl TableColumn {
129 : /// The id of the column within its table, stable across versions of the declaring entry
130 2691 : pub fn column_id(&self) -> u32 {
131 2691 : self.object_id.unpack_table_column_id().1
132 2691 : }
133 : }
134 :
135 : /// A table declaration
136 : #[derive(Clone, Debug)]
137 : pub struct TableDeclaration {
138 : /// The qualified object id of the table
139 : pub object_id: QualifiedCatalogObjectId,
140 : /// The catalog version
141 : pub catalog_version: CatalogVersion,
142 : /// The schema of the table
143 : pub catalog_schema_id: QualifiedCatalogObjectId,
144 : /// The AST node id of the declaration in the declaring script
145 : pub ast_node_id: Option<u32>,
146 : /// The id of the declaring statement
147 : pub ast_statement_id: Option<u32>,
148 : /// The root node of the name scope of the defining SELECT, for derived tables
149 : pub ast_scope_root: Option<u32>,
150 : /// Declared by CREATE VIEW?
151 : pub is_view: bool,
152 : /// The qualified table name
153 : pub table_name: QualifiedTableName,
154 : /// The columns, in declaration order
155 : pub table_columns: Vec<TableColumn>,
156 : /// The column indexes by name
157 : pub table_columns_by_name: HashMap<Arc<str>, usize>,
158 : /// The text of the table name in the declaring script: the script of a session, or the script
159 : /// that a descriptor was built from
160 : pub location: Option<TextSpan>,
161 : }
162 :
163 : impl TableDeclaration {
164 2052 : pub fn new(schema: QualifiedCatalogObjectId, table_id: CatalogTableId, table_name: QualifiedTableName) -> Self {
165 2052 : Self {
166 2052 : object_id: QualifiedCatalogObjectId::table(table_id),
167 2052 : catalog_version: 0,
168 2052 : catalog_schema_id: schema,
169 2052 : ast_node_id: None,
170 2052 : ast_statement_id: None,
171 2052 : ast_scope_root: None,
172 2052 : is_view: false,
173 2052 : table_name,
174 2052 : table_columns: Vec::new(),
175 2052 : table_columns_by_name: HashMap::default(),
176 2052 : location: None,
177 2052 : }
178 2052 : }
179 :
180 3566 : pub fn table_id(&self) -> CatalogTableId {
181 3566 : self.object_id.unpack_table_id()
182 3566 : }
183 :
184 : /// Find a column by name
185 4 : pub fn column_by_name(&self, name: &str) -> Option<&TableColumn> {
186 4 : self.table_columns_by_name.get(name).map(|&i| &self.table_columns[i])
187 4 : }
188 :
189 : /// Find a column by its id
190 68 : pub fn column_by_id(&self, column_id: u32) -> Option<&TableColumn> {
191 98 : self.table_columns.iter().find(|c| c.column_id() == column_id)
192 68 : }
193 : }
194 :
195 : /// A function parameter
196 : #[derive(Clone, Debug)]
197 : pub struct FunctionParam {
198 : /// The AST node id in the declaring script
199 : pub ast_node_id: Option<u32>,
200 : /// The parameter name
201 : pub param_name: Name,
202 : /// The parameter type as written, empty when not specified
203 : pub param_type: Arc<str>,
204 : }
205 :
206 : /// A function declaration
207 : #[derive(Clone, Debug)]
208 : pub struct FunctionDeclaration {
209 : /// The qualified object id of the function
210 : pub object_id: QualifiedCatalogObjectId,
211 : /// The schema of the function
212 : pub catalog_schema_id: QualifiedCatalogObjectId,
213 : /// Whether the function is an aggregate function
214 : pub is_aggregate: bool,
215 : /// The AST node id in the declaring script, None for descriptor functions
216 : pub ast_node_id: Option<u32>,
217 : /// The id of the declaring statement
218 : pub ast_statement_id: Option<u32>,
219 : /// The qualified function name
220 : pub function_name: QualifiedFunctionName,
221 : /// The parameters, in declaration order
222 : pub params: Vec<FunctionParam>,
223 : /// The return type as written, empty when not specified
224 : pub return_type: Arc<str>,
225 : /// The text of the function name in the declaring script
226 : pub location: Option<TextSpan>,
227 : }
228 :
229 : impl FunctionDeclaration {
230 15 : pub fn function_id(&self) -> CatalogFunctionId {
231 15 : self.object_id.unpack_function_id()
232 15 : }
233 : }
234 :
235 : /// A referenced database
236 : #[derive(Clone, Debug)]
237 : pub struct DatabaseReference {
238 : /// The qualified object id of the database
239 : pub object_id: QualifiedCatalogObjectId,
240 : /// The database name
241 : pub database_name: Arc<str>,
242 : /// The database alias, empty when not aliased
243 : pub database_alias: Arc<str>,
244 : }
245 :
246 : impl DatabaseReference {
247 12 : pub fn database_id(&self) -> CatalogDatabaseId {
248 12 : self.object_id.unpack_database_id()
249 12 : }
250 : }
251 :
252 : /// A referenced schema
253 : #[derive(Clone, Debug)]
254 : pub struct SchemaReference {
255 : /// The qualified object id, packs the database and schema ids
256 : pub object_id: QualifiedCatalogObjectId,
257 : /// The database name
258 : pub database_name: Arc<str>,
259 : /// The schema name
260 : pub schema_name: Arc<str>,
261 : }
262 :
263 : impl SchemaReference {
264 10 : pub fn database_id(&self) -> CatalogDatabaseId {
265 10 : self.object_id.unpack_schema_id().0
266 10 : }
267 10 : pub fn schema_id(&self) -> CatalogSchemaId {
268 10 : self.object_id.unpack_schema_id().1
269 10 : }
270 : }
271 :
272 : /// The location of a table: catalog entry and index of the declaration
273 : #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
274 : pub struct TableLoc {
275 : /// The catalog entry that declares the table
276 : pub entry: CatalogEntryId,
277 : /// The index in the table declarations of the entry
278 : pub index: u32,
279 : }
280 :
281 : /// The location of a table column
282 : #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
283 : pub struct ColumnLoc {
284 : /// The table of the column
285 : pub table: TableLoc,
286 : /// The index in the columns of the table
287 : pub column: u32,
288 : }
289 :
290 : /// The location of an object in the vectors of a catalog entry
291 : #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
292 : pub struct ObjectLoc {
293 : /// The catalog entry that declares the object
294 : pub entry: CatalogEntryId,
295 : /// The index in the declaration vector of the object kind
296 : pub index: u32,
297 : }
298 :
299 : /// A catalog object: a declaration of a catalog entry
300 : #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
301 : pub enum CatalogObjectRef {
302 : Database(ObjectLoc),
303 : Schema(ObjectLoc),
304 : Table(TableLoc),
305 : Column(ColumnLoc),
306 : Function(ObjectLoc),
307 : }
308 :
309 : impl CatalogObjectRef {
310 : /// The entry that declares the object
311 492 : pub fn entry(&self) -> CatalogEntryId {
312 492 : match self {
313 68 : CatalogObjectRef::Database(l) | CatalogObjectRef::Schema(l) | CatalogObjectRef::Function(l) => l.entry,
314 150 : CatalogObjectRef::Table(t) => t.entry,
315 274 : CatalogObjectRef::Column(c) => c.table.entry,
316 : }
317 492 : }
318 : }
319 :
320 : /// The declarations of a catalog entry and their indexes
321 : #[derive(Clone, Debug, Default)]
322 : pub struct CatalogEntryData {
323 : /// The id of the catalog entry
324 : pub catalog_entry_id: CatalogEntryId,
325 : /// The catalog version when the entry was created
326 : pub catalog_version: CatalogVersion,
327 : /// The databases the entry references, in registration order
328 : pub database_references: Vec<DatabaseReference>,
329 : /// The schemas the entry references, in registration order
330 : pub schema_references: Vec<SchemaReference>,
331 : /// The tables the entry declares, in declaration order
332 : pub table_declarations: Vec<TableDeclaration>,
333 : /// The functions the entry declares, in declaration order
334 : pub function_declarations: Vec<FunctionDeclaration>,
335 : /// Database references by name
336 : pub databases_by_name: HashMap<Arc<str>, usize>,
337 : /// Schema references by (database, schema)
338 : pub schemas_by_qualified_name: BTreeMap<(Arc<str>, Arc<str>), usize>,
339 : /// Tables by (database, schema, table)
340 : pub tables_by_qualified_name: HashMap<QualifiedKey, usize>,
341 : /// Tables by name, in declaration order
342 : pub tables_by_unqualified_name: BTreeMap<Arc<str>, Vec<usize>>,
343 : /// Tables by (schema, database), in declaration order
344 : pub tables_by_unqualified_schema: BTreeMap<(Arc<str>, Arc<str>), Vec<usize>>,
345 : /// Table columns by name, in declaration order
346 : pub table_columns_by_name: BTreeMap<Arc<str>, Vec<ColumnLoc>>,
347 : /// Functions by (database, schema, function)
348 : pub functions_by_qualified_name: HashMap<QualifiedKey, usize>,
349 : /// Functions by name, in declaration order
350 : pub functions_by_unqualified_name: BTreeMap<Arc<str>, Vec<usize>>,
351 : /// Table indexes by table id
352 : pub tables_by_id: HashMap<u32, usize>,
353 : }
354 :
355 : impl CatalogEntryData {
356 4055 : pub fn new(catalog_entry_id: CatalogEntryId, catalog_version: CatalogVersion) -> Self {
357 4055 : Self {
358 4055 : catalog_entry_id,
359 4055 : catalog_version,
360 4055 : ..Default::default()
361 4055 : }
362 4055 : }
363 :
364 : /// Does another version of the entry declare the same objects?
365 : ///
366 : /// Compares what other entries resolve against: the ids and names of the databases, schemas,
367 : /// tables, columns and functions. AST positions and name ids are ignored, only the declaring
368 : /// script reads them.
369 214 : pub fn same_declarations(&self, other: &CatalogEntryData) -> bool {
370 205 : fn same_table_name(a: &QualifiedTableName, b: &QualifiedTableName) -> bool {
371 205 : a.key() == b.key()
372 205 : }
373 203 : fn same_column(a: &TableColumn, b: &TableColumn) -> bool {
374 203 : a.object_id == b.object_id && a.table == b.table && a.column_name.text == b.column_name.text
375 203 : }
376 207 : fn same_table(a: &TableDeclaration, b: &TableDeclaration) -> bool {
377 207 : a.object_id == b.object_id
378 205 : && a.catalog_version == b.catalog_version
379 205 : && a.catalog_schema_id == b.catalog_schema_id
380 205 : && a.is_view == b.is_view
381 205 : && same_table_name(&a.table_name, &b.table_name)
382 205 : && a.table_columns.len() == b.table_columns.len()
383 203 : && a.table_columns.iter().zip(&b.table_columns).all(|(a, b)| same_column(a, b))
384 207 : }
385 6 : fn same_param(a: &FunctionParam, b: &FunctionParam) -> bool {
386 6 : a.param_name.text == b.param_name.text && a.param_type == b.param_type
387 6 : }
388 8 : fn same_function(a: &FunctionDeclaration, b: &FunctionDeclaration) -> bool {
389 8 : a.object_id == b.object_id
390 8 : && a.catalog_schema_id == b.catalog_schema_id
391 8 : && a.is_aggregate == b.is_aggregate
392 7 : && a.function_name.key() == b.function_name.key()
393 7 : && a.return_type == b.return_type
394 6 : && a.params.len() == b.params.len()
395 6 : && a.params.iter().zip(&b.params).all(|(a, b)| same_param(a, b))
396 8 : }
397 851 : fn same<T>(a: &[T], b: &[T], eq: impl Fn(&T, &T) -> bool) -> bool {
398 851 : a.len() == b.len() && a.iter().zip(b).all(|(a, b)| eq(a, b))
399 851 : }
400 214 : self.catalog_entry_id == other.catalog_entry_id
401 214 : && same(&self.database_references, &other.database_references, |a, b| {
402 214 : a.object_id == b.object_id && a.database_name == b.database_name && a.database_alias == b.database_alias
403 214 : })
404 214 : && same(&self.schema_references, &other.schema_references, |a, b| {
405 214 : a.object_id == b.object_id && a.database_name == b.database_name && a.schema_name == b.schema_name
406 214 : })
407 214 : && same(&self.table_declarations, &other.table_declarations, same_table)
408 209 : && same(&self.function_declarations, &other.function_declarations, same_function)
409 214 : }
410 :
411 : /// The location of a table of this entry
412 2474 : pub fn table_loc(&self, index: usize) -> TableLoc {
413 2474 : TableLoc {
414 2474 : entry: self.catalog_entry_id,
415 2474 : index: index as u32,
416 2474 : }
417 2474 : }
418 :
419 : /// The id of an object of this entry
420 246 : pub fn object_id(&self, object: CatalogObjectRef) -> QualifiedCatalogObjectId {
421 246 : match object {
422 13 : CatalogObjectRef::Database(l) => self.database_references[l.index as usize].object_id,
423 3 : CatalogObjectRef::Schema(l) => self.schema_references[l.index as usize].object_id,
424 75 : CatalogObjectRef::Table(t) => self.table_declarations[t.index as usize].object_id,
425 137 : CatalogObjectRef::Column(c) => self.table_declarations[c.table.index as usize].table_columns[c.column as usize].object_id,
426 18 : CatalogObjectRef::Function(l) => self.function_declarations[l.index as usize].object_id,
427 : }
428 246 : }
429 :
430 : /// A table by id
431 167 : pub fn table_by_id(&self, table_id: CatalogTableId) -> Option<&TableDeclaration> {
432 167 : self.table_loc_by_id(table_id).map(|loc| &self.table_declarations[loc.index as usize])
433 167 : }
434 :
435 : /// The location of a table by id
436 417 : pub fn table_loc_by_id(&self, table_id: CatalogTableId) -> Option<TableLoc> {
437 417 : if table_id.origin != self.catalog_entry_id {
438 0 : return None;
439 417 : }
440 417 : self.tables_by_id.get(&table_id.object).map(|&index| self.table_loc(index))
441 417 : }
442 :
443 : /// Resolve a table by name
444 2409 : pub fn resolve_table(&self, name: &QualifiedTableName, out: &mut Vec<TableLoc>, limit: usize) {
445 2409 : if let Some(&i) = self.tables_by_qualified_name.get(&name.key()) {
446 160 : out.push(self.table_loc(i));
447 160 : return;
448 2249 : }
449 2249 : if name.database_name.text.is_empty() {
450 2146 : if name.schema_name.text.is_empty() {
451 2104 : self.resolve_table_everywhere(&name.table_name.text, out, limit);
452 2104 : } else {
453 42 : self.resolve_table_in_schema(&name.schema_name.text, &name.table_name.text, out, limit);
454 42 : }
455 103 : }
456 2409 : }
457 :
458 : /// Resolve a table by schema and name across databases
459 49 : pub fn resolve_table_in_schema(&self, schema_name: &str, table_name: &str, out: &mut Vec<TableLoc>, limit: usize) {
460 49 : let lower = (Arc::<str>::from(schema_name), Arc::<str>::from(""));
461 49 : for ((schema, _), tables) in self.tables_by_unqualified_schema.range(lower..) {
462 14 : if &**schema != schema_name {
463 5 : break;
464 9 : }
465 12 : for &i in tables {
466 12 : if &*self.table_declarations[i].table_name.table_name.text != table_name {
467 9 : continue;
468 3 : }
469 3 : out.push(self.table_loc(i));
470 3 : if out.len() >= limit {
471 0 : return;
472 3 : }
473 : }
474 : }
475 49 : }
476 :
477 : /// Resolve a table by name only
478 4112 : pub fn resolve_table_everywhere(&self, table_name: &str, out: &mut Vec<TableLoc>, limit: usize) {
479 4112 : if let Some(tables) = self.tables_by_unqualified_name.get(table_name) {
480 1813 : for &i in tables {
481 1813 : out.push(self.table_loc(i));
482 1813 : if out.len() >= limit {
483 1 : return;
484 1812 : }
485 : }
486 2305 : }
487 4112 : }
488 :
489 : /// The table columns with a name
490 133 : pub fn resolve_table_columns(&self, column_name: &str, out: &mut Vec<ColumnLoc>) {
491 133 : if let Some(columns) = self.table_columns_by_name.get(column_name) {
492 17 : out.extend_from_slice(columns);
493 116 : }
494 133 : }
495 :
496 : /// Index the tables and functions (the first step of `NameResolutionPass::finish`)
497 4003 : pub fn index_declarations(&mut self) {
498 4197 : for (i, table) in self.table_declarations.iter().enumerate() {
499 1943 : self.tables_by_id.insert(table.table_id().object, i);
500 1943 : let name = &table.table_name;
501 : // A later declaration of a name replaces an earlier one, a script has one table of a name
502 1943 : let earlier = self.tables_by_qualified_name.insert(name.key(), i);
503 2098 : let declare = |tables: &mut Vec<usize>| match earlier.and_then(|earlier| tables.iter_mut().find(|t| **t == earlier)) {
504 9 : Some(table) => *table = i,
505 2089 : None => tables.push(i),
506 2098 : };
507 1943 : declare(self.tables_by_unqualified_name.entry(name.table_name.text.clone()).or_default());
508 1943 : if !name.schema_name.text.is_empty() {
509 155 : declare(self.tables_by_unqualified_schema.entry((name.schema_name.text.clone(), name.database_name.text.clone())).or_default());
510 1792 : }
511 : }
512 4003 : for (i, function) in self.function_declarations.iter().enumerate() {
513 36 : let name = &function.function_name;
514 36 : self.functions_by_qualified_name.entry(name.key()).or_insert(i);
515 36 : self.functions_by_unqualified_name.entry(name.function_name.text.clone()).or_default().push(i);
516 36 : }
517 4003 : }
518 :
519 : /// Index the columns of all tables by name
520 4003 : pub fn index_table_columns(&mut self) {
521 4197 : for (ti, table) in self.table_declarations.iter().enumerate() {
522 4497 : for (ci, column) in table.table_columns.iter().enumerate() {
523 4497 : self.table_columns_by_name.entry(column.column_name.text.clone()).or_default().push(ColumnLoc {
524 4497 : table: TableLoc {
525 4497 : entry: self.catalog_entry_id,
526 4497 : index: ti as u32,
527 4497 : },
528 4497 : column: ci as u32,
529 4497 : });
530 4497 : }
531 : }
532 4003 : }
533 : }
|