Skip to content

Commit

Permalink
Add protection against recycled objects being found instead of intend…
Browse files Browse the repository at this point in the history
…ed result array
  • Loading branch information
sdsykes committed Mar 17, 2009
1 parent de491b2 commit 53b5630
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 14 deletions.
2 changes: 1 addition & 1 deletion lib/optimizations/columns/macro.rb
Expand Up @@ -76,7 +76,7 @@ def find_by_sql_with_scrooge( sql )
callsite_set = scrooge_callsite(callsite_signature).columns
sql = sql.gsub(scrooge_select_regex, "SELECT #{scrooge_select_sql(callsite_set)} FROM")
results = connection.select_all(sanitize_sql(sql), "#{name} Load Scrooged")
result_set = []
result_set = ResultSets::ResultArray.new
updateable = ResultSets::UpdateableResultSet.new(result_set, self)
results.inject(result_set) do |memo, record|
memo << instantiate(ScroogedAttributes.setup(record, callsite_set, self, callsite_signature, updateable))
Expand Down
9 changes: 9 additions & 0 deletions lib/optimizations/result_sets/result_array.rb
@@ -0,0 +1,9 @@
module Scrooge
module Optimizations
module ResultSets
class ResultArray < Array
attr_accessor :unique_id
end
end
end
end
33 changes: 20 additions & 13 deletions lib/optimizations/result_sets/updateable_result_set.rb
Expand Up @@ -3,13 +3,16 @@ module Optimizations
module ResultSets
class UpdateableResultSet

# Contains weak referernce to result set, and can update from DB
# Contains a weak referernce to the result set, and can update from DB
#

attr_accessor :updaters_attributes

def initialize(result_set_array, klass)
@result_set_object_id = result_set_array.object_id if result_set_array.is_a?(Array)
if result_set_array
@result_set_object_id = result_set_array.object_id
@unique_id = result_set_array.unique_id ||= "#{Time.now.to_f}#{object_id}" # avoid recycled object ids
end
@klass = klass # expected class of items in the array
end

Expand All @@ -27,19 +30,22 @@ def reload_columns_for_ids(columns_to_fetch, result_ids_to_fetch)
end

def result_set_attributes
if @result_set_object_id
result_set = ObjectSpace._id2ref(@result_set_object_id)
result_set.inject(default_attributes) do |memo, r|
if r.is_a?(@klass)
memo |= [r.instance_variable_get(:@attributes)]
end
memo
rs = result_set
return default_attributes unless rs
rs.inject(default_attributes) do |memo, r|
if r.is_a?(@klass)
memo |= [r.instance_variable_get(:@attributes)]
end
else
default_attributes
memo
end
end

def result_set
return nil unless @result_set_object_id
result_set = ObjectSpace._id2ref(@result_set_object_id)
result_set.is_a?(ResultArray) && result_set.unique_id == @unique_id ? result_set : nil
rescue RangeError
default_attributes
nil
end

def default_attributes
Expand Down Expand Up @@ -68,7 +74,8 @@ def update_with(remaining_attributes)

def primary_key_name
@klass.primary_key
end
end

end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/scrooge.rb
Expand Up @@ -5,6 +5,7 @@
require 'optimizations/columns/attributes_proxy'
require 'optimizations/columns/macro'
require 'optimizations/result_sets/updateable_result_set'
require 'optimizations/result_sets/result_array'

module ActiveRecord
class Base
Expand Down

0 comments on commit 53b5630

Please sign in to comment.