mirror of https://github.com/rails/rails
Expand the number of types which can use prepared statements
This will allow all types which require no additional handling to use prepared statements. Specifically, this will allow for `true`, `false`, `Date`, `Time`, and any custom PG type to use prepared statements. This also revealed another source of nil columns in bind params, and an inconsistency in their use. The specific inconsistency comes from a nested query coming from a through association, where one of the inversed associations is not bi-directional. The stop-gap is to simply construct the column at the site it is being used. This should simply go away on its own once we use `Attribute` to represent them instead, since we already have all of the information we need.
This commit is contained in:
parent
ae8cd56c7b
commit
3327cd3f61
|
@ -99,15 +99,17 @@ module ActiveRecord
|
||||||
|
|
||||||
attributes.each do |column_name, value|
|
attributes.each do |column_name, value|
|
||||||
case value
|
case value
|
||||||
when String, Integer, ActiveRecord::StatementCache::Substitute
|
|
||||||
result[column_name] = Arel::Nodes::BindParam.new
|
|
||||||
binds.push([table.column(column_name), value])
|
|
||||||
when Hash
|
when Hash
|
||||||
attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
|
attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
|
||||||
result[column_name] = attrs
|
result[column_name] = attrs
|
||||||
binds += bvs
|
binds += bvs
|
||||||
when Relation
|
when Relation
|
||||||
binds += value.arel.bind_values + value.bind_values
|
binds += value.arel.bind_values + value.bind_values
|
||||||
|
else
|
||||||
|
if can_be_bound?(column_name, value)
|
||||||
|
result[column_name] = Arel::Nodes::BindParam.new
|
||||||
|
binds.push([table.column(column_name), value])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -137,5 +139,11 @@ module ActiveRecord
|
||||||
def handler_for(object)
|
def handler_for(object)
|
||||||
@handlers.detect { |klass, _| klass === object }.last
|
@handlers.detect { |klass, _| klass === object }.last
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_be_bound?(column_name, value)
|
||||||
|
!value.nil? &&
|
||||||
|
handler_for(value).is_a?(BasicObjectHandler) &&
|
||||||
|
!table.associated_with?(column_name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -944,12 +944,11 @@ module ActiveRecord
|
||||||
[@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
|
[@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
|
||||||
when Hash
|
when Hash
|
||||||
opts = predicate_builder.resolve_column_aliases(opts)
|
opts = predicate_builder.resolve_column_aliases(opts)
|
||||||
|
opts = @klass.send(:expand_hash_conditions_for_aggregates, opts)
|
||||||
|
|
||||||
tmp_opts, bind_values = predicate_builder.create_binds(opts)
|
attributes, bind_values = predicate_builder.create_binds(opts)
|
||||||
self.bind_values += bind_values
|
self.bind_values += bind_values
|
||||||
|
|
||||||
attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
|
|
||||||
|
|
||||||
predicate_builder.build_from_hash(attributes)
|
predicate_builder.build_from_hash(attributes)
|
||||||
else
|
else
|
||||||
[opts]
|
[opts]
|
||||||
|
|
|
@ -25,6 +25,9 @@ module ActiveRecord
|
||||||
def column(column_name)
|
def column(column_name)
|
||||||
if klass
|
if klass
|
||||||
klass.columns_hash[column_name.to_s]
|
klass.columns_hash[column_name.to_s]
|
||||||
|
else
|
||||||
|
# FIXME: We really shouldn't need to do this.
|
||||||
|
ConnectionAdapters::Column.new(column_name.to_s, nil, Type::Value.new)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue