Fix direct query execution issues in PG by using select_values/select_rows instead of execute.

This commit is contained in:
Raphael Sofaer 2011-06-22 14:47:59 -07:00
parent 02739259b6
commit e8552fc417
7 changed files with 23 additions and 38 deletions

View file

@ -56,19 +56,14 @@ class ConversationsController < ApplicationController
end end
def new def new
all_contacts_and_ids = Contact.connection.execute(current_user.contacts.joins(:person => :profile all_contacts_and_ids = Contact.connection.select_rows(
).select("contacts.id, profiles.first_name, profiles.last_name, people.diaspora_handle").to_sql).map do |r| current_user.contacts.joins(:person => :profile).
person_json_from_row r select("contacts.id, profiles.first_name, profiles.last_name, people.diaspora_handle").to_sql
end ).map{|r| {:value => r[0], :name => Person.name_from_attrs(r[1], r[2], r[3]).gsub(/(")/, "'")} }
@contacts_json = all_contacts_and_ids.to_json.gsub!(/(")/, '\\"') @contacts_json = all_contacts_and_ids.to_json.gsub!(/(")/, '\\"')
@contact = current_user.contacts.find(params[:contact_id]) if params[:contact_id] @contact = current_user.contacts.find(params[:contact_id]) if params[:contact_id]
render :layout => false render :layout => false
end end
def person_json_from_row r
r = [r["id"], r["first_name"], r["last_name"], r["diaspora_handle"]] if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) && ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
{:value => r[0],
:name => Person.name_from_attrs(r[1], r[2], r[3]).gsub(/(")/, "'")}
end
end end

View file

@ -23,9 +23,9 @@ class ActivityStreams::Photo < Post
def socket_to_user(user_or_id, opts={}) #adds aspect_ids to opts if they are not there def socket_to_user(user_or_id, opts={}) #adds aspect_ids to opts if they are not there
unless opts[:aspect_ids] unless opts[:aspect_ids]
user_id = user_or_id.instance_of?(Fixnum) ? user_or_id : user_or_id.id user_id = user_or_id.instance_of?(Fixnum) ? user_or_id : user_or_id.id
aspect_ids = AspectMembership.connection.execute( aspect_ids = AspectMembership.connection.select_values(
AspectMembership.joins(:contact).where(:contacts => {:user_id => user_id, :person_id => self.author_id}).select('aspect_memberships.aspect_id').to_sql AspectMembership.joins(:contact).where(:contacts => {:user_id => user_id, :person_id => self.author_id}).select('aspect_memberships.aspect_id').to_sql
).map{|r| r.first} )
opts.merge!(:aspect_ids => aspect_ids) opts.merge!(:aspect_ids => aspect_ids)
end end
super(user_or_id, opts) super(user_or_id, opts)

View file

@ -80,7 +80,7 @@ class Person < ActiveRecord::Base
# @return [Array<String>] postgreSQL and mysql deal with null values in orders differently, it seems. # @return [Array<String>] postgreSQL and mysql deal with null values in orders differently, it seems.
def self.search_order def self.search_order
@search_order ||= Proc.new { @search_order ||= Proc.new {
order = if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) && ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) order = if postgres?
"ASC" "ASC"
else else
"DESC" "DESC"

View file

@ -132,9 +132,9 @@ class StatusMessage < Post
def socket_to_user(user_or_id, opts={}) def socket_to_user(user_or_id, opts={})
unless opts[:aspect_ids] unless opts[:aspect_ids]
user_id = user_or_id.instance_of?(Fixnum) ? user_or_id : user_or_id.id user_id = user_or_id.instance_of?(Fixnum) ? user_or_id : user_or_id.id
aspect_ids = AspectMembership.connection.execute( aspect_ids = AspectMembership.connection.select_values(
AspectMembership.joins(:contact).where(:contacts => {:user_id => user_id, :person_id => self.author_id}).select('aspect_memberships.aspect_id').to_sql AspectMembership.joins(:contact).where(:contacts => {:user_id => user_id, :person_id => self.author_id}).select('aspect_memberships.aspect_id').to_sql
).map{|r| r.first} )
opts.merge!(:aspect_ids => aspect_ids) opts.merge!(:aspect_ids => aspect_ids)
end end
super(user_or_id, opts) super(user_or_id, opts)

View file

@ -36,3 +36,8 @@ module Devise
end end
end end
end end
# check what database you have
def postgres?
@using_postgres ||= defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) && ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
end

View file

@ -48,26 +48,11 @@ module Diaspora
all_posts = "#{posts_from_others.to_sql} UNION ALL #{posts_from_self.to_sql} ORDER BY #{opts[:order]} LIMIT #{opts[:limit]}" all_posts = "#{posts_from_others.to_sql} UNION ALL #{posts_from_self.to_sql} ORDER BY #{opts[:order]} LIMIT #{opts[:limit]}"
end end
post_ids = Post.connection.execute(all_posts).map {|post| id_for(post) } post_ids = Post.connection.select_values(all_posts)
Post.where(:id => post_ids).select('DISTINCT posts.*').limit(opts[:limit]).order(order_with_table) Post.where(:id => post_ids).select('DISTINCT posts.*').limit(opts[:limit]).order(order_with_table)
end end
# Determine, cache, and execute the method call needed to extract the id from a raw result row.
# Returns row["id"] for PostgreSQL
# Returns row.first for everything else (MYSQL)
#
# @param row The row to get the id from.
# @return The id of the database row passed in.
def id_for row
@@id_method_for_row ||= if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) && ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
[:[], "id"]
else
:first
end
row.send(*@@id_method_for_row)
end
def visible_photos(opts = {}) def visible_photos(opts = {})
visible_posts(opts.merge(:type => 'Photo')) visible_posts(opts.merge(:type => 'Photo'))
end end
@ -117,9 +102,13 @@ module Diaspora
p = Post.arel_table p = Post.arel_table
post_ids = [] post_ids = []
if contact = self.contact_for(person) if contact = self.contact_for(person)
post_ids = Post.connection.execute(contact.post_visibilities.where(:hidden => false).select('post_visibilities.post_id').to_sql).map{|r| r.first} post_ids = Post.connection.select_values(
contact.post_visibilities.where(:hidden => false).select('post_visibilities.post_id').to_sql
)
end end
post_ids += Post.connection.execute(person.posts.where(:public => true).select('posts.id').to_sql).map{|r| r.first} post_ids += Post.connection.select_values(
person.posts.where(:public => true).select('posts.id').to_sql
)
Post.where(:id => post_ids, :pending => false).select('DISTINCT posts.*').order("posts.created_at DESC") Post.where(:id => post_ids, :pending => false).select('DISTINCT posts.*').order("posts.created_at DESC")
end end

View file

@ -81,9 +81,5 @@ def remote_raphael
end end
def photo_fixture_name def photo_fixture_name
@photo_fixture_name = File.join(File.dirname(__FILE__), 'fixtures', 'button.png') @photo_fixture_name = File.join(File.dirname(__FILE__), 'fixtures', 'button.png')
end
def postgres?
defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) && ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
end end