Skip to content

Commit 3fa4033

Browse files
committed
Initial support for pessimistic locking (sql server locking hints).
SQL statement is constructed correctly and executes without raising errors on SQL 2005. TODO: Add unit tests to test the behavior of the various locking hints and verify works with 2000.
1 parent dff21ff commit 3fa4033

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ def self.sqlserver_connection(config) #:nodoc:
5555

5656
private
5757

58+
# Add basic support for SQL server locking hints
59+
# In the case of SQL server, the lock value must follow the FROM clause
60+
# Mysql: SELECT * FROM tst where testID = 10 LOCK IN share mode
61+
# SQLServer: SELECT * from tst WITH (HOLDLOCK, ROWLOCK) where testID = 10
62+
def self.construct_finder_sql(options)
63+
scope = scope(:find)
64+
sql = "SELECT #{options[:select] || (scope && scope[:select]) || ((options[:joins] || (scope && scope[:joins])) && quoted_table_name + '.*') || '*'} "
65+
sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
66+
67+
add_lock!(sql, options, scope) if ActiveRecord::Base.connection.adapter_name == "SQLServer" && !options[:lock].blank? # SQLServer
68+
69+
add_joins!(sql, options, scope)
70+
add_conditions!(sql, options[:conditions], scope)
71+
72+
add_group!(sql, options[:group], scope)
73+
add_order!(sql, options[:order], scope)
74+
add_limit!(sql, options, scope)
75+
add_lock!(sql, options, scope) unless ActiveRecord::Base.connection.adapter_name == "SQLServer" # Not SQLServer
76+
sql
77+
end
78+
5879
# Overwrite the ActiveRecord::Base method for SQL server.
5980
# GROUP BY is necessary for distinct orderings
6081
def self.construct_finder_sql_for_association_limiting(options, join_dependency)
@@ -576,9 +597,17 @@ def add_order_by_for_association_limiting!(sql, options)
576597
sql << " ORDER BY #{order.join(',')}"
577598
end
578599

600+
# Appends a locking clause to an SQL statement.
601+
# This method *modifies* the +sql+ parameter.
602+
# # SELECT * FROM suppliers FOR UPDATE
603+
# add_lock! 'SELECT * FROM suppliers', :lock => true
604+
# add_lock! 'SELECT * FROM suppliers', :lock => ' WITH(HOLDLOCK, ROWLOCK)'
605+
# http://blog.sqlauthority.com/2007/04/27/sql-server-2005-locking-hints-and-examples/
579606
def add_lock!(sql, options)
580-
@logger.info "Warning: SQLServer :lock option '#{options[:lock].inspect}' not supported" if @logger && options.has_key?(:lock)
581-
sql
607+
case lock = options[:lock]
608+
when true then sql << "WITH(HOLDLOCK, ROWLOCK) "
609+
when String then sql << "#{lock} "
610+
end
582611
end
583612

584613
def recreate_database(name)

0 commit comments

Comments
 (0)