Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #5371 (closed defect: wontfix)

Opened 2 years ago

Last modified 1 year ago

:include loads all columns, overriding :select

Reported by: alex@purefiction.net Assigned to: David
Priority: high Milestone:
Component: ActiveRecord Version: 1.1.1
Severity: normal Keywords: with_scope include find select
Cc: dan@dankohn.com, tarmo@itech.ee

Description

This:

Foo.find(:all, :select => "foos.id, foos.title, (select count(*) from bars where bars.foo_id = foos.id) as count")

performs a select such as this:

SELECT foos.id, foos.title, (select count(*) from bars where bars.foo_id = foos.id) as count FROM foos

But this:

Foo.with_scope(:find => {:include => :bar}) do
  Foo.find(:all, :select => "foos.id, foos.title, (select count(*) from bars where bars.foo_id = foos.id) as count")
end

produces:

SELECT foos."id" AS t0_r0, foos."created_at" AS t0_r1, foos."updated_at" AS t0_r2 FROM foos  LEFT OUTER JOIN bars ON bars.id = foos.bar_id

In other words, the :include overrides the :select, even though you would expect the opposite to happen.

Attachments

options_select_working_with_eager_loading.diff (5.1 kB) - added by paolo.negri on 01/18/07 00:35:53.

Change History

07/09/06 16:03:49 changed by tmacedo@webreakstuff.com

with_scope is not even required to verifiy this bug, this is enough

class DocumentCategory < ActiveRecord::Base

has_many :documents, :select => "id, title, filename, tag, size"

validates_presence_of :name, :project validates_uniqueness_of :name, :scope => 'project_id' validates_length_of :name, :maximum => 255

end

@categories = DocumentCategory.find(:all, :conditions => ['project_id = ?', @project.id], :include => 'documents')

this will perform the following query:

DocumentCategory Load Including Associations (7.225554) SELECT document_categories."id" AS t0_r0, document_categories."name" AS t0_r1, document_categories."project_id" AS t0_r2, documents."id" AS t1_r0, documents."created_at" AS t1_r1, documents."updated_at" AS t1_r2, documents."creator_id" AS t1_r3, documents."modifier_id" AS t1_r4, documents."data" AS t1_r5, documents."tag" AS t1_r6, documents."title" AS t1_r7, documents."filename" AS t1_r8, documents."content_type" AS t1_r9, documents."size" AS t1_r10, documents."document_category_id" AS t1_r11 FROM document_categories LEFT OUTER JOIN documents ON documents.document_category_id = document_categories.id WHERE (project_id = 8)

which is obviously a problem, particularly in this case where one of the columns is binary

07/22/06 09:28:05 changed by anonymous

  • cc set to dan@dankohn.com.
  • summary changed from with_scope with :include overrides nested find's :select to :include loads all columns, overriding :select.

07/31/06 03:51:23 changed by coda.hale@gmail.com

It looks like changing the second line of construct_finder_sql_with_included_associations from this:

sql = "SELECT #{column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || table_name} "

to this:

sql = "SELECT #{options[:select] || column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || table_name} "

will fix the problem. I apologize, but I don't have the time to come up with a decent unit test--perhaps someone more directly affected by this bug could do that.

07/31/06 04:02:27 changed by coda.hale@gmail.com

Wait, no, that last bit kills a bunch of unit tests. I'm not sure if this is possible.

(follow-up: ↓ 6 ) 08/22/06 06:30:34 changed by dave.myron@contentfree.com

It appears that this :include bug has several effects. Also overridden is :finder_sql.

(in reply to: ↑ 5 ) 10/16/06 17:15:50 changed by watersco

In case it helps anyone else, here is a workaround that works for me. I don't understand this code well enough to know what other features this might have broken.

module ActiveRecord
  module Associations
  	module ClassMethods
  	
  	    def find_with_associations(options = {})
          catch :invalid_query do
            join_dependency = JoinDependency.new(self, merge_includes(scope(:find, :include), options[:include]), options[:joins])
            rows = select_all_rows(options, join_dependency)
            
            if options[:select]
            	return rows.collect! { |record| instantiate(record) }
            else
            	return join_dependency.instantiate(rows)
            end
          end
          []
        end
  	
        def construct_finder_sql_with_included_associations(options, join_dependency)
          scope = scope(:find)
          sql = "SELECT #{options[:select] || column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || table_name} "
          sql << join_dependency.join_associations.collect{|join| join.association_join }.join
 
          add_joins!(sql, options, scope)
          add_conditions!(sql, options[:conditions], scope)
          add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && options[:limit]

          sql << "GROUP BY #{options[:group]} " if options[:group]
          sql << "ORDER BY #{options[:order]} " if options[:order]
 
          add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
 
          return sanitize_sql(sql)
        end
    end
  end
end

11/16/06 00:44:52 changed by tarmo

  • cc changed from dan@dankohn.com to dan@dankohn.com, tarmo@itech.ee.

01/18/07 00:35:53 changed by paolo.negri

  • attachment options_select_working_with_eager_loading.diff added.

01/18/07 00:37:58 changed by paolo.negri

I've attached a patch proposal options_select_working_with_eager_loading.diff

It works with :select => 'table_x.col_a, table_y.col_n' don't work with * wildcard, in this case it will fall back on the current behaviour (:select ignored) id (primary keys) will be always extracted from the db for any model included. This patch passes all the tests + the new one introduced with this patch itself. I can put some more work on this if necessary please let me know if this approach seems reasonable enough to be included in the actual framework.

thanks

01/18/07 01:04:43 changed by paolo.negri

I've submitted the same patch

options_select_working_with_eager_loading.diff

as patch #7147

02/24/07 19:20:02 changed by wol

-Any reactions on the patch? On our database, we are otherwise faced with (a) hitting the database with hundreds of queries every time we look at an index, (b) load the returning data with 120 megs of text data which we don't need when we just want to show an index or (c) writing our own sql [which is what the current program does]

04/19/07 00:28:39 changed by marko1

I've been using this patch with good results.

(follow-up: ↓ 14 ) 04/19/07 13:11:59 changed by tmacedo

I had an issue which stopped me from using it:

It only allows you to :select existing columns, you can't use any functions on them.

04/19/07 13:56:01 changed by alex

tmacedo, I doubt that is related to the patch, but rather to how you were using the functions.

(in reply to: ↑ 12 ) 04/19/07 17:13:06 changed by paolo.negri

Replying to tmacedo:

I had an issue which stopped me from using it: It only allows you to :select existing columns, you can't use any functions on them.

Yes, you're right, the patch only allows to select on existing columns and you can not apply any database function to them. The reason is, in theory is possible to include more than once the same table and things get really tricky in this case if you want to correctly handle functions.

The patch doesn't even allow to use the * but this could be easily fixed.

04/19/07 17:15:52 changed by marko1

Allowing table.* would be most useful.

04/28/07 14:20:33 changed by paolo.negri

Hi I posted in #7147 a new version of the patch that allow the use of the * symbol. Now the code is a bit less clunky. All activerecord tests are successfull.

05/22/07 08:23:13 changed by paolo.negri

If someone is interested I released patch #7147 as a gem to make more easy to test the patch in real word applications.

the gem is select_with_include available from rubyforge

more details at

http://assertbuggy.blogspot.com/2007/05/activerecord-select-with-include.html

06/18/07 00:50:36 changed by wycats

  • status changed from new to closed.
  • resolution set to wontfix.

06/18/07 00:53:29 changed by wycats

I closed this because it's being tracked in #7147, and it doesn't look like this is getting fixed (it would require a full select parser). You can get the desired behavior (including full select parsing) by installing the rparsec gem and the parsing plugin from http://cfis.savagexi.com/files/select_parser.zip