module ActiveRecord::ConnectionAdapters::DatabaseStatements
def add_limit!(sql, options)
def add_limit!(sql, options) add_limit_offset!(sql, options) if options end
def add_limit_offset!(sql, options)
generates
add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50})
===== Examples
This method *modifies* the +sql+ parameter.
and an +:offset+ option (optional).
+options+ must be a Hash which contains a +:limit+ option (required)
fragment that has the same semantics as LIMIT and OFFSET.
Appends +LIMIT+ and +OFFSET+ options to an SQL statement, or some SQL
def add_limit_offset!(sql, options) if limit = options[:limit] sql << " LIMIT #{sanitize_limit(limit)}" if offset = options[:offset] sql << " OFFSET #{offset.to_i}" end end sql end
def add_lock!(sql, options)
add_lock! 'SELECT * FROM suppliers', :lock => true
# SELECT * FROM suppliers FOR UPDATE
This method *modifies* the +sql+ parameter.
Appends a locking clause to an SQL statement.
def add_lock!(sql, options) case lock = options[:lock] when true; sql << ' FOR UPDATE' when String; sql << " #{lock}" end end
def begin_db_transaction() end
def begin_db_transaction() end
def case_sensitive_equality_operator
def case_sensitive_equality_operator "=" end
def commit_db_transaction() end
def commit_db_transaction() end
def default_sequence_name(table, column)
def default_sequence_name(table, column) nil end
def delete(sql, name = nil)
def delete(sql, name = nil) delete_sql(sql, name) end
def delete_sql(sql, name = nil)
def delete_sql(sql, name = nil) update_sql(sql, name) end
def empty_insert_statement(table_name)
def empty_insert_statement(table_name) "INSERT INTO #{quote_table_name(table_name)} VALUES(DEFAULT)" end
def execute(sql, name = nil, skip_logging = false)
def execute(sql, name = nil, skip_logging = false) end
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) insert_sql(sql, name, pk, id_value, sequence_name) end
def insert_fixture(fixture, table_name)
Inserts the given fixture into the table. Overridden in adapters that require
def insert_fixture(fixture, table_name) execute "INSERT INTO #{quote_table_name(table_name)} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert' end
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) execute(sql, name) id_value end
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})" end
def outside_transaction?
Not all adapters supports transaction state introspection. Currently,
transaction active, and nil if this information is unknown.
Returns true if there is no transaction active, false if there is a
friends.
house-keeping information recorded by #increment_open_transactions and
by querying the database driver, and does not use the transaction
Checks whether there is currently no transaction active. This is done
def outside_transaction? nil end
def reset_sequence!(table, column, sequence = nil)
def reset_sequence!(table, column, sequence = nil) # Do nothing by default. Implement for PostgreSQL, Oracle, ... end
def rollback_db_transaction() end
Rolls back the transaction (and turns on auto-committing). Must be
def rollback_db_transaction() end
def sanitize_limit(limit)
Returns the sanitized limit parameter, either as an integer, or as a
should look like an integer, or a comma-delimited list of integers.
+limit+ may be anything that can evaluate to a string via #to_s. It
Sanitizes the given LIMIT parameter in order to prevent SQL injection.
def sanitize_limit(limit) if limit.to_s =~ /,/ limit.to_s.split(',').map{ |i| i.to_i }.join(',') else limit.to_i end end
def select(sql, name = nil)
Returns an array of record hashes with the column names as keys and
def select(sql, name = nil) end
def select_all(sql, name = nil)
Returns an array of record hashes with the column names as keys and
def select_all(sql, name = nil) select(sql, name) end
def select_one(sql, name = nil)
Returns a record hash with the column names as keys and column values
def select_one(sql, name = nil) result = select_all(sql, name) result.first if result end
def select_rows(sql, name = nil)
Returns an array of arrays containing the field values.
def select_rows(sql, name = nil) end
def select_value(sql, name = nil)
def select_value(sql, name = nil) if result = select_one(sql, name) result.values.first end end
def select_values(sql, name = nil)
Returns an array of the values of the first column in a select:
def select_values(sql, name = nil) result = select_rows(sql, name) result.map { |v| v[0] } end
def transaction(options = {})
end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
# active_record_1 now automatically released
Model.connection.create_table(...)
Model.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1
Model.connection.transaction do # BEGIN
already-automatically-released savepoints:
#transaction will raise exceptions when it tries to release the
a #transaction call that you know might create a savepoint. Otherwise,
This means that, on MySQL, you shouldn't execute DDL operations inside
then the savepoint that was created will be automatically released.
if you've created a savepoint, then you execute a CREATE TABLE statement,
then any created savepoints will be automatically released. For example,
MySQL doesn't support DDL transactions. If you perform a DDL operation,
=== Caveats
database savepoint acting as a sub-transaction.
- However, if +:requires_new+ is set, the block will be wrapped in a
open database transaction.
that happen within the block are effectively appended to the already
- The block will be run without doing anything. All database statements
of a nested call, #transaction will behave as follows:
i.e. if #transaction is called within another #transaction block. In case
It is safe to call this method if a database transaction is already open,
Savepoints are supported by MySQL and PostgreSQL, but not SQLite3.
http://dev.mysql.com/doc/refman/5.0/en/savepoints.html
of nested transactions, by using savepoints:
In order to get around this problem, #transaction will emulate the effect
we're aware of, is MS-SQL.
writing, the only database that supports true nested transactions that
Most databases don't support true nested transactions. At the time of
== Nested transactions support
of the block.
Runs the given block in a database transaction, and returns the result
def transaction(options = {}) options.assert_valid_keys :requires_new, :joinable last_transaction_joinable = @transaction_joinable if options.has_key?(:joinable) @transaction_joinable = options[:joinable] else @transaction_joinable = true end requires_new = options[:requires_new] || !last_transaction_joinable transaction_open = false begin if block_given? if requires_new || open_transactions == 0 if open_transactions == 0 begin_db_transaction elsif requires_new create_savepoint end increment_open_transactions transaction_open = true end yield end rescue Exception => database_transaction_rollback if transaction_open && !outside_transaction? transaction_open = false decrement_open_transactions if open_transactions == 0 rollback_db_transaction else rollback_to_savepoint end end raise unless database_transaction_rollback.is_a?(ActiveRecord::Rollback) end ensure @transaction_joinable = last_transaction_joinable if outside_transaction? @open_transactions = 0 elsif transaction_open decrement_open_transactions begin if open_transactions == 0 commit_db_transaction else release_savepoint end rescue Exception => database_transaction_rollback if open_transactions == 0 rollback_db_transaction else rollback_to_savepoint end raise end end end
def update(sql, name = nil)
def update(sql, name = nil) update_sql(sql, name) end
def update_sql(sql, name = nil)
def update_sql(sql, name = nil) execute(sql, name) end