aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG2
-rw-r--r--activerecord/lib/active_record/locking.rb29
-rw-r--r--activerecord/test/fixtures/db_definitions/db2.drop.sql1
-rw-r--r--activerecord/test/fixtures/db_definitions/db2.sql8
-rw-r--r--activerecord/test/fixtures/db_definitions/firebird.drop.sql1
-rw-r--r--activerecord/test/fixtures/db_definitions/firebird.sql9
-rw-r--r--activerecord/test/fixtures/db_definitions/mysql.drop.sql1
-rwxr-xr-xactiverecord/test/fixtures/db_definitions/mysql.sql8
-rw-r--r--activerecord/test/fixtures/db_definitions/oci.drop.sql3
-rw-r--r--activerecord/test/fixtures/db_definitions/oci.sql7
-rw-r--r--activerecord/test/fixtures/db_definitions/postgresql.drop.sql1
-rw-r--r--activerecord/test/fixtures/db_definitions/postgresql.sql7
-rw-r--r--activerecord/test/fixtures/db_definitions/sqlite.drop.sql1
-rw-r--r--activerecord/test/fixtures/db_definitions/sqlite.sql7
-rw-r--r--activerecord/test/fixtures/db_definitions/sqlserver.drop.sql1
-rw-r--r--activerecord/test/fixtures/db_definitions/sqlserver.sql8
-rw-r--r--activerecord/test/fixtures/legacy_thing.rb3
-rw-r--r--activerecord/test/fixtures/legacy_things.yml3
-rw-r--r--activerecord/test/locking_test.rb16
19 files changed, 111 insertions, 5 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 12d91b5a98..50d22feb1c 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -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]
diff --git a/activerecord/lib/active_record/locking.rb b/activerecord/lib/active_record/locking.rb
index 71a4666e17..28d55da6df 100644
--- a/activerecord/lib/active_record/locking.rb
+++ b/activerecord/lib/active_record/locking.rb
@@ -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
diff --git a/activerecord/test/fixtures/db_definitions/db2.drop.sql b/activerecord/test/fixtures/db_definitions/db2.drop.sql
index ce2d3688f9..b6febbc40d 100644
--- a/activerecord/test/fixtures/db_definitions/db2.drop.sql
+++ b/activerecord/test/fixtures/db_definitions/db2.drop.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/db2.sql b/activerecord/test/fixtures/db_definitions/db2.sql
index c50e7178f8..9bb2ad991a 100644
--- a/activerecord/test/fixtures/db_definitions/db2.sql
+++ b/activerecord/test/fixtures/db_definitions/db2.sql
@@ -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)
+);
diff --git a/activerecord/test/fixtures/db_definitions/firebird.drop.sql b/activerecord/test/fixtures/db_definitions/firebird.drop.sql
index 44b3be419d..b9df0fe1ab 100644
--- a/activerecord/test/fixtures/db_definitions/firebird.drop.sql
+++ b/activerecord/test/fixtures/db_definitions/firebird.drop.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/firebird.sql b/activerecord/test/fixtures/db_definitions/firebird.sql
index 8d7316d40a..28e4c71b71 100644
--- a/activerecord/test/fixtures/db_definitions/firebird.sql
+++ b/activerecord/test/fixtures/db_definitions/firebird.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/mysql.drop.sql b/activerecord/test/fixtures/db_definitions/mysql.drop.sql
index 8a37e2deae..699ce40db1 100644
--- a/activerecord/test/fixtures/db_definitions/mysql.drop.sql
+++ b/activerecord/test/fixtures/db_definitions/mysql.drop.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/mysql.sql b/activerecord/test/fixtures/db_definitions/mysql.sql
index d9b98042ae..83479393f4 100755
--- a/activerecord/test/fixtures/db_definitions/mysql.sql
+++ b/activerecord/test/fixtures/db_definitions/mysql.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/oci.drop.sql b/activerecord/test/fixtures/db_definitions/oci.drop.sql
index 5a3a663703..6e73717d69 100644
--- a/activerecord/test/fixtures/db_definitions/oci.drop.sql
+++ b/activerecord/test/fixtures/db_definitions/oci.drop.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/oci.sql b/activerecord/test/fixtures/db_definitions/oci.sql
index 832396d0c7..9995f4c85e 100644
--- a/activerecord/test/fixtures/db_definitions/oci.sql
+++ b/activerecord/test/fixtures/db_definitions/oci.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/postgresql.drop.sql b/activerecord/test/fixtures/db_definitions/postgresql.drop.sql
index 7919d13a7f..306890dd3e 100644
--- a/activerecord/test/fixtures/db_definitions/postgresql.drop.sql
+++ b/activerecord/test/fixtures/db_definitions/postgresql.drop.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/postgresql.sql b/activerecord/test/fixtures/db_definitions/postgresql.sql
index cce4eec890..32f6f32fe0 100644
--- a/activerecord/test/fixtures/db_definitions/postgresql.sql
+++ b/activerecord/test/fixtures/db_definitions/postgresql.sql
@@ -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
+);
diff --git a/activerecord/test/fixtures/db_definitions/sqlite.drop.sql b/activerecord/test/fixtures/db_definitions/sqlite.drop.sql
index 8a37e2deae..699ce40db1 100644
--- a/activerecord/test/fixtures/db_definitions/sqlite.drop.sql
+++ b/activerecord/test/fixtures/db_definitions/sqlite.drop.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/sqlite.sql b/activerecord/test/fixtures/db_definitions/sqlite.sql
index 2e643f5930..b66969a40b 100644
--- a/activerecord/test/fixtures/db_definitions/sqlite.sql
+++ b/activerecord/test/fixtures/db_definitions/sqlite.sql
@@ -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
+)
diff --git a/activerecord/test/fixtures/db_definitions/sqlserver.drop.sql b/activerecord/test/fixtures/db_definitions/sqlserver.drop.sql
index edb9aa6e8d..c8803e8360 100644
--- a/activerecord/test/fixtures/db_definitions/sqlserver.drop.sql
+++ b/activerecord/test/fixtures/db_definitions/sqlserver.drop.sql
@@ -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;
diff --git a/activerecord/test/fixtures/db_definitions/sqlserver.sql b/activerecord/test/fixtures/db_definitions/sqlserver.sql
index e27364091f..15a0d5fd76 100644
--- a/activerecord/test/fixtures/db_definitions/sqlserver.sql
+++ b/activerecord/test/fixtures/db_definitions/sqlserver.sql
@@ -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)
+);
diff --git a/activerecord/test/fixtures/legacy_thing.rb b/activerecord/test/fixtures/legacy_thing.rb
new file mode 100644
index 0000000000..eaeb642d12
--- /dev/null
+++ b/activerecord/test/fixtures/legacy_thing.rb
@@ -0,0 +1,3 @@
+class LegacyThing < ActiveRecord::Base
+ set_locking_column :version
+end
diff --git a/activerecord/test/fixtures/legacy_things.yml b/activerecord/test/fixtures/legacy_things.yml
new file mode 100644
index 0000000000..a6d42aab5d
--- /dev/null
+++ b/activerecord/test/fixtures/legacy_things.yml
@@ -0,0 +1,3 @@
+obtuse:
+ id: 1
+ tps_report_number: 500
diff --git a/activerecord/test/locking_test.rb b/activerecord/test/locking_test.rb
index a88abc8200..105f19f2bc 100644
--- a/activerecord/test/locking_test.rb
+++ b/activerecord/test/locking_test.rb
@@ -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