diff --git a/lib/active_record/connection_adapters/sqlserver/quoting.rb b/lib/active_record/connection_adapters/sqlserver/quoting.rb index 1aad866ed..93b0e020d 100644 --- a/lib/active_record/connection_adapters/sqlserver/quoting.rb +++ b/lib/active_record/connection_adapters/sqlserver/quoting.rb @@ -67,7 +67,15 @@ def quoted_false def quoted_datetime(value) if value.acts_like?(:time) - value.is_a?(Date) ? quoted_value_acts_like_time_filter(value).to_time.xmlschema.to(18) : quoted_value_acts_like_time_filter(value).iso8601(3).to(22) + time_zone_qualified_value = quoted_value_acts_like_time_filter(value) + if value.is_a?(Date) + time_zone_qualified_value.to_time.xmlschema.to(18) + else + if value.is_a?(ActiveSupport::TimeWithZone) + time_zone_qualified_value = time_zone_qualified_value.to_time + end + time_zone_qualified_value.iso8601(3).to(22) + end else quoted_date(value) end diff --git a/test/cases/adapter_test_sqlserver.rb b/test/cases/adapter_test_sqlserver.rb index 46a4853ee..138cb06a2 100644 --- a/test/cases/adapter_test_sqlserver.rb +++ b/test/cases/adapter_test_sqlserver.rb @@ -337,7 +337,7 @@ def setup end context 'For Quoting' do - + should 'return 1 for #quoted_true' do assert_equal '1', @connection.quoted_true end @@ -366,7 +366,268 @@ def setup assert_equal '[foo].[bar]', @connection.quote_column_name('foo.bar') assert_equal '[foo].[bar].[baz]', @connection.quote_column_name('foo.bar.baz') end - + + context "#quote" do + + context "string and multibyte values" do + + context "on an activerecord :integer column" do + + setup do + @column = stub("column", :type => :integer) + end + + should "return null for empty string" do + assert_nil @connection.quote('', @column) + end + + end + + context "on an activerecord :binary column" do + + setup do + @column = stub("column", :type => :binary) + end + + should "ask the column class to convert the value" do + value = "value" + result = stub("result") + @column.class.stubs(:string_to_binary).with(value).returns(result) + assert_equal result, @connection.quote(value, @column) + end + + end + + context "on an activerecord :string column or with any value that is_utf8?" do + + should "surround it when N'...'" do + assert_equal "N'foo'", @connection.quote("foo") + end + + should "escape all single quotes by repeating them" do + assert_equal "N'''quotation''s'''", @connection.quote("'quotation's'") + end + + end + + context "with a value that's not is_utf8?" do + + setup do + @value = "value" + @value.stubs(:is_utf8? => false) + end + + should_eventually "call super" + + end + + end + + context "date and time values" do + + setup do + @value = Date.today + end + + context "on a sql datetime column" do + + setup do + @column = stub("column", :sql_type => 'datetime') + end + + should "call quoted_datetime and surrounds its result with single quotes" do + @connection.stubs(:quoted_datetime).with(@value).returns("2000-01-01") + assert_equal "'2000-01-01'", @connection.quote(@value, @column) + end + + end + + context "on a sql datetimeoffset column" do + + setup do + @column = stub("column", :sql_type => 'datetimeoffset') + end + + should "call quoted_full_iso8601 and surrounds its result with single quotes" do + @connection.stubs(:quoted_full_iso8601).with(@value).returns("2000-01-01") + assert_equal "'2000-01-01'", @connection.quote(@value, @column) + end + + end + + context "on a sql time column" do + + setup do + @column = stub("column", :sql_type => 'time') + end + + should "call quoted_full_iso8601 and surrounds its result with single quotes" do + @connection.stubs(:quoted_full_iso8601).with(@value).returns("2000-01-01") + assert_equal "'2000-01-01'", @connection.quote(@value, @column) + end + + end + + context "with another sql column" do + + setup do + @column = stub("column", :sql_type => 'foo') + end + + should_eventually "call super" + + end + + context "with no column" do + + should_eventually "call super" + + end + + end + + context "nil values" do + + context "on a sql timestamp column" do + + setup do + @column = stub("column", :sql_type => 'timestamp') + end + + should "return DEFAULT" do + assert_equal "DEFAULT", @connection.quote(nil, @column) + end + + end + + context "with another sql column" do + + setup do + @column = stub("column", :sql_type => 'foo') + end + + should_eventually "call super" + + end + + end + + context "other values" do + + setup do + @value = stub("value") + end + + should_eventually "call super" + + end + + end + + context "#quoted_datetime" do + + context "with a Date" do + + setup do + @value = Date.parse('2001-02-03T04:05:06-0700') + assert @value.is_a?(Date) + end + + should "return a dd-mm-yyyy date string" do + assert_equal '02-03-2001', @connection.quoted_datetime(@value) + end + + end + + context "when the ActiveRecord default timezone is UTC" do + + setup do + @old_activerecord_timezone = ActiveRecord::Base.default_timezone + ActiveRecord::Base.default_timezone = :utc + end + + teardown do + ActiveRecord::Base.default_timezone = @old_activerecord_timezone + @old_activerecord_timezone = nil + end + + context "with a Time" do + + setup do + @value = Time.parse('2001-02-03T04:05:06-0700') + assert @value.is_a?(Time) + end + + should "return an ISO 8601 datetime string" do + assert_equal '2001-02-03T11:05:06.000', @connection.quoted_datetime(@value) + end + + end + + context "with a DateTime" do + + setup do + @value = DateTime.parse('2001-02-03T04:05:06-0700') + assert @value.is_a?(DateTime) + end + + should "return an ISO 8601 datetime string" do + assert_equal '2001-02-03T11:05:06', @connection.quoted_datetime(@value) + end + + end + + context "with an ActiveSupport::TimeWithZone" do + + setup do + require 'tzinfo' + @old_zone = Time.zone + Time.zone = 'Eastern Time (US & Canada)' + end + + teardown do + Time.zone = @old_zone + @old_zone = nil + end + + context "wrapping a datetime" do + + setup do + @value = DateTime.parse('2001-02-03T04:05:06-0700').in_time_zone + assert @value.is_a?(ActiveSupport::TimeWithZone) + end + + should "return an ISO 8601 datetime string with milliseconds" do + assert_equal '2001-02-03T11:05:06.000', @connection.quoted_datetime(@value) + end + + end + + context "wrapping a time" do + + setup do + @value = Time.parse('2001-02-03T04:05:06-0700').in_time_zone + assert @value.is_a?(ActiveSupport::TimeWithZone) + end + + should "return an ISO 8601 datetime string with milliseconds" do + assert_equal '2001-02-03T11:05:06.000', @connection.quoted_datetime(@value) + end + + end + + end + + context "with a String" do + + should_eventually "call quoted_date on super" + + end + + end + + end + end context 'When disabling referential integrity' do