allow the 'lock_version' column to be configured with set_locking_column. Closes #3402
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3422 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
62d749ab0e
commit
a471e6b4d7
|
@ -1,5 +1,7 @@
|
|||
*SVN*
|
||||
|
||||
* Allow configuration of the column used for optimistic locking [wilsonb@gmail.com]
|
||||
|
||||
* Don't hardcode 'id' in acts as list. [ror@philippeapril.com]
|
||||
|
||||
* Fix date errors for SQLServer in association tests. #3406 [kevin.clark@gmal.com]
|
||||
|
|
|
@ -18,6 +18,8 @@ module ActiveRecord
|
|||
# You must ensure that your database schema defaults the lock_version column to 0.
|
||||
#
|
||||
# This behavior can be turned off by setting <tt>ActiveRecord::Base.lock_optimistically = false</tt>.
|
||||
# To override the name of the lock_version column, invoke the <tt>set_locking_column</tt> method.
|
||||
# This method uses the same syntax as <tt>set_table_name</tt>
|
||||
module Locking
|
||||
def self.append_features(base) #:nodoc:
|
||||
super
|
||||
|
@ -29,13 +31,15 @@ module ActiveRecord
|
|||
|
||||
def update_with_lock #:nodoc:
|
||||
if locking_enabled?
|
||||
previous_value = self.lock_version
|
||||
self.lock_version = previous_value + 1
|
||||
lock_col = self.class.locking_column
|
||||
previous_value = send(lock_col)
|
||||
send(lock_col + '=', previous_value + 1)
|
||||
|
||||
affected_rows = connection.update(<<-end_sql, "#{self.class.name} Update with optimistic locking")
|
||||
UPDATE #{self.class.table_name}
|
||||
SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))}
|
||||
WHERE #{self.class.primary_key} = #{quote(id)} AND lock_version = #{quote(previous_value)}
|
||||
WHERE #{self.class.primary_key} = #{quote(id)}
|
||||
AND #{lock_col} = #{quote(previous_value)}
|
||||
end_sql
|
||||
|
||||
unless affected_rows == 1
|
||||
|
@ -52,7 +56,24 @@ module ActiveRecord
|
|||
cattr_accessor :lock_optimistically
|
||||
|
||||
def locking_enabled? #:nodoc:
|
||||
lock_optimistically && respond_to?(:lock_version)
|
||||
lock_optimistically && respond_to?(self.class.locking_column)
|
||||
end
|
||||
|
||||
class << self
|
||||
def set_locking_column( value=nil, &block )
|
||||
define_attr_method :locking_column, value, &block
|
||||
end
|
||||
|
||||
def locking_column
|
||||
reset_locking_column
|
||||
end
|
||||
|
||||
def reset_locking_column
|
||||
default = 'lock_version'
|
||||
set_locking_column(default)
|
||||
default
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,3 +25,4 @@ DROP TABLE categories_posts;
|
|||
DROP TABLE fk_test_has_pk;
|
||||
DROP TABLE fk_test_has_fk;
|
||||
DROP TABLE keyboards;
|
||||
DROP TABLE legacy_things;
|
||||
|
|
|
@ -194,3 +194,11 @@ CREATE TABLE fk_test_has_fk (
|
|||
|
||||
FOREIGN KEY (fk_id) REFERENCES fk_test_has_pk(id)
|
||||
);
|
||||
|
||||
--This table has an altered lock_version column name
|
||||
CREATE TABLE legacy_things (
|
||||
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
|
||||
tps_report_number INT DEFAULT NULL,
|
||||
version INT DEFAULT 0,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
|
|
@ -26,6 +26,7 @@ DROP TABLE fk_test_has_fk;
|
|||
DROP TABLE fk_test_has_pk;
|
||||
DROP TABLE keyboards;
|
||||
DROP TABLE defaults;
|
||||
DROP TABLE legacy_things;
|
||||
|
||||
DROP DOMAIN D_BOOLEAN;
|
||||
|
||||
|
|
|
@ -257,3 +257,12 @@ CREATE TABLE defaults (
|
|||
);
|
||||
CREATE GENERATOR defaults_seq;
|
||||
SET GENERATOR defaults_seq TO 10000;
|
||||
|
||||
CREATE TABLE legacy_things (
|
||||
id BIGINT NOT NULL,
|
||||
tps_report_number INTEGER,
|
||||
version INTEGER DEFAULT 0 NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
CREATE GENERATOR legacy_things_seq;
|
||||
SET GENERATOR legacy_things_seq TO 10000;
|
||||
|
|
|
@ -25,3 +25,4 @@ DROP TABLE categories_posts;
|
|||
DROP TABLE fk_test_has_fk;
|
||||
DROP TABLE fk_test_has_pk;
|
||||
DROP TABLE keyboards;
|
||||
DROP TABLE legacy_things;
|
||||
|
|
|
@ -197,3 +197,11 @@ CREATE TABLE `keyboards` (
|
|||
`key_number` int(11) NOT NULL auto_increment primary key,
|
||||
`name` varchar(50) default NULL
|
||||
);
|
||||
|
||||
--Altered lock_version column name.
|
||||
CREATE TABLE `legacy_things` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`tps_report_number` int(11) default NULL,
|
||||
`version` int(11) NOT NULL default 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=InnoDB;
|
||||
|
|
|
@ -26,6 +26,8 @@ drop table posts;
|
|||
drop table fk_test_has_pk;
|
||||
drop table fk_test_has_fk;
|
||||
drop table keyboards;
|
||||
drop table legacy_things;
|
||||
|
||||
drop sequence accounts_seq;
|
||||
drop sequence companies_nonstd_seq;
|
||||
drop sequence topics_seq;
|
||||
|
@ -53,3 +55,4 @@ drop sequence categories_posts_seq;
|
|||
drop sequence fk_test_has_pk_seq;
|
||||
drop sequence fk_test_has_fk_seq;
|
||||
drop sequence keyboards_seq;
|
||||
drop sequence legacy_things_seq;
|
||||
|
|
|
@ -269,3 +269,10 @@ create table test_oci_defaults (
|
|||
);
|
||||
create sequence test_oci_defaults_seq minvalue 10000;
|
||||
|
||||
--This table has an altered lock_version column name.
|
||||
create table legacy_things (
|
||||
id integer not null primary key,
|
||||
tps_report_number integer default null,
|
||||
version integer default 0
|
||||
);
|
||||
create sequence legacy_things_seq minvalue 10000;
|
||||
|
|
|
@ -28,3 +28,4 @@ DROP TABLE fk_test_has_fk;
|
|||
DROP TABLE fk_test_has_pk;
|
||||
DROP TABLE geometrics;
|
||||
DROP TABLE keyboards;
|
||||
DROP TABLE legacy_things;
|
||||
|
|
|
@ -225,3 +225,10 @@ CREATE TABLE keyboards (
|
|||
key_number serial primary key,
|
||||
"name" character varying(50)
|
||||
);
|
||||
|
||||
--Altered lock_version column name.
|
||||
CREATE TABLE legacy_things (
|
||||
id serial primary key,
|
||||
tps_report_number integer,
|
||||
version integer default 0
|
||||
);
|
||||
|
|
|
@ -25,3 +25,4 @@ DROP TABLE categories_posts;
|
|||
DROP TABLE fk_test_has_fk;
|
||||
DROP TABLE fk_test_has_pk;
|
||||
DROP TABLE keyboards;
|
||||
DROP TABLE legacy_things;
|
||||
|
|
|
@ -181,3 +181,10 @@ CREATE TABLE 'keyboards' (
|
|||
'key_number' INTEGER PRIMARY KEY NOT NULL,
|
||||
'name' VARCHAR(255) DEFAULT NULL
|
||||
);
|
||||
|
||||
--Altered lock_version column name.
|
||||
CREATE TABLE 'legacy_things' (
|
||||
'id' INTEGER NOT NULL PRIMARY KEY,
|
||||
'tps_report_number' INTEGER DEFAULT NULL,
|
||||
'version' INTEGER NOT NULL DEFAULT 0
|
||||
)
|
||||
|
|
|
@ -25,3 +25,4 @@ DROP TABLE categories_posts;
|
|||
DROP TABLE fk_test_has_fk;
|
||||
DROP TABLE fk_test_has_pk;
|
||||
DROP TABLE keyboards;
|
||||
DROP TABLE legacy_things;
|
||||
|
|
|
@ -181,3 +181,11 @@ CREATE TABLE keyboards (
|
|||
key_number int NOT NULL IDENTITY(1, 1) PRIMARY KEY,
|
||||
name varchar(50) default NULL
|
||||
);
|
||||
|
||||
--This table has an altered lock_version column name.
|
||||
CREATE TABLE legacy_things (
|
||||
id int NOT NULL IDENTITY(1, 1),
|
||||
tps_report_number int default NULL,
|
||||
version int default 0,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
class LegacyThing < ActiveRecord::Base
|
||||
set_locking_column :version
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
obtuse:
|
||||
id: 1
|
||||
tps_report_number: 500
|
|
@ -1,8 +1,9 @@
|
|||
require 'abstract_unit'
|
||||
require 'fixtures/person'
|
||||
require 'fixtures/legacy_thing'
|
||||
|
||||
class LockingTest < Test::Unit::TestCase
|
||||
fixtures :people
|
||||
fixtures :people, :legacy_things
|
||||
|
||||
def test_lock_existing
|
||||
p1 = Person.find(1)
|
||||
|
@ -28,5 +29,18 @@ class LockingTest < Test::Unit::TestCase
|
|||
p2.first_name = "should fail"
|
||||
p2.save
|
||||
}
|
||||
end
|
||||
|
||||
def test_lock_column_name_existing
|
||||
t1 = LegacyThing.find(1)
|
||||
t2 = LegacyThing.find(1)
|
||||
t1.tps_report_number = 400
|
||||
t1.save
|
||||
|
||||
assert_raises(ActiveRecord::StaleObjectError) {
|
||||
t2.tps_report_number = 300
|
||||
t2.save
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue