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
All of queries should return correct result even if including large number #30000
All of queries should return correct result even if including large number #30000
Conversation
73bdbcb
to
09bc8b5
Compare
Ugh... I'm sure I was worried about these sorts of cases when we added that rescue I don't think replacing binds with inline values is the solution, though. It provides a trivial means of blowing out the prepared statement cache, and even in the best case gives a surprise inefficient query.. what was an index lookup is now a full table scan. If we can't pick out just the known cases, like |
I changed the implementation to build |
bfb5d4e
to
04b1c71
Compare
04b1c71
to
aa54da6
Compare
I'm thing this new implementation is good. @matthewd do you still have concerns? |
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.
build_query_attribute
appears to be doing something really implicit. I'd like to see it be made much more explicit, but this seems fine to me overall. The additional test cases make sense.
I would like to see the intent of build_query_attribute
made more clear before this is merged though
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.
This still opens the possibility of 2**N query cache entries for a single query with N integer parameters, but that's far more bounded than infinity. And it avoids wasting database effort on the known-false condition, so that's good.
I agree the current rescues are catching too much, so something must change. If this can fix it while avoiding even more exceptions, so much the better.
activerecord/lib/active_record/relation/predicate_builder/basic_object_handler.rb
Outdated
Show resolved
Hide resolved
activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
Outdated
Show resolved
Hide resolved
aa54da6
to
176c6b8
Compare
activerecord/lib/active_record/relation/predicate_builder/range_handler.rb
Outdated
Show resolved
Hide resolved
What |
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.
Sounds good to me, but let's wait @matthewd's approval
activerecord/lib/active_record/relation/predicate_builder/range_handler.rb
Outdated
Show resolved
Hide resolved
activerecord/lib/active_record/relation/predicate_builder/range_handler.rb
Outdated
Show resolved
Hide resolved
activerecord/lib/active_record/relation/predicate_builder/range_handler.rb
Outdated
Show resolved
Hide resolved
cedd0b2
to
cc507e3
Compare
@@ -106,6 +106,8 @@ def execute(params, connection, &block) | |||
sql = query_builder.sql_for bind_values, connection | |||
|
|||
klass.find_by_sql(sql, bind_values, preparable: true, &block) | |||
rescue ::RangeError | |||
[] |
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.
This rescue makes me nervous, just because it sounds far-reaching.
I agree it's fine to put it here in practice, because of the very limited set of statements that are eligible for this cache, as you noted in the commit message. I think that's worth a comment here too, though: both to hopefully draw attention if the cache ever gets used for other queries, and just to reassure future readers me next time I read through this code
59d7e9f
to
611e8b7
Compare
activerecord/lib/active_record/relation/predicate_builder/range_handler.rb
Outdated
Show resolved
Hide resolved
611e8b7
to
368d4aa
Compare
368d4aa
to
0bb5bc7
Compare
0bb5bc7
to
694909f
Compare
694909f
to
317ce94
Compare
317ce94
to
0b8bf09
Compare
0b8bf09
to
2d32895
Compare
…umber Currently several queries cannot return correct result due to incorrect `RangeError` handling. First example: ```ruby assert_equal true, Topic.where(id: [1, 9223372036854775808]).exists? assert_equal true, Topic.where.not(id: 9223372036854775808).exists? ``` The first example is obviously to be true, but currently it returns false. Second example: ```ruby assert_equal topics(:first), Topic.where(id: 1..9223372036854775808).find(1) ``` The second example also should return the object, but currently it raises `RecordNotFound`. It can be seen from the examples, the queries including large number assuming empty result is not always correct. Therefore, This change handles `RangeError` to generate executable SQL instead of raising `RangeError` to users to always return correct result. By this change, it is no longer raised `RangeError` to users.
Since 31ffbf8, finder methods no longer raise `RangeError`. So `StatementCache#execute` is the only place to raise the exception for finder queries. `StatementCache` is used for simple equality queries in the codebase. This means that if `StatementCache#execute` raises `RangeError`, the result could always be regarded as empty. So `StatementCache#execute` just return nil in that range error case, and treat that as empty in the caller side, then we can avoid catching the exception in much places.
2d32895
to
c196ca7
Compare
I'd be going to merge this PR since I think I've addressed all suggestions, and this PR already got two approvals and the intent of the code is clear enough. Let me know if anyone has any suggestions, I think I could address that before the final 6.0 release. |
|
All of queries should return correct result even if including large number rails/rails#30000
…en with a large number Follow up to #30000.
…en with a large number Follow up to rails#30000.
…en with a large number Follow up to rails#30000.
Currently several queries cannot return correct result due to incorrect
RangeError
handling.First example:
The first example is obviously to be true, but currently it returns
false.
Second example:
The second example also should return the object, but currently it
raises
RecordNotFound
.It can be seen from the examples, the queries including large number
assuming empty result is not always correct.
Therefore, This change handles
RangeError
to generate executable SQLinstead of raising
RangeError
to users to always return correctresult. By this change, it is no longer raised
RangeError
to users.