diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2017-05-28 09:29:49 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2018-06-07 09:58:20 +0900 |
commit | 63e35a1323b6a9b7ad7c90217116cdc99a45da1d (patch) | |
tree | e9f69cb46ac84e98ec9b725122723e2a14811835 /activerecord | |
parent | 5dc72378b783e924c5bf079ca660388ec4ac9224 (diff) | |
download | rails-63e35a1323b6a9b7ad7c90217116cdc99a45da1d.tar.gz rails-63e35a1323b6a9b7ad7c90217116cdc99a45da1d.tar.bz2 rails-63e35a1323b6a9b7ad7c90217116cdc99a45da1d.zip |
Fix GROUP BY queries to apply LIMIT/OFFSET after aggregations
If `eager_loading` is true, `apply_join_dependency` force applies
LIMIT/OFFSET before JOINs by `limited_ids_for` to keep parent records
count. But for aggregation queries, LIMIT/OFFSET should be applied after
aggregations the same as SQL semantics.
And also, we could not replace SELECT list by `limited_ids_for` when a
query has a GROUP BY clause. It had never been worked since it will
causes generating invalid SQL for MySQL, PostgreSQL, and probably most
backends.
```
% ARCONN=postgresql be ruby -w -Itest test/cases/calculations_test.rb -n test_group_by_with_limit
Using postgresql
Run options: -n test_group_by_with_limit --seed 20925
# Running:
E
Error:
CalculationsTest#test_group_by_with_limit:
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "posts.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT DISTINCT "posts"."id", "posts"."type" AS alias_0 FRO... ^
: SELECT DISTINCT "posts"."id", "posts"."type" AS alias_0 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" GROUP BY "posts"."type" ORDER BY "posts"."type" ASC LIMIT $1
```
Fixes #8103.
Closes #27249.
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/lib/active_record/relation/finder_methods.rb | 2 | ||||
-rw-r--r-- | activerecord/test/cases/calculations_test.rb | 18 |
2 files changed, 19 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index f7613a187d..31fb8ce0e5 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -379,7 +379,7 @@ module ActiveRecord ) end - def apply_join_dependency(eager_loading: true) + def apply_join_dependency(eager_loading: group_values.empty?) join_dependency = construct_join_dependency relation = except(:includes, :eager_load, :preload).joins!(join_dependency) diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 080d2a54bc..6ceac59eec 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -705,6 +705,24 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [], Topic.includes(:replies).order(:id).offset(5).pluck(:id) end + def test_group_by_with_limit + expected = { "Post" => 8, "SpecialPost" => 1 } + actual = Post.includes(:comments).group(:type).order(:type).limit(2).count("comments.id") + assert_equal expected, actual + end + + def test_group_by_with_offset + expected = { "SpecialPost" => 1, "StiPost" => 2 } + actual = Post.includes(:comments).group(:type).order(:type).offset(1).count("comments.id") + assert_equal expected, actual + end + + def test_group_by_with_limit_and_offset + expected = { "SpecialPost" => 1 } + actual = Post.includes(:comments).group(:type).order(:type).offset(1).limit(1).count("comments.id") + assert_equal expected, actual + end + def test_pluck_not_auto_table_name_prefix_if_column_included Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) ids = Company.includes(:contracts).pluck(:developer_id) |