diff --git a/Dockerfile.ci b/Dockerfile.ci index aad53b3cb..cfecca3a2 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -9,6 +9,6 @@ WORKDIR $WORKDIR COPY . $WORKDIR -RUN RAILS_COMMIT=65dc2163e3 bundle install --jobs `expr $(cat /proc/cpuinfo | grep -c "cpu cores") - 1` --retry 3 +RUN RAILS_BRANCH=main bundle install --jobs `expr $(cat /proc/cpuinfo | grep -c "cpu cores") - 1` --retry 3 CMD ["sh"] diff --git a/compose.ci.yaml b/compose.ci.yaml index 12fcae5ce..8242db9b8 100644 --- a/compose.ci.yaml +++ b/compose.ci.yaml @@ -4,7 +4,7 @@ services: ci: environment: - ACTIVERECORD_UNITTEST_HOST=sqlserver - - RAILS_COMMIT=65dc2163e3 + - RAILS_BRANCH=main build: context: . dockerfile: Dockerfile.ci @@ -13,7 +13,7 @@ services: - "sqlserver" standardrb: environment: - - RAILS_COMMIT=65dc2163e3 + - RAILS_BRANCH=main build: context: . dockerfile: Dockerfile.ci diff --git a/lib/active_record/connection_adapters/sqlserver/database_statements.rb b/lib/active_record/connection_adapters/sqlserver/database_statements.rb index 657e31417..a3fbe0126 100644 --- a/lib/active_record/connection_adapters/sqlserver/database_statements.rb +++ b/lib/active_record/connection_adapters/sqlserver/database_statements.rb @@ -16,7 +16,7 @@ def write_query?(sql) # :nodoc: def perform_query(raw_connection, intent) sql = intent.processed_sql - unless intent.binds.nil? || intent.binds.empty? + if intent.has_binds? types, params = sp_executesql_types_and_parameters(intent.binds) sql = sp_executesql_sql(intent.processed_sql, types, params, intent.notification_payload[:name]) end @@ -73,15 +73,12 @@ def delete(arel, name = nil, binds = []) intent = QueryIntent.new(adapter: self, arel: arel, name: name, binds: binds) - # Compile Arel to get SQL - compile_arel_in_intent(intent) - # Add `SELECT @@ROWCOUNT` to the end of the SQL to get the number of affected rows. This is needed because SQL Server does not return the number of affected rows in the same way as other databases. sql = intent.processed_sql.present? ? intent.processed_sql : intent.raw_sql - ensure_writes_are_allowed(sql) if write_query?(sql) - intent.processed_sql = "#{sql}; SELECT @@ROWCOUNT AS AffectedRows" + intent.instance_variable_set(:@processed_sql, "#{sql}; SELECT @@ROWCOUNT AS AffectedRows") - affected_rows(raw_execute(intent)) + intent.execute! + intent.affected_rows end # Executes the update statement and returns the number of rows affected. @@ -93,19 +90,16 @@ def update(arel, name = nil, binds = []) intent = QueryIntent.new(adapter: self, arel: arel, name: name, binds: binds) - # Compile Arel to get SQL - compile_arel_in_intent(intent) - # Add `SELECT @@ROWCOUNT` to the end of the SQL to get the number of affected rows. This is needed because SQL Server does not return the number of affected rows in the same way as other databases. sql = intent.processed_sql.present? ? intent.processed_sql : intent.raw_sql - ensure_writes_are_allowed(sql) if write_query?(sql) - intent.processed_sql = "#{sql}; SELECT @@ROWCOUNT AS AffectedRows" + intent.instance_variable_set(:@processed_sql, "#{sql}; SELECT @@ROWCOUNT AS AffectedRows") - affected_rows(raw_execute(intent)) + intent.execute! + intent.affected_rows end def begin_db_transaction - internal_execute("BEGIN TRANSACTION", "TRANSACTION", allow_retry: true, materialize_transactions: false) + query_command("BEGIN TRANSACTION", "TRANSACTION", allow_retry: true, materialize_transactions: false) end def transaction_isolation_levels @@ -118,15 +112,15 @@ def begin_isolated_db_transaction(isolation) end def set_transaction_isolation_level(isolation_level) - internal_execute("SET TRANSACTION ISOLATION LEVEL #{isolation_level}", "TRANSACTION", allow_retry: true, materialize_transactions: false) + query_command("SET TRANSACTION ISOLATION LEVEL #{isolation_level}", "TRANSACTION", allow_retry: true, materialize_transactions: false) end def commit_db_transaction - internal_execute("COMMIT TRANSACTION", "TRANSACTION", allow_retry: false, materialize_transactions: true) + query_command("COMMIT TRANSACTION", "TRANSACTION", allow_retry: false, materialize_transactions: true) end def exec_rollback_db_transaction - internal_execute("IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION", "TRANSACTION", allow_retry: false, materialize_transactions: true) + query_command("IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION", "TRANSACTION", allow_retry: false, materialize_transactions: true) end def case_sensitive_comparison(attribute, value) @@ -370,7 +364,7 @@ def newsequentialid_function def sql_for_insert(sql, pk, binds, returning) if pk.nil? table_name = query_requires_identity_insert?(sql) - pk = primary_key(table_name) + pk = schema_cache.primary_keys(table_name) end sql = if pk && use_output_inserted? && !database_prefix_remote_server? diff --git a/lib/active_record/connection_adapters/sqlserver/quoting.rb b/lib/active_record/connection_adapters/sqlserver/quoting.rb index 5f609aaa0..ca0369587 100644 --- a/lib/active_record/connection_adapters/sqlserver/quoting.rb +++ b/lib/active_record/connection_adapters/sqlserver/quoting.rb @@ -79,6 +79,7 @@ def quote_string_single_national(s) def quote_default_expression(value, column) cast_type = lookup_cast_type(column.sql_type) + if cast_type.type == :uuid && value.is_a?(String) && value.include?("()") value else @@ -118,7 +119,7 @@ def quote(value) "0x#{value.hex}" when ActiveRecord::Type::SQLServer::Data value.quoted - when String, ActiveSupport::Multibyte::Chars + when String "N#{super}" else super @@ -133,6 +134,10 @@ def type_cast(value) super end end + + def lookup_cast_type(sql_type) + type_map.lookup(sql_type) + end end end end diff --git a/lib/active_record/connection_adapters/sqlserver/savepoints.rb b/lib/active_record/connection_adapters/sqlserver/savepoints.rb index 915cd07bb..e68f2f673 100644 --- a/lib/active_record/connection_adapters/sqlserver/savepoints.rb +++ b/lib/active_record/connection_adapters/sqlserver/savepoints.rb @@ -9,11 +9,11 @@ def current_savepoint_name end def create_savepoint(name = current_savepoint_name) - internal_execute("SAVE TRANSACTION #{name}", "TRANSACTION") + query_command("SAVE TRANSACTION #{name}", "TRANSACTION") end def exec_rollback_to_savepoint(name = current_savepoint_name) - internal_execute("ROLLBACK TRANSACTION #{name}", "TRANSACTION") + query_command("ROLLBACK TRANSACTION #{name}", "TRANSACTION") end # SQL Server does require save-points to be explicitly released. diff --git a/lib/active_record/connection_adapters/sqlserver/schema_statements.rb b/lib/active_record/connection_adapters/sqlserver/schema_statements.rb index 87194ef40..1d58747a1 100644 --- a/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +++ b/lib/active_record/connection_adapters/sqlserver/schema_statements.rb @@ -10,31 +10,34 @@ def create_table(table_name, **options) res end - def drop_table(*table_names, **options) - table_names.each do |table_name| - # Mimic CASCADE option as best we can. - if options[:force] == :cascade - execute_procedure(:sp_fkeys, pktable_name: table_name).each do |fkdata| - fktable = fkdata["FKTABLE_NAME"] - fkcolmn = fkdata["FKCOLUMN_NAME"] - pktable = fkdata["PKTABLE_NAME"] - pkcolmn = fkdata["PKCOLUMN_NAME"] - remove_foreign_key fktable, name: fkdata["FK_NAME"] - execute "DELETE FROM #{quote_table_name(fktable)} WHERE #{quote_column_name(fkcolmn)} IN ( SELECT #{quote_column_name(pkcolmn)} FROM #{quote_table_name(pktable)} )" - end - end - if options[:if_exists] && version_year < 2016 - execute "IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #{quote(table_name)}) DROP TABLE #{quote_table_name(table_name)}", "SCHEMA" - else - super + def drop_table_sql(table_name, if_exists: nil, force: nil, **) + sqls = [] + + # Mimic CASCADE option as best we can. + if force == :cascade + execute_procedure(:sp_fkeys, pktable_name: table_name).each do |fkdata| + fktable = fkdata["FKTABLE_NAME"] + fkcolmn = fkdata["FKCOLUMN_NAME"] + pktable = fkdata["PKTABLE_NAME"] + pkcolmn = fkdata["PKCOLUMN_NAME"] + remove_foreign_key fktable, name: fkdata["FK_NAME"] + + sqls << "DELETE FROM #{quote_table_name(fktable)} WHERE #{quote_column_name(fkcolmn)} IN ( SELECT #{quote_column_name(pkcolmn)} FROM #{quote_table_name(pktable)} )" end end + + sqls << if if_exists && version_year < 2016 + "IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #{quote(table_name)}) DROP TABLE #{quote_table_name(table_name)}" + else + super + end + + sqls.join("; ") end def indexes(table_name) data = begin - intent = QueryIntent.new(adapter: self, raw_sql: "EXEC sp_helpindex #{quote(table_name)}", name: "SCHEMA") - select(intent) + select_all("EXEC sp_helpindex #{quote(table_name)}", "SCHEMA") rescue [] end @@ -162,7 +165,7 @@ def primary_keys_select(table_name) binds << Relation::QueryAttribute.new("TABLE_NAME", identifier.object, nv128) binds << Relation::QueryAttribute.new("TABLE_SCHEMA", identifier.schema, nv128) unless identifier.schema.blank? - internal_exec_query(sql, "SCHEMA", binds).map { |row| row["name"] } + select_all(sql, "SCHEMA", binds).map { |row| row["name"] } end def rename_table(table_name, new_name, **options) @@ -323,7 +326,7 @@ def check_constraints(table_name) st.name = '#{table_name}' SQL - chk_info = internal_exec_query(sql, "SCHEMA") + chk_info = select_all(sql, "SCHEMA") chk_info.map do |row| options = { @@ -513,7 +516,7 @@ def column_definitions(table_name) FROM #{database}.INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = #{quote(view_table_name(table_name))} SQL - results = internal_exec_query(sql, "SCHEMA") + results = select_all(sql, "SCHEMA") default_functions = results.each.with_object({}) { |row, out| out[row["name"]] = row["default"] }.compact end @@ -524,7 +527,7 @@ def column_definitions(table_name) binds << Relation::QueryAttribute.new("TABLE_NAME", identifier.object, nv128) binds << Relation::QueryAttribute.new("TABLE_SCHEMA", identifier.schema, nv128) unless identifier.schema.blank? - results = internal_exec_query(sql, "SCHEMA", binds) + results = select_all(sql, "SCHEMA", binds) raise ActiveRecord::StatementInvalid, "Table '#{table_name}' doesn't exist" if results.empty? results.map do |ci| diff --git a/lib/active_record/connection_adapters/sqlserver/showplan.rb b/lib/active_record/connection_adapters/sqlserver/showplan.rb index f35e26053..f07408c4a 100644 --- a/lib/active_record/connection_adapters/sqlserver/showplan.rb +++ b/lib/active_record/connection_adapters/sqlserver/showplan.rb @@ -14,7 +14,7 @@ module Showplan def explain(arel, binds = [], options = []) sql = to_sql(arel) - result = with_showplan_on { internal_exec_query(sql, "EXPLAIN", binds) } + result = with_showplan_on { select_all(sql, "EXPLAIN", binds) } printer = showplan_printer.new(result) printer.pp @@ -31,7 +31,8 @@ def with_showplan_on def set_showplan_option(enable = true) intent = QueryIntent.new(adapter: self, raw_sql: "SET #{showplan_option} #{enable ? "ON" : "OFF"}", name: "SCHEMA") - raw_execute(intent) + intent.execute! + intent.finish rescue raise ActiveRecordError, "#{showplan_option} could not be turned #{enable ? "ON" : "OFF"}, perhaps you do not have SHOWPLAN permissions?" end diff --git a/test/cases/adapter_test_sqlserver.rb b/test/cases/adapter_test_sqlserver.rb index 6d5c87d61..b6c35f210 100644 --- a/test/cases/adapter_test_sqlserver.rb +++ b/test/cases/adapter_test_sqlserver.rb @@ -615,7 +615,9 @@ def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes it "records can be inserted using SQL" do assert_difference("Alien.count", 2) do - Alien.lease_connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')") + assert_deprecated(ActiveRecord.deprecator) do + Alien.lease_connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')") + end end end end @@ -630,9 +632,14 @@ def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes describe "exec_insert" do it "values clause should be case-insensitive" do + first_insert = nil + second_insert = nil + assert_difference("Post.count", 4) do - first_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) VALUES(100, 'Title', 'Body'), (102, 'Title', 'Body')") - second_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) values(113, 'Body', 'Body'), (114, 'Body', 'Body')") + assert_deprecated(ActiveRecord.deprecator) do + first_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) VALUES(100, 'Title', 'Body'), (102, 'Title', 'Body')") + second_insert = connection.exec_insert("INSERT INTO [posts] ([id],[title],[body]) values(113, 'Body', 'Body'), (114, 'Body', 'Body')") + end assert_equal first_insert.rows.map(&:first), [100, 102] assert_equal second_insert.rows.map(&:first), [113, 114] diff --git a/test/cases/coerced_tests.rb b/test/cases/coerced_tests.rb index 44087dbe9..2c75db1b1 100644 --- a/test/cases/coerced_tests.rb +++ b/test/cases/coerced_tests.rb @@ -523,8 +523,8 @@ def test_create_table_with_defaults_coerce five = columns.detect { |c| c.name == "five" } assert_equal "hello", one.default - assert_equal true, two.fetch_cast_type(connection).deserialize(two.default) - assert_equal false, three.fetch_cast_type(connection).deserialize(three.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 @@ -1993,20 +1993,6 @@ class SchemaCacheTest < ActiveRecord::TestCase # Tests fail on Windows AppVeyor CI with 'Permission denied' error when renaming file during `File.atomic_write` call. coerce_tests! :test_yaml_dump_and_load, :test_yaml_dump_and_load_with_gzip if /mswin|mingw/.match?(RbConfig::CONFIG["host_os"]) - # Cast type in SQL Server is :varchar rather than Unicode :string. - coerce_tests! :test_yaml_load_8_0_dump_without_cast_type_still_get_the_right_one - def test_yaml_load_8_0_dump_without_cast_type_still_get_the_right_one - cache = load_bound_reflection(schema_dump_8_0_path) - - assert_no_queries do - columns = cache.columns_hash("courses") - assert_equal 3, columns.size - cast_type = columns["name"].fetch_cast_type(@connection) - assert_not_nil cast_type, "expected cast_type to be present" - assert_equal :varchar, cast_type.type - end - end - private # We need to give the full paths for this to work. @@ -2014,11 +2000,6 @@ def test_yaml_load_8_0_dump_without_cast_type_still_get_the_right_one def schema_dump_5_1_path File.join(ARTest::SQLServer.root_activerecord, "test/assets/schema_dump_5_1.yml") end - - undef_method :schema_dump_8_0_path - def schema_dump_8_0_path - File.join(ARTest::SQLServer.root_activerecord, "test/assets/schema_dump_8_0.yml") - end end end end @@ -2843,3 +2824,33 @@ def test_in_batches_loaded_should_unscope_cursor_after_pluck_coerced end end +class TransactionInstrumentationTest < ActiveRecord::TestCase + # SQL Server does not have query for release_savepoint. + coerce_tests! :test_sql_events_do_not_overlap_with_savepoints + def test_sql_events_do_not_overlap_with_savepoints_coerced + events = [] + subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event| + events << event + end + + Topic.transaction do + Topic.count + Topic.transaction(requires_new: true) { Topic.first } + end + + assert_equal 5, events.size + begin_event, count_event, savepoint_event, select_event, commit_event = events + + assert begin_event.payload[:sql].start_with?("BEGIN") + assert count_event.payload[:sql].start_with?("SELECT") + assert savepoint_event.payload[:sql].start_with?("SAVE TRANSACTION") + assert select_event.payload[:sql].start_with?("SELECT") + assert commit_event.payload[:sql].start_with?("COMMIT") + + events.each_cons(2) do |a, b| + assert_operator a.end, :<=, b.time + end + ensure + ActiveSupport::Notifications.unsubscribe(subscriber) + end +end diff --git a/test/cases/column_test_sqlserver.rb b/test/cases/column_test_sqlserver.rb index e55937662..b4ae10d11 100644 --- a/test/cases/column_test_sqlserver.rb +++ b/test/cases/column_test_sqlserver.rb @@ -44,7 +44,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal 42 _(obj.bigint).must_equal 42 _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::BigInteger _(type.limit).must_equal 8 assert_obj_set_and_save :bigint, -9_223_372_036_854_775_808 @@ -59,7 +59,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal 42 _(obj.int).must_equal 42 _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Integer _(type.limit).must_equal 4 assert_obj_set_and_save :int, -2_147_483_648 @@ -74,7 +74,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal 42 _(obj.smallint).must_equal 42 _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::SmallInteger _(type.limit).must_equal 2 assert_obj_set_and_save :smallint, -32_768 @@ -89,7 +89,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal 42 _(obj.tinyint).must_equal 42 _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::TinyInteger _(type.limit).must_equal 1 assert_obj_set_and_save :tinyint, 0 @@ -104,7 +104,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal true _(obj.bit).must_equal true _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Boolean _(type.limit).must_be_nil obj.bit = 0 @@ -125,7 +125,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal BigDecimal("12345.01") _(obj.decimal_9_2).must_equal BigDecimal("12345.01") _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Decimal _(type.limit).must_be_nil _(type.precision).must_equal 9 @@ -142,7 +142,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal BigDecimal("1234567.89") _(obj.decimal_16_4).must_equal BigDecimal("1234567.89") _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type.precision).must_equal 16 _(type.scale).must_equal 4 obj.decimal_16_4 = "1234567.8901001" @@ -160,7 +160,7 @@ def assert_obj_set_and_save(attribute, value) _(obj.numeric_18_0).must_equal BigDecimal(191) _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::DecimalWithoutScale _(type.limit).must_be_nil _(type.precision).must_equal 18 @@ -181,7 +181,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal BigDecimal("12345678901234567890.01") _(obj.numeric_36_2).must_equal BigDecimal("12345678901234567890.01") _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Decimal _(type.limit).must_be_nil _(type.precision).must_equal 36 @@ -200,7 +200,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal BigDecimal("4.20") _(obj.money).must_equal BigDecimal("4.20") _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Money _(type.limit).must_be_nil _(type.precision).must_equal 19 @@ -219,7 +219,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal BigDecimal("4.20") _(obj.smallmoney).must_equal BigDecimal("4.20") _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::SmallMoney _(type.limit).must_be_nil _(type.precision).must_equal 10 @@ -242,7 +242,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal 123.00000001 _(obj.float).must_equal 123.00000001 _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Float _(type.limit).must_be_nil _(type.precision).must_be_nil @@ -261,7 +261,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_be_close_to 123.45, 0.01 _(obj.real).must_be_close_to 123.45, 0.01 _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Real _(type.limit).must_be_nil _(type.precision).must_be_nil @@ -282,7 +282,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal Date.civil(1, 1, 1) _(obj.date).must_equal Date.civil(1, 1, 1) _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Date _(type.limit).must_be_nil _(type.precision).must_be_nil @@ -321,7 +321,7 @@ def assert_obj_set_and_save(attribute, value) _(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.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::DateTime _(type.limit).must_be_nil _(type.precision).must_be_nil @@ -367,7 +367,7 @@ def assert_obj_set_and_save(attribute, value) _(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.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::DateTime2 _(type.limit).must_be_nil _(type.precision).must_equal 7 @@ -397,7 +397,7 @@ def assert_obj_set_and_save(attribute, value) # datetime2_3 time = Time.utc 9999, 12, 31, 23, 59, 59, Rational(123456789, 1000) col = column("datetime2_3") - _(col.fetch_cast_type(connection).precision).must_equal 3 + _(col.cast_type.precision).must_equal 3 obj.datetime2_3 = time _(obj.datetime2_3).must_equal time.change(nsec: 123000000), "Nanoseconds were <#{obj.datetime2_3.nsec}> vs <123000000>" obj.save! @@ -406,7 +406,7 @@ def assert_obj_set_and_save(attribute, value) _(obj).must_equal obj.class.where(datetime2_3: time).first # datetime2_1 col = column("datetime2_1") - _(col.fetch_cast_type(connection).precision).must_equal 1 + _(col.cast_type.precision).must_equal 1 obj.datetime2_1 = time _(obj.datetime2_1).must_equal time.change(nsec: 100000000), "Nanoseconds were <#{obj.datetime2_1.nsec}> vs <100000000>" obj.save! @@ -415,7 +415,7 @@ def assert_obj_set_and_save(attribute, value) _(obj).must_equal obj.class.where(datetime2_1: time).first # datetime2_0 col = column("datetime2_0") - _(col.fetch_cast_type(connection).precision).must_equal 0 + _(col.cast_type.precision).must_equal 0 time = Time.utc 2016, 4, 19, 16, 45, 40, 771036 obj.datetime2_0 = time _(obj.datetime2_0).must_equal time.change(nsec: 0), "Nanoseconds were <#{obj.datetime2_0.nsec}> vs <0>" @@ -433,7 +433,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal Time.new(1984, 1, 24, 4, 20, 0, -28800).change(nsec: 123456700), "Nanoseconds <#{col.default.nsec}> vs <123456700>" _(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.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::DateTimeOffset _(type.limit).must_be_nil _(type.precision).must_equal 7 @@ -458,13 +458,13 @@ def assert_obj_set_and_save(attribute, value) # With other precisions. time = ActiveSupport::TimeZone["America/Los_Angeles"].local 2010, 12, 31, 23, 59, 59, Rational(123456755, 1000) col = column("datetimeoffset_3") - _(col.fetch_cast_type(connection).precision).must_equal 3 + _(col.cast_type.precision).must_equal 3 obj.datetimeoffset_3 = time _(obj.datetimeoffset_3).must_equal time.change(nsec: 123000000), "Nanoseconds were <#{obj.datetimeoffset_3.nsec}> vs <123000000>" obj.save! _(obj.datetimeoffset_3).must_equal time.change(nsec: 123000000), "Nanoseconds were <#{obj.datetimeoffset_3.nsec}> vs <123000000>" col = column("datetime2_1") - _(col.fetch_cast_type(connection).precision).must_equal 1 + _(col.cast_type.precision).must_equal 1 obj.datetime2_1 = time _(obj.datetime2_1).must_equal time.change(nsec: 100000000), "Nanoseconds were <#{obj.datetime2_1.nsec}> vs <100000000>" obj.save! @@ -479,7 +479,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal Time.utc(1901, 1, 1, 15, 45, 0, 0) _(obj.smalldatetime).must_equal Time.utc(1901, 1, 1, 15, 45, 0, 0) _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::SmallDateTime _(type.limit).must_be_nil _(type.precision).must_be_nil @@ -500,7 +500,7 @@ def assert_obj_set_and_save(attribute, value) _(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_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Time _(type.limit).must_be_nil _(type.precision).must_equal 7 @@ -534,7 +534,7 @@ def assert_obj_set_and_save(attribute, value) _(col.null).must_equal true _(col.default).must_be_nil _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Time _(type.limit).must_be_nil _(type.precision).must_equal 2 @@ -566,7 +566,7 @@ def assert_obj_set_and_save(attribute, value) _(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_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Time _(type.limit).must_be_nil _(type.precision).must_equal 7 @@ -603,7 +603,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal "1234567890" _(obj.char_10).must_equal "1234567890" _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Char _(type.limit).must_equal 10 _(type.precision).must_be_nil @@ -623,7 +623,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal "test varchar_50" _(obj.varchar_50).must_equal "test varchar_50" _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Varchar _(type.limit).must_equal 50 _(type.precision).must_be_nil @@ -640,7 +640,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal "test varchar_max" _(obj.varchar_max).must_equal "test varchar_max" _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::VarcharMax _(type.limit).must_equal 2_147_483_647 _(type.precision).must_be_nil @@ -657,7 +657,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal "test text" _(obj.text).must_equal "test text" _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Text _(type.limit).must_equal 2_147_483_647 _(type.precision).must_be_nil @@ -676,7 +676,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal "12345678åå" _(obj.nchar_10).must_equal "12345678åå" _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::UnicodeChar _(type.limit).must_equal 10 _(type.precision).must_be_nil @@ -696,7 +696,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal "test nvarchar_50 åå" _(obj.nvarchar_50).must_equal "test nvarchar_50 åå" _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::UnicodeVarchar _(type.limit).must_equal 50 _(type.precision).must_be_nil @@ -713,7 +713,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal "test nvarchar_max åå" _(obj.nvarchar_max).must_equal "test nvarchar_max åå" _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::UnicodeVarcharMax _(type.limit).must_equal 2_147_483_647 _(type.precision).must_be_nil @@ -730,7 +730,7 @@ def assert_obj_set_and_save(attribute, value) _(col.default).must_equal "test ntext åå" _(obj.ntext).must_equal "test ntext åå" _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::UnicodeText _(type.limit).must_equal 2_147_483_647 _(type.precision).must_be_nil @@ -751,7 +751,7 @@ def assert_obj_set_and_save(attribute, value) _(col.null).must_equal true _(col.default).must_be_nil _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Binary _(type.limit).must_equal 49 _(type.precision).must_be_nil @@ -772,7 +772,7 @@ def assert_obj_set_and_save(attribute, value) _(col.null).must_equal true _(col.default).must_be_nil _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Varbinary _(type.limit).must_equal 49 _(type.precision).must_be_nil @@ -793,7 +793,7 @@ def assert_obj_set_and_save(attribute, value) _(col.null).must_equal true _(col.default).must_be_nil _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::VarbinaryMax _(type.limit).must_equal 2_147_483_647 _(type.precision).must_be_nil @@ -812,7 +812,7 @@ def assert_obj_set_and_save(attribute, value) _(col.null).must_equal true _(col.default).must_be_nil _(col.default_function).must_equal "newid()" - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Uuid _(type.limit).must_be_nil _(type.precision).must_be_nil @@ -837,7 +837,7 @@ def assert_obj_set_and_save(attribute, value) _(col.null).must_equal true _(col.default).must_be_nil _(col.default_function).must_be_nil - type = col.fetch_cast_type(connection) + type = col.cast_type _(type).must_be_instance_of ActiveRecord::ConnectionAdapters::SQLServer::Type::Timestamp _(type.limit).must_be_nil _(type.precision).must_be_nil