aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorRafael Mendonça França <rafaelmfranca@gmail.com>2013-10-21 19:13:04 -0200
committerRafael Mendonça França <rafaelmfranca@gmail.com>2013-10-21 19:13:04 -0200
commitb98c10c164ba6d17a84097f57ff529a95fec3935 (patch)
treeb77a7d036f6c0b010d6eefe7baa3c85e5c480982 /activerecord
parenta595fc1c56e5e9f4620bf5f248c87e9cb1e31b2f (diff)
parenta2ed5d2381079716cf6224bc7b0538d318b264a2 (diff)
downloadrails-b98c10c164ba6d17a84097f57ff529a95fec3935.tar.gz
rails-b98c10c164ba6d17a84097f57ff529a95fec3935.tar.bz2
rails-b98c10c164ba6d17a84097f57ff529a95fec3935.zip
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
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md13
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb7
-rw-r--r--activerecord/test/cases/relations_test.rb25
-rw-r--r--activerecord/test/cases/sanitize_test.rb17
4 files changed, 56 insertions, 6 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 97a42ca95b..adcec10fe8 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -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*
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index a53f034345..d01f0384b4 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -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)
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 860bd424b7..55501ea35b 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -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
diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb
index 4c0762deca..766b2ff2ef 100644
--- a/activerecord/test/cases/sanitize_test.rb
+++ b/activerecord/test/cases/sanitize_test.rb
@@ -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