Skip to content

Commit 0e7826e

Browse files
committed
Fix upsert warning for MySQL
1 parent 2fa3294 commit 0e7826e

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -639,18 +639,37 @@ def default_index_type?(index) # :nodoc:
639639
end
640640

641641
def build_insert_sql(insert) # :nodoc:
642-
sql = +"INSERT #{insert.into} #{insert.values_list}"
643-
644-
if insert.skip_duplicates?
645-
no_op_column = quote_column_name(insert.keys.first)
646-
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
647-
elsif insert.update_duplicates?
648-
sql << " ON DUPLICATE KEY UPDATE "
649-
if insert.raw_update_sql?
650-
sql << insert.raw_update_sql
651-
else
652-
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
653-
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
642+
no_op_column = quote_column_name(insert.keys.first)
643+
644+
# Avoid MySQL 8.0 deprecation warning, see https://dev.mysql.com/worklog/task/?id=13325.
645+
if !mariadb? && database_version >= "8.0.0"
646+
values_alias = quote_table_name("#{insert.model.table_name}_values")
647+
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
648+
649+
if insert.skip_duplicates?
650+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
651+
elsif insert.update_duplicates?
652+
sql << " ON DUPLICATE KEY UPDATE "
653+
if insert.raw_update_sql?
654+
sql << insert.raw_update_sql
655+
else
656+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
657+
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
658+
end
659+
end
660+
else
661+
sql = +"INSERT #{insert.into} #{insert.values_list}"
662+
663+
if insert.skip_duplicates?
664+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
665+
elsif insert.update_duplicates?
666+
sql << " ON DUPLICATE KEY UPDATE "
667+
if insert.raw_update_sql?
668+
sql << insert.raw_update_sql
669+
else
670+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
671+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
672+
end
654673
end
655674
end
656675

activerecord/test/cases/insert_all_test.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class InsertAllTest < ActiveRecord::TestCase
2020

2121
def setup
2222
Arel::Table.engine = nil # should not rely on the global Arel::Table.engine
23+
@original_db_warnings_action = :ignore
2324
end
2425

2526
def teardown
@@ -336,6 +337,22 @@ def test_upsert_logs_message_including_model_name
336337
end
337338
end
338339

340+
def test_upsert_and_db_warnings
341+
skip unless supports_insert_on_duplicate_update?
342+
343+
begin
344+
with_db_warnings_action(:raise) do
345+
assert_nothing_raised do
346+
Book.upsert({ id: 1001, name: "Remote", author_id: 1 })
347+
end
348+
end
349+
ensure
350+
# We need to explicitly remove the record, because `with_db_warnings_action`
351+
# prevents the wrapping transaction to be rolled back.
352+
Book.delete(1001)
353+
end
354+
end
355+
339356
def test_upsert_all_logs_message_including_model_name
340357
skip unless supports_insert_on_duplicate_update?
341358

0 commit comments

Comments
 (0)