diff options
Diffstat (limited to 'activerecord/lib')
10 files changed, 111 insertions, 108 deletions
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 8bd51dc71f..6c2403d87e 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -200,6 +200,7 @@ module ActiveRecord # this is probably horribly slow, but should only happen at most once for a given AR class attribute_method.bind(self).call(*args, &block) else + return super unless respond_to_missing?(method, true) send(method, *args, &block) end else diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 0c55dbb037..ea7703c82c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -374,26 +374,31 @@ module ActiveRecord end def initialize_type_map(m) # :nodoc: - m.register_type %r(boolean)i, Type::Boolean.new - m.register_type %r(char)i, Type::String.new - m.register_type %r(binary)i, Type::Binary.new - m.alias_type %r(blob)i, 'binary' - m.register_type %r(text)i, Type::Text.new - m.alias_type %r(clob)i, 'text' - m.register_type %r(date)i, Type::Date.new - m.register_type %r(time)i, Type::Time.new - m.alias_type %r(timestamp)i, 'datetime' - m.register_type %r(datetime)i, Type::DateTime.new - m.alias_type %r(numeric)i, 'decimal' - m.alias_type %r(number)i, 'decimal' - m.register_type %r(float)i, Type::Float.new - m.alias_type %r(double)i, 'float' - m.register_type %r(int)i, Type::Integer.new + register_class_with_limit m, %r(boolean)i, Type::Boolean + register_class_with_limit m, %r(char)i, Type::String + register_class_with_limit m, %r(binary)i, Type::Binary + register_class_with_limit m, %r(text)i, Type::Text + register_class_with_limit m, %r(date)i, Type::Date + register_class_with_limit m, %r(time)i, Type::Time + register_class_with_limit m, %r(datetime)i, Type::DateTime + register_class_with_limit m, %r(float)i, Type::Float + register_class_with_limit m, %r(int)i, Type::Integer + + m.alias_type %r(blob)i, 'binary' + m.alias_type %r(clob)i, 'text' + m.alias_type %r(timestamp)i, 'datetime' + m.alias_type %r(numeric)i, 'decimal' + m.alias_type %r(number)i, 'decimal' + m.alias_type %r(double)i, 'float' + m.register_type(%r(decimal)i) do |sql_type| - if Type.extract_scale(sql_type) == 0 - Type::Integer.new + scale = extract_scale(sql_type) + precision = extract_precision(sql_type) + + if scale == 0 + Type::Integer.new(precision: precision) else - Type::Decimal.new + Type::Decimal.new(precision: precision, scale: scale) end end end @@ -403,6 +408,28 @@ module ActiveRecord initialize_type_map(type_map) end + def register_class_with_limit(mapping, key, klass) # :nodoc: + mapping.register_type(key) do |*args| + limit = extract_limit(args.last) + klass.new(limit: limit) + end + end + + def extract_scale(sql_type) # :nodoc: + case sql_type + when /\((\d+)\)/ then 0 + when /\((\d+)(,(\d+))\)/ then $3.to_i + end + end + + def extract_precision(sql_type) # :nodoc: + $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/ + end + + def extract_limit(sql_type) # :nodoc: + $1.to_i if sql_type =~ /\((.*)\)/ + end + def translate_exception_class(e, sql) message = "#{e.class.name}: #{e.message}: #{sql}" @logger.error message if @logger diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 86eb2a38d8..d3f8470c30 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -86,44 +86,12 @@ module ActiveRecord sql_type =~ /blob/i || type == :text end - # Must return the relevant concrete adapter - def adapter - raise NotImplementedError - end - def case_sensitive? collation && !collation.match(/_ci$/) end private - def extract_limit(sql_type) - case sql_type - when /^enum\((.+)\)/i - $1.split(',').map{|enum| enum.strip.length - 2}.max - when /blob|text/i - case sql_type - when /tiny/i - 255 - when /medium/i - 16777215 - when /long/i - 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases - else - super # we could return 65535 here, but we leave it undecorated by default - end - when /^bigint/i; 8 - when /^int/i; 4 - when /^mediumint/i; 3 - when /^smallint/i; 2 - when /^tinyint/i; 1 - when /^float/i; 24 - when /^double/i; 53 - else - super - end - end - # MySQL misreports NOT NULL column default when none is given. # We can't detect this for columns which may have a legitimate '' # default (string) but we can for others (integer, datetime, boolean, @@ -636,10 +604,29 @@ module ActiveRecord protected - def initialize_type_map(m) + def initialize_type_map(m) # :nodoc: super + m.register_type(%r(enum)i) do |sql_type| + limit = sql_type[/^enum\((.+)\)/i, 1] + .split(',').map{|enum| enum.strip.length - 2}.max + Type::String.new(limit: limit) + end + + m.register_type %r(tinytext)i, Type::Text.new(limit: 255) + m.register_type %r(tinyblob)i, Type::Binary.new(limit: 255) + m.register_type %r(mediumtext)i, Type::Text.new(limit: 16777215) + m.register_type %r(mediumblob)i, Type::Binary.new(limit: 16777215) + m.register_type %r(longtext)i, Type::Text.new(limit: 2147483647) + m.register_type %r(longblob)i, Type::Binary.new(limit: 2147483647) + 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) + m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans - m.alias_type %r(enum)i, 'varchar' m.alias_type %r(set)i, 'varchar' m.alias_type %r(year)i, 'integer' m.alias_type %r(bit)i, 'binary' diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index a718756b93..704868c058 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -13,12 +13,12 @@ module ActiveRecord ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/ end - attr_reader :name, :default, :cast_type, :limit, :null, :sql_type, :precision, :scale, :default_function + attr_reader :name, :default, :cast_type, :null, :sql_type, :default_function attr_accessor :primary, :coder alias :encoded? :coder - delegate :type, :klass, :text?, :number?, :binary?, :type_cast_for_write, to: :cast_type + delegate :type, :precision, :scale, :limit, :klass, :text?, :number?, :binary?, :type_cast_for_write, to: :cast_type # Instantiates a new column in the table. # @@ -34,9 +34,6 @@ module ActiveRecord @cast_type = cast_type @sql_type = sql_type @null = null - @limit = extract_limit(sql_type) - @precision = extract_precision(sql_type) - @scale = extract_scale(sql_type) @default = extract_default(default) @default_function = nil @primary = nil @@ -67,17 +64,6 @@ module ActiveRecord def extract_default(default) type_cast(default) end - - private - delegate :extract_scale, to: :cast_type - - def extract_limit(sql_type) - $1.to_i if sql_type =~ /\((.*)\)/ - end - - def extract_precision(sql_type) - $2.to_i if sql_type =~ /^(numeric|decimal|number)\((\d+)(,\d+)?\)/i - end end end # :startdoc: diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb index 80c79642f3..b55766bde0 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb @@ -35,8 +35,6 @@ module ActiveRecord require 'active_record/connection_adapters/postgresql/array_parser' include PostgreSQL::ArrayParser end - - attr_accessor :money_precision end # :startdoc: @@ -112,26 +110,6 @@ module ActiveRecord def has_default_function?(default_value, default) !default_value && (%r{\w+\(.*\)} === default) end - - def extract_limit(sql_type) - case sql_type - when /^bigint/i; 8 - when /^smallint/i; 2 - when /^timestamp/i; nil - else super - end - end - - # Extracts the precision from PostgreSQL-specific data types. - def extract_precision(sql_type) - if sql_type == 'money' - self.class.money_precision - elsif sql_type =~ /timestamp/i - $1.to_i if sql_type =~ /\((\d+)\)/ - else - super - end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb index 1e34c09c88..697dceb7c2 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb @@ -5,7 +5,9 @@ module ActiveRecord class Money < Type::Decimal include Infinity - def extract_scale(sql_type) + class_attribute :precision + + def scale 2 end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 7d1fa0dd08..e3a2422160 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -551,6 +551,8 @@ module ActiveRecord } end + OID_FOR_DECIMAL_TREATED_AS_INT = 23 # :nodoc: + def normalize_oid_type(ftype, fmod) # The type for the numeric depends on the width of the field, # so we'll do something special here. @@ -560,29 +562,27 @@ module ActiveRecord # places after decimal = fmod - 4 & 0xffff # places before decimal = (fmod - 4) >> 16 & 0xffff if ftype == 1700 && (fmod - 4 & 0xffff).zero? - 23 + OID_FOR_DECIMAL_TREATED_AS_INT else ftype end end def initialize_type_map(m) - m.register_type 'int2', OID::Integer.new + register_class_with_limit m, 'int2', OID::Integer m.alias_type 'int4', 'int2' m.alias_type 'int8', 'int2' m.alias_type 'oid', 'int2' - m.register_type 'numeric', OID::Decimal.new m.register_type 'float4', OID::Float.new m.alias_type 'float8', 'float4' m.register_type 'text', Type::Text.new - m.register_type 'varchar', Type::String.new + register_class_with_limit m, 'varchar', Type::String m.alias_type 'char', 'varchar' m.alias_type 'name', 'varchar' m.alias_type 'bpchar', 'varchar' m.register_type 'bool', Type::Boolean.new m.register_type 'bit', OID::Bit.new m.alias_type 'varbit', 'bit' - m.register_type 'timestamp', OID::DateTime.new m.alias_type 'timestamptz', 'timestamp' m.register_type 'date', OID::Date.new m.register_type 'time', OID::Time.new @@ -610,9 +610,33 @@ module ActiveRecord m.alias_type 'lseg', 'varchar' m.alias_type 'box', 'varchar' + m.register_type 'timestamp' do |_, sql_type| + precision = extract_precision(sql_type) + OID::DateTime.new(precision: precision) + end + + m.register_type 'numeric' do |_, sql_type| + precision = extract_precision(sql_type) + scale = extract_scale(sql_type) + OID::Decimal.new(precision: precision, scale: scale) + end + + m.register_type OID_FOR_DECIMAL_TREATED_AS_INT do |_, sql_type| + precision = extract_precision(sql_type) + OID::Integer.new(precision: precision) + end + load_additional_types(m) end + def extract_limit(sql_type) # :nodoc: + case sql_type + when /^bigint/i; 8 + when /^smallint/i; 2 + else super + end + end + def load_additional_types(type_map, oids = nil) if supports_ranges? query = <<-SQL @@ -713,7 +737,7 @@ module ActiveRecord # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision # should know about this but can't detect it there, so deal with it here. - PostgreSQLColumn.money_precision = (postgresql_version >= 80300) ? 19 : 10 + OID::Money.precision = (postgresql_version >= 80300) ? 19 : 10 configure_connection rescue ::PG::Error => error diff --git a/activerecord/lib/active_record/connection_adapters/type.rb b/activerecord/lib/active_record/connection_adapters/type.rb index 9103ae85c0..395a4160a8 100644 --- a/activerecord/lib/active_record/connection_adapters/type.rb +++ b/activerecord/lib/active_record/connection_adapters/type.rb @@ -19,14 +19,6 @@ require 'active_record/connection_adapters/type/hash_lookup_type_map' module ActiveRecord module ConnectionAdapters module Type # :nodoc: - class << self - def extract_scale(sql_type) - case sql_type - when /\((\d+)\)/ then 0 - when /\((\d+)(,(\d+))\)/ then $3.to_i - end - end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/type/decimal.rb b/activerecord/lib/active_record/connection_adapters/type/decimal.rb index a8cd1cf5b5..ac5af4b963 100644 --- a/activerecord/lib/active_record/connection_adapters/type/decimal.rb +++ b/activerecord/lib/active_record/connection_adapters/type/decimal.rb @@ -4,8 +4,6 @@ module ActiveRecord class Decimal < Value # :nodoc: include Numeric - delegate :extract_scale, to: Type - def type :decimal end diff --git a/activerecord/lib/active_record/connection_adapters/type/value.rb b/activerecord/lib/active_record/connection_adapters/type/value.rb index 52d9ed9bc0..54a3e9dd7a 100644 --- a/activerecord/lib/active_record/connection_adapters/type/value.rb +++ b/activerecord/lib/active_record/connection_adapters/type/value.rb @@ -2,8 +2,16 @@ module ActiveRecord module ConnectionAdapters module Type class Value # :nodoc: + attr_reader :precision, :scale, :limit + + def initialize(options = {}) + options.assert_valid_keys(:precision, :scale, :limit) + @precision = options[:precision] + @scale = options[:scale] + @limit = options[:limit] + end + def type; end - def extract_scale(sql_type); end def type_cast(value) cast_value(value) unless value.nil? |