aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/mysql_adapter.rb')
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb23
1 files changed, 22 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index ea0970028c..bd6cb2d3b8 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -491,8 +491,29 @@ module ActiveRecord
execute("RELEASE SAVEPOINT #{current_savepoint_name}")
end
+ # In the simple case, MySQL allows us to place JOINs directly into the UPDATE
+ # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
+ # these, we must use a subquery. However, MySQL is too stupid to create a
+ # temporary table for this automatically, so we have to give it some prompting
+ # in the form of a subsubquery. Ugh!
def join_to_update(update, select) #:nodoc:
- update.table select.ast.cores.last.source
+ if select.limit || select.offset || select.orders.any?
+ subsubselect = select.ast.clone
+ subsubselect.cores.last.projections = [update.ast.key]
+ subsubselect = Arel::Nodes::TableAlias.new(
+ Arel::Nodes::Grouping.new(subsubselect),
+ '__active_record_temp'
+ )
+
+ subselect = Arel::SelectManager.new(select.engine, subsubselect)
+ subselect.project(Arel::Table.new('__active_record_temp')[update.ast.key.name])
+
+ update.ast.limit = nil
+ update.ast.orders = []
+ update.wheres = [update.ast.key.in(subselect)]
+ else
+ update.table select.ast.cores.last.source
+ end
end
# SCHEMA STATEMENTS ========================================