Skip to content

Commit 31c5fb9

Browse files
authored
Fix precision handling for datetimeoffset migration (#1143)
1 parent 7e07687 commit 31c5fb9

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#### Fixed
44

55
- [#1145](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1145) Ensure correct order of COLLATE and NOT NULL in CREATE TABLE statements
6+
- [#1143](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1143) Fix precision handling for datetimeoffset migration
67

78
## v7.1.0
89

lib/active_record/connection_adapters/sqlserver/schema_statements.rb

+10
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,16 @@ def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
313313
end
314314
end
315315
column_type_sql
316+
when "datetimeoffset"
317+
column_type_sql = super
318+
if precision
319+
if (0..7) === precision
320+
column_type_sql << "(#{precision})"
321+
else
322+
raise(ActiveRecordError, "The datetimeoffset type has precision of #{precision}. The allowed range of precision is from 0 to 7.")
323+
end
324+
end
325+
column_type_sql
316326
else
317327
super
318328
end

test/cases/active_schema_test_sqlserver.rb

+38-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
66
describe "indexes" do
7-
87
before do
98
connection.create_table :schema_test_table, force: true, id: false do |t|
109
t.column :foo, :string, limit: 100
@@ -54,13 +53,45 @@ class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
5453
end
5554
end
5655

57-
it "create column with NOT NULL and COLLATE" do
58-
assert_nothing_raised do
59-
connection.create_table :not_null_with_collation_table, force: true, id: false do |t|
60-
t.text :not_null_text_with_collation, null: false, collation: "Latin1_General_CS_AS"
56+
describe 'collation' do
57+
it "create column with NOT NULL and COLLATE" do
58+
assert_nothing_raised do
59+
connection.create_table :not_null_with_collation_table, force: true, id: false do |t|
60+
t.text :not_null_text_with_collation, null: false, collation: "Latin1_General_CS_AS"
61+
end
62+
end
63+
ensure
64+
connection.drop_table :not_null_with_collation_table rescue nil
65+
end
66+
end
67+
68+
describe 'datetimeoffset precision' do
69+
it 'valid precisions are correct' do
70+
assert_nothing_raised do
71+
connection.create_table :datetimeoffset_precisions do |t|
72+
t.datetimeoffset :precision_default
73+
t.datetimeoffset :precision_5, precision: 5
74+
t.datetimeoffset :precision_7, precision: 7
75+
end
76+
end
77+
78+
columns = connection.columns("datetimeoffset_precisions")
79+
80+
assert_equal columns.find { |column| column.name == "precision_default" }.precision, 7
81+
assert_equal columns.find { |column| column.name == "precision_5" }.precision, 5
82+
assert_equal columns.find { |column| column.name == "precision_7" }.precision, 7
83+
ensure
84+
connection.drop_table :datetimeoffset_precisions rescue nil
85+
end
86+
87+
it 'invalid precision raises exception' do
88+
assert_raise(ActiveRecord::ActiveRecordError) do
89+
connection.create_table :datetimeoffset_precisions do |t|
90+
t.datetimeoffset :precision_8, precision: 8
91+
end
6192
end
93+
ensure
94+
connection.drop_table :datetimeoffset_precisions rescue nil
6295
end
63-
ensure
64-
connection.drop_table :not_null_with_collation_table rescue nil
6596
end
6697
end

test/cases/column_test_sqlserver.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -435,20 +435,23 @@ def assert_obj_set_and_save(attribute, value)
435435
_(type.limit).must_be_nil
436436
_(type.precision).must_equal 7
437437
_(type.scale).must_be_nil
438-
# Can save 100 nanosecond precisoins and return again.
438+
439+
# Can save 100 nanosecond precisions and return again.
439440
obj.datetimeoffset_7 = Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456755)
440441
_(obj.datetimeoffset_7).must_equal Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456800), "Nanoseconds were <#{obj.datetimeoffset_7.nsec}> vs <123456800>"
441442
obj.save!
442443
_(obj.datetimeoffset_7).must_equal Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456800), "Nanoseconds were <#{obj.datetimeoffset_7.nsec}> vs <123456800>"
443444
obj.reload
444445
_(obj.datetimeoffset_7).must_equal Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456800), "Nanoseconds were <#{obj.datetimeoffset_7.nsec}> vs <123456800>"
446+
445447
# Maintains the timezone
446448
time = ActiveSupport::TimeZone["America/Los_Angeles"].local 2010, 12, 31, 23, 59, 59, Rational(123456800, 1000)
447449
obj.datetimeoffset_7 = time
448450
_(obj.datetimeoffset_7).must_equal time
449451
obj.save!
450452
_(obj.datetimeoffset_7).must_equal time
451453
_(obj.reload.datetimeoffset_7).must_equal time
454+
452455
# With other precisions.
453456
time = ActiveSupport::TimeZone["America/Los_Angeles"].local 2010, 12, 31, 23, 59, 59, Rational(123456755, 1000)
454457
col = column("datetimeoffset_3")

0 commit comments

Comments
 (0)