activerecord-sqlserver-adapter 5.1.6 → 5.2.0.rc1
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 +16 -19
- data/CHANGELOG.md +6 -46
- data/Dockerfile +14 -0
- data/Gemfile +1 -2
- data/README.md +4 -4
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +1 -1
- data/circle.yml +8 -6
- data/docker-compose.ci.yml +11 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +11 -18
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +13 -2
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +45 -9
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +2 -1
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +33 -14
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +3 -4
- 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_adapter.rb +14 -12
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +3 -1
- data/lib/arel/visitors/sqlserver.rb +1 -1
- data/lib/arel_sqlserver.rb +0 -1
- data/test/bin/install-freetds.sh +1 -1
- data/test/cases/adapter_test_sqlserver.rb +10 -2
- data/test/cases/coerced_tests.rb +262 -13
- data/test/cases/column_test_sqlserver.rb +6 -0
- data/test/cases/helper_sqlserver.rb +2 -1
- data/test/cases/migration_test_sqlserver.rb +3 -1
- data/test/cases/order_test_sqlserver.rb +19 -19
- data/test/schema/sqlserver_specific_schema.rb +9 -1
- data/test/support/core_ext/query_cache.rb +29 -0
- metadata +11 -9
- data/test/bin/.keep +0 -0
@@ -26,13 +26,13 @@ module ActiveRecord
|
|
26
26
|
|
27
27
|
end
|
28
28
|
|
29
|
-
Transaction.send :
|
29
|
+
Transaction.send :prepend, SQLServerTransaction
|
30
30
|
|
31
31
|
module SQLServerRealTransaction
|
32
32
|
|
33
33
|
attr_reader :starting_isolation_level
|
34
34
|
|
35
|
-
def initialize(connection, options,
|
35
|
+
def initialize(connection, options, *args)
|
36
36
|
@connection = connection
|
37
37
|
@starting_isolation_level = current_isolation_level if options[:isolation]
|
38
38
|
super
|
@@ -58,7 +58,6 @@ module ActiveRecord
|
|
58
58
|
|
59
59
|
end
|
60
60
|
|
61
|
-
RealTransaction.send :
|
62
|
-
|
61
|
+
RealTransaction.send :prepend, SQLServerRealTransaction
|
63
62
|
end
|
64
63
|
end
|
@@ -34,7 +34,6 @@ module ActiveRecord
|
|
34
34
|
SQLServer::Quoting,
|
35
35
|
SQLServer::DatabaseStatements,
|
36
36
|
SQLServer::Showplan,
|
37
|
-
SQLServer::SchemaDumper,
|
38
37
|
SQLServer::SchemaStatements,
|
39
38
|
SQLServer::DatabaseLimits,
|
40
39
|
SQLServer::DatabaseTasks
|
@@ -136,6 +135,10 @@ module ActiveRecord
|
|
136
135
|
false
|
137
136
|
end
|
138
137
|
|
138
|
+
def supports_savepoints?
|
139
|
+
true
|
140
|
+
end
|
141
|
+
|
139
142
|
def supports_in_memory_oltp?
|
140
143
|
@version_year >= 2014
|
141
144
|
end
|
@@ -189,7 +192,7 @@ module ActiveRecord
|
|
189
192
|
|
190
193
|
def tables_with_referential_integrity
|
191
194
|
schemas_and_tables = select_rows <<-SQL.strip_heredoc
|
192
|
-
SELECT s.name, o.name
|
195
|
+
SELECT DISTINCT s.name, o.name
|
193
196
|
FROM sys.foreign_keys i
|
194
197
|
INNER JOIN sys.objects o ON i.parent_object_id = o.OBJECT_ID
|
195
198
|
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
@@ -212,7 +215,7 @@ module ActiveRecord
|
|
212
215
|
end
|
213
216
|
|
214
217
|
def sqlserver_azure?
|
215
|
-
|
218
|
+
!!(sqlserver_version =~ /Azure/i)
|
216
219
|
end
|
217
220
|
|
218
221
|
def database_prefix_remote_server?
|
@@ -253,7 +256,7 @@ module ActiveRecord
|
|
253
256
|
|
254
257
|
# === Abstract Adapter (Misc Support) =========================== #
|
255
258
|
|
256
|
-
def initialize_type_map(m)
|
259
|
+
def initialize_type_map(m = type_map)
|
257
260
|
m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
|
258
261
|
# Exact Numerics
|
259
262
|
register_class_with_limit m, 'bigint(8)', SQLServer::Type::BigInteger
|
@@ -435,16 +438,15 @@ module ActiveRecord
|
|
435
438
|
end
|
436
439
|
|
437
440
|
def version_year
|
438
|
-
return
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
/SQL Server (\d+)/.match(vstring).to_a.last.to_s.to_i
|
443
|
-
rescue Exception => e
|
444
|
-
2016
|
445
|
-
end
|
441
|
+
return 2016 if sqlserver_version =~ /vNext/
|
442
|
+
/SQL Server (\d+)/.match(sqlserver_version).to_a.last.to_s.to_i
|
443
|
+
rescue StandardError => e
|
444
|
+
2016
|
446
445
|
end
|
447
446
|
|
447
|
+
def sqlserver_version
|
448
|
+
@sqlserver_version ||= _raw_select('SELECT @@version', fetch: :rows).first.first.to_s
|
449
|
+
end
|
448
450
|
end
|
449
451
|
end
|
450
452
|
end
|
@@ -49,9 +49,11 @@ module ActiveRecord
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def structure_dump(filename, extra_flags)
|
52
|
+
server_arg = "-S #{Shellwords.escape(configuration['host'])}"
|
53
|
+
server_arg += ":#{Shellwords.escape(configuration['port'])}" if configuration['port']
|
52
54
|
command = [
|
53
55
|
"defncopy-ttds",
|
54
|
-
|
56
|
+
server_arg,
|
55
57
|
"-D #{Shellwords.escape(configuration['database'])}",
|
56
58
|
"-U #{Shellwords.escape(configuration['username'])}",
|
57
59
|
"-P #{Shellwords.escape(configuration['password'])}",
|
data/lib/arel_sqlserver.rb
CHANGED
data/test/bin/install-freetds.sh
CHANGED
@@ -5,7 +5,7 @@ set -e
|
|
5
5
|
|
6
6
|
FREETDS_VERSION=1.00.21
|
7
7
|
|
8
|
-
wget
|
8
|
+
wget http://www.freetds.org/files/stable/freetds-$FREETDS_VERSION.tar.gz
|
9
9
|
tar -xzf freetds-$FREETDS_VERSION.tar.gz
|
10
10
|
cd freetds-$FREETDS_VERSION
|
11
11
|
./configure --prefix=/opt/local \
|
@@ -231,6 +231,11 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
231
231
|
end
|
232
232
|
end
|
233
233
|
|
234
|
+
it 'not disable referential integrity for the same table twice' do
|
235
|
+
tables = SSTestHasPk.connection.tables_with_referential_integrity
|
236
|
+
assert_equal tables.size, tables.uniq.size
|
237
|
+
end
|
238
|
+
|
234
239
|
end
|
235
240
|
|
236
241
|
describe 'database statements' do
|
@@ -268,9 +273,12 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
268
273
|
assert_equal 'integer', connection.type_to_sql(:integer, limit: 3)
|
269
274
|
end
|
270
275
|
|
271
|
-
it 'create smallints when limit is
|
276
|
+
it 'create smallints when limit is 2' do
|
272
277
|
assert_equal 'smallint', connection.type_to_sql(:integer, limit: 2)
|
273
|
-
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'create tinyints when limit is 1' do
|
281
|
+
assert_equal 'tinyint', connection.type_to_sql(:integer, limit: 1)
|
274
282
|
end
|
275
283
|
|
276
284
|
it 'create bigints when limit is greateer than 4' do
|
data/test/cases/coerced_tests.rb
CHANGED
@@ -33,6 +33,7 @@ module ActiveRecord
|
|
33
33
|
class AdapterTest < ActiveRecord::TestCase
|
34
34
|
# I really dont think we can support legacy binds.
|
35
35
|
coerce_tests! :test_select_all_with_legacy_binds
|
36
|
+
coerce_tests! :test_insert_update_delete_with_legacy_binds
|
36
37
|
|
37
38
|
# As far as I can tell, SQL Server does not support null bytes in strings.
|
38
39
|
coerce_tests! :test_update_prepared_statement
|
@@ -71,7 +72,11 @@ class AttributeMethodsTest < ActiveRecord::TestCase
|
|
71
72
|
end
|
72
73
|
|
73
74
|
|
74
|
-
|
75
|
+
class NumericDataTest < ActiveRecord::TestCase
|
76
|
+
# We do not have do the DecimalWithoutScale type.
|
77
|
+
coerce_tests! :test_numeric_fields
|
78
|
+
coerce_tests! :test_numeric_fields_with_scale
|
79
|
+
end
|
75
80
|
|
76
81
|
class BasicsTest < ActiveRecord::TestCase
|
77
82
|
coerce_tests! :test_column_names_are_escaped
|
@@ -80,10 +85,6 @@ class BasicsTest < ActiveRecord::TestCase
|
|
80
85
|
assert_equal '[t]]]', conn.quote_column_name('t]')
|
81
86
|
end
|
82
87
|
|
83
|
-
# We do not have do the DecimalWithoutScale type.
|
84
|
-
coerce_tests! :test_numeric_fields
|
85
|
-
coerce_tests! :test_numeric_fields_with_scale
|
86
|
-
|
87
88
|
# Just like PostgreSQLAdapter does.
|
88
89
|
coerce_tests! :test_respect_internal_encoding
|
89
90
|
|
@@ -112,6 +113,16 @@ class BasicsTest < ActiveRecord::TestCase
|
|
112
113
|
end
|
113
114
|
end
|
114
115
|
end
|
116
|
+
|
117
|
+
# Need to escape `quoted_id` once it contains brackets
|
118
|
+
coerce_tests! %r{column names are quoted when using #from clause and model has ignored columns}
|
119
|
+
test "column names are quoted when using #from clause and model has ignored columns coerced" do
|
120
|
+
refute_empty Developer.ignored_columns
|
121
|
+
query = Developer.from("developers").to_sql
|
122
|
+
quoted_id = "#{Developer.quoted_table_name}.#{Developer.quoted_primary_key}"
|
123
|
+
|
124
|
+
assert_match(/SELECT #{Regexp.escape(quoted_id)}.* FROM developers/, query)
|
125
|
+
end
|
115
126
|
end
|
116
127
|
|
117
128
|
|
@@ -140,7 +151,25 @@ module ActiveRecord
|
|
140
151
|
end
|
141
152
|
|
142
153
|
|
143
|
-
|
154
|
+
module ActiveRecord
|
155
|
+
class InstrumentationTest < ActiveRecord::TestCase
|
156
|
+
# This fails randomly due to schema cache being lost?
|
157
|
+
coerce_tests! :test_payload_name_on_load
|
158
|
+
def test_payload_name_on_load_coerced
|
159
|
+
Book.create(name: "test book")
|
160
|
+
Book.first
|
161
|
+
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
|
162
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
163
|
+
if event.payload[:sql].match "SELECT"
|
164
|
+
assert_equal "Book Load", event.payload[:name]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
Book.first
|
168
|
+
ensure
|
169
|
+
ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
144
173
|
|
145
174
|
class CalculationsTest < ActiveRecord::TestCase
|
146
175
|
# This fails randomly due to schema cache being lost?
|
@@ -173,6 +202,14 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
173
202
|
queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY.*@0 = 1, @1 = 1}
|
174
203
|
end
|
175
204
|
|
205
|
+
# SQL Server needs an alias for the calculated column
|
206
|
+
coerce_tests! :test_distinct_count_all_with_custom_select_and_order
|
207
|
+
def test_distinct_count_all_with_custom_select_and_order_coerced
|
208
|
+
accounts = Account.distinct.select("credit_limit % 10 AS the_limit").order(Arel.sql("credit_limit % 10"))
|
209
|
+
assert_queries(1) { assert_equal 3, accounts.count(:all) }
|
210
|
+
assert_queries(1) { assert_equal 3, accounts.load.size }
|
211
|
+
end
|
212
|
+
|
176
213
|
# Leave it up to users to format selects/functions so HAVING works correctly.
|
177
214
|
coerce_tests! :test_having_with_strong_parameters
|
178
215
|
end
|
@@ -186,6 +223,7 @@ module ActiveRecord
|
|
186
223
|
coerce_tests! :test_create_table_with_bigint,
|
187
224
|
:test_create_table_with_defaults
|
188
225
|
end
|
226
|
+
|
189
227
|
class ChangeSchemaWithDependentObjectsTest < ActiveRecord::TestCase
|
190
228
|
# In SQL Server you have to delete the tables yourself in the right order.
|
191
229
|
coerce_tests! :test_create_table_with_force_cascade_drops_dependent_objects
|
@@ -313,7 +351,7 @@ class MigrationTest < ActiveRecord::TestCase
|
|
313
351
|
end
|
314
352
|
|
315
353
|
# For some reason our tests set Rails.@_env which breaks test env switching.
|
316
|
-
coerce_tests! :
|
354
|
+
coerce_tests! :test_internal_metadata_stores_environment_when_other_data_exists
|
317
355
|
coerce_tests! :test_internal_metadata_stores_environment
|
318
356
|
end
|
319
357
|
|
@@ -339,6 +377,7 @@ module ActiveRecord
|
|
339
377
|
# a value of 'default_env' will still show tests failing. Just ignoring all
|
340
378
|
# of them since we have no monkey in this circus.
|
341
379
|
MergeAndResolveDefaultUrlConfigTest.coerce_all_tests! if defined?(MergeAndResolveDefaultUrlConfigTest)
|
380
|
+
ConnectionHandlerTest.coerce_all_tests! if defined?(ConnectionHandlerTest)
|
342
381
|
end
|
343
382
|
end
|
344
383
|
|
@@ -513,7 +552,7 @@ class InheritanceTest < ActiveRecord::TestCase
|
|
513
552
|
coerce_tests! :test_eager_load_belongs_to_primary_key_quoting
|
514
553
|
def test_eager_load_belongs_to_primary_key_quoting_coerced
|
515
554
|
con = Account.connection
|
516
|
-
assert_sql(/\[companies\]\.\[id\] = 1/) do
|
555
|
+
assert_sql(/\[companies\]\.\[id\] = @0.* @0 = 1/) do
|
517
556
|
Account.all.merge!(:includes => :firm).find(1)
|
518
557
|
end
|
519
558
|
end
|
@@ -566,6 +605,7 @@ end
|
|
566
605
|
|
567
606
|
|
568
607
|
|
608
|
+
require 'models/parrot'
|
569
609
|
require 'models/topic'
|
570
610
|
class PersistenceTest < ActiveRecord::TestCase
|
571
611
|
# We can not UPDATE identity columns.
|
@@ -642,8 +682,8 @@ end
|
|
642
682
|
|
643
683
|
require 'models/task'
|
644
684
|
class QueryCacheTest < ActiveRecord::TestCase
|
645
|
-
coerce_tests! :
|
646
|
-
def
|
685
|
+
coerce_tests! :test_cache_does_not_wrap_results_in_arrays
|
686
|
+
def test_cache_does_not_wrap_results_in_arrays_coerced
|
647
687
|
Task.cache do
|
648
688
|
assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
|
649
689
|
end
|
@@ -658,16 +698,16 @@ class RelationTest < ActiveRecord::TestCase
|
|
658
698
|
# Use LEN vs LENGTH function.
|
659
699
|
coerce_tests! :test_reverse_order_with_function
|
660
700
|
def test_reverse_order_with_function_coerced
|
661
|
-
topics = Topic.order("LEN(title)").reverse_order
|
701
|
+
topics = Topic.order(Arel.sql("LEN(title)")).reverse_order
|
662
702
|
assert_equal topics(:second).title, topics.first.title
|
663
703
|
end
|
664
704
|
|
665
705
|
# Use LEN vs LENGTH function.
|
666
706
|
coerce_tests! :test_reverse_order_with_function_other_predicates
|
667
707
|
def test_reverse_order_with_function_other_predicates_coerced
|
668
|
-
topics = Topic.order("author_name, LEN(title), id").reverse_order
|
708
|
+
topics = Topic.order(Arel.sql("author_name, LEN(title), id")).reverse_order
|
669
709
|
assert_equal topics(:second).title, topics.first.title
|
670
|
-
topics = Topic.order("LEN(author_name), id, LEN(title)").reverse_order
|
710
|
+
topics = Topic.order(Arel.sql("LEN(author_name), id, LEN(title)")).reverse_order
|
671
711
|
assert_equal topics(:fifth).title, topics.first.title
|
672
712
|
end
|
673
713
|
|
@@ -697,6 +737,22 @@ class RelationTest < ActiveRecord::TestCase
|
|
697
737
|
# so we are skipping all together.
|
698
738
|
coerce_tests! :test_empty_complex_chained_relations
|
699
739
|
|
740
|
+
# Can't apply offset withour ORDER
|
741
|
+
coerce_tests! %r{using a custom table affects the wheres}
|
742
|
+
test 'using a custom table affects the wheres coerced' do
|
743
|
+
post = posts(:welcome)
|
744
|
+
|
745
|
+
assert_equal post, custom_post_relation.where!(title: post.title).order(:id).take
|
746
|
+
end
|
747
|
+
|
748
|
+
# Can't apply offset withour ORDER
|
749
|
+
coerce_tests! %r{using a custom table with joins affects the joins}
|
750
|
+
test 'using a custom table with joins affects the joins coerced' do
|
751
|
+
post = posts(:welcome)
|
752
|
+
|
753
|
+
assert_equal post, custom_post_relation.joins(:author).where!(title: post.title).order(:id).take
|
754
|
+
end
|
755
|
+
|
700
756
|
# Use LEN() vs length() function.
|
701
757
|
coerce_tests! :test_reverse_arel_assoc_order_with_function
|
702
758
|
def test_reverse_arel_assoc_order_with_function_coerced
|
@@ -705,6 +761,24 @@ class RelationTest < ActiveRecord::TestCase
|
|
705
761
|
end
|
706
762
|
end
|
707
763
|
|
764
|
+
class ActiveRecord::RelationTest < ActiveRecord::TestCase
|
765
|
+
coerce_tests! :test_relation_merging_with_merged_symbol_joins_is_aliased
|
766
|
+
def test_relation_merging_with_merged_symbol_joins_is_aliased__coerced
|
767
|
+
categorizations_with_authors = Categorization.joins(:author)
|
768
|
+
queries = capture_sql { Post.joins(:author, :categorizations).merge(Author.select(:id)).merge(categorizations_with_authors).to_a }
|
769
|
+
|
770
|
+
nb_inner_join = queries.sum { |sql| sql.scan(/INNER\s+JOIN/i).size }
|
771
|
+
assert_equal 3, nb_inner_join, "Wrong amount of INNER JOIN in query"
|
772
|
+
|
773
|
+
# using `\W` as the column separator
|
774
|
+
query_matches = queries.any? do |sql|
|
775
|
+
%r[INNER\s+JOIN\s+#{Regexp.escape(Author.quoted_table_name)}\s+\Wauthors_categorizations\W]i.match?(sql)
|
776
|
+
end
|
777
|
+
|
778
|
+
assert query_matches, "Should be aliasing the child INNER JOINs in query"
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
708
782
|
|
709
783
|
|
710
784
|
|
@@ -857,10 +931,53 @@ class DateTimePrecisionTest < ActiveRecord::TestCase
|
|
857
931
|
end
|
858
932
|
end
|
859
933
|
end
|
934
|
+
|
935
|
+
# datetime is rounded to increments of .000, .003, or .007 seconds
|
936
|
+
coerce_tests! :test_datetime_precision_is_truncated_on_assignment
|
937
|
+
def test_datetime_precision_is_truncated_on_assignment_coerced
|
938
|
+
@connection.create_table(:foos, force: true)
|
939
|
+
@connection.add_column :foos, :created_at, :datetime, precision: 0
|
940
|
+
@connection.add_column :foos, :updated_at, :datetime, precision: 6
|
941
|
+
|
942
|
+
time = ::Time.now.change(nsec: 123456789)
|
943
|
+
foo = Foo.new(created_at: time, updated_at: time)
|
944
|
+
|
945
|
+
assert_equal 0, foo.created_at.nsec
|
946
|
+
assert_equal 123457000, foo.updated_at.nsec
|
947
|
+
|
948
|
+
foo.save!
|
949
|
+
foo.reload
|
950
|
+
|
951
|
+
assert_equal 0, foo.created_at.nsec
|
952
|
+
assert_equal 123457000, foo.updated_at.nsec
|
953
|
+
end
|
860
954
|
end
|
861
955
|
|
862
956
|
|
863
957
|
|
958
|
+
class TimePrecisionTest < ActiveRecord::TestCase
|
959
|
+
# datetime is rounded to increments of .000, .003, or .007 seconds
|
960
|
+
coerce_tests! :test_time_precision_is_truncated_on_assignment
|
961
|
+
def test_time_precision_is_truncated_on_assignment_coerced
|
962
|
+
@connection.create_table(:foos, force: true)
|
963
|
+
@connection.add_column :foos, :start, :time, precision: 0
|
964
|
+
@connection.add_column :foos, :finish, :time, precision: 6
|
965
|
+
|
966
|
+
time = ::Time.now.change(nsec: 123456789)
|
967
|
+
foo = Foo.new(start: time, finish: time)
|
968
|
+
|
969
|
+
assert_equal 0, foo.start.nsec
|
970
|
+
assert_equal 123457000, foo.finish.nsec
|
971
|
+
|
972
|
+
foo.save!
|
973
|
+
foo.reload
|
974
|
+
|
975
|
+
assert_equal 0, foo.start.nsec
|
976
|
+
assert_equal 123457000, foo.finish.nsec
|
977
|
+
end
|
978
|
+
end
|
979
|
+
|
980
|
+
|
864
981
|
|
865
982
|
class DefaultNumbersTest < ActiveRecord::TestCase
|
866
983
|
# We do better with native types and do not return strings for everything.
|
@@ -913,3 +1030,135 @@ module ActiveRecord
|
|
913
1030
|
end
|
914
1031
|
end
|
915
1032
|
|
1033
|
+
class UnsafeRawSqlTest < ActiveRecord::TestCase
|
1034
|
+
coerce_tests! %r{always allows Arel}
|
1035
|
+
test 'order: always allows Arel' do
|
1036
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order(Arel.sql("len(title)")).pluck(:title) }
|
1037
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(Arel.sql("len(title)")).pluck(:title) }
|
1038
|
+
|
1039
|
+
assert_equal ids_depr, ids_disabled
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
test "pluck: always allows Arel" do
|
1043
|
+
values_depr = with_unsafe_raw_sql_deprecated { Post.includes(:comments).pluck(:title, Arel.sql("len(title)")) }
|
1044
|
+
values_disabled = with_unsafe_raw_sql_disabled { Post.includes(:comments).pluck(:title, Arel.sql("len(title)")) }
|
1045
|
+
|
1046
|
+
assert_equal values_depr, values_disabled
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
|
1050
|
+
coerce_tests! %r{order: disallows invalid Array arguments}
|
1051
|
+
test "order: disallows invalid Array arguments" do
|
1052
|
+
with_unsafe_raw_sql_disabled do
|
1053
|
+
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
1054
|
+
Post.order(["author_id", "len(title)"]).pluck(:id)
|
1055
|
+
end
|
1056
|
+
end
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
coerce_tests! %r{order: allows valid Array arguments}
|
1060
|
+
test "order: allows valid Array arguments" do
|
1061
|
+
ids_expected = Post.order(Arel.sql("author_id, len(title)")).pluck(:id)
|
1062
|
+
|
1063
|
+
ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", Arel.sql("len(title)")]).pluck(:id) }
|
1064
|
+
ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", Arel.sql("len(title)")]).pluck(:id) }
|
1065
|
+
|
1066
|
+
assert_equal ids_expected, ids_depr
|
1067
|
+
assert_equal ids_expected, ids_disabled
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
coerce_tests! %r{order: logs deprecation warning for unrecognized column}
|
1071
|
+
test "order: logs deprecation warning for unrecognized column" do
|
1072
|
+
with_unsafe_raw_sql_deprecated do
|
1073
|
+
assert_deprecated(/Dangerous query method/) do
|
1074
|
+
Post.order("len(title)")
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
coerce_tests! %r{pluck: disallows invalid column name}
|
1080
|
+
test "pluck: disallows invalid column name" do
|
1081
|
+
with_unsafe_raw_sql_disabled do
|
1082
|
+
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
1083
|
+
Post.pluck("len(title)")
|
1084
|
+
end
|
1085
|
+
end
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
coerce_tests! %r{pluck: disallows invalid column name amongst valid names}
|
1089
|
+
test "pluck: disallows invalid column name amongst valid names" do
|
1090
|
+
with_unsafe_raw_sql_disabled do
|
1091
|
+
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
1092
|
+
Post.pluck(:title, "len(title)")
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
coerce_tests! %r{pluck: disallows invalid column names with includes}
|
1098
|
+
test "pluck: disallows invalid column names with includes" do
|
1099
|
+
with_unsafe_raw_sql_disabled do
|
1100
|
+
assert_raises(ActiveRecord::UnknownAttributeReference) do
|
1101
|
+
Post.includes(:comments).pluck(:title, "len(title)")
|
1102
|
+
end
|
1103
|
+
end
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
coerce_tests! %r{pluck: logs deprecation warning}
|
1107
|
+
test "pluck: logs deprecation warning" do
|
1108
|
+
with_unsafe_raw_sql_deprecated do
|
1109
|
+
assert_deprecated(/Dangerous query method/) do
|
1110
|
+
Post.includes(:comments).pluck(:title, "len(title)")
|
1111
|
+
end
|
1112
|
+
end
|
1113
|
+
end
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
|
1117
|
+
class ReservedWordTest < ActiveRecord::TestCase
|
1118
|
+
coerce_tests! :test_change_columns
|
1119
|
+
def test_change_columns_coerced
|
1120
|
+
assert_nothing_raised { @connection.change_column_default(:group, :order, "whatever") }
|
1121
|
+
assert_nothing_raised { @connection.change_column("group", "order", :text) }
|
1122
|
+
assert_nothing_raised { @connection.change_column_null("group", "order", true) }
|
1123
|
+
assert_nothing_raised { @connection.rename_column(:group, :order, :values) }
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
|
1128
|
+
|
1129
|
+
class OptimisticLockingTest < ActiveRecord::TestCase
|
1130
|
+
# We do not allow updating identities, but we can test using a non-identity key
|
1131
|
+
coerce_tests! :test_update_with_dirty_primary_key
|
1132
|
+
def test_update_with_dirty_primary_key_coerced
|
1133
|
+
assert_raises(ActiveRecord::RecordNotUnique) do
|
1134
|
+
record = StringKeyObject.find('record1')
|
1135
|
+
record.id = 'record2'
|
1136
|
+
record.save!
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
record = StringKeyObject.find('record1')
|
1140
|
+
record.id = 'record42'
|
1141
|
+
record.save!
|
1142
|
+
|
1143
|
+
assert StringKeyObject.find('record42')
|
1144
|
+
assert_raises(ActiveRecord::RecordNotFound) do
|
1145
|
+
StringKeyObject.find('record1')
|
1146
|
+
end
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
|
1151
|
+
|
1152
|
+
class RelationMergingTest < ActiveRecord::TestCase
|
1153
|
+
coerce_tests! :test_merging_with_order_with_binds
|
1154
|
+
def test_merging_with_order_with_binds_coerced
|
1155
|
+
relation = Post.all.merge(Post.order([Arel.sql("title LIKE ?"), "%suffix"]))
|
1156
|
+
assert_equal ["title LIKE N'%suffix'"], relation.order_values
|
1157
|
+
end
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
|
1161
|
+
class EagerLoadingTooManyIdsTest < ActiveRecord::TestCase
|
1162
|
+
# Temporarily coerce this test due to https://github.com/rails/rails/issues/34945
|
1163
|
+
coerce_tests! :test_eager_loading_too_may_ids
|
1164
|
+
end
|