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
@@ -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
+