Ticket #11493: interleaved_migrations_with_repeatable_loads.diff
| File interleaved_migrations_with_repeatable_loads.diff, 16.1 kB (added by ddollar, 2 months ago) |
|---|
-
a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
old new 232 232 233 233 # Should not be called normally, but this operation is non-destructive. 234 234 # The migrations module handles this automatically. 235 def initialize_schema_information(current_version=0) 236 begin 237 execute "CREATE TABLE #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)} (version #{type_to_sql(:string)})" 238 execute "INSERT INTO #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)} (version) VALUES(#{current_version})" 239 rescue ActiveRecord::StatementInvalid 240 # Schema has been initialized, make sure version is a string 241 version_column = columns(:schema_info).detect { |c| c.name == "version" } 242 243 # can't just alter the table, since SQLite can't deal 244 unless version_column.type == :string 245 version = ActiveRecord::Migrator.current_version 246 execute "DROP TABLE #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)}" 247 initialize_schema_information(version) 235 def initialize_schema_migrations_table 236 sm_table = ActiveRecord::Migrator.schema_migrations_table_name 237 238 unless tables.detect { |t| t == sm_table } 239 create_table(sm_table, :id => false) do |schema_migrations_table| 240 schema_migrations_table.column :version, :string, :null => false 248 241 end 249 end 250 end 242 add_index sm_table, :version, :unique => true, 243 :name => 'unique_schema_migrations' 244 245 # Backwards-compatibility: if we find schema_info, assume we've 246 # migrated up to that point: 247 si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix 248 249 if tables.detect { |t| t == si_table } 251 250 252 def dump_schema_information #:nodoc: 253 begin 254 if (current_schema = ActiveRecord::Migrator.current_version) > 0 255 return "INSERT INTO #{quote_table_name(ActiveRecord::Migrator.schema_info_table_name)} (version) VALUES (#{current_schema})" 251 old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i 252 assume_migrated_upto_version(old_version) 253 drop_table(si_table) 256 254 end 257 rescue ActiveRecord::StatementInvalid258 # No Schema Info259 255 end 260 256 end 261 257 258 def assume_migrated_upto_version(version) 259 sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name) 260 migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i) 261 versions = Dir['db/migrate/[0-9]*_*.rb'].map do |filename| 262 filename.split('/').last.split('_').first.to_i 263 end 264 265 execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')" unless migrated.include?(version.to_i) 266 (versions - migrated).select { |v| v < version.to_i }.each do |v| 267 execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')" 268 end 269 end 262 270 263 271 def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc: 264 272 if native = native_database_types[type] -
a/activerecord/lib/active_record/migration.rb
old new 123 123 # 124 124 # To run migrations against the currently configured database, use 125 125 # <tt>rake db:migrate</tt>. This will update the database by running all of the 126 # pending migrations, creating the <tt>schema_ info</tt> table if missing.126 # pending migrations, creating the <tt>schema_migrations</tt> table if missing. 127 127 # 128 128 # To roll the database back to a previous migration version, use 129 129 # <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which … … 315 315 class << self 316 316 def migrate(migrations_path, target_version = nil) 317 317 case 318 when target_version.nil?, current_version < target_version 319 up(migrations_path, target_version) 320 when current_version > target_version 321 down(migrations_path, target_version) 322 when current_version == target_version 323 return # You're on the right version 318 when target_version.nil? then up(migrations_path, target_version) 319 when current_version > target_version then down(migrations_path, target_version) 320 else up(migrations_path, target_version) 324 321 end 325 322 end 326 323 327 324 def rollback(migrations_path, steps=1) 328 325 migrator = self.new(:down, migrations_path) 329 326 start_index = migrator.migrations.index(migrator.current_migration) … … 346 343 self.new(direction, migrations_path, target_version).run 347 344 end 348 345 349 def schema_ info_table_name350 Base.table_name_prefix + "schema_info"+ Base.table_name_suffix346 def schema_migrations_table_name 347 Base.table_name_prefix + 'schema_migrations' + Base.table_name_suffix 351 348 end 352 349 353 350 def current_version 354 Base.connection.select_value("SELECT version FROM #{schema_info_table_name}").to_i 351 Base.connection.select_values( 352 "SELECT version FROM #{schema_migrations_table_name}").map(&:to_i).max || 0 355 353 end 356 354 357 355 def proper_table_name(name) … … 362 360 363 361 def initialize(direction, migrations_path, target_version = nil) 364 362 raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations? 365 Base.connection.initialize_schema_ information363 Base.connection.initialize_schema_migrations_table 366 364 @direction, @migrations_path, @target_version = direction, migrations_path, target_version 367 365 end 368 366 … … 383 381 def migrate 384 382 current = migrations.detect { |m| m.version == current_version } 385 383 target = migrations.detect { |m| m.version == @target_version } 386 384 387 385 if target.nil? && !@target_version.nil? && @target_version > 0 388 386 raise UnknownMigrationVersionError.new(@target_version) 389 387 end 390 388 391 start = migrations.index(current) || 0392 finish = migrations.index(target) || migrations.size - 1 389 start = up? ? 0 : (migrations.index(current) || 0) 390 finish = migrations.index(target) || migrations.size - 1 393 391 runnable = migrations[start..finish] 394 392 395 # skip the current migration if we're heading upwards396 runnable.shift if up? && runnable.first == current397 398 393 # skip the last migration if we're headed down, but not ALL the way down 399 394 runnable.pop if down? && !target.nil? 400 395 401 396 runnable.each do |migration| 402 397 Base.logger.info "Migrating to #{migration} (#{migration.version})" 403 migration.migrate(@direction) 404 set_schema_version_after_migrating(migration) 398 399 # On our way up, we skip migrating the ones we've already migrated 400 # On our way down, we skip reverting the ones we've never migrated 401 next if up? && migrated.include?(migration.version.to_i) 402 403 if down? && !migrated.include?(migration.version.to_i) 404 migration.announce 'never migrated, skipping'; migration.write 405 else 406 migration.migrate(@direction) 407 record_version_state_after_migrating(migration.version) 408 end 405 409 end 406 410 end 407 411 … … 412 416 migrations = files.inject([]) do |klasses, file| 413 417 version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first 414 418 415 raise IllegalMigrationNameError.new(f ) unless version419 raise IllegalMigrationNameError.new(file) unless version 416 420 version = version.to_i 417 421 418 422 if klasses.detect { |m| m.version == version } … … 432 436 end 433 437 end 434 438 435 def pending_migrations 436 migrations.select { |m| m.version > current_version } 439 def migrated 440 sm_table = self.class.schema_migrations_table_name 441 Base.connection.select_values("SELECT version FROM #{sm_table}").map(&:to_i).sort 437 442 end 438 443 439 444 private 440 def set_schema_version_after_migrating(migration)441 version = migration.version442 445 def record_version_state_after_migrating(version) 446 sm_table = self.class.schema_migrations_table_name 447 443 448 if down? 444 after = migrations[migrations.index(migration) + 1] 445 version = after ? after.version : 0 449 Base.connection.update("DELETE FROM #{sm_table} WHERE version = '#{version}'") 450 else 451 Base.connection.insert("INSERT INTO #{sm_table} (version) VALUES ('#{version}')") 446 452 end 447 448 Base.connection.update("UPDATE #{self.class.schema_info_table_name} SET version = #{version}")449 453 end 450 454 451 455 def up? -
a/activerecord/lib/active_record/schema.rb
old new 34 34 # #add_index, etc.). 35 35 # 36 36 # The +info+ hash is optional, and if given is used to define metadata 37 # about the current schema ( likethe schema's version):37 # about the current schema (currently, only the schema's version): 38 38 # 39 # ActiveRecord::Schema.define(:version => 15) do39 # ActiveRecord::Schema.define(:version => 20380119000001) do 40 40 # ... 41 41 # end 42 42 def self.define(info={}, &block) 43 43 instance_eval(&block) 44 44 45 unless info.empty? 46 initialize_schema_information 47 cols = columns('schema_info') 48 49 info = info.map do |k,v| 50 v = Base.connection.quote(v, cols.detect { |c| c.name == k.to_s }) 51 "#{k} = #{v}" 52 end 53 54 Base.connection.update "UPDATE #{Migrator.schema_info_table_name} SET #{info.join(", ")}" 45 unless info[:version].blank? 46 initialize_schema_migrations_table 47 assume_migrated_upto_version info[:version] 55 48 end 56 49 end 57 50 end -
a/activerecord/lib/active_record/schema_dumper.rb
old new 30 30 def initialize(connection) 31 31 @connection = connection 32 32 @types = @connection.native_database_types 33 @info = @connection.select_one("SELECT * FROM schema_info") rescue nil 33 @version = @connection.select_values( 34 "SELECT version FROM schema_migrations").map(&:to_i).max rescue nil 34 35 end 35 36 36 37 def header(stream) 37 define_params = @ info ? ":version => #{@info['version']}" : ""38 define_params = @version ? ":version => #{@version}" : "" 38 39 39 40 stream.puts <<HEADER 40 41 # This file is auto-generated from the current state of the database. Instead of editing this file, … … 59 60 60 61 def tables(stream) 61 62 @connection.tables.sort.each do |tbl| 62 next if [ "schema_info", ignore_tables].flatten.any? do |ignored|63 next if ['schema_migrations', ignore_tables].flatten.any? do |ignored| 63 64 case ignored 64 65 when String; tbl == ignored 65 66 when Regexp; tbl =~ ignored -
a/activerecord/test/cases/ar_schema_test.rb
old new 25 25 end 26 26 27 27 assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" } 28 assert_nothing_raised { @connection.select_all "SELECT * FROM schema_ info" }29 assert_equal 7, @connection.select_ one("SELECT version FROM schema_info")['version'].to_i28 assert_nothing_raised { @connection.select_all "SELECT * FROM schema_migrations" } 29 assert_equal 7, @connection.select_values("SELECT version FROM schema_migrations").map(&:to_i).max 30 30 end 31 31 end 32 32 -
a/activerecord/test/cases/migration_test.rb
old new 34 34 end 35 35 36 36 def teardown 37 ActiveRecord::Base.connection.initialize_schema_ information38 ActiveRecord::Base.connection. update "UPDATE #{ActiveRecord::Migrator.schema_info_table_name} SET version = 0"37 ActiveRecord::Base.connection.initialize_schema_migrations_table 38 ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}" 39 39 40 40 %w(reminders people_reminders prefix_reminders_suffix).each do |table| 41 41 Reminder.connection.drop_table(table) rescue nil … … 833 833 assert_equal(0, ActiveRecord::Migrator.current_version) 834 834 end 835 835 836 def test_schema_ info_table_name836 def test_schema_migrations_table_name 837 837 ActiveRecord::Base.table_name_prefix = "prefix_" 838 838 ActiveRecord::Base.table_name_suffix = "_suffix" 839 839 Reminder.reset_table_name 840 assert_equal "prefix_schema_ info_suffix", ActiveRecord::Migrator.schema_info_table_name840 assert_equal "prefix_schema_migrations_suffix", ActiveRecord::Migrator.schema_migrations_table_name 841 841 ActiveRecord::Base.table_name_prefix = "" 842 842 ActiveRecord::Base.table_name_suffix = "" 843 843 Reminder.reset_table_name 844 assert_equal "schema_ info", ActiveRecord::Migrator.schema_info_table_name844 assert_equal "schema_migrations", ActiveRecord::Migrator.schema_migrations_table_name 845 845 ensure 846 846 ActiveRecord::Base.table_name_prefix = "" 847 847 ActiveRecord::Base.table_name_suffix = "" -
a/activerecord/test/cases/schema_dumper_test.rb
old new 16 16 output = standard_dump 17 17 assert_match %r{create_table "accounts"}, output 18 18 assert_match %r{create_table "authors"}, output 19 assert_no_match %r{create_table "schema_ info"}, output19 assert_no_match %r{create_table "schema_migrations"}, output 20 20 end 21 21 22 22 def test_schema_dump_excludes_sqlite_sequence … … 81 81 output = stream.string 82 82 assert_no_match %r{create_table "accounts"}, output 83 83 assert_match %r{create_table "authors"}, output 84 assert_no_match %r{create_table "schema_ info"}, output84 assert_no_match %r{create_table "schema_migrations"}, output 85 85 end 86 86 87 87 def test_schema_dump_with_regexp_ignored_table … … 92 92 output = stream.string 93 93 assert_no_match %r{create_table "accounts"}, output 94 94 assert_match %r{create_table "authors"}, output 95 assert_no_match %r{create_table "schema_ info"}, output95 assert_no_match %r{create_table "schema_migrations"}, output 96 96 end 97 97 98 98 def test_schema_dump_illegal_ignored_table_value -
a/activerecord/test/schema/sybase.drop.sql
old new 31 31 DROP TABLE numeric_data 32 32 DROP TABLE mixed_case_monkeys 33 33 DROP TABLE minimalistics 34 DROP TABLE schema_ info34 DROP TABLE schema_migrations 35 35 go