1use crate::analysis::facts::{
3 AlterIndexActionFact, AlterTableActionFact, PersistenceFact, StatementFact, TypeCreationKind,
4};
5use crate::analysis::mutations::{
6 AlterDatabaseMutation, AlterDomainMutation, AlterFunctionMutation, AlterProcedureMutation,
7 AlterPublicationMutation, AlterRoleMutation, AlterSequenceMutation, AlterSubscriptionMutation,
8 AlterTable, AlterTableActionMutation, AlterTypeActionMutation, AlterTypeMutation,
9 ColumnMutation, CreateDatabaseMutation, CreateDomainMutation, CreateFunctionMutation,
10 CreateIndex, CreateMaterializedView, CreatePolicyMutation, CreateProcedureMutation,
11 CreatePublicationMutation, CreateRoleMutation, CreateSchemaMutation, CreateSequenceMutation,
12 CreateSubscriptionMutation, CreateTable, CreateTriggerMutation, CreateTypeMutation, CreateView,
13 DropDatabaseMutation, DropDomainMutation, DropFunctionMutation, DropIndex,
14 DropMaterializedViewMutation, DropPolicyMutation, DropProcedureMutation,
15 DropPublicationMutation, DropRoleMutation, DropSchemaMutation, DropSequenceMutation,
16 DropSubscriptionMutation, DropTable, DropTriggerMutation, DropViewMutation, FkMutation,
17 GrantMutation, Mutation, OpaqueMutation, PersistenceMutation, RefreshMaterializedViewMutation,
18 ReleaseSavepointMutation, Rename, ResolvedGrantTarget, RevokeMutation,
19 RollbackToSavepointMutation, SavepointMutation, SearchPathChange,
20};
21use crate::analysis::state::AnalysisState;
22use crate::ast::identifiers::{ObjectId, QualifiedName};
23use crate::model::types::TypeKind;
24
25pub struct Resolver;
26
27impl Resolver {
28 fn resolve_creation_name(name: &QualifiedName, state: &AnalysisState) -> ObjectId {
29 let schema = name
30 .schema
31 .as_ref()
32 .map(|i| i.resolve())
33 .unwrap_or_else(|| {
34 state
35 .local
36 .search_path
37 .first()
38 .map(|s| s.as_str())
39 .unwrap_or("public")
40 .to_string()
41 });
42
43 ObjectId::new(schema, name.name.resolve())
44 }
45
46 fn resolve_lookup_name(name: &QualifiedName, state: &AnalysisState) -> ObjectId {
47 if let Some(schema_ident) = &name.schema {
48 return ObjectId::new(schema_ident.resolve(), name.name.resolve());
49 }
50
51 let resolved_name = name.name.resolve();
52
53 for schema in &state.local.search_path {
54 let mut candidate = ObjectId::new(schema.clone(), resolved_name.clone());
55 if state.local.relations.contains_key(&candidate)
56 || state.local.types.contains_key(&candidate)
57 || state.local.sequences.contains_key(&candidate)
58 || state.local.functions.keys().any(|k| {
59 k.schema == candidate.schema
60 && (k.name == candidate.name
61 || k.name.starts_with(&format!("{}(", candidate.name)))
62 })
63 {
64 candidate.inferred_schema = true;
65 return candidate;
66 }
67 }
68
69 let schema = state
70 .local
71 .search_path
72 .first()
73 .map(|s| s.as_str())
74 .unwrap_or("public")
75 .to_string();
76 let mut id = ObjectId::new(schema, resolved_name);
77 id.inferred_schema = true;
78 id
79 }
80
81 fn resolve_function_id(
82 name: &QualifiedName,
83 params: &[crate::analysis::facts::ParamFact],
84 state: &AnalysisState,
85 ) -> ObjectId {
86 let base_id = Self::resolve_creation_name(name, state);
87 let sig = params
88 .iter()
89 .map(|p| p.ty.clone())
90 .collect::<Vec<_>>()
91 .join(",");
92 Self::resolve_function_id_by_sig(&base_id, &sig)
93 }
94
95 fn resolve_function_id_by_sig(base_id: &ObjectId, sig: &str) -> ObjectId {
96 let mut id = ObjectId::new(base_id.schema.clone(), format!("{}({})", base_id.name, sig));
97 id.inferred_schema = base_id.inferred_schema;
98 id
99 }
100
101 fn resolve_grant_target(
102 target: &crate::analysis::facts::GrantTarget,
103 state: &AnalysisState,
104 ) -> ResolvedGrantTarget {
105 match target {
106 crate::analysis::facts::GrantTarget::Tables(names) => ResolvedGrantTarget::Tables(
107 names
108 .iter()
109 .map(|n| Self::resolve_lookup_name(n, state))
110 .collect(),
111 ),
112 crate::analysis::facts::GrantTarget::AllTablesInSchema(schemas) => {
113 ResolvedGrantTarget::AllTablesInSchema(schemas.clone())
114 }
115 }
116 }
117
118 pub fn resolve(fact: &StatementFact, state: &AnalysisState) -> Vec<Mutation> {
119 let mut mutations = Vec::new();
120 match fact {
121 StatementFact::CreateSchema {
122 name,
123 if_not_exists,
124 } => {
125 mutations.push(Mutation::CreateSchema(CreateSchemaMutation {
126 name: name.name.resolve(),
127 if_not_exists: *if_not_exists,
128 }));
129 }
130 StatementFact::AlterSchema { name, new_name } => {
131 if let Some(nn) = new_name {
132 let id = Self::resolve_lookup_name(name, state);
133 let mut new_id = ObjectId::new(id.schema.clone(), nn.resolve());
134 new_id.inferred_schema = id.inferred_schema;
135 mutations.push(Mutation::Rename(Rename { old_id: id, new_id }));
136 } else {
137 mutations.push(Mutation::Opaque(OpaqueMutation::DynamicSql));
138 }
139 }
140 StatementFact::DropSchema {
141 names,
142 if_exists,
143 cascade,
144 } => {
145 mutations.push(Mutation::DropSchema(DropSchemaMutation {
146 names: names.iter().map(|n| n.name.resolve()).collect(),
147 if_exists: *if_exists,
148 cascade: *cascade,
149 }));
150 }
151 StatementFact::CreateTable {
152 name,
153 if_not_exists,
154 as_select,
155 persistence,
156 columns,
157 foreign_keys,
158 table_constraints,
159 partition_by,
160 partition_of,
161 partition_type,
162 } => {
163 let id = Self::resolve_creation_name(name, state);
164
165 if !*if_not_exists
166 && (state.relation_is_present(&id)
167 || matches!(
168 state.local.types.get(&id),
169 Some(crate::model::types::TypeOverlay::Present(_))
170 )
171 || matches!(
172 state.local.sequences.get(&id),
173 Some(crate::model::sequence::SequenceOverlay::Present(_))
174 ))
175 {
176 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
177 }
178
179 let resolved_persistence = match persistence {
180 PersistenceFact::Permanent => PersistenceMutation::Permanent,
181 PersistenceFact::Temporary => PersistenceMutation::Temporary,
182 PersistenceFact::Unlogged => PersistenceMutation::Unlogged,
183 };
184
185 let col_mutations: Vec<ColumnMutation> = columns
186 .iter()
187 .map(|c| ColumnMutation {
188 name: c.name.clone(),
189 ty: c.ty.clone(),
190 not_null: c.not_null,
191 is_primary_key: c.is_primary_key,
192 default: c.default.clone(),
193 })
194 .collect();
195
196 let mut fk_mutations = Vec::new();
197 for fk in foreign_keys {
198 let to_table = Self::resolve_lookup_name(&fk.references, state);
199 if !state.relation_is_present(&to_table) {
200 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
201 }
202 fk_mutations.push(FkMutation {
203 constraint_name: fk.constraint_name.clone(),
204 to_table,
205 from_columns: fk.from_columns.clone(),
206 to_columns: fk.to_columns.clone(),
207 });
208 }
209
210 let partition_of_id = partition_of
211 .as_ref()
212 .map(|n| Self::resolve_lookup_name(n, state));
213
214 if let Some(p_id) = &partition_of_id
215 && !state.relation_is_present(p_id)
216 {
217 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
218 }
219
220 mutations.push(Mutation::CreateTable(CreateTable {
221 id,
222 if_not_exists: *if_not_exists,
223 as_select: *as_select,
224 persistence: resolved_persistence,
225 columns: col_mutations,
226 foreign_keys: fk_mutations,
227 table_constraints: table_constraints.clone(),
228 partition_by: partition_by.clone(),
229 partition_of: partition_of_id,
230 partition_type: partition_type.clone(),
231 }));
232 }
233 StatementFact::CreateView {
234 name,
235 or_replace,
236 depends_on,
237 } => {
238 let id = Self::resolve_creation_name(name, state);
239
240 if !*or_replace && state.relation_is_present(&id) {
241 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
242 }
243
244 let resolved_depends = depends_on
245 .iter()
246 .map(|n| Self::resolve_lookup_name(n, state))
247 .collect();
248
249 mutations.push(Mutation::CreateView(CreateView {
250 id,
251 or_replace: *or_replace,
252 depends_on: resolved_depends,
253 }));
254 }
255 StatementFact::AlterView { name, action } => {
256 match action {
257 crate::analysis::facts::AlterViewAction::RenameTo { new_name } => {
258 let id = Self::resolve_lookup_name(name, state);
259 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
260 new_id.inferred_schema = id.inferred_schema;
261 mutations.push(Mutation::Rename(Rename { old_id: id, new_id }));
262 }
263 crate::analysis::facts::AlterViewAction::SetSchema { .. } => {
264 }
267 crate::analysis::facts::AlterViewAction::OwnerTo { .. }
268 | crate::analysis::facts::AlterViewAction::SetDefault { .. }
269 | crate::analysis::facts::AlterViewAction::DropDefault { .. }
270 | crate::analysis::facts::AlterViewAction::RenameColumn { .. }
271 | crate::analysis::facts::AlterViewAction::SetOptions { .. }
272 | crate::analysis::facts::AlterViewAction::ResetOptions { .. } => {
273 }
277 }
278 }
279 StatementFact::CreateMaterializedView { name, depends_on } => {
280 let id = Self::resolve_creation_name(name, state);
281
282 if state.relation_is_present(&id) {
283 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
284 }
285
286 let resolved_depends = depends_on
287 .iter()
288 .map(|n| Self::resolve_lookup_name(n, state))
289 .collect();
290
291 mutations.push(Mutation::CreateMaterializedView(CreateMaterializedView {
292 id,
293 depends_on: resolved_depends,
294 }));
295 }
296 StatementFact::AlterMaterializedView { name, new_name } => {
297 if let Some(new_name) = new_name {
298 let id = Self::resolve_lookup_name(name, state);
299 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
300 new_id.inferred_schema = id.inferred_schema;
301 mutations.push(Mutation::Rename(Rename { old_id: id, new_id }));
302 }
303 }
304 StatementFact::RefreshMaterializedView { name, concurrently } => {
305 mutations.push(Mutation::RefreshMaterializedView(
306 RefreshMaterializedViewMutation {
307 id: Self::resolve_lookup_name(name, state),
308 concurrently: *concurrently,
309 },
310 ));
311 }
312 StatementFact::CreateIndex {
313 name,
314 relation,
315 if_not_exists,
316 concurrently,
317 using_method,
318 has_predicate,
319 unique,
320 } => {
321 let id = Self::resolve_creation_name(name, state);
322
323 if !*if_not_exists && state.local.graph.indexes.iter().any(|ix| ix.index_id == id) {
324 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
325 }
326
327 mutations.push(Mutation::CreateIndex(CreateIndex {
328 id,
329 table: Self::resolve_lookup_name(relation, state),
330 if_not_exists: *if_not_exists,
331 concurrently: *concurrently,
332 using_method: using_method.clone(),
333 has_predicate: *has_predicate,
334 unique: *unique,
335 }));
336 }
337 StatementFact::CreatePolicy {
338 name,
339 table,
340 permissive,
341 command,
342 } => {
343 mutations.push(Mutation::CreatePolicy(CreatePolicyMutation {
344 name: name.clone(),
345 table: Self::resolve_lookup_name(table, state),
346 permissive: *permissive,
347 command: command.clone(),
348 }));
349 }
350 StatementFact::DropPolicy {
351 name,
352 table,
353 if_exists,
354 } => {
355 mutations.push(Mutation::DropPolicy(DropPolicyMutation {
356 name: name.clone(),
357 table: Self::resolve_lookup_name(table, state),
358 if_exists: *if_exists,
359 }));
360 }
361 StatementFact::CreateTrigger {
362 name,
363 table,
364 function,
365 } => {
366 let function_base = function
370 .as_ref()
371 .map(|f| Self::resolve_lookup_name(f, state))
372 .unwrap_or_else(|| ObjectId::new("public", "unknown_function"));
373 let function_id = Self::resolve_function_id_by_sig(&function_base, "");
374 mutations.push(Mutation::CreateTrigger(CreateTriggerMutation {
375 name: name.clone(),
376 table: Self::resolve_lookup_name(table, state),
377 function_id,
378 }));
379 }
380 StatementFact::DropTrigger {
381 name,
382 table,
383 if_exists,
384 } => {
385 mutations.push(Mutation::DropTrigger(DropTriggerMutation {
386 name: name.clone(),
387 table: Self::resolve_lookup_name(table, state),
388 if_exists: *if_exists,
389 }));
390 }
391 StatementFact::AlterIndex { name, actions } => {
392 let id = Self::resolve_lookup_name(name, state);
393 for action in actions {
394 match action {
395 AlterIndexActionFact::RenameTo { new_name } => {
396 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
397 new_id.inferred_schema = id.inferred_schema;
398 mutations.push(Mutation::Rename(Rename {
399 old_id: id.clone(),
400 new_id,
401 }));
402 }
403 }
404 }
405 }
406 StatementFact::CreateType(create_type) => {
407 let id = Self::resolve_creation_name(&create_type.name, state);
408
409 if matches!(
410 state.local.types.get(&id),
411 Some(crate::model::types::TypeOverlay::Present(_))
412 ) || state.relation_is_present(&id)
413 {
414 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
415 }
416
417 let mapped_kind = match create_type.kind {
418 TypeCreationKind::Enum => TypeKind::Enum { variants: vec![] },
419 TypeCreationKind::Range => TypeKind::Range,
420 TypeCreationKind::Composite => TypeKind::Composite,
421 TypeCreationKind::Base => TypeKind::Base,
422 };
423
424 mutations.push(Mutation::CreateType(CreateTypeMutation {
425 id,
426 kind: mapped_kind,
427 }));
428 }
429 StatementFact::AlterType(alter_type) => {
430 let id = Self::resolve_lookup_name(&alter_type.name, state);
431 for action_fact in &alter_type.actions {
432 match action_fact {
433 crate::analysis::facts::AlterTypeActionFact::AddValue { new_value } => {
434 mutations.push(Mutation::AlterType(AlterTypeMutation {
435 id: id.clone(),
436 action: AlterTypeActionMutation::AddValue {
437 new_value: new_value.clone(),
438 },
439 }));
440 }
441 }
442 }
443 }
444 StatementFact::CreateDomain { name, base_type } => {
445 let id = Self::resolve_creation_name(name, state);
446
447 if matches!(
448 state.local.types.get(&id),
449 Some(crate::model::types::TypeOverlay::Present(_))
450 ) || state.relation_is_present(&id)
451 {
452 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
453 }
454
455 mutations.push(Mutation::CreateDomain(CreateDomainMutation {
456 id,
457 base_type: base_type.clone(),
458 }));
459 }
460 StatementFact::AlterDomain { name, action } => {
461 mutations.push(Mutation::AlterDomain(AlterDomainMutation {
462 id: Self::resolve_lookup_name(name, state),
463 action: action.clone(),
464 }));
465 }
466 StatementFact::DropDomain {
467 names,
468 if_exists,
469 cascade,
470 } => {
471 let ids = names
472 .iter()
473 .map(|n| Self::resolve_lookup_name(n, state))
474 .collect();
475 mutations.push(Mutation::DropDomain(DropDomainMutation {
476 ids,
477 if_exists: *if_exists,
478 cascade: *cascade,
479 }));
480 }
481 StatementFact::CreateSequence {
482 name,
483 if_not_exists,
484 owned_by,
485 } => {
486 let id = Self::resolve_creation_name(name, state);
487
488 if !*if_not_exists
489 && matches!(
490 state.local.sequences.get(&id),
491 Some(crate::model::sequence::SequenceOverlay::Present(_))
492 )
493 {
494 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
495 }
496
497 let resolved_owned_by = owned_by.as_ref().map(|(table_name, col)| {
498 (Self::resolve_lookup_name(table_name, state), col.clone())
499 });
500 mutations.push(Mutation::CreateSequence(CreateSequenceMutation {
501 id,
502 if_not_exists: *if_not_exists,
503 owned_by: resolved_owned_by,
504 }));
505 }
506 StatementFact::AlterSequence { name, owned_by } => {
507 let resolved_owned_by = owned_by.as_ref().map(|(table_name, col)| {
508 (Self::resolve_lookup_name(table_name, state), col.clone())
509 });
510 mutations.push(Mutation::AlterSequence(AlterSequenceMutation {
511 id: Self::resolve_lookup_name(name, state),
512 owned_by: resolved_owned_by,
513 }));
514 }
515 StatementFact::DropSequence {
516 names,
517 if_exists,
518 cascade,
519 } => {
520 let ids = names
521 .iter()
522 .map(|n| Self::resolve_lookup_name(n, state))
523 .collect();
524 mutations.push(Mutation::DropSequence(DropSequenceMutation {
525 ids,
526 if_exists: *if_exists,
527 cascade: *cascade,
528 }));
529 }
530 StatementFact::AlterTable { name, actions } => {
531 let id = Self::resolve_lookup_name(name, state);
532 for action_fact in actions {
533 let action = match action_fact {
534 AlterTableActionFact::AddColumn {
535 name: col_name,
536 ty,
537 if_not_exists,
538 not_null,
539 default,
540 } => AlterTableActionMutation::AddColumn {
541 name: col_name.clone(),
542 ty: ty.clone(),
543 if_not_exists: *if_not_exists,
544 not_null: *not_null,
545 default: default.clone(),
546 depends_on: None, },
548 AlterTableActionFact::DropColumn {
549 name: col_name,
550 if_exists,
551 } => AlterTableActionMutation::DropColumn {
552 name: col_name.clone(),
553 if_exists: *if_exists,
554 },
555 AlterTableActionFact::RenameColumn { from, to } => {
556 AlterTableActionMutation::RenameColumn {
557 from: from.resolve(),
558 to: to.resolve(),
559 }
560 }
561 AlterTableActionFact::RenameTo { new_name } => {
562 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
563 new_id.inferred_schema = id.inferred_schema;
564 mutations.push(Mutation::Rename(Rename {
565 old_id: id.clone(),
566 new_id,
567 }));
568 continue;
569 }
570 AlterTableActionFact::AddForeignKey {
571 constraint_name,
572 references,
573 from_columns,
574 to_columns,
575 not_valid,
576 } => {
577 let to_table = Self::resolve_lookup_name(references, state);
578 if !state.relation_is_present(&to_table) {
579 return vec![Mutation::Opaque(
580 OpaqueMutation::UnresolvedReference {
581 object_kind: crate::report::violations::ObjectKind::Table,
582 object_name: to_table.to_string(),
583 },
584 )];
585 }
586 AlterTableActionMutation::AddForeignKey {
587 constraint_name: constraint_name.clone(),
588 to_table,
589 from_columns: from_columns.clone(),
590 to_columns: to_columns.clone(),
591 not_valid: *not_valid,
592 }
593 }
594 AlterTableActionFact::AlterConstraint {
595 name: c_name,
596 deferrable,
597 } => AlterTableActionMutation::AlterConstraint {
598 name: c_name.clone(),
599 deferrable: *deferrable,
600 },
601 AlterTableActionFact::RenameConstraint { old_name, new_name } => {
602 AlterTableActionMutation::RenameConstraint {
603 old_name: old_name.clone(),
604 new_name: new_name.clone(),
605 }
606 }
607 AlterTableActionFact::DropConstraint { name: c_name } => {
608 AlterTableActionMutation::DropConstraint {
609 name: c_name.clone(),
610 }
611 }
612 AlterTableActionFact::AddCheckConstraint {
613 constraint_name,
614 not_valid,
615 } => AlterTableActionMutation::AddCheckConstraint {
616 constraint_name: constraint_name.clone(),
617 not_valid: *not_valid,
618 },
619 AlterTableActionFact::AddUniqueConstraint => {
620 AlterTableActionMutation::AddUniqueConstraint
621 }
622 AlterTableActionFact::AddPrimaryKeyConstraint => {
623 AlterTableActionMutation::AddPrimaryKeyConstraint
624 }
625 AlterTableActionFact::AddExcludeConstraint => {
626 AlterTableActionMutation::AddExcludeConstraint
627 }
628 AlterTableActionFact::SetNotNull { column } => {
629 AlterTableActionMutation::SetNotNull {
630 column: column.clone(),
631 }
632 }
633 AlterTableActionFact::DropNotNull { column } => {
634 AlterTableActionMutation::DropNotNull {
635 column: column.clone(),
636 }
637 }
638 AlterTableActionFact::SetType {
639 column,
640 ty,
641 has_using,
642 } => AlterTableActionMutation::SetType {
643 column: column.clone(),
644 ty: ty.clone(),
645 has_using: *has_using,
646 },
647 AlterTableActionFact::SetDefault { column, default } => {
648 AlterTableActionMutation::SetDefault {
649 column: column.clone(),
650 default: default.clone(),
651 }
652 }
653 AlterTableActionFact::ValidateConstraint { constraint_name } => {
654 AlterTableActionMutation::ValidateConstraint {
655 constraint_name: constraint_name.clone(),
656 }
657 }
658 AlterTableActionFact::AttachPartition { child } => {
659 let child_id = Self::resolve_lookup_name(child, state);
660 if state.local.graph.check_partition_cycle(&id, &child_id) {
661 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
662 }
663 AlterTableActionMutation::AttachPartition { child: child_id }
664 }
665 AlterTableActionFact::DetachPartition { child } => {
666 AlterTableActionMutation::DetachPartition {
667 child: Self::resolve_lookup_name(child, state),
668 }
669 }
670 AlterTableActionFact::SetStorage { column } => {
671 AlterTableActionMutation::SetStorage {
672 column: column.clone(),
673 }
674 }
675 AlterTableActionFact::SetAccessMethod => {
676 AlterTableActionMutation::SetAccessMethod
677 }
678 AlterTableActionFact::DisableTrigger { trigger_name } => {
679 AlterTableActionMutation::DisableTrigger {
680 trigger_name: trigger_name.clone(),
681 }
682 }
683 AlterTableActionFact::EnableTrigger { trigger_name } => {
684 AlterTableActionMutation::EnableTrigger {
685 trigger_name: trigger_name.clone(),
686 }
687 }
688 AlterTableActionFact::SetExpression { .. }
689 | AlterTableActionFact::SetOptions { .. }
690 | AlterTableActionFact::Inherit { .. }
691 | AlterTableActionFact::NoInherit { .. } => {
692 AlterTableActionMutation::Opaque
693 }
694 };
695 mutations.push(Mutation::AlterTable(AlterTable {
696 id: id.clone(),
697 action,
698 }));
699 }
700 }
701 StatementFact::DropTable {
702 name,
703 if_exists,
704 cascade,
705 } => {
706 let id = Self::resolve_lookup_name(name, state);
707 if !state.relation_is_present(&id) && *if_exists {
708 return vec![];
709 }
710 mutations.push(Mutation::DropTable(DropTable {
714 id,
715 if_exists: *if_exists,
716 cascade: *cascade,
717 }));
718 }
719 StatementFact::DropView {
720 name,
721 if_exists,
722 cascade,
723 } => {
724 mutations.push(Mutation::DropView(DropViewMutation {
725 ids: vec![Self::resolve_lookup_name(name, state)],
726 if_exists: *if_exists,
727 cascade: *cascade,
728 }));
729 }
730 StatementFact::DropMaterializedView {
731 names,
732 if_exists,
733 cascade,
734 } => {
735 let ids = names
736 .iter()
737 .map(|n| Self::resolve_lookup_name(n, state))
738 .collect();
739 mutations.push(Mutation::DropMaterializedView(
740 DropMaterializedViewMutation {
741 ids,
742 if_exists: *if_exists,
743 cascade: *cascade,
744 },
745 ));
746 }
747 StatementFact::DropIndex {
748 names,
749 if_exists,
750 concurrently,
751 } => {
752 for name in names {
753 mutations.push(Mutation::DropIndex(DropIndex {
754 id: Self::resolve_lookup_name(name, state),
755 if_exists: *if_exists,
756 concurrently: *concurrently,
757 }));
758 }
759 }
760 StatementFact::SetSearchPath { target } => {
761 mutations.push(Mutation::SearchPath(SearchPathChange {
762 target: target.clone(),
763 }))
764 }
765 StatementFact::BeginTransaction => mutations.push(Mutation::BeginTransaction),
766 StatementFact::CommitTransaction => mutations.push(Mutation::CommitTransaction),
767 StatementFact::RollbackTransaction => mutations.push(Mutation::RollbackTransaction),
768 StatementFact::RollbackToSavepoint { name } => {
769 if !state.local.transactions.iter().any(|t| t.name == *name) {
770 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
771 }
772 mutations.push(Mutation::RollbackToSavepoint(RollbackToSavepointMutation {
773 name: name.clone(),
774 }))
775 }
776 StatementFact::Savepoint { name } => {
777 mutations.push(Mutation::Savepoint(SavepointMutation {
778 name: name.clone(),
779 }))
780 }
781 StatementFact::ReleaseSavepoint { name } => {
782 if !state.local.transactions.iter().any(|t| t.name == *name) {
783 return vec![Mutation::Opaque(OpaqueMutation::DynamicSql)];
784 }
785 mutations.push(Mutation::ReleaseSavepoint(ReleaseSavepointMutation {
786 name: name.clone(),
787 }))
788 }
789 StatementFact::PrepareTransaction { .. } => {
790 mutations.push(Mutation::Opaque(OpaqueMutation::PrepareTransaction))
791 }
792 StatementFact::SetTransaction => {
793 mutations.push(Mutation::Opaque(OpaqueMutation::SetTransaction))
794 }
795 StatementFact::SetConstraints => {
796 mutations.push(Mutation::Opaque(OpaqueMutation::SetConstraints))
797 }
798 StatementFact::OpaqueBlock => mutations.push(Mutation::Opaque(OpaqueMutation::DoBlock)),
799 StatementFact::Execute => mutations.push(Mutation::Opaque(OpaqueMutation::Execute)),
800 StatementFact::Vacuum { relation, is_full } => {
801 let table_id = relation
802 .as_ref()
803 .map(|r| Self::resolve_lookup_name(r, state));
804 mutations.push(Mutation::Vacuum {
805 table_id,
806 is_full: *is_full,
807 })
808 }
809 StatementFact::CreateFunction(f) => {
810 let id = Self::resolve_function_id(&f.name, &f.params, state);
811 mutations.push(Mutation::CreateFunction(CreateFunctionMutation {
812 id,
813 or_replace: f.or_replace,
814 params: f.params.clone(),
815 return_type: f.return_type.clone(),
816 options: f.options.clone(),
817 }));
818 }
819 StatementFact::AlterFunction(f) => {
820 let base_id = Self::resolve_lookup_name(&f.name, state);
821 let sig = f.params.join(",");
822 let id = Self::resolve_function_id_by_sig(&base_id, &sig);
823 mutations.push(Mutation::AlterFunction(AlterFunctionMutation {
824 id,
825 action: f.action.clone(),
826 }));
827 }
828 StatementFact::DropFunction(f) => {
829 mutations.push(Mutation::DropFunction(DropFunctionMutation {
830 signatures: f.signatures.clone(),
831 if_exists: f.if_exists,
832 cascade: f.cascade,
833 }));
834 }
835 StatementFact::CreateProcedure(p) => {
836 let id = Self::resolve_function_id(&p.name, &p.params, state);
837 mutations.push(Mutation::CreateProcedure(CreateProcedureMutation {
838 id,
839 or_replace: p.or_replace,
840 params: p.params.clone(),
841 options: p.options.clone(),
842 }));
843 }
844 StatementFact::AlterProcedure(p) => {
845 let base_id = Self::resolve_lookup_name(&p.name, state);
846 let sig = p
847 .params
848 .iter()
849 .map(|p| p.to_string())
850 .collect::<Vec<_>>()
851 .join(",");
852 let id = Self::resolve_function_id_by_sig(&base_id, &sig);
853 mutations.push(Mutation::AlterProcedure(AlterProcedureMutation {
854 id,
855 action: p.action.clone(),
856 }));
857 }
858 StatementFact::DropProcedure(p) => {
859 mutations.push(Mutation::DropProcedure(DropProcedureMutation {
860 signatures: p.signatures.clone(),
861 if_exists: p.if_exists,
862 cascade: p.cascade,
863 }));
864 }
865 StatementFact::CreatePublication(p) => {
866 mutations.push(Mutation::CreatePublication(CreatePublicationMutation {
867 name: p.name.clone(),
868 scope: p.scope.clone(),
869 params: p.params.clone(),
870 }));
871 }
872 StatementFact::AlterPublication(p) => {
873 mutations.push(Mutation::AlterPublication(AlterPublicationMutation {
874 name: p.name.clone(),
875 }));
876 }
877 StatementFact::DropPublication(p) => {
878 mutations.push(Mutation::DropPublication(DropPublicationMutation {
879 names: p.names.clone(),
880 if_exists: p.if_exists,
881 cascade: p.cascade,
882 }));
883 }
884 StatementFact::CreateSubscription(s) => {
885 mutations.push(Mutation::CreateSubscription(CreateSubscriptionMutation {
886 name: s.name.clone(),
887 connection: s.connection.clone(),
888 publications: s.publications.clone(),
889 params: s.params.clone(),
890 }));
891 }
892 StatementFact::AlterSubscription(s) => {
893 mutations.push(Mutation::AlterSubscription(AlterSubscriptionMutation {
894 name: s.name.clone(),
895 }));
896 }
897 StatementFact::DropSubscription(s) => {
898 mutations.push(Mutation::DropSubscription(DropSubscriptionMutation {
899 name: s.name.clone(),
900 if_exists: s.if_exists,
901 }));
902 }
903 StatementFact::CreateRole(r) => {
904 mutations.push(Mutation::CreateRole(CreateRoleMutation {
905 name: r.name.clone(),
906 inherits: r.inherits,
907 }));
908 }
909 StatementFact::AlterRole(r) => {
910 mutations.push(Mutation::AlterRole(AlterRoleMutation {
911 name: r.name.clone(),
912 inherits: r.inherits,
913 }));
914 }
915 StatementFact::DropRole(r) => {
916 mutations.push(Mutation::DropRole(DropRoleMutation {
917 names: r.names.clone(),
918 if_exists: r.if_exists,
919 }));
920 }
921 StatementFact::Grant(g) => {
922 mutations.push(Mutation::Grant(GrantMutation {
923 privileges: g.privileges.clone(),
924 target: Self::resolve_grant_target(&g.target, state),
925 grantees: g.grantees.clone(),
926 with_grant_option: g.with_grant_option,
927 granted_by: g.granted_by.clone(),
928 }));
929 }
930 StatementFact::Revoke(r) => {
931 mutations.push(Mutation::Revoke(RevokeMutation {
932 grant_option_only: r.grant_option_only,
933 privileges: r.privileges.clone(),
934 target: Self::resolve_grant_target(&r.target, state),
935 revokees: r.revokees.clone(),
936 granted_by: r.granted_by.clone(),
937 cascade: r.cascade,
938 }));
939 }
940 StatementFact::CreateDatabase(d) => {
941 mutations.push(Mutation::CreateDatabase(CreateDatabaseMutation {
942 name: d.name.clone(),
943 options: d.options.clone(),
944 }));
945 }
946 StatementFact::AlterDatabase(d) => {
947 let id = Self::resolve_lookup_name(&d.name, state);
948 mutations.push(Mutation::AlterDatabase(AlterDatabaseMutation {
949 id,
950 action: d.action.clone(),
951 }));
952 }
953 StatementFact::DropDatabase(d) => {
954 let id = Self::resolve_lookup_name(&d.name, state);
955 mutations.push(Mutation::DropDatabase(DropDatabaseMutation {
956 id,
957 if_exists: d.if_exists,
958 }));
959 }
960 }
961 mutations
962 }
963}