Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 4596

Show
Ignore:
Timestamp:
07/08/06 20:35:56 (2 years ago)
Author:
bitsweat
Message:

r4704@asus: jeremy | 2006-06-27 12:00:19 -0700
decimal
r4705@asus: jeremy | 2006-06-27 12:20:47 -0700
current_adapter? checks whether any of its arguments is the name of the current adapter class
r4834@asus: jeremy | 2006-07-08 13:08:24 -0700
Room to float.
r4835@asus: jeremy | 2006-07-08 13:09:18 -0700
Give lock test a few chances.
r4836@asus: jeremy | 2006-07-08 13:12:05 -0700
Numeric and decimal columns map to BigDecimal instead of Float. Those with scale 0 map to Integer. Closes #5454.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/CHANGELOG

    r4594 r4596  
    11*SVN* 
     2 
     3* Numeric and decimal columns map to BigDecimal instead of Float. Those with scale 0 map to Integer. #5454 [robbat2@gentoo.org, work@ashleymoran.me.uk] 
    24 
    35* Firebird migrations support. #5337 [Ken Kunz <kennethkunz@gmail.com>] 
  • trunk/activerecord/lib/active_record/base.rb

    r4586 r4596  
    17271727          self.id = connection.next_sequence_value(self.class.sequence_name) 
    17281728        end 
    1729  
     1729         
    17301730        self.id = connection.insert( 
    17311731          "INSERT INTO #{self.class.table_name} " + 
  • trunk/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb

    r3914 r4596  
    11require 'benchmark' 
    22require 'date' 
     3require 'bigdecimal' 
     4require 'bigdecimal/util' 
    35 
    46require 'active_record/connection_adapters/abstract/schema_definitions' 
  • trunk/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb

    r4391 r4596  
    1717              "'#{quote_string(value)}'" # ' (for ruby-mode) 
    1818            end 
    19           when NilClass              then "NULL" 
    20           when TrueClass             then (column && column.type == :integer ? '1' : quoted_true) 
    21           when FalseClass            then (column && column.type == :integer ? '0' : quoted_false) 
    22           when Float, Fixnum, Bignum then value.to_s 
    23           when Date                  then "'#{value.to_s}'" 
    24           when Time, DateTime        then "'#{quoted_date(value)}'" 
    25           else                            "'#{quote_string(value.to_yaml)}'" 
     19          when NilClass                 then "NULL" 
     20          when TrueClass                then (column && column.type == :integer ? '1' : quoted_true) 
     21          when FalseClass               then (column && column.type == :integer ? '0' : quoted_false) 
     22          when Float, Fixnum, Bignum    then value.to_s 
     23          # BigDecimals need to be output in a non-normalized form and quoted. 
     24          when BigDecimal               then value.to_s('F') 
     25          when Date                     then "'#{value.to_s}'" 
     26          when Time, DateTime           then "'#{quoted_date(value)}'" 
     27          else                          "'#{quote_string(value.to_yaml)}'" 
    2628        end 
    2729      end 
  • trunk/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb

    r4593 r4596  
    11require 'date' 
     2require 'bigdecimal' 
     3require 'bigdecimal/util' 
    24 
    35module ActiveRecord 
     
    57    # An abstract definition of a column in a table. 
    68    class Column 
    7       attr_reader :name, :default, :type, :limit, :null, :sql_type 
     9      attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale 
    810      attr_accessor :primary 
    911 
     
    1618      def initialize(name, default, sql_type = nil, null = true) 
    1719        @name, @sql_type, @null, @limit = name, sql_type, null, extract_limit(sql_type) 
     20        @precision, @scale  = extract_precision(sql_type), extract_scale(sql_type)  
    1821 
    1922        # simplified_type may depend on #limit, type_cast depends on #type 
     
    2932 
    3033      def number? 
    31         [:float, :integer].include? type 
     34        [:float, :integer, :decimal].include? type 
    3235      end 
    3336 
     
    3740          when :integer       then Fixnum 
    3841          when :float         then Float 
     42          when :decimal       then BigDecimal 
    3943          when :datetime      then Time 
    4044          when :date          then Date 
     
    5559          when :integer   then value.to_i rescue value ? 1 : 0 
    5660          when :float     then value.to_f 
     61          when :decimal   then self.class.value_to_decimal(value) 
    5762          when :datetime  then self.class.string_to_time(value) 
    5863          when :timestamp then self.class.string_to_time(value) 
     
    7176          when :integer   then "(#{var_name}.to_i rescue #{var_name} ? 1 : 0)" 
    7277          when :float     then "#{var_name}.to_f" 
     78          when :decimal   then "#{self.class.name}.value_to_decimal(#{var_name})" 
    7379          when :datetime  then "#{self.class.name}.string_to_time(#{var_name})" 
    7480          when :timestamp then "#{self.class.name}.string_to_time(#{var_name})" 
     
    128134      # convert something to a boolean 
    129135      def self.value_to_boolean(value) 
    130         return value if value==true || value==false 
    131         case value.to_s.downcase 
    132         when "true", "t", "1" then true 
    133         else false 
     136        if value == true || value == false 
     137          value 
     138        else 
     139          %w(true t 1).include?(value.to_s.downcase) 
     140        end 
     141      end 
     142 
     143      # convert something to a BigDecimal 
     144      def self.value_to_decimal(value) 
     145        if value.is_a?(BigDecimal) 
     146          value 
     147        elsif value.respond_to?(:to_d) 
     148          value.to_d 
     149        else 
     150          value.to_s.to_d 
    134151        end 
    135152      end 
     
    143160 
    144161        def extract_limit(sql_type) 
    145           return unless sql_type 
    146162          $1.to_i if sql_type =~ /\((.*)\)/ 
     163        end 
     164 
     165        def extract_precision(sql_type) 
     166          $2.to_i if sql_type =~ /^(numeric|decimal)\((\d+)(,\d+)?\)/i 
     167        end 
     168 
     169        def extract_scale(sql_type) 
     170          case sql_type 
     171            when /^(numeric|decimal)\((\d+)\)/i then 0 
     172            when /^(numeric|decimal)\((\d+)(,(\d+))\)/i then $4.to_i 
     173          end 
    147174        end 
    148175 
     
    151178            when /int/i 
    152179              :integer 
    153             when /float|double|decimal|numeric/i 
     180            when /float|double/i 
    154181              :float 
     182            when /decimal|numeric/i 
     183              extract_scale(field_type) == 0 ? :integer : :decimal 
    155184            when /datetime/i 
    156185              :datetime 
     
    176205    end 
    177206 
    178     class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :default, :null) #:nodoc: 
     207    class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc: 
    179208      def to_sql 
    180         column_sql = "#{base.quote_column_name(name)} #{type_to_sql(type.to_sym, limit)}" 
     209        column_sql = "#{base.quote_column_name(name)} #{type_to_sql(type.to_sym, limit, precision, scale)}" 
    181210        add_column_options!(column_sql, :null => null, :default => default) 
    182211        column_sql 
     
    185214 
    186215      private 
    187         def type_to_sql(name, limit
    188           base.type_to_sql(name, limit) rescue name 
     216        def type_to_sql(name, limit, precision, scale
     217          base.type_to_sql(name, limit, precision, scale) rescue name 
    189218        end 
    190219 
     
    218247      # The +type+ parameter must be one of the following values: 
    219248      # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>, 
    220       # <tt>:integer</tt>, <tt>:float</tt>, <tt>:datetime</tt>, 
    221       # <tt>:timestamp</tt>, <tt>:time</tt>, <tt>:date</tt>, 
    222       # <tt>:binary</tt>, <tt>:boolean</tt>. 
     249      # <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>, 
     250      # <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>, 
     251      # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. 
    223252      # 
    224253      # Available options are (none of these exists by default): 
     
    233262      #   Allows or disallows +NULL+ values in the column.  This option could 
    234263      #   have been named <tt>:null_allowed</tt>. 
     264      # * <tt>:precision</tt>: 
     265      #   Specifies the precision for a <tt>:decimal</tt> column.  
     266      # * <tt>:scale</tt>: 
     267      #   Specifies the scale for a <tt>:decimal</tt> column.  
     268      # 
     269      # Please be aware of different RDBMS implementations behavior with 
     270      # <tt>:decimal</tt> columns: 
     271      # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <= 
     272      #   <tt>:precision</tt>, and makes no comments about the requirements of 
     273      #   <tt>:precision</tt>. 
     274      # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].  
     275      #   Default is (10,0). 
     276      # * PostGres?: <tt>:precision</tt> [1..infinity],  
     277      #   <tt>:scale</tt> [0..infinity]. No default. 
     278      # * Sqlite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.  
     279      #   Internal storage as strings. No default. 
     280      # * Sqlite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>, 
     281      #   but the maximum supported <tt>:precision</tt> is 16. No default. 
     282      # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].  
     283      #   Default is (38,0). 
     284      # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].  
     285      #   Default unknown. 
     286      # * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].  
     287      #   Default (9,0). Internal types NUMERIC and DECIMAL have different 
     288      #   storage rules, decimal being better. 
     289      # * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].  
     290      #   Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for 
     291      #   NUMERIC is 19, and DECIMAL is 38. 
     292      # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].  
     293      #   Default (38,0). 
     294      # * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].  
     295      #   Default (38,0). 
     296      # * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>. 
    235297      # 
    236298      # This method returns <tt>self</tt>. 
     
    246308      #  td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false) 
    247309      #    #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL 
     310      # 
     311      #  def.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) 
     312      #    #=> bill_gates_money DECIMAL(15,2) 
     313      # 
     314      #  def.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) 
     315      #    #=> sensor_reading DECIMAL(30,20) 
     316      # 
     317      #  # While <tt>:scale</tt> defaults to zero on most databases, it 
     318      #  # probably wouldn't hurt to include it. 
     319      #  def.column(:huge_integer, :decimal, :precision => 30) 
     320      #    #=> huge_integer DECIMAL(30) 
    248321      def column(name, type, options = {}) 
    249322        column = self[name] || ColumnDefinition.new(@base, name, type) 
    250323        column.limit = options[:limit] || native[type.to_sym][:limit] if options[:limit] or native[type.to_sym] 
     324        column.precision = options[:precision] 
     325        column.scale = options[:scale] 
    251326        column.default = options[:default] 
    252327        column.null = options[:null] 
  • trunk/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb

    r4239 r4596  
    120120      # See TableDefinition#column for details of the options you can use. 
    121121      def add_column(table_name, column_name, type, options = {}) 
    122         add_column_sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit])}" 
     122        add_column_sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" 
    123123        add_column_options!(add_column_sql, options) 
    124124        execute(add_column_sql) 
     
    255255 
    256256 
    257       def type_to_sql(type, limit = nil) #:nodoc: 
     257      def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc: 
    258258        native = native_database_types[type] 
    259         limit ||= native[:limit] 
    260259        column_type_sql = native[:name] 
    261         column_type_sql << "(#{limit})" if limit 
    262         column_type_sql 
     260        if type == :decimal # ignore limit, use precison and scale 
     261          precision ||= native[:precision] 
     262          scale ||= native[:scale] 
     263          if precision 
     264            if scale 
     265              column_type_sql << "(#{precision},#{scale})" 
     266            else 
     267              column_type_sql << "(#{precision})" 
     268            end 
     269          else 
     270            raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specifed" if scale 
     271          end 
     272          column_type_sql 
     273        else 
     274          limit ||= native[:limit] 
     275          column_type_sql << "(#{limit})" if limit 
     276          column_type_sql 
     277        end 
    263278      end             
    264279     
  • trunk/activerecord/lib/active_record/connection_adapters/db2_adapter.rb

    r4013 r4596  
    163163            :integer     => { :name => 'int' }, 
    164164            :float       => { :name => 'float' }, 
     165            :decimal     => { :name => 'decimal' }, 
    165166            :datetime    => { :name => 'timestamp' }, 
    166167            :timestamp   => { :name => 'timestamp' }, 
  • trunk/activerecord/lib/active_record/connection_adapters/frontbase_adapter.rb

    r4393 r4596  
    161161        @null       = nullable == "YES" 
    162162        @text       = [:string, :text].include? @type 
    163         @number     = [:float, :integer].include? @type 
     163        @number     = [:float, :integer, :decimal].include? @type 
    164164        @fb_autogen = false 
    165165 
     
    279279          :integer        => { :name => "INTEGER" }, 
    280280          :float          => { :name => "FLOAT" }, 
     281          :decimal        => { :name => "DECIMAL" }, 
    281282          :datetime       => { :name => "TIMESTAMP" }, 
    282283          :timestamp      => { :name => "TIMESTAMP" }, 
     
    320321              when :float 
    321322                value.to_f.to_s 
     323              when :decimal 
     324                value.to_d.to_s("F") 
    322325              when :datetime, :timestamp 
    323326                "TIMESTAMP '#{value.strftime("%Y-%m-%d %H:%M:%S")}'" 
     
    360363                  s = value.unpack("H*").first 
    361364                  "X'#{s}'" 
    362                 elsif column && [:integer, :float].include?(column.type)  
     365                elsif column && [:integer, :float, :decimal].include?(column.type)  
    363366                  value.to_s 
    364367                else 
     
    371374              when FalseClass 
    372375                (column && column.type == :integer ? '0' : quoted_false) 
    373               when Float, Fixnum, Bignum 
     376              when Float, Fixnum, Bignum, BigDecimal 
    374377                value.to_s 
    375378              when Time, Date, DateTime 
  • trunk/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb

    r4340 r4596  
    103103          :integer     => { :name => "int", :limit => 11 }, 
    104104          :float       => { :name => "float" }, 
     105          :decimal     => { :name => "decimal" }, 
    105106          :datetime    => { :name => "datetime" }, 
    106107          :timestamp   => { :name => "datetime" }, 
     
    119120          s = column.class.string_to_binary(value).unpack("H*")[0] 
    120121          "x'#{s}'" 
     122        elsif value.kind_of?(BigDecimal) 
     123          "'#{value.to_s("F")}'" 
    121124        else 
    122125          super 
     
    313316        end 
    314317         
    315         change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit])}" 
     318        change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" 
    316319        add_column_options!(change_column_sql, options) 
    317320        execute(change_column_sql) 
  • trunk/activerecord/lib/active_record/connection_adapters/openbase_adapter.rb

    r4366 r4596  
    3333        def simplified_type(field_type) 
    3434          return :integer if field_type.downcase =~ /long/ 
    35           return :float  if field_type.downcase == "money" 
     35          return :decimal if field_type.downcase == "money" 
    3636          return :binary  if field_type.downcase == "object" 
    3737          super 
     
    6969          :integer     => { :name => "integer" }, 
    7070          :float       => { :name => "float" }, 
     71          :decimal     => { :name => "decimal" }, 
    7172          :datetime    => { :name => "datetime" }, 
    7273          :timestamp   => { :name => "timestamp" }, 
  • trunk/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb

    r4574 r4596  
    9494          return :boolean if OracleAdapter.emulate_booleans && field_type == 'NUMBER(1)' 
    9595          case field_type 
    96           when /num/i       : @scale == 0 ? :integer : :float 
    97           when /date|time/i : :datetime 
    98           else super 
     96            when /date|time/i then :datetime 
     97            else super 
    9998          end 
    10099        end 
     
    162161            :integer     => { :name => "NUMBER", :limit => 38 }, 
    163162            :float       => { :name => "NUMBER" }, 
     163            :decimal     => { :name => "DECIMAL" }, 
    164164            :datetime    => { :name => "DATE" }, 
    165165            :timestamp   => { :name => "DATE" }, 
  • trunk/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb

    r4580 r4596  
    9494          :integer     => { :name => "integer" }, 
    9595          :float       => { :name => "float" }, 
     96          :decimal     => { :name => "decimal" }, 
    9697          :datetime    => { :name => "timestamp" }, 
    9798          :timestamp   => { :name => "timestamp" }, 
     
    233234 
    234235      def columns(table_name, name = nil) #:nodoc: 
    235         column_definitions(table_name).collect do |name, type, default, notnull
    236           Column.new(name, default_value(default), translate_field_type(type), 
    237             notnull == "f") 
     236        column_definitions(table_name).collect do |name, type, default, notnull, typmod
     237          # typmod now unused as limit, precision, scale all handled by superclass 
     238          Column.new(name, default_value(default), translate_field_type(type), notnull == "f")  
    238239        end 
    239240      end 
     
    347348      def change_column(table_name, column_name, type, options = {}) #:nodoc: 
    348349        begin 
    349           execute "ALTER TABLE #{table_name} ALTER #{column_name} TYPE #{type_to_sql(type, options[:limit])}" 
     350          execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" 
    350351        rescue ActiveRecord::StatementInvalid 
    351352          # This is PG7, so we use a more arcane way of doing it. 
    352353          begin_db_transaction 
    353354          add_column(table_name, "#{column_name}_ar_tmp", type, options) 
    354           execute "UPDATE #{table_name} SET #{column_name}_ar_tmp = CAST(#{column_name} AS #{type_to_sql(type, options[:limit])})" 
     355          execute "UPDATE #{table_name} SET #{column_name}_ar_tmp = CAST(#{column_name} AS #{type_to_sql(type, options[:limit], options[:precision], options[:scale])})" 
    355356          remove_column(table_name, column_name) 
    356357          rename_column(table_name, "#{column_name}_ar_tmp", column_name) 
     
    361362 
    362363      def change_column_default(table_name, column_name, default) #:nodoc: 
    363         execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT '#{default}'" 
     364        execute "ALTER TABLE #{table_name} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT '#{default}'" 
    364365      end 
    365366 
    366367      def rename_column(table_name, column_name, new_column_name) #:nodoc: 
    367         execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}" 
     368        execute "ALTER TABLE #{table_name} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}" 
    368369      end 
    369370 
     
    372373      end 
    373374 
    374       def type_to_sql(type, limit = nil) #:nodoc: 
     375      def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc: 
    375376        return super unless type.to_s == 'integer' 
    376377 
     
    386387      private 
    387388        BYTEA_COLUMN_TYPE_OID = 17 
     389        NUMERIC_COLUMN_TYPE_OID = 1700 
    388390        TIMESTAMPOID = 1114 
    389391        TIMESTAMPTZOID = 1184 
     
    418420                  when TIMESTAMPTZOID, TIMESTAMPOID 
    419421                    column = cast_to_time(column) 
     422                  when NUMERIC_COLUMN_TYPE_OID 
     423                    column = column.to_d if column.respond_to?(:to_d) 
    420424                end 
    421425 
  • trunk/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb

    r4460 r4596  
    111111          :integer     => { :name => "integer" }, 
    112112          :float       => { :name => "float" }, 
     113          :decimal     => { :name => "decimal" }, 
    113114          :datetime    => { :name => "datetime" }, 
    114115          :timestamp   => { :name => "datetime" }, 
  • trunk/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb

    r4418 r4596  
    11require 'active_record/connection_adapters/abstract_adapter' 
     2 
     3require 'bigdecimal' 
     4require 'bigdecimal/util' 
    25 
    36# sqlserver_adapter.rb -- ActiveRecord adapter for Microsoft SQL Server 
     
    4649 
    4750  module ConnectionAdapters 
    48     class ColumnWithIdentity < Column# :nodoc: 
    49       attr_reader :identity, :is_special, :scale 
    50  
    51       def initialize(name, default, sql_type = nil, is_identity = false, null = true, scale_value = 0) 
     51    class SQLServerColumn < Column# :nodoc: 
     52      attr_reader :identity, :is_special 
     53 
     54      def initialize(name, default, sql_type = nil, identity = false, null = true) # TODO: check ok to remove scale_value = 0 
    5255        super(name, default, sql_type, null) 
    53         @identity = is_identity 
    54         @is_special = sql_type =~ /text|ntext|image/i ? true : false 
    55         @scale = scale_value 
     56        @identity = identity 
     57        @is_special = sql_type =~ /text|ntext|image/i 
     58        # TODO: check ok to remove @scale = scale_value 
    5659        # SQL Server only supports limits on *char and float types 
    5760        @limit = nil unless @type == :float or @type == :string 
     
    6063      def simplified_type(field_type) 
    6164        case field_type 
    62           when /int|bigint|smallint|tinyint/i                        then :integer 
    63           when /float|double|decimal|money|numeric|real|smallmoney/i then @scale == 0 ? :integer : :float 
    64           when /datetime|smalldatetime/i                             then :datetime 
    65           when /timestamp/i                                          then :timestamp 
    66           when /time/i                                               then :time 
    67           when /text|ntext/i                                         then :text 
    68           when /binary|image|varbinary/i                             then :binary 
    69           when /char|nchar|nvarchar|string|varchar/i                 then :string 
    70           when /bit/i                                                then :boolean 
    71           when /uniqueidentifier/i                                   then :string 
     65          when /money/i             then :decimal 
     66          when /image/i             then :binary 
     67          when /bit/i               then :boolean 
     68          when /uniqueidentifier/i  then :string 
     69          else super 
    7270        end 
    7371      end 
     
    7674        return nil if value.nil? || value =~ /^\s*null\s*$/i 
    7775        case type 
    78         when :string    then value 
    79         when :integer   then value == true || value == false ? value == true ? 1 : 0 : value.to_i 
    80         when :float     then value.to_f 
    8176        when :datetime  then cast_to_datetime(value) 
    8277        when :timestamp then cast_to_time(value) 
     
    8479        when :date      then cast_to_datetime(value) 
    8580        when :boolean   then value == true or (value =~ /^t(rue)?$/i) == 0 or value.to_s == '1' 
    86         else value 
     81        else super 
    8782        end 
    8883      end 
     
    185180          :integer     => { :name => "int" }, 
    186181          :float       => { :name => "float", :limit => 8 }, 
     182          :decimal     => { :name => "decimal" }, 
    187183          :datetime    => { :name => "datetime" }, 
    188184          :timestamp   => { :name => "datetime" }, 
    189185          :time        => { :name => "datetime" }, 
    190186          :date        => { :name => "datetime" }, 
    191           :binary      => { :name => "image"}, 
    192           :boolean     => { :name => "bit"
     187          :binary      => { :name => "image" }, 
     188          :boolean     => { :name => "bit"
    193189        } 
    194190      end 
     
    241237        table_name = table_name.to_s if table_name.is_a?(Symbol) 
    242238        table_name = table_name.split('.')[-1] unless table_name.nil? 
    243         sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue, DATA_TYPE as ColType, IS_NULLABLE As IsNullable, COL_LENGTH('#{table_name}', COLUMN_NAME) as Length, COLUMNPROPERTY(OBJECT_ID('#{table_name}'), COLUMN_NAME, 'IsIdentity') as IsIdentity, NUMERIC_SCALE as Scale FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '#{table_name}'" 
     239        sql = "SELECT COLUMN_NAME as ColName, 
     240                      COLUMN_DEFAULT as DefaultValue, 
     241                       DATA_TYPE as ColType, 
     242                       IS_NULLABLE As IsNullable, 
     243                       COL_LENGTH('#{table_name}', COLUMN_NAME) as Length, 
     244                       COLUMNPROPERTY(OBJECT_ID('#{table_name}'), COLUMN_NAME, 'IsIdentity') as IsIdentity, 
     245                       NUMERIC_PRECISION as [Precision], 
     246                       NUMERIC_SCALE as Scale 
     247               FROM INFORMATION_SCHEMA.COLUMNS 
     248               WHERE TABLE_NAME = '#{table_name}'" 
    244249        # Comment out if you want to have the Columns select statment logged. 
    245250        # Personally, I think it adds unnecessary bloat to the log.  
     
    250255        result.each do |field| 
    251256          default = field[:DefaultValue].to_s.gsub!(/[()\']/,"") =~ /null/ ? nil : field[:DefaultValue] 
    252           type = "#{field[:ColType]}(#{field[:Length]})" 
     257          if field[:ColType] =~ /numeric|decimal/i 
     258            type = "#{field[:ColType]}(#{field[:Precision]},#{field[:Scale]})" 
     259          else 
     260            type = "#{field[:ColType]}(#{field[:Length]})" 
     261          end 
    253262          is_identity = field[:IsIdentity] == 1 
    254263          is_nullable = field[:IsNullable] == 'YES' 
    255           columns << ColumnWithIdentity.new(field[:ColName], default, type, is_identity, is_nullable, field[:Scale]
     264          columns << SQLServerColumn.new(field[:ColName], default, type, is_identity, is_nullable
    256265        end 
    257266        columns 
     
    337346 
    338347        case value 
    339           when String                 
    340             if column && column.type == :binary && column.class.respond_to?(:string_to_binary) 
    341               "'#{quote_string(column.class.string_to_binary(value))}'" 
    342             else 
    343               "'#{quote_string(value)}'" 
    344             end 
    345           when NilClass              then "NULL" 
    346348          when TrueClass             then '1' 
    347349          when FalseClass            then '0' 
    348           when Float, Fixnum, Bignum then value.to_s 
    349           when Date                  then "'#{value.to_s}'"  
    350350          when Time, DateTime        then "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'" 
    351           else                            "'#{quote_string(value.to_yaml)}'" 
     351          else                       super 
    352352        end 
    353353      end 
     
    460460       
    461461      def change_column(table_name, column_name, type, options = {}) #:nodoc: 
    462         sql_commands = ["ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"] 
     462        sql_commands = ["ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"] 
    463463        if options[:default] 
    464464          remove_default_constraint(table_name, column_name) 
     
    484484      def remove_index(table_name, options = {}) 
    485485        execute "DROP INDEX #{table_name}.#{quote_column_name(index_name(table_name, options))}" 
    486       end 
    487  
    488       def type_to_sql(type, limit = nil) #:nodoc: 
    489         native = native_database_types[type] 
    490         # if there's no :limit in the default type definition, assume that type doesn't support limits 
    491         limit = limit || native[:limit] 
    492         column_type_sql = native[:name] 
    493         column_type_sql << "(#{limit})" if limit 
    494         column_type_sql 
    495486      end 
    496487 
  • trunk/activerecord/lib/active_record/connection_adapters/sybase_adapter.rb

    r4393 r4596  
    8787        def simplified_type(field_type) 
    8888          case field_type 
    89             when /int|bigint|smallint|tinyint/i                        then :integer 
    90             when /float|double|decimal|money|numeric|real|smallmoney/i then :float 
    91             when /text|ntext/i                                         then :text 
    92             when /binary|image|varbinary/i                             then :binary 
    93             when /char|nchar|nvarchar|string|varchar/i                 then :string 
    94             when /bit/i                                                then :boolean 
    95             when /datetime|smalldatetime/i                             then :datetime 
    96             else                                                       super 
     89            when /int|bigint|smallint|tinyint/i        then :integer 
     90            when /float|double|real/i                  then :float 
     91            when /decimal|money|numeric|smallmoney/i   then :decimal 
     92            when /text|ntext/i                         then :text 
     93            when /binary|image|varbinary/i             then :binary 
     94            when /char|nchar|nvarchar|string|varchar/i then :string 
     95            when /bit/i                                then :boolean 
     96            when /datetime|smalldatetime/i             then :datetime 
     97            else                                       super 
    9798          end 
    9899        end 
     
    138139          :integer     => { :name => "int" }, 
    139140          :float       => { :name => "float", :limit => 8 }, 
     141          :decimal     => { :name => "decimal" }, 
    140142          :datetime    => { :name => "datetime" }, 
    141143          :timestamp   => { :name => "timestamp" }, 
     
    288290          when TrueClass             then '1' 
    289291          when FalseClass            then '0' 
    290           when Float, Fixnum, Bignum 
    291             force_numeric?(column) ? value.to_s : "'#{value.to_s}'" 
    292           when Date                  then "'#{value.to_s}'"  
     292          when Float, Fixnum, Bignum then force_numeric?(column) ? value.to_s : "'#{value.to_s}'" 
    293293          when Time, DateTime        then "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'" 
    294           else                            "'#{quote_string(value.to_yaml)}'" 
     294          else                       super 
    295295        end 
    296296      end 
     
    299299      # if column is nil (not specified). 
    300300      def force_numeric?(column) 
    301         (column.nil? || [:integer, :float].include?(column.type)) 
     301        (column.nil? || [:integer, :float, :decimal].include?(column.type)) 
    302302      end 
    303303 
  • trunk/activerecord/lib/active_record/migration.rb

    r4249 r4596  
    6565  # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column to the table called +table_name+ 
    6666  #   named +column_name+ specified to be one of the following types: 
    67   #   :string, :text, :integer, :float, :datetime, :timestamp, :time, :date, :binary, :boolean. A default value can be specified 
    68   #   by passing an +options+ hash like { :default => 11 }. 
     67  #   :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, 
     68  #   :date, :binary, :boolean. A default value can be specified by passing an 
     69  #   +optio