diff options
author | Michael Koziarski <michael@koziarski.com> | 2006-01-14 09:36:52 +0000 |
---|---|---|
committer | Michael Koziarski <michael@koziarski.com> | 2006-01-14 09:36:52 +0000 |
commit | a471e6b4d741c498439767237efad9838df44834 (patch) | |
tree | 430eee828fff690cc1d1174f355e29d4822bfb4b | |
parent | 62d749ab0ef1787e050537bd9a6f833b30f1331d (diff) | |
download | rails-a471e6b4d741c498439767237efad9838df44834.tar.gz rails-a471e6b4d741c498439767237efad9838df44834.tar.bz2 rails-a471e6b4d741c498439767237efad9838df44834.zip |
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
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 |