From 31ffbf8d5056137717da3f11d28c4fbd7fbc8f07 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Mon, 24 Jul 2017 09:50:11 +0900 Subject: All of queries should return correct result even if including large number 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. --- activerecord/lib/arel/predications.rb | 24 ++++++++++++++++++------ activerecord/lib/arel/visitors/to_sql.rb | 4 ++++ 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'activerecord/lib/arel') diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb index 2a62c53aa3..7dafde4952 100644 --- a/activerecord/lib/arel/predications.rb +++ b/activerecord/lib/arel/predications.rb @@ -35,15 +35,17 @@ module Arel # :nodoc: all end def between(other) - if infinity?(other.begin) - if other.end.nil? || infinity?(other.end) + if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1 + self.in([]) + elsif open_ended?(other.begin) + if other.end.nil? || open_ended?(other.end) not_in([]) elsif other.exclude_end? lt(other.end) else lteq(other.end) end - elsif other.end.nil? || infinity?(other.end) + elsif other.end.nil? || open_ended?(other.end) gteq(other.begin) elsif other.exclude_end? gteq(other.begin).and(lt(other.end)) @@ -81,15 +83,17 @@ Passing a range to `#in` is deprecated. Call `#between`, instead. end def not_between(other) - if infinity?(other.begin) - if other.end.nil? || infinity?(other.end) + if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1 + not_in([]) + elsif open_ended?(other.begin) + if other.end.nil? || open_ended?(other.end) self.in([]) elsif other.exclude_end? gteq(other.end) else gt(other.end) end - elsif other.end.nil? || infinity?(other.end) + elsif other.end.nil? || open_ended?(other.end) lt(other.begin) else left = lt(other.begin) @@ -241,5 +245,13 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead. def infinity?(value) value.respond_to?(:infinite?) && value.infinite? end + + def unboundable?(value) + value.respond_to?(:unboundable?) && value.unboundable? + end + + def open_ended?(value) + infinity?(value) || unboundable?(value) + end end end diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index c08403eea9..d0dec63860 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -629,6 +629,8 @@ module Arel # :nodoc: all def visit_Arel_Nodes_Equality(o, collector) right = o.right + return collector << "1=0" if unboundable?(right) + collector = visit o.left, collector if right.nil? @@ -662,6 +664,8 @@ module Arel # :nodoc: all def visit_Arel_Nodes_NotEqual(o, collector) right = o.right + return collector << "1=1" if unboundable?(right) + collector = visit o.left, collector if right.nil? -- cgit v1.2.3