Skip to main content

uqa_sql/catalog/
virtual_relations.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Shared names and OIDs for implemented virtual catalog relations.
8
9macro_rules! virtual_relations {
10    ($($variant:ident => ($schema:literal, $name:literal, $oid:expr)),* $(,)?) => {
11        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
12        pub enum VirtualRelation { $($variant),* }
13
14        impl VirtualRelation {
15            pub const ALL: &'static [Self] = &[$(Self::$variant),*];
16
17            pub const fn namespace(self) -> &'static str {
18                match self { $(Self::$variant => $schema),* }
19            }
20
21            pub const fn name(self) -> &'static str {
22                match self { $(Self::$variant => $name),* }
23            }
24
25            pub fn oid(self) -> i64 {
26                match self { $(Self::$variant => $oid),* }
27            }
28
29            /// Resolve decoded identifiers exactly; parser-owned case folding must not change quoted names.
30            pub fn at(schema: &str, name: &str) -> Option<Self> {
31                match (schema, name) { $(($schema, $name) => Some(Self::$variant),)* _ => None }
32            }
33        }
34    };
35}
36
37virtual_relations! {
38    InformationSchemaCatalogName => ("information_schema", "information_schema_catalog_name", 13313),
39    InformationSchemata => ("information_schema", "schemata", 13467),
40    InformationTables => ("information_schema", "tables", 13510),
41    InformationColumns => ("information_schema", "columns", 13381),
42    InformationColumnPrivileges => ("information_schema", "column_privileges", 13371),
43    InformationRoleColumnGrants => ("information_schema", "role_column_grants", 13429),
44    InformationViews => ("information_schema", "views", 13568),
45    InformationRoutines => ("information_schema", "routines", 13462),
46    InformationSequences => ("information_schema", "sequences", 13471),
47    InformationTableConstraints => ("information_schema", "table_constraints", 13496),
48    InformationKeyColumnUsage => ("information_schema", "key_column_usage", 13414),
49    PgNamespace => ("pg_catalog", "pg_namespace", 2615),
50    PgClass => ("pg_catalog", "pg_class", 1259),
51    PgInherits => ("pg_catalog", "pg_inherits", 2611),
52    PgPartitionedTable => ("pg_catalog", "pg_partitioned_table", 3350),
53    PgAttribute => ("pg_catalog", "pg_attribute", 1249),
54    PgAttrdef => ("pg_catalog", "pg_attrdef", 2604),
55    PgConstraint => ("pg_catalog", "pg_constraint", 2606),
56    PgIndex => ("pg_catalog", "pg_index", 2610),
57    PgTrigger => ("pg_catalog", "pg_trigger", 2620),
58    PgRewrite => ("pg_catalog", "pg_rewrite", 2618),
59    PgRules => ("pg_catalog", "pg_rules", 12023),
60    PgTables => ("pg_catalog", "pg_tables", 12033),
61    PgViews => ("pg_catalog", "pg_views", 12028),
62    PgIndexes => ("pg_catalog", "pg_indexes", 12043),
63    PgType => ("pg_catalog", "pg_type", 1247),
64    PgRange => ("pg_catalog", "pg_range", 3541),
65    PgEnum => ("pg_catalog", "pg_enum", 3501),
66    PgProc => ("pg_catalog", "pg_proc", 1255),
67    PgLanguage => ("pg_catalog", "pg_language", 2612),
68    PgForeignDataWrapper => ("pg_catalog", "pg_foreign_data_wrapper", 2328),
69    PgForeignServer => ("pg_catalog", "pg_foreign_server", 1417),
70    PgForeignTable => ("pg_catalog", "pg_foreign_table", 3118),
71    PgDatabase => ("pg_catalog", "pg_database", 1262),
72    PgAuthid => ("pg_catalog", "pg_authid", 1260),
73    PgAuthMembers => ("pg_catalog", "pg_auth_members", 1261),
74    PgRoles => ("pg_catalog", "pg_roles", 12000),
75    PgUser => ("pg_catalog", "pg_user", 12014),
76    PgSettings => ("pg_catalog", "pg_settings", 12104),
77    PgPreparedStatements => ("pg_catalog", "pg_prepared_statements", 12095),
78    PgCursors => ("pg_catalog", "pg_cursors", 12077),
79    PgDescription => ("pg_catalog", "pg_description", 2609),
80    PgDepend => ("pg_catalog", "pg_depend", 2608),
81    PgShdepend => ("pg_catalog", "pg_shdepend", 1214),
82    PgMatviews => ("pg_catalog", "pg_matviews", 12038),
83    PgSequences => ("pg_catalog", "pg_sequences", 12048),
84    AgGraph => ("ag_catalog", "ag_graph", super::oids::relation_oid("relation", "ag_catalog", "ag_graph")),
85    AgLabel => ("ag_catalog", "ag_label", super::oids::relation_oid("relation", "ag_catalog", "ag_label")),
86}
87
88impl VirtualRelation {
89    pub fn qualified_name(self) -> String {
90        format!("{}.{}", self.namespace(), self.name())
91    }
92
93    pub fn from_qualified_name(name: &str) -> Option<Self> {
94        let (schema, local) = uqa_core::RelationIdentity::parse_reference(name).ok()?;
95        Self::at(schema.as_deref()?, &local)
96    }
97
98    pub const fn kind(self) -> &'static str {
99        if self.accepts_row_lock() {
100            "table"
101        } else {
102            "view"
103        }
104    }
105}
106
107/// Resolve SQL spelling among virtual definitions. Catalog-aware consumers must also stop at earlier physical relations in the effective namespace.
108pub fn resolve_virtual_relation(search_path: &[String], name: &str) -> Option<VirtualRelation> {
109    let names = crate::parse_regobject_name(name)?;
110    match names.as_slice() {
111        [schema, name] => VirtualRelation::at(schema, name),
112        [name] => {
113            if !search_path.iter().any(|schema| schema == "pg_catalog") {
114                if let Some(relation) = VirtualRelation::at("pg_catalog", name) {
115                    return Some(relation);
116                }
117            }
118            search_path
119                .iter()
120                .find_map(|schema| VirtualRelation::at(schema, name))
121        }
122        _ => None,
123    }
124}