I'm running some bizarre Postgres migration code from OpenCongress and I'm getting this error:
RuntimeError: ERROR C25001 MVACUUM cannot run inside a transaction block Fxact.c L2649 RPreventTransactionChain: VACUUM FULL ANALYZE;
So I'd like to try running it without getting wrapped by a transaction.
On databases that support transactions with statements that change the schema, migrations are wrapped in a transaction. If the database does not support this then when a migration fails the parts of it that succeeded will not be rolled back. You will have to rollback the changes that were made by hand.
To run a specific migration up or down, use db:migrate:up or db:migrate:down . The version number in the above commands is the numeric prefix in the migration's filename. For example, to migrate to the migration 20160515085959_add_name_to_users. rb , you would use 20160515085959 as the version number.
A Rails migration is a tool for changing an application's database schema. Instead of managing SQL scripts, you define database changes in a domain-specific language (DSL). The code is database-independent, so you can easily move your app to a new platform.
There's now a method disable_ddl_transaction!
that allows this, e.g.:
class AddIndexesToTablesBasedOnUsage < ActiveRecord::Migration disable_ddl_transaction! def up execute %{ CREATE INDEX CONCURRENTLY index_reservations_subscription_id ON reservations (subscription_id); } end def down execute %{DROP INDEX index_reservations_subscription_id} end end
ActiveRecord::Migration
has the following private method that gets called when running migrations:
def ddl_transaction(&block) if Base.connection.supports_ddl_transactions? Base.transaction { block.call } else block.call end end
As you can see this will wrap the migration in a transaction if the connection supports it.
In ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
you have:
def supports_ddl_transactions? true end
SQLite version 2.0 and beyond also support migration transactions. In ActiveRecord::ConnectionAdapters::SQLiteAdapter
you have:
def supports_ddl_transactions? sqlite_version >= '2.0.0' end
So then, to skip transactions, you need to somehow circumvent this. Something like this might work, though I haven't tested it:
class ActiveRecord::Migration class << self def no_transaction @no_transaction = true end def no_transaction? @no_transaction == true end end private def ddl_transaction(&block) if Base.connection.supports_ddl_transactions? && !self.class.no_transaction? Base.transaction { block.call } else block.call end end end
You could then set up your migration as follows:
class SomeMigration < ActiveRecord::Migration no_transaction def self.up # Do something end def self.down # Do something end end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With