-
Notifications
You must be signed in to change notification settings - Fork 21.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AR: take precision into count when assigning a value to timestamp attribute #20317
Conversation
Tests are broken because datetime precision is not supported at the version of mysql that we have in our servers. This make me wonder, would this patch work on old MySQL versions? |
@rafaelfranca yes it will: at the rails level, unsupported precision works like The fact that older mysql don't support precision raises the following problem: def test_cache_key_changes_when_child_touched
owner = owners(:blackbeard)
pet = pets(:parrot)
owner.update_column :updated_at, Time.current
key = owner.cache_key
assert pet.touch
assert_not_equal key, owner.reload.cache_key
end It will only work stable if there will be at least 1 second between the creation of I've put I'll think more how we can solve it. If you have an idea, please share with me. |
cc @sgrif |
c3024de
to
5a449f0
Compare
Hope I've fixed the build on mysql5.6: I made it differently with Can someone advice how to go from PR to corresponding CI build? Find it here: https://travis-ci.org/rails/rails/pull_requests manually seems impossible. |
@sgrif @rafaelfranca I understand the work load of rails core team, but this is regression problem from 4.0 to 4.1 and we kind of expect a feedback sooner than later. Can you please merge this in and backport to 4.1 or point out why it can not be done? |
Forcing a Travis build. |
I'm traveling and don't have my computer right now but I'll take care of this next chance I get. |
@sgrif if you have back to work, it would be cool to receive another review here |
Are you Github stalking me? Taking a look now. |
in_instance = d.created_at | ||
from_db = Parrot.find(d.id).created_at | ||
assert_equal from_db.usec, in_instance.usec | ||
assert_equal from_db, in_instance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this test hard to follow, and I don't think this is relevant to the behavior of AR::Timestamp. Can we move this to a separate test in something like test/cases/type/date_time_test.rb
, and have it look something like this?
model = Model.new(date_time_attr_that_isnt_auto_touched: Time.now)
assert_equal model.date_time_attr, model.tap(&:save).reload.date_time_attr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any test like that inside am/test/cases/type/
that uses Model
. They all just instantiate the AM::Type::*
object and call #cast
method there.
Also, testing this feature in AM will not cover this change:
https://github.com/rails/rails/pull/20317/files#diff-2695559f74d901580d9c9314a9f4aff7R14
that caused postgresql specific bug.
I would stick with test we have know. I will only change it with use of #reload
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it uses a model, create a test in the active record namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are already several tests of this nature in activerecord/test/cases/type
A few nitpicks. This will need to be rebased. The relevant classes have been moved to Active Model. |
… attribute Timestamp column can have less precision than ruby timestamp In result in how big a fraction of a second can be stored in the database. m = Model.create! m.created_at.usec == m.reload.created_at.usec # => false # due to different seconds precision in Time.now and database column If the precision is low enough, (mysql default is 0, so it is always low enough by default) the value changes when model is reloaded from the database. This patch fixes that issue ensuring that any timestamp assigned as an attribute is converted to column precision under the attribute.
5a449f0
to
d03f519
Compare
You are right about that test. I didn't get what you meant from the first try. So:
|
AR: take precision into count when assigning a value to timestamp attribute
Specifically, versions of MySQL prior to 5.6 do not support this, which is what's used on Travis by default. The method `mysql_56?` appeared to only ever be used to conditionally apply subsecond precision, so I've generalized it and used it more liberally. This should fix the test failures caused by #20317
When I originally reviewed the #20317, I believe these changes were present, but it appears that it was later updated so that they were removed. Since Travis hadn't re-run the build, this slipped through.
The patch does not apply at all cleanly, so this is a manual backport of the most relevant bits
Specifically, versions of MySQL prior to 5.6 do not support this, which is what's used on Travis by default. The method `mysql_56?` appeared to only ever be used to conditionally apply subsecond precision, so I've generalized it and used it more liberally. This should fix the test failures caused by rails#20317
The Problem
Consider this following on MySQL (that have 0 precision on datetime by default):
Rails 4.1.10 and master are affected. Not sure about others.
Timestamp column can have less precision than ruby timestamp
In result in how big a fraction of a second can be stored in the
database.
If the precision is low enough, (mysql default is 0 so it is always low
enough by default) the value changes when model is reloaded from the
database.
The Patch
In order to fix that we just use a precision of a column when assigning a value to the timestamp attribute as time object (not as string - that seems working).
Fixing tests
When I've applied a patch, the new problem raised: existing tests are written incorrectly for mysql that have 0 precision by default.
There are many tests that check that
updated_at
changes on particular model. But it is only true for ruby level but not in the database. This patch reveals the problem.In order to make them pass I've set the precision for tables that are used to check if
updated_at
is changing big enough and consistent for all databases.Further problems
datetime
column type works differently in different databases now because if different default precision. It results in different behaviour of the same AR schema on different databases.It should be consistent. It can be done by setting up a
precision
option ofadd_column
to some value all the time and disallowing it to be nil.