From 15d6e4dce7126fe24bce5cdb91d2ffee68648420 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Mon, 28 May 2012 12:23:37 -0700 Subject: Fix that #exists? can produce invalid SQL: "SELECT DISTINCT DISTINCT" The combination of a :uniq => true association and the #distinct call in #construct_limited_ids_condition combine to create invalid SQL, because we're explicitly selecting DISTINCT, and also sending #distinct on to AREL, via the relation#distinct_value. Rather than build a select distinct clause in #construct_limited_ids_condition, I set #distinct! and pass just the columns into the select statement. This requires introducing a #columns_for_distinct method to return the select columns but not the statement itself. --- .../connection_adapters/abstract/schema_statements.rb | 14 +++++++++++--- .../connection_adapters/postgresql/schema_statements.rb | 9 ++------- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 9c0c4e3ef0..6e1f43cce6 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -706,12 +706,20 @@ module ActiveRecord end # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. - # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax. # - # distinct("posts.id", "posts.created_at desc") + # distinct("posts.id", ["posts.created_at desc"]) # def distinct(columns, order_by) - "DISTINCT #{columns}" + "DISTINCT #{columns_for_distinct(columns, order_by)}" + end + + # Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT. + # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax - they + # require the order columns appear in the SELECT. + # + # columns_for_distinct("posts.id", ["posts.created_at desc"]) + def columns_for_distinct(columns, orders) + columns end # Adds timestamps (+created_at+ and +updated_at+) columns to the named table. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 98916b06a5..8feee23df0 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -467,14 +467,9 @@ module ActiveRecord end end - # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. - # # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and # requires that the ORDER BY include the distinct column. - # - # distinct("posts.id", ["posts.created_at desc"]) - # # => "DISTINCT posts.id, posts.created_at AS alias_0" - def distinct(columns, orders) #:nodoc: + def columns_for_distinct(columns, orders) #:nodoc: order_columns = orders.map{ |s| # Convert Arel node to string s = s.to_sql unless s.is_a?(String) @@ -482,7 +477,7 @@ module ActiveRecord s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '') }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" } - [super].concat(order_columns).join(', ') + [super, *order_columns].join(', ') end end end -- cgit v1.2.3