1use std::cmp::Ordering;
4use std::sync::Arc;
5
6use rupg_common::{Error, Result};
7
8use super::{
9 Catalog, Column, ConKind, DepKind, FIRST_NORMAL_OID, ObjRef, PG_AMOP, PG_AMPROC, PG_ATTRDEF,
10 PG_CAST, PG_CLASS, PG_CONSTRAINT, PG_DEFAULT_ACL, PG_NAMESPACE, PG_OPCLASS, PG_OPERATOR,
11 PG_OPFAMILY, PG_PROC, PG_REWRITE, PG_STATISTIC_EXT, PG_TRIGGER, PG_TS_CONFIG, PG_TS_DICT,
12 PG_TS_PARSER, PG_TS_TEMPLATE, PG_TYPE, is_pinned,
13};
14
15pub mod flag {
17 pub const ORIGINAL: u32 = 0x0001;
19 pub const NORMAL: u32 = 0x0002;
21 pub const AUTO: u32 = 0x0004;
23 pub const INTERNAL: u32 = 0x0008;
25 pub const EXTENSION: u32 = 0x0010;
27 pub const PARTITION: u32 = 0x0020;
29 pub const REVERSE: u32 = 0x0040;
31 pub const IS_PART: u32 = 0x0080;
33 pub const SUBOBJECT: u32 = 0x0100;
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub struct Target {
40 pub object: ObjRef,
42 pub flags: u32,
44 pub dependee: Option<ObjRef>,
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum Refusal {
51 Pinned(ObjRef),
53 Owned {
55 object: ObjRef,
57 owner: ObjRef,
59 },
60}
61
62struct Frame {
64 object: ObjRef,
65 flags: u32,
66}
67
68fn compare(a: ObjRef, b: ObjRef) -> Ordering {
70 b.oid
71 .cmp(&a.oid)
72 .then(a.class.cmp(&b.class))
73 .then(a.sub.cast_unsigned().cmp(&b.sub.cast_unsigned()))
74}
75
76fn covers(object: ObjRef, found: ObjRef) -> bool {
78 found.class == object.class
79 && found.oid == object.oid
80 && (object.sub == 0 || found.sub == object.sub)
81}
82
83fn is_self(object: ObjRef, other: ObjRef) -> bool {
85 object.sub == 0 && other.class == object.class && other.oid == object.oid
86}
87
88fn present_add<'a>(
90 object: ObjRef,
91 flags: u32,
92 entries: impl DoubleEndedIterator<Item = (ObjRef, &'a mut u32)>,
93) -> bool {
94 let mut result = false;
95 for (found, found_flags) in entries.rev() {
96 if found.class != object.class || found.oid != object.oid {
97 continue;
98 }
99 if found.sub == object.sub {
100 *found_flags |= flags;
101 result = true;
102 } else if found.sub == 0 {
103 result = true;
104 } else if object.sub == 0 && flags != 0 {
105 *found_flags |= flags | flag::SUBOBJECT;
106 }
107 }
108 result
109}
110
111fn present(object: ObjRef, objects: &[ObjRef]) -> bool {
113 objects.iter().any(|o| {
114 o.class == object.class && o.oid == object.oid && (o.sub == object.sub || o.sub == 0)
115 })
116}
117
118impl Catalog {
119 pub fn deletions(&self, objects: &[ObjRef]) -> std::result::Result<Vec<Target>, Refusal> {
125 let mut targets = Vec::new();
126 for &object in objects {
127 self.find_dependents(object, flag::ORIGINAL, &mut Vec::new(), &mut targets, objects)?;
128 }
129 Ok(targets)
130 }
131
132 fn find_dependents(
134 &self,
135 object: ObjRef,
136 mut flags: u32,
137 stack: &mut Vec<Frame>,
138 targets: &mut Vec<Target>,
139 pending: &[ObjRef],
140 ) -> std::result::Result<(), Refusal> {
141 if present_add(object, flags, stack.iter_mut().map(|f| (f.object, &mut f.flags))) {
142 return Ok(());
143 }
144 if present_add(object, flags, targets.iter_mut().map(|t| (t.object, &mut t.flags))) {
145 return Ok(());
146 }
147 if is_pinned(object) {
148 return Err(Refusal::Pinned(object));
149 }
150 let mut owners = Vec::new();
151 let mut partition = None;
152 for d in self.depends.iter().filter(|d| covers(object, d.object)) {
153 if is_self(object, d.referenced) {
154 continue;
155 }
156 match d.kind {
157 DepKind::Internal | DepKind::Extension => owners.push(d.referenced),
158 DepKind::PartitionPri => {
159 flags |= flag::IS_PART;
160 partition = Some(d.referenced);
161 }
162 DepKind::PartitionSec => {
163 if flags & flag::IS_PART == 0 {
164 partition = Some(d.referenced);
165 }
166 flags |= flag::IS_PART;
167 }
168 DepKind::Normal | DepKind::Auto => {}
169 }
170 }
171 let mut owner = None;
172 for other in owners {
173 if stack.is_empty() {
174 if present(other, pending) {
175 return Ok(());
176 }
177 owner.get_or_insert(other);
178 continue;
179 }
180 if present_add(other, 0, stack.iter_mut().map(|f| (f.object, &mut f.flags))) {
181 continue;
182 }
183 self.find_dependents(other, flag::REVERSE, stack, targets, pending)?;
184 present_add(object, flags, targets.iter_mut().map(|t| (t.object, &mut t.flags)));
185 return Ok(());
186 }
187 if let Some(owner) = owner {
188 return Err(Refusal::Owned { object, owner: partition.unwrap_or(owner) });
189 }
190 let mut dependents: Vec<(ObjRef, u32)> = self
191 .depends
192 .iter()
193 .filter(|d| covers(object, d.referenced) && !is_self(object, d.object))
194 .map(|d| {
195 let flags = match d.kind {
196 DepKind::Normal => flag::NORMAL,
197 DepKind::Auto => flag::AUTO,
198 DepKind::Internal => flag::INTERNAL,
199 DepKind::Extension => flag::EXTENSION,
200 DepKind::PartitionPri | DepKind::PartitionSec => flag::PARTITION,
201 };
202 (d.object, flags)
203 })
204 .collect();
205 dependents.sort_by(|a, b| compare(a.0, b.0));
206 stack.push(Frame { object, flags });
207 for (dependent, flags) in dependents {
208 self.find_dependents(dependent, flags, stack, targets, pending)?;
209 }
210 let frame = stack.pop().unwrap_or(Frame { object, flags });
211 let dependee = if frame.flags & flag::IS_PART != 0 {
212 partition
213 } else {
214 stack.last().map(|f| f.object)
215 };
216 targets.push(Target { object, flags: frame.flags, dependee });
217 Ok(())
218 }
219
220 pub fn remove(&mut self, targets: &[Target]) -> Result<()> {
226 for target in targets {
227 let object = target.object;
228 self.remove_one(object)?;
229 self.depends.retain(|d| !covers(object, d.object));
230 if self.descriptions.keys().any(|found| covers(object, *found)) {
231 Arc::make_mut(&mut self.descriptions).retain(|found, _| !covers(object, *found));
232 }
233 if self.acls.keys().any(|found| covers(object, *found)) {
234 Arc::make_mut(&mut self.acls).retain(|found, _| !covers(object, *found));
235 }
236 }
237 Ok(())
238 }
239
240 fn remove_one(&mut self, object: ObjRef) -> Result<()> {
242 match object.class {
243 PG_CLASS if object.sub != 0 => {
245 if let Ok(number) = i16::try_from(object.sub)
246 && let Ok(column) = self.column_mut(object.oid, number)
247 {
248 *column = Column {
249 name: format!("........pg.dropped.{}........", object.sub),
250 ty: 0,
251 typmod: -1,
252 ndims: 0,
253 collation: 0,
254 not_null: false,
255 not_null_invalid: false,
256 has_default: false,
257 identity: 0,
258 generated: 0,
259 dropped: true,
260 stat_target: None,
261 storage: column.storage,
262 compression: column.compression,
263 options: Vec::new(),
264 local: column.local,
265 inhcount: column.inhcount,
266 };
267 }
268 }
269 PG_CLASS => {
270 self.relations.remove(&object.oid);
271 }
272 PG_TYPE => {
273 self.types.remove(&object.oid);
274 }
275 PG_ATTRDEF => {
276 if let Some(default) = self.defaults.remove(&object.oid)
277 && let Ok(column) = self.column_mut(default.relation, default.column)
278 {
279 column.has_default = false;
280 }
281 }
282 PG_CONSTRAINT => {
283 if let Some(con) = self.constraints.remove(&object.oid)
285 && con.kind == ConKind::NotNull
286 && let [number] = con.keys[..]
287 && let Ok(column) = self.column_mut(con.relation, number)
288 {
289 column.not_null = false;
290 column.not_null_invalid = false;
291 }
292 }
293 PG_NAMESPACE => {
294 if self.schemas.remove(&object.oid).is_none() && object.oid < FIRST_NORMAL_OID {
295 self.dropped_builtins.insert(object);
296 }
297 }
298 PG_PROC => {
299 self.functions.remove(&object.oid);
300 self.aggregates.remove(&object.oid);
301 }
302 PG_TRIGGER => {
303 self.triggers.remove(&object.oid);
304 }
305 PG_CAST => {
306 self.casts.remove(&object.oid);
307 }
308 PG_OPERATOR => self.remove_operator(object.oid),
309 PG_OPFAMILY => {
310 self.opfamilies.remove(&object.oid);
311 }
312 PG_OPCLASS => {
313 self.opclasses.remove(&object.oid);
314 }
315 PG_AMOP => {
316 self.amops.remove(&object.oid);
317 }
318 PG_AMPROC => {
319 self.amprocs.remove(&object.oid);
320 }
321 PG_TS_TEMPLATE => {
322 self.ts_templates.remove(&object.oid);
323 }
324 PG_TS_PARSER => {
325 self.ts_parsers.remove(&object.oid);
326 }
327 PG_TS_DICT => {
328 self.ts_dictionaries.remove(&object.oid);
329 }
330 PG_TS_CONFIG => {
331 self.ts_configs.remove(&object.oid);
332 self.ts_mappings.retain(|m| m.config != object.oid);
333 }
334 PG_REWRITE => {
335 self.rules.remove(&object.oid);
336 }
337 PG_STATISTIC_EXT => {
338 self.stat_exts.remove(&object.oid);
339 }
340 PG_DEFAULT_ACL => self.remove_default_acl(object.oid),
341 class => {
342 return Err(Error::internal(format!("unsupported object class: {class}")));
343 }
344 }
345 Ok(())
346 }
347
348 pub fn view_of_rule(&self, rule: u32) -> Option<&super::Relation> {
350 self.relations.values().find(|r| r.view.as_ref().is_some_and(|v| v.rule == rule))
351 }
352}