diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c9682689..bee18f96a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,5 +9,6 @@ - [#1381](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1381) Fix `change_column` to preserve old column attributes. - [#1393](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1393) Treat TinyTDS `failed dbsqlsend() function` errors as `ConnectionNotEstablished` so they're retried instead of surfaced as `StatementInvalid`. - [#1397](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1397) Treat "DBPROCESS is dead or not enabled" as ConnectionNotEstablished. +- [#1406](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1406) Stop deserializing column defaults. 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 d2dcdc673..77357ebd8 100644 --- a/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +++ b/lib/active_record/connection_adapters/sqlserver/schema_statements.rb @@ -573,13 +573,16 @@ def default_value_and_function(default:, name:, type:, original_type:, view_exis [string_literal, nil] when /CREATE DEFAULT/mi [nil, nil] + when /\A\(NULL\)\Z/i + [nil, nil] else - type = case type - when /smallint|int|bigint/ then original_type - else type - end value = default.match(/\A\((.*)\)\Z/m)[1] - value = select_value("SELECT CAST(#{value} AS #{type}) AS value", "SCHEMA") + if value.start_with?("(") && value.end_with?(")") + value = value[1..-2] + end + if value.start_with?("'") && value.end_with?("'") + value = value[1..-2] + end [value, nil] end end diff --git a/test/cases/coerced_tests.rb b/test/cases/coerced_tests.rb index d6f3ca03a..069616236 100644 --- a/test/cases/coerced_tests.rb +++ b/test/cases/coerced_tests.rb @@ -524,31 +524,6 @@ def test_distinct_count_all_with_custom_select_and_order_coerced module ActiveRecord class Migration class ChangeSchemaTest < ActiveRecord::TestCase - # Integer.default is a number and not a string - coerce_tests! :test_create_table_with_defaults - def test_create_table_with_defaults_coerce - connection.create_table :testings do |t| - t.column :one, :string, default: "hello" - t.column :two, :boolean, default: true - t.column :three, :boolean, default: false - t.column :four, :integer, default: 1 - t.column :five, :text, default: "hello" - end - - columns = connection.columns(:testings) - one = columns.detect { |c| c.name == "one" } - two = columns.detect { |c| c.name == "two" } - three = columns.detect { |c| c.name == "three" } - four = columns.detect { |c| c.name == "four" } - five = columns.detect { |c| c.name == "five" } - - assert_equal "hello", one.default - assert_equal true, two.cast_type.deserialize(two.default) - assert_equal false, three.cast_type.deserialize(three.default) - assert_equal 1, four.default - assert_equal "hello", five.default - end - # Use precision 6 by default for datetime/timestamp columns. SQL Server uses `datetime2` for date-times with precision. coerce_tests! :test_add_column_with_postgresql_datetime_type def test_add_column_with_postgresql_datetime_type_coerced @@ -610,19 +585,6 @@ def test_add_column_without_limit_coerced module ActiveRecord class Migration class ColumnsTest < ActiveRecord::TestCase - # Our defaults are real 70000 integers vs '70000' strings. - coerce_tests! :test_rename_column_preserves_default_value_not_null - def test_rename_column_preserves_default_value_not_null_coerced - add_column "test_models", "salary", :integer, default: 70000 - default_before = connection.columns("test_models").find { |c| c.name == "salary" }.default - assert_equal 70000, default_before - rename_column "test_models", "salary", "annual_salary" - TestModel.reset_column_information - assert TestModel.column_names.include?("annual_salary") - default_after = connection.columns("test_models").find { |c| c.name == "annual_salary" }.default - assert_equal 70000, default_after - end - # Dropping the column removes the single index. coerce_tests! :test_remove_column_with_multi_column_index def test_remove_column_with_multi_column_index_coerced @@ -1958,32 +1920,6 @@ def test_time_precision_is_truncated_on_assignment_coerced coerce_tests! :test_invalid_time_precision_raises_error end -class DefaultNumbersTest < ActiveRecord::TestCase - # We do better with native types and do not return strings for everything. - coerce_tests! :test_default_positive_integer - def test_default_positive_integer_coerced - record = DefaultNumber.new - assert_equal 7, record.positive_integer - assert_equal 7, record.positive_integer_before_type_cast - end - - # We do better with native types and do not return strings for everything. - coerce_tests! :test_default_negative_integer - def test_default_negative_integer_coerced - record = DefaultNumber.new - assert_equal(-5, record.negative_integer) - assert_equal(-5, record.negative_integer_before_type_cast) - end - - # We do better with native types and do not return strings for everything. - coerce_tests! :test_default_decimal_number - def test_default_decimal_number_coerced - record = DefaultNumber.new - assert_equal BigDecimal("2.78"), record.decimal_number - assert_equal 2.78, record.decimal_number_before_type_cast - end -end - module ActiveRecord class CollectionCacheKeyTest < ActiveRecord::TestCase # Will trust rails has this sorted since you cant offset without a limit. diff --git a/test/cases/column_test_sqlserver.rb b/test/cases/column_test_sqlserver.rb index b4ae10d11..fd84faace 100644 --- a/test/cases/column_test_sqlserver.rb +++ b/test/cases/column_test_sqlserver.rb @@ -41,7 +41,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "bigint(8)" _(col.type).must_equal :integer _(col.null).must_equal true - _(col.default).must_equal 42 + _(col.default).must_equal "42" _(obj.bigint).must_equal 42 _(col.default_function).must_be_nil type = col.cast_type @@ -56,7 +56,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "int(4)" _(col.type).must_equal :integer _(col.null).must_equal true - _(col.default).must_equal 42 + _(col.default).must_equal "42" _(obj.int).must_equal 42 _(col.default_function).must_be_nil type = col.cast_type @@ -71,7 +71,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "smallint(2)" _(col.type).must_equal :integer _(col.null).must_equal true - _(col.default).must_equal 42 + _(col.default).must_equal "42" _(obj.smallint).must_equal 42 _(col.default_function).must_be_nil type = col.cast_type @@ -86,7 +86,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "tinyint(1)" _(col.type).must_equal :integer _(col.null).must_equal true - _(col.default).must_equal 42 + _(col.default).must_equal "42" _(obj.tinyint).must_equal 42 _(col.default_function).must_be_nil type = col.cast_type @@ -101,7 +101,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "bit" _(col.type).must_equal :boolean _(col.null).must_equal true - _(col.default).must_equal true + _(col.default).must_equal "1" _(obj.bit).must_equal true _(col.default_function).must_be_nil type = col.cast_type @@ -122,7 +122,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "decimal(9,2)" _(col.type).must_equal :decimal _(col.null).must_equal true - _(col.default).must_equal BigDecimal("12345.01") + _(col.default).must_equal "12345.01" _(obj.decimal_9_2).must_equal BigDecimal("12345.01") _(col.default_function).must_be_nil type = col.cast_type @@ -139,7 +139,7 @@ def assert_obj_set_and_save(attribute, value) it "decimal(16,4)" do col = column("decimal_16_4") _(col.sql_type).must_equal "decimal(16,4)" - _(col.default).must_equal BigDecimal("1234567.89") + _(col.default).must_equal "1234567.89" _(obj.decimal_16_4).must_equal BigDecimal("1234567.89") _(col.default_function).must_be_nil type = col.cast_type @@ -156,7 +156,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "numeric(18,0)" _(col.type).must_equal :decimal _(col.null).must_equal true - _(col.default).must_equal BigDecimal(191) + _(col.default).must_equal "191" _(obj.numeric_18_0).must_equal BigDecimal(191) _(col.default_function).must_be_nil @@ -178,7 +178,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "numeric(36,2)" _(col.type).must_equal :decimal _(col.null).must_equal true - _(col.default).must_equal BigDecimal("12345678901234567890.01") + _(col.default).must_equal "12345678901234567890.01" _(obj.numeric_36_2).must_equal BigDecimal("12345678901234567890.01") _(col.default_function).must_be_nil type = col.cast_type @@ -197,7 +197,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "money" _(col.type).must_equal :money _(col.null).must_equal true - _(col.default).must_equal BigDecimal("4.20") + _(col.default).must_equal "4.20" _(obj.money).must_equal BigDecimal("4.20") _(col.default_function).must_be_nil type = col.cast_type @@ -216,7 +216,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "smallmoney" _(col.type).must_equal :smallmoney _(col.null).must_equal true - _(col.default).must_equal BigDecimal("4.20") + _(col.default).must_equal "4.20" _(obj.smallmoney).must_equal BigDecimal("4.20") _(col.default_function).must_be_nil type = col.cast_type @@ -239,7 +239,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "float" _(col.type).must_equal :float _(col.null).must_equal true - _(col.default).must_equal 123.00000001 + _(col.default).must_equal "123.00000001" _(obj.float).must_equal 123.00000001 _(col.default_function).must_be_nil type = col.cast_type @@ -258,7 +258,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "real" _(col.type).must_equal :real _(col.null).must_equal true - _(col.default).must_be_close_to 123.45, 0.01 + _(col.default).must_equal "123.45" _(obj.real).must_be_close_to 123.45, 0.01 _(col.default_function).must_be_nil type = col.cast_type @@ -279,7 +279,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "date" _(col.type).must_equal :date _(col.null).must_equal true - _(col.default).must_equal Date.civil(1, 1, 1) + _(col.default).must_equal "0001-01-01" _(obj.date).must_equal Date.civil(1, 1, 1) _(col.default_function).must_be_nil type = col.cast_type @@ -317,8 +317,8 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "datetime" _(col.type).must_equal :datetime _(col.null).must_equal true + _(col.default).must_equal "1753-01-01T00:00:00.123" time = Time.utc 1753, 1, 1, 0, 0, 0, 123000 - _(col.default).must_equal time, "Microseconds were <#{col.default.usec}> vs <123000>" _(obj.datetime).must_equal time, "Microseconds were <#{obj.datetime.usec}> vs <123000>" _(col.default_function).must_be_nil type = col.cast_type @@ -363,8 +363,8 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "datetime2(7)" _(col.type).must_equal :datetime _(col.null).must_equal true + _(col.default).must_equal "9999-12-31 23:59:59.9999999" time = Time.utc 9999, 12, 31, 23, 59, 59, Rational(999999900, 1000) - _(col.default).must_equal time, "Nanoseconds were <#{col.default.nsec}> vs <999999900>" _(obj.datetime2_7).must_equal time, "Nanoseconds were <#{obj.datetime2_7.nsec}> vs <999999900>" _(col.default_function).must_be_nil type = col.cast_type @@ -430,7 +430,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "datetimeoffset(7)" _(col.type).must_equal :datetimeoffset _(col.null).must_equal true - _(col.default).must_equal Time.new(1984, 1, 24, 4, 20, 0, -28800).change(nsec: 123456700), "Nanoseconds <#{col.default.nsec}> vs <123456700>" + _(col.default).must_equal "1984-01-24 04:20:00.1234567 -08:00" _(obj.datetimeoffset_7).must_equal Time.new(1984, 1, 24, 4, 20, 0, -28800).change(nsec: 123456700), "Nanoseconds were <#{obj.datetimeoffset_7.nsec}> vs <999999900>" _(col.default_function).must_be_nil type = col.cast_type @@ -476,7 +476,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "smalldatetime" _(col.type).must_equal :smalldatetime _(col.null).must_equal true - _(col.default).must_equal Time.utc(1901, 1, 1, 15, 45, 0, 0) + _(col.default).must_equal "1901-01-01T15:45:00.000Z" _(obj.smalldatetime).must_equal Time.utc(1901, 1, 1, 15, 45, 0, 0) _(col.default_function).must_be_nil type = col.cast_type @@ -498,7 +498,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "time(7)" _(col.type).must_equal :time _(col.null).must_equal true - _(col.default).must_equal Time.utc(1900, 1, 1, 4, 20, 0, Rational(288321500, 1000)), "Nanoseconds were <#{col.default.nsec}> vs <288321500>" + _(col.default).must_equal "04:20:00.2883215" _(col.default_function).must_be_nil type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Time @@ -564,7 +564,7 @@ def assert_obj_set_and_save(attribute, value) _(col.sql_type).must_equal "time(7)" _(col.type).must_equal :time _(col.null).must_equal true - _(col.default).must_equal Time.utc(1900, 1, 1, 15, 3, 42, Rational(62197800, 1000)), "Nanoseconds were <#{col.default.nsec}> vs <62197800>" + _(col.default).must_equal "15:03:42.0621978" _(col.default_function).must_be_nil type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Time diff --git a/test/cases/migration_test_sqlserver.rb b/test/cases/migration_test_sqlserver.rb index 888e67d83..60b5d26a5 100644 --- a/test/cases/migration_test_sqlserver.rb +++ b/test/cases/migration_test_sqlserver.rb @@ -34,7 +34,7 @@ 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_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"]