fatkodima/online_migrations

add_column_with_default and Arel.sql literal did not backfill data

alan-pie opened this issue · 4 comments

I had the following migration which I expected to backfill sent_at with the value from created_at, but ended up just creating the new column with null values. Is there a bug or did I do something wrong?

online_migrations 0.5.4
postgresql 14.6
active_record 6.1.7.1

class AddSentAtToPayouts < ActiveRecord::Migration[6.1]
  disable_ddl_transaction!

  def change
    add_column_with_default(
      :payouts,
      :sent_at,
      :timestamp,
      default: Arel.sql('created_at')
    )
  end
end

That is not possible in PostgreSQL - you should have literals (numbers, strings etc) as a DEFAULT or function calls (like random(), current_timestamp etc).
If you want to have sent_at be set as a default to created_at, that should probably be done via db triggers or model callbacks.

If you want to just create a new column and populate existing rows with the value of created_at, without setting a default of some kind, then add_column + update_column_in_batches(:payouts, :sent_at, Arel.sql('created_at')) should work.

I see. This line led me to believe it was possible:

update_column_in_batches(table_name, column_name, default, **batch_options)

But now I see that for newer versions of PostgreSQL it doesn't use that branch.

Would this work if Arel.sql literals were considered a volitile_default??

No, Postgres SQL syntax just does not allow to specify other columns as a DEFAULT.
You can manually try (to see the error)

add_column(table_name, column_name, type, **options)
which gets called in your case with newer Postgres.

Seems like this gem is not able to overcome that PostgreSQL limitation.
Feel free to ask any questions, if you have one.