activerecord-sqlserver-adapter 4.1.8 → 4.2.0.pre

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