activerecord-sqlserver-adapter 4.1.8 → 4.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,5 +1,3 @@
1
1
  require 'arel'
2
- require 'arel/select_manager_sqlserver'
3
- require 'arel/nodes_sqlserver'
4
- require 'arel/visitors/sqlserver'
5
2
  require 'arel/visitors/bind_visitor'
3
+ require 'arel/visitors/sqlserver'
@@ -0,0 +1,420 @@
1
+ require 'cases/helper_sqlserver'
2
+ require 'models/topic'
3
+ require 'models/task'
4
+ require 'models/post'
5
+ require 'models/subscriber'
6
+ require 'models/minimalistic'
7
+
8
+ class AdapterTestSQLServer < ActiveRecord::TestCase
9
+
10
+ fixtures :tasks
11
+
12
+ let(:basic_insert_sql) { "INSERT INTO [funny_jokes] ([name]) VALUES('Knock knock')" }
13
+ let(:basic_update_sql) { "UPDATE [customers] SET [address_street] = NULL WHERE [id] = 2" }
14
+ let(:basic_select_sql) { "SELECT * FROM [customers] WHERE ([customers].[id] = 1)" }
15
+
16
+ it 'has basic and non-senstive information in the adpaters inspect method' do
17
+ string = connection.inspect
18
+ string.must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
19
+ string.must_match %r{version\: \d.\d}
20
+ string.must_match %r{mode: (dblib|odbc)}
21
+ string.must_match %r{azure: (true|false)}
22
+ string.wont_match %r{host}
23
+ string.wont_match %r{password}
24
+ string.wont_match %r{username}
25
+ string.wont_match %r{port}
26
+ end
27
+
28
+ it 'has a 128 max #table_alias_length' do
29
+ assert connection.table_alias_length <= 128
30
+ end
31
+
32
+ it 'raises invalid statement error for bad SQL' do
33
+ assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.update("UPDATE XXX") }
34
+ end
35
+
36
+ it 'is has our adapter_name' do
37
+ assert_equal 'SQLServer', connection.adapter_name
38
+ end
39
+
40
+ it 'supports migrations' do
41
+ assert connection.supports_migrations?
42
+ end
43
+
44
+ it 'support DDL in transactions' do
45
+ assert connection.supports_ddl_transactions?
46
+ end
47
+
48
+ it 'allow owner table name prefixs like dbo to still allow table exists to return true' do
49
+ begin
50
+ assert_equal 'topics', Topic.table_name
51
+ assert Topic.table_exists?
52
+ Topic.table_name = 'dbo.topics'
53
+ assert Topic.table_exists?, 'Tasks table name of dbo.topics should return true for exists.'
54
+ ensure
55
+ Topic.table_name = 'topics'
56
+ end
57
+ end
58
+
59
+ it 'return true to insert sql query for inserts only' do
60
+ assert connection.send(:insert_sql?,'INSERT...')
61
+ assert connection.send(:insert_sql?, "EXEC sp_executesql N'INSERT INTO [fk_test_has_fks] ([fk_id]) VALUES (@0); SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident', N'@0 int', @0 = 0")
62
+ assert !connection.send(:insert_sql?,'UPDATE...')
63
+ assert !connection.send(:insert_sql?,'SELECT...')
64
+ end
65
+
66
+ it 'return unquoted table name object from basic INSERT UPDATE and SELECT statements' do
67
+ assert_equal 'funny_jokes', connection.send(:get_table_name, basic_insert_sql)
68
+ assert_equal 'customers', connection.send(:get_table_name, basic_update_sql)
69
+ assert_equal 'customers', connection.send(:get_table_name, basic_select_sql)
70
+ end
71
+
72
+ describe 'with different language' do
73
+
74
+ before do
75
+ @default_language = connection.user_options_language
76
+ end
77
+
78
+ after do
79
+ connection.execute("SET LANGUAGE #{@default_language}") rescue nil
80
+ connection.send :initialize_dateformatter
81
+ end
82
+
83
+ it 'memos users dateformat' do
84
+ connection.execute("SET LANGUAGE us_english") rescue nil
85
+ dateformat = connection.instance_variable_get(:@database_dateformat)
86
+ assert_equal 'mdy', dateformat
87
+ end
88
+
89
+ it 'has a dateformatter' do
90
+ assert Date::DATE_FORMATS[:_sqlserver_dateformat]
91
+ assert Time::DATE_FORMATS[:_sqlserver_dateformat]
92
+ end
93
+
94
+ it 'does a datetime insertion when language is german' do
95
+ connection.execute("SET LANGUAGE deutsch")
96
+ connection.send :initialize_dateformatter
97
+ assert_nothing_raised do
98
+ starting = Time.utc(2000, 1, 31, 5, 42, 0)
99
+ ending = Date.new(2006, 12, 31)
100
+ Task.create! starting: starting, ending: ending
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ describe 'testing #lowercase_schema_reflection' do
107
+
108
+ before do
109
+ SSTestUpper.delete_all
110
+ SSTestUpper.create COLUMN1: 'Got a minute?', COLUMN2: 419
111
+ SSTestUpper.create COLUMN1: 'Favorite number?', COLUMN2: 69
112
+ end
113
+
114
+ after do
115
+ connection.lowercase_schema_reflection = false
116
+ end
117
+
118
+ it 'not lowercase schema reflection by default' do
119
+ assert SSTestUpper.columns_hash['COLUMN1']
120
+ assert_equal 'Got a minute?', SSTestUpper.first.COLUMN1
121
+ assert_equal 'Favorite number?', SSTestUpper.last.COLUMN1
122
+ assert SSTestUpper.columns_hash['COLUMN2']
123
+ end
124
+
125
+ it 'lowercase schema reflection when set' do
126
+ connection.lowercase_schema_reflection = true
127
+ assert SSTestUppered.columns_hash['column1']
128
+ assert_equal 'Got a minute?', SSTestUppered.first.column1
129
+ assert_equal 'Favorite number?', SSTestUppered.last.column1
130
+ assert SSTestUppered.columns_hash['column2']
131
+ end
132
+
133
+ end
134
+
135
+ describe 'identity inserts' do
136
+
137
+ before do
138
+ @identity_insert_sql = "INSERT INTO [funny_jokes] ([id],[name]) VALUES(420,'Knock knock')"
139
+ @identity_insert_sql_unquoted = "INSERT INTO funny_jokes (id, name) VALUES(420, 'Knock knock')"
140
+ @identity_insert_sql_unordered = "INSERT INTO [funny_jokes] ([name],[id]) VALUES('Knock knock',420)"
141
+ @identity_insert_sql_sp = "EXEC sp_executesql N'INSERT INTO [funny_jokes] ([id],[name]) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Knock knock'"
142
+ @identity_insert_sql_unquoted_sp = "EXEC sp_executesql N'INSERT INTO [funny_jokes] (id, name) VALUES (@0, @1)', N'@0 int, @1 nvarchar(255)', @0 = 420, @1 = N'Knock knock'"
143
+ @identity_insert_sql_unordered_sp = "EXEC sp_executesql N'INSERT INTO [funny_jokes] ([name],[id]) VALUES (@0, @1)', N'@0 nvarchar(255), @1 int', @0 = N'Knock knock', @1 = 420"
144
+ end
145
+
146
+ it 'return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column' do
147
+ assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql)
148
+ assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted)
149
+ assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered)
150
+ assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_sp)
151
+ assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted_sp)
152
+ assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered_sp)
153
+ end
154
+
155
+ it 'return false to #query_requires_identity_insert? for normal SQL' do
156
+ [basic_insert_sql, basic_update_sql, basic_select_sql].each do |sql|
157
+ assert !connection.send(:query_requires_identity_insert?,sql), "SQL was #{sql}"
158
+ end
159
+ end
160
+
161
+ it 'find identity column using #identity_column' do
162
+ task_id_column = Task.columns_hash['id']
163
+ assert_equal task_id_column.name, connection.send(:identity_column, Task.table_name).name
164
+ assert_equal task_id_column.sql_type, connection.send(:identity_column, Task.table_name).sql_type
165
+ end
166
+
167
+ it 'return nil when calling #identity_column for a table_name with no identity' do
168
+ assert_nil connection.send(:identity_column, Subscriber.table_name)
169
+ end
170
+
171
+ end
172
+
173
+ describe 'quoting' do
174
+
175
+ it 'return 1 for #quoted_true' do
176
+ assert_equal '1', connection.quoted_true
177
+ end
178
+
179
+ it 'return 0 for #quoted_false' do
180
+ assert_equal '0', connection.quoted_false
181
+ end
182
+
183
+ it 'not escape backslash characters like abstract adapter' do
184
+ string_with_backslashs = "\\n"
185
+ assert_equal string_with_backslashs, connection.quote_string(string_with_backslashs)
186
+ end
187
+
188
+ it 'quote column names with brackets' do
189
+ assert_equal '[foo]', connection.quote_column_name(:foo)
190
+ assert_equal '[foo]', connection.quote_column_name('foo')
191
+ assert_equal '[foo].[bar]', connection.quote_column_name('foo.bar')
192
+ end
193
+
194
+ it 'not quote already quoted column names with brackets' do
195
+ assert_equal '[foo]', connection.quote_column_name('[foo]')
196
+ assert_equal '[foo].[bar]', connection.quote_column_name('[foo].[bar]')
197
+ end
198
+
199
+ it 'quote table names like columns' do
200
+ assert_equal '[foo].[bar]', connection.quote_column_name('foo.bar')
201
+ assert_equal '[foo].[bar].[baz]', connection.quote_column_name('foo.bar.baz')
202
+ end
203
+
204
+ it "surround string with national prefix" do
205
+ assert_equal "N'foo'", connection.quote("foo")
206
+ end
207
+
208
+ it "escape all single quotes by repeating them" do
209
+ assert_equal "N'''quotation''s'''", connection.quote("'quotation's'")
210
+ end
211
+
212
+ end
213
+
214
+ describe 'disabling referential integrity' do
215
+
216
+ before do
217
+ connection.disable_referential_integrity { SSTestHasPk.delete_all; SSTestHasFk.delete_all }
218
+ @parent = SSTestHasPk.create!
219
+ @member = SSTestHasFk.create!(fk_id: @parent.id)
220
+ end
221
+
222
+ it 'NOT ALLOW by default the deletion of a referenced parent' do
223
+ SSTestHasPk.connection.disable_referential_integrity { }
224
+ assert_raise(ActiveRecord::StatementInvalid) { @parent.destroy }
225
+ end
226
+
227
+ it 'ALLOW deletion of referenced parent using #disable_referential_integrity block' do
228
+ SSTestHasPk.connection.disable_referential_integrity { @parent.destroy }
229
+ end
230
+
231
+ it 'again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block' do
232
+ assert_raise(ActiveRecord::StatementInvalid) do
233
+ SSTestHasPk.connection.disable_referential_integrity { }
234
+ @parent.destroy
235
+ end
236
+ end
237
+
238
+ end
239
+
240
+ describe 'database statements' do
241
+
242
+ it "run the database consistency checker useroptions command" do
243
+ keys = [:textsize, :language, :isolation_level, :dateformat]
244
+ user_options = connection.user_options
245
+ keys.each do |key|
246
+ msg = "Expected key:#{key} in user_options:#{user_options.inspect}"
247
+ assert user_options.key?(key), msg
248
+ end
249
+ end
250
+
251
+ it "return a underscored key hash with indifferent access of the results" do
252
+ user_options = connection.user_options
253
+ assert_equal 'read committed', user_options['isolation_level']
254
+ assert_equal 'read committed', user_options[:isolation_level]
255
+ end
256
+
257
+ end
258
+
259
+ describe 'schema statements' do
260
+
261
+ it 'create integers when no limit supplied' do
262
+ assert_equal 'integer', connection.type_to_sql(:integer)
263
+ end
264
+
265
+ it 'create integers when limit is 4' do
266
+ assert_equal 'integer', connection.type_to_sql(:integer, 4)
267
+ end
268
+
269
+ it 'create integers when limit is 3' do
270
+ assert_equal 'integer', connection.type_to_sql(:integer, 3)
271
+ end
272
+
273
+ it 'create smallints when limit is less than 3' do
274
+ assert_equal 'smallint', connection.type_to_sql(:integer, 2)
275
+ assert_equal 'smallint', connection.type_to_sql(:integer, 1)
276
+ end
277
+
278
+ it 'create bigints when limit is greateer than 4' do
279
+ assert_equal 'bigint', connection.type_to_sql(:integer, 5)
280
+ assert_equal 'bigint', connection.type_to_sql(:integer, 6)
281
+ assert_equal 'bigint', connection.type_to_sql(:integer, 7)
282
+ assert_equal 'bigint', connection.type_to_sql(:integer, 8)
283
+ end
284
+
285
+ it 'create floats when no limit supplied' do
286
+ assert_equal 'float', connection.type_to_sql(:float)
287
+ end
288
+
289
+ end
290
+
291
+ describe 'indexes' do
292
+
293
+ let(:desc_index_name) { 'idx_credit_limit_test_desc' }
294
+
295
+ it 'have indexes with descending order' do
296
+ begin
297
+ connection.execute "CREATE INDEX [#{desc_index_name}] ON [accounts] (credit_limit DESC)"
298
+ assert connection.indexes('accounts').find { |i| i.name == desc_index_name }
299
+ ensure
300
+ connection.execute "DROP INDEX [#{desc_index_name}] ON [accounts]"
301
+ end
302
+ end
303
+
304
+ end
305
+
306
+ describe 'views' do
307
+
308
+ # Using connection.views
309
+
310
+ it 'return an array' do
311
+ assert_instance_of Array, connection.views
312
+ end
313
+
314
+ it 'find SSTestCustomersView table name' do
315
+ connection.views.must_include 'sst_customers_view'
316
+ end
317
+
318
+ it 'work with dynamic finders' do
319
+ name = 'MetaSkills'
320
+ customer = SSTestCustomersView.create! name: name
321
+ assert_equal customer, SSTestCustomersView.find_by_name(name)
322
+ end
323
+
324
+ it 'not contain system views' do
325
+ systables = ['sysconstraints','syssegments']
326
+ systables.each do |systable|
327
+ assert !connection.views.include?(systable), "This systable #{systable} should not be in the views array."
328
+ end
329
+ end
330
+
331
+ it 'allow the connection#view_information method to return meta data on the view' do
332
+ view_info = connection.send(:view_information,'sst_customers_view')
333
+ assert_equal('sst_customers_view', view_info['TABLE_NAME'])
334
+ assert_match(/CREATE VIEW sst_customers_view/, view_info['VIEW_DEFINITION'])
335
+ end
336
+
337
+ it 'allow the connection#view_table_name method to return true table_name for the view' do
338
+ assert_equal 'customers', connection.send(:view_table_name,'sst_customers_view')
339
+ assert_equal 'topics', connection.send(:view_table_name,'topics'), 'No view here, the same table name should come back.'
340
+ end
341
+
342
+ # With same column names
343
+
344
+ it 'have matching column objects' do
345
+ columns = ['id','name','balance']
346
+ assert !SSTestCustomersView.columns.blank?
347
+ assert_equal columns.size, SSTestCustomersView.columns.size
348
+ columns.each do |colname|
349
+ assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
350
+ SSTestCustomersView.columns_hash[colname],
351
+ "Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
352
+ end
353
+ end
354
+
355
+ it 'find identity column' do
356
+ SSTestCustomersView.primary_key.must_equal 'id'
357
+ connection.primary_key(SSTestCustomersView.table_name).must_equal 'id'
358
+ SSTestCustomersView.columns_hash['id'].must_be :is_identity?
359
+ end
360
+
361
+ it 'find default values' do
362
+ assert_equal 0, SSTestCustomersView.new.balance
363
+ end
364
+
365
+ it 'respond true to table_exists?' do
366
+ assert SSTestCustomersView.table_exists?
367
+ end
368
+
369
+ # With aliased column names
370
+
371
+ it 'have matching column objects' do
372
+ columns = ['id','pretend_null']
373
+ assert !SSTestStringDefaultsView.columns.blank?
374
+ assert_equal columns.size, SSTestStringDefaultsView.columns.size
375
+ columns.each do |colname|
376
+ assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
377
+ SSTestStringDefaultsView.columns_hash[colname],
378
+ "Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
379
+ end
380
+ end
381
+
382
+ it 'find identity column' do
383
+ SSTestStringDefaultsView.primary_key.must_equal 'id'
384
+ connection.primary_key(SSTestStringDefaultsView.table_name).must_equal 'id'
385
+ SSTestStringDefaultsView.columns_hash['id'].must_be :is_identity?
386
+ end
387
+
388
+ it 'find default values' do
389
+ assert_equal 'null', SSTestStringDefaultsView.new.pretend_null,
390
+ SSTestStringDefaultsView.columns_hash['pretend_null'].inspect
391
+ end
392
+
393
+ it 'respond true to table_exists?' do
394
+ assert SSTestStringDefaultsView.table_exists?
395
+ end
396
+
397
+ # Doing identity inserts
398
+
399
+ it 'be able to do an identity insert' do
400
+ customer = SSTestCustomersView.new
401
+ customer.id = 420
402
+ customer.save!
403
+ assert SSTestCustomersView.find(420)
404
+ end
405
+
406
+ # That have more than 4000 chars for their defintion
407
+
408
+ it 'cope with null returned for the defintion' do
409
+ assert_nothing_raised() { SSTestStringDefaultsBigView.columns }
410
+ end
411
+
412
+ it 'using alternate view defintion still be able to find real default' do
413
+ assert_equal 'null', SSTestStringDefaultsBigView.new.pretend_null,
414
+ SSTestStringDefaultsBigView.columns_hash['pretend_null'].inspect
415
+ end
416
+
417
+ end
418
+
419
+ end
420
+
@@ -0,0 +1,642 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+
4
+ module ActiveRecord
5
+ class AdapterTest < ActiveRecord::TestCase
6
+
7
+ # As far as I can tell, SQL Server does not support null bytes in strings.
8
+ coerce_tests! :test_update_prepared_statement
9
+
10
+ end
11
+ end
12
+
13
+
14
+
15
+
16
+ require 'models/topic'
17
+ class AttributeMethodsTest < ActiveRecord::TestCase
18
+
19
+ coerce_tests! :test_typecast_attribute_from_select_to_false
20
+ def test_typecast_attribute_from_select_to_false_coerced
21
+ Topic.create(:title => 'Budget')
22
+ topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 2, 1, 0) as is_test").first
23
+ assert !topic.is_test?
24
+ end
25
+
26
+ coerce_tests! :test_typecast_attribute_from_select_to_true
27
+ def test_typecast_attribute_from_select_to_true_coerced
28
+ Topic.create(:title => 'Budget')
29
+ topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 1, 1, 0) as is_test").first
30
+ assert topic.is_test?
31
+ end
32
+
33
+ end
34
+
35
+
36
+
37
+
38
+ class BasicsTest < ActiveRecord::TestCase
39
+
40
+ coerce_tests! :test_column_names_are_escaped
41
+ def test_column_names_are_escaped_coerced
42
+ conn = ActiveRecord::Base.connection
43
+ classname = conn.class.name[/[^:]*$/]
44
+ badchar = "'"
45
+ quoted = conn.quote_column_name "foo#{badchar}bar"
46
+ assert_equal "[foo'bar]", quoted
47
+ end
48
+
49
+ # This test has a few problems. First, it would require that we use
50
+ # the `Type::SQLServer::BigInteger.new(limit: 8)` for the `world_population`
51
+ # attribute. Second, since we allow the DB to win at casting for TinyTDS,
52
+ # it always comes back as a BigDecimal.
53
+ coerce_tests! :test_numeric_fields
54
+
55
+ # Just like PostgreSQLAdapter does.
56
+ coerce_tests! :test_respect_internal_encoding
57
+
58
+ end
59
+
60
+
61
+
62
+
63
+ class BelongsToAssociationsTest < ActiveRecord::TestCase
64
+
65
+ # Since @client.firm is a single first/top, and we use FETCH the order clause is used.
66
+ coerce_tests! :test_belongs_to_does_not_use_order_by
67
+
68
+ coerce_tests! :test_belongs_to_with_primary_key_joins_on_correct_column
69
+ def test_belongs_to_with_primary_key_joins_on_correct_column_coerced
70
+ sql = Client.joins(:firm_with_primary_key).to_sql
71
+ assert_no_match(/\[firm_with_primary_keys_companies\]\.\[id\]/, sql)
72
+ assert_match(/\[firm_with_primary_keys_companies\]\.\[name\]/, sql)
73
+ end
74
+
75
+ end
76
+
77
+
78
+
79
+
80
+ module ActiveRecord
81
+ class BindParameterTest < ActiveRecord::TestCase
82
+
83
+ # Never finds `sql` since we use `EXEC sp_executesql` wrappers.
84
+ coerce_tests! :test_binds_are_logged,
85
+ :test_binds_are_logged_after_type_cast
86
+
87
+ end
88
+ end
89
+
90
+
91
+
92
+
93
+ class CalculationsTest < ActiveRecord::TestCase
94
+
95
+ # Are decimal, not integer.
96
+ coerce_tests! :test_should_return_decimal_average_of_integer_field
97
+ def test_should_return_decimal_average_of_integer_field_coerced
98
+ value = Account.average(:id)
99
+ assert_equal BigDecimal('3.0').to_s, BigDecimal(value).to_s
100
+ end
101
+
102
+ coerce_tests! :test_limit_is_kept
103
+ def test_limit_is_kept_coerced
104
+ queries = assert_sql { Account.limit(1).count }
105
+ assert_equal 1, queries.length
106
+ queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY}
107
+ end
108
+
109
+ coerce_tests! :test_limit_with_offset_is_kept
110
+ def test_limit_with_offset_is_kept_coerced
111
+ queries = assert_sql { Account.limit(1).offset(1).count }
112
+ assert_equal 1, queries.length
113
+ queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY}
114
+ end
115
+
116
+ end
117
+
118
+
119
+
120
+
121
+ module ActiveRecord
122
+ class Migration
123
+ class ChangeSchemaTest < ActiveRecord::TestCase
124
+
125
+ # We test these.
126
+ coerce_tests! :test_create_table_with_bigint,
127
+ :test_create_table_with_defaults
128
+
129
+ end
130
+ end
131
+ end
132
+
133
+
134
+
135
+
136
+ module ActiveRecord
137
+ class Migration
138
+ class ColumnAttributesTest < ActiveRecord::TestCase
139
+
140
+ # We have a default 4000 varying character limit.
141
+ coerce_tests! :test_add_column_without_limit
142
+ def test_add_column_without_limit_coerced
143
+ add_column :test_models, :description, :string, limit: nil
144
+ TestModel.reset_column_information
145
+ TestModel.columns_hash["description"].limit.must_equal 4000
146
+ end
147
+
148
+ end
149
+ end
150
+ end
151
+
152
+
153
+
154
+
155
+ module ActiveRecord
156
+ class Migration
157
+ class ColumnsTest
158
+
159
+ # Our defaults are reall 70000 integers vs '70000' strings.
160
+ coerce_tests! :test_rename_column_preserves_default_value_not_null
161
+ def test_rename_column_preserves_default_value_not_null_coerced
162
+ add_column 'test_models', 'salary', :integer, :default => 70000
163
+ default_before = connection.columns("test_models").find { |c| c.name == "salary" }.default
164
+ assert_equal 70000, default_before
165
+ rename_column "test_models", "salary", "annual_salary"
166
+ assert TestModel.column_names.include?("annual_salary")
167
+ default_after = connection.columns("test_models").find { |c| c.name == "annual_salary" }.default
168
+ assert_equal 70000, default_after
169
+ end
170
+
171
+ # Dropping the column removes the single index.
172
+ coerce_tests! :test_remove_column_with_multi_column_index
173
+ def test_remove_column_with_multi_column_index_coerced
174
+ add_column "test_models", :hat_size, :integer
175
+ add_column "test_models", :hat_style, :string, :limit => 100
176
+ add_index "test_models", ["hat_style", "hat_size"], :unique => true
177
+ assert_equal 1, connection.indexes('test_models').size
178
+ remove_column("test_models", "hat_size")
179
+ assert_equal [], connection.indexes('test_models').map(&:name)
180
+ end
181
+
182
+ end
183
+ end
184
+ end
185
+
186
+
187
+
188
+
189
+ class CoreTest < ActiveRecord::TestCase
190
+
191
+ # I think fixtures are useing the wrong time zone and the `:first`
192
+ # `topics`.`bonus_time` attribute of 2005-01-30t15:28:00.00+01:00 is
193
+ # getting local EST time for me and set to "09:28:00.0000000".
194
+ coerce_tests! :test_pretty_print_persisted
195
+
196
+ end
197
+
198
+
199
+
200
+
201
+ module ActiveRecord
202
+ module ConnectionAdapters
203
+
204
+ # Just like PostgreSQLAdapter does.
205
+ TypeLookupTest.coerce_all_tests! if defined?(TypeLookupTest)
206
+
207
+ # All sorts of errors due to how we test. Even setting ENV['RAILS_ENV'] to
208
+ # a value of 'default_env' will still show tests failing. Just ignoring all
209
+ # of them since we have no monkey in this circus.
210
+ MergeAndResolveDefaultUrlConfigTest.coerce_all_tests! if defined?(MergeAndResolveDefaultUrlConfigTest)
211
+
212
+ end
213
+ end
214
+
215
+
216
+
217
+
218
+ class DefaultScopingTest < ActiveRecord::TestCase
219
+
220
+ # We are not doing order duplicate removal anymore.
221
+ coerce_tests! :test_order_in_default_scope_should_not_prevail
222
+
223
+ end
224
+
225
+
226
+
227
+
228
+ require 'models/post'
229
+ require 'models/subscriber'
230
+ class EachTest < ActiveRecord::TestCase
231
+
232
+ coerce_tests! :test_find_in_batches_should_quote_batch_order
233
+ def test_find_in_batches_should_quote_batch_order_coerced
234
+ c = Post.connection
235
+ assert_sql(/ORDER BY \[posts\]\.\[id\]/) do
236
+ Post.find_in_batches(:batch_size => 1) do |batch|
237
+ assert_kind_of Array, batch
238
+ assert_kind_of Post, batch.first
239
+ end
240
+ end
241
+ end
242
+
243
+ end
244
+
245
+
246
+
247
+
248
+ require 'models/owner'
249
+ class Owner < ActiveRecord::Base
250
+ scope :including_last_pet, -> {
251
+ select('owners.*, (select TOP (1) p.pet_id from pets p where p.owner_id = owners.owner_id order by p.name desc ) as last_pet_id').
252
+ includes(:last_pet)
253
+ }
254
+ end
255
+ class EagerAssociationTest < ActiveRecord::TestCase
256
+
257
+ # Use LEN() vs length() function.
258
+ coerce_tests! :test_count_with_include
259
+ def test_count_with_include_coerced
260
+ assert_equal 3, authors(:david).posts_with_comments.where("LEN(comments.body) > 15").references(:comments).count
261
+ end
262
+
263
+ # Use TOP (1) in scope vs limit 1.
264
+ coerce_tests! %r{including association based on sql condition and no database column}
265
+ it "including association based on sql condition and no database column coerced" do
266
+ assert_equal pets(:parrot), Owner.including_last_pet.first.last_pet
267
+ end
268
+
269
+ end
270
+
271
+
272
+
273
+
274
+ require 'models/topic'
275
+ class FinderTest < ActiveRecord::TestCase
276
+
277
+ coerce_tests! %r{doesn't have implicit ordering},
278
+ :test_find_doesnt_have_implicit_ordering # We have implicit ordering, via FETCH.
279
+
280
+ coerce_tests! :test_exists_does_not_select_columns_without_alias
281
+ def test_exists_does_not_select_columns_without_alias_coerced
282
+ assert_sql(/SELECT\s+1 AS one FROM \[topics\].*OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY/i) do
283
+ Topic.exists?
284
+ end
285
+ end
286
+
287
+ coerce_tests! :test_string_sanitation
288
+ def test_string_sanitation_coerced
289
+ assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
290
+ assert_equal "N'something; select table'", ActiveRecord::Base.sanitize("something; select table")
291
+ end
292
+
293
+ coerce_tests! :test_take_and_first_and_last_with_integer_should_use_sql_limit
294
+ def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
295
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY/) { Topic.take(3).entries }
296
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT 2 ROWS ONLY/) { Topic.first(2).entries }
297
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY/) { Topic.last(5).entries }
298
+ end
299
+
300
+ end
301
+
302
+
303
+
304
+
305
+ class HasOneAssociationsTest < ActiveRecord::TestCase
306
+
307
+ # We use OFFSET/FETCH vs TOP. So we always have an order.
308
+ coerce_tests! :test_has_one_does_not_use_order_by
309
+
310
+ end
311
+
312
+
313
+
314
+
315
+ require 'models/company'
316
+ class InheritanceTest < ActiveRecord::TestCase
317
+
318
+ coerce_tests! :test_a_bad_type_column
319
+ def test_a_bad_type_column_coerced
320
+ Company.connection.with_identity_insert_enabled('companies') do
321
+ Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
322
+ end
323
+ assert_raise(ActiveRecord::SubclassNotFound) { Company.find(100) }
324
+ end
325
+
326
+ coerce_tests! :test_eager_load_belongs_to_primary_key_quoting
327
+ def test_eager_load_belongs_to_primary_key_quoting_coerced
328
+ con = Account.connection
329
+ assert_sql(/\[companies\]\.\[id\] IN \(1\)/) do
330
+ Account.all.merge!(:includes => :firm).find(1)
331
+ end
332
+ end
333
+
334
+ end
335
+
336
+
337
+
338
+
339
+ class BigNumber < ActiveRecord::Base
340
+ attribute :value_of_e, Type::SQLServer::Integer.new
341
+ attribute :my_house_population, Type::SQLServer::Integer.new
342
+ end
343
+ class MigrationTest < ActiveRecord::TestCase
344
+
345
+ coerce_tests! :test_add_table_with_decimals
346
+ def test_add_table_with_decimals_coerced
347
+ Person.connection.drop_table :big_numbers rescue nil
348
+ assert !BigNumber.table_exists?
349
+ GiveMeBigNumbers.up
350
+ assert BigNumber.create(
351
+ :bank_balance => 1586.43,
352
+ :big_bank_balance => BigDecimal("1000234000567.95"),
353
+ :world_population => 6000000000,
354
+ :my_house_population => 3,
355
+ :value_of_e => BigDecimal("2.7182818284590452353602875")
356
+ )
357
+ b = BigNumber.first
358
+ assert_not_nil b
359
+ assert_not_nil b.bank_balance
360
+ assert_not_nil b.big_bank_balance
361
+ assert_not_nil b.world_population
362
+ assert_not_nil b.my_house_population
363
+ assert_not_nil b.value_of_e
364
+ # SQLServer: We rock and cast during assignment.
365
+ assert_kind_of BigDecimal, b.world_population
366
+ assert_equal BigDecimal('6000000000'), b.world_population
367
+ # TODO: Our trust the DB policy breaks this expectation. Review SQLServer::Type::Castable module.
368
+ skip
369
+ assert_kind_of Fixnum, b.my_house_population
370
+ assert_equal 3, b.my_house_population
371
+ assert_kind_of BigDecimal, b.bank_balance
372
+ assert_equal BigDecimal("1586.43"), b.bank_balance
373
+ assert_kind_of BigDecimal, b.big_bank_balance
374
+ assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
375
+ assert_kind_of BigDecimal, b.value_of_e
376
+ assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
377
+ GiveMeBigNumbers.down
378
+ assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first }
379
+ end
380
+
381
+ end
382
+
383
+
384
+
385
+
386
+ require 'models/developer'
387
+ require 'models/computer'
388
+ class NestedRelationScopingTest < ActiveRecord::TestCase
389
+
390
+ coerce_tests! :test_merge_options
391
+ def test_merge_options_coerced
392
+ Developer.where('salary = 80000').scoping do
393
+ Developer.limit(10).scoping do
394
+ devs = Developer.all
395
+ sql = devs.to_sql
396
+ assert_match '(salary = 80000)', sql
397
+ assert_match 'FETCH NEXT 10 ROWS ONLY', sql
398
+ end
399
+ end
400
+ end
401
+
402
+ end
403
+
404
+
405
+
406
+
407
+ require 'models/topic'
408
+ class PersistenceTest < ActiveRecord::TestCase
409
+
410
+ # We can not UPDATE identity columns.
411
+ coerce_tests! :test_update_columns_changing_id
412
+
413
+ # Previous test required updating a identity column.
414
+ coerce_tests! :test_update_all_doesnt_ignore_order
415
+ def test_update_all_doesnt_ignore_order_coerced
416
+ david, mary = authors(:david), authors(:mary)
417
+ david.id.must_equal 1
418
+ mary.id.must_equal 2
419
+ david.name.wont_equal mary.name
420
+ assert_sql(/UPDATE.*\(SELECT \[authors\].\[id\] FROM \[authors\].*ORDER BY \[authors\].\[id\]/i) do
421
+ Author.where('[id] > 1').order(:id).update_all(name: 'Test')
422
+ end
423
+ david.reload.name.must_equal 'David'
424
+ mary.reload.name.must_equal 'Test'
425
+ end
426
+
427
+ # We can not UPDATE identity columns.
428
+ coerce_tests! :test_update_attributes
429
+ def test_update_attributes_coerced
430
+ topic = Topic.find(1)
431
+ assert !topic.approved?
432
+ assert_equal "The First Topic", topic.title
433
+ topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
434
+ topic.reload
435
+ assert topic.approved?
436
+ assert_equal "The First Topic Updated", topic.title
437
+ topic.update_attributes(approved: false, title: "The First Topic")
438
+ topic.reload
439
+ assert !topic.approved?
440
+ assert_equal "The First Topic", topic.title
441
+ # SQLServer: Here is where it breaks down. No exceptions.
442
+ # assert_raise(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid) do
443
+ # topic.update_attributes(id: 3, title: "Hm is it possible?")
444
+ # end
445
+ # assert_not_equal "Hm is it possible?", Topic.find(3).title
446
+ # topic.update_attributes(id: 1234)
447
+ # assert_nothing_raised { topic.reload }
448
+ # assert_equal topic.title, Topic.find(1234).title
449
+ end
450
+
451
+ end
452
+
453
+
454
+
455
+
456
+ require 'models/topic'
457
+ module ActiveRecord
458
+ class PredicateBuilderTest < ActiveRecord::TestCase
459
+
460
+ coerce_tests! :test_registering_new_handlers
461
+ def test_registering_new_handlers_coerced
462
+ PredicateBuilder.register_handler(Regexp, proc do |column, value|
463
+ Arel::Nodes::InfixOperation.new('~', column, Arel.sql(value.source))
464
+ end)
465
+ assert_match %r{\[topics\]\.\[title\] ~ rails}i, Topic.where(title: /rails/).to_sql
466
+ end
467
+
468
+ end
469
+ end
470
+
471
+
472
+
473
+
474
+ require 'models/task'
475
+ class QueryCacheTest < ActiveRecord::TestCase
476
+
477
+ coerce_tests! :test_cache_does_not_wrap_string_results_in_arrays
478
+ def test_cache_does_not_wrap_string_results_in_arrays_coerced
479
+ Task.cache do
480
+ assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
481
+ end
482
+ end
483
+
484
+ end
485
+
486
+
487
+
488
+
489
+ require 'models/post'
490
+ class RelationTest < ActiveRecord::TestCase
491
+
492
+ # We have implicit ordering, via FETCH.
493
+ coerce_tests! %r{doesn't have implicit ordering}
494
+
495
+ # We are not doing order duplicate removal anymore.
496
+ coerce_tests! :test_order_using_scoping
497
+
498
+ # Account for our `EXEC sp_executesql...` statements.
499
+ coerce_tests! :test_to_sql_on_eager_join
500
+ def test_to_sql_on_eager_join_coerced
501
+ expected = assert_sql { Post.eager_load(:last_comment).order('comments.id DESC').to_a }.first
502
+ actual = Post.eager_load(:last_comment).order('comments.id DESC').to_sql
503
+ actual = "EXEC sp_executesql N'#{ActiveRecord::ConnectionAdapters::SQLServer::Utils.quote_string(actual)}'"
504
+ assert_equal expected, actual
505
+ end
506
+
507
+ # We are not doing order duplicate removal anymore.
508
+ coerce_tests! :test_default_scope_order_with_scope_order
509
+
510
+ end
511
+
512
+
513
+
514
+
515
+ require 'models/post'
516
+ class SanitizeTest < ActiveRecord::TestCase
517
+
518
+ coerce_tests! :test_sanitize_sql_like_example_use_case
519
+ def test_sanitize_sql_like_example_use_case_coerced
520
+ searchable_post = Class.new(Post) do
521
+ def self.search(term)
522
+ where("title LIKE ?", sanitize_sql_like(term, '!'))
523
+ end
524
+ end
525
+ assert_sql(/\(title LIKE N''20!% !_reduction!_!!''\)/) do
526
+ searchable_post.search("20% _reduction_!").to_a
527
+ end
528
+ end
529
+
530
+ end
531
+
532
+
533
+
534
+
535
+ class SchemaDumperTest < ActiveRecord::TestCase
536
+
537
+ # We have precision to 38.
538
+ coerce_tests! :test_schema_dump_keeps_large_precision_integer_columns_as_decimal
539
+ def test_schema_dump_keeps_large_precision_integer_columns_as_decimal_coerced
540
+ output = standard_dump
541
+ assert_match %r{t.decimal\s+"atoms_in_universe",\s+precision: 38}, output
542
+ end
543
+
544
+ # This accidently returns the wrong number because of our tables too.
545
+ coerce_tests! :test_types_line_up
546
+
547
+ end
548
+
549
+
550
+
551
+
552
+ class TestAdapterWithInvalidConnection < ActiveRecord::TestCase
553
+
554
+ # We trust Rails on this since we do not want to install mysql.
555
+ coerce_tests! %r{inspect on Model class does not raise}
556
+
557
+ end
558
+
559
+
560
+
561
+
562
+ require 'models/topic'
563
+ class TransactionTest < ActiveRecord::TestCase
564
+
565
+ coerce_tests! :test_releasing_named_savepoints
566
+ def test_releasing_named_savepoints_coerced
567
+ Topic.transaction do
568
+ Topic.connection.create_savepoint("another")
569
+ Topic.connection.release_savepoint("another")
570
+ # We do not have a notion of releasing, so this does nothing vs raise an error.
571
+ Topic.connection.release_savepoint("another")
572
+ end
573
+ end
574
+
575
+ end
576
+
577
+
578
+
579
+
580
+ require 'models/tag'
581
+ class TransactionIsolationTest < ActiveRecord::TestCase
582
+
583
+ # SQL Server will lock the table for counts even when both
584
+ # connections are `READ COMMITTED`. So we bypass with `READPAST`.
585
+ coerce_tests! %r{read committed}
586
+ test "read committed coerced" do
587
+ Tag.transaction(isolation: :read_committed) do
588
+ assert_equal 0, Tag.count
589
+ Tag2.transaction do
590
+ Tag2.create
591
+ assert_equal 0, Tag.lock('WITH(READPAST)').count
592
+ end
593
+ end
594
+ assert_equal 1, Tag.count
595
+ end
596
+
597
+ # I really need some help understanding this one.
598
+ coerce_tests! %r{repeatable read}
599
+
600
+ end
601
+
602
+
603
+ require 'models/post'
604
+ module ActiveRecord
605
+ class WhereChainTest < ActiveRecord::TestCase
606
+
607
+ coerce_tests! :test_not_eq_with_array_parameter
608
+ def test_not_eq_with_array_parameter_coerced
609
+ expected = Arel::Nodes::Not.new("title = N'hello'")
610
+ relation = Post.where.not(['title = ?', 'hello'])
611
+ assert_equal([expected], relation.where_values)
612
+ end
613
+
614
+ end
615
+ end
616
+
617
+
618
+
619
+
620
+ class ViewWithPrimaryKeyTest < ActiveRecord::TestCase
621
+
622
+ # We do better than ActiveRecord and find the views PK.
623
+ coerce_tests! :test_does_not_assume_id_column_as_primary_key
624
+
625
+ end
626
+
627
+
628
+
629
+
630
+ require 'models/author'
631
+ class YamlSerializationTest < ActiveRecord::TestCase
632
+
633
+ coerce_tests! :test_types_of_virtual_columns_are_not_changed_on_round_trip
634
+ def test_types_of_virtual_columns_are_not_changed_on_round_trip_coerced
635
+ author = Author.select('authors.*, 5 as posts_count').first
636
+ dumped = YAML.load(YAML.dump(author))
637
+ assert_equal 5, author.posts_count
638
+ assert_equal 5, dumped.posts_count
639
+ end
640
+
641
+ end
642
+