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.
- 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
|