aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/base.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/base.rb')
-rwxr-xr-xactiverecord/lib/active_record/base.rb37
1 files changed, 28 insertions, 9 deletions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index fe528f514c..55befcd29f 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -365,6 +365,8 @@ module ActiveRecord #:nodoc:
# * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join, but not
# include the joined columns.
# * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated.
+ # * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
+ # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE".
#
# Examples for find by id:
# Person.find(1) # returns the object for ID = 1
@@ -384,6 +386,17 @@ module ActiveRecord #:nodoc:
# Person.find(:all, :offset => 10, :limit => 10)
# Person.find(:all, :include => [ :account, :friends ])
# Person.find(:all, :group => "category")
+ #
+ # Example for find with a lock. Imagine two concurrent transactions:
+ # each will read person.visits == 2, add 1 to it, and save, resulting
+ # in two saves of person.visits = 3. By locking the row, the second
+ # transaction has to wait until the first is finished; we get the
+ # expected person.visits == 4.
+ # Person.transaction do
+ # person = Person.find(1, :lock => true)
+ # person.visits += 1
+ # person.save!
+ # end
def find(*args)
options = extract_options_from_args!(args)
validate_find_options(options)
@@ -850,7 +863,7 @@ module ActiveRecord #:nodoc:
method_scoping.assert_valid_keys([ :find, :create ])
if f = method_scoping[:find]
- f.assert_valid_keys([ :conditions, :joins, :select, :include, :from, :offset, :limit, :order, :readonly ])
+ f.assert_valid_keys([ :conditions, :joins, :select, :include, :from, :offset, :limit, :order, :readonly, :lock ])
f[:readonly] = true if !f[:joins].blank? && !f.has_key?(:readonly)
end
@@ -1028,6 +1041,7 @@ module ActiveRecord #:nodoc:
add_order!(sql, options[:order])
add_limit!(sql, options, scope)
+ add_lock!(sql, options, scope)
sql
end
@@ -1061,14 +1075,19 @@ module ActiveRecord #:nodoc:
# The optional scope argument is for the current :find scope.
def add_limit!(sql, options, scope = :auto)
scope = scope(:find) if :auto == scope
- if scope
- options[:limit] ||= scope[:limit]
- options[:offset] ||= scope[:offset]
- end
+ options = options.reverse_merge(:limit => scope[:limit], :offset => scope[:offset]) if scope
connection.add_limit_offset!(sql, options)
end
# The optional scope argument is for the current :find scope.
+ # The :lock option has precedence over a scoped :lock.
+ def add_lock!(sql, options, scope = :auto)
+ scope = scope(:find) if :auto == :scope
+ options = options.reverse_merge(:lock => scope[:lock]) if scope
+ connection.add_lock!(sql, options)
+ end
+
+ # The optional scope argument is for the current :find scope.
def add_joins!(sql, options, scope = :auto)
scope = scope(:find) if :auto == scope
join = (scope && scope[:joins]) || options[:joins]
@@ -1361,12 +1380,12 @@ module ActiveRecord #:nodoc:
end
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset,
- :order, :select, :readonly, :group, :from ]
-
+ :order, :select, :readonly, :group, :from, :lock ]
+
def validate_find_options(options) #:nodoc:
options.assert_valid_keys(VALID_FIND_OPTIONS)
end
-
+
def set_readonly_option!(options) #:nodoc:
# Inherit :readonly from finder scope if set. Otherwise,
# if :joins is not blank then :readonly defaults to true.
@@ -2025,4 +2044,4 @@ module ActiveRecord #:nodoc:
value
end
end
-end \ No newline at end of file
+end