activerecord-sqlserver-adapter 8.0.9 → 8.0.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 751a7342bce3b73b0a34f0a28a4d534fdfe546802dadc5705248af88027284af
4
- data.tar.gz: 924a275891a2097967a8c08b6621084891747fa697dc966cfe782720af08dfa0
3
+ metadata.gz: e6c3e4f4ea64ada810516060935068217cc32d43b160f33fec283e6a81889168
4
+ data.tar.gz: efa5b8818e45ca35a610a850ed44253f4682f83267a46822b23604fd78655e94
5
5
  SHA512:
6
- metadata.gz: ab4f95b51a6cf2479ffe9df506b588232b1f7206c435bd79c12e8f0b144f33daeec56a8ed92f22d5be3e39468360339a1a80b05f006371fc361d00091a54f779
7
- data.tar.gz: d4cbe509ec55ed661c7ba1abeed3e926800b2ef4d5fbc134fd033c1c5a96e85fefbb4a26f94eda91b58969878d89d1e1813607b6fa6c63496ae6baa6500cd51b
6
+ metadata.gz: 9e8f1d1a400b6a624d22ae77f6b8d70a31e967790cdd30be86d476f94af7e45ea913d5278a02fddebcd4ee30749c0277c4624e61b6f4ec521403a966f5dc2f96
7
+ data.tar.gz: 78ff679e5aea744e81da238916812c364b7fef69e6b7e4cc2bbb4a59f96d256cd62f70ca886504fe815723aa12d2e91efef88793c92cbe6c494f58dc78f3c041
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## v8.0.10
2
+
3
+ #### Fixed
4
+
5
+ - [#1370](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1370) Fixed query logging so that filter parameters are respected.
6
+
1
7
  ## v8.0.9
2
8
 
3
9
  #### Fixed
data/VERSION CHANGED
@@ -1 +1 @@
1
- 8.0.9
1
+ 8.0.10
@@ -14,6 +14,11 @@ module ActiveRecord
14
14
  end
15
15
 
16
16
  def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch:)
17
+ unless binds.nil? || binds.empty?
18
+ types, params = sp_executesql_types_and_parameters(binds)
19
+ sql = sp_executesql_sql(sql, types, params, notification_payload[:name])
20
+ end
21
+
17
22
  result = if id_insert_table_name = query_requires_identity_insert?(sql)
18
23
  with_identity_insert_enabled(id_insert_table_name, raw_connection) do
19
24
  internal_exec_sql_query(sql, raw_connection)
@@ -40,15 +45,6 @@ module ActiveRecord
40
45
  raw_result.first[column_name]
41
46
  end
42
47
 
43
- def raw_execute(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, batch: false)
44
- unless binds.nil? || binds.empty?
45
- types, params = sp_executesql_types_and_parameters(binds)
46
- sql = sp_executesql_sql(sql, types, params, name)
47
- end
48
-
49
- super
50
- end
51
-
52
48
  def internal_exec_sql_query(sql, conn)
53
49
  handle = internal_raw_execute(sql, conn)
54
50
  handle_to_names_and_values(handle, ar_result: true)
@@ -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(.)*@\1 = 1/) do
251
+ assert_queries_and_values_match(/FETCH NEXT @3 ROWS ONLY/, ['Firm', 'Agency', 1, 1]) 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
 
@@ -391,7 +327,7 @@ class CalculationsTest < ActiveRecord::TestCase
391
327
  assert_predicate accounts, :loaded?
392
328
  assert_equal expected, accounts.count(:id)
393
329
  end
394
-
330
+
395
331
  # Fix randomly failing test. The loading of the model's schema was affecting the test.
396
332
  coerce_tests! :test_offset_is_kept
397
333
  def test_offset_is_kept_coerced
@@ -512,7 +448,7 @@ class CalculationsTest < ActiveRecord::TestCase
512
448
  def test_limit_is_kept_coerced
513
449
  queries = capture_sql { Account.limit(1).count }
514
450
  assert_equal 1, queries.length
515
- assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/, queries.first)
451
+ assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/, queries.first)
516
452
  end
517
453
 
518
454
  # Match SQL Server limit implementation
@@ -520,7 +456,7 @@ class CalculationsTest < ActiveRecord::TestCase
520
456
  def test_limit_with_offset_is_kept_coerced
521
457
  queries = capture_sql { Account.limit(1).offset(1).count }
522
458
  assert_equal 1, queries.length
523
- assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY.*@0 = 1, @1 = 1/, queries.first)
459
+ assert_match(/ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY/, queries.first)
524
460
  end
525
461
 
526
462
  # SQL Server needs an alias for the calculated column
@@ -987,9 +923,9 @@ class FinderTest < ActiveRecord::TestCase
987
923
  # Assert SQL Server limit implementation
988
924
  coerce_tests! :test_take_and_first_and_last_with_integer_should_use_sql_limit
989
925
  def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
990
- assert_queries_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 3/) { Topic.take(3).entries }
991
- assert_queries_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 2/) { Topic.first(2).entries }
992
- assert_queries_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 5/) { Topic.last(5).entries }
926
+ assert_queries_and_values_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/, [3]) { Topic.take(3).entries }
927
+ assert_queries_and_values_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/, [2]) { Topic.first(2).entries }
928
+ assert_queries_and_values_match(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/, [5]) { Topic.last(5).entries }
993
929
  end
994
930
 
995
931
  # This fails only when run in the full test suite task. Just taking it out of the mix.
@@ -1020,7 +956,7 @@ class FinderTest < ActiveRecord::TestCase
1020
956
  # Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
1021
957
  coerce_tests! :test_include_on_unloaded_relation_with_match
1022
958
  def test_include_on_unloaded_relation_with_match_coerced
1023
- assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY.*@2 = 1/) do
959
+ assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY/) do
1024
960
  assert_equal true, Customer.where(name: "David").include?(customers(:david))
1025
961
  end
1026
962
  end
@@ -1028,7 +964,7 @@ class FinderTest < ActiveRecord::TestCase
1028
964
  # Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
1029
965
  coerce_tests! :test_include_on_unloaded_relation_without_match
1030
966
  def test_include_on_unloaded_relation_without_match_coerced
1031
- assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY.*@2 = 1/) do
967
+ assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY/) do
1032
968
  assert_equal false, Customer.where(name: "David").include?(customers(:mary))
1033
969
  end
1034
970
  end
@@ -1036,7 +972,7 @@ class FinderTest < ActiveRecord::TestCase
1036
972
  # Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
1037
973
  coerce_tests! :test_member_on_unloaded_relation_with_match
1038
974
  def test_member_on_unloaded_relation_with_match_coerced
1039
- assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY.*@2 = 1/) do
975
+ assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY/) do
1040
976
  assert_equal true, Customer.where(name: "David").member?(customers(:david))
1041
977
  end
1042
978
  end
@@ -1044,7 +980,7 @@ class FinderTest < ActiveRecord::TestCase
1044
980
  # Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
1045
981
  coerce_tests! :test_member_on_unloaded_relation_without_match
1046
982
  def test_member_on_unloaded_relation_without_match_coerced
1047
- assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY.*@2 = 1/) do
983
+ assert_queries_match(/1 AS one.*FETCH NEXT @2 ROWS ONLY/) do
1048
984
  assert_equal false, Customer.where(name: "David").member?(customers(:mary))
1049
985
  end
1050
986
  end
@@ -1059,7 +995,7 @@ class FinderTest < ActiveRecord::TestCase
1059
995
  assert_equal topics(:third), Topic.last
1060
996
 
1061
997
  c = Topic.lease_connection
1062
- 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.*@0 = 1/i) {
998
+ assert_queries_and_values_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, [1]) {
1063
999
  Topic.last
1064
1000
  }
1065
1001
  ensure
@@ -1073,7 +1009,7 @@ class FinderTest < ActiveRecord::TestCase
1073
1009
  Topic.implicit_order_column = "id"
1074
1010
 
1075
1011
  c = Topic.lease_connection
1076
- assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/i) {
1012
+ assert_queries_and_values_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/i, [1]) {
1077
1013
  Topic.last
1078
1014
  }
1079
1015
  ensure
@@ -1088,7 +1024,7 @@ class FinderTest < ActiveRecord::TestCase
1088
1024
 
1089
1025
  c = NonPrimaryKey.lease_connection
1090
1026
 
1091
- 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.*@0 = 1/i) {
1027
+ assert_queries_and_values_match(/ORDER BY #{Regexp.escape(c.quote_table_name("non_primary_keys.created_at"))} DESC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY/i, [1]) {
1092
1028
  NonPrimaryKey.last
1093
1029
  }
1094
1030
  ensure
@@ -1098,7 +1034,7 @@ class FinderTest < ActiveRecord::TestCase
1098
1034
  # Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
1099
1035
  coerce_tests! :test_member_on_unloaded_relation_with_composite_primary_key
1100
1036
  def test_member_on_unloaded_relation_with_composite_primary_key_coerced
1101
- assert_queries_match(/1 AS one.* FETCH NEXT @(\d) ROWS ONLY.*@\1 = 1/) do
1037
+ assert_queries_match(/1 AS one.* FETCH NEXT @3 ROWS ONLY/) do
1102
1038
  book = cpk_books(:cpk_great_author_first_book)
1103
1039
  assert Cpk::Book.where(title: "The first book").member?(book)
1104
1040
  end
@@ -1113,7 +1049,7 @@ class FinderTest < ActiveRecord::TestCase
1113
1049
  quoted_color = Regexp.escape(c.quote_table_name("clothing_items.color"))
1114
1050
  quoted_descrption = Regexp.escape(c.quote_table_name("clothing_items.description"))
1115
1051
 
1116
- assert_queries_match(/ORDER BY #{quoted_descrption} ASC, #{quoted_type} ASC, #{quoted_color} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY.*@\1 = 1/i) do
1052
+ assert_queries_match(/ORDER BY #{quoted_descrption} ASC, #{quoted_type} ASC, #{quoted_color} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
1117
1053
  assert_kind_of ClothingItem, ClothingItem.first
1118
1054
  end
1119
1055
  ensure
@@ -1127,7 +1063,7 @@ class FinderTest < ActiveRecord::TestCase
1127
1063
  quoted_type = Regexp.escape(c.quote_table_name("clothing_items.clothing_type"))
1128
1064
  quoted_color = Regexp.escape(c.quote_table_name("clothing_items.color"))
1129
1065
 
1130
- assert_queries_match(/ORDER BY #{quoted_type} DESC, #{quoted_color} DESC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY.*@\1 = 1/i) do
1066
+ assert_queries_match(/ORDER BY #{quoted_type} DESC, #{quoted_color} DESC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
1131
1067
  assert_kind_of ClothingItem, ClothingItem.last
1132
1068
  end
1133
1069
  end
@@ -1139,7 +1075,7 @@ class FinderTest < ActiveRecord::TestCase
1139
1075
  quoted_type = Regexp.escape(c.quote_table_name("clothing_items.clothing_type"))
1140
1076
  quoted_color = Regexp.escape(c.quote_table_name("clothing_items.color"))
1141
1077
 
1142
- assert_queries_match(/ORDER BY #{quoted_type} ASC, #{quoted_color} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY.*@\1 = 1/i) do
1078
+ assert_queries_match(/ORDER BY #{quoted_type} ASC, #{quoted_color} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
1143
1079
  assert_kind_of ClothingItem, ClothingItem.first
1144
1080
  end
1145
1081
  end
@@ -1152,7 +1088,7 @@ class FinderTest < ActiveRecord::TestCase
1152
1088
  quoted_type = Regexp.escape(c.quote_table_name("clothing_items.clothing_type"))
1153
1089
  quoted_color = Regexp.escape(c.quote_table_name("clothing_items.color"))
1154
1090
 
1155
- assert_queries_match(/ORDER BY #{quoted_color} ASC, #{quoted_type} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY.*@\1 = 1/i) do
1091
+ assert_queries_match(/ORDER BY #{quoted_color} ASC, #{quoted_type} ASC OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
1156
1092
  assert_kind_of ClothingItem, ClothingItem.first
1157
1093
  end
1158
1094
  ensure
@@ -1162,7 +1098,7 @@ class FinderTest < ActiveRecord::TestCase
1162
1098
  # Check for `FETCH NEXT x ROWS` rather then `LIMIT`.
1163
1099
  coerce_tests! :test_include_on_unloaded_relation_with_composite_primary_key
1164
1100
  def test_include_on_unloaded_relation_with_composite_primary_key_coerced
1165
- assert_queries_match(/1 AS one.*OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY.*@\1 = 1/) do
1101
+ assert_queries_match(/1 AS one.*OFFSET 0 ROWS FETCH NEXT @(\d) ROWS ONLY/) do
1166
1102
  book = cpk_books(:cpk_great_author_first_book)
1167
1103
  assert Cpk::Book.where(title: "The first book").include?(book)
1168
1104
  end
@@ -1172,11 +1108,11 @@ class FinderTest < ActiveRecord::TestCase
1172
1108
  coerce_tests! :test_nth_to_last_with_order_uses_limit
1173
1109
  def test_nth_to_last_with_order_uses_limit_coerced
1174
1110
  c = Topic.lease_connection
1175
- assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET @(\d) ROWS FETCH NEXT @(\d) ROWS ONLY.*@\1 = 1.*@\2 = 1/i) do
1111
+ assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.id"))} DESC OFFSET @(\d) ROWS FETCH NEXT @(\d) ROWS ONLY/i) do
1176
1112
  Topic.second_to_last
1177
1113
  end
1178
1114
 
1179
- assert_queries_match(/ORDER BY #{Regexp.escape(c.quote_table_name("topics.updated_at"))} DESC OFFSET @(\d) ROWS FETCH NEXT @(\d) ROWS ONLY.*@\1 = 1.*@\2 = 1/i) do
1115
+ 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
1180
1116
  Topic.order(:updated_at).second_to_last
1181
1117
  end
1182
1118
  end
@@ -1227,7 +1163,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
1227
1163
  def test_has_one_coerced
1228
1164
  firm = companies(:first_firm)
1229
1165
  first_account = Account.find(1)
1230
- assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY(.)*@\1 = 1/) do
1166
+ assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY/) do
1231
1167
  assert_equal first_account, firm.account
1232
1168
  assert_equal first_account.credit_limit, firm.account.credit_limit
1233
1169
  end
@@ -1239,7 +1175,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
1239
1175
  coerce_tests! :test_has_one_through_executes_limited_query
1240
1176
  def test_has_one_through_executes_limited_query_coerced
1241
1177
  boring_club = clubs(:boring_club)
1242
- assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY(.)*@\1 = 1/) do
1178
+ assert_queries_match(/FETCH NEXT @(\d) ROWS ONLY/) do
1243
1179
  assert_equal boring_club, @member.general_club
1244
1180
  end
1245
1181
  end
@@ -1460,7 +1396,7 @@ class RelationTest < ActiveRecord::TestCase
1460
1396
  # Find any limit via our expression.
1461
1397
  coerce_tests! %r{relations don't load all records in #inspect}
1462
1398
  def test_relations_dont_load_all_records_in_inspect_coerced
1463
- assert_queries_match(/NEXT @0 ROWS.*@0 = \d+/) do
1399
+ assert_queries_match(/NEXT @0 ROWS/) do
1464
1400
  Post.all.inspect
1465
1401
  end
1466
1402
  end
@@ -1568,10 +1504,10 @@ class SchemaDumperTest < ActiveRecord::TestCase
1568
1504
 
1569
1505
  schema_info = ActiveRecord::Base.lease_connection.dump_schema_information
1570
1506
  expected = <<~STR
1571
- INSERT INTO #{ActiveRecord::Base.lease_connection.quote_table_name("schema_migrations")} (version) VALUES
1572
- (N'20100301010101'),
1573
- (N'20100201010101'),
1574
- (N'20100101010101');
1507
+ INSERT INTO #{ActiveRecord::Base.lease_connection.quote_table_name("schema_migrations")} (version) VALUES
1508
+ (N'20100301010101'),
1509
+ (N'20100201010101'),
1510
+ (N'20100101010101');
1575
1511
  STR
1576
1512
  assert_equal expected.strip, schema_info
1577
1513
  ensure
@@ -2148,7 +2084,7 @@ class RelationMergingTest < ActiveRecord::TestCase
2148
2084
  non_mary_and_bob = Author.where.not(id: [mary, bob])
2149
2085
 
2150
2086
  author_id = Author.lease_connection.quote_table_name("authors.id")
2151
- assert_queries_match(/WHERE #{Regexp.escape(author_id)} NOT IN \((@\d), \g<1>\)'/) do
2087
+ assert_queries_match(/WHERE #{Regexp.escape(author_id)} NOT IN \((@\d), \g<1>\)/) do
2152
2088
  assert_equal [david], non_mary_and_bob.merge(non_mary_and_bob)
2153
2089
  end
2154
2090
 
@@ -2313,7 +2249,7 @@ class PreloaderTest < ActiveRecord::TestCase
2313
2249
 
2314
2250
  c = Cpk::OrderAgreement.lease_connection
2315
2251
  order_id_column = Regexp.escape(c.quote_table_name("cpk_order_agreements.order_id"))
2316
- order_id_constraint = /#{order_id_column} = @0.*@0 = \d+$/
2252
+ order_id_constraint = /#{order_id_column} = @0$/
2317
2253
  expectation = /SELECT.*WHERE.* #{order_id_constraint}/
2318
2254
 
2319
2255
  assert_match(expectation, preload_sql)
@@ -2337,7 +2273,7 @@ class PreloaderTest < ActiveRecord::TestCase
2337
2273
 
2338
2274
  c = Cpk::Order.lease_connection
2339
2275
  order_id = Regexp.escape(c.quote_table_name("cpk_orders.id"))
2340
- order_constraint = /#{order_id} = @0.*@0 = \d+$/
2276
+ order_constraint = /#{order_id} = @0$/
2341
2277
  expectation = /SELECT.*WHERE.* #{order_constraint}/
2342
2278
 
2343
2279
  assert_match(expectation, preload_sql)
@@ -2404,66 +2340,6 @@ end
2404
2340
 
2405
2341
  require "models/dashboard"
2406
2342
  class QueryLogsTest < ActiveRecord::TestCase
2407
- # SQL requires double single-quotes.
2408
- coerce_tests! :test_sql_commenter_format
2409
- def test_sql_commenter_format_coerced
2410
- ActiveRecord::QueryLogs.tags_formatter = :sqlcommenter
2411
- ActiveRecord::QueryLogs.tags = [:application]
2412
-
2413
- assert_queries_match(%r{/\*application=''active_record''\*/}) do
2414
- Dashboard.first
2415
- end
2416
- end
2417
-
2418
- # SQL requires double single-quotes.
2419
- coerce_tests! :test_sqlcommenter_format_value
2420
- def test_sqlcommenter_format_value_coerced
2421
- ActiveRecord::QueryLogs.tags_formatter = :sqlcommenter
2422
-
2423
- ActiveRecord::QueryLogs.tags = [
2424
- :application,
2425
- { tracestate: "congo=t61rcWkgMzE,rojo=00f067aa0ba902b7", custom_proc: -> { "Joe's Shack" } },
2426
- ]
2427
-
2428
- assert_queries_match(%r{custom_proc=''Joe%27s%20Shack'',tracestate=''congo%3Dt61rcWkgMzE%2Crojo%3D00f067aa0ba902b7''\*/}) do
2429
- Dashboard.first
2430
- end
2431
- end
2432
-
2433
- # SQL requires double single-quotes.
2434
- coerce_tests! :test_sqlcommenter_format_value_string_coercible
2435
- def test_sqlcommenter_format_value_string_coercible_coerced
2436
- ActiveRecord::QueryLogs.tags_formatter = :sqlcommenter
2437
-
2438
- ActiveRecord::QueryLogs.tags = [
2439
- :application,
2440
- { custom_proc: -> { 1234 } },
2441
- ]
2442
-
2443
- assert_queries_match(%r{custom_proc=''1234''\*/}) do
2444
- Dashboard.first
2445
- end
2446
- end
2447
-
2448
- # SQL requires double single-quotes.
2449
- coerce_tests! :test_sqlcommenter_format_allows_string_keys
2450
- def test_sqlcommenter_format_allows_string_keys_coerced
2451
- ActiveRecord::QueryLogs.tags_formatter = :sqlcommenter
2452
-
2453
- ActiveRecord::QueryLogs.tags = [
2454
- :application,
2455
- {
2456
- "string" => "value",
2457
- tracestate: "congo=t61rcWkgMzE,rojo=00f067aa0ba902b7",
2458
- custom_proc: -> { "Joe's Shack" }
2459
- },
2460
- ]
2461
-
2462
- assert_queries_match(%r{custom_proc=''Joe%27s%20Shack'',string=''value'',tracestate=''congo%3Dt61rcWkgMzE%2Crojo%3D00f067aa0ba902b7''\*/}) do
2463
- Dashboard.first
2464
- end
2465
- end
2466
-
2467
2343
  # Invalid character encoding causes `ActiveRecord::StatementInvalid` error similar to Postgres.
2468
2344
  coerce_tests! :test_invalid_encoding_query
2469
2345
  def test_invalid_encoding_query_coerced
@@ -2712,33 +2588,6 @@ module ActiveRecord
2712
2588
  end
2713
2589
  end
2714
2590
 
2715
- require "models/car"
2716
- class ExplainTest < ActiveRecord::TestCase
2717
- # Expected query slightly different from because of 'sp_executesql' and query parameters.
2718
- coerce_tests! :test_relation_explain_with_first
2719
- def test_relation_explain_with_first_coerced
2720
- expected_query = capture_sql {
2721
- Car.all.first
2722
- }.first[/EXEC sp_executesql N'(.*?) NEXT/, 1]
2723
- message = Car.all.explain.first
2724
- assert_match(/^EXPLAIN/, message)
2725
- assert_match(expected_query, message)
2726
- end
2727
-
2728
- # Expected query slightly different from because of 'sp_executesql' and query parameters.
2729
- coerce_tests! :test_relation_explain_with_last
2730
- def test_relation_explain_with_last_coerced
2731
- expected_query = capture_sql {
2732
- Car.all.last
2733
- }.first[/EXEC sp_executesql N'(.*?) NEXT/, 1]
2734
- expected_query = expected_query
2735
- message = Car.all.explain.last
2736
-
2737
- assert_match(/^EXPLAIN/, message)
2738
- assert_match(expected_query, message)
2739
- end
2740
- end
2741
-
2742
2591
  module ActiveRecord
2743
2592
  module Assertions
2744
2593
  class QueryAssertionsTest < ActiveSupport::TestCase
@@ -29,7 +29,7 @@ class OptimizerHitsTestSQLServer < ActiveRecord::TestCase
29
29
  end
30
30
 
31
31
  it "support subqueries" do
32
- assert_queries_match(%r{.*'SELECT COUNT\(count_column\) FROM \(SELECT .*\) subquery_for_count OPTION \(MAXDOP 2\)'.*}) do
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] IN (1, 2)"
31
+ _(plan).must_include "SELECT [cars].* FROM [cars] WHERE [cars].[id] IN (@0, @1)"
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] IN (N'honda', N'zyke')"
37
+ _(plan).must_include " SELECT [cars].* FROM [cars] WHERE [cars].[name] IN (@0, @1)"
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
- assert_queries_match(/@0 = 'T'/) { SSTestDatatypeMigration.where(char_col: value.new).first }
120
- assert_queries_match(/@0 = 'T'/) { SSTestDatatypeMigration.where(varchar_col: value.new).first }
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
- assert_queries_match(/@0 = 'T'/) { SSTestDatatypeMigration.where(char_col: data.new("T", type.new)).first }
125
- assert_queries_match(/@0 = 'T'/) { SSTestDatatypeMigration.where(varchar_col: data.new("T", type.new)).first }
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
- assert_queries_match(/@0 = 'T'/) { SSTestDatatypeMigration.where(char_col: "T").first }
128
- assert_queries_match(/@0 = 'T'/) { SSTestDatatypeMigration.where(varchar_col: "T").first }
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: 8.0.9
4
+ version: 8.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken Collins
@@ -243,8 +243,8 @@ licenses:
243
243
  - MIT
244
244
  metadata:
245
245
  bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
246
- changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v8.0.9/CHANGELOG.md
247
- source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v8.0.9
246
+ changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v8.0.10/CHANGELOG.md
247
+ source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v8.0.10
248
248
  rdoc_options: []
249
249
  require_paths:
250
250
  - lib