1use super::{
10 security::{table_binding::BoundTableAclEntry, BoundTableSecurity, TablePrivileges},
11 VirtualRelation,
12};
13mod columns;
14
15macro_rules! system_relations {
16 ($($variant:ident => ($schema:literal, $name:literal, $oid:literal, $kind:literal)),* $(,)?) => {
17 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
19 pub enum SystemRelation {
20 Projected(VirtualRelation),
21 $($variant),*
22 }
23
24 impl SystemRelation {
25 pub fn all() -> impl Iterator<Item = Self> {
26 VirtualRelation::ALL.iter().copied().map(Self::Projected)
27 .chain([$(Self::$variant),*])
28 }
29
30 pub const fn namespace(self) -> &'static str {
31 match self {
32 Self::Projected(relation) => relation.namespace(),
33 $(Self::$variant => $schema),*
34 }
35 }
36
37 pub const fn name(self) -> &'static str {
38 match self {
39 Self::Projected(relation) => relation.name(),
40 $(Self::$variant => $name),*
41 }
42 }
43
44 pub fn oid(self) -> i64 {
45 match self {
46 Self::Projected(relation) => relation.oid(),
47 $(Self::$variant => $oid),*
48 }
49 }
50
51 pub const fn kind(self) -> &'static str {
52 match self {
53 Self::Projected(relation) => relation.kind(),
54 $(Self::$variant => $kind),*
55 }
56 }
57
58 pub fn at(schema: &str, name: &str) -> Option<Self> {
59 VirtualRelation::at(schema, name).map(Self::Projected).or_else(|| {
60 match (schema, name) {
61 $(($schema, $name) => Some(Self::$variant),)*
62 _ => None,
63 }
64 })
65 }
66 }
67 };
68}
69
70system_relations! {
71 PgDbRoleSetting => ("pg_catalog", "pg_db_role_setting", 2964, "table"),
72 PgShadow => ("pg_catalog", "pg_shadow", 12005, "view"),
73 PgTablespace => ("pg_catalog", "pg_tablespace", 1213, "table"),
74 PgCollation => ("pg_catalog", "pg_collation", 3456, "table"),
75 PgSequence => ("pg_catalog", "pg_sequence", 2224, "table"),
76 InformationEnabledRoles => ("information_schema", "enabled_roles", 13410, "view"),
77}
78
79impl SystemRelation {
80 pub const fn tracks_serializable_reads(self) -> bool {
82 matches!(
83 self,
84 Self::Projected(VirtualRelation::AgGraph | VirtualRelation::AgLabel)
85 )
86 }
87
88 pub fn qualified_name(self) -> String {
89 format!("{}.{}", self.namespace(), self.name())
90 }
91
92 pub fn from_qualified_name(name: &str) -> Option<Self> {
93 let (schema, local) = uqa_core::RelationIdentity::parse_reference(name).ok()?;
94 Self::at(schema.as_deref()?, &local)
95 }
96
97 pub fn object_id(self) -> [u8; 16] {
99 let mut identity = [0; 16];
100 identity[..8].copy_from_slice(b"UQA:cat:");
101 identity[8..].copy_from_slice(&self.oid().to_be_bytes());
102 identity
103 }
104
105 pub fn bootstrap_security(self) -> BoundTableSecurity {
106 let mut security = BoundTableSecurity::owner(super::roles::RoleIdentity::BOOTSTRAP);
107 let mut acl = vec![BoundTableAclEntry {
108 role: Some(security.role_owner),
109 grantor: security.role_owner,
110 privileges: TablePrivileges::ALL,
111 grant_options: TablePrivileges::default(),
112 }];
113 if !matches!(
114 self,
115 Self::PgShadow
116 | Self::Projected(
117 VirtualRelation::PgAuthid | VirtualRelation::AgGraph | VirtualRelation::AgLabel
118 )
119 ) {
120 acl.push(BoundTableAclEntry {
121 role: None,
122 grantor: security.role_owner,
123 privileges: TablePrivileges {
124 select: true,
125 update: self == Self::Projected(VirtualRelation::PgSettings),
126 ..TablePrivileges::default()
127 },
128 grant_options: TablePrivileges::default(),
129 });
130 }
131 security.acl = Some(acl);
132 security
133 }
134
135 pub const fn view_sources(self) -> &'static [Self] {
137 use SystemRelation::Projected as P;
138 use VirtualRelation::{
139 InformationColumnPrivileges, PgAttrdef, PgAttribute, PgClass, PgConstraint, PgIndex,
140 PgLanguage, PgNamespace, PgProc, PgRewrite, PgTrigger, PgType,
141 };
142 match self {
143 P(VirtualRelation::InformationSchemata) => {
144 &[P(PgNamespace), Self::Projected(VirtualRelation::PgAuthid)]
145 }
146 P(VirtualRelation::InformationTables) => {
147 &[P(PgNamespace), P(PgClass), P(PgType), P(PgNamespace)]
148 }
149 P(VirtualRelation::InformationColumns) => &[
150 P(PgAttribute),
151 P(PgAttrdef),
152 P(PgClass),
153 P(PgNamespace),
154 P(PgType),
155 P(PgNamespace),
156 P(PgType),
157 P(PgNamespace),
158 Self::PgCollation,
159 P(PgNamespace),
160 P(VirtualRelation::PgDepend),
161 Self::PgSequence,
162 ],
163 P(InformationColumnPrivileges) => &[
164 P(PgNamespace),
165 Self::Projected(VirtualRelation::PgAuthid),
166 P(PgAttribute),
167 P(PgClass),
168 P(PgClass),
169 P(PgAttribute),
170 P(PgClass),
171 Self::Projected(VirtualRelation::PgAuthid),
172 ],
173 P(VirtualRelation::InformationRoleColumnGrants) => &[
174 P(InformationColumnPrivileges),
175 Self::InformationEnabledRoles,
176 Self::InformationEnabledRoles,
177 ],
178 P(VirtualRelation::InformationViews) => &[
179 P(PgNamespace),
180 P(PgClass),
181 P(PgTrigger),
182 P(PgTrigger),
183 P(PgTrigger),
184 ],
185 P(VirtualRelation::InformationRoutines) => &[
186 P(PgNamespace),
187 P(PgProc),
188 P(PgLanguage),
189 P(PgType),
190 P(PgNamespace),
191 ],
192 P(VirtualRelation::InformationSequences) => &[
193 P(PgNamespace),
194 P(PgClass),
195 Self::PgSequence,
196 P(VirtualRelation::PgDepend),
197 ],
198 P(VirtualRelation::InformationTableConstraints) => &[
199 P(PgNamespace),
200 P(PgNamespace),
201 P(PgConstraint),
202 P(PgClass),
203 P(PgIndex),
204 ],
205 P(VirtualRelation::InformationKeyColumnUsage) => &[
206 P(PgAttribute),
207 P(PgNamespace),
208 P(PgClass),
209 P(PgNamespace),
210 P(PgConstraint),
211 ],
212 P(VirtualRelation::PgRules) => &[P(PgRewrite), P(PgClass), P(PgNamespace)],
213 P(VirtualRelation::PgTables | VirtualRelation::PgMatviews) => {
214 &[P(PgClass), P(PgNamespace), Self::PgTablespace]
215 }
216 P(VirtualRelation::PgViews) => &[P(PgClass), P(PgNamespace)],
217 P(VirtualRelation::PgIndexes) => &[
218 P(PgIndex),
219 P(PgClass),
220 P(PgClass),
221 P(PgNamespace),
222 Self::PgTablespace,
223 ],
224 P(VirtualRelation::PgRoles) | Self::PgShadow => &[
225 Self::Projected(VirtualRelation::PgAuthid),
226 Self::PgDbRoleSetting,
227 ],
228 P(VirtualRelation::PgUser) => &[Self::PgShadow],
229 P(VirtualRelation::PgSequences) => &[Self::PgSequence, P(PgClass), P(PgNamespace)],
230 Self::InformationEnabledRoles => &[Self::Projected(VirtualRelation::PgAuthid)],
231 _ => &[],
232 }
233 }
234}
235
236#[cfg(test)]
237mod tests;