activerecord-jdbcsqlserver-adapter 50.0.0 → 52.0.0
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.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.travis.yml +4 -5
- data/CHANGELOG.md +22 -101
- data/{Dockerfile → Dockerfile.ci} +0 -0
- data/Gemfile +1 -3
- data/README.md +5 -9
- data/VERSION +1 -1
- data/activerecord-jdbcsqlserver-adapter.gemspec +2 -2
- data/appveyor.yml +1 -1
- data/docker-compose.ci.yml +7 -5
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +51 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +18 -20
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +5 -3
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +43 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +26 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +13 -2
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +94 -28
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver/jdbc_overrides.rb +5 -25
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +24 -1
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +23 -2
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +110 -74
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +15 -7
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +3 -4
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +5 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +3 -6
- data/lib/active_record/connection_adapters/sqlserver/type/json.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +7 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +47 -24
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +5 -3
- data/lib/activerecord-jdbcsqlserver-adapter.rb +4 -1
- data/lib/arel/visitors/sqlserver.rb +17 -4
- data/lib/arel_sqlserver.rb +0 -1
- data/lib/jdbc_mssql_driver_loader.rb +22 -0
- data/test/bin/install-freetds.sh +18 -0
- data/test/bin/setup.sh +19 -0
- data/test/cases/adapter_test_sqlserver.rb +43 -39
- data/test/cases/change_column_null_test_sqlserver.rb +42 -0
- data/test/cases/coerced_tests.rb +419 -39
- data/test/cases/column_test_sqlserver.rb +496 -462
- data/test/cases/connection_test_sqlserver.rb +2 -2
- data/test/cases/fetch_test_sqlserver.rb +5 -5
- data/test/cases/helper_sqlserver.rb +12 -1
- data/test/cases/json_test_sqlserver.rb +6 -6
- data/test/cases/migration_test_sqlserver.rb +13 -3
- data/test/cases/order_test_sqlserver.rb +19 -19
- data/test/cases/pessimistic_locking_test_sqlserver.rb +37 -20
- data/test/cases/rake_test_sqlserver.rb +20 -20
- data/test/cases/schema_dumper_test_sqlserver.rb +44 -43
- data/test/cases/schema_test_sqlserver.rb +2 -2
- data/test/cases/showplan_test_sqlserver.rb +25 -10
- data/test/cases/specific_schema_test_sqlserver.rb +11 -17
- data/test/cases/transaction_test_sqlserver.rb +9 -9
- data/test/cases/trigger_test_sqlserver.rb +31 -0
- data/test/cases/utils_test_sqlserver.rb +36 -36
- data/test/cases/uuid_test_sqlserver.rb +8 -8
- data/test/config.yml +2 -2
- data/test/migrations/create_clients_and_change_column_null.rb +23 -0
- data/test/models/sqlserver/trigger.rb +7 -0
- data/test/models/sqlserver/trigger_history.rb +3 -0
- data/test/schema/datatypes/2012.sql +1 -0
- data/test/schema/sqlserver_specific_schema.rb +47 -5
- data/test/support/core_ext/query_cache.rb +29 -0
- data/test/support/sql_counter_sqlserver.rb +1 -1
- metadata +32 -15
- data/RAILS5-TODO.md +0 -5
- data/test/models/sqlserver/dot_table_name.rb +0 -3
data/test/bin/setup.sh
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -x
|
4
|
+
set -e
|
5
|
+
|
6
|
+
tag=2017-GA
|
7
|
+
|
8
|
+
docker pull metaskills/mssql-server-linux-rails:$tag
|
9
|
+
|
10
|
+
container=$(docker ps -a -q --filter ancestor=metaskills/mssql-server-linux-rails:$tag)
|
11
|
+
if [[ -z $container ]]; then
|
12
|
+
docker run -p 1433:1433 -d metaskills/mssql-server-linux-rails:$tag && sleep 10
|
13
|
+
exit
|
14
|
+
fi
|
15
|
+
|
16
|
+
container=$(docker ps -q --filter ancestor=metaskills/mssql-server-linux-rails:$tag)
|
17
|
+
if [[ -z $container ]]; then
|
18
|
+
docker start $container && sleep 10
|
19
|
+
fi
|
@@ -13,16 +13,17 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
13
13
|
let(:basic_update_sql) { "UPDATE [customers] SET [address_street] = NULL WHERE [id] = 2" }
|
14
14
|
let(:basic_select_sql) { "SELECT * FROM [customers] WHERE ([customers].[id] = 1)" }
|
15
15
|
|
16
|
-
it 'has basic and non-
|
16
|
+
it 'has basic and non-sensitive information in the adapters inspect method' do
|
17
17
|
string = connection.inspect
|
18
|
-
|
19
|
-
string.must_match %r{
|
20
|
-
string.must_match %r{
|
21
|
-
string.must_match %r{
|
22
|
-
string.
|
23
|
-
string.wont_match %r{
|
24
|
-
string.wont_match %r{
|
25
|
-
string.wont_match %r{
|
18
|
+
|
19
|
+
_(string).must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
|
20
|
+
_(string).must_match %r{version\: \d+\.\d}
|
21
|
+
_(string).must_match %r{mode: (dblib|jdbc)}
|
22
|
+
_(string).must_match %r{azure: (true|false)}
|
23
|
+
_(string).wont_match %r{host}
|
24
|
+
_(string).wont_match %r{password}
|
25
|
+
_(string).wont_match %r{username}
|
26
|
+
_(string).wont_match %r{port}
|
26
27
|
end
|
27
28
|
|
28
29
|
it 'has a 128 max #table_alias_length' do
|
@@ -37,10 +38,6 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
37
38
|
assert_equal 'SQLServer', connection.adapter_name
|
38
39
|
end
|
39
40
|
|
40
|
-
it 'supports migrations' do
|
41
|
-
assert connection.supports_migrations?
|
42
|
-
end
|
43
|
-
|
44
41
|
it 'support DDL in transactions' do
|
45
42
|
assert connection.supports_ddl_transactions?
|
46
43
|
end
|
@@ -145,12 +142,12 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
145
142
|
end
|
146
143
|
|
147
144
|
it 'return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column' do
|
148
|
-
assert_equal '
|
149
|
-
assert_equal '
|
150
|
-
assert_equal '
|
151
|
-
assert_equal '
|
152
|
-
assert_equal '
|
153
|
-
assert_equal '
|
145
|
+
assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql)
|
146
|
+
assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted)
|
147
|
+
assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered)
|
148
|
+
assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_sp)
|
149
|
+
assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted_sp)
|
150
|
+
assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered_sp)
|
154
151
|
end
|
155
152
|
|
156
153
|
it 'return false to #query_requires_identity_insert? for normal SQL' do
|
@@ -166,7 +163,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
166
163
|
end
|
167
164
|
|
168
165
|
it 'return an empty array when calling #identity_columns for a table_name with no identity' do
|
169
|
-
connection.send(:identity_columns, Subscriber.table_name).must_equal []
|
166
|
+
_(connection.send(:identity_columns, Subscriber.table_name)).must_equal []
|
170
167
|
end
|
171
168
|
|
172
169
|
end
|
@@ -236,6 +233,11 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
236
233
|
end
|
237
234
|
end
|
238
235
|
|
236
|
+
it 'not disable referential integrity for the same table twice' do
|
237
|
+
tables = SSTestHasPk.connection.tables_with_referential_integrity
|
238
|
+
assert_equal tables.size, tables.uniq.size
|
239
|
+
end
|
240
|
+
|
239
241
|
end
|
240
242
|
|
241
243
|
describe 'database statements' do
|
@@ -266,23 +268,26 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
266
268
|
end
|
267
269
|
|
268
270
|
it 'create integers when limit is 4' do
|
269
|
-
assert_equal 'integer', connection.type_to_sql(:integer, 4)
|
271
|
+
assert_equal 'integer', connection.type_to_sql(:integer, limit: 4)
|
270
272
|
end
|
271
273
|
|
272
274
|
it 'create integers when limit is 3' do
|
273
|
-
assert_equal 'integer', connection.type_to_sql(:integer, 3)
|
275
|
+
assert_equal 'integer', connection.type_to_sql(:integer, limit: 3)
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'create smallints when limit is 2' do
|
279
|
+
assert_equal 'smallint', connection.type_to_sql(:integer, limit: 2)
|
274
280
|
end
|
275
281
|
|
276
|
-
it 'create
|
277
|
-
assert_equal '
|
278
|
-
assert_equal 'smallint', connection.type_to_sql(:integer, 1)
|
282
|
+
it 'create tinyints when limit is 1' do
|
283
|
+
assert_equal 'tinyint', connection.type_to_sql(:integer, limit: 1)
|
279
284
|
end
|
280
285
|
|
281
286
|
it 'create bigints when limit is greateer than 4' do
|
282
|
-
assert_equal 'bigint', connection.type_to_sql(:integer, 5)
|
283
|
-
assert_equal 'bigint', connection.type_to_sql(:integer, 6)
|
284
|
-
assert_equal 'bigint', connection.type_to_sql(:integer, 7)
|
285
|
-
assert_equal 'bigint', connection.type_to_sql(:integer, 8)
|
287
|
+
assert_equal 'bigint', connection.type_to_sql(:integer, limit: 5)
|
288
|
+
assert_equal 'bigint', connection.type_to_sql(:integer, limit: 6)
|
289
|
+
assert_equal 'bigint', connection.type_to_sql(:integer, limit: 7)
|
290
|
+
assert_equal 'bigint', connection.type_to_sql(:integer, limit: 8)
|
286
291
|
end
|
287
292
|
|
288
293
|
it 'create floats when no limit supplied' do
|
@@ -300,7 +305,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
300
305
|
end
|
301
306
|
|
302
307
|
it 'find SSTestCustomersView table name' do
|
303
|
-
connection.views.must_include 'sst_customers_view'
|
308
|
+
_(connection.views).must_include 'sst_customers_view'
|
304
309
|
end
|
305
310
|
|
306
311
|
it 'work with dynamic finders' do
|
@@ -341,9 +346,9 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
341
346
|
end
|
342
347
|
|
343
348
|
it 'find identity column' do
|
344
|
-
SSTestCustomersView.primary_key.must_equal 'id'
|
345
|
-
connection.primary_key(SSTestCustomersView.table_name).must_equal 'id'
|
346
|
-
SSTestCustomersView.columns_hash['id'].must_be :is_identity?
|
349
|
+
_(SSTestCustomersView.primary_key).must_equal 'id'
|
350
|
+
_(connection.primary_key(SSTestCustomersView.table_name)).must_equal 'id'
|
351
|
+
_(SSTestCustomersView.columns_hash['id']).must_be :is_identity?
|
347
352
|
end
|
348
353
|
|
349
354
|
it 'find default values' do
|
@@ -368,9 +373,9 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
368
373
|
end
|
369
374
|
|
370
375
|
it 'find identity column' do
|
371
|
-
SSTestStringDefaultsView.primary_key.must_equal 'id'
|
372
|
-
connection.primary_key(SSTestStringDefaultsView.table_name).must_equal 'id'
|
373
|
-
SSTestStringDefaultsView.columns_hash['id'].must_be :is_identity?
|
376
|
+
_(SSTestStringDefaultsView.primary_key).must_equal 'id'
|
377
|
+
_(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal 'id'
|
378
|
+
_(SSTestStringDefaultsView.columns_hash['id']).must_be :is_identity?
|
374
379
|
end
|
375
380
|
|
376
381
|
it 'find default values' do
|
@@ -419,12 +424,11 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
419
424
|
|
420
425
|
it 'in_memory_oltp' do
|
421
426
|
if ENV['IN_MEMORY_OLTP'] && connection.supports_in_memory_oltp?
|
422
|
-
SSTMemory.primary_key.must_equal 'id'
|
423
|
-
SSTMemory.columns_hash['id'].must_be :is_identity?
|
427
|
+
_(SSTMemory.primary_key).must_equal 'id'
|
428
|
+
_(SSTMemory.columns_hash['id']).must_be :is_identity?
|
424
429
|
else
|
425
430
|
skip 'supports_in_memory_oltp? => false'
|
426
431
|
end
|
427
432
|
end
|
428
433
|
|
429
434
|
end
|
430
|
-
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'cases/helper_sqlserver'
|
2
|
+
require 'migrations/create_clients_and_change_column_null'
|
3
|
+
|
4
|
+
class ChangeColumnNullTestSqlServer < ActiveRecord::TestCase
|
5
|
+
before do
|
6
|
+
@old_verbose = ActiveRecord::Migration.verbose
|
7
|
+
ActiveRecord::Migration.verbose = false
|
8
|
+
CreateClientsAndChangeColumnNull.new.up
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
CreateClientsAndChangeColumnNull.new.down
|
13
|
+
ActiveRecord::Migration.verbose = @old_verbose
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_column(table, name)
|
17
|
+
table.find { |column| column.name == name }
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:clients_table) { connection.columns('clients') }
|
21
|
+
let(:name_column) { find_column(clients_table, 'name') }
|
22
|
+
let(:code_column) { find_column(clients_table, 'code') }
|
23
|
+
let(:value_column) { find_column(clients_table, 'value') }
|
24
|
+
|
25
|
+
describe '#change_column_null' do
|
26
|
+
it 'does not change the column limit' do
|
27
|
+
_(name_column.limit).must_equal 15
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'does not change the column default' do
|
31
|
+
_(code_column.default).must_equal 'n/a'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'does not change the column precision' do
|
35
|
+
_(value_column.precision).must_equal 32
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'does not change the column scale' do
|
39
|
+
_(value_column.scale).must_equal 8
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/test/cases/coerced_tests.rb
CHANGED
@@ -31,6 +31,10 @@ end
|
|
31
31
|
require 'models/event'
|
32
32
|
module ActiveRecord
|
33
33
|
class AdapterTest < ActiveRecord::TestCase
|
34
|
+
# I really dont think we can support legacy binds.
|
35
|
+
coerce_tests! :test_select_all_with_legacy_binds
|
36
|
+
coerce_tests! :test_insert_update_delete_with_legacy_binds
|
37
|
+
|
34
38
|
# As far as I can tell, SQL Server does not support null bytes in strings.
|
35
39
|
coerce_tests! :test_update_prepared_statement
|
36
40
|
coerce_tests! :test_log_invalid_encoding if defined? JRUBY_VERSION # JRuby just happily converts the encoding
|
@@ -53,14 +57,14 @@ end
|
|
53
57
|
|
54
58
|
require 'models/topic'
|
55
59
|
class AttributeMethodsTest < ActiveRecord::TestCase
|
56
|
-
coerce_tests!
|
60
|
+
coerce_tests! %r{typecast attribute from select to false}
|
57
61
|
def test_typecast_attribute_from_select_to_false_coerced
|
58
62
|
Topic.create(:title => 'Budget')
|
59
63
|
topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 2, 1, 0) as is_test").first
|
60
64
|
assert !topic.is_test?
|
61
65
|
end
|
62
66
|
|
63
|
-
coerce_tests!
|
67
|
+
coerce_tests! %r{typecast attribute from select to true}
|
64
68
|
def test_typecast_attribute_from_select_to_true_coerced
|
65
69
|
Topic.create(:title => 'Budget')
|
66
70
|
topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 1, 1, 0) as is_test").first
|
@@ -69,7 +73,11 @@ class AttributeMethodsTest < ActiveRecord::TestCase
|
|
69
73
|
end
|
70
74
|
|
71
75
|
|
72
|
-
|
76
|
+
class NumericDataTest < ActiveRecord::TestCase
|
77
|
+
# We do not have do the DecimalWithoutScale type.
|
78
|
+
coerce_tests! :test_numeric_fields
|
79
|
+
coerce_tests! :test_numeric_fields_with_scale
|
80
|
+
end
|
73
81
|
|
74
82
|
class BasicsTest < ActiveRecord::TestCase
|
75
83
|
coerce_tests! :test_column_names_are_escaped
|
@@ -78,16 +86,44 @@ class BasicsTest < ActiveRecord::TestCase
|
|
78
86
|
assert_equal '[t]]]', conn.quote_column_name('t]')
|
79
87
|
end
|
80
88
|
|
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
89
|
# Just like PostgreSQLAdapter does.
|
86
90
|
coerce_tests! :test_respect_internal_encoding
|
87
91
|
|
88
92
|
# Caused in Rails v4.2.5 by adding `firm_id` column in this http://git.io/vBfMs
|
89
93
|
# commit. Trust Rails has this covered.
|
90
94
|
coerce_tests! :test_find_keeps_multiple_group_values
|
95
|
+
|
96
|
+
def test_update_date_time_attributes
|
97
|
+
Time.use_zone("Eastern Time (US & Canada)") do
|
98
|
+
topic = Topic.find(1)
|
99
|
+
time = Time.zone.parse("2017-07-17 10:56")
|
100
|
+
topic.update_attributes!(written_on: time)
|
101
|
+
assert_equal(time, topic.written_on)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_update_date_time_attributes_with_default_timezone_local
|
106
|
+
with_env_tz 'America/New_York' do
|
107
|
+
with_timezone_config default: :local do
|
108
|
+
Time.use_zone("Eastern Time (US & Canada)") do
|
109
|
+
topic = Topic.find(1)
|
110
|
+
time = Time.zone.parse("2017-07-17 10:56")
|
111
|
+
topic.update_attributes!(written_on: time)
|
112
|
+
assert_equal(time, topic.written_on)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Need to escape `quoted_id` once it contains brackets
|
119
|
+
coerce_tests! %r{column names are quoted when using #from clause and model has ignored columns}
|
120
|
+
test "column names are quoted when using #from clause and model has ignored columns coerced" do
|
121
|
+
refute_empty Developer.ignored_columns
|
122
|
+
query = Developer.from("developers").to_sql
|
123
|
+
quoted_id = "#{Developer.quoted_table_name}.#{Developer.quoted_primary_key}"
|
124
|
+
|
125
|
+
assert_match(/SELECT #{Regexp.escape(quoted_id)}.* FROM developers/, query)
|
126
|
+
end
|
91
127
|
end
|
92
128
|
|
93
129
|
|
@@ -108,17 +144,63 @@ end
|
|
108
144
|
|
109
145
|
|
110
146
|
|
147
|
+
# module ActiveRecord
|
148
|
+
# class BindParameterTest < ActiveRecord::TestCase
|
149
|
+
# # Same as original coerced test except log is found using `EXEC sp_executesql` wrapper.
|
150
|
+
# # coerce_tests! :test_binds_are_logged
|
151
|
+
# # def test_binds_are_logged_coerced
|
152
|
+
# # sub = Arel::Nodes::BindParam.new(1)
|
153
|
+
# # binds = [Relation::QueryAttribute.new("id", 1, Type::Value.new)]
|
154
|
+
# # sql = "select * from topics where id = #{sub.to_sql}"
|
155
|
+
# #
|
156
|
+
# # @connection.exec_query(sql, "SQL", binds)
|
157
|
+
# #
|
158
|
+
# # logged_sql = "EXEC sp_executesql N'#{sql}', N'#{sub.to_sql} int', #{sub.to_sql} = 1"
|
159
|
+
# # message = @subscriber.calls.find { |args| args[4][:sql] == logged_sql }
|
160
|
+
# #
|
161
|
+
# # assert_equal binds, message[4][:binds]
|
162
|
+
# # end
|
163
|
+
# #
|
164
|
+
# # # SQL Server adapter does not use a statement cache as query plans are already reused using `EXEC sp_executesql`.
|
165
|
+
# # coerce_tests! :test_statement_cache
|
166
|
+
# # coerce_tests! :test_statement_cache_with_query_cache
|
167
|
+
# # coerce_tests! :test_statement_cache_with_find_by
|
168
|
+
# # coerce_tests! :test_statement_cache_with_in_clause
|
169
|
+
# # coerce_tests! :test_statement_cache_with_sql_string_literal
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
|
173
|
+
|
111
174
|
module ActiveRecord
|
112
|
-
class
|
113
|
-
#
|
114
|
-
coerce_tests! :
|
175
|
+
class InstrumentationTest < ActiveRecord::TestCase
|
176
|
+
# This fails randomly due to schema cache being lost?
|
177
|
+
coerce_tests! :test_payload_name_on_load
|
178
|
+
def test_payload_name_on_load_coerced
|
179
|
+
Book.create(name: "test book")
|
180
|
+
Book.first
|
181
|
+
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
|
182
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
183
|
+
if event.payload[:sql].match "SELECT"
|
184
|
+
assert_equal "Book Load", event.payload[:name]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
Book.first
|
188
|
+
ensure
|
189
|
+
ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
|
190
|
+
end
|
115
191
|
end
|
116
192
|
end
|
117
193
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
194
|
class CalculationsTest < ActiveRecord::TestCase
|
195
|
+
# This fails randomly due to schema cache being lost?
|
196
|
+
coerce_tests! :test_offset_is_kept
|
197
|
+
def test_offset_is_kept_coerced
|
198
|
+
Account.first
|
199
|
+
queries = assert_sql { Account.offset(1).count }
|
200
|
+
assert_equal 1, queries.length
|
201
|
+
assert_match(/OFFSET/, queries.first)
|
202
|
+
end
|
203
|
+
|
122
204
|
# Are decimal, not integer.
|
123
205
|
coerce_tests! :test_should_return_decimal_average_of_integer_field
|
124
206
|
def test_should_return_decimal_average_of_integer_field_coerced
|
@@ -130,28 +212,36 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
130
212
|
def test_limit_is_kept_coerced
|
131
213
|
queries = capture_sql_ss { Account.limit(1).count }
|
132
214
|
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}
|
215
|
+
_(queries.first).must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1}
|
134
216
|
end unless defined? JRUBY_VERSION
|
135
217
|
|
136
218
|
def test_limit_is_kept_coerced
|
137
219
|
queries = capture_sql_ss { Account.limit(1).count }
|
138
220
|
assert_equal 1, queries.length
|
139
|
-
queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT \? ROWS ONLY}
|
221
|
+
_(queries.first).must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT \? ROWS ONLY}
|
140
222
|
end if defined? JRUBY_VERSION
|
141
223
|
|
142
224
|
coerce_tests! :test_limit_with_offset_is_kept
|
143
225
|
def test_limit_with_offset_is_kept_coerced
|
144
226
|
queries = capture_sql_ss { Account.limit(1).offset(1).count }
|
145
227
|
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}
|
228
|
+
_(queries.first).must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY.*@0 = 1, @1 = 1}
|
147
229
|
end unless defined? JRUBY_VERSION
|
148
230
|
|
149
231
|
def test_limit_with_offset_is_kept_coerced
|
150
232
|
queries = capture_sql_ss { Account.limit(1).offset(1).count }
|
151
233
|
assert_equal 1, queries.length
|
152
|
-
queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET \? ROWS FETCH NEXT \? ROWS ONLY}
|
234
|
+
_(queries.first).must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET \? ROWS FETCH NEXT \? ROWS ONLY}
|
153
235
|
end if defined? JRUBY_VERSION
|
154
236
|
|
237
|
+
# SQL Server needs an alias for the calculated column
|
238
|
+
coerce_tests! :test_distinct_count_all_with_custom_select_and_order
|
239
|
+
def test_distinct_count_all_with_custom_select_and_order_coerced
|
240
|
+
accounts = Account.distinct.select("credit_limit % 10 AS the_limit").order(Arel.sql("credit_limit % 10"))
|
241
|
+
assert_queries(1) { assert_equal 3, accounts.count(:all) }
|
242
|
+
assert_queries(1) { assert_equal 3, accounts.load.size }
|
243
|
+
end
|
244
|
+
|
155
245
|
# Leave it up to users to format selects/functions so HAVING works correctly.
|
156
246
|
coerce_tests! :test_having_with_strong_parameters
|
157
247
|
end
|
@@ -165,6 +255,7 @@ module ActiveRecord
|
|
165
255
|
coerce_tests! :test_create_table_with_bigint,
|
166
256
|
:test_create_table_with_defaults
|
167
257
|
end
|
258
|
+
|
168
259
|
class ChangeSchemaWithDependentObjectsTest < ActiveRecord::TestCase
|
169
260
|
# In SQL Server you have to delete the tables yourself in the right order.
|
170
261
|
coerce_tests! :test_create_table_with_force_cascade_drops_dependent_objects
|
@@ -174,6 +265,29 @@ end
|
|
174
265
|
|
175
266
|
|
176
267
|
|
268
|
+
module ActiveRecord
|
269
|
+
module ConnectionAdapters
|
270
|
+
class QuoteARBaseTest < ActiveRecord::TestCase
|
271
|
+
|
272
|
+
# Use our date format.
|
273
|
+
coerce_tests! :test_quote_ar_object
|
274
|
+
def test_quote_ar_object_coerced
|
275
|
+
value = DatetimePrimaryKey.new(id: @time)
|
276
|
+
assert_equal "'02-14-2017 12:34:56.789'", @connection.quote(value)
|
277
|
+
end
|
278
|
+
|
279
|
+
# Use our date format.
|
280
|
+
coerce_tests! :test_type_cast_ar_object
|
281
|
+
def test_type_cast_ar_object_coerced
|
282
|
+
value = DatetimePrimaryKey.new(id: @time)
|
283
|
+
assert_equal "02-14-2017 12:34:56.789", @connection.type_cast(value)
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
|
177
291
|
|
178
292
|
module ActiveRecord
|
179
293
|
class Migration
|
@@ -183,7 +297,7 @@ module ActiveRecord
|
|
183
297
|
def test_add_column_without_limit_coerced
|
184
298
|
add_column :test_models, :description, :string, limit: nil
|
185
299
|
TestModel.reset_column_information
|
186
|
-
TestModel.columns_hash["description"].limit.must_equal 4000
|
300
|
+
_(TestModel.columns_hash["description"].limit).must_equal 4000
|
187
301
|
end
|
188
302
|
end
|
189
303
|
end
|
@@ -269,7 +383,7 @@ class MigrationTest < ActiveRecord::TestCase
|
|
269
383
|
end
|
270
384
|
|
271
385
|
# For some reason our tests set Rails.@_env which breaks test env switching.
|
272
|
-
coerce_tests! :
|
386
|
+
coerce_tests! :test_internal_metadata_stores_environment_when_other_data_exists
|
273
387
|
coerce_tests! :test_internal_metadata_stores_environment
|
274
388
|
end
|
275
389
|
|
@@ -295,6 +409,7 @@ module ActiveRecord
|
|
295
409
|
# a value of 'default_env' will still show tests failing. Just ignoring all
|
296
410
|
# of them since we have no monkey in this circus.
|
297
411
|
MergeAndResolveDefaultUrlConfigTest.coerce_all_tests! if defined?(MergeAndResolveDefaultUrlConfigTest)
|
412
|
+
ConnectionHandlerTest.coerce_all_tests! if defined?(ConnectionHandlerTest)
|
298
413
|
end
|
299
414
|
end
|
300
415
|
|
@@ -302,6 +417,10 @@ end
|
|
302
417
|
|
303
418
|
|
304
419
|
module ActiveRecord
|
420
|
+
class DatabaseTasksDumpSchemaCacheTest < ActiveRecord::TestCase
|
421
|
+
# Skip this test with /tmp/my_schema_cache.yml path on Windows.
|
422
|
+
coerce_tests! :test_dump_schema_cache if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
423
|
+
end
|
305
424
|
class DatabaseTasksCreateAllTest < ActiveRecord::TestCase
|
306
425
|
# We extend `local_database?` so that common VM IPs can be used.
|
307
426
|
coerce_tests! :test_ignores_remote_databases, :test_warning_for_remote_databases
|
@@ -395,12 +514,6 @@ class FinderTest < ActiveRecord::TestCase
|
|
395
514
|
end
|
396
515
|
end if defined? JRUBY_VERSION
|
397
516
|
|
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
517
|
coerce_tests! :test_take_and_first_and_last_with_integer_should_use_sql_limit
|
405
518
|
def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
|
406
519
|
assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 3/) { Topic.take(3).entries }
|
@@ -485,7 +598,7 @@ class InheritanceTest < ActiveRecord::TestCase
|
|
485
598
|
coerce_tests! :test_eager_load_belongs_to_primary_key_quoting
|
486
599
|
def test_eager_load_belongs_to_primary_key_quoting_coerced
|
487
600
|
con = Account.connection
|
488
|
-
assert_sql(/\[companies\]\.\[id\] =
|
601
|
+
assert_sql(/\[companies\]\.\[id\] = \?/) do
|
489
602
|
Account.all.merge!(:includes => :firm).find(1)
|
490
603
|
end
|
491
604
|
end
|
@@ -538,6 +651,7 @@ end
|
|
538
651
|
|
539
652
|
|
540
653
|
|
654
|
+
require 'models/parrot'
|
541
655
|
require 'models/topic'
|
542
656
|
class PersistenceTest < ActiveRecord::TestCase
|
543
657
|
# We can not UPDATE identity columns.
|
@@ -547,14 +661,14 @@ class PersistenceTest < ActiveRecord::TestCase
|
|
547
661
|
coerce_tests! :test_update_all_doesnt_ignore_order
|
548
662
|
def test_update_all_doesnt_ignore_order_coerced
|
549
663
|
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
|
664
|
+
_(david.id).must_equal 1
|
665
|
+
_(mary.id).must_equal 2
|
666
|
+
_(david.name).wont_equal mary.name
|
553
667
|
assert_sql(/UPDATE.*\(SELECT \[authors\].\[id\] FROM \[authors\].*ORDER BY \[authors\].\[id\]/i) do
|
554
668
|
Author.where('[id] > 1').order(:id).update_all(name: 'Test')
|
555
669
|
end
|
556
|
-
david.reload.name.must_equal 'David'
|
557
|
-
mary.reload.name.must_equal 'Test'
|
670
|
+
_(david.reload.name).must_equal 'David'
|
671
|
+
_(mary.reload.name).must_equal 'Test'
|
558
672
|
end
|
559
673
|
|
560
674
|
# We can not UPDATE identity columns.
|
@@ -580,6 +694,19 @@ class PersistenceTest < ActiveRecord::TestCase
|
|
580
694
|
# assert_nothing_raised { topic.reload }
|
581
695
|
# assert_equal topic.title, Topic.find(1234).title
|
582
696
|
end
|
697
|
+
|
698
|
+
coerce_tests! :test_delete_new_record
|
699
|
+
def test_delete_new_record_coerced
|
700
|
+
client = Client.new(name: "37signals")
|
701
|
+
client.delete
|
702
|
+
assert_predicate client, :frozen?
|
703
|
+
|
704
|
+
assert_not client.save
|
705
|
+
assert_raise(ActiveRecord::RecordNotSaved) { client.save! }
|
706
|
+
|
707
|
+
assert_predicate client, :frozen?
|
708
|
+
assert_raise(FrozenError) { client.name = "something else" } # For some reason we get a FrozenError instead of a RuntimeError here
|
709
|
+
end
|
583
710
|
end
|
584
711
|
|
585
712
|
|
@@ -603,10 +730,19 @@ end
|
|
603
730
|
|
604
731
|
|
605
732
|
|
733
|
+
class PrimaryKeysTest < ActiveRecord::TestCase
|
734
|
+
# Gonna trust Rails core for this. We end up with 2 querys vs 3 asserted
|
735
|
+
# but as far as I can tell, this is only one for us anyway.
|
736
|
+
coerce_tests! :test_create_without_primary_key_no_extra_query
|
737
|
+
end
|
738
|
+
|
739
|
+
|
740
|
+
|
741
|
+
|
606
742
|
require 'models/task'
|
607
743
|
class QueryCacheTest < ActiveRecord::TestCase
|
608
|
-
coerce_tests! :
|
609
|
-
def
|
744
|
+
coerce_tests! :test_cache_does_not_wrap_results_in_arrays
|
745
|
+
def test_cache_does_not_wrap_results_in_arrays_coerced
|
610
746
|
Task.cache do
|
611
747
|
assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
|
612
748
|
end
|
@@ -621,16 +757,16 @@ class RelationTest < ActiveRecord::TestCase
|
|
621
757
|
# Use LEN vs LENGTH function.
|
622
758
|
coerce_tests! :test_reverse_order_with_function
|
623
759
|
def test_reverse_order_with_function_coerced
|
624
|
-
topics = Topic.order("LEN(title)").reverse_order
|
760
|
+
topics = Topic.order(Arel.sql("LEN(title)")).reverse_order
|
625
761
|
assert_equal topics(:second).title, topics.first.title
|
626
762
|
end
|
627
763
|
|
628
764
|
# Use LEN vs LENGTH function.
|
629
765
|
coerce_tests! :test_reverse_order_with_function_other_predicates
|
630
766
|
def test_reverse_order_with_function_other_predicates_coerced
|
631
|
-
topics = Topic.order("author_name, LEN(title), id").reverse_order
|
767
|
+
topics = Topic.order(Arel.sql("author_name, LEN(title), id")).reverse_order
|
632
768
|
assert_equal topics(:second).title, topics.first.title
|
633
|
-
topics = Topic.order("LEN(author_name), id, LEN(title)").reverse_order
|
769
|
+
topics = Topic.order(Arel.sql("LEN(author_name), id, LEN(title)")).reverse_order
|
634
770
|
assert_equal topics(:fifth).title, topics.first.title
|
635
771
|
end
|
636
772
|
|
@@ -646,6 +782,60 @@ class RelationTest < ActiveRecord::TestCase
|
|
646
782
|
# Leave it up to users to format selects/functions so HAVING works correctly.
|
647
783
|
coerce_tests! :test_multiple_where_and_having_clauses
|
648
784
|
coerce_tests! :test_having_with_binds_for_both_where_and_having
|
785
|
+
|
786
|
+
# Find any limit via our expression.
|
787
|
+
coerce_tests! %r{relations don't load all records in #inspect}
|
788
|
+
def test_relations_dont_load_all_records_in_inspect_coerced
|
789
|
+
assert_sql(/NEXT \? ROWS ONLY/) do
|
790
|
+
Post.all.inspect
|
791
|
+
end
|
792
|
+
end
|
793
|
+
|
794
|
+
# I wanted to add `.order("author_id")` scope to avoid error: Column "posts.id" is invalid in the ORDER BY
|
795
|
+
# However, this pull request on Rails core drops order on exists relation. https://github.com/rails/rails/pull/28699
|
796
|
+
# so we are skipping all together.
|
797
|
+
coerce_tests! :test_empty_complex_chained_relations
|
798
|
+
|
799
|
+
# Can't apply offset withour ORDER
|
800
|
+
coerce_tests! %r{using a custom table affects the wheres}
|
801
|
+
test 'using a custom table affects the wheres coerced' do
|
802
|
+
post = posts(:welcome)
|
803
|
+
|
804
|
+
assert_equal post, custom_post_relation.where!(title: post.title).order(:id).take
|
805
|
+
end
|
806
|
+
|
807
|
+
# Can't apply offset withour ORDER
|
808
|
+
coerce_tests! %r{using a custom table with joins affects the joins}
|
809
|
+
test 'using a custom table with joins affects the joins coerced' do
|
810
|
+
post = posts(:welcome)
|
811
|
+
|
812
|
+
assert_equal post, custom_post_relation.joins(:author).where!(title: post.title).order(:id).take
|
813
|
+
end
|
814
|
+
|
815
|
+
# Use LEN() vs length() function.
|
816
|
+
coerce_tests! :test_reverse_arel_assoc_order_with_function
|
817
|
+
def test_reverse_arel_assoc_order_with_function_coerced
|
818
|
+
topics = Topic.order(Arel.sql("LEN(title)") => :asc).reverse_order
|
819
|
+
assert_equal topics(:second).title, topics.first.title
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
class ActiveRecord::RelationTest < ActiveRecord::TestCase
|
824
|
+
coerce_tests! :test_relation_merging_with_merged_symbol_joins_is_aliased
|
825
|
+
def test_relation_merging_with_merged_symbol_joins_is_aliased__coerced
|
826
|
+
categorizations_with_authors = Categorization.joins(:author)
|
827
|
+
queries = capture_sql { Post.joins(:author, :categorizations).merge(Author.select(:id)).merge(categorizations_with_authors).to_a }
|
828
|
+
|
829
|
+
nb_inner_join = queries.sum { |sql| sql.scan(/INNER\s+JOIN/i).size }
|
830
|
+
assert_equal 3, nb_inner_join, "Wrong amount of INNER JOIN in query"
|
831
|
+
|
832
|
+
# using `\W` as the column separator
|
833
|
+
query_matches = queries.any? do |sql|
|
834
|
+
%r[INNER\s+JOIN\s+#{Regexp.escape(Author.quoted_table_name)}\s+\Wauthors_categorizations\W]i.match?(sql)
|
835
|
+
end
|
836
|
+
|
837
|
+
assert query_matches, "Should be aliasing the child INNER JOINs in query"
|
838
|
+
end
|
649
839
|
end
|
650
840
|
|
651
841
|
|
@@ -677,9 +867,6 @@ class SchemaDumperTest < ActiveRecord::TestCase
|
|
677
867
|
assert_match %r{t.decimal\s+"atoms_in_universe",\s+precision: 38}, output
|
678
868
|
end
|
679
869
|
|
680
|
-
# This accidently returns the wrong number because of our tables too.
|
681
|
-
coerce_tests! :test_types_line_up
|
682
|
-
|
683
870
|
# This is a poorly written test and really does not catch the bottom'ness it is meant too. Ours throw it off.
|
684
871
|
coerce_tests! :test_foreign_keys_are_dumped_at_the_bottom_to_circumvent_dependency_issues
|
685
872
|
|
@@ -803,10 +990,55 @@ class DateTimePrecisionTest < ActiveRecord::TestCase
|
|
803
990
|
end
|
804
991
|
end
|
805
992
|
end
|
993
|
+
|
994
|
+
unless defined? JRUBY_VERSION
|
995
|
+
# datetime is rounded to increments of .000, .003, or .007 seconds
|
996
|
+
coerce_tests! :test_datetime_precision_is_truncated_on_assignment
|
997
|
+
def test_datetime_precision_is_truncated_on_assignment_coerced
|
998
|
+
@connection.create_table(:foos, force: true)
|
999
|
+
@connection.add_column :foos, :created_at, :datetime, precision: 0
|
1000
|
+
@connection.add_column :foos, :updated_at, :datetime, precision: 6
|
1001
|
+
|
1002
|
+
time = ::Time.now.change(nsec: 123456789)
|
1003
|
+
foo = Foo.new(created_at: time, updated_at: time)
|
1004
|
+
|
1005
|
+
assert_equal 0, foo.created_at.nsec
|
1006
|
+
assert_equal 123457000, foo.updated_at.nsec
|
1007
|
+
|
1008
|
+
foo.save!
|
1009
|
+
foo.reload
|
1010
|
+
|
1011
|
+
assert_equal 0, foo.created_at.nsec
|
1012
|
+
assert_equal 123457000, foo.updated_at.nsec
|
1013
|
+
end
|
1014
|
+
end
|
806
1015
|
end
|
807
1016
|
|
808
1017
|
|
809
1018
|
|
1019
|
+
class TimePrecisionTest < ActiveRecord::TestCase
|
1020
|
+
# datetime is rounded to increments of .000, .003, or .007 seconds
|
1021
|
+
coerce_tests! :test_time_precision_is_truncated_on_assignment
|
1022
|
+
def test_time_precision_is_truncated_on_assignment_coerced
|
1023
|
+
@connection.create_table(:foos, force: true)
|
1024
|
+
@connection.add_column :foos, :start, :time, precision: 0
|
1025
|
+
@connection.add_column :foos, :finish, :time, precision: 6
|
1026
|
+
|
1027
|
+
time = ::Time.now.change(nsec: 123456789)
|
1028
|
+
foo = Foo.new(start: time, finish: time)
|
1029
|
+
|
1030
|
+
assert_equal 0, foo.start.nsec
|
1031
|
+
assert_equal 123457000, foo.finish.nsec
|
1032
|
+
|
1033
|
+
foo.save!
|
1034
|
+
foo.reload
|
1035
|
+
|
1036
|
+
assert_equal 0, foo.start.nsec
|
1037
|
+
assert_equal 123457000, foo.finish.nsec
|
1038
|
+
end
|
1039
|
+
end unless defined? JRUBY_VERSION
|
1040
|
+
|
1041
|
+
|
810
1042
|
|
811
1043
|
class DefaultNumbersTest < ActiveRecord::TestCase
|
812
1044
|
# We do better with native types and do not return strings for everything.
|
@@ -843,3 +1075,151 @@ module ActiveRecord
|
|
843
1075
|
#coerce_tests! :test_find_does_not_use_statement_cache_if_table_name_is_changed
|
844
1076
|
end
|
845
1077
|
end
|
1078
|
+
|
1079
|
+
|
1080
|
+
|
1081
|
+
|
1082
|
+
module ActiveRecord
|
1083
|
+
module ConnectionAdapters
|
1084
|
+
class SchemaCacheTest < ActiveRecord::TestCase
|
1085
|
+
private
|
1086
|
+
# We need to give the full path for this to work.
|
1087
|
+
def schema_dump_path
|
1088
|
+
File.join ARTest::SQLServer.root_activerecord, 'test/assets/schema_dump_5_1.yml'
|
1089
|
+
end
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
class UnsafeRawSqlTest < ActiveRecord::TestCase
|
1095
|
+
coerce_tests! %r{always allows Arel}
|
1096
|
+
test 'order: always allows Arel' do
|
1097
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order(Arel.sql("len(title)")).pluck(:title) }
|
1098
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(Arel.sql("len(title)")).pluck(:title) }
|
1099
|
+
|
1100
|
+
assert_equal ids_depr, ids_disabled
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
test "pluck: always allows Arel" do
|
1104
|
+
values_depr = with_unsafe_raw_sql_deprecated { Post.includes(:comments).pluck(:title, Arel.sql("len(title)")) }
|
1105
|
+
values_disabled = with_unsafe_raw_sql_disabled { Post.includes(:comments).pluck(:title, Arel.sql("len(title)")) }
|
1106
|
+
|
1107
|
+
assert_equal values_depr, values_disabled
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
|
1111
|
+
coerce_tests! %r{order: disallows invalid Array arguments}
|
1112
|
+
test "order: disallows invalid Array arguments" do
|
1113
|
+
with_unsafe_raw_sql_disabled do
|
1114
|
+
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
1115
|
+
Post.order(["author_id", "len(title)"]).pluck(:id)
|
1116
|
+
end
|
1117
|
+
end
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
coerce_tests! %r{order: allows valid Array arguments}
|
1121
|
+
test "order: allows valid Array arguments" do
|
1122
|
+
ids_expected = Post.order(Arel.sql("author_id, len(title)")).pluck(:id)
|
1123
|
+
|
1124
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", Arel.sql("len(title)")]).pluck(:id) }
|
1125
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", Arel.sql("len(title)")]).pluck(:id) }
|
1126
|
+
|
1127
|
+
assert_equal ids_expected, ids_depr
|
1128
|
+
assert_equal ids_expected, ids_disabled
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
coerce_tests! %r{order: logs deprecation warning for unrecognized column}
|
1132
|
+
test "order: logs deprecation warning for unrecognized column" do
|
1133
|
+
with_unsafe_raw_sql_deprecated do
|
1134
|
+
assert_deprecated(/Dangerous query method/) do
|
1135
|
+
Post.order("len(title)")
|
1136
|
+
end
|
1137
|
+
end
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
coerce_tests! %r{pluck: disallows invalid column name}
|
1141
|
+
test "pluck: disallows invalid column name" do
|
1142
|
+
with_unsafe_raw_sql_disabled do
|
1143
|
+
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
1144
|
+
Post.pluck("len(title)")
|
1145
|
+
end
|
1146
|
+
end
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
coerce_tests! %r{pluck: disallows invalid column name amongst valid names}
|
1150
|
+
test "pluck: disallows invalid column name amongst valid names" do
|
1151
|
+
with_unsafe_raw_sql_disabled do
|
1152
|
+
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
1153
|
+
Post.pluck(:title, "len(title)")
|
1154
|
+
end
|
1155
|
+
end
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
coerce_tests! %r{pluck: disallows invalid column names with includes}
|
1159
|
+
test "pluck: disallows invalid column names with includes" do
|
1160
|
+
with_unsafe_raw_sql_disabled do
|
1161
|
+
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
1162
|
+
Post.includes(:comments).pluck(:title, "len(title)")
|
1163
|
+
end
|
1164
|
+
end
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
coerce_tests! %r{pluck: logs deprecation warning}
|
1168
|
+
test "pluck: logs deprecation warning" do
|
1169
|
+
with_unsafe_raw_sql_deprecated do
|
1170
|
+
assert_deprecated(/Dangerous query method/) do
|
1171
|
+
Post.includes(:comments).pluck(:title, "len(title)")
|
1172
|
+
end
|
1173
|
+
end
|
1174
|
+
end
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
|
1178
|
+
class ReservedWordTest < ActiveRecord::TestCase
|
1179
|
+
coerce_tests! :test_change_columns
|
1180
|
+
def test_change_columns_coerced
|
1181
|
+
assert_nothing_raised { @connection.change_column_default(:group, :order, "whatever") }
|
1182
|
+
assert_nothing_raised { @connection.change_column("group", "order", :text) }
|
1183
|
+
assert_nothing_raised { @connection.change_column_null("group", "order", true) }
|
1184
|
+
assert_nothing_raised { @connection.rename_column(:group, :order, :values) }
|
1185
|
+
end
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
|
1189
|
+
|
1190
|
+
class OptimisticLockingTest < ActiveRecord::TestCase
|
1191
|
+
# We do not allow updating identities, but we can test using a non-identity key
|
1192
|
+
coerce_tests! :test_update_with_dirty_primary_key
|
1193
|
+
def test_update_with_dirty_primary_key_coerced
|
1194
|
+
assert_raises(ActiveRecord::RecordNotUnique) do
|
1195
|
+
record = StringKeyObject.find('record1')
|
1196
|
+
record.id = 'record2'
|
1197
|
+
record.save!
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
record = StringKeyObject.find('record1')
|
1201
|
+
record.id = 'record42'
|
1202
|
+
record.save!
|
1203
|
+
|
1204
|
+
assert StringKeyObject.find('record42')
|
1205
|
+
assert_raises(ActiveRecord::RecordNotFound) do
|
1206
|
+
StringKeyObject.find('record1')
|
1207
|
+
end
|
1208
|
+
end
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
|
1212
|
+
|
1213
|
+
class RelationMergingTest < ActiveRecord::TestCase
|
1214
|
+
coerce_tests! :test_merging_with_order_with_binds
|
1215
|
+
def test_merging_with_order_with_binds_coerced
|
1216
|
+
relation = Post.all.merge(Post.order([Arel.sql("title LIKE ?"), "%suffix"]))
|
1217
|
+
assert_equal ["title LIKE N'%suffix'"], relation.order_values
|
1218
|
+
end
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
|
1222
|
+
class EagerLoadingTooManyIdsTest < ActiveRecord::TestCase
|
1223
|
+
# Temporarily coerce this test due to https://github.com/rails/rails/issues/34945
|
1224
|
+
coerce_tests! :test_eager_loading_too_may_ids
|
1225
|
+
end
|