activerecord-sqlserver-adapter 7.2.8 → 7.2.9
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/CHANGELOG.md +6 -0
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +6 -5
- data/test/cases/coerced_tests.rb +34 -106
- data/test/cases/optimizer_hints_test_sqlserver.rb +1 -1
- data/test/cases/showplan_test_sqlserver.rb +2 -2
- data/test/cases/specific_schema_test_sqlserver.rb +6 -6
- data/test/support/query_assertions.rb +22 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aeac1dd3621ed52e93f365fefbca8a0e83ffcfbdac6b01907260efa98db1069f
|
|
4
|
+
data.tar.gz: daa368ec2b8e38e25aaab374640a29e7d6a5482a78609b32cabefdc716a01b78
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0ca3530b11fd81b695bde3264fd2daaa221c7f21a7c6e86cbfef14bdf4a60b4aba26238aec58c2456d953fb1aa933c27c0800978061ad71889b0e92fc6a4ebf7
|
|
7
|
+
data.tar.gz: 5b3b6bbf751511101b26d319554ec1f394fc0d4a76250812146e7400a342b31aa60cb314406f4352f27a49b04fdfa79cf41c7cba12c916b866df6254bf0ddf03
|
data/CHANGELOG.md
CHANGED
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.2.
|
|
1
|
+
7.2.9
|
|
@@ -34,12 +34,13 @@ module ActiveRecord
|
|
|
34
34
|
check_if_write_query(sql)
|
|
35
35
|
mark_transaction_written_if_write(sql)
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
type_casted_binds = type_casted_binds(binds)
|
|
38
|
+
log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
|
|
39
|
+
unless without_prepared_statement?(binds)
|
|
40
|
+
types, params = sp_executesql_types_and_parameters(binds)
|
|
41
|
+
sql = sp_executesql_sql(sql, types, params, name)
|
|
42
|
+
end
|
|
41
43
|
|
|
42
|
-
log(sql, name, binds, async: async) do |notification_payload|
|
|
43
44
|
with_raw_connection do |conn|
|
|
44
45
|
result = if id_insert_table_name = query_requires_identity_insert?(sql)
|
|
45
46
|
with_identity_insert_enabled(id_insert_table_name, conn) do
|
data/test/cases/coerced_tests.rb
CHANGED
|
@@ -248,7 +248,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
|
|
|
248
248
|
def test_belongs_to_coerced
|
|
249
249
|
client = Client.find(3)
|
|
250
250
|
first_firm = companies(:first_firm)
|
|
251
|
-
assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY
|
|
251
|
+
assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY/) do
|
|
252
252
|
assert_equal first_firm, client.firm
|
|
253
253
|
assert_equal first_firm.name, client.firm.name
|
|
254
254
|
end
|
|
@@ -257,21 +257,6 @@ end
|
|
|
257
257
|
|
|
258
258
|
module ActiveRecord
|
|
259
259
|
class BindParameterTest < ActiveRecord::TestCase
|
|
260
|
-
# Same as original coerced test except log is found using `EXEC sp_executesql` wrapper.
|
|
261
|
-
coerce_tests! :test_binds_are_logged
|
|
262
|
-
def test_binds_are_logged_coerced
|
|
263
|
-
sub = Arel::Nodes::BindParam.new(1)
|
|
264
|
-
binds = [Relation::QueryAttribute.new("id", 1, Type::Value.new)]
|
|
265
|
-
sql = "select * from topics where id = #{sub.to_sql}"
|
|
266
|
-
|
|
267
|
-
@connection.exec_query(sql, "SQL", binds)
|
|
268
|
-
|
|
269
|
-
logged_sql = "EXEC sp_executesql N'#{sql}', N'#{sub.to_sql} int', #{sub.to_sql} = 1"
|
|
270
|
-
message = @subscriber.calls.find { |args| args[4][:sql] == logged_sql }
|
|
271
|
-
|
|
272
|
-
assert_equal binds, message[4][:binds]
|
|
273
|
-
end
|
|
274
|
-
|
|
275
260
|
# SQL Server adapter does not use a statement cache as query plans are already reused using `EXEC sp_executesql`.
|
|
276
261
|
coerce_tests! :test_statement_cache
|
|
277
262
|
coerce_tests! :test_statement_cache_with_query_cache
|
|
@@ -279,55 +264,6 @@ module ActiveRecord
|
|
|
279
264
|
coerce_tests! :test_statement_cache_with_find_by
|
|
280
265
|
coerce_tests! :test_statement_cache_with_in_clause
|
|
281
266
|
coerce_tests! :test_statement_cache_with_sql_string_literal
|
|
282
|
-
|
|
283
|
-
# Same as original coerced test except prepared statements include `EXEC sp_executesql` wrapper.
|
|
284
|
-
coerce_tests! :test_bind_params_to_sql_with_prepared_statements, :test_bind_params_to_sql_with_unprepared_statements
|
|
285
|
-
def test_bind_params_to_sql_with_prepared_statements_coerced
|
|
286
|
-
assert_bind_params_to_sql_coerced(prepared: true)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
def test_bind_params_to_sql_with_unprepared_statements_coerced
|
|
290
|
-
@connection.unprepared_statement do
|
|
291
|
-
assert_bind_params_to_sql_coerced(prepared: false)
|
|
292
|
-
end
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
private
|
|
296
|
-
|
|
297
|
-
def assert_bind_params_to_sql_coerced(prepared:)
|
|
298
|
-
table = Author.quoted_table_name
|
|
299
|
-
pk = "#{table}.#{Author.quoted_primary_key}"
|
|
300
|
-
|
|
301
|
-
# prepared_statements: true
|
|
302
|
-
#
|
|
303
|
-
# EXEC sp_executesql N'SELECT [authors].* FROM [authors] WHERE [authors].[id] IN (@0, @1, @2) OR [authors].[id] IS NULL)', N'@0 bigint, @1 bigint, @2 bigint', @0 = 1, @1 = 2, @2 = 3
|
|
304
|
-
#
|
|
305
|
-
# prepared_statements: false
|
|
306
|
-
#
|
|
307
|
-
# SELECT [authors].* FROM [authors] WHERE ([authors].[id] IN (1, 2, 3) OR [authors].[id] IS NULL)
|
|
308
|
-
#
|
|
309
|
-
sql_unprepared = "SELECT #{table}.* FROM #{table} WHERE (#{pk} IN (#{bind_params(1..3)}) OR #{pk} IS NULL)"
|
|
310
|
-
sql_prepared = "EXEC sp_executesql N'SELECT #{table}.* FROM #{table} WHERE (#{pk} IN (#{bind_params(1..3)}) OR #{pk} IS NULL)', N'@0 bigint, @1 bigint, @2 bigint', @0 = 1, @1 = 2, @2 = 3"
|
|
311
|
-
|
|
312
|
-
authors = Author.where(id: [1, 2, 3, nil])
|
|
313
|
-
assert_equal sql_unprepared, @connection.to_sql(authors.arel)
|
|
314
|
-
assert_queries_match(prepared ? sql_prepared : sql_unprepared) { assert_equal 3, authors.length }
|
|
315
|
-
|
|
316
|
-
# prepared_statements: true
|
|
317
|
-
#
|
|
318
|
-
# EXEC sp_executesql N'SELECT [authors].* FROM [authors] WHERE [authors].[id] IN (@0, @1, @2)', N'@0 bigint, @1 bigint, @2 bigint', @0 = 1, @1 = 2, @2 = 3
|
|
319
|
-
#
|
|
320
|
-
# prepared_statements: false
|
|
321
|
-
#
|
|
322
|
-
# SELECT [authors].* FROM [authors] WHERE [authors].[id] IN (1, 2, 3)
|
|
323
|
-
#
|
|
324
|
-
sql_unprepared = "SELECT #{table}.* FROM #{table} WHERE #{pk} IN (#{bind_params(1..3)})"
|
|
325
|
-
sql_prepared = "EXEC sp_executesql N'SELECT #{table}.* FROM #{table} WHERE #{pk} IN (#{bind_params(1..3)})', N'@0 bigint, @1 bigint, @2 bigint', @0 = 1, @1 = 2, @2 = 3"
|
|
326
|
-
|
|
327
|
-
authors = Author.where(id: [1, 2, 3, 9223372036854775808])
|
|
328
|
-
assert_equal sql_unprepared, @connection.to_sql(authors.arel)
|
|
329
|
-
assert_queries_match(prepared ? sql_prepared : sql_unprepared) { assert_equal 3, authors.length }
|
|
330
|
-
end
|
|
331
267
|
end
|
|
332
268
|
end
|
|
333
269
|
|
|
@@ -387,7 +323,7 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
|
387
323
|
assert_predicate accounts, :loaded?
|
|
388
324
|
assert_equal expected, accounts.count(:id)
|
|
389
325
|
end
|
|
390
|
-
|
|
326
|
+
|
|
391
327
|
# Fix randomly failing test. The loading of the model's schema was affecting the test.
|
|
392
328
|
coerce_tests! :test_offset_is_kept
|
|
393
329
|
def test_offset_is_kept_coerced
|
|
@@ -508,7 +444,7 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
|
508
444
|
def test_limit_is_kept_coerced
|
|
509
445
|
queries = capture_sql { Account.limit(1).count }
|
|
510
446
|
assert_equal 1, queries.length
|
|
511
|
-
assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY
|
|
447
|
+
assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/, queries.first)
|
|
512
448
|
end
|
|
513
449
|
|
|
514
450
|
# Match SQL Server limit implementation
|
|
@@ -516,7 +452,7 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
|
516
452
|
def test_limit_with_offset_is_kept_coerced
|
|
517
453
|
queries = capture_sql { Account.limit(1).offset(1).count }
|
|
518
454
|
assert_equal 1, queries.length
|
|
519
|
-
assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY
|
|
455
|
+
assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY/, queries.first)
|
|
520
456
|
end
|
|
521
457
|
|
|
522
458
|
# SQL Server needs an alias for the calculated column
|
|
@@ -980,9 +916,9 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
980
916
|
# Assert SQL Server limit implementation
|
|
981
917
|
coerce_tests! :test_take_and_first_and_last_with_integer_should_use_sql_limit
|
|
982
918
|
def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
919
|
+
assert_queries_and_values_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/, [3]) { Topic.take(3).entries }
|
|
920
|
+
assert_queries_and_values_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/, [2]) { Topic.first(2).entries }
|
|
921
|
+
assert_queries_and_values_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/, [5]) { Topic.last(5).entries }
|
|
986
922
|
end
|
|
987
923
|
|
|
988
924
|
# This fails only when run in the full test suite task. Just taking it out of the mix.
|
|
@@ -1013,7 +949,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1013
949
|
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
1014
950
|
coerce_tests! :test_include_on_unloaded_relation_with_match
|
|
1015
951
|
def test_include_on_unloaded_relation_with_match_coerced
|
|
1016
|
-
assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY
|
|
952
|
+
assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY/) do
|
|
1017
953
|
assert_equal true, Customer.where(name: "David").include?(customers(:david))
|
|
1018
954
|
end
|
|
1019
955
|
end
|
|
@@ -1021,7 +957,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1021
957
|
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
1022
958
|
coerce_tests! :test_include_on_unloaded_relation_without_match
|
|
1023
959
|
def test_include_on_unloaded_relation_without_match_coerced
|
|
1024
|
-
assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY
|
|
960
|
+
assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY/) do
|
|
1025
961
|
assert_equal false, Customer.where(name: "David").include?(customers(:mary))
|
|
1026
962
|
end
|
|
1027
963
|
end
|
|
@@ -1029,7 +965,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1029
965
|
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
1030
966
|
coerce_tests! :test_member_on_unloaded_relation_with_match
|
|
1031
967
|
def test_member_on_unloaded_relation_with_match_coerced
|
|
1032
|
-
assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY
|
|
968
|
+
assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY/) do
|
|
1033
969
|
assert_equal true, Customer.where(name: "David").member?(customers(:david))
|
|
1034
970
|
end
|
|
1035
971
|
end
|
|
@@ -1037,7 +973,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1037
973
|
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
1038
974
|
coerce_tests! :test_member_on_unloaded_relation_without_match
|
|
1039
975
|
def test_member_on_unloaded_relation_without_match_coerced
|
|
1040
|
-
assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY
|
|
976
|
+
assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY/) do
|
|
1041
977
|
assert_equal false, Customer.where(name: "David").member?(customers(:mary))
|
|
1042
978
|
end
|
|
1043
979
|
end
|
|
@@ -1052,7 +988,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1052
988
|
assert_equal topics(:third), Topic.last
|
|
1053
989
|
|
|
1054
990
|
c = Topic.lease_connection
|
|
1055
|
-
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.title"))} DESC, #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY
|
|
991
|
+
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.title"))} DESC, #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/i) {
|
|
1056
992
|
Topic.last
|
|
1057
993
|
}
|
|
1058
994
|
ensure
|
|
@@ -1066,7 +1002,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1066
1002
|
Topic.implicit_order_column = "id"
|
|
1067
1003
|
|
|
1068
1004
|
c = Topic.lease_connection
|
|
1069
|
-
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY
|
|
1005
|
+
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/i) {
|
|
1070
1006
|
Topic.last
|
|
1071
1007
|
}
|
|
1072
1008
|
ensure
|
|
@@ -1081,7 +1017,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1081
1017
|
|
|
1082
1018
|
c = NonPrimaryKey.lease_connection
|
|
1083
1019
|
|
|
1084
|
-
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("non_primary_keys.created_at"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY
|
|
1020
|
+
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("non_primary_keys.created_at"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/i) {
|
|
1085
1021
|
NonPrimaryKey.last
|
|
1086
1022
|
}
|
|
1087
1023
|
ensure
|
|
@@ -1091,7 +1027,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1091
1027
|
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
1092
1028
|
coerce_tests! :test_member_on_unloaded_relation_with_composite_primary_key
|
|
1093
1029
|
def test_member_on_unloaded_relation_with_composite_primary_key_coerced
|
|
1094
|
-
assert_queries_match(/1 AS one.* FETCH NEXT @(\d) ROWS ONLY
|
|
1030
|
+
assert_queries_match(/1 AS one.* FETCH NEXT @(\d) ROWS ONLY/) do
|
|
1095
1031
|
book = cpk_books(:cpk_great_author_first_book)
|
|
1096
1032
|
assert Cpk::Book.where(title: "The first book").member?(book)
|
|
1097
1033
|
end
|
|
@@ -1106,7 +1042,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1106
1042
|
quoted_color = Regexp.escape(c.quote_table_name("clothing_items.color"))
|
|
1107
1043
|
quoted_descrption = Regexp.escape(c.quote_table_name("clothing_items.description"))
|
|
1108
1044
|
|
|
1109
|
-
assert_queries_match(/ORDER BY #{quoted_descrption} ASC, #{quoted_type} ASC, #{quoted_color} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY
|
|
1045
|
+
assert_queries_match(/ORDER BY #{quoted_descrption} ASC, #{quoted_type} ASC, #{quoted_color} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
|
|
1110
1046
|
assert_kind_of ClothingItem, ClothingItem.first
|
|
1111
1047
|
end
|
|
1112
1048
|
ensure
|
|
@@ -1120,7 +1056,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1120
1056
|
quoted_type = Regexp.escape(c.quote_table_name("clothing_items.clothing_type"))
|
|
1121
1057
|
quoted_color = Regexp.escape(c.quote_table_name("clothing_items.color"))
|
|
1122
1058
|
|
|
1123
|
-
assert_queries_match(/ORDER BY #{quoted_type} DESC, #{quoted_color} DESC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY
|
|
1059
|
+
assert_queries_match(/ORDER BY #{quoted_type} DESC, #{quoted_color} DESC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
|
|
1124
1060
|
assert_kind_of ClothingItem, ClothingItem.last
|
|
1125
1061
|
end
|
|
1126
1062
|
end
|
|
@@ -1132,7 +1068,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1132
1068
|
quoted_type = Regexp.escape(c.quote_table_name("clothing_items.clothing_type"))
|
|
1133
1069
|
quoted_color = Regexp.escape(c.quote_table_name("clothing_items.color"))
|
|
1134
1070
|
|
|
1135
|
-
assert_queries_match(/ORDER BY #{quoted_type} ASC, #{quoted_color} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY
|
|
1071
|
+
assert_queries_match(/ORDER BY #{quoted_type} ASC, #{quoted_color} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
|
|
1136
1072
|
assert_kind_of ClothingItem, ClothingItem.first
|
|
1137
1073
|
end
|
|
1138
1074
|
end
|
|
@@ -1145,7 +1081,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1145
1081
|
quoted_type = Regexp.escape(c.quote_table_name("clothing_items.clothing_type"))
|
|
1146
1082
|
quoted_color = Regexp.escape(c.quote_table_name("clothing_items.color"))
|
|
1147
1083
|
|
|
1148
|
-
assert_queries_match(/ORDER BY #{quoted_color} ASC, #{quoted_type} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY
|
|
1084
|
+
assert_queries_match(/ORDER BY #{quoted_color} ASC, #{quoted_type} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
|
|
1149
1085
|
assert_kind_of ClothingItem, ClothingItem.first
|
|
1150
1086
|
end
|
|
1151
1087
|
ensure
|
|
@@ -1155,7 +1091,7 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1155
1091
|
# Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
|
|
1156
1092
|
coerce_tests! :test_include_on_unloaded_relation_with_composite_primary_key
|
|
1157
1093
|
def test_include_on_unloaded_relation_with_composite_primary_key_coerced
|
|
1158
|
-
assert_queries_match(/1 AS one.*OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY
|
|
1094
|
+
assert_queries_match(/1 AS one.*OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/) do
|
|
1159
1095
|
book = cpk_books(:cpk_great_author_first_book)
|
|
1160
1096
|
assert Cpk::Book.where(title: "The first book").include?(book)
|
|
1161
1097
|
end
|
|
@@ -1165,11 +1101,11 @@ class FinderTest < ActiveRecord::TestCase
|
|
|
1165
1101
|
coerce_tests! :test_nth_to_last_with_order_uses_limit
|
|
1166
1102
|
def test_nth_to_last_with_order_uses_limit_coerced
|
|
1167
1103
|
c = Topic.lease_connection
|
|
1168
|
-
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET @(\d) ROWS FETCH NEXT @(\d) ROWS ONLY
|
|
1104
|
+
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET @(\d) ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
|
|
1169
1105
|
Topic.second_to_last
|
|
1170
1106
|
end
|
|
1171
1107
|
|
|
1172
|
-
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.updated_at"))} DESC OFFSET @(\d) ROWS FETCH NEXT @(\d) ROWS ONLY
|
|
1108
|
+
assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.updated_at"))} DESC OFFSET @(\d) ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
|
|
1173
1109
|
Topic.order(:updated_at).second_to_last
|
|
1174
1110
|
end
|
|
1175
1111
|
end
|
|
@@ -1217,7 +1153,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
|
|
|
1217
1153
|
def test_has_one_coerced
|
|
1218
1154
|
firm = companies(:first_firm)
|
|
1219
1155
|
first_account = Account.find(1)
|
|
1220
|
-
assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY
|
|
1156
|
+
assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY/) do
|
|
1221
1157
|
assert_equal first_account, firm.account
|
|
1222
1158
|
assert_equal first_account.credit_limit, firm.account.credit_limit
|
|
1223
1159
|
end
|
|
@@ -1229,7 +1165,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
|
|
|
1229
1165
|
coerce_tests! :test_has_one_through_executes_limited_query
|
|
1230
1166
|
def test_has_one_through_executes_limited_query_coerced
|
|
1231
1167
|
boring_club = clubs(:boring_club)
|
|
1232
|
-
assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY
|
|
1168
|
+
assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY/) do
|
|
1233
1169
|
assert_equal boring_club, @member.general_club
|
|
1234
1170
|
end
|
|
1235
1171
|
end
|
|
@@ -1436,7 +1372,7 @@ class RelationTest < ActiveRecord::TestCase
|
|
|
1436
1372
|
# Find any limit via our expression.
|
|
1437
1373
|
coerce_tests! %r{relations don't load all records in #inspect}
|
|
1438
1374
|
def test_relations_dont_load_all_records_in_inspect_coerced
|
|
1439
|
-
assert_queries_match(/NEXT @0 ROWS
|
|
1375
|
+
assert_queries_match(/NEXT @0 ROWS/) do
|
|
1440
1376
|
Post.all.inspect
|
|
1441
1377
|
end
|
|
1442
1378
|
end
|
|
@@ -2124,7 +2060,7 @@ class RelationMergingTest < ActiveRecord::TestCase
|
|
|
2124
2060
|
non_mary_and_bob = Author.where.not(id: [mary, bob])
|
|
2125
2061
|
|
|
2126
2062
|
author_id = Author.lease_connection.quote_table_name("authors.id")
|
|
2127
|
-
assert_queries_match(/WHERE #{Regexp.escape(author_id)} NOT IN \((@\d), \g<1>\)
|
|
2063
|
+
assert_queries_match(/WHERE #{Regexp.escape(author_id)} NOT IN \((@\d), \g<1>\)/) do
|
|
2128
2064
|
assert_equal [david], non_mary_and_bob.merge(non_mary_and_bob)
|
|
2129
2065
|
end
|
|
2130
2066
|
|
|
@@ -2262,14 +2198,6 @@ class LogSubscriberTest < ActiveRecord::TestCase
|
|
|
2262
2198
|
def test_verbose_query_logs_coerced
|
|
2263
2199
|
original_test_verbose_query_logs
|
|
2264
2200
|
end
|
|
2265
|
-
|
|
2266
|
-
# Bindings logged slightly differently.
|
|
2267
|
-
coerce_tests! :test_where_in_binds_logging_include_attribute_names
|
|
2268
|
-
def test_where_in_binds_logging_include_attribute_names_coerced
|
|
2269
|
-
Developer.where(id: [1, 2, 3, 4, 5]).load
|
|
2270
|
-
wait
|
|
2271
|
-
assert_match(%{@0 = 1, @1 = 2, @2 = 3, @3 = 4, @4 = 5 [["id", nil], ["id", nil], ["id", nil], ["id", nil], ["id", nil]]}, @logger.logged(:debug).last)
|
|
2272
|
-
end
|
|
2273
2201
|
end
|
|
2274
2202
|
|
|
2275
2203
|
class ReloadModelsTest < ActiveRecord::TestCase
|
|
@@ -2337,7 +2265,7 @@ class PreloaderTest < ActiveRecord::TestCase
|
|
|
2337
2265
|
|
|
2338
2266
|
c = Cpk::OrderAgreement.lease_connection
|
|
2339
2267
|
order_id_column = Regexp.escape(c.quote_table_name("cpk_order_agreements.order_id"))
|
|
2340
|
-
order_id_constraint = /#{order_id_column} = @0
|
|
2268
|
+
order_id_constraint = /#{order_id_column} = @0$/
|
|
2341
2269
|
expectation = /SELECT.*WHERE.* #{order_id_constraint}/
|
|
2342
2270
|
|
|
2343
2271
|
assert_match(expectation, preload_sql)
|
|
@@ -2361,7 +2289,7 @@ class PreloaderTest < ActiveRecord::TestCase
|
|
|
2361
2289
|
|
|
2362
2290
|
c = Cpk::Order.lease_connection
|
|
2363
2291
|
order_id = Regexp.escape(c.quote_table_name("cpk_orders.id"))
|
|
2364
|
-
order_constraint = /#{order_id} = @0
|
|
2292
|
+
order_constraint = /#{order_id} = @0$/
|
|
2365
2293
|
expectation = /SELECT.*WHERE.* #{order_constraint}/
|
|
2366
2294
|
|
|
2367
2295
|
assert_match(expectation, preload_sql)
|
|
@@ -2432,7 +2360,7 @@ class QueryLogsTest < ActiveRecord::TestCase
|
|
|
2432
2360
|
coerce_tests! :test_sql_commenter_format
|
|
2433
2361
|
def test_sql_commenter_format_coerced
|
|
2434
2362
|
ActiveRecord::QueryLogs.update_formatter(:sqlcommenter)
|
|
2435
|
-
assert_queries_match(%r{/\*application='
|
|
2363
|
+
assert_queries_match(%r{/\*application='active_record'\*/}) do
|
|
2436
2364
|
Dashboard.first
|
|
2437
2365
|
end
|
|
2438
2366
|
end
|
|
@@ -2447,7 +2375,7 @@ class QueryLogsTest < ActiveRecord::TestCase
|
|
|
2447
2375
|
{ tracestate: "congo=t61rcWkgMzE,rojo=00f067aa0ba902b7", custom_proc: -> { "Joe's Shack" } },
|
|
2448
2376
|
]
|
|
2449
2377
|
|
|
2450
|
-
assert_queries_match(%r{custom_proc='
|
|
2378
|
+
assert_queries_match(%r{custom_proc='Joe%27s%20Shack',tracestate='congo%3Dt61rcWkgMzE%2Crojo%3D00f067aa0ba902b7'\*/}) do
|
|
2451
2379
|
Dashboard.first
|
|
2452
2380
|
end
|
|
2453
2381
|
end
|
|
@@ -2462,7 +2390,7 @@ class QueryLogsTest < ActiveRecord::TestCase
|
|
|
2462
2390
|
{ custom_proc: -> { 1234 } },
|
|
2463
2391
|
]
|
|
2464
2392
|
|
|
2465
|
-
assert_queries_match(%r{custom_proc='
|
|
2393
|
+
assert_queries_match(%r{custom_proc='1234'\*/}) do
|
|
2466
2394
|
Dashboard.first
|
|
2467
2395
|
end
|
|
2468
2396
|
end
|
|
@@ -2481,7 +2409,7 @@ class QueryLogsTest < ActiveRecord::TestCase
|
|
|
2481
2409
|
},
|
|
2482
2410
|
]
|
|
2483
2411
|
|
|
2484
|
-
assert_queries_match(%r{custom_proc='
|
|
2412
|
+
assert_queries_match(%r{custom_proc='Joe%27s%20Shack',string='value',tracestate='congo%3Dt61rcWkgMzE%2Crojo%3D00f067aa0ba902b7'\*/}) do
|
|
2485
2413
|
Dashboard.first
|
|
2486
2414
|
end
|
|
2487
2415
|
end
|
|
@@ -2705,7 +2633,7 @@ class ExplainTest < ActiveRecord::TestCase
|
|
|
2705
2633
|
def test_relation_explain_with_first_coerced
|
|
2706
2634
|
expected_query = capture_sql {
|
|
2707
2635
|
Car.all.first
|
|
2708
|
-
}.first[/
|
|
2636
|
+
}.first[/(.*?) NEXT/, 1]
|
|
2709
2637
|
message = Car.all.explain.first
|
|
2710
2638
|
assert_match(/^EXPLAIN/, message)
|
|
2711
2639
|
assert_match(expected_query, message)
|
|
@@ -2716,7 +2644,7 @@ class ExplainTest < ActiveRecord::TestCase
|
|
|
2716
2644
|
def test_relation_explain_with_last_coerced
|
|
2717
2645
|
expected_query = capture_sql {
|
|
2718
2646
|
Car.all.last
|
|
2719
|
-
}.first[/
|
|
2647
|
+
}.first[/(.*?) NEXT/, 1]
|
|
2720
2648
|
expected_query = expected_query
|
|
2721
2649
|
message = Car.all.explain.last
|
|
2722
2650
|
|
|
@@ -29,7 +29,7 @@ class OptimizerHitsTestSQLServer < ActiveRecord::TestCase
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "support subqueries" do
|
|
32
|
-
assert_queries_match(%r{
|
|
32
|
+
assert_queries_match(%r{SELECT COUNT\(count_column\) FROM \(SELECT .*\) subquery_for_count OPTION \(MAXDOP 2\)}) do
|
|
33
33
|
companies = Company.optimizer_hints("MAXDOP 2")
|
|
34
34
|
companies = companies.select(:id).where(firm_id: [0, 1]).limit(3)
|
|
35
35
|
assert_equal 3, companies.count
|
|
@@ -28,13 +28,13 @@ class ShowplanTestSQLServer < ActiveRecord::TestCase
|
|
|
28
28
|
|
|
29
29
|
it "from array condition using index" do
|
|
30
30
|
plan = Car.where(id: [1, 2]).explain.inspect
|
|
31
|
-
_(plan).must_include "SELECT [cars].* FROM [cars] WHERE [cars].[id]
|
|
31
|
+
_(plan).must_include "SELECT [cars].* FROM [cars] WHERE [cars].[id]"
|
|
32
32
|
_(plan).must_include "Clustered Index Seek", "make sure we do not showplan the sp_executesql"
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it "from array condition" do
|
|
36
36
|
plan = Car.where(name: ["honda", "zyke"]).explain.inspect
|
|
37
|
-
_(plan).must_include " SELECT [cars].* FROM [cars] WHERE [cars].[name]
|
|
37
|
+
_(plan).must_include " SELECT [cars].* FROM [cars] WHERE [cars].[name]"
|
|
38
38
|
_(plan).must_include "Clustered Index Scan", "make sure we do not showplan the sp_executesql"
|
|
39
39
|
end
|
|
40
40
|
end
|
|
@@ -116,16 +116,16 @@ class SpecificSchemaTestSQLServer < ActiveRecord::TestCase
|
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
118
|
# Using ActiveRecord's quoted_id feature for objects.
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
assert_queries_and_values_match(/.*/, ["'T'", 1]) { SSTestDatatypeMigration.where(char_col: value.new).first }
|
|
120
|
+
assert_queries_and_values_match(/.*/, ["'T'", 1]) { SSTestDatatypeMigration.where(varchar_col: value.new).first }
|
|
121
121
|
# Using our custom char type data.
|
|
122
122
|
type = ActiveRecord::Type::SQLServer::Char
|
|
123
123
|
data = ActiveRecord::Type::SQLServer::Data
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
assert_queries_and_values_match(/.*/, ["'T'", 1]) { SSTestDatatypeMigration.where(char_col: data.new("T", type.new)).first }
|
|
125
|
+
assert_queries_and_values_match(/.*/, ["'T'", 1]) { SSTestDatatypeMigration.where(varchar_col: data.new("T", type.new)).first }
|
|
126
126
|
# Taking care of everything.
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
assert_queries_and_values_match(/.*/, ["'T'", 1]) { SSTestDatatypeMigration.where(char_col: "T").first }
|
|
128
|
+
assert_queries_and_values_match(/.*/, ["'T'", 1]) { SSTestDatatypeMigration.where(varchar_col: "T").first }
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
it "can update and hence properly quoted non-national char/varchar columns" do
|
|
@@ -22,6 +22,28 @@ module ARTest
|
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def assert_queries_and_values_match(match, bound_values=[], count: nil, &block)
|
|
26
|
+
ActiveRecord::Base.lease_connection.materialize_transactions
|
|
27
|
+
|
|
28
|
+
counter = ActiveRecord::Assertions::QueryAssertions::SQLCounter.new
|
|
29
|
+
ActiveSupport::Notifications.subscribed(counter, "sql.active_record") do
|
|
30
|
+
result = _assert_nothing_raised_or_warn("assert_queries_match", &block)
|
|
31
|
+
queries = counter.log_full
|
|
32
|
+
matched_queries = queries.select do |query, values|
|
|
33
|
+
values = values.map { |v| v.respond_to?(:quoted) ? v.quoted : v }
|
|
34
|
+
match === query && bound_values === values
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if count
|
|
38
|
+
assert_equal count, matched_queries.size, "#{matched_queries.size} instead of #{count} queries were executed.#{count.log.empty? ? '' : "\nQueries:\n#{counter.log.join("\n")}"}"
|
|
39
|
+
else
|
|
40
|
+
assert_operator matched_queries.size, :>=, 1, "1 or more queries expected, but none were executed.#{counter.log.empty? ? '' : "\nQueries:\n#{counter.log.join("\n")}"}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
result
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
25
47
|
private
|
|
26
48
|
|
|
27
49
|
# Rails tests expect a save-point to be created and released. SQL Server does not release
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-sqlserver-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 7.2.
|
|
4
|
+
version: 7.2.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ken Collins
|
|
@@ -241,8 +241,8 @@ licenses:
|
|
|
241
241
|
- MIT
|
|
242
242
|
metadata:
|
|
243
243
|
bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
|
|
244
|
-
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.2.
|
|
245
|
-
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.2.
|
|
244
|
+
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.2.9/CHANGELOG.md
|
|
245
|
+
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.2.9
|
|
246
246
|
rdoc_options: []
|
|
247
247
|
require_paths:
|
|
248
248
|
- lib
|