@@ -43,7 +43,7 @@ impl RemoveColumn {
46− fn not_null_constraint_trigger_name(&self, ctx: &MigrationContext) -> String {
46+ fn null_constraint_trigger_name(&self, ctx: &MigrationContext) -> String {
48 "{}_remove_column_{}_{}_nn",
48 "{}_remove_column_{}_{}_nn",
49 ctx.prefix(),
49 ctx.prefix(),
@@ -51,15 +51,6 @@ impl RemoveColumn {
51 self.column
51 self.column
55− fn not_null_constraint_name(&self, ctx: &MigrationContext) -> String {
57− "{}_add_column_not_null_{}_{}",
65#[typetag::serde(name = "remove_column")]
56#[typetag::serde(name = "remove_column")]
@@ -141,7 +132,6 @@ impl Action for RemoveColumn {
142 let maybe_null_check = if !column.nullable {
133 let maybe_null_check = if !column.nullable {
143 // Replace NOT NULL constraint with a constraint trigger that only triggers on the old schema.
134 // Replace NOT NULL constraint with a constraint trigger that only triggers on the old schema.
144− // We will add a null check to the down function on the new schema below as well to cover both cases.
145 // As we are using a complex down function, we must remove the NOT NULL check for the new schema.
135 // As we are using a complex down function, we must remove the NOT NULL check for the new schema.
146 // NOT NULL is not checked at the end of a transaction, but immediately upon update.
136 // NOT NULL is not checked at the end of a transaction, but immediately upon update.
147 let query = format!(
137 let query = format!(
@@ -167,7 +157,7 @@ impl Action for RemoveColumn {
167 EXECUTE PROCEDURE {trigger_name}();
157 EXECUTE PROCEDURE {trigger_name}();
169 table = self.table,
159 table = self.table,
170− trigger_name = self.not_null_constraint_trigger_name(ctx),
160+ trigger_name = self.null_constraint_trigger_name(ctx),
171 column = self.column,
161 column = self.column,
173 db.run(&query)
163 db.run(&query)
@@ -246,6 +236,7 @@ impl Action for RemoveColumn {
246 from_table_real = from_table.real_name,
236 from_table_real = from_table.real_name,
247 column_name = self.column,
237 column_name = self.column,
248 trigger_name = self.trigger_name(ctx),
238 trigger_name = self.trigger_name(ctx),
239+ // declarations = declarations.join("\n"),
250 db.run(&query).context("failed to create down trigger")?;
241 db.run(&query).context("failed to create down trigger")?;
@@ -319,6 +310,8 @@ impl Action for RemoveColumn {
313+ if !column.nullable {}
@@ -354,7 +347,7 @@ impl Action for RemoveColumn {
354 column = self.column,
347 column = self.column,
355 trigger_name = self.trigger_name(ctx),
348 trigger_name = self.trigger_name(ctx),
356 reverse_trigger_name = self.reverse_trigger_name(ctx),
349 reverse_trigger_name = self.reverse_trigger_name(ctx),
357− null_trigger_name = self.not_null_constraint_trigger_name(ctx),
350+ null_trigger_name = self.null_constraint_trigger_name(ctx),
359 db.run(&query)
352 db.run(&query)
360 .context("failed to drop column and down trigger")?;
353 .context("failed to drop column and down trigger")?;
@@ -371,70 +364,17 @@ impl Action for RemoveColumn {
373 fn abort(&self, ctx: &MigrationContext, db: &mut dyn Conn) -> anyhow::Result<()> {
366 fn abort(&self, ctx: &MigrationContext, db: &mut dyn Conn) -> anyhow::Result<()> {
374− // We might have temporaily removed the NOT NULL check and have to reinstate it
367+ // We might have removed the NOT NULL check so we reinstate it
375− let has_not_null_function = !db
379− FROM information_schema.routines
380− WHERE routine_schema = 'public'
381− AND routine_name = $1
383− &[&self.not_null_constraint_trigger_name(ctx)],
385− .context("failed to get any NOT NULL function")?
388− if has_not_null_function {
389− // Make column NOT NULL again without taking any long lived locks with a temporary constraint
390− let query = format!(
392− ALTER TABLE "{table}"
393− ADD CONSTRAINT "{constraint_name}"
394− CHECK ("{column}" IS NOT NULL) NOT VALID
397− constraint_name = self.not_null_constraint_name(ctx),
398− column = self.column,
401− .context("failed to add NOT NULL constraint")?;
403− let query = format!(
368+ db.run(&format!(
405− ALTER TABLE "{table}"
370+ ALTER TABLE {table}
406− VALIDATE CONSTRAINT "{constraint_name}"
409− constraint_name = self.not_null_constraint_name(ctx),
412− .context("failed to validate NOT NULL constraint")?;
414− // This ALTER TABLE call will not require any exclusive locks as it can use the validated constraint from above
418− ALTER COLUMN {column}
371+ ALTER COLUMN {column}
419− SET NOT NULL
372+ SET NOT NULL
421− table = self.table,
374+ table = self.table,
422− column = self.column
375+ column = self.column
424− .context("failed to reinstate column NOT NULL")?;
377+ .context("failed to reinstate column not null constraint")?;
426− // Drop the temporary constraint
427− let query = format!(
429− ALTER TABLE "{table}"
430− DROP CONSTRAINT "{constraint_name}"
433− constraint_name = self.not_null_constraint_name(ctx),
436− .context("failed to drop NOT NULL constraint")?;
439 // Remove function and trigger
379 // Remove function and trigger
440 db.run(&format!(
380 db.run(&format!(
@@ -445,7 +385,7 @@ impl Action for RemoveColumn {
446 trigger_name = self.trigger_name(ctx),
386 trigger_name = self.trigger_name(ctx),
447 reverse_trigger_name = self.reverse_trigger_name(ctx),
387 reverse_trigger_name = self.reverse_trigger_name(ctx),
448− null_trigger_name = self.not_null_constraint_trigger_name(ctx),
388+ null_trigger_name = self.null_constraint_trigger_name(ctx),
450 .context("failed to drop down trigger")?;
390 .context("failed to drop down trigger")?;