@@ -330,6 +330,23 @@ def initialize
330330 #
331331 # For a list of commands that are reversible, please see
332332 # <tt>ActiveRecord::Migration::CommandRecorder</tt>.
333+ #
334+ # == Transactional Migrations
335+ #
336+ # If the database adapter supports DDL transactions, all migrations will
337+ # automatically be wrapped in a transaction. There are queries that you
338+ # can't execute inside a transaction though, and for these situations
339+ # you can turn the automatic transactions off.
340+ #
341+ # class ChangeEnum < ActiveRecord::Migration
342+ # self.disable_ddl_transaction!
343+ # def up
344+ # execute "ALTER TYPE model_size ADD VALUE 'new_value'"
345+ # end
346+ # end
347+ #
348+ # Remember that you can still open your own transactions, even if you
349+ # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
333350 class Migration
334351 autoload :CommandRecorder , 'active_record/migration/command_recorder'
335352
@@ -351,6 +368,7 @@ def call(env)
351368
352369 class << self
353370 attr_accessor :delegate # :nodoc:
371+ attr_accessor :disable_ddl_transaction # :nodoc:
354372 end
355373
356374 def self . check_pending!
@@ -365,8 +383,16 @@ def self.migrate(direction)
365383 new . migrate direction
366384 end
367385
368- cattr_accessor :verbose
386+ # Disable DDL transactions for this migration.
387+ def self . disable_ddl_transaction!
388+ @disable_ddl_transaction = true
389+ end
390+
391+ def disable_ddl_transaction # :nodoc:
392+ self . class . disable_ddl_transaction
393+ end
369394
395+ cattr_accessor :verbose
370396 attr_accessor :name , :version
371397
372398 def initialize ( name = self . class . name , version = nil )
@@ -375,8 +401,8 @@ def initialize(name = self.class.name, version = nil)
375401 @connection = nil
376402 end
377403
404+ self . verbose = true
378405 # instantiate the delegate object after initialize is defined
379- self . verbose = true
380406 self . delegate = new
381407
382408 # Reverses the migration commands for the given block and
@@ -663,7 +689,7 @@ def basename
663689 File . basename ( filename )
664690 end
665691
666- delegate :migrate , :announce , :write , :to => :migration
692+ delegate :migrate , :announce , :write , :disable_ddl_transaction , to : :migration
667693
668694 private
669695
@@ -856,12 +882,12 @@ def migrate
856882 Base . logger . info "Migrating to #{ migration . name } (#{ migration . version } )" if Base . logger
857883
858884 begin
859- ddl_transaction do
885+ ddl_transaction ( migration ) do
860886 migration . migrate ( @direction )
861887 record_version_state_after_migrating ( migration . version )
862888 end
863889 rescue => e
864- canceled_msg = Base . connection . supports_ddl_transactions? ? "this and " : ""
890+ canceled_msg = use_transaction? ( migration ) ? "this and " : ""
865891 raise StandardError , "An error has occurred, #{ canceled_msg } all later migrations canceled:\n \n #{ e } " , e . backtrace
866892 end
867893 end
@@ -935,12 +961,16 @@ def down?
935961 end
936962
937963 # Wrap the migration in a transaction only if supported by the adapter.
938- def ddl_transaction
939- if Base . connection . supports_ddl_transactions?
964+ def ddl_transaction ( migration )
965+ if use_transaction? ( migration )
940966 Base . transaction { yield }
941967 else
942968 yield
943969 end
944970 end
971+
972+ def use_transaction? ( migration )
973+ !migration . disable_ddl_transaction && Base . connection . supports_ddl_transactions?
974+ end
945975 end
946976end
0 commit comments