1use crate::analysis::facts::{SearchPathTarget, TableConstraintFact};
3use crate::analysis::graph::{
4 DependencyGraph, FkEdge, IndexEdge, PartitionEdge, RenameEdge, SequenceEdge, ViewEdge,
5};
6use crate::analysis::mutations::{
7 AlterTableActionMutation, AlterTypeActionMutation, Mutation, PersistenceMutation,
8};
9use crate::analysis::transaction::{StateChange, TransactionFrame};
10use crate::ast::identifiers::ObjectId;
11use crate::db::cache::DbCache;
12use crate::model::relation::{
13 ColumnAction, Persistence, RelationKind, RelationOverlay, RelationState,
14};
15use crate::model::sequence::{SequenceOverlay, SequenceState};
16use crate::model::types::{TypeKind, TypeOverlay, TypeState};
17use std::collections::{HashMap, HashSet};
18
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum Confidence {
21 Exact,
22 Tainted,
23}
24
25#[derive(Debug, PartialEq, Eq)]
26pub enum MutationResult {
27 Applied,
28 Skipped,
29}
30
31#[derive(Debug, Default, Clone)]
32pub struct CascadeResult {
33 pub dropped_relations: HashSet<ObjectId>,
34 pub dropped_indexes: HashSet<ObjectId>,
35 pub dropped_constraints: HashSet<(ObjectId, String)>,
36}
37
38pub struct LocalState {
39 pub relations: HashMap<ObjectId, RelationOverlay>,
40 pub types: HashMap<ObjectId, TypeOverlay>,
41 pub sequences: HashMap<ObjectId, SequenceOverlay>,
42 pub graph: DependencyGraph,
43 pub search_path: Vec<String>,
44 pub confidence: Confidence,
45 pub transactions: Vec<TransactionFrame>,
46 pub pending_validation: HashSet<(ObjectId, String)>,
47 pub generation_counter: u64,
48}
49
50pub struct AnalysisState {
51 pub pg_version_num: Option<u32>,
52 pub baseline_relations: HashSet<ObjectId>,
53 pub baseline_foreign_keys: HashSet<(ObjectId, String)>,
54 pub local: LocalState,
55}
56
57impl AnalysisState {
58 pub fn new(cache: DbCache) -> Self {
59 let mut relations: HashMap<ObjectId, RelationOverlay> = HashMap::new();
60 let mut baseline_relations = HashSet::new();
61 let mut baseline_foreign_keys = HashSet::new();
62 let mut graph = DependencyGraph::new();
63
64 for (id, rel_state) in cache.baseline_relations() {
65 relations.insert(id.clone(), RelationOverlay::Present(rel_state.clone()));
66 baseline_relations.insert(id.clone());
67 }
68
69 for fk in cache.foreign_keys {
70 baseline_foreign_keys.insert((fk.from_table.clone(), fk.constraint_name.clone()));
71 graph.foreign_keys.push(FkEdge {
72 constraint_name: Some(fk.constraint_name),
73 from_table: fk.from_table,
74 from_columns: Vec::new(),
75 to_table: fk.to_table,
76 to_columns: Vec::new(),
77 from_generation: 0,
78 });
79 }
80
81 for idx in cache.indexes {
82 baseline_relations.insert(idx.index_id.clone());
83 graph.indexes.push(IndexEdge {
84 index_id: idx.index_id,
85 relation_id: idx.table_id,
86 using_method: None,
87 has_predicate: false,
88 is_concurrent: false,
89 });
90 }
91
92 Self {
93 pg_version_num: cache.pg_version_num,
94 baseline_relations,
95 baseline_foreign_keys,
96 local: LocalState {
97 relations,
98 types: HashMap::new(),
99 sequences: HashMap::new(),
100 graph,
101 search_path: vec!["public".to_string()],
102 confidence: Confidence::Exact,
103 transactions: Vec::new(),
104 pending_validation: HashSet::new(),
105 generation_counter: 0,
106 },
107 }
108 }
109
110 pub fn get_relation(&self, id: &ObjectId) -> Option<&RelationOverlay> {
111 self.local.relations.get(id)
112 }
113
114 pub fn relation_is_present(&self, id: &ObjectId) -> bool {
115 matches!(
116 self.local.relations.get(id),
117 Some(RelationOverlay::Present(_))
118 )
119 }
120
121 pub fn get_cascade_closure(&self, target_oid: &ObjectId) -> CascadeResult {
122 let mut result = CascadeResult::default();
123 let mut visited = HashSet::new();
124 self.walk_cascade(target_oid, &mut visited, &mut result);
125 result
126 }
127
128 fn walk_cascade(
129 &self,
130 current: &ObjectId,
131 visited: &mut HashSet<ObjectId>,
132 result: &mut CascadeResult,
133 ) {
134 let resolved_current = self.local.graph.resolve_rename(current).clone();
135
136 if !visited.insert(resolved_current.clone()) {
137 return;
138 }
139
140 result.dropped_relations.insert(resolved_current.clone());
141
142 for view_edge in &self.local.graph.views {
143 if view_edge
144 .depends_on
145 .iter()
146 .any(|dep| self.local.graph.resolve_rename(dep) == &resolved_current)
147 {
148 let resolved_view_id = self.local.graph.resolve_rename(&view_edge.view_id).clone();
149 if !visited.contains(&resolved_view_id) {
150 self.walk_cascade(&resolved_view_id, visited, result);
151 }
152 }
153 }
154
155 for index_edge in &self.local.graph.indexes {
156 if self.local.graph.resolve_rename(&index_edge.relation_id) == &resolved_current {
157 result.dropped_indexes.insert(
158 self.local
159 .graph
160 .resolve_rename(&index_edge.index_id)
161 .clone(),
162 );
163 }
164 }
165
166 for fk_edge in &self.local.graph.foreign_keys {
167 if self.local.graph.resolve_rename(&fk_edge.to_table) == &resolved_current
168 && let Some(cname) = &fk_edge.constraint_name
169 {
170 result.dropped_constraints.insert((
171 self.local.graph.resolve_rename(&fk_edge.from_table).clone(),
172 cname.clone(),
173 ));
174 }
175 }
176
177 for partition_edge in &self.local.graph.partitions {
178 if self.local.graph.resolve_rename(&partition_edge.parent) == &resolved_current {
179 let resolved_child = self
180 .local
181 .graph
182 .resolve_rename(&partition_edge.child)
183 .clone();
184 if !visited.contains(&resolved_child) {
185 self.walk_cascade(&resolved_child, visited, result);
186 }
187 }
188 }
189 }
190
191 pub fn apply(
192 &mut self,
193 mutation: &Mutation,
194 precomputed_cascade: Option<&CascadeResult>,
195 ) -> MutationResult {
196 match mutation {
197 Mutation::CreateSchema(_) => MutationResult::Applied,
198 Mutation::DropSchema(drop_schema) => {
199 if drop_schema.cascade {
200 let renames = self.local.graph.renames.clone();
201 let resolve = |id: &ObjectId| -> ObjectId {
202 let mut current = id;
203 loop {
204 match renames.iter().find(|r| &r.from == current) {
205 Some(edge) => current = &edge.to,
206 None => return current.clone(),
207 }
208 }
209 };
210
211 let mut relations_to_drop = Vec::new();
212 for id in self.local.relations.keys() {
213 if drop_schema.names.contains(&id.schema) {
214 relations_to_drop.push(id.clone());
215 }
216 }
217 for id in relations_to_drop {
218 self.snapshot_relation(&id);
219 self.local.relations.insert(id, RelationOverlay::Dropped);
220 }
221
222 let mut types_to_drop = Vec::new();
223 for id in self.local.types.keys() {
224 if drop_schema.names.contains(&id.schema) {
225 types_to_drop.push(id.clone());
226 }
227 }
228 for id in types_to_drop {
229 self.snapshot_type(&id);
230 self.local.types.insert(id, TypeOverlay::Dropped);
231 }
232
233 let mut seqs_to_drop = Vec::new();
234 for id in self.local.sequences.keys() {
235 if drop_schema.names.contains(&id.schema) {
236 seqs_to_drop.push(id.clone());
237 }
238 }
239 for id in seqs_to_drop {
240 self.snapshot_sequence(&id);
241 self.local.sequences.insert(id, SequenceOverlay::Dropped);
242 }
243
244 self.snapshot_fk_graph_full();
245 self.snapshot_view_graph_full();
246 self.snapshot_index_graph_full();
247 self.snapshot_partition_graph_full();
248 self.snapshot_sequence_graph_full();
249 self.snapshot_rename_graph_full();
250
251 let g = &mut self.local.graph;
252 g.foreign_keys.retain(|fk| {
253 !drop_schema.names.contains(&resolve(&fk.from_table).schema)
254 && !drop_schema.names.contains(&resolve(&fk.to_table).schema)
255 });
256 g.views
257 .retain(|v| !drop_schema.names.contains(&resolve(&v.view_id).schema));
258 g.indexes
259 .retain(|idx| !drop_schema.names.contains(&resolve(&idx.index_id).schema));
260 g.partitions.retain(|p| {
261 !drop_schema.names.contains(&resolve(&p.parent).schema)
262 && !drop_schema.names.contains(&resolve(&p.child).schema)
263 });
264 g.sequences
265 .retain(|s| !drop_schema.names.contains(&resolve(&s.sequence_id).schema));
266 g.renames.retain(|r| {
267 !drop_schema.names.contains(&resolve(&r.from).schema)
268 && !drop_schema.names.contains(&resolve(&r.to).schema)
269 });
270 }
271 MutationResult::Applied
272 }
273 Mutation::DropTable(drop_table) => {
274 if !self.relation_is_present(&drop_table.id) {
275 if drop_table.if_exists {
276 return MutationResult::Skipped;
277 } else {
278 self.local.confidence = Confidence::Tainted;
279 return MutationResult::Skipped;
280 }
281 }
282
283 let renames = self.local.graph.renames.clone();
284 let resolve = |id: &ObjectId| -> ObjectId {
285 let mut current = id;
286 loop {
287 match renames.iter().find(|r| &r.from == current) {
288 Some(edge) => current = &edge.to,
289 None => return current.clone(),
290 }
291 }
292 };
293
294 let resolved_drop = resolve(&drop_table.id);
295
296 if drop_table.cascade {
297 let local_closure;
298 let closure = match precomputed_cascade {
299 Some(c) => c,
300 None => {
301 local_closure = self.get_cascade_closure(&drop_table.id);
302 &local_closure
303 }
304 };
305
306 for dropped_rel_id in &closure.dropped_relations {
307 self.snapshot_relation(dropped_rel_id);
308 self.local
309 .relations
310 .insert(dropped_rel_id.clone(), RelationOverlay::Dropped);
311 }
312
313 self.snapshot_index_graph_full();
314 self.local
315 .graph
316 .indexes
317 .retain(|idx| !closure.dropped_indexes.contains(&resolve(&idx.index_id)));
318
319 self.snapshot_fk_graph_full();
320 self.local.graph.foreign_keys.retain(|fk| {
321 let from_dropped =
322 closure.dropped_relations.contains(&resolve(&fk.from_table));
323 let to_dropped = closure.dropped_relations.contains(&resolve(&fk.to_table));
324 let constraint_explicitly_dropped = if let Some(cname) = &fk.constraint_name
325 {
326 closure
327 .dropped_constraints
328 .contains(&(resolve(&fk.from_table), cname.clone()))
329 } else {
330 false
331 };
332 !(from_dropped || to_dropped || constraint_explicitly_dropped)
333 });
334
335 self.snapshot_view_graph_full();
336 self.local
337 .graph
338 .views
339 .retain(|v| !closure.dropped_relations.contains(&resolve(&v.view_id)));
340 } else {
341 let has_view_deps = self
342 .local
343 .graph
344 .views
345 .iter()
346 .any(|v| v.depends_on.iter().any(|dep| resolve(dep) == resolved_drop));
347 let has_fk_deps = self.local.graph.foreign_keys.iter().any(|fk| {
348 resolve(&fk.to_table) == resolved_drop
349 && resolve(&fk.from_table) != resolved_drop
350 });
351 let has_partition_deps = self
352 .local
353 .graph
354 .partitions
355 .iter()
356 .any(|p| resolve(&p.parent) == resolved_drop);
357
358 if has_view_deps || has_fk_deps || has_partition_deps {
359 self.local.confidence = Confidence::Tainted;
360 return MutationResult::Skipped;
361 }
362
363 self.snapshot_relation(&drop_table.id);
364 self.local
365 .relations
366 .insert(drop_table.id.clone(), RelationOverlay::Dropped);
367 }
368
369 self.snapshot_partition_graph_full();
370 self.local.graph.partitions.retain(|p| {
371 resolve(&p.parent) != resolved_drop && resolve(&p.child) != resolved_drop
372 });
373
374 MutationResult::Applied
375 }
376 Mutation::CreateTable(create) => {
377 if create.if_not_exists && self.relation_is_present(&create.id) {
378 return MutationResult::Skipped;
379 }
380
381 self.snapshot_relation(&create.id);
382
383 self.snapshot_generation_counter();
384 self.local.generation_counter += 1;
385 let generation = self.local.generation_counter;
386 let tx_depth = self.local.transactions.len();
387
388 let pk_columns: HashSet<&str> = create
389 .table_constraints
390 .iter()
391 .filter_map(|tc| {
392 if let TableConstraintFact::PrimaryKey { columns } = tc {
393 Some(columns.iter().map(|s| s.as_str()))
394 } else {
395 None
396 }
397 })
398 .flatten()
399 .collect();
400
401 let estimated_rows = if create.as_select { None } else { Some(0) };
402
403 let persistence = match &create.persistence {
404 PersistenceMutation::Permanent => Persistence::Permanent,
405 PersistenceMutation::Temporary => Persistence::Temporary,
406 PersistenceMutation::Unlogged => Persistence::Unlogged,
407 };
408
409 let mut rel_state = RelationState::new(
410 create.id.clone(),
411 generation,
412 estimated_rows,
413 RelationKind::Table,
414 persistence,
415 tx_depth,
416 );
417
418 for col in &create.columns {
419 let is_pk = col.is_primary_key || pk_columns.contains(col.name.as_str());
420 rel_state.apply_column_action(&ColumnAction::Add {
421 name: col.name.clone(),
422 data_type: col.ty.clone(),
423 not_null: col.not_null || is_pk,
424 default: col.default.clone(),
425 });
426 }
427
428 self.local
429 .relations
430 .insert(create.id.clone(), RelationOverlay::Present(rel_state));
431
432 if let Some(parent_id) = &create.partition_of {
433 self.snapshot_partition_graph();
434 self.local.graph.partitions.push(PartitionEdge {
435 parent: parent_id.clone(),
436 child: create.id.clone(),
437 });
438 }
439
440 if !create.foreign_keys.is_empty() {
441 self.snapshot_fk_graph();
442 }
443
444 for fk in &create.foreign_keys {
445 self.local.graph.foreign_keys.push(FkEdge {
446 constraint_name: fk.constraint_name.clone(),
447 from_table: create.id.clone(),
448 from_columns: fk.from_columns.clone(),
449 to_table: fk.to_table.clone(),
450 to_columns: fk.to_columns.clone(),
451 from_generation: generation,
452 });
453 }
454 MutationResult::Applied
455 }
456 Mutation::CreateView(create_view) => {
457 self.snapshot_relation(&create_view.id);
458 self.snapshot_view_graph();
459 self.snapshot_generation_counter();
460 self.local.generation_counter += 1;
461 let generation = self.local.generation_counter;
462 let tx_depth = self.local.transactions.len();
463
464 self.local.relations.insert(
465 create_view.id.clone(),
466 RelationOverlay::Present(RelationState::new(
467 create_view.id.clone(),
468 generation,
469 Some(0),
470 RelationKind::View,
471 Persistence::Permanent,
472 tx_depth,
473 )),
474 );
475
476 self.local.graph.views.push(ViewEdge {
477 view_id: create_view.id.clone(),
478 depends_on: create_view.depends_on.clone(),
479 view_generation: generation,
480 });
481 MutationResult::Applied
482 }
483 Mutation::CreateMaterializedView(create_mat) => {
484 self.snapshot_relation(&create_mat.id);
485 self.snapshot_view_graph();
486 self.snapshot_generation_counter();
487 self.local.generation_counter += 1;
488 let generation = self.local.generation_counter;
489 let tx_depth = self.local.transactions.len();
490
491 self.local.relations.insert(
492 create_mat.id.clone(),
493 RelationOverlay::Present(RelationState::new(
494 create_mat.id.clone(),
495 generation,
496 None,
497 RelationKind::MaterializedView,
498 Persistence::Permanent,
499 tx_depth,
500 )),
501 );
502
503 self.local.graph.views.push(ViewEdge {
504 view_id: create_mat.id.clone(),
505 depends_on: create_mat.depends_on.clone(),
506 view_generation: generation,
507 });
508 MutationResult::Applied
509 }
510 Mutation::RefreshMaterializedView(refresh) => {
511 if !self.relation_is_present(&refresh.id) {
512 self.local.confidence = Confidence::Tainted;
513 return MutationResult::Skipped;
514 }
515
516 self.snapshot_relation(&refresh.id);
517 self.snapshot_generation_counter();
518 self.local.generation_counter += 1;
519 let new_gen = self.local.generation_counter;
520
521 if let Some(RelationOverlay::Present(rel)) =
522 self.local.relations.get_mut(&refresh.id)
523 {
524 rel.generation = new_gen;
525 }
526 MutationResult::Applied
527 }
528 Mutation::CreateIndex(create_index) => {
529 if create_index.if_not_exists
530 && self
531 .local
532 .graph
533 .indexes
534 .iter()
535 .any(|idx| idx.index_id == create_index.id)
536 {
537 return MutationResult::Skipped;
538 }
539 self.snapshot_index_graph();
540 self.local.graph.indexes.push(IndexEdge {
541 index_id: create_index.id.clone(),
542 relation_id: create_index.table.clone(),
543 using_method: create_index.using_method.clone(),
544 has_predicate: create_index.has_predicate,
545 is_concurrent: create_index.concurrently,
546 });
547 MutationResult::Applied
548 }
549 Mutation::CreatePolicy(policy) => {
550 self.snapshot_relation(&policy.table);
551 self.snapshot_generation_counter();
552 self.local.generation_counter += 1;
553 let new_gen = self.local.generation_counter;
554
555 if let Some(RelationOverlay::Present(rel)) =
556 self.local.relations.get_mut(&policy.table)
557 {
558 rel.policies.insert(policy.name.clone());
559 rel.generation = new_gen;
560 }
561 MutationResult::Applied
562 }
563 Mutation::DropPolicy(policy) => {
564 if policy.if_exists {
565 let exists = self
566 .local
567 .relations
568 .get(&policy.table)
569 .map(|o| {
570 if let RelationOverlay::Present(rel) = o {
571 rel.policies.contains(&policy.name)
572 } else {
573 false
574 }
575 })
576 .unwrap_or(false);
577 if !exists {
578 return MutationResult::Skipped;
579 }
580 }
581 self.snapshot_relation(&policy.table);
582 self.snapshot_generation_counter();
583 self.local.generation_counter += 1;
584 let new_gen = self.local.generation_counter;
585
586 if let Some(RelationOverlay::Present(rel)) =
587 self.local.relations.get_mut(&policy.table)
588 {
589 rel.policies.remove(&policy.name);
590 rel.generation = new_gen;
591 }
592 MutationResult::Applied
593 }
594 Mutation::CreateTrigger(trigger) => {
595 self.snapshot_relation(&trigger.table);
596 self.snapshot_generation_counter();
597 self.local.generation_counter += 1;
598 let new_gen = self.local.generation_counter;
599
600 if let Some(RelationOverlay::Present(rel)) =
601 self.local.relations.get_mut(&trigger.table)
602 {
603 rel.triggers.insert(trigger.name.clone());
604 rel.generation = new_gen;
605 }
606 MutationResult::Applied
607 }
608 Mutation::DropTrigger(trigger) => {
609 if trigger.if_exists {
610 let exists = self
611 .local
612 .relations
613 .get(&trigger.table)
614 .map(|o| {
615 if let RelationOverlay::Present(rel) = o {
616 rel.triggers.contains(&trigger.name)
617 } else {
618 false
619 }
620 })
621 .unwrap_or(false);
622 if !exists {
623 return MutationResult::Skipped;
624 }
625 }
626 self.snapshot_relation(&trigger.table);
627 self.snapshot_generation_counter();
628 self.local.generation_counter += 1;
629 let new_gen = self.local.generation_counter;
630
631 if let Some(RelationOverlay::Present(rel)) =
632 self.local.relations.get_mut(&trigger.table)
633 {
634 rel.triggers.remove(&trigger.name);
635 rel.generation = new_gen;
636 }
637 MutationResult::Applied
638 }
639 Mutation::CreateType(create_type) => {
640 self.snapshot_type(&create_type.id);
641 self.snapshot_generation_counter();
642 self.local.generation_counter += 1;
643 let generation = self.local.generation_counter;
644
645 self.local.types.insert(
646 create_type.id.clone(),
647 TypeOverlay::Present(TypeState {
648 id: create_type.id.clone(),
649 generation,
650 kind: create_type.kind.clone(),
651 }),
652 );
653 MutationResult::Applied
654 }
655 Mutation::AlterType(alter) => {
656 self.snapshot_type(&alter.id);
657 if let Some(TypeOverlay::Present(t)) = self.local.types.get_mut(&alter.id) {
658 match &alter.action {
659 AlterTypeActionMutation::AddValue { new_value } => {
660 if let TypeKind::Enum { variants } = &mut t.kind {
661 variants.push(new_value.clone());
662 }
663 }
664 }
665 }
666 MutationResult::Applied
667 }
668 Mutation::CreateDomain(create) => {
669 self.snapshot_type(&create.id);
670 self.snapshot_generation_counter();
671 self.local.generation_counter += 1;
672 let generation = self.local.generation_counter;
673
674 self.local.types.insert(
675 create.id.clone(),
676 TypeOverlay::Present(TypeState {
677 id: create.id.clone(),
678 generation,
679 kind: TypeKind::Domain {
680 base_type: create.base_type.clone(),
681 },
682 }),
683 );
684 MutationResult::Applied
685 }
686 Mutation::AlterDomain(alter) => {
687 self.snapshot_type(&alter.id);
688 self.snapshot_generation_counter();
689 self.local.generation_counter += 1;
690 let new_gen = self.local.generation_counter;
691
692 if let Some(TypeOverlay::Present(t)) = self.local.types.get_mut(&alter.id) {
693 t.generation = new_gen;
694 }
695 MutationResult::Applied
696 }
697 Mutation::DropDomain(drop_domain) => {
698 for id in &drop_domain.ids {
699 if !self.local.types.contains_key(id) && !drop_domain.if_exists {
700 self.local.confidence = Confidence::Tainted;
701 return MutationResult::Skipped;
702 }
703 }
704 let mut any_applied = false;
705 for id in &drop_domain.ids {
706 if !self.local.types.contains_key(id) {
707 continue;
708 }
709 self.snapshot_type(id);
710 self.local.types.insert(id.clone(), TypeOverlay::Dropped);
711 any_applied = true;
712 }
713 if !any_applied && !drop_domain.ids.is_empty() {
714 return MutationResult::Skipped;
715 }
716 MutationResult::Applied
717 }
718 Mutation::CreateSequence(create) => {
719 if create.if_not_exists && self.local.sequences.contains_key(&create.id) {
720 return MutationResult::Skipped;
721 }
722 self.snapshot_sequence(&create.id);
723 self.snapshot_generation_counter();
724 self.local.generation_counter += 1;
725 let generation = self.local.generation_counter;
726
727 self.local.sequences.insert(
728 create.id.clone(),
729 SequenceOverlay::Present(SequenceState {
730 id: create.id.clone(),
731 generation,
732 }),
733 );
734
735 if let Some((table_id, col)) = &create.owned_by {
736 self.snapshot_sequence_graph();
737 self.local.graph.sequences.push(SequenceEdge {
738 sequence_id: create.id.clone(),
739 table_id: table_id.clone(),
740 column: col.clone(),
741 });
742 }
743 MutationResult::Applied
744 }
745 Mutation::AlterSequence(alter) => {
746 self.snapshot_sequence(&alter.id);
747 self.snapshot_generation_counter();
748 self.local.generation_counter += 1;
749
750 if let Some((table_id, col)) = &alter.owned_by {
751 self.snapshot_sequence_graph_full();
752 self.local
753 .graph
754 .sequences
755 .retain(|s| s.sequence_id != alter.id);
756 self.local.graph.sequences.push(SequenceEdge {
757 sequence_id: alter.id.clone(),
758 table_id: table_id.clone(),
759 column: col.clone(),
760 });
761 }
762 MutationResult::Applied
763 }
764 Mutation::DropSequence(drop_seq) => {
765 for id in &drop_seq.ids {
766 if !self.local.sequences.contains_key(id) && !drop_seq.if_exists {
767 self.local.confidence = Confidence::Tainted;
768 return MutationResult::Skipped;
769 }
770 }
771 let mut any_applied = false;
772 for id in &drop_seq.ids {
773 if !self.local.sequences.contains_key(id) {
774 continue;
775 }
776 self.snapshot_sequence(id);
777 self.local
778 .sequences
779 .insert(id.clone(), SequenceOverlay::Dropped);
780 self.snapshot_sequence_graph_full();
781 self.local.graph.sequences.retain(|s| s.sequence_id != *id);
782 any_applied = true;
783 }
784 if !any_applied && !drop_seq.ids.is_empty() {
785 return MutationResult::Skipped;
786 }
787 MutationResult::Applied
788 }
789 Mutation::AlterTable(alter) => {
790 if !self.relation_is_present(&alter.id) {
791 self.local.confidence = Confidence::Tainted;
792 return MutationResult::Skipped;
793 }
794
795 match &alter.action {
796 AlterTableActionMutation::AddColumn {
797 name,
798 if_not_exists,
799 ..
800 } if *if_not_exists => {
801 if let Some(RelationOverlay::Present(rel)) =
802 self.local.relations.get(&alter.id)
803 && rel.has_column(name)
804 {
805 return MutationResult::Skipped;
806 }
807 }
808 AlterTableActionMutation::DropColumn {
809 name, if_exists, ..
810 } if *if_exists => {
811 if let Some(RelationOverlay::Present(rel)) =
812 self.local.relations.get(&alter.id)
813 && !rel.has_column(name)
814 {
815 return MutationResult::Skipped;
816 }
817 }
818 _ => {}
819 }
820
821 self.snapshot_relation(&alter.id);
822
823 match &alter.action {
824 AlterTableActionMutation::AddColumn {
825 name,
826 ty,
827 not_null,
828 default,
829 ..
830 } => {
831 if let Some(RelationOverlay::Present(rel)) =
832 self.local.relations.get_mut(&alter.id)
833 {
834 rel.apply_column_action(&ColumnAction::Add {
835 name: name.clone(),
836 data_type: ty.clone(),
837 not_null: *not_null,
838 default: default.clone(),
839 });
840 }
841 }
842 AlterTableActionMutation::DropColumn { name, .. } => {
843 if let Some(RelationOverlay::Present(rel)) =
844 self.local.relations.get_mut(&alter.id)
845 {
846 rel.apply_column_action(&ColumnAction::Drop { name: name.clone() });
847 }
848 }
849 AlterTableActionMutation::RenameColumn { from, to } => {
850 if let Some(RelationOverlay::Present(rel)) =
851 self.local.relations.get_mut(&alter.id)
852 {
853 rel.apply_column_action(&ColumnAction::Rename {
854 from: from.clone(),
855 to: to.clone(),
856 });
857 }
858 }
859 AlterTableActionMutation::SetNotNull { column } => {
860 if let Some(RelationOverlay::Present(rel)) =
861 self.local.relations.get_mut(&alter.id)
862 {
863 rel.apply_column_action(&ColumnAction::SetNotNull {
864 name: column.clone(),
865 });
866 }
867 }
868 AlterTableActionMutation::DropNotNull { column } => {
869 if let Some(RelationOverlay::Present(rel)) =
870 self.local.relations.get_mut(&alter.id)
871 {
872 rel.apply_column_action(&ColumnAction::DropNotNull {
873 name: column.clone(),
874 });
875 }
876 }
877 AlterTableActionMutation::SetType {
878 column,
879 ty,
880 has_using: _,
881 } => {
882 if let Some(RelationOverlay::Present(rel)) =
883 self.local.relations.get_mut(&alter.id)
884 {
885 rel.apply_column_action(&ColumnAction::SetType {
886 name: column.clone(),
887 data_type: ty.clone(),
888 });
889 }
890 }
891 AlterTableActionMutation::SetDefault { column, default } => {
892 if let Some(RelationOverlay::Present(rel)) =
893 self.local.relations.get_mut(&alter.id)
894 {
895 rel.apply_column_action(&ColumnAction::SetDefault {
896 name: column.clone(),
897 default: default.clone(),
898 });
899 }
900 }
901 AlterTableActionMutation::AddForeignKey {
902 constraint_name,
903 to_table,
904 from_columns,
905 to_columns,
906 not_valid,
907 } => {
908 self.snapshot_fk_graph();
909 let from_generation = self
910 .local
911 .relations
912 .get(&alter.id)
913 .and_then(|o| {
914 if let RelationOverlay::Present(r) = o {
915 Some(r.generation)
916 } else {
917 None
918 }
919 })
920 .unwrap_or(0);
921
922 self.local.graph.foreign_keys.push(FkEdge {
923 constraint_name: constraint_name.clone(),
924 from_table: alter.id.clone(),
925 from_columns: from_columns.clone(),
926 to_table: to_table.clone(),
927 to_columns: to_columns.clone(),
928 from_generation,
929 });
930
931 if *not_valid {
932 let key = constraint_name
933 .clone()
934 .unwrap_or_else(|| format!("__fk__{}", to_table));
935 self.snapshot_pending_validation();
936 self.local
937 .pending_validation
938 .insert((alter.id.clone(), key));
939 }
940 }
941 AlterTableActionMutation::RenameConstraint { old_name, new_name } => {
942 self.snapshot_fk_graph_full();
943 for fk in &mut self.local.graph.foreign_keys {
944 if fk.from_table == alter.id
945 && fk.constraint_name.as_deref() == Some(old_name.as_str())
946 {
947 fk.constraint_name = Some(new_name.clone());
948 }
949 }
950 }
951 AlterTableActionMutation::DropConstraint { name } => {
952 self.snapshot_pending_validation();
953 self.local
954 .pending_validation
955 .remove(&(alter.id.clone(), name.clone()));
956 self.snapshot_fk_graph_full();
957 self.local
958 .graph
959 .foreign_keys
960 .retain(|fk| fk.constraint_name.as_deref() != Some(name.as_str()));
961 }
962 AlterTableActionMutation::ValidateConstraint { constraint_name } => {
963 self.snapshot_pending_validation();
964 self.local
965 .pending_validation
966 .remove(&(alter.id.clone(), constraint_name.clone()));
967 }
968 AlterTableActionMutation::AttachPartition { child } => {
969 self.snapshot_partition_graph();
970 self.local.graph.partitions.push(PartitionEdge {
971 parent: alter.id.clone(),
972 child: child.clone(),
973 });
974 }
975 AlterTableActionMutation::DetachPartition { child } => {
976 self.snapshot_partition_graph_full();
977 self.local
978 .graph
979 .partitions
980 .retain(|p| !(p.parent == alter.id && p.child == *child));
981 }
982 AlterTableActionMutation::AlterConstraint { .. }
983 | AlterTableActionMutation::AddCheckConstraint { .. }
984 | AlterTableActionMutation::AddUniqueConstraint
985 | AlterTableActionMutation::AddPrimaryKeyConstraint
986 | AlterTableActionMutation::AddExcludeConstraint
987 | AlterTableActionMutation::SetStorage { .. }
988 | AlterTableActionMutation::SetAccessMethod => {
989 }
991 }
992 MutationResult::Applied
993 }
994 Mutation::Rename(rename) => {
995 self.snapshot_relation(&rename.old_id);
996 self.snapshot_relation(&rename.new_id);
997 self.snapshot_rename_graph();
998 if let Some(overlay) = self.local.relations.remove(&rename.old_id) {
999 self.local.relations.insert(rename.new_id.clone(), overlay);
1000 }
1001
1002 self.snapshot_index_graph_full();
1003 for idx in &mut self.local.graph.indexes {
1004 if idx.index_id == rename.old_id {
1005 idx.index_id = rename.new_id.clone();
1006 }
1007 }
1008
1009 self.snapshot_sequence(&rename.old_id);
1010 self.snapshot_sequence(&rename.new_id);
1011 if let Some(overlay) = self.local.sequences.remove(&rename.old_id) {
1012 self.local.sequences.insert(rename.new_id.clone(), overlay);
1013 }
1014
1015 self.snapshot_type(&rename.old_id);
1016 self.snapshot_type(&rename.new_id);
1017 if let Some(overlay) = self.local.types.remove(&rename.old_id) {
1018 self.local.types.insert(rename.new_id.clone(), overlay);
1019 }
1020
1021 self.local.graph.renames.push(RenameEdge {
1022 from: rename.old_id.clone(),
1023 to: rename.new_id.clone(),
1024 });
1025 MutationResult::Applied
1026 }
1027 Mutation::DropView(drop_view) => {
1028 for id in &drop_view.ids {
1029 if !self.relation_is_present(id) && !drop_view.if_exists {
1030 self.local.confidence = Confidence::Tainted;
1031 return MutationResult::Skipped;
1032 }
1033 }
1034
1035 let renames = self.local.graph.renames.clone();
1036 let resolve = |id: &ObjectId| -> ObjectId {
1037 let mut current = id;
1038 loop {
1039 match renames.iter().find(|r| &r.from == current) {
1040 Some(edge) => current = &edge.to,
1041 None => return current.clone(),
1042 }
1043 }
1044 };
1045
1046 let mut any_applied = false;
1047 for id in &drop_view.ids {
1048 if !self.relation_is_present(id) {
1049 continue;
1050 }
1051
1052 let resolved_id = resolve(id);
1053 let has_dependents = self.local.graph.views.iter().any(|v| {
1054 v.depends_on.iter().any(|dep| resolve(dep) == resolved_id)
1055 && !drop_view.ids.contains(&resolve(&v.view_id))
1056 });
1057 if has_dependents {
1058 self.local.confidence = Confidence::Tainted;
1059 return MutationResult::Skipped;
1060 }
1061
1062 self.snapshot_relation(id);
1063 self.local
1064 .relations
1065 .insert(id.clone(), RelationOverlay::Dropped);
1066 self.snapshot_view_graph_full();
1067 self.local
1068 .graph
1069 .views
1070 .retain(|v| resolve(&v.view_id) != resolved_id);
1071 any_applied = true;
1072 }
1073 if !any_applied && !drop_view.ids.is_empty() {
1074 return MutationResult::Skipped;
1075 }
1076 MutationResult::Applied
1077 }
1078 Mutation::DropMaterializedView(drop_mat_view) => {
1079 for id in &drop_mat_view.ids {
1080 if !self.relation_is_present(id) && !drop_mat_view.if_exists {
1081 self.local.confidence = Confidence::Tainted;
1082 return MutationResult::Skipped;
1083 }
1084 }
1085
1086 let renames = self.local.graph.renames.clone();
1087 let resolve = |id: &ObjectId| -> ObjectId {
1088 let mut current = id;
1089 loop {
1090 match renames.iter().find(|r| &r.from == current) {
1091 Some(edge) => current = &edge.to,
1092 None => return current.clone(),
1093 }
1094 }
1095 };
1096
1097 let mut any_applied = false;
1098 for id in &drop_mat_view.ids {
1099 if !self.relation_is_present(id) {
1100 continue;
1101 }
1102
1103 let resolved_id = resolve(id);
1104 let has_dependents = self.local.graph.views.iter().any(|v| {
1105 v.depends_on.iter().any(|dep| resolve(dep) == resolved_id)
1106 && !drop_mat_view.ids.contains(&resolve(&v.view_id))
1107 });
1108 if has_dependents {
1109 self.local.confidence = Confidence::Tainted;
1110 return MutationResult::Skipped;
1111 }
1112
1113 self.snapshot_relation(id);
1114 self.local
1115 .relations
1116 .insert(id.clone(), RelationOverlay::Dropped);
1117 self.snapshot_view_graph_full();
1118 self.local
1119 .graph
1120 .views
1121 .retain(|v| resolve(&v.view_id) != resolved_id);
1122 any_applied = true;
1123 }
1124 if !any_applied && !drop_mat_view.ids.is_empty() {
1125 return MutationResult::Skipped;
1126 }
1127 MutationResult::Applied
1128 }
1129 Mutation::DropIndex(drop_index) => {
1130 let present = self
1131 .local
1132 .graph
1133 .indexes
1134 .iter()
1135 .any(|idx| idx.index_id == drop_index.id);
1136 if !present {
1137 if drop_index.if_exists {
1138 return MutationResult::Skipped;
1139 } else {
1140 self.local.confidence = Confidence::Tainted;
1141 return MutationResult::Skipped;
1142 }
1143 }
1144 self.snapshot_index_graph_full();
1145 self.local
1146 .graph
1147 .indexes
1148 .retain(|idx| idx.index_id != drop_index.id);
1149 MutationResult::Applied
1150 }
1151 Mutation::SearchPath(change) => {
1152 self.snapshot_search_path();
1153 match &change.target {
1154 SearchPathTarget::Default => {
1155 self.local.search_path = vec!["public".to_string()];
1156 }
1157 SearchPathTarget::Schemas(schemas) => {
1158 self.local.search_path = schemas.clone();
1159 }
1160 }
1161 MutationResult::Applied
1162 }
1163 Mutation::BeginTransaction => {
1164 self.local
1165 .transactions
1166 .push(TransactionFrame::new("__transaction__"));
1167 MutationResult::Applied
1168 }
1169 Mutation::CommitTransaction => {
1170 self.local.transactions.clear();
1171 MutationResult::Applied
1172 }
1173 Mutation::RollbackTransaction => {
1174 let frames: Vec<_> = self.local.transactions.drain(..).collect();
1175 for frame in frames.into_iter().rev() {
1176 self.replay_undo_log(frame);
1177 }
1178 MutationResult::Applied
1179 }
1180 Mutation::Savepoint(sp) => {
1181 self.local
1182 .transactions
1183 .push(TransactionFrame::new(sp.name.clone()));
1184 MutationResult::Applied
1185 }
1186 Mutation::ReleaseSavepoint(rsp) => {
1187 if let Some(pos) = self
1188 .local
1189 .transactions
1190 .iter()
1191 .rposition(|f| f.name == rsp.name)
1192 {
1193 let mut released_frame = self.local.transactions.remove(pos);
1194 if let Some(parent_frame) = self.local.transactions.last_mut() {
1195 parent_frame.undo_log.append(&mut released_frame.undo_log);
1196 }
1197 }
1198 MutationResult::Applied
1199 }
1200 Mutation::RollbackToSavepoint(rsp) => {
1201 if let Some(pos) = self
1202 .local
1203 .transactions
1204 .iter()
1205 .rposition(|f| f.name == rsp.name)
1206 {
1207 let frames: Vec<_> = self.local.transactions.drain(pos..).collect();
1208 for frame in frames.into_iter().rev() {
1209 self.replay_undo_log(frame);
1210 }
1211 self.local
1212 .transactions
1213 .push(TransactionFrame::new(rsp.name.clone()));
1214 }
1215 MutationResult::Applied
1216 }
1217 Mutation::Opaque(_) => {
1218 self.local.confidence = Confidence::Tainted;
1219 MutationResult::Applied
1220 }
1221 Mutation::Vacuum { .. } => MutationResult::Applied,
1222 }
1223 }
1224
1225 fn snapshot_relation(&mut self, id: &ObjectId) {
1226 if let Some(frame) = self.local.transactions.last_mut() {
1227 let previous = self.local.relations.get(id).cloned();
1228 frame.undo_log.push(StateChange::RelationSnapshot {
1229 id: id.clone(),
1230 previous,
1231 });
1232 }
1233 }
1234
1235 fn snapshot_type(&mut self, id: &ObjectId) {
1236 if let Some(frame) = self.local.transactions.last_mut() {
1237 let previous = self.local.types.get(id).cloned();
1238 frame.undo_log.push(StateChange::TypeSnapshot {
1239 id: id.clone(),
1240 previous,
1241 });
1242 }
1243 }
1244
1245 fn snapshot_sequence(&mut self, id: &ObjectId) {
1246 if let Some(frame) = self.local.transactions.last_mut() {
1247 let previous = self.local.sequences.get(id).cloned();
1248 frame.undo_log.push(StateChange::SequenceSnapshot {
1249 id: id.clone(),
1250 previous,
1251 });
1252 }
1253 }
1254
1255 fn snapshot_fk_graph(&mut self) {
1256 if let Some(frame) = self.local.transactions.last_mut() {
1257 frame.undo_log.push(StateChange::FkGraphLengthMarker {
1258 len: self.local.graph.foreign_keys.len(),
1259 });
1260 }
1261 }
1262
1263 fn snapshot_fk_graph_full(&mut self) {
1264 if let Some(frame) = self.local.transactions.last_mut() {
1265 frame.undo_log.push(StateChange::FkGraphSnapshot {
1266 previous: self.local.graph.foreign_keys.clone(),
1267 });
1268 }
1269 }
1270
1271 fn snapshot_view_graph(&mut self) {
1272 if let Some(frame) = self.local.transactions.last_mut() {
1273 frame.undo_log.push(StateChange::ViewGraphLengthMarker {
1274 len: self.local.graph.views.len(),
1275 });
1276 }
1277 }
1278
1279 fn snapshot_view_graph_full(&mut self) {
1280 if let Some(frame) = self.local.transactions.last_mut() {
1281 frame.undo_log.push(StateChange::ViewGraphSnapshot {
1282 previous: self.local.graph.views.clone(),
1283 });
1284 }
1285 }
1286
1287 fn snapshot_index_graph(&mut self) {
1288 if let Some(frame) = self.local.transactions.last_mut() {
1289 frame.undo_log.push(StateChange::IndexGraphLengthMarker {
1290 len: self.local.graph.indexes.len(),
1291 });
1292 }
1293 }
1294
1295 fn snapshot_index_graph_full(&mut self) {
1296 if let Some(frame) = self.local.transactions.last_mut() {
1297 frame.undo_log.push(StateChange::IndexGraphSnapshot {
1298 previous: self.local.graph.indexes.clone(),
1299 });
1300 }
1301 }
1302
1303 fn snapshot_rename_graph(&mut self) {
1304 if let Some(frame) = self.local.transactions.last_mut() {
1305 frame.undo_log.push(StateChange::RenameGraphLengthMarker {
1306 len: self.local.graph.renames.len(),
1307 });
1308 }
1309 }
1310
1311 fn snapshot_rename_graph_full(&mut self) {
1312 if let Some(frame) = self.local.transactions.last_mut() {
1313 frame.undo_log.push(StateChange::RenameGraphSnapshot {
1314 previous: self.local.graph.renames.clone(),
1315 });
1316 }
1317 }
1318
1319 fn snapshot_sequence_graph(&mut self) {
1320 if let Some(frame) = self.local.transactions.last_mut() {
1321 frame.undo_log.push(StateChange::SequenceGraphLengthMarker {
1322 len: self.local.graph.sequences.len(),
1323 });
1324 }
1325 }
1326
1327 fn snapshot_sequence_graph_full(&mut self) {
1328 if let Some(frame) = self.local.transactions.last_mut() {
1329 frame.undo_log.push(StateChange::SequenceGraphSnapshot {
1330 previous: self.local.graph.sequences.clone(),
1331 });
1332 }
1333 }
1334
1335 fn snapshot_partition_graph(&mut self) {
1336 if let Some(frame) = self.local.transactions.last_mut() {
1337 frame
1338 .undo_log
1339 .push(StateChange::PartitionGraphLengthMarker {
1340 len: self.local.graph.partitions.len(),
1341 });
1342 }
1343 }
1344
1345 fn snapshot_partition_graph_full(&mut self) {
1346 if let Some(frame) = self.local.transactions.last_mut() {
1347 frame.undo_log.push(StateChange::PartitionGraphSnapshot {
1348 previous: self.local.graph.partitions.clone(),
1349 });
1350 }
1351 }
1352
1353 fn snapshot_search_path(&mut self) {
1354 if let Some(frame) = self.local.transactions.last_mut() {
1355 frame.undo_log.push(StateChange::SearchPathSnapshot {
1356 previous: self.local.search_path.clone(),
1357 });
1358 }
1359 }
1360
1361 fn snapshot_generation_counter(&mut self) {
1362 if let Some(frame) = self.local.transactions.last_mut() {
1363 frame.undo_log.push(StateChange::GenerationCounterSnapshot {
1364 previous: self.local.generation_counter,
1365 });
1366 }
1367 }
1368
1369 fn snapshot_pending_validation(&mut self) {
1370 if let Some(frame) = self.local.transactions.last_mut() {
1371 frame.undo_log.push(StateChange::PendingValidationSnapshot {
1372 previous: self.local.pending_validation.clone(),
1373 });
1374 }
1375 }
1376
1377 fn replay_undo_log(&mut self, frame: TransactionFrame) {
1378 for change in frame.undo_log.into_iter().rev() {
1379 match change {
1380 StateChange::RelationSnapshot { id, previous } => match previous {
1381 Some(overlay) => {
1382 self.local.relations.insert(id, overlay);
1383 }
1384 None => {
1385 self.local.relations.remove(&id);
1386 }
1387 },
1388 StateChange::TypeSnapshot { id, previous } => match previous {
1389 Some(overlay) => {
1390 self.local.types.insert(id, overlay);
1391 }
1392 None => {
1393 self.local.types.remove(&id);
1394 }
1395 },
1396 StateChange::SequenceSnapshot { id, previous } => match previous {
1397 Some(overlay) => {
1398 self.local.sequences.insert(id, overlay);
1399 }
1400 None => {
1401 self.local.sequences.remove(&id);
1402 }
1403 },
1404 StateChange::SearchPathSnapshot { previous } => {
1405 self.local.search_path = previous;
1406 }
1407 StateChange::GenerationCounterSnapshot { previous } => {
1408 self.local.generation_counter = previous;
1409 }
1410 StateChange::PendingValidationSnapshot { previous } => {
1411 self.local.pending_validation = previous;
1412 }
1413 StateChange::FkGraphLengthMarker { len } => {
1414 self.local.graph.foreign_keys.truncate(len);
1415 }
1416 StateChange::FkGraphSnapshot { previous } => {
1417 self.local.graph.foreign_keys = previous;
1418 }
1419 StateChange::ViewGraphLengthMarker { len } => {
1420 self.local.graph.views.truncate(len);
1421 }
1422 StateChange::ViewGraphSnapshot { previous } => {
1423 self.local.graph.views = previous;
1424 }
1425 StateChange::IndexGraphLengthMarker { len } => {
1426 self.local.graph.indexes.truncate(len);
1427 }
1428 StateChange::IndexGraphSnapshot { previous } => {
1429 self.local.graph.indexes = previous;
1430 }
1431 StateChange::RenameGraphLengthMarker { len } => {
1432 self.local.graph.renames.truncate(len);
1433 }
1434 StateChange::RenameGraphSnapshot { previous } => {
1435 self.local.graph.renames = previous;
1436 }
1437 StateChange::SequenceGraphLengthMarker { len } => {
1438 self.local.graph.sequences.truncate(len);
1439 }
1440 StateChange::SequenceGraphSnapshot { previous } => {
1441 self.local.graph.sequences = previous;
1442 }
1443 StateChange::PartitionGraphLengthMarker { len } => {
1444 self.local.graph.partitions.truncate(len);
1445 }
1446 StateChange::PartitionGraphSnapshot { previous } => {
1447 self.local.graph.partitions = previous;
1448 }
1449 }
1450 }
1451 }
1452}