activerecord-jdbcsqlserver-adapter 50.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +27 -0
  4. data/CHANGELOG.md +124 -0
  5. data/CODE_OF_CONDUCT.md +31 -0
  6. data/Dockerfile +20 -0
  7. data/Gemfile +77 -0
  8. data/Guardfile +29 -0
  9. data/MIT-LICENSE +20 -0
  10. data/RAILS5-TODO.md +5 -0
  11. data/README.md +93 -0
  12. data/RUNNING_UNIT_TESTS.md +96 -0
  13. data/Rakefile +46 -0
  14. data/VERSION +1 -0
  15. data/activerecord-jdbcsqlserver-adapter.gemspec +21 -0
  16. data/appveyor.yml +39 -0
  17. data/docker-compose.ci.yml +11 -0
  18. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +27 -0
  19. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
  20. data/lib/active_record/connection_adapters/sqlserver/core_ext/date_time.rb +58 -0
  21. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +47 -0
  22. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +4 -0
  23. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
  24. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +362 -0
  25. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +67 -0
  26. data/lib/active_record/connection_adapters/sqlserver/errors.rb +7 -0
  27. data/lib/active_record/connection_adapters/sqlserver/jdbc_overrides.rb +192 -0
  28. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +99 -0
  29. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +34 -0
  30. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -0
  31. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +517 -0
  32. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +66 -0
  33. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +66 -0
  34. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +22 -0
  35. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +20 -0
  36. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +112 -0
  37. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +64 -0
  38. data/lib/active_record/connection_adapters/sqlserver/type.rb +49 -0
  39. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +19 -0
  40. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +21 -0
  41. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +15 -0
  42. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +32 -0
  43. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +30 -0
  44. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +61 -0
  45. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +71 -0
  46. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +17 -0
  47. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +23 -0
  48. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +21 -0
  49. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +19 -0
  50. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +15 -0
  51. data/lib/active_record/connection_adapters/sqlserver/type/json.rb +11 -0
  52. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +25 -0
  53. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +19 -0
  54. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +15 -0
  55. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +25 -0
  56. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +29 -0
  57. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
  58. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +19 -0
  59. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +68 -0
  60. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +93 -0
  61. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +19 -0
  62. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +25 -0
  63. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +21 -0
  64. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
  65. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +19 -0
  66. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +26 -0
  67. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +24 -0
  68. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +36 -0
  69. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +26 -0
  70. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +24 -0
  71. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +26 -0
  72. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +24 -0
  73. data/lib/active_record/connection_adapters/sqlserver/utils.rb +146 -0
  74. data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
  75. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +445 -0
  76. data/lib/active_record/connection_adapters/sqlserver_column.rb +28 -0
  77. data/lib/active_record/jdbc_sqlserver_connection_methods.rb +31 -0
  78. data/lib/active_record/sqlserver_base.rb +16 -0
  79. data/lib/active_record/tasks/sqlserver_database_tasks.rb +131 -0
  80. data/lib/activerecord-jdbcsqlserver-adapter.rb +24 -0
  81. data/lib/activerecord-sqlserver-adapter.rb +1 -0
  82. data/lib/arel/visitors/sqlserver.rb +205 -0
  83. data/lib/arel_sqlserver.rb +3 -0
  84. data/test/appveyor/dbsetup.ps1 +27 -0
  85. data/test/appveyor/dbsetup.sql +11 -0
  86. data/test/bin/wait-for.sh +79 -0
  87. data/test/cases/adapter_test_sqlserver.rb +430 -0
  88. data/test/cases/coerced_tests.rb +845 -0
  89. data/test/cases/column_test_sqlserver.rb +812 -0
  90. data/test/cases/connection_test_sqlserver.rb +71 -0
  91. data/test/cases/execute_procedure_test_sqlserver.rb +45 -0
  92. data/test/cases/fetch_test_sqlserver.rb +57 -0
  93. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +76 -0
  94. data/test/cases/helper_sqlserver.rb +44 -0
  95. data/test/cases/index_test_sqlserver.rb +47 -0
  96. data/test/cases/json_test_sqlserver.rb +32 -0
  97. data/test/cases/migration_test_sqlserver.rb +61 -0
  98. data/test/cases/order_test_sqlserver.rb +147 -0
  99. data/test/cases/pessimistic_locking_test_sqlserver.rb +94 -0
  100. data/test/cases/rake_test_sqlserver.rb +169 -0
  101. data/test/cases/schema_dumper_test_sqlserver.rb +234 -0
  102. data/test/cases/schema_test_sqlserver.rb +54 -0
  103. data/test/cases/scratchpad_test_sqlserver.rb +8 -0
  104. data/test/cases/showplan_test_sqlserver.rb +65 -0
  105. data/test/cases/specific_schema_test_sqlserver.rb +180 -0
  106. data/test/cases/transaction_test_sqlserver.rb +91 -0
  107. data/test/cases/utils_test_sqlserver.rb +129 -0
  108. data/test/cases/uuid_test_sqlserver.rb +49 -0
  109. data/test/config.yml +38 -0
  110. data/test/debug.rb +14 -0
  111. data/test/fixtures/1px.gif +0 -0
  112. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
  113. data/test/models/sqlserver/booking.rb +3 -0
  114. data/test/models/sqlserver/customers_view.rb +3 -0
  115. data/test/models/sqlserver/datatype.rb +3 -0
  116. data/test/models/sqlserver/datatype_migration.rb +8 -0
  117. data/test/models/sqlserver/dollar_table_name.rb +3 -0
  118. data/test/models/sqlserver/dot_table_name.rb +3 -0
  119. data/test/models/sqlserver/edge_schema.rb +13 -0
  120. data/test/models/sqlserver/fk_has_fk.rb +3 -0
  121. data/test/models/sqlserver/fk_has_pk.rb +3 -0
  122. data/test/models/sqlserver/natural_pk_data.rb +4 -0
  123. data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
  124. data/test/models/sqlserver/no_pk_data.rb +3 -0
  125. data/test/models/sqlserver/object_default.rb +3 -0
  126. data/test/models/sqlserver/quoted_table.rb +7 -0
  127. data/test/models/sqlserver/quoted_view_1.rb +3 -0
  128. data/test/models/sqlserver/quoted_view_2.rb +3 -0
  129. data/test/models/sqlserver/sst_memory.rb +3 -0
  130. data/test/models/sqlserver/string_default.rb +3 -0
  131. data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
  132. data/test/models/sqlserver/string_defaults_view.rb +3 -0
  133. data/test/models/sqlserver/tinyint_pk.rb +3 -0
  134. data/test/models/sqlserver/upper.rb +3 -0
  135. data/test/models/sqlserver/uppered.rb +3 -0
  136. data/test/models/sqlserver/uuid.rb +3 -0
  137. data/test/schema/datatypes/2012.sql +55 -0
  138. data/test/schema/enable-in-memory-oltp.sql +81 -0
  139. data/test/schema/sqlserver_specific_schema.rb +238 -0
  140. data/test/support/coerceable_test_sqlserver.rb +49 -0
  141. data/test/support/connection_reflection.rb +34 -0
  142. data/test/support/load_schema_sqlserver.rb +29 -0
  143. data/test/support/minitest_sqlserver.rb +1 -0
  144. data/test/support/paths_sqlserver.rb +50 -0
  145. data/test/support/rake_helpers.rb +41 -0
  146. data/test/support/sql_counter_sqlserver.rb +28 -0
  147. data/test/support/test_in_memory_oltp.rb +15 -0
  148. metadata +310 -0
@@ -0,0 +1,845 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+
4
+
5
+ require 'models/event'
6
+ class UniquenessValidationTest < ActiveRecord::TestCase
7
+ # So sp_executesql swallows this exception. Run without prpared to see it.
8
+ coerce_tests! :test_validate_uniqueness_with_limit
9
+ def test_validate_uniqueness_with_limit_coerced
10
+ connection.unprepared_statement do
11
+ assert_raise(ActiveRecord::ValueTooLong) do
12
+ Event.create(title: "abcdefgh")
13
+ end
14
+ end
15
+ end
16
+
17
+ # So sp_executesql swallows this exception. Run without prpared to see it.
18
+ coerce_tests! :test_validate_uniqueness_with_limit_and_utf8
19
+ def test_validate_uniqueness_with_limit_and_utf8_coerced
20
+ connection.unprepared_statement do
21
+ assert_raise(ActiveRecord::ValueTooLong) do
22
+ Event.create(title: "一二三四五六七八")
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+
30
+
31
+ require 'models/event'
32
+ module ActiveRecord
33
+ class AdapterTest < ActiveRecord::TestCase
34
+ # As far as I can tell, SQL Server does not support null bytes in strings.
35
+ coerce_tests! :test_update_prepared_statement
36
+ coerce_tests! :test_log_invalid_encoding if defined? JRUBY_VERSION # JRuby just happily converts the encoding
37
+
38
+ # So sp_executesql swallows this exception. Run without prpared to see it.
39
+ coerce_tests! :test_value_limit_violations_are_translated_to_specific_exception
40
+ def test_value_limit_violations_are_translated_to_specific_exception_coerced
41
+ connection.unprepared_statement do
42
+ error = assert_raises(ActiveRecord::ValueTooLong) do
43
+ Event.create(title: 'abcdefgh')
44
+ end
45
+ assert_not_nil error.cause
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+
53
+
54
+ require 'models/topic'
55
+ class AttributeMethodsTest < ActiveRecord::TestCase
56
+ coerce_tests! :test_typecast_attribute_from_select_to_false
57
+ def test_typecast_attribute_from_select_to_false_coerced
58
+ Topic.create(:title => 'Budget')
59
+ topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 2, 1, 0) as is_test").first
60
+ assert !topic.is_test?
61
+ end
62
+
63
+ coerce_tests! :test_typecast_attribute_from_select_to_true
64
+ def test_typecast_attribute_from_select_to_true_coerced
65
+ Topic.create(:title => 'Budget')
66
+ topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 1, 1, 0) as is_test").first
67
+ assert topic.is_test?
68
+ end
69
+ end
70
+
71
+
72
+
73
+
74
+ class BasicsTest < ActiveRecord::TestCase
75
+ coerce_tests! :test_column_names_are_escaped
76
+ def test_column_names_are_escaped_coerced
77
+ conn = ActiveRecord::Base.connection
78
+ assert_equal '[t]]]', conn.quote_column_name('t]')
79
+ end
80
+
81
+ # We do not have do the DecimalWithoutScale type.
82
+ coerce_tests! :test_numeric_fields
83
+ coerce_tests! :test_numeric_fields_with_scale
84
+
85
+ # Just like PostgreSQLAdapter does.
86
+ coerce_tests! :test_respect_internal_encoding
87
+
88
+ # Caused in Rails v4.2.5 by adding `firm_id` column in this http://git.io/vBfMs
89
+ # commit. Trust Rails has this covered.
90
+ coerce_tests! :test_find_keeps_multiple_group_values
91
+ end
92
+
93
+
94
+
95
+
96
+ class BelongsToAssociationsTest < ActiveRecord::TestCase
97
+ # Since @client.firm is a single first/top, and we use FETCH the order clause is used.
98
+ coerce_tests! :test_belongs_to_does_not_use_order_by
99
+
100
+ coerce_tests! :test_belongs_to_with_primary_key_joins_on_correct_column
101
+ def test_belongs_to_with_primary_key_joins_on_correct_column_coerced
102
+ sql = Client.joins(:firm_with_primary_key).to_sql
103
+ assert_no_match(/\[firm_with_primary_keys_companies\]\.\[id\]/, sql)
104
+ assert_match(/\[firm_with_primary_keys_companies\]\.\[name\]/, sql)
105
+ end
106
+ end
107
+
108
+
109
+
110
+
111
+ module ActiveRecord
112
+ class BindParameterTest < ActiveRecord::TestCase
113
+ # Never finds `sql` since we use `EXEC sp_executesql` wrappers.
114
+ coerce_tests! :test_binds_are_logged
115
+ end
116
+ end
117
+
118
+
119
+
120
+
121
+ class CalculationsTest < ActiveRecord::TestCase
122
+ # Are decimal, not integer.
123
+ coerce_tests! :test_should_return_decimal_average_of_integer_field
124
+ def test_should_return_decimal_average_of_integer_field_coerced
125
+ value = Account.average(:id)
126
+ assert_equal BigDecimal('3.0').to_s, BigDecimal(value).to_s
127
+ end
128
+
129
+ coerce_tests! :test_limit_is_kept
130
+ def test_limit_is_kept_coerced
131
+ queries = capture_sql_ss { Account.limit(1).count }
132
+ assert_equal 1, queries.length
133
+ queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1}
134
+ end unless defined? JRUBY_VERSION
135
+
136
+ def test_limit_is_kept_coerced
137
+ queries = capture_sql_ss { Account.limit(1).count }
138
+ assert_equal 1, queries.length
139
+ queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT \? ROWS ONLY}
140
+ end if defined? JRUBY_VERSION
141
+
142
+ coerce_tests! :test_limit_with_offset_is_kept
143
+ def test_limit_with_offset_is_kept_coerced
144
+ queries = capture_sql_ss { Account.limit(1).offset(1).count }
145
+ assert_equal 1, queries.length
146
+ queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY.*@0 = 1, @1 = 1}
147
+ end unless defined? JRUBY_VERSION
148
+
149
+ def test_limit_with_offset_is_kept_coerced
150
+ queries = capture_sql_ss { Account.limit(1).offset(1).count }
151
+ assert_equal 1, queries.length
152
+ queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET \? ROWS FETCH NEXT \? ROWS ONLY}
153
+ end if defined? JRUBY_VERSION
154
+
155
+ # Leave it up to users to format selects/functions so HAVING works correctly.
156
+ coerce_tests! :test_having_with_strong_parameters
157
+ end
158
+
159
+
160
+
161
+ module ActiveRecord
162
+ class Migration
163
+ class ChangeSchemaTest < ActiveRecord::TestCase
164
+ # We test these.
165
+ coerce_tests! :test_create_table_with_bigint,
166
+ :test_create_table_with_defaults
167
+ end
168
+ class ChangeSchemaWithDependentObjectsTest < ActiveRecord::TestCase
169
+ # In SQL Server you have to delete the tables yourself in the right order.
170
+ coerce_tests! :test_create_table_with_force_cascade_drops_dependent_objects
171
+ end
172
+ end
173
+ end
174
+
175
+
176
+
177
+
178
+ module ActiveRecord
179
+ class Migration
180
+ class ColumnAttributesTest < ActiveRecord::TestCase
181
+ # We have a default 4000 varying character limit.
182
+ coerce_tests! :test_add_column_without_limit
183
+ def test_add_column_without_limit_coerced
184
+ add_column :test_models, :description, :string, limit: nil
185
+ TestModel.reset_column_information
186
+ TestModel.columns_hash["description"].limit.must_equal 4000
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+
193
+
194
+
195
+ module ActiveRecord
196
+ class Migration
197
+ class ColumnsTest
198
+ # Our defaults are real 70000 integers vs '70000' strings.
199
+ coerce_tests! :test_rename_column_preserves_default_value_not_null
200
+ def test_rename_column_preserves_default_value_not_null_coerced
201
+ add_column 'test_models', 'salary', :integer, :default => 70000
202
+ default_before = connection.columns("test_models").find { |c| c.name == "salary" }.default
203
+ assert_equal 70000, default_before
204
+ rename_column "test_models", "salary", "annual_salary"
205
+ TestModel.reset_column_information
206
+ assert TestModel.column_names.include?("annual_salary")
207
+ default_after = connection.columns("test_models").find { |c| c.name == "annual_salary" }.default
208
+ assert_equal 70000, default_after
209
+ end
210
+
211
+ # Dropping the column removes the single index.
212
+ coerce_tests! :test_remove_column_with_multi_column_index
213
+ def test_remove_column_with_multi_column_index_coerced
214
+ add_column "test_models", :hat_size, :integer
215
+ add_column "test_models", :hat_style, :string, :limit => 100
216
+ add_index "test_models", ["hat_style", "hat_size"], :unique => true
217
+ assert_equal 1, connection.indexes('test_models').size
218
+ remove_column("test_models", "hat_size")
219
+ assert_equal [], connection.indexes('test_models').map(&:name)
220
+ end
221
+
222
+ # Choose `StatementInvalid` vs `ActiveRecordError`.
223
+ coerce_tests! :test_rename_nonexistent_column
224
+ def test_rename_nonexistent_column_coerced
225
+ exception = ActiveRecord::StatementInvalid
226
+ assert_raise(exception) do
227
+ rename_column "test_models", "nonexistent", "should_fail"
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+
235
+
236
+
237
+ class MigrationTest < ActiveRecord::TestCase
238
+ # We do not have do the DecimalWithoutScale type.
239
+ coerce_tests! :test_add_table_with_decimals
240
+ def test_add_table_with_decimals_coerced
241
+ Person.connection.drop_table :big_numbers rescue nil
242
+ assert !BigNumber.table_exists?
243
+ GiveMeBigNumbers.up
244
+ BigNumber.reset_column_information
245
+ assert BigNumber.create(
246
+ :bank_balance => 1586.43,
247
+ :big_bank_balance => BigDecimal("1000234000567.95"),
248
+ :world_population => 6000000000,
249
+ :my_house_population => 3,
250
+ :value_of_e => BigDecimal("2.7182818284590452353602875")
251
+ )
252
+ b = BigNumber.first
253
+ assert_not_nil b
254
+ assert_not_nil b.bank_balance
255
+ assert_not_nil b.big_bank_balance
256
+ assert_not_nil b.world_population
257
+ assert_not_nil b.my_house_population
258
+ assert_not_nil b.value_of_e
259
+ assert_kind_of BigDecimal, b.world_population
260
+ assert_equal '6000000000.0', b.world_population.to_s
261
+ assert_kind_of Integer, b.my_house_population
262
+ assert_equal 3, b.my_house_population
263
+ assert_kind_of BigDecimal, b.bank_balance
264
+ assert_equal BigDecimal("1586.43"), b.bank_balance
265
+ assert_kind_of BigDecimal, b.big_bank_balance
266
+ assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
267
+ GiveMeBigNumbers.down
268
+ assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first }
269
+ end
270
+
271
+ # For some reason our tests set Rails.@_env which breaks test env switching.
272
+ coerce_tests! :test_migration_sets_internal_metadata_even_when_fully_migrated
273
+ coerce_tests! :test_internal_metadata_stores_environment
274
+ end
275
+
276
+
277
+
278
+
279
+ class CoreTest < ActiveRecord::TestCase
280
+ # I think fixtures are useing the wrong time zone and the `:first`
281
+ # `topics`.`bonus_time` attribute of 2005-01-30t15:28:00.00+01:00 is
282
+ # getting local EST time for me and set to "09:28:00.0000000".
283
+ coerce_tests! :test_pretty_print_persisted
284
+ end
285
+
286
+
287
+
288
+
289
+ module ActiveRecord
290
+ module ConnectionAdapters
291
+ # Just like PostgreSQLAdapter does.
292
+ TypeLookupTest.coerce_all_tests! if defined?(TypeLookupTest)
293
+
294
+ # All sorts of errors due to how we test. Even setting ENV['RAILS_ENV'] to
295
+ # a value of 'default_env' will still show tests failing. Just ignoring all
296
+ # of them since we have no monkey in this circus.
297
+ MergeAndResolveDefaultUrlConfigTest.coerce_all_tests! if defined?(MergeAndResolveDefaultUrlConfigTest)
298
+ end
299
+ end
300
+
301
+
302
+
303
+
304
+ module ActiveRecord
305
+ class DatabaseTasksCreateAllTest < ActiveRecord::TestCase
306
+ # We extend `local_database?` so that common VM IPs can be used.
307
+ coerce_tests! :test_ignores_remote_databases, :test_warning_for_remote_databases
308
+ end
309
+ class DatabaseTasksDropAllTest < ActiveRecord::TestCase
310
+ # We extend `local_database?` so that common VM IPs can be used.
311
+ coerce_tests! :test_ignores_remote_databases, :test_warning_for_remote_databases
312
+ end
313
+ end
314
+
315
+
316
+
317
+
318
+ class DefaultScopingTest < ActiveRecord::TestCase
319
+ # We are not doing order duplicate removal anymore.
320
+ coerce_tests! :test_order_in_default_scope_should_not_prevail
321
+
322
+ # Use our escaped format in assertion.
323
+ coerce_tests! :test_with_abstract_class_scope_should_be_executed_in_correct_context
324
+ def test_with_abstract_class_scope_should_be_executed_in_correct_context_coerced
325
+ vegetarian_pattern, gender_pattern = [/[lions].[is_vegetarian]/, /[lions].[gender]/]
326
+ assert_match vegetarian_pattern, Lion.all.to_sql
327
+ assert_match gender_pattern, Lion.female.to_sql
328
+ end
329
+ end
330
+
331
+
332
+
333
+
334
+ require 'models/post'
335
+ require 'models/subscriber'
336
+ class EachTest < ActiveRecord::TestCase
337
+ # Quoting in tests does not cope with bracket quoting.
338
+ coerce_tests! :test_find_in_batches_should_quote_batch_order
339
+ def test_find_in_batches_should_quote_batch_order_coerced
340
+ c = Post.connection
341
+ assert_sql(/ORDER BY \[posts\]\.\[id\]/) do
342
+ Post.find_in_batches(:batch_size => 1) do |batch|
343
+ assert_kind_of Array, batch
344
+ assert_kind_of Post, batch.first
345
+ end
346
+ end
347
+ end
348
+
349
+ # Quoting in tests does not cope with bracket quoting.
350
+ coerce_tests! :test_in_batches_should_quote_batch_order
351
+ def test_in_batches_should_quote_batch_order_coerced
352
+ c = Post.connection
353
+ assert_sql(/ORDER BY \[posts\]\.\[id\]/) do
354
+ Post.in_batches(of: 1) do |relation|
355
+ assert_kind_of ActiveRecord::Relation, relation
356
+ assert_kind_of Post, relation.first
357
+ end
358
+ end
359
+ end
360
+ end
361
+
362
+
363
+
364
+
365
+ class EagerAssociationTest < ActiveRecord::TestCase
366
+ # Use LEN() vs length() function.
367
+ coerce_tests! :test_count_with_include
368
+ def test_count_with_include_coerced
369
+ assert_equal 3, authors(:david).posts_with_comments.where("LEN(comments.body) > 15").references(:comments).count
370
+ end
371
+
372
+ # Use TOP (1) in scope vs limit 1.
373
+ coerce_tests! %r{including association based on sql condition and no database column}
374
+ end
375
+
376
+
377
+
378
+
379
+ require 'models/topic'
380
+ class FinderTest < ActiveRecord::TestCase
381
+ coerce_tests! %r{doesn't have implicit ordering},
382
+ :test_find_doesnt_have_implicit_ordering # We have implicit ordering, via FETCH.
383
+
384
+ coerce_tests! :test_exists_does_not_select_columns_without_alias
385
+ def test_exists_does_not_select_columns_without_alias_coerced
386
+ assert_sql(/SELECT\s+1 AS one FROM \[topics\].*OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/i) do
387
+ Topic.exists?
388
+ end
389
+ end unless defined? JRUBY_VERSION
390
+
391
+ def test_exists_does_not_select_columns_without_alias_coerced
392
+ # Unfortunately the best we can do is check for ? with prepared statements on
393
+ assert_sql(/SELECT\s+1 AS one FROM \[topics\].*OFFSET 0 ROWS FETCH NEXT \? ROWS ONLY/i) do
394
+ Topic.exists?
395
+ end
396
+ end if defined? JRUBY_VERSION
397
+
398
+ coerce_tests! :test_string_sanitation
399
+ def test_string_sanitation_coerced
400
+ assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
401
+ assert_equal "N'something; select table'", ActiveRecord::Base.sanitize("something; select table")
402
+ end
403
+
404
+ coerce_tests! :test_take_and_first_and_last_with_integer_should_use_sql_limit
405
+ def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
406
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 3/) { Topic.take(3).entries }
407
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 2/) { Topic.first(2).entries }
408
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 5/) { Topic.last(5).entries }
409
+ end unless defined? JRUBY_VERSION
410
+
411
+ def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
412
+ # Unfortunately the best we can do is check for ? with prepared statements on
413
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT \? ROWS ONLY/) { Topic.take(3).entries }
414
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT \? ROWS ONLY/) { Topic.first(2).entries }
415
+ assert_sql(/OFFSET 0 ROWS FETCH NEXT \? ROWS ONLY/) { Topic.last(5).entries }
416
+ end if defined? JRUBY_VERSION
417
+
418
+ # This fails only when run in the full test suite task. Just taking it out of the mix.
419
+ coerce_tests! :test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
420
+
421
+ # Can not use array condition due to not finding right type and hence fractional second quoting.
422
+ coerce_tests! :test_condition_utc_time_interpolation_with_default_timezone_local
423
+ def test_condition_utc_time_interpolation_with_default_timezone_local_coerced
424
+ with_env_tz 'America/New_York' do
425
+ with_timezone_config default: :local do
426
+ topic = Topic.first
427
+ assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
428
+ end
429
+ end
430
+ end
431
+
432
+ # Can not use array condition due to not finding right type and hence fractional second quoting.
433
+ coerce_tests! :test_condition_local_time_interpolation_with_default_timezone_utc
434
+ def test_condition_local_time_interpolation_with_default_timezone_utc_coerced
435
+ with_env_tz 'America/New_York' do
436
+ with_timezone_config default: :utc do
437
+ topic = Topic.first
438
+ assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
439
+ end
440
+ end
441
+ end
442
+ end
443
+
444
+
445
+
446
+
447
+ module ActiveRecord
448
+ class Migration
449
+ class ForeignKeyTest < ActiveRecord::TestCase
450
+ # We do not support :restrict.
451
+ coerce_tests! :test_add_on_delete_restrict_foreign_key
452
+ def test_add_on_delete_restrict_foreign_key_coerced
453
+ assert_raises ArgumentError do
454
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :restrict
455
+ end
456
+ assert_raises ArgumentError do
457
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :restrict
458
+ end
459
+ end
460
+ end
461
+ end
462
+ end
463
+
464
+
465
+
466
+
467
+ class HasOneAssociationsTest < ActiveRecord::TestCase
468
+ # We use OFFSET/FETCH vs TOP. So we always have an order.
469
+ coerce_tests! :test_has_one_does_not_use_order_by
470
+ end
471
+
472
+
473
+
474
+
475
+ require 'models/company'
476
+ class InheritanceTest < ActiveRecord::TestCase
477
+ coerce_tests! :test_a_bad_type_column
478
+ def test_a_bad_type_column_coerced
479
+ Company.connection.with_identity_insert_enabled('companies') do
480
+ Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
481
+ end
482
+ assert_raise(ActiveRecord::SubclassNotFound) { Company.find(100) }
483
+ end
484
+
485
+ coerce_tests! :test_eager_load_belongs_to_primary_key_quoting
486
+ def test_eager_load_belongs_to_primary_key_quoting_coerced
487
+ con = Account.connection
488
+ assert_sql(/\[companies\]\.\[id\] = 1/) do
489
+ Account.all.merge!(:includes => :firm).find(1)
490
+ end
491
+ end
492
+ end
493
+
494
+
495
+
496
+
497
+ class LeftOuterJoinAssociationTest < ActiveRecord::TestCase
498
+ # Uses || operator in SQL. Just trust core gets value out of this test.
499
+ coerce_tests! :test_does_not_override_select
500
+ end
501
+
502
+
503
+
504
+
505
+ class NamedScopingTest < ActiveRecord::TestCase
506
+ # This works now because we add an `order(:id)` sort to break the order tie for deterministic results.
507
+ coerce_tests! :test_scopes_honor_current_scopes_from_when_defined
508
+ def test_scopes_honor_current_scopes_from_when_defined_coerced
509
+ assert !Post.ranked_by_comments.order(:id).limit_by(5).empty?
510
+ assert !authors(:david).posts.ranked_by_comments.order(:id).limit_by(5).empty?
511
+ assert_not_equal Post.ranked_by_comments.order(:id).limit_by(5), authors(:david).posts.ranked_by_comments.order(:id).limit_by(5)
512
+ assert_not_equal Post.order(:id).top(5), authors(:david).posts.order(:id).top(5)
513
+ # Oracle sometimes sorts differently if WHERE condition is changed
514
+ assert_equal authors(:david).posts.ranked_by_comments.limit_by(5).to_a.sort_by(&:id), authors(:david).posts.top(5).to_a.sort_by(&:id)
515
+ assert_equal Post.ranked_by_comments.limit_by(5), Post.top(5)
516
+ end
517
+ end
518
+
519
+
520
+
521
+
522
+ require 'models/developer'
523
+ require 'models/computer'
524
+ class NestedRelationScopingTest < ActiveRecord::TestCase
525
+ coerce_tests! :test_merge_options
526
+ def test_merge_options_coerced
527
+ Developer.where('salary = 80000').scoping do
528
+ Developer.limit(10).scoping do
529
+ devs = Developer.all
530
+ sql = devs.to_sql
531
+ assert_match '(salary = 80000)', sql
532
+ assert_match 'FETCH NEXT 10 ROWS ONLY', sql
533
+ end
534
+ end
535
+ end
536
+ end
537
+
538
+
539
+
540
+
541
+ require 'models/topic'
542
+ class PersistenceTest < ActiveRecord::TestCase
543
+ # We can not UPDATE identity columns.
544
+ coerce_tests! :test_update_columns_changing_id
545
+
546
+ # Previous test required updating a identity column.
547
+ coerce_tests! :test_update_all_doesnt_ignore_order
548
+ def test_update_all_doesnt_ignore_order_coerced
549
+ david, mary = authors(:david), authors(:mary)
550
+ david.id.must_equal 1
551
+ mary.id.must_equal 2
552
+ david.name.wont_equal mary.name
553
+ assert_sql(/UPDATE.*\(SELECT \[authors\].\[id\] FROM \[authors\].*ORDER BY \[authors\].\[id\]/i) do
554
+ Author.where('[id] > 1').order(:id).update_all(name: 'Test')
555
+ end
556
+ david.reload.name.must_equal 'David'
557
+ mary.reload.name.must_equal 'Test'
558
+ end
559
+
560
+ # We can not UPDATE identity columns.
561
+ coerce_tests! :test_update_attributes
562
+ def test_update_attributes_coerced
563
+ topic = Topic.find(1)
564
+ assert !topic.approved?
565
+ assert_equal "The First Topic", topic.title
566
+ topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
567
+ topic.reload
568
+ assert topic.approved?
569
+ assert_equal "The First Topic Updated", topic.title
570
+ topic.update_attributes(approved: false, title: "The First Topic")
571
+ topic.reload
572
+ assert !topic.approved?
573
+ assert_equal "The First Topic", topic.title
574
+ # SQLServer: Here is where it breaks down. No exceptions.
575
+ # assert_raise(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid) do
576
+ # topic.update_attributes(id: 3, title: "Hm is it possible?")
577
+ # end
578
+ # assert_not_equal "Hm is it possible?", Topic.find(3).title
579
+ # topic.update_attributes(id: 1234)
580
+ # assert_nothing_raised { topic.reload }
581
+ # assert_equal topic.title, Topic.find(1234).title
582
+ end
583
+ end
584
+
585
+
586
+
587
+
588
+ require 'models/topic'
589
+ module ActiveRecord
590
+ class PredicateBuilderTest < ActiveRecord::TestCase
591
+ coerce_tests! :test_registering_new_handlers
592
+ def test_registering_new_handlers_coerced
593
+ Topic.predicate_builder.register_handler(Regexp, proc do |column, value|
594
+ Arel::Nodes::InfixOperation.new('~', column, Arel.sql(value.source))
595
+ end)
596
+ assert_match %r{\[topics\].\[title\] ~ rails}i, Topic.where(title: /rails/).to_sql
597
+ ensure
598
+ Topic.reset_column_information
599
+ end
600
+ end
601
+ end
602
+
603
+
604
+
605
+
606
+ require 'models/task'
607
+ class QueryCacheTest < ActiveRecord::TestCase
608
+ coerce_tests! :test_cache_does_not_wrap_string_results_in_arrays
609
+ def test_cache_does_not_wrap_string_results_in_arrays_coerced
610
+ Task.cache do
611
+ assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
612
+ end
613
+ end
614
+ end
615
+
616
+
617
+
618
+
619
+ require 'models/post'
620
+ class RelationTest < ActiveRecord::TestCase
621
+ # Use LEN vs LENGTH function.
622
+ coerce_tests! :test_reverse_order_with_function
623
+ def test_reverse_order_with_function_coerced
624
+ topics = Topic.order("LEN(title)").reverse_order
625
+ assert_equal topics(:second).title, topics.first.title
626
+ end
627
+
628
+ # Use LEN vs LENGTH function.
629
+ coerce_tests! :test_reverse_order_with_function_other_predicates
630
+ def test_reverse_order_with_function_other_predicates_coerced
631
+ topics = Topic.order("author_name, LEN(title), id").reverse_order
632
+ assert_equal topics(:second).title, topics.first.title
633
+ topics = Topic.order("LEN(author_name), id, LEN(title)").reverse_order
634
+ assert_equal topics(:fifth).title, topics.first.title
635
+ end
636
+
637
+ # We have implicit ordering, via FETCH.
638
+ coerce_tests! %r{doesn't have implicit ordering}
639
+
640
+ # We are not doing order duplicate removal anymore.
641
+ coerce_tests! :test_order_using_scoping
642
+
643
+ # We are not doing order duplicate removal anymore.
644
+ coerce_tests! :test_default_scope_order_with_scope_order
645
+
646
+ # Leave it up to users to format selects/functions so HAVING works correctly.
647
+ coerce_tests! :test_multiple_where_and_having_clauses
648
+ coerce_tests! :test_having_with_binds_for_both_where_and_having
649
+ end
650
+
651
+
652
+
653
+
654
+ require 'models/post'
655
+ class SanitizeTest < ActiveRecord::TestCase
656
+ coerce_tests! :test_sanitize_sql_like_example_use_case
657
+ def test_sanitize_sql_like_example_use_case_coerced
658
+ searchable_post = Class.new(Post) do
659
+ def self.search(term)
660
+ where("title LIKE ?", sanitize_sql_like(term, '!'))
661
+ end
662
+ end
663
+ assert_sql(/\(title LIKE N'20!% !_reduction!_!!'\)/) do
664
+ searchable_post.search("20% _reduction_!").to_a
665
+ end
666
+ end
667
+ end
668
+
669
+
670
+
671
+
672
+ class SchemaDumperTest < ActiveRecord::TestCase
673
+ # We have precision to 38.
674
+ coerce_tests! :test_schema_dump_keeps_large_precision_integer_columns_as_decimal
675
+ def test_schema_dump_keeps_large_precision_integer_columns_as_decimal_coerced
676
+ output = standard_dump
677
+ assert_match %r{t.decimal\s+"atoms_in_universe",\s+precision: 38}, output
678
+ end
679
+
680
+ # This accidently returns the wrong number because of our tables too.
681
+ coerce_tests! :test_types_line_up
682
+
683
+ # This is a poorly written test and really does not catch the bottom'ness it is meant too. Ours throw it off.
684
+ coerce_tests! :test_foreign_keys_are_dumped_at_the_bottom_to_circumvent_dependency_issues
685
+
686
+ # Fall through false positive with no filter.
687
+ coerce_tests! :test_schema_dumps_partial_indices
688
+ def test_schema_dumps_partial_indices_coerced
689
+ index_definition = standard_dump.split(/\n/).grep(/t.index.*company_partial_index/).first.strip
690
+ assert_equal 't.index ["firm_id", "type"], name: "company_partial_index", where: "([rating]>(10))"', index_definition
691
+ end
692
+
693
+ # We do not quote the 2.78 string default.
694
+ coerce_tests! :test_schema_dump_includes_decimal_options
695
+ def test_schema_dump_includes_decimal_options_coerced
696
+ output = dump_all_table_schema([/^[^n]/])
697
+ assert_match %r{precision: 3,[[:space:]]+scale: 2,[[:space:]]+default: 2\.78}, output
698
+ end
699
+ end
700
+
701
+ class SchemaDumperDefaultsTest < ActiveRecord::TestCase
702
+ # These date formats do not match ours. We got these covered in our dumper tests.
703
+ coerce_tests! :test_schema_dump_defaults_with_universally_supported_types
704
+ end
705
+
706
+
707
+
708
+
709
+ class TestAdapterWithInvalidConnection < ActiveRecord::TestCase
710
+ # We trust Rails on this since we do not want to install mysql.
711
+ coerce_tests! %r{inspect on Model class does not raise}
712
+ end
713
+
714
+
715
+
716
+
717
+ require 'models/topic'
718
+ class TransactionTest < ActiveRecord::TestCase
719
+ coerce_tests! :test_releasing_named_savepoints
720
+ def test_releasing_named_savepoints_coerced
721
+ Topic.transaction do
722
+ Topic.connection.create_savepoint("another")
723
+ Topic.connection.release_savepoint("another")
724
+ # We do not have a notion of releasing, so this does nothing vs raise an error.
725
+ Topic.connection.release_savepoint("another")
726
+ end
727
+ end
728
+ end unless defined? JRUBY_VERSION # The rails version of this test passes
729
+
730
+
731
+
732
+
733
+ require 'models/tag'
734
+ class TransactionIsolationTest < ActiveRecord::TestCase
735
+ # SQL Server will lock the table for counts even when both
736
+ # connections are `READ COMMITTED`. So we bypass with `READPAST`.
737
+ coerce_tests! %r{read committed}
738
+ test "read committed coerced" do
739
+ Tag.transaction(isolation: :read_committed) do
740
+ assert_equal 0, Tag.count
741
+ Tag2.transaction do
742
+ Tag2.create
743
+ assert_equal 0, Tag.lock('WITH(READPAST)').count
744
+ end
745
+ end
746
+ assert_equal 1, Tag.count
747
+ end
748
+
749
+ # I really need some help understanding this one.
750
+ coerce_tests! %r{repeatable read}
751
+ end
752
+
753
+
754
+
755
+
756
+ require 'models/book'
757
+ class ViewWithPrimaryKeyTest < ActiveRecord::TestCase
758
+ # We have a few view tables. use includes vs equality.
759
+ coerce_tests! :test_views
760
+ def test_views_coerced
761
+ assert_includes @connection.views, Ebook.table_name
762
+ end
763
+
764
+ # We do better than ActiveRecord and find the views PK.
765
+ coerce_tests! :test_does_not_assume_id_column_as_primary_key
766
+ def test_does_not_assume_id_column_as_primary_key_coerced
767
+ model = Class.new(ActiveRecord::Base) { self.table_name = "ebooks" }
768
+ assert_equal 'id', model.primary_key
769
+ end
770
+ end
771
+ class ViewWithoutPrimaryKeyTest < ActiveRecord::TestCase
772
+ # We have a few view tables. use includes vs equality.
773
+ coerce_tests! :test_views
774
+ def test_views_coerced
775
+ assert_includes @connection.views, Paperback.table_name
776
+ end
777
+ end
778
+
779
+
780
+
781
+
782
+ require 'models/author'
783
+ class YamlSerializationTest < ActiveRecord::TestCase
784
+ coerce_tests! :test_types_of_virtual_columns_are_not_changed_on_round_trip
785
+ def test_types_of_virtual_columns_are_not_changed_on_round_trip_coerced
786
+ author = Author.select('authors.*, 5 as posts_count').first
787
+ dumped = YAML.load(YAML.dump(author))
788
+ assert_equal 5, author.posts_count
789
+ assert_equal 5, dumped.posts_count
790
+ end
791
+ end
792
+
793
+
794
+
795
+
796
+ class DateTimePrecisionTest < ActiveRecord::TestCase
797
+ # Original test had `7` which we support vs `8` which we use.
798
+ coerce_tests! :test_invalid_datetime_precision_raises_error
799
+ def test_invalid_datetime_precision_raises_error_coerced
800
+ assert_raises ActiveRecord::ActiveRecordError do
801
+ @connection.create_table(:foos, force: true) do |t|
802
+ t.timestamps precision: 8
803
+ end
804
+ end
805
+ end
806
+ end
807
+
808
+
809
+
810
+
811
+ class DefaultNumbersTest < ActiveRecord::TestCase
812
+ # We do better with native types and do not return strings for everything.
813
+ coerce_tests! :test_default_positive_integer
814
+ def test_default_positive_integer_coerced
815
+ record = DefaultNumber.new
816
+ assert_equal 7, record.positive_integer
817
+ assert_equal 7, record.positive_integer_before_type_cast
818
+ end
819
+ coerce_tests! :test_default_negative_integer
820
+ def test_default_negative_integer_coerced
821
+ record = DefaultNumber.new
822
+ assert_equal -5, record.negative_integer
823
+ assert_equal -5, record.negative_integer_before_type_cast
824
+ end
825
+ end
826
+
827
+
828
+
829
+
830
+ module ActiveRecord
831
+ class CollectionCacheKeyTest < ActiveRecord::TestCase
832
+ # Will trust rails has this sorted since you cant offset without a limit.
833
+ coerce_tests! %r{with offset which return 0 rows}
834
+ end
835
+ end
836
+
837
+
838
+
839
+
840
+ module ActiveRecord
841
+ class StatementCacheTest < ActiveRecord::TestCase
842
+ # Getting random failures.
843
+ #coerce_tests! :test_find_does_not_use_statement_cache_if_table_name_is_changed
844
+ end
845
+ end