Skip to main content

safe_migrate/analysis/
mutations.rs

1use crate::analysis::expr_ir::ExprIr;
2use crate::analysis::facts::{
3    ResetSettingTarget, SearchPathTarget, TableConstraintFact, TimeoutSetting, TimeoutSettingValue,
4};
5use crate::ast::identifiers::ObjectId;
6use crate::model::types::TypeKind;
7
8#[derive(Clone, Debug, PartialEq)]
9pub enum PersistenceMutation {
10    Permanent,
11    Temporary,
12    Unlogged,
13}
14
15#[derive(Clone, Debug, PartialEq)]
16pub enum Mutation {
17    CreateSchema(CreateSchemaMutation),
18    AlterSchema(AlterSchemaMutation),
19    DropSchema(DropSchemaMutation),
20    CreateTable(CreateTable),
21    CreateView(CreateView),
22    CreateMaterializedView(CreateMaterializedView),
23    RefreshMaterializedView(RefreshMaterializedViewMutation),
24    CreateIndex(CreateIndex),
25    CreatePolicy(CreatePolicyMutation),
26    DropPolicy(DropPolicyMutation),
27    CreateTrigger(CreateTriggerMutation),
28    DropTrigger(DropTriggerMutation),
29    RenameTrigger(RenameTriggerMutation),
30    AlterTable(AlterTable),
31    CreateType(CreateTypeMutation),
32    AlterType(AlterTypeMutation),
33    RenameType(Rename),
34    CreateDomain(CreateDomainMutation),
35    AlterDomain(AlterDomainMutation),
36    DropDomain(DropDomainMutation),
37    DropType(DropTypeMutation),
38    CreateSequence(CreateSequenceMutation),
39    AlterSequence(AlterSequenceMutation),
40    DropSequence(DropSequenceMutation),
41    Rename(Rename),
42    DropTable(DropTable),
43    DropView(DropViewMutation),
44    DropMaterializedView(DropMaterializedViewMutation),
45    DropIndex(DropIndex),
46    ChangeRelationOwner {
47        id: ObjectId,
48        new_owner: crate::analysis::facts::RoleFact,
49    },
50    SearchPath(SearchPathChange),
51    TimeoutSetting(TimeoutSettingChange),
52    ResetSettings(ResetSettingTarget),
53    /// Statement-scoped no-op evaluated after real mutations so timeout
54    /// rules do not report on statements PostgreSQL would not execute.
55    CheckTimeouts,
56    BeginTransaction,
57    CommitTransaction,
58    CommitAndChain,
59    RollbackTransaction,
60    RollbackAndChain,
61    RollbackToSavepoint(RollbackToSavepointMutation),
62    Savepoint(SavepointMutation),
63    ReleaseSavepoint(ReleaseSavepointMutation),
64    CreateFunction(CreateFunctionMutation),
65    AlterFunction(AlterFunctionMutation),
66    DropFunction(DropFunctionMutation),
67    CreateProcedure(CreateProcedureMutation),
68    AlterProcedure(AlterProcedureMutation),
69    DropProcedure(DropProcedureMutation),
70    CreateAggregate(CreateAggregateMutation),
71    AlterAggregate(AlterAggregateMutation),
72    DropAggregate(DropAggregateMutation),
73    CreatePublication(CreatePublicationMutation),
74    AlterPublication(AlterPublicationMutation),
75    DropPublication(DropPublicationMutation),
76    CreateSubscription(CreateSubscriptionMutation),
77    AlterSubscription(AlterSubscriptionMutation),
78    DropSubscription(DropSubscriptionMutation),
79    CreateRole(CreateRoleMutation),
80    AlterRole(AlterRoleMutation),
81    DropRole(DropRoleMutation),
82    Grant(GrantMutation),
83    Revoke(RevokeMutation),
84    CreateDatabase(CreateDatabaseMutation),
85    AlterDatabase(AlterDatabaseMutation),
86    DropDatabase(DropDatabaseMutation),
87    /// Produced by `SET [LOCAL] ROLE` and `SET [LOCAL] SESSION AUTHORIZATION`.
88    /// `role = None` means ROLE NONE / SESSION AUTHORIZATION DEFAULT.
89    /// `local = true` means the active value expires at transaction end.
90    SwitchRole {
91        role: Option<crate::analysis::facts::RoleFact>,
92        local: bool,
93        is_session_auth: bool,
94    },
95    Opaque(OpaqueMutation),
96    Vacuum {
97        table_id: Option<ObjectId>,
98        is_full: bool,
99    },
100}
101
102#[derive(Clone, Debug, PartialEq)]
103pub struct CreateSchemaMutation {
104    pub name: String,
105    pub if_not_exists: bool,
106    pub authorization: Option<crate::analysis::facts::RoleFact>,
107}
108
109#[derive(Clone, Debug, PartialEq)]
110pub enum AlterSchemaMutation {
111    Rename {
112        old_name: String,
113        new_name: String,
114    },
115    OwnerTo {
116        name: String,
117        new_owner: crate::analysis::facts::RoleFact,
118    },
119}
120
121#[derive(Clone, Debug, PartialEq)]
122pub struct DropSchemaMutation {
123    pub names: Vec<String>,
124    pub if_exists: bool,
125    pub cascade: bool,
126}
127
128#[derive(Clone, Debug, PartialEq)]
129pub struct CreatePolicyMutation {
130    pub name: String,
131    pub table: ObjectId,
132    pub permissive: bool,
133    pub command: crate::analysis::facts::PolicyCommand,
134    pub semantics_complete: bool,
135}
136
137#[derive(Clone, Debug, PartialEq)]
138pub struct DropPolicyMutation {
139    pub name: String,
140    pub table: ObjectId,
141    pub if_exists: bool,
142}
143
144#[derive(Clone, Debug, PartialEq)]
145pub struct CreateTriggerMutation {
146    pub name: String,
147    pub table: ObjectId,
148    pub function_id: ObjectId,
149}
150
151#[derive(Clone, Debug, PartialEq)]
152pub struct DropTriggerMutation {
153    pub name: String,
154    pub table: ObjectId,
155    pub if_exists: bool,
156}
157
158#[derive(Clone, Debug, PartialEq)]
159pub struct RenameTriggerMutation {
160    pub name: String,
161    pub table: ObjectId,
162    pub new_name: String,
163}
164
165#[derive(Clone, Debug, PartialEq)]
166pub struct DropViewMutation {
167    pub ids: Vec<ObjectId>,
168    pub if_exists: bool,
169    pub cascade: bool,
170}
171
172#[derive(Clone, Debug, PartialEq)]
173pub struct DropMaterializedViewMutation {
174    pub ids: Vec<ObjectId>,
175    pub if_exists: bool,
176    pub cascade: bool,
177}
178
179#[derive(Clone, Debug, PartialEq)]
180pub struct CreateMaterializedView {
181    pub id: ObjectId,
182    pub depends_on: Vec<ObjectId>,
183}
184
185#[derive(Clone, Debug, PartialEq)]
186pub struct RefreshMaterializedViewMutation {
187    pub id: ObjectId,
188    pub concurrently: bool,
189}
190
191#[derive(Clone, Debug, PartialEq)]
192pub struct CreateSequenceMutation {
193    pub id: ObjectId,
194    pub if_not_exists: bool,
195    pub owned_by: Option<(ObjectId, String)>,
196}
197
198#[derive(Clone, Debug, PartialEq)]
199pub struct AlterSequenceMutation {
200    pub id: ObjectId,
201    pub if_exists: bool,
202    pub action: AlterSequenceActionMutation,
203}
204
205#[derive(Clone, Debug, PartialEq)]
206pub enum AlterSequenceActionMutation {
207    OwnedBy(Option<(ObjectId, String)>),
208    OwnerTo(crate::analysis::facts::RoleFact),
209    RenameTo(ObjectId),
210    SetSchema(ObjectId),
211    Other,
212}
213
214#[derive(Clone, Debug, PartialEq)]
215pub struct DropSequenceMutation {
216    pub ids: Vec<ObjectId>,
217    pub if_exists: bool,
218    pub cascade: bool,
219}
220
221#[derive(Clone, Debug, PartialEq)]
222pub struct CreateDomainMutation {
223    pub id: ObjectId,
224    pub base_type: String,
225}
226
227#[derive(Clone, Debug, PartialEq)]
228pub struct AlterDomainMutation {
229    pub id: ObjectId,
230    pub action: Option<crate::analysis::facts::AlterDomainActionFact>,
231}
232
233#[derive(Clone, Debug, PartialEq)]
234pub struct DropDomainMutation {
235    pub ids: Vec<ObjectId>,
236    pub if_exists: bool,
237    pub cascade: bool,
238}
239
240#[derive(Clone, Debug, PartialEq)]
241pub struct DropTypeMutation {
242    pub ids: Vec<ObjectId>,
243    pub if_exists: bool,
244    pub cascade: bool,
245}
246
247#[derive(Clone, Debug, PartialEq)]
248pub struct CreateTypeMutation {
249    pub id: ObjectId,
250    pub kind: TypeKind,
251}
252
253#[derive(Clone, Debug, PartialEq)]
254pub struct AlterTypeMutation {
255    pub id: ObjectId,
256    pub action: AlterTypeActionMutation,
257}
258
259#[derive(Clone, Debug, PartialEq)]
260pub enum AlterTypeActionMutation {
261    AddValue {
262        new_value: String,
263        neighbor: Option<String>,
264        before: bool,
265    },
266    RenameValue {
267        old_value: String,
268        new_value: String,
269    },
270}
271
272#[derive(Clone, Debug, PartialEq)]
273pub struct CreateTable {
274    pub id: ObjectId,
275    pub if_not_exists: bool,
276    pub as_select: bool,
277    pub persistence: PersistenceMutation,
278    pub columns: Vec<ColumnMutation>,
279    pub foreign_keys: Vec<FkMutation>,
280    pub table_constraints: Vec<TableConstraintFact>,
281    pub partition_by: Option<String>,
282    pub partition_of: Option<ObjectId>,
283    pub partition_type: Option<String>,
284}
285
286#[derive(Clone, Debug, PartialEq)]
287pub struct ColumnMutation {
288    pub name: String,
289    pub ty: Option<String>,
290    pub not_null: bool,
291    pub is_primary_key: bool,
292    pub primary_key_constraint_name: Option<String>,
293    pub is_unique: bool,
294    pub unique_constraint_name: Option<String>,
295    pub default: Option<ExprIr>,
296    pub generation: crate::analysis::facts::ColumnGeneration,
297}
298
299#[derive(Clone, Debug, PartialEq)]
300pub struct FkMutation {
301    pub constraint_name: Option<String>,
302    pub to_table: ObjectId,
303    pub from_columns: Vec<String>,
304    pub to_columns: Vec<String>,
305}
306
307#[derive(Clone, Debug, PartialEq)]
308pub struct CreateView {
309    pub id: ObjectId,
310    pub or_replace: bool,
311    pub depends_on: Vec<ObjectId>,
312}
313
314#[derive(Clone, Debug, PartialEq)]
315pub struct CreateIndex {
316    pub id: ObjectId,
317    pub table: ObjectId,
318    pub if_not_exists: bool,
319    pub concurrently: bool,
320    pub using_method: Option<String>,
321    pub has_predicate: bool,
322    pub unique: bool,
323}
324
325#[derive(Clone, Debug, PartialEq)]
326pub struct AlterTable {
327    pub id: ObjectId,
328    pub action: AlterTableActionMutation,
329}
330
331#[derive(Clone, Debug, PartialEq)]
332pub struct Rename {
333    pub old_id: ObjectId,
334    pub new_id: ObjectId,
335}
336
337#[derive(Clone, Debug, PartialEq)]
338pub struct DropTable {
339    pub ids: Vec<ObjectId>,
340    pub if_exists: bool,
341    pub cascade: bool,
342}
343
344#[derive(Clone, Debug, PartialEq)]
345pub struct DropIndex {
346    pub ids: Vec<ObjectId>,
347    pub if_exists: bool,
348    pub concurrently: bool,
349    pub cascade: bool,
350}
351
352#[derive(Clone, Debug, PartialEq)]
353pub struct SearchPathChange {
354    pub target: SearchPathTarget,
355    pub local: bool,
356}
357
358#[derive(Clone, Debug, PartialEq)]
359pub struct TimeoutSettingChange {
360    pub setting: TimeoutSetting,
361    pub value: TimeoutSettingValue,
362    pub local: bool,
363}
364
365#[derive(Clone, Debug, PartialEq)]
366pub struct SavepointMutation {
367    pub name: String,
368}
369
370#[derive(Clone, Debug, PartialEq)]
371pub struct ReleaseSavepointMutation {
372    pub name: String,
373}
374
375#[derive(Clone, Debug, PartialEq)]
376pub struct RollbackToSavepointMutation {
377    pub name: String,
378}
379
380#[derive(Clone, Debug, PartialEq)]
381pub struct CreateFunctionMutation {
382    pub id: ObjectId,
383    pub or_replace: bool,
384    pub params: Vec<crate::analysis::facts::ParamFact>,
385    pub return_type: Option<crate::analysis::facts::RetTypeFact>,
386    pub options: Vec<crate::analysis::facts::FuncOptionFact>,
387}
388
389#[derive(Clone, Debug, PartialEq)]
390pub struct AlterFunctionMutation {
391    pub id: ObjectId,
392    pub action: crate::analysis::facts::AlterFunctionAction,
393}
394
395#[derive(Clone, Debug, PartialEq)]
396pub struct DropFunctionMutation {
397    pub signatures: Vec<crate::analysis::facts::FunctionSigFact>,
398    pub if_exists: bool,
399    pub cascade: bool,
400}
401
402#[derive(Clone, Debug, PartialEq)]
403pub struct CreateProcedureMutation {
404    pub id: ObjectId,
405    pub or_replace: bool,
406    pub params: Vec<crate::analysis::facts::ParamFact>,
407    pub options: Vec<crate::analysis::facts::FuncOptionFact>,
408}
409
410#[derive(Clone, Debug, PartialEq)]
411pub struct AlterProcedureMutation {
412    pub id: ObjectId,
413    pub action: crate::analysis::facts::AlterFunctionAction,
414}
415
416#[derive(Clone, Debug, PartialEq)]
417pub struct DropProcedureMutation {
418    pub signatures: Vec<crate::analysis::facts::FunctionSigFact>,
419    pub if_exists: bool,
420    pub cascade: bool,
421}
422
423#[derive(Clone, Debug, PartialEq)]
424pub struct CreateAggregateMutation {
425    pub id: ObjectId,
426    pub or_replace: bool,
427    pub params: Vec<crate::analysis::facts::ParamFact>,
428}
429
430#[derive(Clone, Debug, PartialEq)]
431pub struct AlterAggregateMutation {
432    pub id: ObjectId,
433    pub action: crate::analysis::facts::AlterFunctionAction,
434}
435
436#[derive(Clone, Debug, PartialEq)]
437pub struct DropAggregateMutation {
438    pub signatures: Vec<crate::analysis::facts::FunctionSigFact>,
439    pub if_exists: bool,
440    pub cascade: bool,
441}
442
443#[derive(Clone, Debug, PartialEq)]
444pub struct CreatePublicationMutation {
445    pub name: String,
446    pub scope: crate::analysis::facts::PublicationScope,
447    pub params: Vec<crate::analysis::facts::AttributeFact>,
448}
449
450#[derive(Clone, Debug, PartialEq)]
451pub struct AlterPublicationMutation {
452    pub name: String,
453    pub action: crate::analysis::facts::AlterPublicationActionFact,
454}
455
456#[derive(Clone, Debug, PartialEq)]
457pub struct DropPublicationMutation {
458    pub names: Vec<String>,
459    pub if_exists: bool,
460    pub cascade: bool,
461}
462
463#[derive(Clone, Debug, PartialEq)]
464pub struct CreateSubscriptionMutation {
465    pub name: Option<String>,
466    pub connection: crate::analysis::facts::ConnectionTarget,
467    pub publications: Vec<String>,
468    pub params: Option<Vec<crate::analysis::facts::AttributeFact>>,
469}
470
471#[derive(Clone, Debug, PartialEq)]
472pub struct AlterSubscriptionMutation {
473    pub name: String,
474    pub action: crate::analysis::facts::AlterSubscriptionActionFact,
475}
476
477#[derive(Clone, Debug, PartialEq)]
478pub struct DropSubscriptionMutation {
479    pub name: String,
480    pub if_exists: bool,
481}
482
483#[derive(Clone, Debug, PartialEq)]
484pub struct CreateRoleMutation {
485    pub name: String,
486    pub inherits: bool,
487    pub can_login: bool,
488}
489
490#[derive(Clone, Debug, PartialEq)]
491pub struct AlterRoleMutation {
492    pub name: crate::analysis::facts::RoleFact,
493    pub inherits: Option<bool>,
494}
495
496#[derive(Clone, Debug, PartialEq)]
497pub struct DropRoleMutation {
498    pub names: Vec<String>,
499    pub if_exists: bool,
500}
501
502#[derive(Clone, Debug, PartialEq)]
503pub enum ResolvedGrantTarget {
504    Tables(Vec<ObjectId>),
505    AllTablesInSchema(Vec<String>),
506}
507
508#[derive(Clone, Debug, PartialEq)]
509pub struct GrantMutation {
510    pub privileges: crate::analysis::facts::PrivilegeSpec,
511    pub target: ResolvedGrantTarget,
512    pub grantees: Vec<crate::analysis::facts::RoleFact>,
513    pub with_grant_option: bool,
514    pub granted_by: Option<crate::analysis::facts::RoleFact>,
515}
516
517#[derive(Clone, Debug, PartialEq)]
518pub struct RevokeMutation {
519    pub grant_option_only: bool,
520    pub privileges: crate::analysis::facts::PrivilegeSpec,
521    pub target: ResolvedGrantTarget,
522    pub revokees: Vec<crate::analysis::facts::RoleFact>,
523    pub granted_by: Option<crate::analysis::facts::RoleFact>,
524    pub cascade: bool,
525}
526
527#[derive(Clone, Debug, PartialEq)]
528pub struct CreateDatabaseMutation {
529    pub name: String,
530    pub options: Vec<crate::analysis::facts::DatabaseOptionFact>,
531}
532
533#[derive(Clone, Debug, PartialEq)]
534pub struct AlterDatabaseMutation {
535    pub id: ObjectId,
536    pub action: crate::analysis::facts::AlterDatabaseAction,
537}
538
539#[derive(Clone, Debug, PartialEq)]
540pub struct DropDatabaseMutation {
541    pub id: ObjectId,
542    pub if_exists: bool,
543}
544
545#[derive(Clone, Debug, PartialEq)]
546pub enum OpaqueMutation {
547    /// Squawk accepted the statement but safe-migrate has no typed extractor
548    /// for it. Treating it as a no-op would leave later analysis falsely exact.
549    UnsupportedStatement,
550    DoBlock,
551    Execute,
552    DynamicSql,
553    PrepareTransaction,
554    SetTransaction,
555    SetConstraints,
556    StateCollision(String),
557    UnresolvedReference {
558        object_kind: crate::report::violations::ObjectKind,
559        object_name: String,
560    },
561}
562
563#[derive(Clone, Debug, PartialEq)]
564pub enum AlterTableActionMutation {
565    AddColumn {
566        name: String,
567        ty: Option<String>,
568        if_not_exists: bool,
569        not_null: bool,
570        default: Option<ExprIr>,
571        depends_on: Option<(ObjectId, String)>,
572        generation: crate::analysis::facts::ColumnGeneration,
573    },
574    DropColumn {
575        name: String,
576        if_exists: bool,
577        cascade: bool,
578    },
579    RenameColumn {
580        from: String,
581        to: String,
582    },
583    AddForeignKey {
584        constraint_name: Option<String>,
585        to_table: ObjectId,
586        from_columns: Vec<String>,
587        to_columns: Vec<String>,
588        not_valid: bool,
589    },
590    AlterConstraint {
591        name: Option<String>,
592        deferrable: bool,
593    },
594    RenameConstraint {
595        old_name: String,
596        new_name: String,
597    },
598    DropConstraint {
599        name: String,
600        if_exists: bool,
601        cascade: bool,
602    },
603    AddCheckConstraint {
604        constraint_name: Option<String>,
605        not_valid: bool,
606    },
607    AddUniqueConstraint {
608        constraint_name: Option<String>,
609        columns: Vec<String>,
610        using_index: Option<ObjectId>,
611    },
612    AddPrimaryKeyConstraint {
613        constraint_name: Option<String>,
614        columns: Vec<String>,
615        using_index: Option<ObjectId>,
616    },
617    AddExcludeConstraint {
618        constraint_name: Option<String>,
619    },
620    SetNotNull {
621        column: String,
622    },
623    DropNotNull {
624        column: String,
625    },
626    SetType {
627        column: String,
628        ty: String,
629        has_using: bool,
630    },
631    SetDefault {
632        column: String,
633        default: Option<ExprIr>,
634    },
635    ValidateConstraint {
636        constraint_name: String,
637    },
638    DisableTrigger {
639        trigger_name: Option<String>,
640    },
641    EnableTrigger {
642        trigger_name: Option<String>,
643    },
644    AttachPartition {
645        child: ObjectId,
646        strategy: Option<String>,
647    },
648    DetachPartition {
649        child: ObjectId,
650    },
651    SetStorage {
652        column: String,
653    },
654    SetAccessMethod,
655    OwnerTo {
656        new_owner: crate::analysis::facts::RoleFact,
657    },
658    Opaque,
659}