diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2017-12-20 05:09:49 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2017-12-20 06:41:10 +0900 |
commit | c6cd9a59f200863ccfe8ad1d9c5a8876c39b9c5c (patch) | |
tree | 2fbbd9af309f7e01c43a6571744d824ad1f8ae97 /activerecord/lib/active_record/relation | |
parent | eb6baccda26d65c70d0e2df28c6cd51ec3cdb2ac (diff) | |
download | rails-c6cd9a59f200863ccfe8ad1d9c5a8876c39b9c5c.tar.gz rails-c6cd9a59f200863ccfe8ad1d9c5a8876c39b9c5c.tar.bz2 rails-c6cd9a59f200863ccfe8ad1d9c5a8876c39b9c5c.zip |
Fix `count(:all)` to correctly work `distinct` with custom SELECT list
Currently `count(:all)` with `distinct` doesn't work correctly because
SELECT list is always replaced to `*` or primary key in that case even
if having custom SELECT list.
And also, PostgreSQL has a limitation that ORDER BY expressions must
appear in select list for SELECT DISTINCT.
Therefore, we should not replace custom SELECT list when using
`count(:all)` with `distinct`.
Closes #31277.
Diffstat (limited to 'activerecord/lib/active_record/relation')
-rw-r--r-- | activerecord/lib/active_record/relation/calculations.rb | 18 |
1 files changed, 8 insertions, 10 deletions
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index d49472fc70..cb0b06cfdc 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -217,7 +217,7 @@ module ActiveRecord if operation == "count" column_name ||= select_for_count if column_name == :all - if distinct && (group_values.any? || !(has_limit_or_offset? && order_values.any?)) + if distinct && (group_values.any? || select_values.empty? && order_values.empty?) column_name = primary_key end elsif column_name =~ /\s*DISTINCT[\s(]+/i @@ -249,7 +249,7 @@ module ActiveRecord def execute_simple_calculation(operation, column_name, distinct) #:nodoc: column_alias = column_name - if operation == "count" && has_limit_or_offset? + if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?) # Shortcut when limit is zero. return 0 if limit_value == 0 @@ -391,14 +391,12 @@ module ActiveRecord end def build_count_subquery(relation, column_name, distinct) - relation.select_values = [ - if column_name == :all - distinct ? table[Arel.star] : Arel.sql(FinderMethods::ONE_AS_ONE) - else - column_alias = Arel.sql("count_column") - aggregate_column(column_name).as(column_alias) - end - ] + if column_name == :all + relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct + else + column_alias = Arel.sql("count_column") + relation.select_values = [ aggregate_column(column_name).as(column_alias) ] + end subquery = relation.arel.as(Arel.sql("subquery_for_count")) select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false) |