--- /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb 2009-04-21 01:27:52.000000000 -0500
+++ base.rb 2009-04-21 01:24:35.000000000 -0500
@@ -1492,11 +1492,12 @@
# Merges conditions so that the result is a valid +condition+
def merge_conditions(*conditions)
+ chain_aliases = conditions.extract_options! || Hash.new
segments = []
conditions.each do |condition|
unless condition.blank?
- sql = sanitize_sql(condition)
+ sql = sanitize_sql(condition, chain_aliases)
segments << sql unless sql.blank?
end
end
@@ -1688,8 +1689,9 @@
sql = "SELECT #{options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))} "
sql << "FROM #{options[:from] || (scope && scope[:from]) || quoted_table_name} "
- add_joins!(sql, options[:joins], scope)
- add_conditions!(sql, options[:conditions], scope)
+ chain_aliases = Hash.new
+ add_joins!(sql, options[:joins], scope, chain_aliases)
+ add_conditions!(sql, options[:conditions], scope, chain_aliases)
add_group!(sql, options[:group], options[:having], scope)
add_order!(sql, options[:order], scope)
@@ -1783,9 +1785,11 @@
end
# The optional scope argument is for the current :find scope.
- def add_joins!(sql, joins, scope = :auto)
+ def add_joins!(sql, joins, scope = :auto, chain_aliases = Hash.new)
scope = scope(:find) if :auto == scope
merged_joins = scope && scope[:joins] && joins ? merge_joins(scope[:joins], joins) : (joins || scope && scope[:joins])
+ chain_aliases.clear # blangenfeld
+ chain_aliases[nil] = self.table_name
case merged_joins
when Symbol, Hash, Array
if array_of_strings?(merged_joins)
@@ -1793,6 +1797,18 @@
else
join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, merged_joins, nil)
sql << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} "
+
+ # blangenfeld
+ join_dependency.join_associations.each_with_index do |join, index|
+ path = []
+ j = join
+ while j.respond_to?( :reflection )
+ path << j.reflection.name
+ j = j.parent
+ end
+ chain_aliases[path.reverse] = join.aliased_table_name
+ end
+
end
when String
sql << " #{merged_joins} "
@@ -1801,12 +1817,14 @@
# Adds a sanitized version of +conditions+ to the +sql+ string. Note that the passed-in +sql+ string is changed.
# The optional scope argument is for the current :find scope.
- def add_conditions!(sql, conditions, scope = :auto)
+ def add_conditions!(sql, conditions, scope = :auto, chain_aliases = nil)
scope = scope(:find) if :auto == scope
conditions = [conditions]
conditions << scope[:conditions] if scope
conditions << type_condition if finder_needs_type_condition?
+ conditions << chain_aliases # blangenfeld
merged_conditions = merge_conditions(*conditions)
+
sql << "WHERE #{merged_conditions} " unless merged_conditions.blank?
end
@@ -2117,9 +2135,9 @@
merge = hash[method][key] && params[key] # merge if both scopes have the same key
if key == :conditions && merge
if params[key].is_a?(Hash) && hash[method][key].is_a?(Hash)
- hash[method][key] = merge_conditions(hash[method][key].deep_merge(params[key]))
+ hash[method][key] = merge_conditions(hash[method][key].deep_merge(params[key]), nil)
else
- hash[method][key] = merge_conditions(params[key], hash[method][key])
+ hash[method][key] = merge_conditions(params[key], hash[method][key], nil)
end
elsif key == :include && merge
hash[method][key] = merge_includes(hash[method][key], params[key]).uniq
@@ -2228,12 +2246,12 @@
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
# { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'"
# "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"
- def sanitize_sql_for_conditions(condition)
+ def sanitize_sql_for_conditions(condition, chain_aliases = nil)
return nil if condition.blank?
case condition
- when Array; sanitize_sql_array(condition)
- when Hash; sanitize_sql_hash_for_conditions(condition)
+ when Array; sanitize_sql_array(condition, chain_aliases)
+ when Hash; sanitize_sql_hash_for_conditions(condition, quoted_table_name, chain_aliases)
else condition
end
end
@@ -2299,11 +2317,11 @@
# And for value objects on a composed_of relationship:
# { :address => Address.new("123 abc st.", "chicago") }
# # => "address_street='123 abc st.' and address_city='chicago'"
- def sanitize_sql_hash_for_conditions(attrs, table_name = quoted_table_name)
+ def sanitize_sql_hash_for_conditions(attrs, table_name = quoted_table_name, chain_aliases = nil, path = nil)
attrs = expand_hash_conditions_for_aggregates(attrs)
conditions = attrs.map do |attr, value|
- unless value.is_a?(Hash)
+ if !value.is_a?(Hash)
attr = attr.to_s
# Extract table name from qualified attribute names.
@@ -2313,8 +2331,15 @@
end
attribute_condition("#{table_name}.#{connection.quote_column_name(attr)}", value)
- else
+ elsif chain_aliases.nil?
sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s))
+ else
+ path_plus_one = [path, attr.to_sym].flatten.compact
+ if table_alias = chain_aliases[path_plus_one]
+ sanitize_sql_hash_for_conditions(value, connection.quote_table_name(table_alias), chain_aliases, path_plus_one)
+ else
+ sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s), chain_aliases, path)
+ end
end
end.join(' AND ')
@@ -2334,9 +2359,15 @@
# Accepts an array of conditions. The array has each value
# sanitized and interpolated into the SQL statement.
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
- def sanitize_sql_array(ary)
+ def sanitize_sql_array(ary, chain_aliases = nil)
statement, *values = ary
- if values.first.is_a?(Hash) and statement =~ /:\w+/
+ if statement.is_a?(Hash)
+ conditions = []
+ ary.each do |condition|
+ conditions << "(#{sanitize_sql_hash_for_conditions(condition, quoted_table_name, chain_aliases)})"
+ end
+ conditions.join(' OR ')
+ elsif values.first.is_a?(Hash) and statement =~ /:\w+/
replace_named_bind_variables(statement, values.first)
elsif statement.include?('?')
replace_bind_variables(statement, values)