Fix undesirable RangeError by Type::Integer. Add Type::UnsignedInteger.
This commit is contained in:
parent
6961afefd2
commit
b61a93b44e
@ -1,3 +1,7 @@
|
||||
* Fix undesirable RangeError by Type::Integer. Add Type::UnsignedInteger.
|
||||
|
||||
*Ryuta Kamizono*
|
||||
|
||||
* Add `foreign_type` option to `has_one` and `has_many` association macros.
|
||||
|
||||
This option enables to define the column name of associated object's type for polymorphic associations.
|
||||
|
@ -656,14 +656,15 @@ def initialize_type_map(m) # :nodoc:
|
||||
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
||||
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
||||
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
||||
m.register_type %r(^bigint)i, Type::Integer.new(limit: 8)
|
||||
m.register_type %r(^int)i, Type::Integer.new(limit: 4)
|
||||
m.register_type %r(^mediumint)i, Type::Integer.new(limit: 3)
|
||||
m.register_type %r(^smallint)i, Type::Integer.new(limit: 2)
|
||||
m.register_type %r(^tinyint)i, Type::Integer.new(limit: 1)
|
||||
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
||||
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
||||
|
||||
register_integer_type m, %r(^bigint)i, limit: 8
|
||||
register_integer_type m, %r(^int)i, limit: 4
|
||||
register_integer_type m, %r(^mediumint)i, limit: 3
|
||||
register_integer_type m, %r(^smallint)i, limit: 2
|
||||
register_integer_type m, %r(^tinyint)i, limit: 1
|
||||
|
||||
m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans
|
||||
m.alias_type %r(set)i, 'varchar'
|
||||
m.alias_type %r(year)i, 'integer'
|
||||
@ -676,6 +677,16 @@ def initialize_type_map(m) # :nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def register_integer_type(mapping, key, options) # :nodoc:
|
||||
mapping.register_type(key) do |sql_type|
|
||||
if /unsigned/i =~ sql_type
|
||||
Type::UnsignedInteger.new(options)
|
||||
else
|
||||
Type::Integer.new(options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# MySQL is too stupid to create a temporary table for use subquery, so we have
|
||||
# to give it some prompting in the form of a subsubquery. Ugh!
|
||||
def subquery_for(key, select)
|
||||
|
@ -17,6 +17,7 @@
|
||||
require 'active_record/type/string'
|
||||
require 'active_record/type/text'
|
||||
require 'active_record/type/time'
|
||||
require 'active_record/type/unsigned_integer'
|
||||
|
||||
require 'active_record/type/type_map'
|
||||
require 'active_record/type/hash_lookup_type_map'
|
||||
|
@ -5,7 +5,7 @@ class Integer < Value # :nodoc:
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
@range = -max_value...max_value
|
||||
@range = min_value...max_value
|
||||
end
|
||||
|
||||
def type
|
||||
@ -46,6 +46,10 @@ def max_value
|
||||
limit = self.limit || 4
|
||||
1 << (limit * 8 - 1) # 8 bits per byte with one bit for sign
|
||||
end
|
||||
|
||||
def min_value
|
||||
-max_value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
15
activerecord/lib/active_record/type/unsigned_integer.rb
Normal file
15
activerecord/lib/active_record/type/unsigned_integer.rb
Normal file
@ -0,0 +1,15 @@
|
||||
module ActiveRecord
|
||||
module Type
|
||||
class UnsignedInteger < Integer # :nodoc:
|
||||
private
|
||||
|
||||
def max_value
|
||||
super * 2
|
||||
end
|
||||
|
||||
def min_value
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
30
activerecord/test/cases/adapters/mysql/unsigned_type_test.rb
Normal file
30
activerecord/test/cases/adapters/mysql/unsigned_type_test.rb
Normal file
@ -0,0 +1,30 @@
|
||||
require "cases/helper"
|
||||
|
||||
class UnsignedTypeTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
class UnsignedType < ActiveRecord::Base
|
||||
end
|
||||
|
||||
setup do
|
||||
@connection = ActiveRecord::Base.connection
|
||||
@connection.create_table("unsigned_types", force: true) do |t|
|
||||
t.column :unsigned_integer, "int unsigned"
|
||||
end
|
||||
end
|
||||
|
||||
teardown do
|
||||
@connection.drop_table "unsigned_types"
|
||||
end
|
||||
|
||||
test "unsigned int max value is in range" do
|
||||
assert expected = UnsignedType.create(unsigned_integer: 4294967295)
|
||||
assert_equal expected, UnsignedType.find_by(unsigned_integer: 4294967295)
|
||||
end
|
||||
|
||||
test "minus value is out of range" do
|
||||
assert_raise(RangeError) do
|
||||
UnsignedType.create(unsigned_integer: -10)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,30 @@
|
||||
require "cases/helper"
|
||||
|
||||
class UnsignedTypeTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
class UnsignedType < ActiveRecord::Base
|
||||
end
|
||||
|
||||
setup do
|
||||
@connection = ActiveRecord::Base.connection
|
||||
@connection.create_table("unsigned_types", force: true) do |t|
|
||||
t.column :unsigned_integer, "int unsigned"
|
||||
end
|
||||
end
|
||||
|
||||
teardown do
|
||||
@connection.drop_table "unsigned_types"
|
||||
end
|
||||
|
||||
test "unsigned int max value is in range" do
|
||||
assert expected = UnsignedType.create(unsigned_integer: 4294967295)
|
||||
assert_equal expected, UnsignedType.find_by(unsigned_integer: 4294967295)
|
||||
end
|
||||
|
||||
test "minus value is out of range" do
|
||||
assert_raise(RangeError) do
|
||||
UnsignedType.create(unsigned_integer: -10)
|
||||
end
|
||||
end
|
||||
end
|
18
activerecord/test/cases/type/unsigned_integer_test.rb
Normal file
18
activerecord/test/cases/type/unsigned_integer_test.rb
Normal file
@ -0,0 +1,18 @@
|
||||
require "cases/helper"
|
||||
require "models/company"
|
||||
|
||||
module ActiveRecord
|
||||
module Type
|
||||
class UnsignedIntegerTest < ActiveRecord::TestCase
|
||||
test "unsigned int max value is in range" do
|
||||
assert_equal(4294967295, UnsignedInteger.new.type_cast_from_user("4294967295"))
|
||||
end
|
||||
|
||||
test "minus value is out of range" do
|
||||
assert_raises(::RangeError) do
|
||||
UnsignedInteger.new.type_cast_from_user("-1")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user