uqa_sql/catalog/dependencies/
shared.rs1use super::ObjectAddress;
10use std::cmp::Ordering;
11use std::fmt::Write as _;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum SharedDependencyKind {
16 Owner,
18 Acl,
20 InitialAcl,
22 Policy,
24 Tablespace,
26}
27
28impl SharedDependencyKind {
29 #[must_use]
31 pub const fn code(self) -> char {
32 match self {
33 Self::Owner => 'o',
34 Self::Acl => 'a',
35 Self::InitialAcl => 'i',
36 Self::Policy => 'r',
37 Self::Tablespace => 't',
38 }
39 }
40
41 fn describe(self, object: &str) -> String {
42 match self {
43 Self::Owner => format!("owner of {object}"),
44 Self::Acl => format!("privileges for {object}"),
45 Self::InitialAcl => format!("initial privileges for {object}"),
46 Self::Policy => format!("target of {object}"),
47 Self::Tablespace => format!("tablespace for {object}"),
48 }
49 }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54pub struct SharedDependency {
55 pub database: u32,
57 pub dependent: ObjectAddress,
58 pub referenced: ObjectAddress,
59 pub kind: SharedDependencyKind,
60}
61
62const MAX_REPORTED_DEPENDENTS: usize = 100;
64
65pub fn shared_dependency_detail<'a>(
67 dependencies: impl IntoIterator<Item = &'a SharedDependency>,
68 referenced: ObjectAddress,
69 describe: super::Describe<'_>,
70) -> Result<Option<String>, crate::SQLError> {
71 let mut dependents = dependencies
72 .into_iter()
73 .filter(|dependency| dependency.referenced == referenced)
74 .map(|dependency| (dependency.dependent, dependency.kind))
75 .collect::<Vec<_>>();
76 dependents.sort_by(|(left, left_kind), (right, right_kind)| {
77 shared_dependency_order(left, right).then(left_kind.code().cmp(&right_kind.code()))
78 });
79 let mut lines = Vec::new();
80 let mut unreported = 0_usize;
81 for (index, (object, kind)) in dependents.into_iter().enumerate() {
82 if index >= MAX_REPORTED_DEPENDENTS {
83 unreported += 1;
84 continue;
85 }
86 if let Some(description) = describe(object)? {
88 lines.push(kind.describe(&description));
89 }
90 }
91 if lines.is_empty() {
92 return Ok(None);
93 }
94 let mut detail = lines.join("\n");
95 if unreported > 0 {
96 write!(
97 detail,
98 "\nand {unreported} other object{} (see server log for list)",
99 if unreported == 1 { "" } else { "s" }
100 )
101 .expect("writing to a String cannot fail");
102 }
103 Ok(Some(detail))
104}
105
106fn shared_dependency_order(left: &ObjectAddress, right: &ObjectAddress) -> Ordering {
108 left.object_id
109 .cmp(&right.object_id)
110 .then(left.class_id.cmp(&right.class_id))
111 .then(
112 left.sub_id
113 .cast_unsigned()
114 .cmp(&right.sub_id.cast_unsigned()),
115 )
116}
117
118#[cfg(test)]
119mod tests;