diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index fb942a152b..417b252125 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,15 @@ +* Use full precision for `updated_at` in `insert_all`/`upsert_all` + + `CURRENT_TIMESTAMP` provides differing precision depending on the database, + and not all databases support explicitly specifying additional precision. + + Instead, we delegate to the new `connection.high_precision_current_timestamp` + for the SQL to produce a high precision timestamp on the current database. + + Fixes #42992 + + *Sam Bostock* + * Add config option for ignoring tables when dumping the schema cache. Applications can now be configured to ignore certain tables when dumping the schema cache. diff --git a/activerecord/lib/active_record/insert_all.rb b/activerecord/lib/active_record/insert_all.rb index fefd8bd0a5..0e3de9c453 100644 --- a/activerecord/lib/active_record/insert_all.rb +++ b/activerecord/lib/active_record/insert_all.rb @@ -198,7 +198,7 @@ module ActiveRecord def touch_model_timestamps_unless(&block) model.timestamp_attributes_for_update_in_model.filter_map do |column_name| if touch_timestamp_attribute?(column_name) - "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE CURRENT_TIMESTAMP END)," + "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE #{connection.high_precision_current_timestamp} END)," end end.join end diff --git a/activerecord/test/cases/insert_all_test.rb b/activerecord/test/cases/insert_all_test.rb index 9b4660efd6..56cca2e1a5 100644 --- a/activerecord/test/cases/insert_all_test.rb +++ b/activerecord/test/cases/insert_all_test.rb @@ -364,6 +364,15 @@ class InsertAllTest < ActiveRecord::TestCase assert_equal Time.now.year, Book.find(101).updated_on.year end + def test_upsert_all_respects_updated_at_precision_when_touched_implicitly + skip unless supports_insert_on_duplicate_update? && supports_datetime_with_precision? + + Book.insert_all [{ id: 101, name: "Out of the Silent Planet", published_on: Date.new(1938, 4, 1), updated_at: 5.years.ago, updated_on: 5.years.ago }] + Book.upsert_all [{ id: 101, name: "Out of the Silent Planet", published_on: Date.new(1938, 4, 8) }] + + assert_not_predicate Book.find(101).updated_at.usec, :zero?, "updated_at should have sub-second precision" + end + def test_upsert_all_uses_given_updated_at_over_implicit_updated_at skip unless supports_insert_on_duplicate_update?