activerecord-sqlserver-adapter-odbc-extended 8.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.github/issue_template.md +22 -0
  3. data/.github/workflows/ci.yml +32 -0
  4. data/.gitignore +9 -0
  5. data/.rubocop.yml +69 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +132 -0
  8. data/Dockerfile.ci +14 -0
  9. data/Gemfile +26 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +104 -0
  12. data/RUNNING_UNIT_TESTS.md +38 -0
  13. data/Rakefile +45 -0
  14. data/VERSION +1 -0
  15. data/activerecord-sqlserver-adapter-odbc-extended.gemspec +34 -0
  16. data/compose.ci.yaml +15 -0
  17. data/lib/active_record/connection_adapters/extended_sqlserver_adapter.rb +204 -0
  18. data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +41 -0
  19. data/lib/active_record/connection_adapters/sqlserver/odbc_database_statements.rb +234 -0
  20. data/lib/active_record/connection_adapters/sqlserver/type/binary_ext.rb +25 -0
  21. data/lib/activerecord-sqlserver-adapter-odbc-extended.rb +12 -0
  22. data/test/appveyor/dbsetup.ps1 +27 -0
  23. data/test/appveyor/dbsetup.sql +11 -0
  24. data/test/cases/active_schema_test_sqlserver.rb +127 -0
  25. data/test/cases/adapter_test_sqlserver.rb +648 -0
  26. data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
  27. data/test/cases/change_column_null_test_sqlserver.rb +44 -0
  28. data/test/cases/coerced_tests.rb +2796 -0
  29. data/test/cases/column_test_sqlserver.rb +848 -0
  30. data/test/cases/connection_test_sqlserver.rb +138 -0
  31. data/test/cases/dbconsole.rb +19 -0
  32. data/test/cases/disconnected_test_sqlserver.rb +42 -0
  33. data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
  34. data/test/cases/enum_test_sqlserver.rb +49 -0
  35. data/test/cases/execute_procedure_test_sqlserver.rb +57 -0
  36. data/test/cases/fetch_test_sqlserver.rb +88 -0
  37. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +72 -0
  38. data/test/cases/helper_sqlserver.rb +61 -0
  39. data/test/cases/migration_test_sqlserver.rb +144 -0
  40. data/test/cases/order_test_sqlserver.rb +153 -0
  41. data/test/cases/pessimistic_locking_test_sqlserver.rb +102 -0
  42. data/test/cases/primary_keys_test_sqlserver.rb +103 -0
  43. data/test/cases/rake_test_sqlserver.rb +198 -0
  44. data/test/cases/schema_dumper_test_sqlserver.rb +296 -0
  45. data/test/cases/schema_test_sqlserver.rb +111 -0
  46. data/test/cases/trigger_test_sqlserver.rb +51 -0
  47. data/test/cases/utils_test_sqlserver.rb +129 -0
  48. data/test/cases/uuid_test_sqlserver.rb +54 -0
  49. data/test/cases/view_test_sqlserver.rb +58 -0
  50. data/test/config.yml +38 -0
  51. data/test/debug.rb +16 -0
  52. data/test/fixtures/1px.gif +0 -0
  53. data/test/migrations/create_clients_and_change_column_collation.rb +19 -0
  54. data/test/migrations/create_clients_and_change_column_null.rb +25 -0
  55. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
  56. data/test/models/sqlserver/alien.rb +5 -0
  57. data/test/models/sqlserver/booking.rb +5 -0
  58. data/test/models/sqlserver/composite_pk.rb +9 -0
  59. data/test/models/sqlserver/customers_view.rb +5 -0
  60. data/test/models/sqlserver/datatype.rb +5 -0
  61. data/test/models/sqlserver/datatype_migration.rb +10 -0
  62. data/test/models/sqlserver/dollar_table_name.rb +5 -0
  63. data/test/models/sqlserver/edge_schema.rb +13 -0
  64. data/test/models/sqlserver/fk_has_fk.rb +5 -0
  65. data/test/models/sqlserver/fk_has_pk.rb +5 -0
  66. data/test/models/sqlserver/natural_pk_data.rb +6 -0
  67. data/test/models/sqlserver/natural_pk_int_data.rb +5 -0
  68. data/test/models/sqlserver/no_pk_data.rb +5 -0
  69. data/test/models/sqlserver/object_default.rb +5 -0
  70. data/test/models/sqlserver/quoted_table.rb +9 -0
  71. data/test/models/sqlserver/quoted_view_1.rb +5 -0
  72. data/test/models/sqlserver/quoted_view_2.rb +5 -0
  73. data/test/models/sqlserver/sst_memory.rb +5 -0
  74. data/test/models/sqlserver/sst_string_collation.rb +3 -0
  75. data/test/models/sqlserver/string_default.rb +5 -0
  76. data/test/models/sqlserver/string_defaults_big_view.rb +5 -0
  77. data/test/models/sqlserver/string_defaults_view.rb +5 -0
  78. data/test/models/sqlserver/table_with_spaces.rb +5 -0
  79. data/test/models/sqlserver/tinyint_pk.rb +5 -0
  80. data/test/models/sqlserver/trigger.rb +17 -0
  81. data/test/models/sqlserver/trigger_history.rb +5 -0
  82. data/test/models/sqlserver/upper.rb +5 -0
  83. data/test/models/sqlserver/uppered.rb +5 -0
  84. data/test/models/sqlserver/uuid.rb +5 -0
  85. data/test/schema/datatypes/2012.sql +56 -0
  86. data/test/schema/enable-in-memory-oltp.sql +81 -0
  87. data/test/schema/sqlserver_specific_schema.rb +363 -0
  88. data/test/support/coerceable_test_sqlserver.rb +55 -0
  89. data/test/support/connection_reflection.rb +32 -0
  90. data/test/support/core_ext/query_cache.rb +38 -0
  91. data/test/support/load_schema_sqlserver.rb +29 -0
  92. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic.dump +0 -0
  93. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
  94. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic.dump +0 -0
  95. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic_associations.dump +0 -0
  96. data/test/support/minitest_sqlserver.rb +3 -0
  97. data/test/support/paths_sqlserver.rb +50 -0
  98. data/test/support/query_assertions.rb +49 -0
  99. data/test/support/rake_helpers.rb +46 -0
  100. data/test/support/table_definition_sqlserver.rb +24 -0
  101. data/test/support/test_in_memory_oltp.rb +17 -0
  102. metadata +240 -0
@@ -0,0 +1,848 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_sqlserver"
4
+
5
+ class ColumnTestSQLServer < ActiveRecord::TestCase
6
+ it "#table_name" do
7
+ assert SSTestDatatype.columns.all? { |c| c.table_name == "sst_datatypes" }
8
+ assert SSTestCustomersView.columns.all? { |c| c.table_name == "customers" }
9
+ end
10
+
11
+ describe "ActiveRecord::ConnectionAdapters::SQLServer::Type" do
12
+ let(:obj) { SSTestDatatype.new }
13
+
14
+ Type = ActiveRecord::ConnectionAdapters::SQLServer::Type
15
+
16
+ def new_obj; SSTestDatatype.new; end
17
+
18
+ def column(name); SSTestDatatype.columns_hash[name]; end
19
+
20
+ def assert_obj_set_and_save(attribute, value)
21
+ obj.send :"#{attribute}=", value
22
+ _(obj.send(attribute)).must_equal value
23
+ obj.save!
24
+ _(obj.reload.send(attribute)).must_equal value
25
+ end
26
+
27
+ # http://msdn.microsoft.com/en-us/library/ms187752.aspx
28
+
29
+ # Exact Numerics
30
+
31
+ it "int(4) PRIMARY KEY" do
32
+ col = column("id")
33
+ _(col.sql_type).must_equal "int(4)"
34
+ _(col.null).must_equal false
35
+ end
36
+
37
+ it "bigint(8)" do
38
+ col = column("bigint")
39
+ _(col.sql_type).must_equal "bigint(8)"
40
+ _(col.type).must_equal :integer
41
+ _(col.null).must_equal true
42
+ _(col.default).must_equal 42
43
+ _(obj.bigint).must_equal 42
44
+ _(col.default_function).must_be_nil
45
+ type = connection.lookup_cast_type_from_column(col)
46
+ _(type).must_be_instance_of Type::BigInteger
47
+ _(type.limit).must_equal 8
48
+ assert_obj_set_and_save :bigint, -9_223_372_036_854_775_808
49
+ assert_obj_set_and_save :bigint, 9_223_372_036_854_775_807
50
+ end
51
+
52
+ it "int(4)" do
53
+ col = column("int")
54
+ _(col.sql_type).must_equal "int(4)"
55
+ _(col.type).must_equal :integer
56
+ _(col.null).must_equal true
57
+ _(col.default).must_equal 42
58
+ _(obj.int).must_equal 42
59
+ _(col.default_function).must_be_nil
60
+ type = connection.lookup_cast_type_from_column(col)
61
+ _(type).must_be_instance_of Type::Integer
62
+ _(type.limit).must_equal 4
63
+ assert_obj_set_and_save :int, -2_147_483_648
64
+ assert_obj_set_and_save :int, 2_147_483_647
65
+ end
66
+
67
+ it "smallint(2)" do
68
+ col = column("smallint")
69
+ _(col.sql_type).must_equal "smallint(2)"
70
+ _(col.type).must_equal :integer
71
+ _(col.null).must_equal true
72
+ _(col.default).must_equal 42
73
+ _(obj.smallint).must_equal 42
74
+ _(col.default_function).must_be_nil
75
+ type = connection.lookup_cast_type_from_column(col)
76
+ _(type).must_be_instance_of Type::SmallInteger
77
+ _(type.limit).must_equal 2
78
+ assert_obj_set_and_save :smallint, -32_768
79
+ assert_obj_set_and_save :smallint, 32_767
80
+ end
81
+
82
+ it "tinyint(1)" do
83
+ col = column("tinyint")
84
+ _(col.sql_type).must_equal "tinyint(1)"
85
+ _(col.type).must_equal :integer
86
+ _(col.null).must_equal true
87
+ _(col.default).must_equal 42
88
+ _(obj.tinyint).must_equal 42
89
+ _(col.default_function).must_be_nil
90
+ type = connection.lookup_cast_type_from_column(col)
91
+ _(type).must_be_instance_of Type::TinyInteger
92
+ _(type.limit).must_equal 1
93
+ assert_obj_set_and_save :tinyint, 0
94
+ assert_obj_set_and_save :tinyint, 255
95
+ end
96
+
97
+ it "bit" do
98
+ col = column("bit")
99
+ _(col.sql_type).must_equal "bit"
100
+ _(col.type).must_equal :boolean
101
+ _(col.null).must_equal true
102
+ _(col.default).must_equal true
103
+ _(obj.bit).must_equal true
104
+ _(col.default_function).must_be_nil
105
+ type = connection.lookup_cast_type_from_column(col)
106
+ _(type).must_be_instance_of Type::Boolean
107
+ _(type.limit).must_be_nil
108
+ obj.bit = 0
109
+ _(obj.bit).must_equal false
110
+ obj.save!
111
+ _(obj.reload.bit).must_equal false
112
+ obj.bit = "1"
113
+ _(obj.bit).must_equal true
114
+ obj.save!
115
+ _(obj.reload.bit).must_equal true
116
+ end
117
+
118
+ it "decimal(9,2)" do
119
+ col = column("decimal_9_2")
120
+ _(col.sql_type).must_equal "decimal(9,2)"
121
+ _(col.type).must_equal :decimal
122
+ _(col.null).must_equal true
123
+ _(col.default).must_equal BigDecimal("12345.01")
124
+ _(obj.decimal_9_2).must_equal BigDecimal("12345.01")
125
+ _(col.default_function).must_be_nil
126
+ type = connection.lookup_cast_type_from_column(col)
127
+ _(type).must_be_instance_of Type::Decimal
128
+ _(type.limit).must_be_nil
129
+ _(type.precision).must_equal 9
130
+ _(type.scale).must_equal 2
131
+ obj.decimal_9_2 = "1234567.8901"
132
+ _(obj.decimal_9_2).must_equal BigDecimal("1234567.89")
133
+ obj.save!
134
+ _(obj.reload.decimal_9_2).must_equal BigDecimal("1234567.89")
135
+ end
136
+
137
+ it "decimal(16,4)" do
138
+ col = column("decimal_16_4")
139
+ _(col.sql_type).must_equal "decimal(16,4)"
140
+ _(col.default).must_equal BigDecimal("1234567.89")
141
+ _(obj.decimal_16_4).must_equal BigDecimal("1234567.89")
142
+ _(col.default_function).must_be_nil
143
+ type = connection.lookup_cast_type_from_column(col)
144
+ _(type.precision).must_equal 16
145
+ _(type.scale).must_equal 4
146
+ obj.decimal_16_4 = "1234567.8901001"
147
+ _(obj.decimal_16_4).must_equal BigDecimal("1234567.8901")
148
+ obj.save!
149
+ _(obj.reload.decimal_16_4).must_equal BigDecimal("1234567.8901")
150
+ end
151
+
152
+ it "numeric(18,0)" do
153
+ col = column("numeric_18_0")
154
+ _(col.sql_type).must_equal "numeric(18,0)"
155
+ _(col.type).must_equal :decimal
156
+ _(col.null).must_equal true
157
+ _(col.default).must_equal BigDecimal("191")
158
+ _(obj.numeric_18_0).must_equal BigDecimal("191")
159
+ _(col.default_function).must_be_nil
160
+
161
+ type = connection.lookup_cast_type_from_column(col)
162
+ _(type).must_be_instance_of Type::DecimalWithoutScale
163
+ _(type.limit).must_be_nil
164
+ _(type.precision).must_equal 18
165
+ _(type.scale).must_be_nil
166
+
167
+ obj.numeric_18_0 = "192.1"
168
+ _(obj.numeric_18_0).must_equal BigDecimal("192")
169
+
170
+ obj.save!
171
+ _(obj.reload.numeric_18_0).must_equal BigDecimal("192")
172
+ end
173
+
174
+ it "numeric(36,2)" do
175
+ col = column("numeric_36_2")
176
+ _(col.sql_type).must_equal "numeric(36,2)"
177
+ _(col.type).must_equal :decimal
178
+ _(col.null).must_equal true
179
+ _(col.default).must_equal BigDecimal("12345678901234567890.01")
180
+ _(obj.numeric_36_2).must_equal BigDecimal("12345678901234567890.01")
181
+ _(col.default_function).must_be_nil
182
+ type = connection.lookup_cast_type_from_column(col)
183
+ _(type).must_be_instance_of Type::Decimal
184
+ _(type.limit).must_be_nil
185
+ _(type.precision).must_equal 36
186
+ _(type.scale).must_equal 2
187
+ obj.numeric_36_2 = "192.123"
188
+ _(obj.numeric_36_2).must_equal BigDecimal("192.12")
189
+ obj.save!
190
+ _(obj.reload.numeric_36_2).must_equal BigDecimal("192.12")
191
+ end
192
+
193
+ it "money" do
194
+ col = column("money")
195
+ _(col.sql_type).must_equal "money"
196
+ _(col.type).must_equal :money
197
+ _(col.null).must_equal true
198
+ _(col.default).must_equal BigDecimal("4.20")
199
+ _(obj.money).must_equal BigDecimal("4.20")
200
+ _(col.default_function).must_be_nil
201
+ type = connection.lookup_cast_type_from_column(col)
202
+ _(type).must_be_instance_of Type::Money
203
+ _(type.limit).must_be_nil
204
+ _(type.precision).must_equal 19
205
+ _(type.scale).must_equal 4
206
+ obj.money = "922337203685477.58061"
207
+ _(obj.money).must_equal BigDecimal("922337203685477.5806")
208
+ obj.save!
209
+ _(obj.reload.money).must_equal BigDecimal("922337203685477.5806")
210
+ end
211
+
212
+ it "smallmoney" do
213
+ col = column("smallmoney")
214
+ _(col.sql_type).must_equal "smallmoney"
215
+ _(col.type).must_equal :smallmoney
216
+ _(col.null).must_equal true
217
+ _(col.default).must_equal BigDecimal("4.20")
218
+ _(obj.smallmoney).must_equal BigDecimal("4.20")
219
+ _(col.default_function).must_be_nil
220
+ type = connection.lookup_cast_type_from_column(col)
221
+ _(type).must_be_instance_of Type::SmallMoney
222
+ _(type.limit).must_be_nil
223
+ _(type.precision).must_equal 10
224
+ _(type.scale).must_equal 4
225
+ obj.smallmoney = "214748.36461"
226
+ _(obj.smallmoney).must_equal BigDecimal("214748.3646")
227
+ obj.save!
228
+ _(obj.reload.smallmoney).must_equal BigDecimal("214748.3646")
229
+ end
230
+
231
+ # Approximate Numerics
232
+ # Float limits are adjusted to 24 or 53 by the database as per http://msdn.microsoft.com/en-us/library/ms173773.aspx
233
+ # Floats with a limit of <= 24 are reduced to reals by sqlserver on creation.
234
+
235
+ it "float" do
236
+ col = column("float")
237
+ _(col.sql_type).must_equal "float"
238
+ _(col.type).must_equal :float
239
+ _(col.null).must_equal true
240
+ _(col.default).must_equal 123.00000001
241
+ _(obj.float).must_equal 123.00000001
242
+ _(col.default_function).must_be_nil
243
+ type = connection.lookup_cast_type_from_column(col)
244
+ _(type).must_be_instance_of Type::Float
245
+ _(type.limit).must_be_nil
246
+ _(type.precision).must_be_nil
247
+ _(type.scale).must_be_nil
248
+ obj.float = "214748.36461"
249
+ _(obj.float).must_equal 214748.36461
250
+ obj.save!
251
+ _(obj.reload.float).must_equal 214748.36461
252
+ end
253
+
254
+ it "real" do
255
+ col = column("real")
256
+ _(col.sql_type).must_equal "real"
257
+ _(col.type).must_equal :real
258
+ _(col.null).must_equal true
259
+ _(col.default).must_be_close_to 123.45, 0.01
260
+ _(obj.real).must_be_close_to 123.45, 0.01
261
+ _(col.default_function).must_be_nil
262
+ type = connection.lookup_cast_type_from_column(col)
263
+ _(type).must_be_instance_of Type::Real
264
+ _(type.limit).must_be_nil
265
+ _(type.precision).must_be_nil
266
+ _(type.scale).must_be_nil
267
+ obj.real = "214748.36461"
268
+ _(obj.real).must_be_close_to 214748.36461, 0.01
269
+ obj.save!
270
+ _(obj.reload.real).must_be_close_to 214748.36461, 0.01
271
+ end
272
+
273
+ # Date and Time
274
+
275
+ it "date" do
276
+ col = column("date")
277
+ _(col.sql_type).must_equal "date"
278
+ _(col.type).must_equal :date
279
+ _(col.null).must_equal true
280
+ _(col.default).must_equal Date.civil(1900, 1, 1)
281
+ _(obj.date).must_equal Date.civil(1900, 1, 1)
282
+ _(col.default_function).must_be_nil
283
+ type = connection.lookup_cast_type_from_column(col)
284
+ _(type).must_be_instance_of Type::Date
285
+ _(type.limit).must_be_nil
286
+ _(type.precision).must_be_nil
287
+ _(type.scale).must_be_nil
288
+ # Can cast strings. SQL Server format.
289
+ obj.date = "04-01-1900"
290
+ obj.date.must_equal Date.civil(1900, 4, 1)
291
+ obj.save!
292
+ obj.date.must_equal Date.civil(1900, 4, 1)
293
+ obj.reload
294
+ obj.date.must_equal Date.civil(1900, 4, 1)
295
+ # Can cast strings. ISO format.
296
+ obj.date = "1900-04-01"
297
+ obj.date.must_equal Date.civil(1900, 4, 1)
298
+ obj.save!
299
+ obj.date.must_equal Date.civil(1900, 4, 1)
300
+ obj.reload
301
+ obj.date.must_equal Date.civil(1900, 4, 1)
302
+ # Can keep and return assigned date.
303
+ assert_obj_set_and_save :date, Date.civil(1972, 4, 14)
304
+ # Can accept and cast time objects.
305
+ obj.date = Time.utc(2010, 4, 14, 12, 34, 56, 3000)
306
+ _(obj.date).must_equal Date.civil(2010, 4, 14)
307
+ obj.save!
308
+ _(obj.reload.date).must_equal Date.civil(2010, 4, 14)
309
+ end
310
+
311
+ it "datetime" do
312
+ col = column("datetime")
313
+ _(col.sql_type).must_equal "datetime"
314
+ _(col.type).must_equal :datetime
315
+ _(col.null).must_equal true
316
+ time = Time.utc 1753, 1, 1, 0, 0, 0, 123000
317
+ _(col.default).must_equal time, "Microseconds were <#{col.default.usec}> vs <123000>"
318
+ _(obj.datetime).must_equal time, "Microseconds were <#{obj.datetime.usec}> vs <123000>"
319
+ _(col.default_function).must_be_nil
320
+ type = connection.lookup_cast_type_from_column(col)
321
+ _(type).must_be_instance_of Type::DateTime
322
+ _(type.limit).must_be_nil
323
+ _(type.precision).must_be_nil
324
+ _(type.scale).must_be_nil
325
+ obj.save!
326
+ _(obj).must_equal obj.class.where(datetime: time).first
327
+ # Can save to proper accuracy and return again.
328
+ time = Time.utc 2010, 4, 1, 12, 34, 56, 3000
329
+ obj.datetime = time
330
+ _(obj.datetime).must_equal time, "Microseconds were <#{obj.datetime.usec}> vs <3000>"
331
+ obj.save!
332
+ _(obj.datetime).must_equal time, "Microseconds were <#{obj.datetime.usec}> vs <3000>"
333
+ obj.reload
334
+ _(obj.datetime).must_equal time, "Microseconds were <#{obj.datetime.usec}> vs <3000>"
335
+ _(obj).must_equal obj.class.where(datetime: time).first
336
+ # Can filter by datetime range
337
+ _(obj).must_equal obj.class.where(datetime: time..DateTime::Infinity.new).first
338
+ # Will cast to true DB value on attribute write, save and return again.
339
+ time = Time.utc 2010, 4, 1, 12, 34, 56, 234567
340
+ time2 = Time.utc 2010, 4, 1, 12, 34, 56, 233000
341
+ obj.datetime = time
342
+ _(obj.datetime).must_equal time2, "Microseconds were <#{obj.datetime.usec}> vs <233000>"
343
+ obj.save!
344
+ _(obj.datetime).must_equal time2, "Microseconds were <#{obj.datetime.usec}> vs <233000>"
345
+ obj.reload
346
+ _(obj.datetime).must_equal time2, "Microseconds were <#{obj.datetime.usec}> vs <233000>"
347
+ _(obj).must_equal obj.class.where(datetime: time).first
348
+ _(obj).must_equal obj.class.where(datetime: time2).first
349
+ # Set and find nil.
350
+ obj.datetime = nil
351
+ _(obj.datetime).must_be_nil
352
+ obj.save!
353
+ _(obj.datetime).must_be_nil
354
+ _(obj).must_equal obj.class.where(datetime: nil).first
355
+ end
356
+
357
+ it "datetime2" do
358
+ skip "datetime2 not supported in this protocol version" unless connection_tds_73
359
+ col = column("datetime2_7")
360
+ _(col.sql_type).must_equal "datetime2(7)"
361
+ _(col.type).must_equal :datetime
362
+ _(col.null).must_equal true
363
+ time = Time.utc 9999, 12, 31, 23, 59, 59, Rational(999999900, 1000)
364
+ _(col.default).must_equal time, "Nanoseconds were <#{col.default.nsec}> vs <999999900>"
365
+ _(obj.datetime2_7).must_equal time, "Nanoseconds were <#{obj.datetime2_7.nsec}> vs <999999900>"
366
+ _(col.default_function).must_be_nil
367
+ type = connection.lookup_cast_type_from_column(col)
368
+ _(type).must_be_instance_of Type::DateTime2
369
+ _(type.limit).must_be_nil
370
+ _(type.precision).must_equal 7
371
+ _(type.scale).must_be_nil
372
+ obj.save!
373
+ _(obj).must_equal obj.class.where(datetime2_7: time).first
374
+ # Can save 100 nanosecond precisoins and return again.
375
+ time = Time.utc 9999, 12, 31, 23, 59, 59, Rational(123456755, 1000)
376
+ time2 = Time.utc 9999, 12, 31, 23, 59, 59, Rational(123456800, 1000)
377
+ obj.datetime2_7 = time
378
+ _(obj.datetime2_7).must_equal time2, "Nanoseconds were <#{obj.datetime2_7.nsec}> vs <123456800>"
379
+ obj.save!
380
+ _(obj.datetime2_7).must_equal time2, "Nanoseconds were <#{obj.datetime2_7.nsec}> vs <123456800>"
381
+ obj.reload
382
+ _(obj.datetime2_7).must_equal time2, "Nanoseconds were <#{obj.datetime2_7.nsec}> vs <123456800>"
383
+ _(obj).must_equal obj.class.where(datetime2_7: time).first
384
+ _(obj).must_equal obj.class.where(datetime2_7: time2).first
385
+ # Can save small fraction nanosecond precisoins and return again.
386
+ time = Time.utc 2008, 6, 21, 13, 30, 0, Rational(15020, 1000)
387
+ time2 = Time.utc 2008, 6, 21, 13, 30, 0, Rational(15000, 1000)
388
+ obj.datetime2_7 = time
389
+ _(obj.datetime2_7).must_equal time2, "Nanoseconds were <#{obj.datetime2_7.nsec}> vs <15000>"
390
+ obj.save!
391
+ _(obj.reload.datetime2_7).must_equal time2, "Nanoseconds were <#{obj.datetime2_7.nsec}> vs <15000>"
392
+ _(obj).must_equal obj.class.where(datetime2_7: time).first
393
+ _(obj).must_equal obj.class.where(datetime2_7: time2).first
394
+ # datetime2_3
395
+ time = Time.utc 9999, 12, 31, 23, 59, 59, Rational(123456789, 1000)
396
+ col = column("datetime2_3")
397
+ _(connection.lookup_cast_type_from_column(col).precision).must_equal 3
398
+ obj.datetime2_3 = time
399
+ _(obj.datetime2_3).must_equal time.change(nsec: 123000000), "Nanoseconds were <#{obj.datetime2_3.nsec}> vs <123000000>"
400
+ obj.save!; obj.reload
401
+ _(obj.datetime2_3).must_equal time.change(nsec: 123000000), "Nanoseconds were <#{obj.datetime2_3.nsec}> vs <123000000>"
402
+ _(obj).must_equal obj.class.where(datetime2_3: time).first
403
+ # datetime2_1
404
+ col = column("datetime2_1")
405
+ _(connection.lookup_cast_type_from_column(col).precision).must_equal 1
406
+ obj.datetime2_1 = time
407
+ _(obj.datetime2_1).must_equal time.change(nsec: 100000000), "Nanoseconds were <#{obj.datetime2_1.nsec}> vs <100000000>"
408
+ obj.save!; obj.reload
409
+ _(obj.datetime2_1).must_equal time.change(nsec: 100000000), "Nanoseconds were <#{obj.datetime2_1.nsec}> vs <100000000>"
410
+ _(obj).must_equal obj.class.where(datetime2_1: time).first
411
+ # datetime2_0
412
+ col = column("datetime2_0")
413
+ _(connection.lookup_cast_type_from_column(col).precision).must_equal 0
414
+ time = Time.utc 2016, 4, 19, 16, 45, 40, 771036
415
+ obj.datetime2_0 = time
416
+ _(obj.datetime2_0).must_equal time.change(nsec: 0), "Nanoseconds were <#{obj.datetime2_0.nsec}> vs <0>"
417
+ obj.save!; obj.reload
418
+ _(obj.datetime2_0).must_equal time.change(nsec: 0), "Nanoseconds were <#{obj.datetime2_0.nsec}> vs <0>"
419
+ _(obj).must_equal obj.class.where(datetime2_0: time).first
420
+ end
421
+
422
+ it "datetimeoffset" do
423
+ skip "datetimeoffset not supported in this protocol version" unless connection_tds_73
424
+ col = column("datetimeoffset_7")
425
+ _(col.sql_type).must_equal "datetimeoffset(7)"
426
+ _(col.type).must_equal :datetimeoffset
427
+ _(col.null).must_equal true
428
+ _(col.default).must_equal Time.new(1984, 1, 24, 4, 20, 0, -28800).change(nsec: 123456700), "Nanoseconds <#{col.default.nsec}> vs <123456700>"
429
+ _(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>"
430
+ _(col.default_function).must_be_nil
431
+ type = connection.lookup_cast_type_from_column(col)
432
+ _(type).must_be_instance_of Type::DateTimeOffset
433
+ _(type.limit).must_be_nil
434
+ _(type.precision).must_equal 7
435
+ _(type.scale).must_be_nil
436
+
437
+ # Can save 100 nanosecond precisions and return again.
438
+ obj.datetimeoffset_7 = Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456755)
439
+ _(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>"
440
+ obj.save!
441
+ _(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>"
442
+ obj.reload
443
+ _(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>"
444
+
445
+ # Maintains the timezone
446
+ time = ActiveSupport::TimeZone["America/Los_Angeles"].local 2010, 12, 31, 23, 59, 59, Rational(123456800, 1000)
447
+ obj.datetimeoffset_7 = time
448
+ _(obj.datetimeoffset_7).must_equal time
449
+ obj.save!
450
+ _(obj.datetimeoffset_7).must_equal time
451
+ _(obj.reload.datetimeoffset_7).must_equal time
452
+
453
+ # With other precisions.
454
+ time = ActiveSupport::TimeZone["America/Los_Angeles"].local 2010, 12, 31, 23, 59, 59, Rational(123456755, 1000)
455
+ col = column("datetimeoffset_3")
456
+ _(connection.lookup_cast_type_from_column(col).precision).must_equal 3
457
+ obj.datetimeoffset_3 = time
458
+ _(obj.datetimeoffset_3).must_equal time.change(nsec: 123000000), "Nanoseconds were <#{obj.datetimeoffset_3.nsec}> vs <123000000>"
459
+ obj.save!
460
+ _(obj.datetimeoffset_3).must_equal time.change(nsec: 123000000), "Nanoseconds were <#{obj.datetimeoffset_3.nsec}> vs <123000000>"
461
+ col = column("datetime2_1")
462
+ _(connection.lookup_cast_type_from_column(col).precision).must_equal 1
463
+ obj.datetime2_1 = time
464
+ _(obj.datetime2_1).must_equal time.change(nsec: 100000000), "Nanoseconds were <#{obj.datetime2_1.nsec}> vs <100000000>"
465
+ obj.save!
466
+ _(obj.datetime2_1).must_equal time.change(nsec: 100000000), "Nanoseconds were <#{obj.datetime2_1.nsec}> vs <100000000>"
467
+ end
468
+
469
+ it "smalldatetime" do
470
+ col = column("smalldatetime")
471
+ _(col.sql_type).must_equal "smalldatetime"
472
+ _(col.type).must_equal :smalldatetime
473
+ _(col.null).must_equal true
474
+ _(col.default).must_equal Time.utc(1901, 1, 1, 15, 45, 0, 0)
475
+ _(obj.smalldatetime).must_equal Time.utc(1901, 1, 1, 15, 45, 0, 0)
476
+ _(col.default_function).must_be_nil
477
+ type = connection.lookup_cast_type_from_column(col)
478
+ _(type).must_be_instance_of Type::SmallDateTime
479
+ _(type.limit).must_be_nil
480
+ _(type.precision).must_be_nil
481
+ _(type.scale).must_be_nil
482
+ # Will remove fractional seconds and return again.
483
+ obj.smalldatetime = Time.utc(2078, 6, 5, 4, 20, 0, 3000)
484
+ _(obj.smalldatetime).must_equal Time.utc(2078, 6, 5, 4, 20, 0, 0), "Microseconds were <#{obj.smalldatetime.usec}> vs <0>"
485
+ obj.save!
486
+ _(obj.smalldatetime).must_equal Time.utc(2078, 6, 5, 4, 20, 0, 0), "Microseconds were <#{obj.reload.smalldatetime.usec}> vs <0>"
487
+ obj.reload
488
+ _(obj.smalldatetime).must_equal Time.utc(2078, 6, 5, 4, 20, 0, 0), "Microseconds were <#{obj.reload.smalldatetime.usec}> vs <0>"
489
+ end
490
+
491
+ it "time(7)" do
492
+ skip "time() not supported in this protocol version" unless connection_tds_73
493
+ col = column("time_7")
494
+ _(col.sql_type).must_equal "time(7)"
495
+ _(col.type).must_equal :time
496
+ _(col.null).must_equal true
497
+ _(col.default).must_equal Time.utc(1900, 1, 1, 4, 20, 0, Rational(288321500, 1000)), "Nanoseconds were <#{col.default.nsec}> vs <288321500>"
498
+ _(col.default_function).must_be_nil
499
+ type = connection.lookup_cast_type_from_column(col)
500
+ _(type).must_be_instance_of Type::Time
501
+ _(type.limit).must_be_nil
502
+ _(type.precision).must_equal 7
503
+ _(type.scale).must_be_nil
504
+ # Time's #usec precision (low micro)
505
+ obj.time_7 = Time.utc(2000, 1, 1, 15, 45, 0, 300)
506
+ _(obj.time_7).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 300), "Microseconds were <#{obj.time_7.usec}> vs <0>"
507
+ _(obj.time_7).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 300), "Nanoseconds were <#{obj.time_7.nsec}> vs <300>"
508
+ obj.save!; obj.reload
509
+ _(obj.time_7).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 300), "Microseconds were <#{obj.time_7.usec}> vs <0>"
510
+ _(obj.time_7).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 300), "Nanoseconds were <#{obj.time_7.nsec}> vs <300>"
511
+ # Time's #usec precision (high micro)
512
+ obj.time_7 = Time.utc(2000, 1, 1, 15, 45, 0, 234567)
513
+ _(obj.time_7).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 234567), "Microseconds were <#{obj.time_7.usec}> vs <234567>"
514
+ obj.save!; obj.reload
515
+ _(obj.time_7).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 234567), "Microseconds were <#{obj.time_7.usec}> vs <234567>"
516
+ # Time's #usec precision (high nano rounded)
517
+ obj.time_7 = Time.utc(2000, 1, 1, 15, 45, 0, Rational(288321545, 1000))
518
+ _(obj.time_7).must_equal Time.utc(2000, 1, 1, 15, 45, 0, Rational(288321500, 1000)), "Nanoseconds were <#{obj.time_7.nsec}> vs <288321500>"
519
+ obj.save!; obj.reload
520
+ _(obj.time_7).must_equal Time.utc(2000, 1, 1, 15, 45, 0, Rational(288321500, 1000)), "Nanoseconds were <#{obj.time_7.nsec}> vs <288321500>"
521
+ end
522
+
523
+ it "time(2)" do
524
+ skip "time() not supported in this protocol version" unless connection_tds_73
525
+ col = column("time_2")
526
+ _(col.sql_type).must_equal "time(2)"
527
+ _(col.type).must_equal :time
528
+ _(col.null).must_equal true
529
+ _(col.default).must_be_nil
530
+ _(col.default_function).must_be_nil
531
+ type = connection.lookup_cast_type_from_column(col)
532
+ _(type).must_be_instance_of Type::Time
533
+ _(type.limit).must_be_nil
534
+ _(type.precision).must_equal 2
535
+ _(type.scale).must_be_nil
536
+ # Always uses TinyTDS/Windows 2000-01-01 convention too.
537
+ obj.time_2 = Time.utc(2015, 1, 10, 15, 45, 0, 0)
538
+ _(obj.time_2).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 0)
539
+ obj.save!; obj.reload
540
+ _(obj.time_2).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 0)
541
+ # Time's #usec precision (barely in 2 precision equal to 0.03 seconds)
542
+ obj.time_2 = Time.utc(2000, 1, 1, 15, 45, 0, 30000)
543
+ _(obj.time_2).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 30000), "Microseconds were <#{obj.time_2.usec}> vs <30000>"
544
+ obj.save!; obj.reload
545
+ _(obj.time_2).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 30000), "Microseconds were <#{obj.time_2.usec}> vs <30000>"
546
+ # Time's #usec precision (below 2 precision)
547
+ obj.time_2 = Time.utc(2000, 1, 1, 15, 45, 0, 4000)
548
+ _(obj.time_2).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 0), "Microseconds were <#{obj.time_2.usec}> vs <0>"
549
+ obj.save!; obj.reload
550
+ _(obj.time_2).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 0), "Microseconds were <#{obj.time_2.usec}> vs <0>"
551
+ end
552
+
553
+ it "time using default precision" do
554
+ skip "time() not supported in this protocol version" unless connection_tds_73
555
+ col = column("time_default")
556
+ _(col.sql_type).must_equal "time(7)"
557
+ _(col.type).must_equal :time
558
+ _(col.null).must_equal true
559
+ _(col.default).must_equal Time.utc(1900, 1, 1, 15, 3, 42, Rational(62197800, 1000)), "Nanoseconds were <#{col.default.nsec}> vs <62197800>"
560
+ _(col.default_function).must_be_nil
561
+ type = connection.lookup_cast_type_from_column(col)
562
+ _(type).must_be_instance_of Type::Time
563
+ _(type.limit).must_be_nil
564
+ _(type.precision).must_equal 7
565
+ _(type.scale).must_be_nil
566
+ # Time's #usec precision (low micro)
567
+ obj.time_default = Time.utc(2000, 1, 1, 15, 45, 0, 300)
568
+ _(obj.time_default).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 300), "Microseconds were <#{obj.time_default.usec}> vs <0>"
569
+ _(obj.time_default).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 300), "Nanoseconds were <#{obj.time_default.nsec}> vs <300>"
570
+ obj.save!; obj.reload
571
+ _(obj.time_default).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 300), "Microseconds were <#{obj.time_default.usec}> vs <0>"
572
+ _(obj.time_default).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 300), "Nanoseconds were <#{obj.time_default.nsec}> vs <300>"
573
+ # Time's #usec precision (high micro)
574
+ obj.time_default = Time.utc(2000, 1, 1, 15, 45, 0, 234567)
575
+ _(obj.time_default).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 234567), "Microseconds were <#{obj.time_default.usec}> vs <234567>"
576
+ obj.save!; obj.reload
577
+ _(obj.time_default).must_equal Time.utc(2000, 1, 1, 15, 45, 0, 234567), "Microseconds were <#{obj.time_default.usec}> vs <234567>"
578
+ # Time's #usec precision (high nano rounded)
579
+ obj.time_default = Time.utc(2000, 1, 1, 15, 45, 0, Rational(288321545, 1000))
580
+ _(obj.time_default).must_equal Time.utc(2000, 1, 1, 15, 45, 0, Rational(288321500, 1000)), "Nanoseconds were <#{obj.time_default.nsec}> vs <288321500>"
581
+ obj.save!; obj.reload
582
+ _(obj.time_default).must_equal Time.utc(2000, 1, 1, 15, 45, 0, Rational(288321500, 1000)), "Nanoseconds were <#{obj.time_default.nsec}> vs <288321500>"
583
+ end
584
+
585
+ # Character Strings
586
+
587
+ it "char(10)" do
588
+ col = column("char_10")
589
+ _(col.sql_type).must_equal "char(10)"
590
+ _(col.type).must_equal :char
591
+ _(col.null).must_equal true
592
+ _(col.default).must_equal "1234567890"
593
+ _(obj.char_10).must_equal "1234567890"
594
+ _(col.default_function).must_be_nil
595
+ type = connection.lookup_cast_type_from_column(col)
596
+ _(type).must_be_instance_of Type::Char
597
+ _(type.limit).must_equal 10
598
+ _(type.precision).must_be_nil
599
+ _(type.scale).must_be_nil
600
+ # Basic set and save.
601
+ obj.char_10 = "012345"
602
+ _(obj.char_10.strip).must_equal "012345"
603
+ obj.save!
604
+ _(obj.reload.char_10.strip).must_equal "012345"
605
+ end
606
+
607
+ it "varchar(50)" do
608
+ col = column("varchar_50")
609
+ _(col.sql_type).must_equal "varchar(50)"
610
+ _(col.type).must_equal :varchar
611
+ _(col.null).must_equal true
612
+ _(col.default).must_equal "test varchar_50"
613
+ _(obj.varchar_50).must_equal "test varchar_50"
614
+ _(col.default_function).must_be_nil
615
+ type = connection.lookup_cast_type_from_column(col)
616
+ _(type).must_be_instance_of Type::Varchar
617
+ _(type.limit).must_equal 50
618
+ _(type.precision).must_be_nil
619
+ _(type.scale).must_be_nil
620
+ # Basic set and save.
621
+ assert_obj_set_and_save :varchar_50, "Hello World"
622
+ end
623
+
624
+ it "varchar(max)" do
625
+ col = column("varchar_max")
626
+ _(col.sql_type).must_equal "varchar(max)"
627
+ _(col.type).must_equal :varchar_max
628
+ _(col.null).must_equal true
629
+ _(col.default).must_equal "test varchar_max"
630
+ _(obj.varchar_max).must_equal "test varchar_max"
631
+ _(col.default_function).must_be_nil
632
+ type = connection.lookup_cast_type_from_column(col)
633
+ _(type).must_be_instance_of Type::VarcharMax
634
+ _(type.limit).must_equal 2_147_483_647
635
+ _(type.precision).must_be_nil
636
+ _(type.scale).must_be_nil
637
+ # Basic set and save.
638
+ assert_obj_set_and_save :varchar_max, "Hello World"
639
+ end
640
+
641
+ it "text" do
642
+ col = column("text")
643
+ _(col.sql_type).must_equal "text"
644
+ _(col.type).must_equal :text_basic
645
+ _(col.null).must_equal true
646
+ _(col.default).must_equal "test text"
647
+ _(obj.text).must_equal "test text"
648
+ _(col.default_function).must_be_nil
649
+ type = connection.lookup_cast_type_from_column(col)
650
+ _(type).must_be_instance_of Type::Text
651
+ _(type.limit).must_equal 2_147_483_647
652
+ _(type.precision).must_be_nil
653
+ _(type.scale).must_be_nil
654
+ # Basic set and save.
655
+ assert_obj_set_and_save :text, "Hello World"
656
+ end
657
+
658
+ # Unicode Character Strings
659
+
660
+ it "nchar(10)" do
661
+ col = column("nchar_10")
662
+ _(col.sql_type).must_equal "nchar(10)"
663
+ _(col.type).must_equal :nchar
664
+ _(col.null).must_equal true
665
+ _(col.default).must_equal "12345678åå"
666
+ _(obj.nchar_10).must_equal "12345678åå"
667
+ _(col.default_function).must_be_nil
668
+ type = connection.lookup_cast_type_from_column(col)
669
+ _(type).must_be_instance_of Type::UnicodeChar
670
+ _(type.limit).must_equal 10
671
+ _(type.precision).must_be_nil
672
+ _(type.scale).must_be_nil
673
+ # Basic set and save.
674
+ obj.nchar_10 = "五六"
675
+ _(obj.nchar_10.strip).must_equal "五六"
676
+ obj.save!
677
+ _(obj.reload.nchar_10.strip).must_equal "五六"
678
+ end
679
+
680
+ it "nvarchar(50)" do
681
+ col = column("nvarchar_50")
682
+ _(col.sql_type).must_equal "nvarchar(50)"
683
+ _(col.type).must_equal :string
684
+ _(col.null).must_equal true
685
+ _(col.default).must_equal "test nvarchar_50 åå"
686
+ _(obj.nvarchar_50).must_equal "test nvarchar_50 åå"
687
+ _(col.default_function).must_be_nil
688
+ type = connection.lookup_cast_type_from_column(col)
689
+ _(type).must_be_instance_of Type::UnicodeVarchar
690
+ _(type.limit).must_equal 50
691
+ _(type.precision).must_be_nil
692
+ _(type.scale).must_be_nil
693
+ # Basic set and save.
694
+ assert_obj_set_and_save :nvarchar_50, "一二34五六"
695
+ end
696
+
697
+ it "nvarchar(max)" do
698
+ col = column("nvarchar_max")
699
+ _(col.sql_type).must_equal "nvarchar(max)"
700
+ _(col.type).must_equal :text
701
+ _(col.null).must_equal true
702
+ _(col.default).must_equal "test nvarchar_max åå"
703
+ _(obj.nvarchar_max).must_equal "test nvarchar_max åå"
704
+ _(col.default_function).must_be_nil
705
+ type = connection.lookup_cast_type_from_column(col)
706
+ _(type).must_be_instance_of Type::UnicodeVarcharMax
707
+ _(type.limit).must_equal 2_147_483_647
708
+ _(type.precision).must_be_nil
709
+ _(type.scale).must_be_nil
710
+ # Basic set and save.
711
+ assert_obj_set_and_save :nvarchar_max, "一二34五六"
712
+ end
713
+
714
+ it "ntext" do
715
+ col = column("ntext")
716
+ _(col.sql_type).must_equal "ntext"
717
+ _(col.type).must_equal :ntext
718
+ _(col.null).must_equal true
719
+ _(col.default).must_equal "test ntext åå"
720
+ _(obj.ntext).must_equal "test ntext åå"
721
+ _(col.default_function).must_be_nil
722
+ type = connection.lookup_cast_type_from_column(col)
723
+ _(type).must_be_instance_of Type::UnicodeText
724
+ _(type.limit).must_equal 2_147_483_647
725
+ _(type.precision).must_be_nil
726
+ _(type.scale).must_be_nil
727
+ # Basic set and save.
728
+ assert_obj_set_and_save :ntext, "一二34五六"
729
+ end
730
+
731
+ # Binary Strings
732
+
733
+ let(:binary_file) { File.join ARTest::SQLServer.test_root_sqlserver, "fixtures", "1px.gif" }
734
+ let(:binary_data) { File.open(binary_file, "rb") { |f| f.read } }
735
+
736
+ it "binary(49)" do
737
+ col = column("binary_49")
738
+ _(col.sql_type).must_equal "binary(49)"
739
+ _(col.type).must_equal :binary_basic
740
+ _(col.null).must_equal true
741
+ _(col.default).must_be_nil
742
+ _(col.default_function).must_be_nil
743
+ type = connection.lookup_cast_type_from_column(col)
744
+ _(type).must_be_instance_of Type::Binary
745
+ _(type.limit).must_equal 49
746
+ _(type.precision).must_be_nil
747
+ _(type.scale).must_be_nil
748
+ # Basic set and save.
749
+ _(binary_data.encoding).must_equal Encoding::BINARY
750
+ _(binary_data.length).must_equal 49
751
+ obj.binary_49 = binary_data
752
+ _(obj.binary_49).must_equal binary_data
753
+ obj.save!
754
+ _(obj.reload.binary_49).must_equal binary_data
755
+ end
756
+
757
+ it "varbinary(49)" do
758
+ col = column("varbinary_49")
759
+ _(col.sql_type).must_equal "varbinary(49)"
760
+ _(col.type).must_equal :varbinary
761
+ _(col.null).must_equal true
762
+ _(col.default).must_be_nil
763
+ _(col.default_function).must_be_nil
764
+ type = connection.lookup_cast_type_from_column(col)
765
+ _(type).must_be_instance_of Type::Varbinary
766
+ _(type.limit).must_equal 49
767
+ _(type.precision).must_be_nil
768
+ _(type.scale).must_be_nil
769
+ # Basic set and save.
770
+ binary_data20 = binary_data.to(20)
771
+ _(binary_data20.encoding).must_equal Encoding::BINARY
772
+ obj.varbinary_49 = binary_data20
773
+ _(obj.varbinary_49).must_equal binary_data20
774
+ obj.save!
775
+ _(obj.reload.varbinary_49).must_equal binary_data20
776
+ end
777
+
778
+ it "varbinary(max)" do
779
+ col = column("varbinary_max")
780
+ _(col.sql_type).must_equal "varbinary(max)"
781
+ _(col.type).must_equal :binary
782
+ _(col.null).must_equal true
783
+ _(col.default).must_be_nil
784
+ _(col.default_function).must_be_nil
785
+ type = connection.lookup_cast_type_from_column(col)
786
+ _(type).must_be_instance_of Type::VarbinaryMax
787
+ _(type.limit).must_equal 2_147_483_647
788
+ _(type.precision).must_be_nil
789
+ _(type.scale).must_be_nil
790
+ # Basic set and save.
791
+ _(binary_data.encoding).must_equal Encoding::BINARY
792
+ assert_obj_set_and_save :varbinary_max, binary_data
793
+ end
794
+
795
+ # Other Data Types
796
+
797
+ it "uniqueidentifier" do
798
+ col = column("uniqueidentifier")
799
+ _(col.sql_type).must_equal "uniqueidentifier"
800
+ _(col.type).must_equal :uuid
801
+ _(col.null).must_equal true
802
+ _(col.default).must_be_nil
803
+ _(col.default_function).must_equal "newid()"
804
+ type = connection.lookup_cast_type_from_column(col)
805
+ _(type).must_be_instance_of Type::Uuid
806
+ _(type.limit).must_be_nil
807
+ _(type.precision).must_be_nil
808
+ _(type.scale).must_be_nil
809
+ # Basic set and save.
810
+ obj.uniqueidentifier = "this will not qualify as valid"
811
+ _(obj.uniqueidentifier).must_be_nil
812
+ obj.save!; obj.reload
813
+ _(obj.uniqueidentifier).must_match Type::Uuid::ACCEPTABLE_UUID
814
+ obj.uniqueidentifier = "6F9619FF-8B86-D011-B42D-00C04FC964FF"
815
+ _(obj.uniqueidentifier).must_equal "6F9619FF-8B86-D011-B42D-00C04FC964FF"
816
+ obj.save!; obj.reload
817
+ _(obj.uniqueidentifier).must_equal "6F9619FF-8B86-D011-B42D-00C04FC964FF"
818
+ end
819
+
820
+ it "timestamp" do
821
+ col = column("timestamp")
822
+ _(col.sql_type).must_equal "timestamp"
823
+ _(col.type).must_equal :ss_timestamp
824
+ _(col.null).must_equal true
825
+ _(col.default).must_be_nil
826
+ _(col.default_function).must_be_nil
827
+ type = connection.lookup_cast_type_from_column(col)
828
+ _(type).must_be_instance_of Type::Timestamp
829
+ _(type.limit).must_be_nil
830
+ _(type.precision).must_be_nil
831
+ _(type.scale).must_be_nil
832
+ # Basic read.
833
+ _(obj.timestamp).must_be_nil
834
+ obj.save!; obj.reload
835
+ _(obj.timestamp).must_match %r|\000|
836
+ obj.timestamp
837
+ # Can set another attribute
838
+ obj.uniqueidentifier = "6F9619FF-8B86-D011-B42D-00C04FC964FF"
839
+ obj.save!
840
+ end
841
+
842
+ it "does not mark object as changed after save" do
843
+ obj.save!
844
+ obj.attributes
845
+ _(obj.changed?).must_equal false
846
+ end
847
+ end
848
+ end