aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorRyuta Kamizono <kamipo@gmail.com>2019-02-08 21:28:50 +0900
committerRyuta Kamizono <kamipo@gmail.com>2019-02-08 21:28:50 +0900
commit07dcd99a5a5b0ccbaa91e0d18e3b7b165fecffb1 (patch)
treece89b6445e4a9215992875cb447284614fb33c68 /activerecord
parent4cb1438b57067d637c79d49d0662c43b5b4e64c2 (diff)
downloadrails-07dcd99a5a5b0ccbaa91e0d18e3b7b165fecffb1.tar.gz
rails-07dcd99a5a5b0ccbaa91e0d18e3b7b165fecffb1.tar.bz2
rails-07dcd99a5a5b0ccbaa91e0d18e3b7b165fecffb1.zip
Fix `relation.exists?` with giving both `distinct` and `offset`
The `distinct` affects (reduces) rows of the result, so it is important part when both `distinct` and `offset` are given. Replacing SELECT clause to `1 AS one` and removing `distinct` and `order` is just optimization for the `exists?`, we should not apply the optimization for that case. Fixes #35191.
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb12
-rw-r--r--activerecord/test/cases/finder_test.rb10
2 files changed, 18 insertions, 4 deletions
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 8f1065c1e7..91cfc4e849 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -307,8 +307,6 @@ module ActiveRecord
return false if !conditions || limit_value == 0
- conditions = sanitize_forbidden_attributes(conditions)
-
if eager_loading?
relation = apply_join_dependency(eager_loading: false)
return relation.exists?(conditions)
@@ -316,7 +314,7 @@ module ActiveRecord
relation = construct_relation_for_exists(conditions)
- skip_query_cache_if_necessary { connection.select_value(relation.arel, "#{name} Exists") } ? true : false
+ skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists") } ? true : false
end
# This method is called whenever no records are found with either a single
@@ -354,7 +352,13 @@ module ActiveRecord
end
def construct_relation_for_exists(conditions)
- relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
+ conditions = sanitize_forbidden_attributes(conditions)
+
+ if distinct_value && offset_value
+ relation = limit(1)
+ else
+ relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
+ end
case conditions
when Array, Hash
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 6af2a43c7f..4040682280 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -271,6 +271,16 @@ class FinderTest < ActiveRecord::TestCase
assert_equal true, Topic.exists?({})
end
+ def test_exists_with_distinct_and_offset_and_joins
+ assert Post.left_joins(:comments).distinct.offset(10).exists?
+ assert_not Post.left_joins(:comments).distinct.offset(11).exists?
+ end
+
+ def test_exists_with_distinct_and_offset_and_select
+ assert Post.select(:body).distinct.offset(3).exists?
+ assert_not Post.select(:body).distinct.offset(4).exists?
+ end
+
# Ensure +exists?+ runs without an error by excluding distinct value.
# See https://github.com/rails/rails/pull/26981.
def test_exists_with_order_and_distinct