aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/arel/visitors/mysql.rb
diff options
context:
space:
mode:
authorRyuta Kamizono <kamipo@gmail.com>2018-10-03 05:29:27 +0900
committerRyuta Kamizono <kamipo@gmail.com>2018-10-03 06:24:41 +0900
commitbfea0af4ba7d717d6a065b4370e3ccfd8869dde6 (patch)
tree7c4a6911f73370146786659e88177a958f7bcb89 /activerecord/lib/arel/visitors/mysql.rb
parent92fece96da28d9f641bc8a8db1187b91c94cabfb (diff)
downloadrails-bfea0af4ba7d717d6a065b4370e3ccfd8869dde6.tar.gz
rails-bfea0af4ba7d717d6a065b4370e3ccfd8869dde6.tar.bz2
rails-bfea0af4ba7d717d6a065b4370e3ccfd8869dde6.zip
Move UPDATE/DELETE with JOIN handling to the Arel side
Diffstat (limited to 'activerecord/lib/arel/visitors/mysql.rb')
-rw-r--r--activerecord/lib/arel/visitors/mysql.rb48
1 files changed, 31 insertions, 17 deletions
diff --git a/activerecord/lib/arel/visitors/mysql.rb b/activerecord/lib/arel/visitors/mysql.rb
index eb8a449079..081452caeb 100644
--- a/activerecord/lib/arel/visitors/mysql.rb
+++ b/activerecord/lib/arel/visitors/mysql.rb
@@ -65,12 +65,42 @@ module Arel # :nodoc: all
collector
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.
+ def prepare_update_statement(o)
+ if has_join_sources?(o)
+ if has_limit_or_offset_or_orders?(o)
+ super
+ else
+ o
+ end
+ elsif o.offset
+ super
+ else
+ o
+ end
+ end
+
+ def prepare_delete_statement(o)
+ if has_join_sources?(o) || o.offset
+ super
+ else
+ o
+ end
+ end
+
+ # MySQL is too stupid to create a temporary table for use subquery, so we have
+ # to give it some prompting in the form of a subsubquery.
def build_subselect(key, o)
subselect = super
# Materialize subquery by adding distinct
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
- subselect.distinct unless subselect.limit || subselect.offset || subselect.orders.any?
+ unless has_limit_or_offset_or_orders?(subselect)
+ core = subselect.cores.last
+ core.set_quantifier = Arel::Nodes::Distinct.new
+ end
Nodes::SelectStatement.new.tap do |stmt|
core = stmt.cores.last
@@ -78,22 +108,6 @@ module Arel # :nodoc: all
core.projections = [Arel.sql(quote_column_name(key.name))]
end
end
-
- def collect_where_for(o, collector)
- return super if o.offset
-
- unless o.wheres.empty?
- collector << " WHERE "
- collector = inject_join o.wheres, collector, " AND "
- end
-
- unless o.orders.empty?
- collector << " ORDER BY "
- collector = inject_join o.orders, collector, ", "
- end
-
- maybe_visit o.limit, collector
- end
end
end
end