activerecord-sqlserver-adapter_new 4.2.15

Sign up to get free protection for your applications and to get access to all the features.
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