ibm_db 0.4.0 → 0.4.6
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.
- data/CHANGES +19 -9
- data/README +29 -20
- data/ext/extconf.rb +55 -50
- data/ext/ibm_db.c +6267 -6259
- data/ext/ruby_ibm_db.h +164 -164
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +167 -142
- data/lib/active_record/vendor/db2-i5-zOS.yaml +68 -68
- data/lib/linux32/ibm_db.so +0 -0
- data/test/adapter_test.rb +128 -0
- data/test/base_test.rb +1579 -0
- data/test/{activerecord → connections}/native_ibm_db/connection.rb +6 -7
- data/test/fixtures/db_definitions/i5/ibm_db.drop.sql +32 -0
- data/test/fixtures/db_definitions/i5/ibm_db.sql +232 -0
- data/test/fixtures/db_definitions/i5/ibm_db2.drop.sql +2 -0
- data/test/fixtures/db_definitions/i5/ibm_db2.sql +5 -0
- data/test/fixtures/db_definitions/luw/ibm_db.drop.sql +31 -0
- data/test/fixtures/db_definitions/luw/ibm_db.sql +226 -0
- data/test/fixtures/db_definitions/luw/ibm_db2.drop.sql +2 -0
- data/test/fixtures/db_definitions/luw/ibm_db2.sql +5 -0
- data/test/fixtures/db_definitions/zOS/ibm_db.drop.sql +32 -0
- data/test/fixtures/db_definitions/zOS/ibm_db.sql +284 -0
- data/test/fixtures/db_definitions/zOS/ibm_db2.drop.sql +2 -0
- data/test/fixtures/db_definitions/zOS/ibm_db2.sql +7 -0
- data/test/locking_test.rb +190 -0
- data/test/migration_test.rb +779 -0
- metadata +39 -17
@@ -0,0 +1,32 @@
|
|
1
|
+
DROP TABLE accounts;
|
2
|
+
DROP TABLE funny_jokes;
|
3
|
+
DROP TABLE companies;
|
4
|
+
DROP TABLE topics;
|
5
|
+
DROP TABLE developers;
|
6
|
+
DROP TABLE projects;
|
7
|
+
DROP TABLE developers_projects;
|
8
|
+
DROP TABLE orders;
|
9
|
+
DROP TABLE customers;
|
10
|
+
DROP TABLE movies;
|
11
|
+
DROP TABLE subscribers;
|
12
|
+
DROP TABLE booleantests;
|
13
|
+
DROP TABLE auto_id_tests;
|
14
|
+
DROP TABLE entrants;
|
15
|
+
DROP TABLE colnametests;
|
16
|
+
DROP TABLE mixins;
|
17
|
+
DROP TABLE people;
|
18
|
+
DROP TABLE readers;
|
19
|
+
DROP TABLE binaries;
|
20
|
+
DROP TABLE computers;
|
21
|
+
DROP TABLE posts;
|
22
|
+
DROP TABLE comments;
|
23
|
+
DROP TABLE authors;
|
24
|
+
DROP TABLE tasks;
|
25
|
+
DROP TABLE categories;
|
26
|
+
DROP TABLE categories_posts;
|
27
|
+
DROP TABLE fk_test_has_pk;
|
28
|
+
DROP TABLE fk_test_has_fk;
|
29
|
+
DROP TABLE keyboards;
|
30
|
+
DROP TABLE legacy_things;
|
31
|
+
DROP TABLE numeric_data;
|
32
|
+
DROP TABLE mixed_case_monkeys;
|
@@ -0,0 +1,284 @@
|
|
1
|
+
CREATE TABLE accounts (
|
2
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
3
|
+
firm_id INT DEFAULT NULL,
|
4
|
+
credit_limit INT DEFAULT NULL,
|
5
|
+
PRIMARY KEY (id)
|
6
|
+
);
|
7
|
+
CREATE UNIQUE INDEX accounts_id_idx ON
|
8
|
+
accounts (id);
|
9
|
+
|
10
|
+
CREATE TABLE funny_jokes (
|
11
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
12
|
+
name VARCHAR(50) DEFAULT NULL,
|
13
|
+
PRIMARY KEY (id)
|
14
|
+
);
|
15
|
+
CREATE UNIQUE INDEX funny_jokes_id_idx ON
|
16
|
+
funny_jokes (id);
|
17
|
+
|
18
|
+
CREATE TABLE companies (
|
19
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
20
|
+
type VARCHAR(50) DEFAULT NULL,
|
21
|
+
ruby_type VARCHAR(50) DEFAULT NULL,
|
22
|
+
firm_id INT DEFAULT NULL,
|
23
|
+
name VARCHAR(50) DEFAULT NULL,
|
24
|
+
client_of INT DEFAULT NULL,
|
25
|
+
rating INT DEFAULT 1,
|
26
|
+
PRIMARY KEY (id)
|
27
|
+
);
|
28
|
+
CREATE UNIQUE INDEX companies_id_idx ON
|
29
|
+
companies (id);
|
30
|
+
|
31
|
+
CREATE TABLE topics (
|
32
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
33
|
+
title VARCHAR(255) DEFAULT NULL,
|
34
|
+
author_name VARCHAR(255) DEFAULT NULL,
|
35
|
+
author_email_address VARCHAR(255) DEFAULT NULL,
|
36
|
+
written_on TIMESTAMP DEFAULT NULL,
|
37
|
+
--bonus_time TIMESTAMP DEFAULT NULL,
|
38
|
+
bonus_time TIME DEFAULT NULL,
|
39
|
+
last_read DATE DEFAULT NULL,
|
40
|
+
content VARCHAR(3000),
|
41
|
+
approved SMALLINT DEFAULT 1,
|
42
|
+
replies_count INT DEFAULT 0,
|
43
|
+
parent_id INT DEFAULT NULL,
|
44
|
+
type VARCHAR(50) DEFAULT NULL,
|
45
|
+
PRIMARY KEY (id)
|
46
|
+
);
|
47
|
+
CREATE UNIQUE INDEX topics_id_idx ON
|
48
|
+
topics (id);
|
49
|
+
|
50
|
+
CREATE TABLE developers (
|
51
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
52
|
+
name VARCHAR(100) DEFAULT NULL,
|
53
|
+
salary INT DEFAULT 70000,
|
54
|
+
created_at TIMESTAMP DEFAULT NULL,
|
55
|
+
updated_at TIMESTAMP DEFAULT NULL,
|
56
|
+
PRIMARY KEY (id)
|
57
|
+
);
|
58
|
+
CREATE UNIQUE INDEX developers_id_idx ON
|
59
|
+
developers (id);
|
60
|
+
|
61
|
+
CREATE TABLE projects (
|
62
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
63
|
+
name VARCHAR(100) DEFAULT NULL,
|
64
|
+
type VARCHAR(255) DEFAULT NULL,
|
65
|
+
PRIMARY KEY (id)
|
66
|
+
);
|
67
|
+
CREATE UNIQUE INDEX projects_id_idx ON
|
68
|
+
projects (id);
|
69
|
+
|
70
|
+
CREATE TABLE developers_projects (
|
71
|
+
developer_id INT NOT NULL,
|
72
|
+
project_id INT NOT NULL,
|
73
|
+
joined_on DATE DEFAULT NULL,
|
74
|
+
access_level SMALLINT DEFAULT 1
|
75
|
+
);
|
76
|
+
|
77
|
+
CREATE TABLE orders (
|
78
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
79
|
+
name VARCHAR(100) DEFAULT NULL,
|
80
|
+
billing_customer_id INT DEFAULT NULL,
|
81
|
+
shipping_customer_id INT DEFAULT NULL,
|
82
|
+
PRIMARY KEY (id)
|
83
|
+
);
|
84
|
+
CREATE UNIQUE INDEX orders_idx ON
|
85
|
+
orders (id);
|
86
|
+
|
87
|
+
CREATE TABLE customers (
|
88
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
89
|
+
name VARCHAR(100) DEFAULT NULL,
|
90
|
+
balance INT DEFAULT 0,
|
91
|
+
address_street VARCHAR(100) DEFAULT NULL,
|
92
|
+
address_city VARCHAR(100) DEFAULT NULL,
|
93
|
+
address_country VARCHAR(100) DEFAULT NULL,
|
94
|
+
gps_location VARCHAR(100) DEFAULT NULL,
|
95
|
+
PRIMARY KEY (id)
|
96
|
+
);
|
97
|
+
CREATE UNIQUE INDEX customers_id_idx ON
|
98
|
+
customers (id);
|
99
|
+
|
100
|
+
CREATE TABLE movies (
|
101
|
+
movieid INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
102
|
+
name VARCHAR(100) DEFAULT NULL,
|
103
|
+
PRIMARY KEY (movieid)
|
104
|
+
);
|
105
|
+
CREATE UNIQUE INDEX movies_id_idx ON
|
106
|
+
movies (movieid);
|
107
|
+
|
108
|
+
CREATE TABLE subscribers (
|
109
|
+
nick VARCHAR(100) NOT NULL,
|
110
|
+
name VARCHAR(100) DEFAULT NULL,
|
111
|
+
PRIMARY KEY (nick)
|
112
|
+
);
|
113
|
+
CREATE UNIQUE INDEX subscribers_id_idx ON
|
114
|
+
subscribers (nick);
|
115
|
+
|
116
|
+
CREATE TABLE booleantests (
|
117
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
118
|
+
value INT DEFAULT NULL,
|
119
|
+
PRIMARY KEY (id)
|
120
|
+
);
|
121
|
+
CREATE UNIQUE INDEX booleantest_id_idx ON
|
122
|
+
booleantests (id);
|
123
|
+
|
124
|
+
CREATE TABLE auto_id_tests (
|
125
|
+
auto_id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
126
|
+
value INT DEFAULT NULL,
|
127
|
+
PRIMARY KEY (auto_id)
|
128
|
+
);
|
129
|
+
CREATE UNIQUE INDEX auto_id_tests_idx ON
|
130
|
+
auto_id_tests (auto_id);
|
131
|
+
|
132
|
+
CREATE TABLE entrants (
|
133
|
+
id INT NOT NULL PRIMARY KEY,
|
134
|
+
name VARCHAR(255) NOT NULL,
|
135
|
+
course_id INT NOT NULL
|
136
|
+
);
|
137
|
+
CREATE UNIQUE INDEX entrants_id_idx ON
|
138
|
+
entrants (id);
|
139
|
+
|
140
|
+
CREATE TABLE colnametests (
|
141
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
142
|
+
references INT NOT NULL,
|
143
|
+
PRIMARY KEY (id)
|
144
|
+
);
|
145
|
+
CREATE UNIQUE INDEX colnametest_id_idx ON
|
146
|
+
colnametests (id);
|
147
|
+
|
148
|
+
CREATE TABLE mixins (
|
149
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
150
|
+
parent_id INT DEFAULT NULL,
|
151
|
+
pos INT DEFAULT NULL,
|
152
|
+
created_at TIMESTAMP DEFAULT NULL,
|
153
|
+
updated_at TIMESTAMP DEFAULT NULL,
|
154
|
+
lft INT DEFAULT NULL,
|
155
|
+
rgt INT DEFAULT NULL,
|
156
|
+
root_id INT DEFAULT NULL,
|
157
|
+
type VARCHAR(40) DEFAULT NULL,
|
158
|
+
PRIMARY KEY (id)
|
159
|
+
);
|
160
|
+
CREATE UNIQUE INDEX mixins_id_idx ON
|
161
|
+
mixins (id);
|
162
|
+
|
163
|
+
CREATE TABLE people (
|
164
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
165
|
+
first_name VARCHAR(40) NOT NULL,
|
166
|
+
lock_version INT DEFAULT 0,
|
167
|
+
PRIMARY KEY (id)
|
168
|
+
);
|
169
|
+
CREATE UNIQUE INDEX people_id_idx ON
|
170
|
+
people (id);
|
171
|
+
|
172
|
+
CREATE TABLE readers (
|
173
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
174
|
+
post_id INT NOT NULL,
|
175
|
+
person_id INT NOT NULL,
|
176
|
+
PRIMARY KEY (id)
|
177
|
+
);
|
178
|
+
CREATE UNIQUE INDEX readers_id_idx ON
|
179
|
+
readers (id);
|
180
|
+
|
181
|
+
CREATE TABLE binaries (
|
182
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
183
|
+
data BLOB(5000000),
|
184
|
+
PRIMARY KEY (id)
|
185
|
+
);
|
186
|
+
CREATE UNIQUE INDEX binaries_id_idx ON
|
187
|
+
binaries (id);
|
188
|
+
--CREATE LOB TABLESPACE datalob;
|
189
|
+
--CREATE AUXILIARY TABLE data_aux IN datalob
|
190
|
+
--STORES binaries COLUMN data;
|
191
|
+
--CREATE UNIQUE INDEX lob_data_idx ON data_aux;
|
192
|
+
|
193
|
+
CREATE TABLE computers (
|
194
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
195
|
+
developer INT NOT NULL,
|
196
|
+
extendedWarranty INT NOT NULL
|
197
|
+
);
|
198
|
+
|
199
|
+
CREATE TABLE posts (
|
200
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
201
|
+
author_id INT DEFAULT NULL,
|
202
|
+
title VARCHAR(255) DEFAULT NULL,
|
203
|
+
type VARCHAR(255) DEFAULT NULL,
|
204
|
+
body VARCHAR(3000) DEFAULT NULL
|
205
|
+
);
|
206
|
+
|
207
|
+
CREATE TABLE comments (
|
208
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
209
|
+
post_id INT DEFAULT NULL,
|
210
|
+
type VARCHAR(255) DEFAULT NULL,
|
211
|
+
body VARCHAR(3000) DEFAULT NULL
|
212
|
+
);
|
213
|
+
|
214
|
+
CREATE TABLE authors (
|
215
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
216
|
+
name VARCHAR(255) DEFAULT NULL
|
217
|
+
);
|
218
|
+
|
219
|
+
CREATE TABLE tasks (
|
220
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
221
|
+
starting TIMESTAMP DEFAULT NULL,
|
222
|
+
ending TIMESTAMP DEFAULT NULL
|
223
|
+
);
|
224
|
+
|
225
|
+
CREATE TABLE categories (
|
226
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
227
|
+
name VARCHAR(255) NOT NULL,
|
228
|
+
type VARCHAR(40) DEFAULT NULL
|
229
|
+
);
|
230
|
+
|
231
|
+
CREATE TABLE categories_posts (
|
232
|
+
category_id INT NOT NULL,
|
233
|
+
post_id INT NOT NULL
|
234
|
+
);
|
235
|
+
|
236
|
+
CREATE TABLE keyboards (
|
237
|
+
key_number INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
238
|
+
name VARCHAR(255)
|
239
|
+
);
|
240
|
+
|
241
|
+
CREATE TABLE fk_test_has_pk (
|
242
|
+
id INT NOT NULL PRIMARY KEY
|
243
|
+
);
|
244
|
+
CREATE UNIQUE INDEX fk_test_has_id_idx ON
|
245
|
+
fk_test_has_pk (id);
|
246
|
+
|
247
|
+
CREATE TABLE fk_test_has_fk (
|
248
|
+
id INT NOT NULL PRIMARY KEY,
|
249
|
+
fk_id INT NOT NULL,
|
250
|
+
|
251
|
+
FOREIGN KEY (fk_id) REFERENCES fk_test_has_pk(id)
|
252
|
+
);
|
253
|
+
CREATE UNIQUE INDEX fk_test_has_fk_idx ON
|
254
|
+
fk_test_has_fk (id);
|
255
|
+
|
256
|
+
--This table has an altered lock_version column name
|
257
|
+
CREATE TABLE legacy_things (
|
258
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
259
|
+
tps_report_number INT DEFAULT NULL,
|
260
|
+
version INT DEFAULT 0,
|
261
|
+
PRIMARY KEY (id)
|
262
|
+
);
|
263
|
+
CREATE UNIQUE INDEX legacy_thin_id_idx ON
|
264
|
+
legacy_things (id);
|
265
|
+
|
266
|
+
CREATE TABLE numeric_data (
|
267
|
+
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
268
|
+
bank_balance DECIMAL(10,2),
|
269
|
+
big_bank_balance DECIMAL(15,2),
|
270
|
+
world_population DECIMAL(10),
|
271
|
+
my_house_population DECIMAL(2),
|
272
|
+
decimal_number_with_default DECIMAL(3,2) DEFAULT 2.78
|
273
|
+
);
|
274
|
+
CREATE UNIQUE INDEX numeric_data_idx ON
|
275
|
+
numeric_data (id);
|
276
|
+
|
277
|
+
CREATE TABLE mixed_case_monkeys (
|
278
|
+
monkeyID INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
|
279
|
+
fleaCount INT DEFAULT 0,
|
280
|
+
PRIMARY KEY (monkeyID)
|
281
|
+
);
|
282
|
+
|
283
|
+
CREATE UNIQUE INDEX mixed_monkeys_idx ON
|
284
|
+
mixed_case_monkeys (monkeyID);
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/person'
|
3
|
+
require 'fixtures/legacy_thing'
|
4
|
+
|
5
|
+
class LockWithoutDefault < ActiveRecord::Base; end
|
6
|
+
|
7
|
+
class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
|
8
|
+
set_table_name :lock_without_defaults_cust
|
9
|
+
set_locking_column :custom_lock_version
|
10
|
+
end
|
11
|
+
|
12
|
+
class OptimisticLockingTest < Test::Unit::TestCase
|
13
|
+
fixtures :people, :legacy_things
|
14
|
+
|
15
|
+
def test_lock_existing
|
16
|
+
p1 = Person.find(1)
|
17
|
+
p2 = Person.find(1)
|
18
|
+
assert_equal 0, p1.lock_version
|
19
|
+
assert_equal 0, p2.lock_version
|
20
|
+
|
21
|
+
p1.save!
|
22
|
+
assert_equal 1, p1.lock_version
|
23
|
+
assert_equal 0, p2.lock_version
|
24
|
+
|
25
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_lock_new
|
29
|
+
p1 = Person.new(:first_name => 'anika')
|
30
|
+
assert_equal 0, p1.lock_version
|
31
|
+
|
32
|
+
p1.save!
|
33
|
+
p2 = Person.find(p1.id)
|
34
|
+
assert_equal 0, p1.lock_version
|
35
|
+
assert_equal 0, p2.lock_version
|
36
|
+
|
37
|
+
p1.save!
|
38
|
+
assert_equal 1, p1.lock_version
|
39
|
+
assert_equal 0, p2.lock_version
|
40
|
+
|
41
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_lock_column_name_existing
|
45
|
+
t1 = LegacyThing.find(1)
|
46
|
+
t2 = LegacyThing.find(1)
|
47
|
+
assert_equal 0, t1.version
|
48
|
+
assert_equal 0, t2.version
|
49
|
+
|
50
|
+
t1.save!
|
51
|
+
assert_equal 1, t1.version
|
52
|
+
assert_equal 0, t2.version
|
53
|
+
|
54
|
+
assert_raises(ActiveRecord::StaleObjectError) { t2.save! }
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_lock_column_is_mass_assignable
|
58
|
+
p1 = Person.create(:first_name => 'bianca')
|
59
|
+
assert_equal 0, p1.lock_version
|
60
|
+
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
61
|
+
|
62
|
+
p1.save!
|
63
|
+
assert_equal 1, p1.lock_version
|
64
|
+
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_lock_without_default_sets_version_to_zero
|
68
|
+
t1 = LockWithoutDefault.new
|
69
|
+
assert_equal 0, t1.lock_version
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_lock_with_custom_column_without_default_sets_version_to_zero
|
73
|
+
t1 = LockWithCustomColumnWithoutDefault.new
|
74
|
+
assert_equal 0, t1.custom_lock_version
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# TODO: test against the generated SQL since testing locking behavior itself
|
80
|
+
# is so cumbersome. Will deadlock Ruby threads if the underlying db.execute
|
81
|
+
# blocks, so separate script called by Kernel#system is needed.
|
82
|
+
# (See exec vs. async_exec in the PostgreSQL adapter.)
|
83
|
+
|
84
|
+
# TODO: The SQL Server and Sybase adapters currently have no support for pessimistic locking
|
85
|
+
|
86
|
+
unless current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
87
|
+
class PessimisticLockingTest < Test::Unit::TestCase
|
88
|
+
self.use_transactional_fixtures = false
|
89
|
+
fixtures :people, :readers
|
90
|
+
|
91
|
+
def setup
|
92
|
+
# Avoid introspection queries during tests.
|
93
|
+
Person.columns; Reader.columns
|
94
|
+
|
95
|
+
@allow_concurrency = ActiveRecord::Base.allow_concurrency
|
96
|
+
ActiveRecord::Base.allow_concurrency = true
|
97
|
+
end
|
98
|
+
|
99
|
+
def teardown
|
100
|
+
ActiveRecord::Base.allow_concurrency = @allow_concurrency
|
101
|
+
end
|
102
|
+
|
103
|
+
# Test typical find.
|
104
|
+
def test_sane_find_with_lock
|
105
|
+
assert_nothing_raised do
|
106
|
+
Person.transaction do
|
107
|
+
Person.find 1, :lock => true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Test scoped lock.
|
113
|
+
def test_sane_find_with_scoped_lock
|
114
|
+
assert_nothing_raised do
|
115
|
+
Person.transaction do
|
116
|
+
Person.with_scope(:find => { :lock => true }) do
|
117
|
+
Person.find 1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
|
124
|
+
unless current_adapter?(:PostgreSQLAdapter, :IBM_DBAdapter)
|
125
|
+
# Test locked eager find.
|
126
|
+
def test_eager_find_with_lock
|
127
|
+
assert_nothing_raised do
|
128
|
+
Person.transaction do
|
129
|
+
Person.find 1, :include => :readers, :lock => true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Locking a record reloads it.
|
136
|
+
def test_sane_lock_method
|
137
|
+
assert_nothing_raised do
|
138
|
+
Person.transaction do
|
139
|
+
person = Person.find 1
|
140
|
+
old, person.first_name = person.first_name, 'fooman'
|
141
|
+
person.lock!
|
142
|
+
assert_equal old, person.first_name
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
|
148
|
+
def test_no_locks_no_wait
|
149
|
+
first, second = duel { Person.find 1 }
|
150
|
+
assert first.end > second.end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_second_lock_waits
|
154
|
+
assert [0.2, 1, 5].any? { |zzz|
|
155
|
+
first, second = duel(zzz) { Person.find 1, :lock => true }
|
156
|
+
second.end > first.end
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
protected
|
161
|
+
def duel(zzz = 5)
|
162
|
+
t0, t1, t2, t3 = nil, nil, nil, nil
|
163
|
+
|
164
|
+
a = Thread.new do
|
165
|
+
t0 = Time.now
|
166
|
+
Person.transaction do
|
167
|
+
yield
|
168
|
+
sleep zzz # block thread 2 for zzz seconds
|
169
|
+
end
|
170
|
+
t1 = Time.now
|
171
|
+
end
|
172
|
+
|
173
|
+
b = Thread.new do
|
174
|
+
sleep zzz / 2.0 # ensure thread 1 tx starts first
|
175
|
+
t2 = Time.now
|
176
|
+
Person.transaction { yield }
|
177
|
+
t3 = Time.now
|
178
|
+
end
|
179
|
+
|
180
|
+
a.join
|
181
|
+
b.join
|
182
|
+
|
183
|
+
assert t1 > t0 + zzz
|
184
|
+
assert t2 > t0
|
185
|
+
assert t3 > t2
|
186
|
+
[t0.to_f..t1.to_f, t2.to_f..t3.to_f]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|