Created
May 13, 2011 03:31
-
-
Save AquaGeek/969916 to your computer and use it in GitHub Desktop.
Rails Lighthouse ticket #1533
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 328011d9841b0d4999878b582e50a6e9489a5ae5 Mon Sep 17 00:00:00 2001 | |
From: Nathan Zook <[email protected]> | |
Date: Thu, 4 Mar 2010 17:14:19 -0600 | |
Subject: [PATCH] Broke out joining the quoted values in ActiveRecord::Base (to support the Oracle adapter) | |
--- | |
activerecord/lib/active_record/base.rb | 6 +++++- | |
1 files changed, 5 insertions(+), 1 deletions(-) | |
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb | |
index cd67490..68dec91 100755 | |
--- a/activerecord/lib/active_record/base.rb | |
+++ b/activerecord/lib/active_record/base.rb | |
@@ -1639,13 +1639,17 @@ module ActiveRecord #:nodoc: | |
if value.respond_to?(:empty?) && value.empty? | |
connection.quote(nil) | |
else | |
- value.map { |v| connection.quote(v) }.join(',') | |
+ join_quoted_values_for_condition(value.map{|v| connection.quote(v)}) | |
end | |
else | |
connection.quote(value) | |
end | |
end | |
+ def join_quoted_values_for_condition(values) #:nodoc: | |
+ values * ',' | |
+ end | |
+ | |
def raise_if_bind_arity_mismatch(statement, expected, provided) #:nodoc: | |
unless expected == provided | |
raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}" | |
-- | |
1.6.0.4 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 3e79b5f92602051b47f9d20cedf51dd96ff93b82 | |
Author: Giorgio Gonnella <[email protected]> | |
Date: Mon Mar 2 17:44:41 2009 +0100 | |
Solves preloading more than 1000 associated records in Oracle | |
Rails often uses "in" sql clauses when preloading associations. Oracle has | |
a 1000 term restriction on such clauses, so that you cannot say something | |
like "WHERE parent_id IN (1,2,3,4 ... 1001)". | |
[#1533 state:resolved] | |
diff --git a/vendor/rails/activerecord/lib/active_record/association_preload.rb b/vendor/rails/activerecord/lib/active_record/association_preload.rb | |
index 69300e5..4ecad6f 100644 | |
--- a/vendor/rails/activerecord/lib/active_record/association_preload.rb | |
+++ b/vendor/rails/activerecord/lib/active_record/association_preload.rb | |
@@ -322,8 +322,9 @@ module ActiveRecord | |
end | |
end | |
conditions = "#{table_name}.#{connection.quote_column_name(primary_key)} #{in_or_equals_for_ids(ids)}" | |
+ conditions = ([conditions] * (ids.size.to_f/1000).ceil).join(" OR ") | |
conditions << append_conditions(reflection, preload_options) | |
- associated_records = klass.find(:all, :conditions => [conditions, ids], | |
+ associated_records = klass.find(:all, :conditions => [conditions, *ids.in_groups_of(1000, false)], | |
:include => options[:include], | |
:select => options[:select], | |
:joins => options[:joins], | |
@@ -335,20 +336,21 @@ module ActiveRecord | |
def find_associated_records(ids, reflection, preload_options) | |
options = reflection.options | |
table_name = reflection.klass.quoted_table_name | |
- | |
+ | |
if interface = reflection.options[:as] | |
conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'" | |
else | |
foreign_key = reflection.primary_key_name | |
conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} #{in_or_equals_for_ids(ids)}" | |
end | |
- | |
+ | |
+ conditions = ([conditions] * (ids.size.to_f/1000).ceil).join(" OR ") | |
conditions << append_conditions(reflection, preload_options) | |
- | |
+ | |
reflection.klass.find(:all, | |
:select => (preload_options[:select] || options[:select] || "#{table_name}.*"), | |
:include => preload_options[:include] || options[:include], | |
- :conditions => [conditions, ids], | |
+ :conditions => [conditions, *ids.in_groups_of(1000, false)], | |
:joins => options[:joins], | |
:group => preload_options[:group] || options[:group], | |
:order => preload_options[:order] || options[:order]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Ugly monkey patch so Rails can load associations with more than 1000 items in | |
# Oracle. See: https://rails.lighthouseapp.com/projects/8994/tickets/1533 | |
module ActiveRecord | |
module AssociationPreloadOracleWorkaround | |
# Oracle's IN() clause limit. | |
ORACLE_LIMIT = 1000 | |
# Oracle's limit on number of arguments to a function. | |
ORACLE_CHUNK = 255 | |
def self.included(base) | |
base.extend(ClassMethods) | |
base.class_eval do | |
class << self | |
alias_method_chain(:in_or_equals_for_ids, :oracle_workaround) | |
end | |
end | |
end | |
module ClassMethods | |
# Override in_or_equals_for_ids to split IN clauses that have more than | |
# 1000 items in them. | |
def in_or_equals_for_ids_with_oracle_workaround(ids) | |
sql = "" | |
if(ids.size > ORACLE_LIMIT) | |
# If there are more than 1000, actually separate them into groups of | |
# 255, since that seems to be the limit of Oracle's odcinumberlist(). | |
in_clauses = [] | |
0.step(ids.size, ORACLE_CHUNK) do |i| | |
ids_chunk = ids[i, ORACLE_CHUNK] | |
in_clauses << sanitize_sql_array(["(SELECT * FROM TABLE(sys.odcinumberlist(?)))", ids_chunk]) | |
end | |
sql = "IN(#{in_clauses.join(" UNION ")})" | |
else | |
sql = in_or_equals_for_ids_without_oracle_workaround(ids) | |
end | |
sql | |
end | |
end | |
end | |
end | |
ActiveRecord::Base.send :include, ActiveRecord::AssociationPreloadOracleWorkaround |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment