uqa_sql/catalog/
relation_oids.rs1use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum RelationOidKind {
14 Table,
16 View,
18 ForeignTable,
20 Sequence,
22 CompositeType,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
28#[serde(deny_unknown_fields)]
29pub struct RelationCatalogOids {
30 pub relation: u32,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub row_type: Option<u32>,
33 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub array_type: Option<u32>,
35 #[serde(default, skip_serializing_if = "Option::is_none")]
36 pub rule: Option<u32>,
37}
38
39impl RelationCatalogOids {
40 #[must_use]
42 pub fn row_type_reference(
43 &self,
44 relation: &uqa_core::RelationIdentity,
45 ) -> Option<crate::ast::CompositeTypeReference> {
46 Some(crate::ast::CompositeTypeReference {
47 schema: relation.schema.clone(),
48 name: relation.name.clone(),
49 oid: self.row_type?,
50 array_oid: self.array_type.unwrap_or(0),
51 relation_oid: self.relation,
52 })
53 }
54
55 #[must_use]
57 pub fn legacy(kind: RelationOidKind, object_id: &[u8; 16]) -> Self {
58 let derive = |label| {
59 u32::try_from(super::oids::stable_object_oid(label, object_id))
60 .expect("derived catalog OIDs fit in u32")
61 };
62 Self {
63 relation: derive("relation"),
64 row_type: (kind != RelationOidKind::Sequence).then(|| derive("rowtype")),
65 array_type: None,
66 rule: (kind == RelationOidKind::View).then(|| derive("view-rule")),
67 }
68 }
69
70 #[must_use]
72 pub fn reltype(&self) -> u32 {
73 self.row_type.unwrap_or(0)
74 }
75
76 pub fn claimed(&self) -> impl Iterator<Item = u32> {
78 [
79 Some(self.relation),
80 self.row_type,
81 self.array_type,
82 self.rule,
83 ]
84 .into_iter()
85 .flatten()
86 }
87
88 #[must_use]
90 pub fn is_valid_for(&self, kind: RelationOidKind, object_id: &[u8; 16]) -> bool {
91 let user = |oid: u32| oid >= super::oids::FIRST_NORMAL_OBJECT_ID;
92 let has_row_type = kind != RelationOidKind::Sequence;
93 if self.row_type.is_some() != has_row_type
94 || self.array_type.is_some() != has_row_type
95 || self.rule.is_some() != (kind == RelationOidKind::View)
96 || !self.array_type.is_none_or(user)
97 {
98 return false;
99 }
100 if self.claimed().all(user) {
101 return true;
102 }
103 let legacy = Self::legacy(kind, object_id);
104 self.relation == legacy.relation
105 && self.row_type == legacy.row_type
106 && self.rule == legacy.rule
107 }
108}
109
110#[cfg(test)]
111mod tests;