1use crate::analysis::facts::{
2 AlterIndexActionFact, AlterTableActionFact, PersistenceFact, StatementFact, TypeCreationKind,
3};
4use crate::analysis::mutations::{
5 AlterAggregateMutation, AlterDatabaseMutation, AlterDomainMutation, AlterFunctionMutation,
6 AlterProcedureMutation, AlterPublicationMutation, AlterRoleMutation, AlterSchemaMutation,
7 AlterSequenceActionMutation, AlterSequenceMutation, AlterSubscriptionMutation, AlterTable,
8 AlterTableActionMutation, AlterTypeActionMutation, AlterTypeMutation, ColumnMutation,
9 CreateAggregateMutation, CreateDatabaseMutation, CreateDomainMutation, CreateFunctionMutation,
10 CreateIndex, CreateMaterializedView, CreatePolicyMutation, CreateProcedureMutation,
11 CreatePublicationMutation, CreateRoleMutation, CreateSchemaMutation, CreateSequenceMutation,
12 CreateSubscriptionMutation, CreateTable, CreateTriggerMutation, CreateTypeMutation, CreateView,
13 DropAggregateMutation, DropDatabaseMutation, DropDomainMutation, DropFunctionMutation,
14 DropIndex, DropMaterializedViewMutation, DropPolicyMutation, DropProcedureMutation,
15 DropPublicationMutation, DropRoleMutation, DropSchemaMutation, DropSequenceMutation,
16 DropSubscriptionMutation, DropTable, DropTriggerMutation, DropTypeMutation, DropViewMutation,
17 FkMutation, GrantMutation, Mutation, OpaqueMutation, PersistenceMutation,
18 RefreshMaterializedViewMutation, ReleaseSavepointMutation, Rename, RenameTriggerMutation,
19 ResolvedGrantTarget, RevokeMutation, RollbackToSavepointMutation, SavepointMutation,
20 SearchPathChange, TimeoutSettingChange,
21};
22use crate::analysis::state::AnalysisState;
23use crate::ast::identifiers::{ObjectId, QualifiedName};
24use crate::model::types::TypeKind;
25
26pub struct Resolver;
27
28impl Resolver {
29 fn resolve_creation_name(name: &QualifiedName, state: &AnalysisState) -> ObjectId {
30 let schema = name
31 .schema
32 .as_ref()
33 .map(|i| i.resolve())
34 .unwrap_or_else(|| {
35 state
36 .local
37 .search_path
38 .first()
39 .map(|s| s.as_str())
40 .unwrap_or("public")
41 .to_string()
42 });
43
44 ObjectId::new(schema, name.name.resolve())
45 }
46
47 fn resolve_lookup_name(name: &QualifiedName, state: &AnalysisState) -> ObjectId {
48 if let Some(schema_ident) = &name.schema {
49 return ObjectId::new(schema_ident.resolve(), name.name.resolve());
50 }
51
52 let resolved_name = name.name.resolve();
53
54 for schema in &state.local.search_path {
55 let mut candidate = ObjectId::new(schema.clone(), resolved_name.clone());
56 if state.local.relations.contains_key(&candidate)
57 || state.local.types.contains_key(&candidate)
58 || state.local.sequences.contains_key(&candidate)
59 || state.local.functions.keys().any(|k| {
60 k.schema == candidate.schema
61 && (k.name == candidate.name
62 || k.name.starts_with(&format!("{}(", candidate.name)))
63 })
64 {
65 candidate.inferred_schema = true;
66 return candidate;
67 }
68 }
69
70 let schema = state
71 .local
72 .search_path
73 .first()
74 .map(|s| s.as_str())
75 .unwrap_or("public")
76 .to_string();
77 let mut id = ObjectId::new(schema, resolved_name);
78 id.inferred_schema = true;
79 id
80 }
81
82 fn resolve_type_lookup_name(name: &QualifiedName, state: &AnalysisState) -> ObjectId {
83 if let Some(schema_ident) = &name.schema {
84 return ObjectId::new(schema_ident.resolve(), name.name.resolve());
85 }
86
87 let resolved_name = name.name.resolve();
88 for schema in &state.local.search_path {
89 let mut candidate = ObjectId::new(schema.clone(), resolved_name.clone());
90 if matches!(
91 state.local.types.get(&candidate),
92 Some(crate::model::types::TypeOverlay::Present(_))
93 ) {
94 candidate.inferred_schema = true;
95 return candidate;
96 }
97 }
98
99 let schema = state
100 .local
101 .search_path
102 .first()
103 .cloned()
104 .unwrap_or_else(|| "public".to_string());
105 let mut id = ObjectId::new(schema, resolved_name);
106 id.inferred_schema = true;
107 id
108 }
109
110 fn resolve_constraint_index_name(name: &QualifiedName, table: &ObjectId) -> ObjectId {
111 let schema = name
112 .schema
113 .as_ref()
114 .map(|schema| schema.resolve())
115 .unwrap_or_else(|| table.schema.clone());
116 ObjectId::new(schema, name.name.resolve())
117 }
118
119 fn resolve_function_id(
120 name: &QualifiedName,
121 params: &[crate::analysis::facts::ParamFact],
122 state: &AnalysisState,
123 ) -> ObjectId {
124 let base_id = Self::resolve_creation_name(name, state);
125 let sig = params
126 .iter()
127 .filter(|p| !matches!(&p.mode, crate::analysis::facts::ParamModeFact::Out))
128 .map(|p| p.ty.clone())
129 .collect::<Vec<_>>()
130 .join(",");
131 Self::resolve_function_id_by_sig(&base_id, &sig)
132 }
133
134 fn resolve_function_id_by_sig(base_id: &ObjectId, sig: &str) -> ObjectId {
135 let normalized_sig = sig
137 .split(',')
138 .map(Self::normalize_function_arg_type)
139 .collect::<Vec<_>>()
140 .join(",");
141
142 let mut id = ObjectId::new(
143 base_id.schema.clone(),
144 format!("{}({})", base_id.name, normalized_sig),
145 );
146 id.inferred_schema = base_id.inferred_schema;
147 id
148 }
149
150 fn resolve_publication_object(
151 object: &crate::analysis::facts::PublicationObjectFact,
152 state: &AnalysisState,
153 ) -> crate::analysis::facts::PublicationObjectFact {
154 match object {
155 crate::analysis::facts::PublicationObjectFact::Table {
156 name,
157 only,
158 include_partitions,
159 columns,
160 row_filter,
161 } => {
162 let id = Self::resolve_lookup_name(name, state);
163 crate::analysis::facts::PublicationObjectFact::Table {
164 name: crate::ast::identifiers::QualifiedName::new(
165 Some(crate::ast::identifiers::Ident::new(id.schema, true)),
166 crate::ast::identifiers::Ident::new(id.name, true),
167 ),
168 only: *only,
169 include_partitions: *include_partitions,
170 columns: columns.clone(),
171 row_filter: row_filter.clone(),
172 }
173 }
174 crate::analysis::facts::PublicationObjectFact::CurrentSchemaShorthand => {
175 crate::analysis::facts::PublicationObjectFact::SchemaTables {
176 schema: state
177 .local
178 .search_path
179 .first()
180 .cloned()
181 .unwrap_or_else(|| "public".to_string()),
182 row_filter: None,
183 }
184 }
185 other => other.clone(),
186 }
187 }
188
189 fn resolve_publication_scope(
190 scope: &crate::analysis::facts::PublicationScope,
191 state: &AnalysisState,
192 ) -> crate::analysis::facts::PublicationScope {
193 match scope {
194 crate::analysis::facts::PublicationScope::AllTables { except } => {
195 crate::analysis::facts::PublicationScope::AllTables {
196 except: except.clone(),
197 }
198 }
199 crate::analysis::facts::PublicationScope::Explicit(objects) => {
200 crate::analysis::facts::PublicationScope::Explicit(
201 objects
202 .iter()
203 .map(|object| Self::resolve_publication_object(object, state))
204 .collect(),
205 )
206 }
207 }
208 }
209
210 fn resolve_alter_publication_action(
211 action: &crate::analysis::facts::AlterPublicationActionFact,
212 state: &AnalysisState,
213 ) -> crate::analysis::facts::AlterPublicationActionFact {
214 use crate::analysis::facts::AlterPublicationActionFact;
215 match action {
216 AlterPublicationActionFact::AddObjects(objects) => {
217 AlterPublicationActionFact::AddObjects(
218 objects
219 .iter()
220 .map(|object| Self::resolve_publication_object(object, state))
221 .collect(),
222 )
223 }
224 AlterPublicationActionFact::DropObjects(objects) => {
225 AlterPublicationActionFact::DropObjects(
226 objects
227 .iter()
228 .map(|object| Self::resolve_publication_object(object, state))
229 .collect(),
230 )
231 }
232 AlterPublicationActionFact::SetObjects(scope) => {
233 AlterPublicationActionFact::SetObjects(Self::resolve_publication_scope(
234 scope, state,
235 ))
236 }
237 other => other.clone(),
238 }
239 }
240
241 pub(crate) fn normalize_function_arg_type(raw: &str) -> String {
242 let normalized = Self::fold_unquoted_identifier_case(raw.trim());
243 if let Some(element_type) = normalized.strip_suffix("[]") {
244 return format!("{}[]", Self::normalize_function_arg_type(element_type));
245 }
246 match normalized.as_str() {
247 "int" | "int4" => "integer".to_string(),
248 "int8" => "bigint".to_string(),
249 "int2" => "smallint".to_string(),
250 "float8" => "double precision".to_string(),
251 "float4" => "real".to_string(),
252 "bool" => "boolean".to_string(),
253 "varchar" => "character varying".to_string(),
254 "char" => "character".to_string(),
255 "time" => "time without time zone".to_string(),
256 "timestamp" => "timestamp without time zone".to_string(),
257 "timestamptz" => "timestamp with time zone".to_string(),
258 "decimal" => "numeric".to_string(),
259 _ => normalized,
260 }
261 }
262
263 fn fold_unquoted_identifier_case(raw: &str) -> String {
264 let mut folded = String::with_capacity(raw.len());
265 let mut quoted = false;
266 let mut chars = raw.chars().peekable();
267 while let Some(character) = chars.next() {
268 match character {
269 '"' if quoted && chars.peek() == Some(&'"') => {
270 folded.push('"');
271 folded.push('"');
272 chars.next();
273 }
274 '"' => {
275 quoted = !quoted;
276 folded.push(character);
277 }
278 character if quoted => folded.push(character),
279 character => folded.extend(character.to_lowercase()),
280 }
281 }
282 folded
283 }
284
285 fn resolve_grant_target(
286 target: &crate::analysis::facts::GrantTarget,
287 state: &AnalysisState,
288 ) -> ResolvedGrantTarget {
289 match target {
290 crate::analysis::facts::GrantTarget::Tables(names) => ResolvedGrantTarget::Tables(
291 names
292 .iter()
293 .map(|n| Self::resolve_lookup_name(n, state))
294 .collect(),
295 ),
296 crate::analysis::facts::GrantTarget::AllTablesInSchema(schemas) => {
297 ResolvedGrantTarget::AllTablesInSchema(schemas.clone())
298 }
299 }
300 }
301
302 pub fn resolve(fact: &StatementFact, state: &AnalysisState) -> Vec<Mutation> {
303 let mut mutations = Vec::new();
304 match fact {
305 StatementFact::CreateSchema {
306 name,
307 if_not_exists,
308 authorization,
309 } => {
310 mutations.push(Mutation::CreateSchema(CreateSchemaMutation {
311 name: name.name.resolve(),
312 if_not_exists: *if_not_exists,
313 authorization: authorization.clone(),
314 }));
315 }
316 StatementFact::SchemaNeutralNoop => {}
317 StatementFact::AlterSchema { name, action } => {
318 let name = name.name.resolve();
319 let action = match action {
320 crate::analysis::facts::AlterSchemaActionFact::RenameTo { new_name } => {
321 AlterSchemaMutation::Rename {
322 old_name: name,
323 new_name: new_name.resolve(),
324 }
325 }
326 crate::analysis::facts::AlterSchemaActionFact::OwnerTo { new_owner } => {
327 AlterSchemaMutation::OwnerTo {
328 name,
329 new_owner: new_owner.clone(),
330 }
331 }
332 };
333 mutations.push(Mutation::AlterSchema(action));
334 }
335 StatementFact::DropSchema {
336 names,
337 if_exists,
338 cascade,
339 } => {
340 mutations.push(Mutation::DropSchema(DropSchemaMutation {
341 names: names.iter().map(|n| n.name.resolve()).collect(),
342 if_exists: *if_exists,
343 cascade: *cascade,
344 }));
345 }
346 StatementFact::CreateTable {
347 name,
348 if_not_exists,
349 as_select,
350 persistence,
351 columns,
352 foreign_keys,
353 table_constraints,
354 partition_by,
355 partition_of,
356 partition_type,
357 } => {
358 let id = Self::resolve_creation_name(name, state);
359
360 let resolved_persistence = match persistence {
361 PersistenceFact::Permanent => PersistenceMutation::Permanent,
362 PersistenceFact::Temporary => PersistenceMutation::Temporary,
363 PersistenceFact::Unlogged => PersistenceMutation::Unlogged,
364 };
365
366 let col_mutations: Vec<ColumnMutation> = columns
367 .iter()
368 .map(|c| ColumnMutation {
369 name: c.name.clone(),
370 ty: c.ty.clone(),
371 not_null: c.not_null,
372 is_primary_key: c.is_primary_key,
373 primary_key_constraint_name: c.primary_key_constraint_name.clone(),
374 is_unique: c.is_unique,
375 unique_constraint_name: c.unique_constraint_name.clone(),
376 default: c.default.clone(),
377 generation: c.generation,
378 })
379 .collect();
380
381 let mut fk_mutations = Vec::new();
382 for fk in foreign_keys {
383 let to_table = Self::resolve_lookup_name(&fk.references, state);
384
385 fk_mutations.push(FkMutation {
386 constraint_name: fk.constraint_name.clone(),
387 to_table,
388 from_columns: fk.from_columns.clone(),
389 to_columns: fk.to_columns.clone(),
390 });
391 }
392
393 let partition_of_id = partition_of
394 .as_ref()
395 .map(|n| Self::resolve_lookup_name(n, state));
396
397 mutations.push(Mutation::CreateTable(CreateTable {
398 id,
399 if_not_exists: *if_not_exists,
400 as_select: *as_select,
401 persistence: resolved_persistence,
402 columns: col_mutations,
403 foreign_keys: fk_mutations,
404 table_constraints: table_constraints.clone(),
405 partition_by: partition_by.clone(),
406 partition_of: partition_of_id,
407 partition_type: partition_type.clone(),
408 }));
409 }
410 StatementFact::CreateView {
411 name,
412 or_replace,
413 depends_on,
414 } => {
415 let id = Self::resolve_creation_name(name, state);
416
417 let resolved_depends = depends_on
418 .iter()
419 .map(|n| Self::resolve_lookup_name(n, state))
420 .collect();
421
422 mutations.push(Mutation::CreateView(CreateView {
423 id,
424 or_replace: *or_replace,
425 depends_on: resolved_depends,
426 }));
427 }
428 StatementFact::AlterView { name, action } => {
429 match action {
430 crate::analysis::facts::AlterViewAction::RenameTo { new_name } => {
431 let id = Self::resolve_lookup_name(name, state);
432 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
433 new_id.inferred_schema = id.inferred_schema;
434 mutations.push(Mutation::Rename(Rename { old_id: id, new_id }));
435 }
436 crate::analysis::facts::AlterViewAction::SetSchema { new_schema } => {
437 let id = Self::resolve_lookup_name(name, state);
438 let new_id = ObjectId::new(new_schema, &id.name);
439 mutations.push(Mutation::Rename(Rename { old_id: id, new_id }));
440 }
441 crate::analysis::facts::AlterViewAction::OwnerTo { new_owner } => {
442 mutations.push(Mutation::ChangeRelationOwner {
443 id: Self::resolve_lookup_name(name, state),
444 new_owner: new_owner.clone(),
445 });
446 }
447 crate::analysis::facts::AlterViewAction::SetDefault { .. }
448 | crate::analysis::facts::AlterViewAction::DropDefault { .. }
449 | crate::analysis::facts::AlterViewAction::RenameColumn { .. }
450 | crate::analysis::facts::AlterViewAction::SetOptions { .. }
451 | crate::analysis::facts::AlterViewAction::ResetOptions { .. } => {
452 }
456 }
457 }
458 StatementFact::CreateMaterializedView { name, depends_on } => {
459 let id = Self::resolve_creation_name(name, state);
460
461 let resolved_depends = depends_on
462 .iter()
463 .map(|n| Self::resolve_lookup_name(n, state))
464 .collect();
465
466 mutations.push(Mutation::CreateMaterializedView(CreateMaterializedView {
467 id,
468 depends_on: resolved_depends,
469 }));
470 }
471 StatementFact::AlterMaterializedView { name, new_name } => {
472 if let Some(new_name) = new_name {
473 let id = Self::resolve_lookup_name(name, state);
474 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
475 new_id.inferred_schema = id.inferred_schema;
476 mutations.push(Mutation::Rename(Rename { old_id: id, new_id }));
477 }
478 }
479 StatementFact::RefreshMaterializedView { name, concurrently } => {
480 mutations.push(Mutation::RefreshMaterializedView(
481 RefreshMaterializedViewMutation {
482 id: Self::resolve_lookup_name(name, state),
483 concurrently: *concurrently,
484 },
485 ));
486 }
487 StatementFact::CreateIndex {
488 name,
489 relation,
490 if_not_exists,
491 concurrently,
492 using_method,
493 has_predicate,
494 unique,
495 } => {
496 let table = Self::resolve_lookup_name(relation, state);
497 let id = if name.schema.is_some() {
500 Self::resolve_creation_name(name, state)
501 } else {
502 ObjectId::new(table.schema.clone(), name.name.resolve())
503 };
504
505 mutations.push(Mutation::CreateIndex(CreateIndex {
506 id,
507 table,
508 if_not_exists: *if_not_exists,
509 concurrently: *concurrently,
510 using_method: using_method.clone(),
511 has_predicate: *has_predicate,
512 unique: *unique,
513 }));
514 }
515 StatementFact::CreatePolicy {
516 name,
517 table,
518 permissive,
519 command,
520 } => {
521 mutations.push(Mutation::CreatePolicy(CreatePolicyMutation {
522 name: name.clone(),
523 table: Self::resolve_lookup_name(table, state),
524 permissive: *permissive,
525 command: command.clone(),
526 }));
527 }
528 StatementFact::DropPolicy {
529 name,
530 table,
531 if_exists,
532 } => {
533 mutations.push(Mutation::DropPolicy(DropPolicyMutation {
534 name: name.clone(),
535 table: Self::resolve_lookup_name(table, state),
536 if_exists: *if_exists,
537 }));
538 }
539 StatementFact::CreateTrigger {
540 name,
541 table,
542 function,
543 } => {
544 let function_base = function
548 .as_ref()
549 .map(|f| Self::resolve_lookup_name(f, state))
550 .unwrap_or_else(|| ObjectId::new("public", "unknown_function"));
551 let function_id = Self::resolve_function_id_by_sig(&function_base, "");
552 mutations.push(Mutation::CreateTrigger(CreateTriggerMutation {
553 name: name.clone(),
554 table: Self::resolve_lookup_name(table, state),
555 function_id,
556 }));
557 }
558 StatementFact::DropTrigger {
559 name,
560 table,
561 if_exists,
562 } => {
563 mutations.push(Mutation::DropTrigger(DropTriggerMutation {
564 name: name.clone(),
565 table: Self::resolve_lookup_name(table, state),
566 if_exists: *if_exists,
567 }));
568 }
569 StatementFact::AlterTrigger {
570 name,
571 table,
572 new_name,
573 } => mutations.push(Mutation::RenameTrigger(RenameTriggerMutation {
574 name: name.clone(),
575 table: Self::resolve_lookup_name(table, state),
576 new_name: new_name.clone(),
577 })),
578 StatementFact::AlterIndex { name, actions } => {
579 let id = Self::resolve_lookup_name(name, state);
580 for action in actions {
581 match action {
582 AlterIndexActionFact::RenameTo { new_name } => {
583 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
584 new_id.inferred_schema = id.inferred_schema;
585 mutations.push(Mutation::Rename(Rename {
586 old_id: id.clone(),
587 new_id,
588 }));
589 }
590 }
591 }
592 }
593 StatementFact::CreateType(create_type) => {
594 let id = Self::resolve_creation_name(&create_type.name, state);
595
596 let mapped_kind = match &create_type.kind {
597 TypeCreationKind::Enum { variants } => TypeKind::Enum {
598 variants: variants.clone(),
599 },
600 TypeCreationKind::Range => TypeKind::Range,
601 TypeCreationKind::Composite => TypeKind::Composite,
602 TypeCreationKind::Base => TypeKind::Base,
603 };
604
605 mutations.push(Mutation::CreateType(CreateTypeMutation {
606 id,
607 kind: mapped_kind,
608 }));
609 }
610 StatementFact::AlterType(alter_type) => {
611 let id = Self::resolve_type_lookup_name(&alter_type.name, state);
612 for action_fact in &alter_type.actions {
613 match action_fact {
614 crate::analysis::facts::AlterTypeActionFact::RenameTo { new_name } => {
615 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
616 new_id.inferred_schema = id.inferred_schema;
617 mutations.push(Mutation::RenameType(Rename {
618 old_id: id.clone(),
619 new_id,
620 }));
621 }
622 crate::analysis::facts::AlterTypeActionFact::SetSchema { new_schema } => {
623 mutations.push(Mutation::RenameType(Rename {
624 old_id: id.clone(),
625 new_id: ObjectId::new(new_schema, &id.name),
626 }));
627 }
628 crate::analysis::facts::AlterTypeActionFact::AddValue {
629 new_value,
630 neighbor,
631 before,
632 } => {
633 mutations.push(Mutation::AlterType(AlterTypeMutation {
634 id: id.clone(),
635 action: AlterTypeActionMutation::AddValue {
636 new_value: new_value.clone(),
637 neighbor: neighbor.clone(),
638 before: *before,
639 },
640 }));
641 }
642 crate::analysis::facts::AlterTypeActionFact::RenameValue {
643 old_value,
644 new_value,
645 } => {
646 mutations.push(Mutation::AlterType(AlterTypeMutation {
647 id: id.clone(),
648 action: AlterTypeActionMutation::RenameValue {
649 old_value: old_value.clone(),
650 new_value: new_value.clone(),
651 },
652 }));
653 }
654 }
655 }
656 }
657 StatementFact::CreateDomain { name, base_type } => {
658 let id = Self::resolve_creation_name(name, state);
659
660 mutations.push(Mutation::CreateDomain(CreateDomainMutation {
661 id,
662 base_type: base_type.clone(),
663 }));
664 }
665 StatementFact::AlterDomain { name, action } => {
666 mutations.push(Mutation::AlterDomain(AlterDomainMutation {
667 id: Self::resolve_lookup_name(name, state),
668 action: action.clone(),
669 }));
670 }
671 StatementFact::DropDomain {
672 names,
673 if_exists,
674 cascade,
675 } => {
676 let ids = names
677 .iter()
678 .map(|n| Self::resolve_lookup_name(n, state))
679 .collect();
680 mutations.push(Mutation::DropDomain(DropDomainMutation {
681 ids,
682 if_exists: *if_exists,
683 cascade: *cascade,
684 }));
685 }
686 StatementFact::DropType {
687 names,
688 if_exists,
689 cascade,
690 } => {
691 let ids = names
692 .iter()
693 .map(|n| Self::resolve_lookup_name(n, state))
694 .collect();
695 mutations.push(Mutation::DropType(DropTypeMutation {
696 ids,
697 if_exists: *if_exists,
698 cascade: *cascade,
699 }));
700 }
701 StatementFact::CreateSequence {
702 name,
703 if_not_exists,
704 owned_by,
705 } => {
706 let id = Self::resolve_creation_name(name, state);
707
708 let resolved_owned_by = owned_by.as_ref().map(|(table_name, col)| {
709 (Self::resolve_lookup_name(table_name, state), col.clone())
710 });
711 mutations.push(Mutation::CreateSequence(CreateSequenceMutation {
712 id,
713 if_not_exists: *if_not_exists,
714 owned_by: resolved_owned_by,
715 }));
716 }
717 StatementFact::AlterSequence {
718 name,
719 if_exists,
720 action,
721 } => {
722 let id = Self::resolve_lookup_name(name, state);
723 let action = match action {
724 crate::analysis::facts::AlterSequenceActionFact::OwnedBy(owned_by) => {
725 AlterSequenceActionMutation::OwnedBy(owned_by.as_ref().map(
726 |(table_name, col)| {
727 (Self::resolve_lookup_name(table_name, state), col.clone())
728 },
729 ))
730 }
731 crate::analysis::facts::AlterSequenceActionFact::OwnerTo(owner) => {
732 AlterSequenceActionMutation::OwnerTo(owner.clone())
733 }
734 crate::analysis::facts::AlterSequenceActionFact::RenameTo(new_name) => {
735 AlterSequenceActionMutation::RenameTo(ObjectId::new(
736 &id.schema,
737 new_name.resolve(),
738 ))
739 }
740 crate::analysis::facts::AlterSequenceActionFact::SetSchema(schema) => {
741 AlterSequenceActionMutation::SetSchema(ObjectId::new(schema, &id.name))
742 }
743 crate::analysis::facts::AlterSequenceActionFact::Other => {
744 AlterSequenceActionMutation::Other
745 }
746 };
747 mutations.push(Mutation::AlterSequence(AlterSequenceMutation {
748 id,
749 if_exists: *if_exists,
750 action,
751 }));
752 }
753 StatementFact::DropSequence {
754 names,
755 if_exists,
756 cascade,
757 } => {
758 let ids = names
759 .iter()
760 .map(|n| Self::resolve_lookup_name(n, state))
761 .collect();
762 mutations.push(Mutation::DropSequence(DropSequenceMutation {
763 ids,
764 if_exists: *if_exists,
765 cascade: *cascade,
766 }));
767 }
768 StatementFact::AlterTable { name, actions } => {
769 let id = Self::resolve_lookup_name(name, state);
770 for action_fact in actions {
771 let action = match action_fact {
772 AlterTableActionFact::AddColumn {
773 name: col_name,
774 ty,
775 if_not_exists,
776 not_null,
777 default,
778 generation,
779 } => AlterTableActionMutation::AddColumn {
780 name: col_name.clone(),
781 ty: ty.clone(),
782 if_not_exists: *if_not_exists,
783 not_null: *not_null,
784 default: default.clone(),
785 depends_on: None, generation: *generation,
787 },
788 AlterTableActionFact::DropColumn {
789 name: col_name,
790 if_exists,
791 } => AlterTableActionMutation::DropColumn {
792 name: col_name.clone(),
793 if_exists: *if_exists,
794 },
795 AlterTableActionFact::RenameColumn { from, to } => {
796 AlterTableActionMutation::RenameColumn {
797 from: from.resolve(),
798 to: to.resolve(),
799 }
800 }
801 AlterTableActionFact::RenameTo { new_name } => {
802 let mut new_id = ObjectId::new(id.schema.clone(), new_name.resolve());
803 new_id.inferred_schema = id.inferred_schema;
804 mutations.push(Mutation::Rename(Rename {
805 old_id: id.clone(),
806 new_id,
807 }));
808 continue;
809 }
810 AlterTableActionFact::SetSchema { new_schema } => {
811 let new_id = ObjectId::new(new_schema, &id.name);
812 mutations.push(Mutation::Rename(Rename {
813 old_id: id.clone(),
814 new_id,
815 }));
816 continue;
817 }
818 AlterTableActionFact::AddForeignKey {
819 constraint_name,
820 references,
821 from_columns,
822 to_columns,
823 not_valid,
824 } => {
825 let to_table = Self::resolve_lookup_name(references, state);
826 if !state.relation_is_present(&to_table) {
827 return vec![Mutation::Opaque(
828 OpaqueMutation::UnresolvedReference {
829 object_kind: crate::report::violations::ObjectKind::Table,
830 object_name: to_table.to_string(),
831 },
832 )];
833 }
834 AlterTableActionMutation::AddForeignKey {
835 constraint_name: constraint_name.clone(),
836 to_table,
837 from_columns: from_columns.clone(),
838 to_columns: to_columns.clone(),
839 not_valid: *not_valid,
840 }
841 }
842 AlterTableActionFact::AlterConstraint {
843 name: c_name,
844 deferrable,
845 } => AlterTableActionMutation::AlterConstraint {
846 name: c_name.clone(),
847 deferrable: *deferrable,
848 },
849 AlterTableActionFact::RenameConstraint { old_name, new_name } => {
850 AlterTableActionMutation::RenameConstraint {
851 old_name: old_name.clone(),
852 new_name: new_name.clone(),
853 }
854 }
855 AlterTableActionFact::DropConstraint { name: c_name } => {
856 AlterTableActionMutation::DropConstraint {
857 name: c_name.clone(),
858 }
859 }
860 AlterTableActionFact::AddCheckConstraint {
861 constraint_name,
862 not_valid,
863 } => AlterTableActionMutation::AddCheckConstraint {
864 constraint_name: constraint_name.clone(),
865 not_valid: *not_valid,
866 },
867 AlterTableActionFact::AddUniqueConstraint {
868 constraint_name,
869 using_index,
870 } => AlterTableActionMutation::AddUniqueConstraint {
871 constraint_name: constraint_name.clone(),
872 using_index: using_index
873 .as_ref()
874 .map(|name| Self::resolve_constraint_index_name(name, &id)),
875 },
876 AlterTableActionFact::AddPrimaryKeyConstraint {
877 constraint_name,
878 using_index,
879 } => AlterTableActionMutation::AddPrimaryKeyConstraint {
880 constraint_name: constraint_name.clone(),
881 using_index: using_index
882 .as_ref()
883 .map(|name| Self::resolve_constraint_index_name(name, &id)),
884 },
885 AlterTableActionFact::AddExcludeConstraint { constraint_name } => {
886 AlterTableActionMutation::AddExcludeConstraint {
887 constraint_name: constraint_name.clone(),
888 }
889 }
890 AlterTableActionFact::SetNotNull { column } => {
891 AlterTableActionMutation::SetNotNull {
892 column: column.clone(),
893 }
894 }
895 AlterTableActionFact::DropNotNull { column } => {
896 AlterTableActionMutation::DropNotNull {
897 column: column.clone(),
898 }
899 }
900 AlterTableActionFact::SetType {
901 column,
902 ty,
903 has_using,
904 } => AlterTableActionMutation::SetType {
905 column: column.clone(),
906 ty: ty.clone(),
907 has_using: *has_using,
908 },
909 AlterTableActionFact::SetDefault { column, default } => {
910 AlterTableActionMutation::SetDefault {
911 column: column.clone(),
912 default: default.clone(),
913 }
914 }
915 AlterTableActionFact::ValidateConstraint { constraint_name } => {
916 AlterTableActionMutation::ValidateConstraint {
917 constraint_name: constraint_name.clone(),
918 }
919 }
920 AlterTableActionFact::AttachPartition { child, strategy } => {
921 let child_id = Self::resolve_lookup_name(child, state);
922
923 AlterTableActionMutation::AttachPartition {
924 child: child_id,
925 strategy: strategy.clone(),
926 }
927 }
928 AlterTableActionFact::DetachPartition { child } => {
929 AlterTableActionMutation::DetachPartition {
930 child: Self::resolve_lookup_name(child, state),
931 }
932 }
933 AlterTableActionFact::SetStorage { column } => {
934 AlterTableActionMutation::SetStorage {
935 column: column.clone(),
936 }
937 }
938 AlterTableActionFact::SetAccessMethod => {
939 AlterTableActionMutation::SetAccessMethod
940 }
941 AlterTableActionFact::DisableTrigger { trigger_name } => {
942 AlterTableActionMutation::DisableTrigger {
943 trigger_name: trigger_name.clone(),
944 }
945 }
946 AlterTableActionFact::EnableTrigger { trigger_name } => {
947 AlterTableActionMutation::EnableTrigger {
948 trigger_name: trigger_name.clone(),
949 }
950 }
951 AlterTableActionFact::SetExpression { .. }
952 | AlterTableActionFact::SetOptions { .. }
953 | AlterTableActionFact::Inherit { .. }
954 | AlterTableActionFact::NoInherit { .. }
955 | AlterTableActionFact::ClusterOn { .. }
956 | AlterTableActionFact::InheritTable { .. }
957 | AlterTableActionFact::NoInheritTable { .. }
958 | AlterTableActionFact::MergePartitions { .. }
959 | AlterTableActionFact::SplitPartition
960 | AlterTableActionFact::SetTablespace { .. }
961 | AlterTableActionFact::SetLogged
962 | AlterTableActionFact::SetUnlogged
963 | AlterTableActionFact::ReplicaIdentity { .. }
964 | AlterTableActionFact::ForceRls
965 | AlterTableActionFact::EnableRls
966 | AlterTableActionFact::DisableRls
967 | AlterTableActionFact::EnableAlwaysTrigger { .. }
968 | AlterTableActionFact::EnableReplicaTrigger { .. } => {
969 AlterTableActionMutation::Opaque
970 }
971 AlterTableActionFact::OwnerTo { new_owner } => {
972 AlterTableActionMutation::OwnerTo {
973 new_owner: new_owner.clone(),
974 }
975 }
976 };
977 mutations.push(Mutation::AlterTable(AlterTable {
978 id: id.clone(),
979 action,
980 }));
981 }
982 }
983 StatementFact::DropTable {
984 name,
985 if_exists,
986 cascade,
987 } => {
988 let id = Self::resolve_lookup_name(name, state);
989
990 mutations.push(Mutation::DropTable(DropTable {
994 id,
995 if_exists: *if_exists,
996 cascade: *cascade,
997 }));
998 }
999 StatementFact::DropView {
1000 name,
1001 if_exists,
1002 cascade,
1003 } => {
1004 mutations.push(Mutation::DropView(DropViewMutation {
1005 ids: vec![Self::resolve_lookup_name(name, state)],
1006 if_exists: *if_exists,
1007 cascade: *cascade,
1008 }));
1009 }
1010 StatementFact::DropMaterializedView {
1011 names,
1012 if_exists,
1013 cascade,
1014 } => {
1015 let ids = names
1016 .iter()
1017 .map(|n| Self::resolve_lookup_name(n, state))
1018 .collect();
1019 mutations.push(Mutation::DropMaterializedView(
1020 DropMaterializedViewMutation {
1021 ids,
1022 if_exists: *if_exists,
1023 cascade: *cascade,
1024 },
1025 ));
1026 }
1027 StatementFact::DropIndex {
1028 names,
1029 if_exists,
1030 concurrently,
1031 } => {
1032 for name in names {
1033 mutations.push(Mutation::DropIndex(DropIndex {
1034 id: Self::resolve_lookup_name(name, state),
1035 if_exists: *if_exists,
1036 concurrently: *concurrently,
1037 }));
1038 }
1039 }
1040 StatementFact::SetSearchPath { target, local } => {
1041 mutations.push(Mutation::SearchPath(SearchPathChange {
1042 target: target.clone(),
1043 local: *local,
1044 }))
1045 }
1046 StatementFact::SetTimeout {
1047 setting,
1048 value,
1049 local,
1050 } => mutations.push(Mutation::TimeoutSetting(TimeoutSettingChange {
1051 setting: *setting,
1052 value: value.clone(),
1053 local: *local,
1054 })),
1055 StatementFact::ResetSettings { target } => {
1056 mutations.push(Mutation::ResetSettings(*target))
1057 }
1058 StatementFact::BeginTransaction => mutations.push(Mutation::BeginTransaction),
1059 StatementFact::CommitTransaction => mutations.push(Mutation::CommitTransaction),
1060 StatementFact::CommitAndChain => mutations.push(Mutation::CommitAndChain),
1061 StatementFact::RollbackTransaction => mutations.push(Mutation::RollbackTransaction),
1062 StatementFact::RollbackAndChain => mutations.push(Mutation::RollbackAndChain),
1063 StatementFact::RollbackToSavepoint { name } => {
1064 mutations.push(Mutation::RollbackToSavepoint(RollbackToSavepointMutation {
1065 name: name.clone(),
1066 }))
1067 }
1068 StatementFact::Savepoint { name } => {
1069 mutations.push(Mutation::Savepoint(SavepointMutation {
1070 name: name.clone(),
1071 }))
1072 }
1073 StatementFact::ReleaseSavepoint { name } => {
1074 mutations.push(Mutation::ReleaseSavepoint(ReleaseSavepointMutation {
1075 name: name.clone(),
1076 }))
1077 }
1078 StatementFact::PrepareTransaction { .. } => {
1079 mutations.push(Mutation::Opaque(OpaqueMutation::PrepareTransaction))
1080 }
1081 StatementFact::SetTransaction => {
1082 mutations.push(Mutation::Opaque(OpaqueMutation::SetTransaction))
1083 }
1084 StatementFact::SetConstraints => {
1085 mutations.push(Mutation::Opaque(OpaqueMutation::SetConstraints))
1086 }
1087 StatementFact::OpaqueBlock => mutations.push(Mutation::Opaque(OpaqueMutation::DoBlock)),
1088 StatementFact::Execute => mutations.push(Mutation::Opaque(OpaqueMutation::Execute)),
1089 StatementFact::Vacuum { relation, is_full } => {
1090 let table_id = relation
1091 .as_ref()
1092 .map(|r| Self::resolve_lookup_name(r, state));
1093 mutations.push(Mutation::Vacuum {
1094 table_id,
1095 is_full: *is_full,
1096 })
1097 }
1098 StatementFact::CreateFunction(f) => {
1099 let id = Self::resolve_function_id(&f.name, &f.params, state);
1100 mutations.push(Mutation::CreateFunction(CreateFunctionMutation {
1101 id,
1102 or_replace: f.or_replace,
1103 params: f.params.clone(),
1104 return_type: f.return_type.clone(),
1105 options: f.options.clone(),
1106 }));
1107 }
1108 StatementFact::AlterFunction(f) => {
1109 let base_id = Self::resolve_lookup_name(&f.name, state);
1110 let sig = f.params.join(",");
1111 let id = Self::resolve_function_id_by_sig(&base_id, &sig);
1112 mutations.push(Mutation::AlterFunction(AlterFunctionMutation {
1113 id,
1114 action: f.action.clone(),
1115 }));
1116 }
1117 StatementFact::DropFunction(f) => {
1118 let mut signatures = Vec::new();
1119 for sig in &f.signatures {
1120 let mut normalized_sig = sig.clone();
1121 normalized_sig.params = normalized_sig
1122 .params
1123 .into_iter()
1124 .map(|p| Self::normalize_function_arg_type(&p))
1125 .collect();
1126 signatures.push(normalized_sig);
1127 }
1128 mutations.push(Mutation::DropFunction(DropFunctionMutation {
1129 signatures,
1130 if_exists: f.if_exists,
1131 cascade: f.cascade,
1132 }));
1133 }
1134 StatementFact::CreateProcedure(p) => {
1135 let id = Self::resolve_function_id(&p.name, &p.params, state);
1136 mutations.push(Mutation::CreateProcedure(CreateProcedureMutation {
1137 id,
1138 or_replace: p.or_replace,
1139 params: p.params.clone(),
1140 options: p.options.clone(),
1141 }));
1142 }
1143 StatementFact::AlterProcedure(p) => {
1144 let base_id = Self::resolve_lookup_name(&p.name, state);
1145 let sig = p
1146 .params
1147 .iter()
1148 .map(|p| p.to_string())
1149 .collect::<Vec<_>>()
1150 .join(",");
1151 let id = Self::resolve_function_id_by_sig(&base_id, &sig);
1152 mutations.push(Mutation::AlterProcedure(AlterProcedureMutation {
1153 id,
1154 action: p.action.clone(),
1155 }));
1156 }
1157 StatementFact::DropProcedure(p) => {
1158 let signatures = p
1159 .signatures
1160 .iter()
1161 .cloned()
1162 .map(|mut signature| {
1163 signature.params = signature
1164 .params
1165 .into_iter()
1166 .map(|param| Self::normalize_function_arg_type(¶m))
1167 .collect();
1168 signature
1169 })
1170 .collect();
1171 mutations.push(Mutation::DropProcedure(DropProcedureMutation {
1172 signatures,
1173 if_exists: p.if_exists,
1174 cascade: p.cascade,
1175 }));
1176 }
1177 StatementFact::CreateAggregate(a) => {
1178 let id = Self::resolve_function_id(&a.name, &a.params, state);
1179 mutations.push(Mutation::CreateAggregate(CreateAggregateMutation {
1180 id,
1181 or_replace: a.or_replace,
1182 params: a.params.clone(),
1183 }));
1184 }
1185 StatementFact::AlterAggregate(a) => {
1186 let base_id = Self::resolve_lookup_name(&a.name, state);
1187 let signature = a
1188 .params
1189 .iter()
1190 .map(|param| Self::normalize_function_arg_type(param))
1191 .collect::<Vec<_>>()
1192 .join(",");
1193 let id = Self::resolve_function_id_by_sig(&base_id, &signature);
1194 mutations.push(Mutation::AlterAggregate(AlterAggregateMutation {
1195 id,
1196 action: a.action.clone(),
1197 }));
1198 }
1199 StatementFact::DropAggregate(a) => {
1200 let signatures = a
1201 .signatures
1202 .iter()
1203 .cloned()
1204 .map(|mut signature| {
1205 signature.params = signature
1206 .params
1207 .into_iter()
1208 .map(|param| Self::normalize_function_arg_type(¶m))
1209 .collect();
1210 signature
1211 })
1212 .collect();
1213 mutations.push(Mutation::DropAggregate(DropAggregateMutation {
1214 signatures,
1215 if_exists: a.if_exists,
1216 cascade: a.cascade,
1217 }));
1218 }
1219 StatementFact::CreatePublication(p) => {
1220 mutations.push(Mutation::CreatePublication(CreatePublicationMutation {
1221 name: p.name.clone(),
1222 scope: Self::resolve_publication_scope(&p.scope, state),
1223 params: p.params.clone(),
1224 }));
1225 }
1226 StatementFact::AlterPublication(p) => {
1227 mutations.push(Mutation::AlterPublication(AlterPublicationMutation {
1228 name: p.name.clone(),
1229 action: Self::resolve_alter_publication_action(&p.action, state),
1230 }));
1231 }
1232 StatementFact::DropPublication(p) => {
1233 mutations.push(Mutation::DropPublication(DropPublicationMutation {
1234 names: p.names.clone(),
1235 if_exists: p.if_exists,
1236 cascade: p.cascade,
1237 }));
1238 }
1239 StatementFact::CreateSubscription(s) => {
1240 mutations.push(Mutation::CreateSubscription(CreateSubscriptionMutation {
1241 name: s.name.clone(),
1242 connection: s.connection.clone(),
1243 publications: s.publications.clone(),
1244 params: s.params.clone(),
1245 }));
1246 }
1247 StatementFact::AlterSubscription(s) => {
1248 mutations.push(Mutation::AlterSubscription(AlterSubscriptionMutation {
1249 name: s.name.clone(),
1250 action: s.action.clone(),
1251 }));
1252 }
1253 StatementFact::DropSubscription(s) => {
1254 mutations.push(Mutation::DropSubscription(DropSubscriptionMutation {
1255 name: s.name.clone(),
1256 if_exists: s.if_exists,
1257 }));
1258 }
1259 StatementFact::CreateRole(r) => {
1260 mutations.push(Mutation::CreateRole(CreateRoleMutation {
1261 name: r.name.clone(),
1262 inherits: r.inherits,
1263 can_login: r.can_login,
1264 }));
1265 }
1266 StatementFact::AlterRole(r) => {
1267 mutations.push(Mutation::AlterRole(AlterRoleMutation {
1268 name: r.name.clone(),
1269 inherits: r.inherits,
1270 }));
1271 }
1272 StatementFact::DropRole(r) => {
1273 mutations.push(Mutation::DropRole(DropRoleMutation {
1274 names: r.names.clone(),
1275 if_exists: r.if_exists,
1276 }));
1277 }
1278 StatementFact::Grant(g) => {
1279 mutations.push(Mutation::Grant(GrantMutation {
1280 privileges: g.privileges.clone(),
1281 target: Self::resolve_grant_target(&g.target, state),
1282 grantees: g.grantees.clone(),
1283 with_grant_option: g.with_grant_option,
1284 granted_by: g.granted_by.clone(),
1285 }));
1286 }
1287 StatementFact::Revoke(r) => {
1288 mutations.push(Mutation::Revoke(RevokeMutation {
1289 grant_option_only: r.grant_option_only,
1290 privileges: r.privileges.clone(),
1291 target: Self::resolve_grant_target(&r.target, state),
1292 revokees: r.revokees.clone(),
1293 granted_by: r.granted_by.clone(),
1294 cascade: r.cascade,
1295 }));
1296 }
1297 StatementFact::CreateDatabase(d) => {
1298 mutations.push(Mutation::CreateDatabase(CreateDatabaseMutation {
1299 name: d.name.clone(),
1300 options: d.options.clone(),
1301 }));
1302 }
1303 StatementFact::AlterDatabase(d) => {
1304 let id = Self::resolve_lookup_name(&d.name, state);
1305 mutations.push(Mutation::AlterDatabase(AlterDatabaseMutation {
1306 id,
1307 action: d.action.clone(),
1308 }));
1309 }
1310 StatementFact::DropDatabase(d) => {
1311 let id = Self::resolve_lookup_name(&d.name, state);
1312 mutations.push(Mutation::DropDatabase(DropDatabaseMutation {
1313 id,
1314 if_exists: d.if_exists,
1315 }));
1316 }
1317 StatementFact::SetRole {
1318 role,
1319 local,
1320 is_session_auth,
1321 } => {
1322 mutations.push(Mutation::SwitchRole {
1323 role: role.clone(),
1324 local: *local,
1325 is_session_auth: *is_session_auth,
1326 });
1327 }
1328 }
1329 mutations
1330 }
1331}