ibm_db 0.9.5 → 0.10.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.
Files changed (44) hide show
  1. data/CHANGES +5 -0
  2. data/README +63 -97
  3. data/ext/ibm_db.c +20 -4
  4. data/ext/ruby_ibm_db.h +10 -0
  5. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2 -4
  6. data/test/{adapter_test.rb → cases/adapter_test.rb} +39 -14
  7. data/test/cases/associations/cascaded_eager_loading_test.rb +113 -0
  8. data/test/{associations → cases/associations}/eager_test.rb +231 -65
  9. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +686 -0
  10. data/test/cases/associations/join_model_test.rb +797 -0
  11. data/test/{base_test.rb → cases/base_test.rb} +605 -385
  12. data/test/cases/calculations_test.rb +275 -0
  13. data/test/cases/finder_test.rb +885 -0
  14. data/test/cases/fixtures_test.rb +630 -0
  15. data/test/{migration_test.rb → cases/migration_test.rb} +530 -146
  16. data/test/cases/query_cache_test.rb +127 -0
  17. data/test/cases/validations_test.rb +1509 -0
  18. data/test/connections/native_ibm_db/connection.rb +1 -1
  19. data/test/models/warehouse_thing.rb +5 -0
  20. data/test/schema/i5/ibm_db_specific_schema.rb +133 -0
  21. data/test/schema/ids/ibm_db_specific_schema.rb +136 -0
  22. data/test/schema/luw/ibm_db_specific_schema.rb +133 -0
  23. data/test/schema/schema.rb +432 -0
  24. data/test/schema/zOS/ibm_db_specific_schema.rb +204 -0
  25. metadata +29 -33
  26. data/test/associations_test.rb +0 -2151
  27. data/test/fixtures/db_definitions/i5/ibm_db.drop.sql +0 -33
  28. data/test/fixtures/db_definitions/i5/ibm_db.sql +0 -236
  29. data/test/fixtures/db_definitions/i5/ibm_db2.drop.sql +0 -2
  30. data/test/fixtures/db_definitions/i5/ibm_db2.sql +0 -5
  31. data/test/fixtures/db_definitions/ids/ibm_db.drop.sql +0 -33
  32. data/test/fixtures/db_definitions/ids/ibm_db.sql +0 -237
  33. data/test/fixtures/db_definitions/ids/ibm_db2.drop.sql +0 -2
  34. data/test/fixtures/db_definitions/ids/ibm_db2.sql +0 -5
  35. data/test/fixtures/db_definitions/luw/ibm_db.drop.sql +0 -33
  36. data/test/fixtures/db_definitions/luw/ibm_db.sql +0 -236
  37. data/test/fixtures/db_definitions/luw/ibm_db2.drop.sql +0 -2
  38. data/test/fixtures/db_definitions/luw/ibm_db2.sql +0 -5
  39. data/test/fixtures/db_definitions/schema.rb +0 -361
  40. data/test/fixtures/db_definitions/zOS/ibm_db.drop.sql +0 -33
  41. data/test/fixtures/db_definitions/zOS/ibm_db.sql +0 -288
  42. data/test/fixtures/db_definitions/zOS/ibm_db2.drop.sql +0 -2
  43. data/test/fixtures/db_definitions/zOS/ibm_db2.sql +0 -7
  44. data/test/locking_test.rb +0 -282
@@ -1,33 +0,0 @@
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;
33
- DROP TABLE minimalistics;
@@ -1,288 +0,0 @@
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 TIME 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);
285
-
286
- CREATE TABLE minimalistics (
287
- id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 100)
288
- );
@@ -1,2 +0,0 @@
1
- DROP TABLE courses;
2
-
@@ -1,7 +0,0 @@
1
- CREATE TABLE courses (
2
- id INT NOT NULL PRIMARY KEY,
3
- name VARCHAR(255) NOT NULL
4
- );
5
- CREATE UNIQUE INDEX courses_id_idx ON
6
- courses (id);
7
-
data/test/locking_test.rb DELETED
@@ -1,282 +0,0 @@
1
- require 'abstract_unit'
2
- require 'fixtures/person'
3
- require 'fixtures/reader'
4
- require 'fixtures/legacy_thing'
5
-
6
- class LockWithoutDefault < ActiveRecord::Base; end
7
-
8
- class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
9
- set_table_name :lock_without_defaults_cust
10
- set_locking_column :custom_lock_version
11
- end
12
-
13
- class ReadonlyFirstNamePerson < Person
14
- attr_readonly :first_name
15
- end
16
-
17
- class IBMDBOptimisticLockingTest < Test::Unit::TestCase
18
- fixtures :people, :legacy_things
19
-
20
- # need to disable transactional fixtures, because otherwise the sqlite3
21
- # adapter (at least) chokes when we try and change the schema in the middle
22
- # of a test (see test_increment_counter_*).
23
- self.use_transactional_fixtures = false
24
-
25
- def test_lock_existing
26
- p1 = Person.find(1)
27
- p2 = Person.find(1)
28
- assert_equal 0, p1.lock_version
29
- assert_equal 0, p2.lock_version
30
-
31
- p1.save!
32
- assert_equal 1, p1.lock_version
33
- assert_equal 0, p2.lock_version
34
-
35
- assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
36
- end
37
-
38
- def test_lock_repeating
39
- p1 = Person.find(1)
40
- p2 = Person.find(1)
41
- assert_equal 0, p1.lock_version
42
- assert_equal 0, p2.lock_version
43
-
44
- p1.save!
45
- assert_equal 1, p1.lock_version
46
- assert_equal 0, p2.lock_version
47
-
48
- assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
49
- assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
50
- end
51
-
52
- def test_lock_new
53
- p1 = Person.new(:first_name => 'anika')
54
- assert_equal 0, p1.lock_version
55
-
56
- p1.save!
57
- p2 = Person.find(p1.id)
58
- assert_equal 0, p1.lock_version
59
- assert_equal 0, p2.lock_version
60
-
61
- p1.save!
62
- assert_equal 1, p1.lock_version
63
- assert_equal 0, p2.lock_version
64
-
65
- assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
66
- end
67
-
68
- def test_lock_new_with_nil
69
- p1 = Person.new(:first_name => 'anika')
70
- p1.save!
71
- p1.lock_version = nil # simulate bad fixture or column with no default
72
- p1.save!
73
- assert_equal 1, p1.lock_version
74
- end
75
-
76
-
77
- def test_lock_column_name_existing
78
- t1 = LegacyThing.find(1)
79
- t2 = LegacyThing.find(1)
80
- assert_equal 0, t1.version
81
- assert_equal 0, t2.version
82
-
83
- t1.save!
84
- assert_equal 1, t1.version
85
- assert_equal 0, t2.version
86
-
87
- assert_raises(ActiveRecord::StaleObjectError) { t2.save! }
88
- end
89
-
90
- def test_lock_column_is_mass_assignable
91
- p1 = Person.create(:first_name => 'bianca')
92
- assert_equal 0, p1.lock_version
93
- assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
94
-
95
- p1.save!
96
- assert_equal 1, p1.lock_version
97
- assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
98
- end
99
-
100
- def test_lock_without_default_sets_version_to_zero
101
- t1 = LockWithoutDefault.new
102
- assert_equal 0, t1.lock_version
103
- end
104
-
105
- def test_lock_with_custom_column_without_default_sets_version_to_zero
106
- t1 = LockWithCustomColumnWithoutDefault.new
107
- assert_equal 0, t1.custom_lock_version
108
- end
109
-
110
- def test_readonly_attributes
111
- assert_equal Set.new([ 'first_name' ]), ReadonlyFirstNamePerson.readonly_attributes
112
-
113
- p = ReadonlyFirstNamePerson.create(:first_name => "unchangeable name")
114
- p.reload
115
- assert_equal "unchangeable name", p.first_name
116
-
117
- p.update_attributes(:first_name => "changed name")
118
- p.reload
119
- assert_equal "unchangeable name", p.first_name
120
- end
121
-
122
- { :lock_version => Person, :custom_lock_version => LegacyThing }.each do |name, model|
123
- define_method("test_increment_counter_updates_#{name}") do
124
- counter_test model, 1 do |id|
125
- model.increment_counter :test_count, id
126
- end
127
- end
128
-
129
- define_method("test_decrement_counter_updates_#{name}") do
130
- counter_test model, -1 do |id|
131
- model.decrement_counter :test_count, id
132
- end
133
- end
134
-
135
- define_method("test_update_counters_updates_#{name}") do
136
- counter_test model, 1 do |id|
137
- model.update_counters id, :test_count => 1
138
- end
139
- end
140
- end
141
-
142
- private
143
-
144
- def add_counter_column_to(model)
145
- model.connection.add_column model.table_name, :test_count, :integer, :null => false, :default => 0
146
- model.reset_column_information
147
- # OpenBase does not set a value to existing rows when adding a not null default column
148
- model.update_all(:test_count => 0) if current_adapter?(:OpenBaseAdapter)
149
- end
150
-
151
- def remove_counter_column_from(model)
152
- model.connection.remove_column model.table_name, :test_count
153
- model.reset_column_information
154
- end
155
-
156
- def counter_test(model, expected_count)
157
- add_counter_column_to(model)
158
- object = model.find(:first)
159
- assert_equal 0, object.test_count
160
- assert_equal 0, object.send(model.locking_column)
161
- yield object.id
162
- object.reload
163
- assert_equal expected_count, object.test_count
164
- assert_equal 1, object.send(model.locking_column)
165
- ensure
166
- remove_counter_column_from(model)
167
- end
168
- end
169
-
170
-
171
- # TODO: test against the generated SQL since testing locking behavior itself
172
- # is so cumbersome. Will deadlock Ruby threads if the underlying db.execute
173
- # blocks, so separate script called by Kernel#system is needed.
174
- # (See exec vs. async_exec in the PostgreSQL adapter.)
175
-
176
- # TODO: The SQL Server, Sybase, and OpenBase adapters currently have no support for pessimistic locking
177
-
178
- unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :OpenBaseAdapter)
179
- class PessimisticLockingTest < Test::Unit::TestCase
180
- self.use_transactional_fixtures = false
181
- fixtures :people, :readers
182
-
183
- def setup
184
- # Avoid introspection queries during tests.
185
- Person.columns; Reader.columns
186
-
187
- @allow_concurrency = ActiveRecord::Base.allow_concurrency
188
- ActiveRecord::Base.allow_concurrency = true
189
- end
190
-
191
- def teardown
192
- ActiveRecord::Base.allow_concurrency = @allow_concurrency
193
- end
194
-
195
- # Test typical find.
196
- def test_sane_find_with_lock
197
- assert_nothing_raised do
198
- Person.transaction do
199
- Person.find 1, :lock => true
200
- end
201
- end
202
- end
203
-
204
- # Test scoped lock.
205
- def test_sane_find_with_scoped_lock
206
- assert_nothing_raised do
207
- Person.transaction do
208
- Person.with_scope(:find => { :lock => true }) do
209
- Person.find 1
210
- end
211
- end
212
- end
213
- end
214
-
215
- # PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
216
- unless current_adapter?(:PostgreSQLAdapter, :IBM_DBAdapter)
217
- # Test locked eager find.
218
- def test_eager_find_with_lock
219
- assert_nothing_raised do
220
- Person.transaction do
221
- Person.find 1, :include => :readers, :lock => true
222
- end
223
- end
224
- end
225
- end
226
-
227
- # Locking a record reloads it.
228
- def test_sane_lock_method
229
- assert_nothing_raised do
230
- Person.transaction do
231
- person = Person.find 1
232
- old, person.first_name = person.first_name, 'fooman'
233
- person.lock!
234
- assert_equal old, person.first_name
235
- end
236
- end
237
- end
238
-
239
- if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
240
- def test_no_locks_no_wait
241
- first, second = duel { Person.find 1 }
242
- assert first.end > second.end
243
- end
244
-
245
- def test_second_lock_waits
246
- assert [0.2, 1, 5].any? { |zzz|
247
- first, second = duel(zzz) { Person.find 1, :lock => true }
248
- second.end > first.end
249
- }
250
- end
251
-
252
- protected
253
- def duel(zzz = 5)
254
- t0, t1, t2, t3 = nil, nil, nil, nil
255
-
256
- a = Thread.new do
257
- t0 = Time.now
258
- Person.transaction do
259
- yield
260
- sleep zzz # block thread 2 for zzz seconds
261
- end
262
- t1 = Time.now
263
- end
264
-
265
- b = Thread.new do
266
- sleep zzz / 2.0 # ensure thread 1 tx starts first
267
- t2 = Time.now
268
- Person.transaction { yield }
269
- t3 = Time.now
270
- end
271
-
272
- a.join
273
- b.join
274
-
275
- assert t1 > t0 + zzz
276
- assert t2 > t0
277
- assert t3 > t2
278
- [t0.to_f..t1.to_f, t2.to_f..t3.to_f]
279
- end
280
- end
281
- end
282
- end