activerecord-sqlserver-adapter_new 4.2.15

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