activerecord-jdbcsqlserver-adapter 50.1.0 → 51.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.travis.yml +4 -5
- data/BACKERS.md +32 -0
- data/CHANGELOG.md +21 -87
- data/README.md +2 -3
- data/VERSION +1 -1
- data/activerecord-jdbcsqlserver-adapter.gemspec +3 -2
- data/appveyor.yml +1 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +55 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +4 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +5 -3
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +41 -18
- data/lib/active_record/connection_adapters/sqlserver/jdbc_overrides.rb +2 -12
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +72 -52
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +15 -7
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +5 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +3 -6
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +27 -10
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +2 -2
- data/lib/activerecord-jdbcsqlserver-adapter.rb +1 -1
- data/lib/arel/visitors/sqlserver.rb +16 -3
- data/test/bin/setup.sh +19 -0
- data/test/cases/adapter_test_sqlserver.rb +17 -20
- data/test/cases/coerced_tests.rb +117 -11
- data/test/cases/column_test_sqlserver.rb +1 -1
- data/test/cases/helper_sqlserver.rb +6 -1
- data/test/cases/pessimistic_locking_test_sqlserver.rb +28 -11
- data/test/cases/schema_dumper_test_sqlserver.rb +10 -10
- data/test/cases/specific_schema_test_sqlserver.rb +0 -6
- data/test/cases/trigger_test_sqlserver.rb +31 -0
- data/test/config.yml +2 -2
- data/test/models/sqlserver/trigger.rb +7 -0
- data/test/models/sqlserver/trigger_history.rb +3 -0
- data/test/schema/sqlserver_specific_schema.rb +39 -5
- data/test/support/sql_counter_sqlserver.rb +3 -2
- metadata +23 -16
- data/RAILS5-TODO.md +0 -5
- data/lib/jdbc_mssql_driver_loader.rb +0 -22
- 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
|
-
|
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 <<
|
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) ||
|
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-
|
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
|
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 '
|
149
|
-
assert_equal '
|
150
|
-
assert_equal '
|
151
|
-
assert_equal '
|
152
|
-
assert_equal '
|
153
|
-
assert_equal '
|
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
|
+
|
data/test/cases/coerced_tests.rb
CHANGED
@@ -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!
|
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!
|
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 :
|
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/
|
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
|