aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schùˆrrer <martin@schuerrer.org>2014-03-03 17:44:55 +0100
committerMartin Schùˆrrer <martin@schuerrer.org>2014-03-04 10:05:30 +0100
commitf317cc8bc007978d7b135ddd1acdd7e3d1e582a3 (patch)
tree26894ebe8a7d684799fd3397b861db769e3f877b
parentffcc6172b4d40ca7c8b02fd298c679b5bcf5787b (diff)
downloadrails-f317cc8bc007978d7b135ddd1acdd7e3d1e582a3.tar.gz
rails-f317cc8bc007978d7b135ddd1acdd7e3d1e582a3.tar.bz2
rails-f317cc8bc007978d7b135ddd1acdd7e3d1e582a3.zip
Make exists? use bound values.
When we build a query with an inline value that is a numeric (e.g. because it's out of range for an int4) PostgreSQL doesn't use an index on the column, since it's now comparing numerics and not int4s. This leads to a _very_ slow query. When we use bound parameters instead of inline values PostgreSQL raises numeric_value_out_of_range since no automatic coercion happens.
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb7
-rw-r--r--activerecord/test/cases/finder_test.rb16
2 files changed, 20 insertions, 3 deletions
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 7099bdd285..1ba7fc47c0 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -292,7 +292,12 @@ module ActiveRecord
when Array, Hash
relation = relation.where(conditions)
else
- relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none
+ if conditions != :none
+ column = columns_hash[primary_key]
+ substitute = connection.substitute_at(column, bind_values.length)
+ relation = where(table[primary_key].eq(substitute))
+ relation.bind_values += [[column, conditions]]
+ end
end
connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index b1eded6494..78c4e02434 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -58,15 +58,27 @@ class FinderTest < ActiveRecord::TestCase
assert_equal false, Topic.exists?(45)
assert_equal false, Topic.exists?(Topic.new)
+ assert_raise(NoMethodError) { Topic.exists?([1,2]) }
+ end
+
+ def test_exists_fails_when_parameter_has_invalid_type
+ begin
+ assert_equal false, Topic.exists?(("9"*53).to_i) # number that's bigger than int
+ flunk if defined? ActiveRecord::ConnectionAdapters::PostgreSQLAdapter and Topic.connection.is_a? ActiveRecord::ConnectionAdapters::PostgreSQLAdapter # PostgreSQL does raise here
+ rescue ActiveRecord::StatementInvalid
+ # PostgreSQL complains that it can't coerce a numeric that's bigger than int into int
+ rescue Exception
+ flunk
+ end
+
begin
assert_equal false, Topic.exists?("foo")
+ flunk if defined? ActiveRecord::ConnectionAdapters::PostgreSQLAdapter and Topic.connection.is_a? ActiveRecord::ConnectionAdapters::PostgreSQLAdapter # PostgreSQL does raise here
rescue ActiveRecord::StatementInvalid
# PostgreSQL complains about string comparison with integer field
rescue Exception
flunk
end
-
- assert_raise(NoMethodError) { Topic.exists?([1,2]) }
end
def test_exists_does_not_select_columns_without_alias