diff --git a/CHANGELOG.md b/CHANGELOG.md index d345aff8d..0cb742c89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ #### Changed +- [#1381](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1381) Fix `change_column` to preserve old column attributes. + #### Fixed Please check [8-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/8-1-stable/CHANGELOG.md) for previous changes. diff --git a/lib/active_record/connection_adapters/sqlserver/schema_statements.rb b/lib/active_record/connection_adapters/sqlserver/schema_statements.rb index ab6313f4b..db85d21f3 100644 --- a/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +++ b/lib/active_record/connection_adapters/sqlserver/schema_statements.rb @@ -196,14 +196,16 @@ def change_column(table_name, column_name, type, options = {}) end column_object = schema_cache.columns(table_name).find { |c| c.name.to_s == column_name.to_s } - without_constraints = options.key?(:default) || options.key?(:limit) + changing_type = column_object && column_object.type != type.to_sym + no_constraint_options = options.key?(:default) || options.key?(:limit) + default = if !options.key?(:default) && column_object column_object.default else options[:default] end - if without_constraints || (column_object && column_object.type != type.to_sym) + if no_constraint_options || changing_type remove_default_constraint(table_name, column_name) indexes = indexes(table_name).select { |index| index.columns.include?(column_name.to_s) } remove_indexes(table_name, column_name) @@ -212,10 +214,14 @@ def change_column(table_name, column_name, type, options = {}) sql_commands << "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(options[:default], column_object)} WHERE #{quote_column_name(column_name)} IS NULL" if !options[:null].nil? && options[:null] == false && !options[:default].nil? alter_command = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])}" alter_command += " COLLATE #{options[:collation]}" if options[:collation].present? - alter_command += " NOT NULL" if !options[:null].nil? && options[:null] == false + if !options[:null].nil? + alter_command += " NOT NULL" if options[:null] == false + elsif column_object && !column_object.null + alter_command += " NOT NULL" + end sql_commands << alter_command - if without_constraints + if no_constraint_options || (changing_type && default.present?) default = quote_default_expression(default, column_object || column_for(table_name, column_name)) sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{default} FOR #{quote_column_name(column_name)}" end diff --git a/test/cases/migration_test_sqlserver.rb b/test/cases/migration_test_sqlserver.rb index b829c8632..e4d713627 100644 --- a/test/cases/migration_test_sqlserver.rb +++ b/test/cases/migration_test_sqlserver.rb @@ -34,11 +34,13 @@ class MigrationTestSQLServer < ActiveRecord::TestCase lock_version_column = Person.columns_hash["lock_version"] assert_equal :integer, lock_version_column.type assert lock_version_column.default.present? + assert_equal 0, lock_version_column.default assert_nothing_raised { connection.change_column "people", "lock_version", :string } Person.reset_column_information lock_version_column = Person.columns_hash["lock_version"] assert_equal :string, lock_version_column.type - assert lock_version_column.default.nil? + assert lock_version_column.default.present? + assert_equal "0", lock_version_column.default assert_nothing_raised { connection.change_column "people", "lock_version", :integer } Person.reset_column_information end