mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #12588 from jetthoughts/12586_subquery_with_unprepared_sql
Inline bind values for sub-queries generated for Relation in where Conflicts: activerecord/CHANGELOG.md
This commit is contained in:
commit
b98c10c164
4 changed files with 56 additions and 6 deletions
|
@ -1,3 +1,12 @@
|
|||
* Sub-query generated for `Relation` passed as array condition did not take in account
|
||||
bind values and have invalid syntax.
|
||||
|
||||
Generate sub-query with inline bind values.
|
||||
|
||||
Fixes: #12586
|
||||
|
||||
*Paul Nikitochkin*
|
||||
|
||||
* Fix a bug where rake db:structure:load crashed when the path contained
|
||||
spaces.
|
||||
|
||||
|
@ -8,9 +17,9 @@
|
|||
Allows you to call `#unscope` on a relation with negative equality
|
||||
operators, i.e. `Arel::Nodes::NotIn` and `Arel::Nodes::NotEqual` that have
|
||||
been generated through the use of `where.not`.
|
||||
|
||||
|
||||
*Eric Hankins*
|
||||
|
||||
|
||||
* Raise an exception when model without primary key calls `.find_with_ids`.
|
||||
|
||||
*Shimpei Makimoto*
|
||||
|
|
|
@ -894,6 +894,13 @@ module ActiveRecord
|
|||
def build_where(opts, other = [])
|
||||
case opts
|
||||
when String, Array
|
||||
#TODO: Remove duplication with: /activerecord/lib/active_record/sanitization.rb:113
|
||||
values = Hash === other.first ? other.first.values : other
|
||||
|
||||
values.grep(ActiveRecord::Relation) do |rel|
|
||||
self.bind_values += rel.bind_values
|
||||
end
|
||||
|
||||
[@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
|
||||
when Hash
|
||||
opts = PredicateBuilder.resolve_column_aliases(klass, opts)
|
||||
|
|
|
@ -639,6 +639,31 @@ class RelationTest < ActiveRecord::TestCase
|
|||
relation = Author.where('id in (?)', Author.where(id: david).select(:id))
|
||||
assert_equal [david], relation.to_a
|
||||
}
|
||||
|
||||
assert_queries(1) do
|
||||
relation = Author.where('id in (:author_ids)', author_ids: Author.where(id: david).select(:id))
|
||||
assert_equal [david], relation.to_a
|
||||
end
|
||||
end
|
||||
|
||||
def test_find_all_using_where_with_relation_with_bound_values
|
||||
david = authors(:david)
|
||||
davids_posts = david.posts.to_a
|
||||
|
||||
assert_queries(1) do
|
||||
relation = Post.where(id: david.posts.select(:id))
|
||||
assert_equal davids_posts, relation.to_a
|
||||
end
|
||||
|
||||
assert_queries(1) do
|
||||
relation = Post.where('id in (?)', david.posts.select(:id))
|
||||
assert_equal davids_posts, relation.to_a, 'should process Relation as bind variables'
|
||||
end
|
||||
|
||||
assert_queries(1) do
|
||||
relation = Post.where('id in (:post_ids)', post_ids: david.posts.select(:id))
|
||||
assert_equal davids_posts, relation.to_a, 'should process Relation as named bind variables'
|
||||
end
|
||||
end
|
||||
|
||||
def test_find_all_using_where_with_relation_and_alternate_primary_key
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
require "cases/helper"
|
||||
require 'models/binary'
|
||||
require 'models/author'
|
||||
require 'models/post'
|
||||
|
||||
class SanitizeTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
|
@ -9,7 +11,7 @@ class SanitizeTest < ActiveRecord::TestCase
|
|||
quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
|
||||
quoted_column_name = ActiveRecord::Base.connection.quote_column_name("name")
|
||||
quoted_table_name = ActiveRecord::Base.connection.quote_table_name("adorable_animals")
|
||||
expected_value = "#{quoted_table_name}.#{quoted_column_name} = #{quoted_bambi}"
|
||||
expected_value = "#{quoted_table_name}.#{quoted_column_name} = #{quoted_bambi}"
|
||||
|
||||
assert_equal expected_value, Binary.send(:sanitize_sql_hash, {adorable_animals: {name: 'Bambi'}})
|
||||
end
|
||||
|
@ -33,8 +35,15 @@ class SanitizeTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_sanitize_sql_array_handles_relations
|
||||
assert_match(/\(\bselect\b.*?\bwhere\b.*?\)/i,
|
||||
Binary.send(:sanitize_sql_array, ["id in (?)", Binary.where(id: 1)]),
|
||||
"should sanitize `Relation` as subquery")
|
||||
david = Author.create!(name: 'David')
|
||||
david_posts = david.posts.select(:id)
|
||||
|
||||
sub_query_pattern = /\(\bselect\b.*?\bwhere\b.*?\)/i
|
||||
|
||||
select_author_sql = Post.send(:sanitize_sql_array, ['id in (?)', david_posts])
|
||||
assert_match(sub_query_pattern, select_author_sql, 'should sanitize `Relation` as subquery for bind variables')
|
||||
|
||||
select_author_sql = Post.send(:sanitize_sql_array, ['id in (:post_ids)', post_ids: david_posts])
|
||||
assert_match(sub_query_pattern, select_author_sql, 'should sanitize `Relation` as subquery for named bind variables')
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue