uqa_sql/catalog/events/
definition.rs1mod context;
10mod rules;
11mod triggers;
12use crate::{
13 catalog::resolution::{RelationLookupMode, RelationResolution},
14 SQLError,
15};
16pub use context::{EventAnalysisContext, EventForeignPrivileges, EventRelationCatalog};
17use uqa_core::RelationIdentity;
18
19impl EventAnalysisContext<'_> {
20 pub fn event_relation_from_resolution(
21 requested: &str,
22 resolution: RelationResolution,
23 ) -> Result<(RelationIdentity, &'static str), SQLError> {
24 let (canonical, kind) = match resolution {
25 RelationResolution::Found(canonical, kind)
26 if matches!(kind, "table" | "view" | "materialized view") =>
27 {
28 (canonical, kind)
29 }
30 RelationResolution::Found(canonical, kind @ ("index" | "composite type")) => {
32 return Err(crate::catalog::analysis::UnopenableRelation {
33 name: RelationIdentity::from_legacy_name(&canonical)
34 .map_or(canonical, |relation| relation.name),
35 kinds: if kind == "index" {
36 "indexes"
37 } else {
38 "composite types"
39 },
40 }
41 .error());
42 }
43 RelationResolution::Found(_, _) | RelationResolution::MissingRelation => {
44 return Err(SQLError::UnknownTable(requested.to_string()));
45 }
46 RelationResolution::MissingSchema(schema) => {
47 return Err(SQLError::Routine {
48 sqlstate: "3F000".into(),
49 message: format!("schema \"{schema}\" does not exist"),
50 });
51 }
52 };
53 let relation = RelationIdentity::from_legacy_name(&canonical).map_err(|error| {
54 SQLError::Internal(format!(
55 "decode resolved event relation `{canonical}`: {error}"
56 ))
57 })?;
58 Ok((relation, kind))
59 }
60
61 pub fn resolve_event_relation_kind(
62 &self,
63 name: &str,
64 lookup_mode: RelationLookupMode,
65 ) -> Result<(RelationIdentity, &'static str), SQLError> {
66 let resolution = match lookup_mode {
67 RelationLookupMode::Dynamic => self.relations.resolve_visible_relation_kind(name)?,
68 RelationLookupMode::Bound => self.relations.resolve_bound_relation_kind(name)?,
69 };
70 Self::event_relation_from_resolution(name, resolution)
71 }
72}
73
74impl EventAnalysisContext<'_> {
75 pub fn ensure_event_relation_owner(
76 &self,
77 relation: &RelationIdentity,
78 error_kind: Option<&str>,
79 ) -> Result<(), SQLError> {
80 let (owner, relation_kind) = self.catalog.event_relation_owner(relation)?;
81 if self
82 .authority
83 .current_user_has_role_identity_privileges(owner)
84 {
85 return Ok(());
86 }
87 Err(SQLError::Routine {
88 sqlstate: "42501".into(),
89 message: format!(
90 "must be owner of {} {}",
91 error_kind.unwrap_or(relation_kind),
92 relation.name
93 ),
94 })
95 }
96}
97
98#[cfg(test)]
99mod tests;
100
101pub fn duplicate_object(kind: &str, name: &str, table: &str) -> SQLError {
102 SQLError::Routine {
103 sqlstate: "42710".into(),
104 message: format!("{kind} \"{name}\" for relation \"{table}\" already exists"),
105 }
106}
107
108pub fn undefined_object(kind: &str, name: &str, table: &str) -> SQLError {
109 SQLError::Routine {
110 sqlstate: "42704".into(),
111 message: format!("{kind} \"{name}\" for table \"{table}\" does not exist"),
112 }
113}
114
115pub fn undefined_rule(name: &str, relation: &str) -> SQLError {
116 SQLError::Routine {
117 sqlstate: "42704".into(),
118 message: format!("rule \"{name}\" for relation \"{relation}\" does not exist"),
119 }
120}
121
122pub mod lookup;
123
124pub mod dependents;
125pub mod rewrites;