Module: ArJdbc::MSSQL::LockMethods
- Included in:
- Column
- Defined in:
- lib/arjdbc/mssql/lock_methods.rb
Instance Method Summary collapse
-
#add_lock!(sql, options) ⇒ Object
Microsoft SQL Server uses its own syntax for SELECT ..
Instance Method Details
#add_lock!(sql, options) ⇒ Object
Microsoft SQL Server uses its own syntax for SELECT .. FOR UPDATE: SELECT .. FROM table1 WITH(ROWLOCK,UPDLOCK), table2 WITH(ROWLOCK,UPDLOCK) WHERE ..
This does in-place modification of the passed-in string.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/arjdbc/mssql/lock_methods.rb', line 14 def add_lock!(sql, ) if (lock = [:lock]) && sql =~ /\A\s*SELECT/mi # Check for and extract the :limit/:offset sub-query if sql =~ /\A(\s*SELECT t\.\* FROM \()(.*)(\) AS t WHERE t._row_num BETWEEN \d+ AND \d+\s*)\Z/m prefix, subselect, suffix = [$1, $2, $3] add_lock!(subselect, ) return sql.replace(prefix + subselect + suffix) end unless sql =~ SELECT_FROM_WHERE_RE # If you get this error, this driver probably needs to be fixed. raise NotImplementedError, "Don't know how to add_lock! to SQL statement: #{sql.inspect}" end select_clause, from_word, from_tables, where_clause = $1, $2, $3, $4 with_clause = lock.is_a?(String) ? " #{lock} " : " WITH(ROWLOCK,UPDLOCK) " # Split the FROM clause into its constituent tables, and add the with clause after each one. new_from_tables = [] scanner = StringScanner.new(from_tables) until scanner.eos? prev_pos = scanner.pos if scanner.scan_until(/,|(INNER\s+JOIN|CROSS\s+JOIN|(LEFT|RIGHT|FULL)(\s+OUTER)?\s+JOIN)\s+/mi) join_operand = scanner.pre_match[prev_pos..-1] join_operator = scanner.matched else join_operand = scanner.rest join_operator = "" scanner.terminate end # At this point, we have something like: # join_operand == "appointments " # join_operator == "INNER JOIN " # or: # join_operand == "appointment_details AS d1 ON appointments.[id] = d1.[appointment_id]" # join_operator == "" if join_operand =~ /\A(.*)(\s+ON\s+.*)\Z/mi table_spec, on_clause = $1, $2 else table_spec = join_operand on_clause = "" end # Add the "WITH(ROWLOCK,UPDLOCK)" option to the table specification table_spec << with_clause unless table_spec =~ /\A\(\s*SELECT\s+/mi # HACK - this parser isn't so great join_operand = table_spec + on_clause # So now we have something like: # join_operand == "appointments WITH(ROWLOCK,UPDLOCK) " # join_operator == "INNER JOIN " # or: # join_operand == "appointment_details AS d1 WITH(ROWLOCK,UPDLOCK) ON appointments.[id] = d1.[appointment_id]" # join_operator == "" new_from_tables << join_operand new_from_tables << join_operator end sql.replace( select_clause.to_s << from_word.to_s << new_from_tables.join << where_clause.to_s ) end sql end |