Translate numeric value out of range to the specific exception

Raise `ActiveRecord::RangeError` when values that executed are out of range.
This commit is contained in:
Ryuta Kamizono 2016-06-01 04:00:05 +09:00
parent cf6c2948d5
commit 49edce37f9
7 changed files with 26 additions and 8 deletions

@ -738,6 +738,7 @@ def add_options_for_index_columns(quoted_columns, **options)
ER_DO_NOT_HAVE_DEFAULT = 1364 ER_DO_NOT_HAVE_DEFAULT = 1364
ER_NO_REFERENCED_ROW_2 = 1452 ER_NO_REFERENCED_ROW_2 = 1452
ER_DATA_TOO_LONG = 1406 ER_DATA_TOO_LONG = 1406
ER_OUT_OF_RANGE = 1264
ER_LOCK_DEADLOCK = 1213 ER_LOCK_DEADLOCK = 1213
ER_CANNOT_ADD_FOREIGN = 1215 ER_CANNOT_ADD_FOREIGN = 1215
ER_CANNOT_CREATE_TABLE = 1005 ER_CANNOT_CREATE_TABLE = 1005
@ -758,6 +759,8 @@ def translate_exception(exception, message)
end end
when ER_DATA_TOO_LONG when ER_DATA_TOO_LONG
ValueTooLong.new(message) ValueTooLong.new(message)
when ER_OUT_OF_RANGE
RangeError.new(message)
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
NotNullViolation.new(message) NotNullViolation.new(message)
when ER_LOCK_DEADLOCK when ER_LOCK_DEADLOCK

@ -408,6 +408,7 @@ def postgresql_version
# See http://www.postgresql.org/docs/current/static/errcodes-appendix.html # See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
VALUE_LIMIT_VIOLATION = "22001" VALUE_LIMIT_VIOLATION = "22001"
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
NOT_NULL_VIOLATION = "23502" NOT_NULL_VIOLATION = "23502"
FOREIGN_KEY_VIOLATION = "23503" FOREIGN_KEY_VIOLATION = "23503"
UNIQUE_VIOLATION = "23505" UNIQUE_VIOLATION = "23505"
@ -424,6 +425,8 @@ def translate_exception(exception, message)
InvalidForeignKey.new(message) InvalidForeignKey.new(message)
when VALUE_LIMIT_VIOLATION when VALUE_LIMIT_VIOLATION
ValueTooLong.new(message) ValueTooLong.new(message)
when NUMERIC_VALUE_OUT_OF_RANGE
RangeError.new(message)
when NOT_NULL_VIOLATION when NOT_NULL_VIOLATION
NotNullViolation.new(message) NotNullViolation.new(message)
when SERIALIZATION_FAILURE when SERIALIZATION_FAILURE

@ -194,7 +194,7 @@ def find(*ids) # :nodoc:
name, primary_key, id) name, primary_key, id)
end end
record record
rescue RangeError rescue ::RangeError
raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'", raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
name, primary_key) name, primary_key)
end end
@ -223,7 +223,7 @@ def find_by(*args) # :nodoc:
statement.execute(hash.values, self, connection).first statement.execute(hash.values, self, connection).first
rescue TypeError rescue TypeError
raise ActiveRecord::StatementInvalid raise ActiveRecord::StatementInvalid
rescue RangeError rescue ::RangeError
nil nil
end end
end end

@ -159,6 +159,10 @@ class NotNullViolation < StatementInvalid
class ValueTooLong < StatementInvalid class ValueTooLong < StatementInvalid
end end
# Raised when values that executed are out of range.
class RangeError < StatementInvalid
end
# Raised when number of bind variables in statement given to +:condition+ key # Raised when number of bind variables in statement given to +:condition+ key
# (for example, when using {ActiveRecord::Base.find}[rdoc-ref:FinderMethods#find] method) # (for example, when using {ActiveRecord::Base.find}[rdoc-ref:FinderMethods#find] method)
# does not match number of expected values supplied. # does not match number of expected values supplied.

@ -76,7 +76,7 @@ def find(*args)
# Post.find_by "published_at < ?", 2.weeks.ago # Post.find_by "published_at < ?", 2.weeks.ago
def find_by(arg, *args) def find_by(arg, *args)
where(arg, *args).take where(arg, *args).take
rescue RangeError rescue ::RangeError
nil nil
end end
@ -84,7 +84,7 @@ def find_by(arg, *args)
# an ActiveRecord::RecordNotFound error. # an ActiveRecord::RecordNotFound error.
def find_by!(arg, *args) def find_by!(arg, *args)
where(arg, *args).take! where(arg, *args).take!
rescue RangeError rescue ::RangeError
raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value", raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
@klass.name) @klass.name)
end end
@ -333,7 +333,7 @@ def exists?(conditions = :none)
end end
connection.select_value(relation, "#{name} Exists", relation.bound_attributes) ? true : false connection.select_value(relation, "#{name} Exists", relation.bound_attributes) ? true : false
rescue RangeError rescue ::RangeError
false false
end end
@ -458,7 +458,7 @@ def find_with_ids(*ids)
else else
find_some(ids) find_some(ids)
end end
rescue RangeError rescue ::RangeError
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID" raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
end end

@ -226,6 +226,14 @@ def test_value_limit_violations_are_translated_to_specific_exception
assert_not_nil error.cause assert_not_nil error.cause
end end
def test_numeric_value_out_of_ranges_are_translated_to_specific_exception
error = assert_raises(ActiveRecord::RangeError) do
Book.connection.create("INSERT INTO books(author_id) VALUES (2147483648)")
end
assert_not_nil error.cause
end
end end
def test_disable_referential_integrity def test_disable_referential_integrity

@ -34,10 +34,10 @@ class UnsignedType < ActiveRecord::Base
assert_raise(ActiveModel::RangeError) do assert_raise(ActiveModel::RangeError) do
UnsignedType.create(unsigned_bigint: -10) UnsignedType.create(unsigned_bigint: -10)
end end
assert_raise(ActiveRecord::StatementInvalid) do assert_raise(ActiveRecord::RangeError) do
UnsignedType.create(unsigned_float: -10.0) UnsignedType.create(unsigned_float: -10.0)
end end
assert_raise(ActiveRecord::StatementInvalid) do assert_raise(ActiveRecord::RangeError) do
UnsignedType.create(unsigned_decimal: -10.0) UnsignedType.create(unsigned_decimal: -10.0)
end end
end end