@@ -10,6 +10,15 @@ pub struct AddColumn {
12impl AddColumn {
12impl AddColumn {
13+ fn temp_column_name(&self, ctx: &Context) -> String {
15+ "{}_temp_column_{}_{}",
13 fn trigger_name(&self, ctx: &Context) -> String {
22 fn trigger_name(&self, ctx: &Context) -> String {
15 "{}_add_column_{}_{}",
24 "{}_add_column_{}_{}",
@@ -40,9 +49,10 @@ impl Action for AddColumn {
41 fn run(&self, ctx: &Context, db: &mut dyn Conn, schema: &Schema) -> anyhow::Result<()> {
50 fn run(&self, ctx: &Context, db: &mut dyn Conn, schema: &Schema) -> anyhow::Result<()> {
42 let table = schema.get_table(db, &self.table)?;
51 let table = schema.get_table(db, &self.table)?;
52+ let temp_column_name = self.temp_column_name(ctx);
44 let mut definition_parts = vec![
54 let mut definition_parts = vec![
45− self.column.name.to_string(),
55+ temp_column_name.to_string(),
46 self.column.data_type.to_string(),
56 self.column.data_type.to_string(),
@@ -93,7 +103,7 @@ impl Action for AddColumn {
94 {declarations}
104 {declarations}
96− NEW.{column_name} = {up};
106+ NEW.{temp_column_name} = {up};
99 RETURN NEW;
109 RETURN NEW;
@@ -103,7 +113,7 @@ impl Action for AddColumn {
103 DROP TRIGGER IF EXISTS {trigger_name} ON {table};
113 DROP TRIGGER IF EXISTS {trigger_name} ON {table};
104 CREATE TRIGGER {trigger_name} BEFORE UPDATE OR INSERT ON {table} FOR EACH ROW EXECUTE PROCEDURE {trigger_name}();
114 CREATE TRIGGER {trigger_name} BEFORE UPDATE OR INSERT ON {table} FOR EACH ROW EXECUTE PROCEDURE {trigger_name}();
106− column_name = self.column.name,
116+ temp_column_name = temp_column_name,
107 trigger_name = self.trigger_name(ctx),
117 trigger_name = self.trigger_name(ctx),
109 table = self.table,
119 table = self.table,
@@ -114,7 +124,7 @@ impl Action for AddColumn {
115 // Backfill values in batches
125 // Backfill values in batches
116 if self.up.is_some() {
126 if self.up.is_some() {
117− common::batch_touch_rows(db, &table.real_name, &self.column.name)?;
127+ common::batch_touch_rows(db, &table.real_name, &temp_column_name)?;
120 // Add a temporary NOT NULL constraint if the column shouldn't be nullable.
130 // Add a temporary NOT NULL constraint if the column shouldn't be nullable.
@@ -130,7 +140,7 @@ impl Action for AddColumn {
131 table = self.table,
141 table = self.table,
132 constraint_name = self.not_null_constraint_name(&ctx),
142 constraint_name = self.not_null_constraint_name(&ctx),
133− column = self.column.name,
143+ column = temp_column_name,
135 db.run(&query)?;
145 db.run(&query)?;
@@ -138,7 +148,9 @@ impl Action for AddColumn {
141− fn complete(&self, ctx: &Context, db: &mut dyn Conn, _schema: &Schema) -> anyhow::Result<()> {
151+ fn complete(&self, ctx: &Context, db: &mut dyn Conn, schema: &Schema) -> anyhow::Result<()> {
152+ let table = schema.get_table(db, &self.table)?;
142 // Remove triggers and procedures
154 // Remove triggers and procedures
143 let query = format!(
155 let query = format!(
@@ -174,7 +186,7 @@ impl Action for AddColumn {
174 ALTER COLUMN {column} SET NOT NULL
186 ALTER COLUMN {column} SET NOT NULL
176 table = self.table,
188 table = self.table,
177− column = self.column.name,
189+ column = self.temp_column_name(ctx),
179 db.run(&query)?;
191 db.run(&query)?;
@@ -190,10 +202,26 @@ impl Action for AddColumn {
190 db.run(&query)?;
202 db.run(&query)?;
205+ // Rename the temporary column to its real name
209+ RENAME COLUMN {temp_column_name} TO {column_name}
211+ table = table.real_name,
212+ temp_column_name = self.temp_column_name(ctx),
213+ column_name = self.column.name,
196− fn update_schema(&self, _ctx: &Context, _schema: &mut Schema) -> anyhow::Result<()> {
219+ fn update_schema(&self, ctx: &Context, schema: &mut Schema) -> anyhow::Result<()> {
220+ schema.change_table(&self.table, |table_changes| {
221+ table_changes.change_column(&self.column.name, |column_changes| {
222+ column_changes.set_column(&self.temp_column_name(ctx));
@@ -216,7 +244,7 @@ impl Action for AddColumn {
216 DROP COLUMN IF EXISTS {column}
244 DROP COLUMN IF EXISTS {column}
218 table = self.table,
246 table = self.table,
219− column = self.column.name,
247+ column = self.temp_column_name(ctx),
221 db.run(&query)?;
249 db.run(&query)?;