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}
135
136#[derive(Clone, Debug, PartialEq)]
137pub struct DropPolicyMutation {
138    pub name: String,
139    pub table: ObjectId,
140    pub if_exists: bool,
141}
142
143#[derive(Clone, Debug, PartialEq)]
144pub struct CreateTriggerMutation {
145    pub name: String,
146    pub table: ObjectId,
147    pub function_id: ObjectId,
148}
149
150#[derive(Clone, Debug, PartialEq)]
151pub struct DropTriggerMutation {
152    pub name: String,
153    pub table: ObjectId,
154    pub if_exists: bool,
155}
156
157#[derive(Clone, Debug, PartialEq)]
158pub struct RenameTriggerMutation {
159    pub name: String,
160    pub table: ObjectId,
161    pub new_name: String,
162}
163
164#[derive(Clone, Debug, PartialEq)]
165pub struct DropViewMutation {
166    pub ids: Vec<ObjectId>,
167    pub if_exists: bool,
168    pub cascade: bool,
169}
170
171#[derive(Clone, Debug, PartialEq)]
172pub struct DropMaterializedViewMutation {
173    pub ids: Vec<ObjectId>,
174    pub if_exists: bool,
175    pub cascade: bool,
176}
177
178#[derive(Clone, Debug, PartialEq)]
179pub struct CreateMaterializedView {
180    pub id: ObjectId,
181    pub depends_on: Vec<ObjectId>,
182}
183
184#[derive(Clone, Debug, PartialEq)]
185pub struct RefreshMaterializedViewMutation {
186    pub id: ObjectId,
187    pub concurrently: bool,
188}
189
190#[derive(Clone, Debug, PartialEq)]
191pub struct CreateSequenceMutation {
192    pub id: ObjectId,
193    pub if_not_exists: bool,
194    pub owned_by: Option<(ObjectId, String)>,
195}
196
197#[derive(Clone, Debug, PartialEq)]
198pub struct AlterSequenceMutation {
199    pub id: ObjectId,
200    pub if_exists: bool,
201    pub action: AlterSequenceActionMutation,
202}
203
204#[derive(Clone, Debug, PartialEq)]
205pub enum AlterSequenceActionMutation {
206    OwnedBy(Option<(ObjectId, String)>),
207    OwnerTo(crate::analysis::facts::RoleFact),
208    RenameTo(ObjectId),
209    SetSchema(ObjectId),
210    Other,
211}
212
213#[derive(Clone, Debug, PartialEq)]
214pub struct DropSequenceMutation {
215    pub ids: Vec<ObjectId>,
216    pub if_exists: bool,
217    pub cascade: bool,
218}
219
220#[derive(Clone, Debug, PartialEq)]
221pub struct CreateDomainMutation {
222    pub id: ObjectId,
223    pub base_type: String,
224}
225
226#[derive(Clone, Debug, PartialEq)]
227pub struct AlterDomainMutation {
228    pub id: ObjectId,
229    pub action: Option<crate::analysis::facts::AlterDomainActionFact>,
230}
231
232#[derive(Clone, Debug, PartialEq)]
233pub struct DropDomainMutation {
234    pub ids: Vec<ObjectId>,
235    pub if_exists: bool,
236    pub cascade: bool,
237}
238
239#[derive(Clone, Debug, PartialEq)]
240pub struct DropTypeMutation {
241    pub ids: Vec<ObjectId>,
242    pub if_exists: bool,
243    pub cascade: bool,
244}
245
246#[derive(Clone, Debug, PartialEq)]
247pub struct CreateTypeMutation {
248    pub id: ObjectId,
249    pub kind: TypeKind,
250}
251
252#[derive(Clone, Debug, PartialEq)]
253pub struct AlterTypeMutation {
254    pub id: ObjectId,
255    pub action: AlterTypeActionMutation,
256}
257
258#[derive(Clone, Debug, PartialEq)]
259pub enum AlterTypeActionMutation {
260    AddValue {
261        new_value: String,
262        neighbor: Option<String>,
263        before: bool,
264    },
265    RenameValue {
266        old_value: String,
267        new_value: String,
268    },
269}
270
271#[derive(Clone, Debug, PartialEq)]
272pub struct CreateTable {
273    pub id: ObjectId,
274    pub if_not_exists: bool,
275    pub as_select: bool,
276    pub persistence: PersistenceMutation,
277    pub columns: Vec<ColumnMutation>,
278    pub foreign_keys: Vec<FkMutation>,
279    pub table_constraints: Vec<TableConstraintFact>,
280    pub partition_by: Option<String>,
281    pub partition_of: Option<ObjectId>,
282    pub partition_type: Option<String>,
283}
284
285#[derive(Clone, Debug, PartialEq)]
286pub struct ColumnMutation {
287    pub name: String,
288    pub ty: Option<String>,
289    pub not_null: bool,
290    pub is_primary_key: bool,
291    pub primary_key_constraint_name: Option<String>,
292    pub is_unique: bool,
293    pub unique_constraint_name: Option<String>,
294    pub default: Option<ExprIr>,
295    pub generation: crate::analysis::facts::ColumnGeneration,
296}
297
298#[derive(Clone, Debug, PartialEq)]
299pub struct FkMutation {
300    pub constraint_name: Option<String>,
301    pub to_table: ObjectId,
302    pub from_columns: Vec<String>,
303    pub to_columns: Vec<String>,
304}
305
306#[derive(Clone, Debug, PartialEq)]
307pub struct CreateView {
308    pub id: ObjectId,
309    pub or_replace: bool,
310    pub depends_on: Vec<ObjectId>,
311}
312
313#[derive(Clone, Debug, PartialEq)]
314pub struct CreateIndex {
315    pub id: ObjectId,
316    pub table: ObjectId,
317    pub if_not_exists: bool,
318    pub concurrently: bool,
319    pub using_method: Option<String>,
320    pub has_predicate: bool,
321    pub unique: bool,
322}
323
324#[derive(Clone, Debug, PartialEq)]
325pub struct AlterTable {
326    pub id: ObjectId,
327    pub action: AlterTableActionMutation,
328}
329
330#[derive(Clone, Debug, PartialEq)]
331pub struct Rename {
332    pub old_id: ObjectId,
333    pub new_id: ObjectId,
334}
335
336#[derive(Clone, Debug, PartialEq)]
337pub struct DropTable {
338    pub id: ObjectId,
339    pub if_exists: bool,
340    pub cascade: bool,
341}
342
343#[derive(Clone, Debug, PartialEq)]
344pub struct DropIndex {
345    pub id: ObjectId,
346    pub if_exists: bool,
347    pub concurrently: bool,
348}
349
350#[derive(Clone, Debug, PartialEq)]
351pub struct SearchPathChange {
352    pub target: SearchPathTarget,
353    pub local: bool,
354}
355
356#[derive(Clone, Debug, PartialEq)]
357pub struct TimeoutSettingChange {
358    pub setting: TimeoutSetting,
359    pub value: TimeoutSettingValue,
360    pub local: bool,
361}
362
363#[derive(Clone, Debug, PartialEq)]
364pub struct SavepointMutation {
365    pub name: String,
366}
367
368#[derive(Clone, Debug, PartialEq)]
369pub struct ReleaseSavepointMutation {
370    pub name: String,
371}
372
373#[derive(Clone, Debug, PartialEq)]
374pub struct RollbackToSavepointMutation {
375    pub name: String,
376}
377
378#[derive(Clone, Debug, PartialEq)]
379pub struct CreateFunctionMutation {
380    pub id: ObjectId,
381    pub or_replace: bool,
382    pub params: Vec<crate::analysis::facts::ParamFact>,
383    pub return_type: Option<crate::analysis::facts::RetTypeFact>,
384    pub options: Vec<crate::analysis::facts::FuncOptionFact>,
385}
386
387#[derive(Clone, Debug, PartialEq)]
388pub struct AlterFunctionMutation {
389    pub id: ObjectId,
390    pub action: crate::analysis::facts::AlterFunctionAction,
391}
392
393#[derive(Clone, Debug, PartialEq)]
394pub struct DropFunctionMutation {
395    pub signatures: Vec<crate::analysis::facts::FunctionSigFact>,
396    pub if_exists: bool,
397    pub cascade: bool,
398}
399
400#[derive(Clone, Debug, PartialEq)]
401pub struct CreateProcedureMutation {
402    pub id: ObjectId,
403    pub or_replace: bool,
404    pub params: Vec<crate::analysis::facts::ParamFact>,
405    pub options: Vec<crate::analysis::facts::FuncOptionFact>,
406}
407
408#[derive(Clone, Debug, PartialEq)]
409pub struct AlterProcedureMutation {
410    pub id: ObjectId,
411    pub action: crate::analysis::facts::AlterFunctionAction,
412}
413
414#[derive(Clone, Debug, PartialEq)]
415pub struct DropProcedureMutation {
416    pub signatures: Vec<crate::analysis::facts::FunctionSigFact>,
417    pub if_exists: bool,
418    pub cascade: bool,
419}
420
421#[derive(Clone, Debug, PartialEq)]
422pub struct CreateAggregateMutation {
423    pub id: ObjectId,
424    pub or_replace: bool,
425    pub params: Vec<crate::analysis::facts::ParamFact>,
426}
427
428#[derive(Clone, Debug, PartialEq)]
429pub struct AlterAggregateMutation {
430    pub id: ObjectId,
431    pub action: crate::analysis::facts::AlterFunctionAction,
432}
433
434#[derive(Clone, Debug, PartialEq)]
435pub struct DropAggregateMutation {
436    pub signatures: Vec<crate::analysis::facts::FunctionSigFact>,
437    pub if_exists: bool,
438    pub cascade: bool,
439}
440
441#[derive(Clone, Debug, PartialEq)]
442pub struct CreatePublicationMutation {
443    pub name: String,
444    pub scope: crate::analysis::facts::PublicationScope,
445    pub params: Vec<crate::analysis::facts::AttributeFact>,
446}
447
448#[derive(Clone, Debug, PartialEq)]
449pub struct AlterPublicationMutation {
450    pub name: String,
451    pub action: crate::analysis::facts::AlterPublicationActionFact,
452}
453
454#[derive(Clone, Debug, PartialEq)]
455pub struct DropPublicationMutation {
456    pub names: Vec<String>,
457    pub if_exists: bool,
458    pub cascade: bool,
459}
460
461#[derive(Clone, Debug, PartialEq)]
462pub struct CreateSubscriptionMutation {
463    pub name: Option<String>,
464    pub connection: crate::analysis::facts::ConnectionTarget,
465    pub publications: Vec<String>,
466    pub params: Option<Vec<crate::analysis::facts::AttributeFact>>,
467}
468
469#[derive(Clone, Debug, PartialEq)]
470pub struct AlterSubscriptionMutation {
471    pub name: String,
472    pub action: crate::analysis::facts::AlterSubscriptionActionFact,
473}
474
475#[derive(Clone, Debug, PartialEq)]
476pub struct DropSubscriptionMutation {
477    pub name: String,
478    pub if_exists: bool,
479}
480
481#[derive(Clone, Debug, PartialEq)]
482pub struct CreateRoleMutation {
483    pub name: String,
484    pub inherits: bool,
485    pub can_login: bool,
486}
487
488#[derive(Clone, Debug, PartialEq)]
489pub struct AlterRoleMutation {
490    pub name: crate::analysis::facts::RoleFact,
491    pub inherits: Option<bool>,
492}
493
494#[derive(Clone, Debug, PartialEq)]
495pub struct DropRoleMutation {
496    pub names: Vec<String>,
497    pub if_exists: bool,
498}
499
500#[derive(Clone, Debug, PartialEq)]
501pub enum ResolvedGrantTarget {
502    Tables(Vec<ObjectId>),
503    AllTablesInSchema(Vec<String>),
504}
505
506#[derive(Clone, Debug, PartialEq)]
507pub struct GrantMutation {
508    pub privileges: crate::analysis::facts::PrivilegeSpec,
509    pub target: ResolvedGrantTarget,
510    pub grantees: Vec<crate::analysis::facts::RoleFact>,
511    pub with_grant_option: bool,
512    pub granted_by: Option<crate::analysis::facts::RoleFact>,
513}
514
515#[derive(Clone, Debug, PartialEq)]
516pub struct RevokeMutation {
517    pub grant_option_only: bool,
518    pub privileges: crate::analysis::facts::PrivilegeSpec,
519    pub target: ResolvedGrantTarget,
520    pub revokees: Vec<crate::analysis::facts::RoleFact>,
521    pub granted_by: Option<crate::analysis::facts::RoleFact>,
522    pub cascade: bool,
523}
524
525#[derive(Clone, Debug, PartialEq)]
526pub struct CreateDatabaseMutation {
527    pub name: String,
528    pub options: Vec<crate::analysis::facts::DatabaseOptionFact>,
529}
530
531#[derive(Clone, Debug, PartialEq)]
532pub struct AlterDatabaseMutation {
533    pub id: ObjectId,
534    pub action: crate::analysis::facts::AlterDatabaseAction,
535}
536
537#[derive(Clone, Debug, PartialEq)]
538pub struct DropDatabaseMutation {
539    pub id: ObjectId,
540    pub if_exists: bool,
541}
542
543#[derive(Clone, Debug, PartialEq)]
544pub enum OpaqueMutation {
545    /// Squawk accepted the statement but safe-migrate has no typed extractor
546    /// for it. Treating it as a no-op would leave later analysis falsely exact.
547    UnsupportedStatement,
548    DoBlock,
549    Execute,
550    DynamicSql,
551    PrepareTransaction,
552    SetTransaction,
553    SetConstraints,
554    StateCollision(String),
555    UnresolvedReference {
556        object_kind: crate::report::violations::ObjectKind,
557        object_name: String,
558    },
559}
560
561#[derive(Clone, Debug, PartialEq)]
562pub enum AlterTableActionMutation {
563    AddColumn {
564        name: String,
565        ty: Option<String>,
566        if_not_exists: bool,
567        not_null: bool,
568        default: Option<ExprIr>,
569        depends_on: Option<(ObjectId, String)>,
570        generation: crate::analysis::facts::ColumnGeneration,
571    },
572    DropColumn {
573        name: String,
574        if_exists: bool,
575    },
576    RenameColumn {
577        from: String,
578        to: String,
579    },
580    AddForeignKey {
581        constraint_name: Option<String>,
582        to_table: ObjectId,
583        from_columns: Vec<String>,
584        to_columns: Vec<String>,
585        not_valid: bool,
586    },
587    AlterConstraint {
588        name: Option<String>,
589        deferrable: bool,
590    },
591    RenameConstraint {
592        old_name: String,
593        new_name: String,
594    },
595    DropConstraint {
596        name: String,
597    },
598    AddCheckConstraint {
599        constraint_name: Option<String>,
600        not_valid: bool,
601    },
602    AddUniqueConstraint {
603        constraint_name: Option<String>,
604        using_index: Option<ObjectId>,
605    },
606    AddPrimaryKeyConstraint {
607        constraint_name: Option<String>,
608        using_index: Option<ObjectId>,
609    },
610    AddExcludeConstraint {
611        constraint_name: Option<String>,
612    },
613    SetNotNull {
614        column: String,
615    },
616    DropNotNull {
617        column: String,
618    },
619    SetType {
620        column: String,
621        ty: String,
622        has_using: bool,
623    },
624    SetDefault {
625        column: String,
626        default: Option<ExprIr>,
627    },
628    ValidateConstraint {
629        constraint_name: String,
630    },
631    DisableTrigger {
632        trigger_name: Option<String>,
633    },
634    EnableTrigger {
635        trigger_name: Option<String>,
636    },
637    AttachPartition {
638        child: ObjectId,
639        strategy: Option<String>,
640    },
641    DetachPartition {
642        child: ObjectId,
643    },
644    SetStorage {
645        column: String,
646    },
647    SetAccessMethod,
648    OwnerTo {
649        new_owner: crate::analysis::facts::RoleFact,
650    },
651    Opaque,
652}