Skip to content

Commit efbac92

Browse files
committed
Allow ActiveRecord's #insert to work with an empty hash of attributes when using MySQL
Here's what happens: when calling `Book.insert({})`, the following exception is raised: ``` /Users/sto/.gem/ruby/ruby-3.3.5/gems/irb-1.14.1/lib/irb.rb:1260:in `full_message': Trilogy::ProtocolError: 1054: Unknown column '' in 'field list' (ActiveRecord::StatementInvalid) ``` This is due to Rails generating the following SQL query: ```sql INSERT INTO `posts` (`created_at`,`updated_at`) VALUES (CURRENT_TIMESTAMP(6), CURRENT_TIMESTAMP(6)) AS `posts_values` ON DUPLICATE KEY UPDATE ``=`posts_values`.`` /*application='MysqlDefaultTime'*/ ``` This simple commit should allow it to work, though I must admit that I haven't tested all scenarios locally, hoping that the test suite might catch any problem in CI. Nonetheless, I think it's reasonable to skip appending `ON DUPLICATE KEY UPDATE` using `no_op_column` when `no_op_column` is made of a non-existent column name.
1 parent fac6689 commit efbac92

File tree

3 files changed

+19
-3
lines changed

3 files changed

+19
-3
lines changed

activerecord/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* Fix incorrect SQL query when passing an empty hash to `ActiveRecord::Base.insert`.
2+
3+
*David Stosik*
4+
15
* Allow to save records with polymorphic join tables that have inverse of specified.
26

37
*Markus Doits*

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ def default_index_type?(index) # :nodoc:
628628
end
629629

630630
def build_insert_sql(insert) # :nodoc:
631-
no_op_column = quote_column_name(insert.keys.first)
631+
no_op_column = quote_column_name(insert.keys.first) if insert.keys.first
632632

633633
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
634634
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
@@ -637,7 +637,9 @@ def build_insert_sql(insert) # :nodoc:
637637
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
638638

639639
if insert.skip_duplicates?
640-
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
640+
if no_op_column
641+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
642+
end
641643
elsif insert.update_duplicates?
642644
if insert.raw_update_sql?
643645
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
@@ -651,7 +653,9 @@ def build_insert_sql(insert) # :nodoc:
651653
sql = +"INSERT #{insert.into} #{insert.values_list}"
652654

653655
if insert.skip_duplicates?
654-
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
656+
if no_op_column
657+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
658+
end
655659
elsif insert.update_duplicates?
656660
sql << " ON DUPLICATE KEY UPDATE "
657661
if insert.raw_update_sql?

activerecord/test/cases/insert_all_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ def test_insert_all_generates_correct_sql
149149
Book.insert_all [{ id: 1, name: "Agile Web Development with Rails" }]
150150
end
151151
end
152+
153+
def test_insert_all_succeeds_when_passed_no_attributes
154+
skip unless supports_insert_on_duplicate_skip?
155+
156+
assert_nothing_raised do
157+
Book.insert_all [{}]
158+
end
159+
end
152160
end
153161

154162
def test_insert_all_with_skip_duplicates_and_autonumber_id_not_given

0 commit comments

Comments
 (0)