提交 d681adbb 编写于 作者: R Ryuta Kamizono

Use table name qualified column name for update counters

MySQL supports JOINs to UPDATE, so if column name isn't qualified by
table name, it would cause an ambiguous error:

```
Mysql2::Error: Column 'integer' in field list is ambiguous: UPDATE `pets` INNER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` SET `integer` = COALESCE(`integer`, 0) + 1 WHERE `toys`.`name` = ?
```
上级 68d6c135
......@@ -349,7 +349,7 @@ def update_all(updates)
stmt = Arel::UpdateManager.new
stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates))
stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates, table.name))
stmt.table(table)
if has_join_values? || offset_value
......@@ -377,14 +377,14 @@ def update_counters(counters) # :nodoc:
updates = counters.map do |counter_name, value|
operator = value < 0 ? "-" : "+"
quoted_column = connection.quote_column_name(counter_name)
quoted_column = connection.quote_table_name_for_assignment(table.name, counter_name)
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
end
if touch
names = touch if touch != true
touch_updates = klass.touch_attributes_with_time(*names)
updates << klass.sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty?
updates << klass.sanitize_sql_for_assignment(touch_updates, table.name) unless touch_updates.empty?
end
update_all updates.join(", ")
......@@ -414,14 +414,12 @@ def update_counters(counters) # :nodoc:
# Person.where(name: 'David').touch_all
# # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
def touch_all(*names, time: nil)
updates = touch_attributes_with_time(*names, time: time)
if klass.locking_enabled?
quoted_locking_column = connection.quote_column_name(klass.locking_column)
updates = sanitize_sql_for_assignment(updates) + ", #{quoted_locking_column} = COALESCE(#{quoted_locking_column}, 0) + 1"
names << { time: time }
update_counters(klass.locking_column => 1, touch: names)
else
update_all klass.touch_attributes_with_time(*names, time: time)
end
update_all(updates)
end
# Destroys the records by instantiating each
......
......@@ -94,6 +94,14 @@ def test_update_all_with_joins_and_offset_and_order
assert_equal posts(:welcome), comments(:greetings).post
end
def test_update_counters_with_joins
assert_nil pets(:parrot).integer
Pet.joins(:toys).where(toys: { name: "Bone" }).update_counters(integer: 1)
assert_equal 1, pets(:parrot).reload.integer
end
def test_touch_all_updates_records_timestamps
david = developers(:david)
david_previously_updated_at = david.updated_at
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册