activerecord-jdbcsqlserver-adapter 50.1.0 → 51.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.travis.yml +4 -5
  4. data/BACKERS.md +32 -0
  5. data/CHANGELOG.md +21 -87
  6. data/README.md +2 -3
  7. data/VERSION +1 -1
  8. data/activerecord-jdbcsqlserver-adapter.gemspec +3 -2
  9. data/appveyor.yml +1 -1
  10. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +3 -1
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -1
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +55 -0
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +4 -2
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +5 -3
  15. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +41 -18
  16. data/lib/active_record/connection_adapters/sqlserver/jdbc_overrides.rb +2 -12
  17. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -0
  18. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +21 -0
  19. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +72 -52
  20. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +15 -7
  21. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +0 -4
  22. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +5 -0
  23. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +3 -6
  24. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +27 -10
  25. data/lib/active_record/tasks/sqlserver_database_tasks.rb +2 -2
  26. data/lib/activerecord-jdbcsqlserver-adapter.rb +1 -1
  27. data/lib/arel/visitors/sqlserver.rb +16 -3
  28. data/test/bin/setup.sh +19 -0
  29. data/test/cases/adapter_test_sqlserver.rb +17 -20
  30. data/test/cases/coerced_tests.rb +117 -11
  31. data/test/cases/column_test_sqlserver.rb +1 -1
  32. data/test/cases/helper_sqlserver.rb +6 -1
  33. data/test/cases/pessimistic_locking_test_sqlserver.rb +28 -11
  34. data/test/cases/schema_dumper_test_sqlserver.rb +10 -10
  35. data/test/cases/specific_schema_test_sqlserver.rb +0 -6
  36. data/test/cases/trigger_test_sqlserver.rb +31 -0
  37. data/test/config.yml +2 -2
  38. data/test/models/sqlserver/trigger.rb +7 -0
  39. data/test/models/sqlserver/trigger_history.rb +3 -0
  40. data/test/schema/sqlserver_specific_schema.rb +39 -5
  41. data/test/support/sql_counter_sqlserver.rb +3 -2
  42. metadata +23 -16
  43. data/RAILS5-TODO.md +0 -5
  44. data/lib/jdbc_mssql_driver_loader.rb +0 -22
  45. data/test/models/sqlserver/dot_table_name.rb +0 -3
@@ -48,7 +48,7 @@ module ActiveRecord
48
48
  create true
49
49
  end
50
50
 
51
- def structure_dump(filename)
51
+ def structure_dump(filename, extra_flags)
52
52
  command = [
53
53
  "defncopy",
54
54
  "-S #{Shellwords.escape(configuration['host'])}",
@@ -71,7 +71,7 @@ module ActiveRecord
71
71
  File.open(filename, "w") { |file| file.puts dump }
72
72
  end
73
73
 
74
- def structure_load(filename)
74
+ def structure_load(filename, extra_flags)
75
75
  connection.execute File.read(filename)
76
76
  end
77
77
 
@@ -2,7 +2,7 @@
2
2
  require 'active_record/connection_adapters/sqlserver/core_ext/date_time'
3
3
 
4
4
  # Load the jar file for the jdbc driver
5
- require_relative './jdbc_mssql_driver_loader'
5
+ require 'jdbc/mssql'
6
6
 
7
7
  # Standadard arjdbc functionality
8
8
  require 'arjdbc/abstract/connection_management'
@@ -95,17 +95,29 @@ module Arel
95
95
  collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector
96
96
  end
97
97
  if o.right.any?
98
- collector << " " if o.left
98
+ collector << SPACE if o.left
99
99
  collector = inject_join o.right, collector, ' '
100
100
  end
101
101
  collector
102
102
  end
103
103
 
104
+ def visit_Arel_Nodes_InnerJoin o, collector
105
+ collector << "INNER JOIN "
106
+ collector = visit o.left, collector
107
+ collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
108
+ if o.right
109
+ collector << SPACE
110
+ visit(o.right, collector)
111
+ else
112
+ collector
113
+ end
114
+ end
115
+
104
116
  def visit_Arel_Nodes_OuterJoin o, collector
105
117
  collector << "LEFT OUTER JOIN "
106
118
  collector = visit o.left, collector
107
119
  collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
108
- collector << " "
120
+ collector << SPACE
109
121
  visit o.right, collector
110
122
  end
111
123
 
@@ -190,7 +202,8 @@ module Arel
190
202
 
191
203
  def primary_Key_From_Table t
192
204
  return unless t
193
- column_name = schema_cache.primary_keys(t.name) || column_cache(t.name).first.try(:second).try(:name)
205
+ column_name = @connection.schema_cache.primary_keys(t.name) ||
206
+ @connection.schema_cache.columns_hash(t.name).first.try(:second).try(:name)
194
207
  column_name ? t[column_name] : nil
195
208
  end
196
209
 
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,10 +13,10 @@ 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-senstive information in the adpaters inspect method' do
16
+ it 'has basic and non-sensitive information in the adapters inspect method' do
17
17
  string = connection.inspect
18
18
  string.must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
19
- string.must_match %r{version\: \d\d\.\d}
19
+ string.must_match %r{version\: \d+\.\d}
20
20
  string.must_match %r{mode: (dblib|jdbc)}
21
21
  string.must_match %r{azure: (true|false)}
22
22
  string.wont_match %r{host}
@@ -37,10 +37,6 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
37
37
  assert_equal 'SQLServer', connection.adapter_name
38
38
  end
39
39
 
40
- it 'supports migrations' do
41
- assert connection.supports_migrations?
42
- end
43
-
44
40
  it 'support DDL in transactions' do
45
41
  assert connection.supports_ddl_transactions?
46
42
  end
@@ -145,12 +141,12 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
145
141
  end
146
142
 
147
143
  it 'return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column' do
148
- assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql)
149
- assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted)
150
- assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered)
151
- assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_sp)
152
- assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted_sp)
153
- assert_equal '[funny_jokes]', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered_sp)
144
+ assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql)
145
+ assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted)
146
+ assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered)
147
+ assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_sp)
148
+ assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unquoted_sp)
149
+ assert_equal 'funny_jokes', connection.send(:query_requires_identity_insert?,@identity_insert_sql_unordered_sp)
154
150
  end
155
151
 
156
152
  it 'return false to #query_requires_identity_insert? for normal SQL' do
@@ -266,23 +262,23 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
266
262
  end
267
263
 
268
264
  it 'create integers when limit is 4' do
269
- assert_equal 'integer', connection.type_to_sql(:integer, 4)
265
+ assert_equal 'integer', connection.type_to_sql(:integer, limit: 4)
270
266
  end
271
267
 
272
268
  it 'create integers when limit is 3' do
273
- assert_equal 'integer', connection.type_to_sql(:integer, 3)
269
+ assert_equal 'integer', connection.type_to_sql(:integer, limit: 3)
274
270
  end
275
271
 
276
272
  it 'create smallints when limit is less than 3' do
277
- assert_equal 'smallint', connection.type_to_sql(:integer, 2)
278
- assert_equal 'smallint', connection.type_to_sql(:integer, 1)
273
+ assert_equal 'smallint', connection.type_to_sql(:integer, limit: 2)
274
+ assert_equal 'smallint', connection.type_to_sql(:integer, limit: 1)
279
275
  end
280
276
 
281
277
  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)
278
+ assert_equal 'bigint', connection.type_to_sql(:integer, limit: 5)
279
+ assert_equal 'bigint', connection.type_to_sql(:integer, limit: 6)
280
+ assert_equal 'bigint', connection.type_to_sql(:integer, limit: 7)
281
+ assert_equal 'bigint', connection.type_to_sql(:integer, limit: 8)
286
282
  end
287
283
 
288
284
  it 'create floats when no limit supplied' do
@@ -427,3 +423,4 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
427
423
  end
428
424
 
429
425
  end
426
+
@@ -31,6 +31,9 @@ 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
+
34
37
  # As far as I can tell, SQL Server does not support null bytes in strings.
35
38
  coerce_tests! :test_update_prepared_statement
36
39
  coerce_tests! :test_log_invalid_encoding if defined? JRUBY_VERSION # JRuby just happily converts the encoding
@@ -53,14 +56,14 @@ end
53
56
 
54
57
  require 'models/topic'
55
58
  class AttributeMethodsTest < ActiveRecord::TestCase
56
- coerce_tests! :test_typecast_attribute_from_select_to_false
59
+ coerce_tests! %r{typecast attribute from select to false}
57
60
  def test_typecast_attribute_from_select_to_false_coerced
58
61
  Topic.create(:title => 'Budget')
59
62
  topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 2, 1, 0) as is_test").first
60
63
  assert !topic.is_test?
61
64
  end
62
65
 
63
- coerce_tests! :test_typecast_attribute_from_select_to_true
66
+ coerce_tests! %r{typecast attribute from select to true}
64
67
  def test_typecast_attribute_from_select_to_true_coerced
65
68
  Topic.create(:title => 'Budget')
66
69
  topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 1, 1, 0) as is_test").first
@@ -88,6 +91,37 @@ class BasicsTest < ActiveRecord::TestCase
88
91
  # Caused in Rails v4.2.5 by adding `firm_id` column in this http://git.io/vBfMs
89
92
  # commit. Trust Rails has this covered.
90
93
  coerce_tests! :test_find_keeps_multiple_group_values
94
+
95
+ def test_update_date_time_attributes
96
+ Time.use_zone("Eastern Time (US & Canada)") do
97
+ topic = Topic.find(1)
98
+ time = Time.zone.parse("2017-07-17 10:56")
99
+ topic.update_attributes!(written_on: time)
100
+ assert_equal(time, topic.written_on)
101
+ end
102
+ end
103
+
104
+ def test_update_date_time_attributes_with_default_timezone_local
105
+ with_env_tz 'America/New_York' do
106
+ with_timezone_config default: :local do
107
+ Time.use_zone("Eastern Time (US & Canada)") do
108
+ topic = Topic.find(1)
109
+ time = Time.zone.parse("2017-07-17 10:56")
110
+ topic.update_attributes!(written_on: time)
111
+ assert_equal(time, topic.written_on)
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ coerce_tests! %r{column names are quoted when using #from clause and model has ignored columns}
118
+ def test_column_names_are_quoted_when_using_from_clause_and_model_has_ignored_columns_coerced
119
+ refute_empty Developer.ignored_columns
120
+ query = Developer.from("developers").to_sql
121
+ quoted_id = "#{Developer.quoted_table_name}.#{Developer.quoted_primary_key}"
122
+
123
+ assert_match(/SELECT #{Regexp.quote(quoted_id)}.* FROM developers/, query)
124
+ end
91
125
  end
92
126
 
93
127
 
@@ -119,6 +153,15 @@ end
119
153
 
120
154
 
121
155
  class CalculationsTest < ActiveRecord::TestCase
156
+ # This fails randomly due to schema cache being lost?
157
+ coerce_tests! :test_offset_is_kept
158
+ def test_offset_is_kept_coerced
159
+ Account.first
160
+ queries = assert_sql { Account.offset(1).count }
161
+ assert_equal 1, queries.length
162
+ assert_match(/OFFSET/, queries.first)
163
+ end
164
+
122
165
  # Are decimal, not integer.
123
166
  coerce_tests! :test_should_return_decimal_average_of_integer_field
124
167
  def test_should_return_decimal_average_of_integer_field_coerced
@@ -174,6 +217,29 @@ end
174
217
 
175
218
 
176
219
 
220
+ module ActiveRecord
221
+ module ConnectionAdapters
222
+ class QuoteARBaseTest < ActiveRecord::TestCase
223
+
224
+ # Use our date format.
225
+ coerce_tests! :test_quote_ar_object
226
+ def test_quote_ar_object_coerced
227
+ value = DatetimePrimaryKey.new(id: @time)
228
+ assert_equal "'02-14-2017 12:34:56.789'", @connection.quote(value)
229
+ end
230
+
231
+ # Use our date format.
232
+ coerce_tests! :test_type_cast_ar_object
233
+ def test_type_cast_ar_object_coerced
234
+ value = DatetimePrimaryKey.new(id: @time)
235
+ assert_equal "02-14-2017 12:34:56.789", @connection.type_cast(value)
236
+ end
237
+
238
+ end
239
+ end
240
+ end
241
+
242
+
177
243
 
178
244
  module ActiveRecord
179
245
  class Migration
@@ -302,6 +368,10 @@ end
302
368
 
303
369
 
304
370
  module ActiveRecord
371
+ class DatabaseTasksDumpSchemaCacheTest < ActiveRecord::TestCase
372
+ # Skip this test with /tmp/my_schema_cache.yml path on Windows.
373
+ coerce_tests! :test_dump_schema_cache if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
374
+ end
305
375
  class DatabaseTasksCreateAllTest < ActiveRecord::TestCase
306
376
  # We extend `local_database?` so that common VM IPs can be used.
307
377
  coerce_tests! :test_ignores_remote_databases, :test_warning_for_remote_databases
@@ -395,12 +465,6 @@ class FinderTest < ActiveRecord::TestCase
395
465
  end
396
466
  end if defined? JRUBY_VERSION
397
467
 
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
468
  coerce_tests! :test_take_and_first_and_last_with_integer_should_use_sql_limit
405
469
  def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
406
470
  assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 3/) { Topic.take(3).entries }
@@ -603,6 +667,15 @@ end
603
667
 
604
668
 
605
669
 
670
+ class PrimaryKeysTest < ActiveRecord::TestCase
671
+ # Gonna trust Rails core for this. We end up with 2 querys vs 3 asserted
672
+ # but as far as I can tell, this is only one for us anyway.
673
+ coerce_tests! :test_create_without_primary_key_no_extra_query
674
+ end
675
+
676
+
677
+
678
+
606
679
  require 'models/task'
607
680
  class QueryCacheTest < ActiveRecord::TestCase
608
681
  coerce_tests! :test_cache_does_not_wrap_string_results_in_arrays
@@ -646,6 +719,26 @@ class RelationTest < ActiveRecord::TestCase
646
719
  # Leave it up to users to format selects/functions so HAVING works correctly.
647
720
  coerce_tests! :test_multiple_where_and_having_clauses
648
721
  coerce_tests! :test_having_with_binds_for_both_where_and_having
722
+
723
+ # Find any limit via our expression.
724
+ coerce_tests! %r{relations don't load all records in #inspect}
725
+ def test_relations_dont_load_all_records_in_inspect_coerced
726
+ assert_sql(/NEXT \? ROWS ONLY/) do
727
+ Post.all.inspect
728
+ end
729
+ end
730
+
731
+ # I wanted to add `.order("author_id")` scope to avoid error: Column "posts.id" is invalid in the ORDER BY
732
+ # However, this pull request on Rails core drops order on exists relation. https://github.com/rails/rails/pull/28699
733
+ # so we are skipping all together.
734
+ coerce_tests! :test_empty_complex_chained_relations
735
+
736
+ # Use LEN() vs length() function.
737
+ coerce_tests! :test_reverse_arel_assoc_order_with_function
738
+ def test_reverse_arel_assoc_order_with_function_coerced
739
+ topics = Topic.order(Arel.sql("LEN(title)") => :asc).reverse_order
740
+ assert_equal topics(:second).title, topics.first.title
741
+ end
649
742
  end
650
743
 
651
744
 
@@ -677,9 +770,6 @@ class SchemaDumperTest < ActiveRecord::TestCase
677
770
  assert_match %r{t.decimal\s+"atoms_in_universe",\s+precision: 38}, output
678
771
  end
679
772
 
680
- # This accidently returns the wrong number because of our tables too.
681
- coerce_tests! :test_types_line_up
682
-
683
773
  # This is a poorly written test and really does not catch the bottom'ness it is meant too. Ours throw it off.
684
774
  coerce_tests! :test_foreign_keys_are_dumped_at_the_bottom_to_circumvent_dependency_issues
685
775
 
@@ -843,3 +933,19 @@ module ActiveRecord
843
933
  #coerce_tests! :test_find_does_not_use_statement_cache_if_table_name_is_changed
844
934
  end
845
935
  end
936
+
937
+
938
+
939
+
940
+ module ActiveRecord
941
+ module ConnectionAdapters
942
+ class SchemaCacheTest < ActiveRecord::TestCase
943
+ private
944
+ # We need to give the full path for this to work.
945
+ def schema_dump_path
946
+ File.join ARTest::SQLServer.root_activerecord, 'test/assets/schema_dump_5_1.yml'
947
+ end
948
+ end
949
+ end
950
+ end
951
+
@@ -36,7 +36,7 @@ class ColumnTestSQLServer < ActiveRecord::TestCase
36
36
  it 'bigint(8)' do
37
37
  col = column('bigint')
38
38
  col.sql_type.must_equal 'bigint(8)'
39
- col.type.must_equal :bigint
39
+ col.type.must_equal :integer
40
40
  col.null.must_equal true
41
41
  col.default.must_equal 42
42
42
  obj.bigint.must_equal 42
@@ -9,7 +9,7 @@ require 'support/load_schema_sqlserver'
9
9
  require 'support/coerceable_test_sqlserver'
10
10
  require 'support/sql_counter_sqlserver'
11
11
  require 'support/connection_reflection'
12
- require 'mocha/minitest'
12
+ require 'mocha/mini_test'
13
13
 
14
14
  module ActiveRecord
15
15
  class TestCase < ActiveSupport::TestCase
@@ -23,9 +23,14 @@ module ActiveRecord
23
23
 
24
24
  let(:logger) { ActiveRecord::Base.logger }
25
25
 
26
+ setup :ensure_clean_rails_env
26
27
 
27
28
  private
28
29
 
30
+ def ensure_clean_rails_env
31
+ Rails.instance_variable_set(:@_env, nil) if defined?(::Rails)
32
+ end
33
+
29
34
  def host_windows?
30
35
  RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
31
36
  end
@@ -46,23 +46,40 @@ class PessimisticLockingTestSQLServer < ActiveRecord::TestCase
46
46
  end
47
47
  end
48
48
 
49
- it 'reload with lock when #lock! called' do
50
- assert_nothing_raised do
51
- Person.transaction do
52
- person = Person.find 1
53
- old, person.first_name = person.first_name, 'fooman'
54
- person.lock!
55
- assert_equal old, person.first_name
56
- end
57
- end
58
- end
59
-
60
49
  it 'can add a custom lock directive' do
61
50
  assert_sql %r|SELECT \[people\]\.\* FROM \[people\] WITH\(HOLDLOCK, ROWLOCK\)| do
62
51
  Person.lock('WITH(HOLDLOCK, ROWLOCK)').load
63
52
  end
64
53
  end
65
54
 
55
+ describe 'joining tables' do
56
+
57
+ it 'joined tables use updlock by default' do
58
+ assert_sql %r|SELECT \[people\]\.\* FROM \[people\] WITH\(UPDLOCK\) INNER JOIN \[readers\] WITH\(UPDLOCK\)\s+ON \[readers\]\.\[person_id\] = \[people\]\.\[id\]| do
59
+ Person.lock(true).joins(:readers).load
60
+ end
61
+ end
62
+
63
+ it 'joined tables can use custom lock directive' do
64
+ assert_sql %r|SELECT \[people\]\.\* FROM \[people\] WITH\(NOLOCK\) INNER JOIN \[readers\] WITH\(NOLOCK\)\s+ON \[readers\]\.\[person_id\] = \[people\]\.\[id\]| do
65
+ Person.lock('WITH(NOLOCK)').joins(:readers).load
66
+ end
67
+ end
68
+
69
+ it 'left joined tables use updlock by default' do
70
+ assert_sql %r|SELECT \[people\]\.\* FROM \[people\] WITH\(UPDLOCK\) LEFT OUTER JOIN \[readers\] WITH\(UPDLOCK\)\s+ON \[readers\]\.\[person_id\] = \[people\]\.\[id\]| do
71
+ Person.lock(true).left_joins(:readers).load
72
+ end
73
+ end
74
+
75
+ it 'left joined tables can use custom lock directive' do
76
+ assert_sql %r|SELECT \[people\]\.\* FROM \[people\] WITH\(NOLOCK\) LEFT OUTER JOIN \[readers\] WITH\(NOLOCK\)\s+ON \[readers\]\.\[person_id\] = \[people\]\.\[id\]| do
77
+ Person.lock('WITH(NOLOCK)').left_joins(:readers).load
78
+ end
79
+ end
80
+
81
+ end
82
+
66
83
  end
67
84
 
68
85
  describe 'For paginated finds' do