Skip to content

Commit

Permalink
Merge pull request rails#51274 from fatkodima/fix-mysql-upsert-warning
Browse files Browse the repository at this point in the history
  • Loading branch information
byroot authored Mar 7, 2024
2 parents 2fa3294 + 0e7826e commit 7f349f8
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -639,18 +639,37 @@ def default_index_type?(index) # :nodoc:
end

def build_insert_sql(insert) # :nodoc:
sql = +"INSERT #{insert.into} #{insert.values_list}"

if insert.skip_duplicates?
no_op_column = quote_column_name(insert.keys.first)
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
elsif insert.update_duplicates?
sql << " ON DUPLICATE KEY UPDATE "
if insert.raw_update_sql?
sql << insert.raw_update_sql
else
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
no_op_column = quote_column_name(insert.keys.first)

# Avoid MySQL 8.0 deprecation warning, see https://dev.mysql.com/worklog/task/?id=13325.
if !mariadb? && database_version >= "8.0.0"
values_alias = quote_table_name("#{insert.model.table_name}_values")
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"

if insert.skip_duplicates?
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
elsif insert.update_duplicates?
sql << " ON DUPLICATE KEY UPDATE "
if insert.raw_update_sql?
sql << insert.raw_update_sql
else
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
end
end
else
sql = +"INSERT #{insert.into} #{insert.values_list}"

if insert.skip_duplicates?
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
elsif insert.update_duplicates?
sql << " ON DUPLICATE KEY UPDATE "
if insert.raw_update_sql?
sql << insert.raw_update_sql
else
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
end
end
end

Expand Down
17 changes: 17 additions & 0 deletions activerecord/test/cases/insert_all_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class InsertAllTest < ActiveRecord::TestCase

def setup
Arel::Table.engine = nil # should not rely on the global Arel::Table.engine
@original_db_warnings_action = :ignore
end

def teardown
Expand Down Expand Up @@ -336,6 +337,22 @@ def test_upsert_logs_message_including_model_name
end
end

def test_upsert_and_db_warnings
skip unless supports_insert_on_duplicate_update?

begin
with_db_warnings_action(:raise) do
assert_nothing_raised do
Book.upsert({ id: 1001, name: "Remote", author_id: 1 })
end
end
ensure
# We need to explicitly remove the record, because `with_db_warnings_action`
# prevents the wrapping transaction to be rolled back.
Book.delete(1001)
end
end

def test_upsert_all_logs_message_including_model_name
skip unless supports_insert_on_duplicate_update?

Expand Down

0 comments on commit 7f349f8

Please sign in to comment.