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.
This commit is contained in:
Sam Bostock 2021-08-10 17:31:36 -04:00
parent 58cfa9259d
commit 213c4c5b50
No known key found for this signature in database
GPG Key ID: 96D854C4833F2660
3 changed files with 22 additions and 1 deletions

View File

@ -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. * 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. Applications can now be configured to ignore certain tables when dumping the schema cache.

View File

@ -198,7 +198,7 @@ module ActiveRecord
def touch_model_timestamps_unless(&block) def touch_model_timestamps_unless(&block)
model.timestamp_attributes_for_update_in_model.filter_map do |column_name| model.timestamp_attributes_for_update_in_model.filter_map do |column_name|
if touch_timestamp_attribute?(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
end.join end.join
end end

View File

@ -364,6 +364,15 @@ class InsertAllTest < ActiveRecord::TestCase
assert_equal Time.now.year, Book.find(101).updated_on.year assert_equal Time.now.year, Book.find(101).updated_on.year
end 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 def test_upsert_all_uses_given_updated_at_over_implicit_updated_at
skip unless supports_insert_on_duplicate_update? skip unless supports_insert_on_duplicate_update?