LCOV - code coverage report
Current view: top level - dashql-core/src/catalog - entry.rs Coverage Total Hit
Test: DashQL d805a4b Lines: 99.1 % 218 216
Test Date: 2026-11-09 20:22:13

            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              : }
        

Generated by: LCOV version 2.0-1