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