mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Handle UPDATE/DELETE with OFFSET in Arel
This commit is contained in:
parent
322c5704e5
commit
6d40d2d3d1
6 changed files with 35 additions and 19 deletions
|
@ -356,11 +356,12 @@ module ActiveRecord
|
|||
stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
|
||||
end
|
||||
|
||||
if has_join_values? || offset_value
|
||||
if has_join_values?
|
||||
@klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
|
||||
else
|
||||
stmt.key = arel_attribute(primary_key)
|
||||
stmt.take(arel.limit)
|
||||
stmt.offset(arel.offset)
|
||||
stmt.order(*arel.orders)
|
||||
stmt.wheres = arel.constraints
|
||||
end
|
||||
|
@ -484,11 +485,12 @@ module ActiveRecord
|
|||
stmt = Arel::DeleteManager.new
|
||||
stmt.from(table)
|
||||
|
||||
if has_join_values? || offset_value
|
||||
if has_join_values?
|
||||
@klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
|
||||
else
|
||||
stmt.key = arel_attribute(primary_key)
|
||||
stmt.take(arel.limit)
|
||||
stmt.offset(arel.offset)
|
||||
stmt.order(*arel.orders)
|
||||
stmt.wheres = arel.constraints
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
module Arel # :nodoc: all
|
||||
module Nodes
|
||||
class DeleteStatement < Arel::Nodes::Node
|
||||
attr_accessor :left, :right, :orders, :limit, :key
|
||||
attr_accessor :left, :right, :orders, :limit, :offset, :key
|
||||
|
||||
alias :relation :left
|
||||
alias :relation= :left=
|
||||
|
@ -16,6 +16,7 @@ module Arel # :nodoc: all
|
|||
@right = wheres
|
||||
@orders = []
|
||||
@limit = nil
|
||||
@offset = nil
|
||||
@key = nil
|
||||
end
|
||||
|
||||
|
@ -26,7 +27,7 @@ module Arel # :nodoc: all
|
|||
end
|
||||
|
||||
def hash
|
||||
[self.class, @left, @right, @orders, @limit, @key].hash
|
||||
[self.class, @left, @right, @orders, @limit, @offset, @key].hash
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
|
@ -35,6 +36,7 @@ module Arel # :nodoc: all
|
|||
self.right == other.right &&
|
||||
self.orders == other.orders &&
|
||||
self.limit == other.limit &&
|
||||
self.offset == other.offset &&
|
||||
self.key == other.key
|
||||
end
|
||||
alias :== :eql?
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
module Arel # :nodoc: all
|
||||
module Nodes
|
||||
class UpdateStatement < Arel::Nodes::Node
|
||||
attr_accessor :relation, :wheres, :values, :orders, :limit, :key
|
||||
attr_accessor :relation, :wheres, :values, :orders, :limit, :offset, :key
|
||||
|
||||
def initialize
|
||||
@relation = nil
|
||||
|
@ -11,6 +11,7 @@ module Arel # :nodoc: all
|
|||
@values = []
|
||||
@orders = []
|
||||
@limit = nil
|
||||
@offset = nil
|
||||
@key = nil
|
||||
end
|
||||
|
||||
|
@ -21,7 +22,7 @@ module Arel # :nodoc: all
|
|||
end
|
||||
|
||||
def hash
|
||||
[@relation, @wheres, @values, @orders, @limit, @key].hash
|
||||
[@relation, @wheres, @values, @orders, @limit, @offset, @key].hash
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
|
@ -31,6 +32,7 @@ module Arel # :nodoc: all
|
|||
self.values == other.values &&
|
||||
self.orders == other.orders &&
|
||||
self.limit == other.limit &&
|
||||
self.offset == other.offset &&
|
||||
self.key == other.key
|
||||
end
|
||||
alias :== :eql?
|
||||
|
|
|
@ -10,6 +10,11 @@ module Arel # :nodoc: all
|
|||
self
|
||||
end
|
||||
|
||||
def offset(offset)
|
||||
@ast.offset = Nodes::Offset.new(Nodes.build_quoted(offset)) if offset
|
||||
self
|
||||
end
|
||||
|
||||
def order(*expr)
|
||||
@ast.orders = expr
|
||||
self
|
||||
|
|
|
@ -56,18 +56,6 @@ module Arel # :nodoc: all
|
|||
super
|
||||
end
|
||||
|
||||
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
||||
collector << "UPDATE "
|
||||
collector = visit o.relation, collector
|
||||
|
||||
unless o.values.empty?
|
||||
collector << " SET "
|
||||
collector = inject_join o.values, collector, ", "
|
||||
end
|
||||
|
||||
collect_where_for(o, collector)
|
||||
end
|
||||
|
||||
def visit_Arel_Nodes_Concat(o, collector)
|
||||
collector << " CONCAT("
|
||||
visit o.left, collector
|
||||
|
@ -77,7 +65,23 @@ module Arel # :nodoc: all
|
|||
collector
|
||||
end
|
||||
|
||||
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?
|
||||
|
||||
Nodes::SelectStatement.new.tap do |stmt|
|
||||
core = stmt.cores.last
|
||||
core.froms = Nodes::Grouping.new(subselect).as("__active_record_temp")
|
||||
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 "
|
||||
|
|
|
@ -88,6 +88,7 @@ module Arel # :nodoc: all
|
|||
core.wheres = o.wheres
|
||||
core.projections = [key]
|
||||
stmt.limit = o.limit
|
||||
stmt.offset = o.offset
|
||||
stmt.orders = o.orders
|
||||
stmt
|
||||
end
|
||||
|
@ -800,7 +801,7 @@ module Arel # :nodoc: all
|
|||
end
|
||||
|
||||
def collect_where_for(o, collector)
|
||||
if o.orders.empty? && o.limit.nil?
|
||||
if o.orders.empty? && o.limit.nil? && o.offset.nil?
|
||||
wheres = o.wheres
|
||||
else
|
||||
wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
|
||||
|
|
Loading…
Reference in a new issue