mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
exec returns an AR::Result
This commit is contained in:
@@ -448,8 +448,8 @@ module ActiveRecord #:nodoc:
|
||||
# # You can use the same string replacement techniques as you can with ActiveRecord#find
|
||||
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
|
||||
# > [#<Post:0x36bff9c @attributes={"first_name"=>"The Cheap Man Buys Twice"}>, ...]
|
||||
def find_by_sql(sql)
|
||||
connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
|
||||
def find_by_sql(sql, bind_values = [])
|
||||
connection.select_all(sanitize_sql(sql), "#{name} Load", bind_values).collect! { |record| instantiate(record) }
|
||||
end
|
||||
|
||||
# Creates an object (or multiple objects) and saves it to the database, if validations pass.
|
||||
|
||||
@@ -3,8 +3,8 @@ module ActiveRecord
|
||||
module DatabaseStatements
|
||||
# Returns an array of record hashes with the column names as keys and
|
||||
# column values as values.
|
||||
def select_all(sql, name = nil)
|
||||
select(sql, name)
|
||||
def select_all(sql, name = nil, bind_values = [])
|
||||
select(sql, name, bind_values)
|
||||
end
|
||||
|
||||
# Returns a record hash with the column names as keys and column values
|
||||
@@ -260,7 +260,7 @@ module ActiveRecord
|
||||
protected
|
||||
# Returns an array of record hashes with the column names as keys and
|
||||
# column values as values.
|
||||
def select(sql, name = nil)
|
||||
def select(sql, name = nil, bind_values = [])
|
||||
end
|
||||
undef_method :select
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ require 'active_record/connection_adapters/abstract/connection_pool'
|
||||
require 'active_record/connection_adapters/abstract/connection_specification'
|
||||
require 'active_record/connection_adapters/abstract/query_cache'
|
||||
require 'active_record/connection_adapters/abstract/database_limits'
|
||||
require 'active_record/result'
|
||||
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters # :nodoc:
|
||||
|
||||
@@ -50,6 +50,7 @@ module ActiveRecord
|
||||
|
||||
def initialize(connection, logger, config)
|
||||
super(connection, logger)
|
||||
@statements = {}
|
||||
@config = config
|
||||
end
|
||||
|
||||
@@ -131,6 +132,27 @@ module ActiveRecord
|
||||
|
||||
# DATABASE STATEMENTS ======================================
|
||||
|
||||
def exec(sql, name = nil, bind_values = [])
|
||||
log(sql, name) do
|
||||
|
||||
# Don't cache statements without bind values
|
||||
if bind_values.empty?
|
||||
stmt = @connection.prepare(sql)
|
||||
cols = stmt.columns
|
||||
else
|
||||
cache = @statements[sql] ||= {
|
||||
:stmt => @connection.prepare(sql)
|
||||
}
|
||||
stmt = cache[:stmt]
|
||||
cols = cache[:cols] ||= stmt.columns
|
||||
stmt.reset!
|
||||
stmt.bind_params bind_values.map { |col, val| val }
|
||||
end
|
||||
|
||||
ActiveRecord::Result.new(cols, stmt.to_a)
|
||||
end
|
||||
end
|
||||
|
||||
def execute(sql, name = nil) #:nodoc:
|
||||
log(sql, name) { @connection.execute(sql) }
|
||||
end
|
||||
@@ -280,8 +302,8 @@ module ActiveRecord
|
||||
end
|
||||
|
||||
protected
|
||||
def select(sql, name = nil) #:nodoc:
|
||||
execute(sql, name).map do |row|
|
||||
def select(sql, name = nil, bind_values = []) #:nodoc:
|
||||
exec(sql, name, bind_values).map do |row|
|
||||
record = {}
|
||||
row.each do |key, value|
|
||||
record[key.sub(/^"?\w+"?\./, '')] = value if key.is_a?(String)
|
||||
|
||||
@@ -61,7 +61,7 @@ module ActiveRecord
|
||||
def to_a
|
||||
return @records if loaded?
|
||||
|
||||
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql)
|
||||
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql, @bind_values)
|
||||
|
||||
preload = @preload_values
|
||||
preload += @includes_values unless eager_loading?
|
||||
|
||||
30
activerecord/lib/active_record/result.rb
Normal file
30
activerecord/lib/active_record/result.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
module ActiveRecord
|
||||
###
|
||||
# This class encapsulates a Result returned from calling +exec+ on any
|
||||
# database connection adapter. For example:
|
||||
#
|
||||
# x = ActiveRecord::Base.connection.exec('SELECT * FROM foo')
|
||||
# x # => #<ActiveRecord::Result:0xdeadbeef>
|
||||
class Result
|
||||
include Enumerable
|
||||
|
||||
attr_reader :columns, :rows
|
||||
|
||||
def initialize(columns, rows)
|
||||
@columns = columns
|
||||
@rows = rows
|
||||
@hash_rows = nil
|
||||
end
|
||||
|
||||
def each
|
||||
hash_rows.each { |row| yield row }
|
||||
end
|
||||
|
||||
private
|
||||
def hash_rows
|
||||
@hash_rows ||= @rows.map { |row|
|
||||
ActiveSupport::OrderedHash[@columns.zip(row)]
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -60,6 +60,41 @@ module ActiveRecord
|
||||
bind_param = conn.substitute_for('foo', [])
|
||||
assert_equal Arel.sql('?'), bind_param
|
||||
end
|
||||
|
||||
def test_exec_no_binds
|
||||
conn = Base.sqlite3_connection :database => ':memory:',
|
||||
:adapter => 'sqlite3',
|
||||
:timeout => 100
|
||||
|
||||
conn.exec('create table ex(id int, data string)')
|
||||
result = conn.exec('SELECT id, data FROM ex')
|
||||
assert_equal 0, result.rows.length
|
||||
assert_equal 2, result.columns.length
|
||||
assert_equal %w{ id data }, result.columns
|
||||
|
||||
conn.exec('INSERT INTO ex (id, data) VALUES (1, "foo")')
|
||||
result = conn.exec('SELECT id, data FROM ex')
|
||||
assert_equal 1, result.rows.length
|
||||
assert_equal 2, result.columns.length
|
||||
|
||||
assert_equal [[1, 'foo']], result.rows
|
||||
end
|
||||
|
||||
def test_exec_with_binds
|
||||
conn = Base.sqlite3_connection :database => ':memory:',
|
||||
:adapter => 'sqlite3',
|
||||
:timeout => 100
|
||||
|
||||
conn.exec('create table ex(id int, data string)')
|
||||
conn.exec('INSERT INTO ex (id, data) VALUES (1, "foo")')
|
||||
result = conn.exec(
|
||||
'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]])
|
||||
|
||||
assert_equal 1, result.rows.length
|
||||
assert_equal 2, result.columns.length
|
||||
|
||||
assert_equal [[1, 'foo']], result.rows
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -55,6 +55,14 @@ ActiveRecord::Base.connection.class.class_eval do
|
||||
end
|
||||
|
||||
alias_method_chain :execute, :query_record
|
||||
|
||||
def exec_with_query_record(sql, name = nil, binds = [], &block)
|
||||
$queries_executed ||= []
|
||||
$queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r }
|
||||
exec_without_query_record(sql, name, binds, &block)
|
||||
end
|
||||
|
||||
alias_method_chain :exec, :query_record
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connection.class.class_eval {
|
||||
|
||||
Reference in New Issue
Block a user