#![allow(clippy::too_many_lines)]
#![allow(clippy::option_if_let_else)]
#![allow(clippy::format_push_string)]
#![allow(clippy::needless_pass_by_value)]
pub mod check_not_valid_validate;
pub mod concurrent_index;
pub mod emit;
pub mod extensions;
pub mod fk_not_valid_validate;
pub mod functions;
pub mod grants;
pub mod partitions;
pub mod policies;
pub mod refresh_mv_concurrently;
pub mod reloptions;
pub mod set_not_null_check_pattern;
pub mod sql;
pub mod triggers;
pub mod types;
pub mod views;
use crate::diff::change::{Change, ChangeEntry};
use crate::diff::destructiveness::Destructiveness;
use crate::identifier::QualifiedName;
use crate::ir::catalog::Catalog;
use crate::plan::ordered::OrderedChangeSet;
use crate::plan::policy::PlannerPolicy;
use crate::plan::raw_step::RawStep;
pub(super) struct Ctx<'a> {
pub(super) target: &'a Catalog,
pub(super) source: &'a Catalog,
pub(super) policy: &'a PlannerPolicy,
}
pub fn rewrite(
ordered: OrderedChangeSet,
target: &Catalog,
policy: &PlannerPolicy,
) -> Vec<RawStep> {
rewrite_with_source(ordered, target, &Catalog::empty(), policy)
}
pub fn rewrite_with_source(
ordered: OrderedChangeSet,
target: &Catalog,
source: &Catalog,
policy: &PlannerPolicy,
) -> Vec<RawStep> {
let ctx = Ctx {
target,
source,
policy,
};
let mut out = Vec::new();
for entry in ordered.creates_and_adds {
emit_change(entry, &ctx, &mut out);
}
for entry in ordered.modifies {
emit_change(entry, &ctx, &mut out);
}
for entry in ordered.drops {
emit_change(entry, &ctx, &mut out);
}
for fk in ordered.deferred_fks {
emit::deferred_fk::emit(&fk, &ctx, &mut out);
}
let mut findings_sink: Vec<crate::lint::Finding> = Vec::new();
refresh_mv_concurrently::rewrite(&mut out, source, policy, &mut findings_sink);
out
}
fn emit_change(entry: ChangeEntry, ctx: &Ctx<'_>, out: &mut Vec<RawStep>) {
let destructive_reason = destructive_reason(&entry.destructiveness);
let destructive = entry.destructiveness.requires_approval();
match entry.change {
Change::CreateSchema(s) => emit::schema::create(s, destructive, destructive_reason, out),
Change::DropSchema(name) => emit::schema::drop_(name, destructive, destructive_reason, out),
Change::AlterSchema { name, comment } => emit::schema::alter(name, comment, out),
Change::CreateTable(t) => emit::table::create(t, destructive, destructive_reason, out),
Change::DropTable { qname, .. } => {
emit::table::drop_(qname, destructive, destructive_reason, out);
}
Change::AlterTable { qname, ops } => emit::table::alter(qname, ops, ctx, out),
Change::CreateIndex(idx) => {
emit::index::create(idx, ctx, destructive, destructive_reason, out);
}
Change::DropIndex(qname) => {
emit::index::drop_(qname, ctx, destructive, destructive_reason, out);
}
Change::ReplaceIndex { from, to } => {
emit::index::replace(from, to, ctx, destructive, destructive_reason, out);
}
Change::CreateSequence(s) => {
emit::sequence::create(s, destructive, destructive_reason, out);
}
Change::DropSequence(qname) => {
emit::sequence::drop_(qname, destructive, destructive_reason, out);
}
Change::AlterSequence { qname, ops } => emit::sequence::alter(qname, ops, out),
Change::ValidateConstraint { table, constraint } => {
emit::constraint::validate(table, constraint, destructive, destructive_reason, out);
}
Change::RecreateIndex { qname } => {
emit::index::recreate(qname, ctx, destructive, destructive_reason, out);
}
Change::View(vc) => emit::view::emit(vc, destructive, destructive_reason, out),
Change::Mv(mc) => emit::mv::emit(mc, destructive, destructive_reason, out),
Change::UserType(utc) => {
emit::user_type::emit(utc, destructive, destructive_reason, ctx, out);
}
Change::Function(fc) => emit::function::emit(fc, destructive, destructive_reason, out),
Change::Procedure(pc) => emit::procedure::emit(pc, destructive, destructive_reason, out),
Change::Extension(ec) => emit::extension::emit(ec, destructive, destructive_reason, out),
Change::Trigger(tc) => emit::trigger::emit(tc, destructive, destructive_reason, out),
Change::Table(tc) => {
use crate::diff::change::TableChange;
match tc {
TableChange::AttachPartition {
parent,
child,
bounds,
} => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::AttachPartition,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![child.clone()],
sql: crate::plan::rewrite::partitions::attach_partition(
&parent, &child, &bounds,
),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
TableChange::DetachPartition { parent, child } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::DetachPartition,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![child.clone()],
sql: crate::plan::rewrite::partitions::detach_partition(&parent, &child),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
}
}
Change::AlterObjectOwner(op) => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::AlterObjectOwner,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![op.qname.clone()],
sql: grants::alter_object_owner(op.kind, &op.qname, &op.signature, &op.to),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::GrantObjectPrivilege {
kind,
qname,
signature,
grant,
} => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::GrantObjectPrivilege,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: grants::grant_object_privilege(kind, &qname, &signature, &grant),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::RevokeObjectPrivilege {
kind,
qname,
signature,
grant,
} => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::RevokeObjectPrivilege,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: grants::revoke_object_privilege(kind, &qname, &signature, &grant),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::GrantColumnPrivilege { qname, grant } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::GrantColumnPrivilege,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: grants::grant_column_privilege(&qname, &grant),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::RevokeColumnPrivilege { qname, grant } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::RevokeColumnPrivilege,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: grants::revoke_column_privilege(&qname, &grant),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::AlterDefaultPrivileges {
target_role,
schema,
object_type,
is_grant,
grant,
} => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::AlterDefaultPrivileges,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![],
sql: grants::alter_default_privileges(
&target_role,
schema.as_ref(),
object_type,
is_grant,
&grant,
),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::CreatePolicy { table, policy } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::CreatePolicy,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![table.clone()],
sql: policies::create_policy(&table, &policy),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::DropPolicy { table, name } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::DropPolicy,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![table.clone()],
sql: policies::drop_policy(&table, &name),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::AlterPolicy { table, policy } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::AlterPolicy,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![table.clone()],
sql: policies::alter_policy(&table, &policy),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::SetTableRowSecurity { qname, enable } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::SetTableRowSecurity,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: policies::set_table_row_security(&qname, enable),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::SetTableForceRowSecurity { qname, force } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::SetTableForceRowSecurity,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: policies::set_table_force_row_security(&qname, force),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::SetTableStorage { qname, options } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::SetTableStorage,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: reloptions::alter_table_set_storage(&qname, &options),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::SetIndexStorage { qname, options } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::SetIndexStorage,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: reloptions::alter_index_set_storage(&qname, &options),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::SetMaterializedViewStorage { qname, options } => {
out.push(RawStep {
step_no: 0,
kind: crate::plan::raw_step::StepKind::SetMaterializedViewStorage,
destructive: false,
destructive_reason: None,
intent_id: None,
targets: vec![qname.clone()],
sql: reloptions::alter_mv_set_storage(&qname, &options),
transactional: crate::plan::raw_step::TransactionConstraint::InTransaction,
});
}
Change::UnsupportedDiff { .. } => {
unreachable!("UnsupportedDiff must never reach the rewrite phase")
}
}
}
pub(super) fn schema_target(name: &crate::identifier::Identifier) -> QualifiedName {
QualifiedName::new(name.clone(), name.clone())
}
pub(super) fn destructive_reason(d: &Destructiveness) -> Option<String> {
match d {
Destructiveness::Safe => None,
Destructiveness::RequiresApproval { reason }
| Destructiveness::RequiresApprovalAndDataLossWarning { reason } => Some(reason.clone()),
}
}
#[cfg(test)]
mod tests;