aboutsummaryrefslogblamecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
blob: b55766bde0c998afc96d8be3c685d5eeb9e22401 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                                           





                                                                      
                                                                           



                                                                          
                                                                                       

                        
                                                               




                                                                                    

                   
                                









                                                                             
                                         
           

































































                                                                            
                  
                          






                                                         


       
require 'active_record/connection_adapters/postgresql/cast'

module ActiveRecord
  module ConnectionAdapters
    # PostgreSQL-specific extensions to column definitions in a table.
    class PostgreSQLColumn < Column #:nodoc:
      attr_accessor :array

      def initialize(name, default, cast_type, sql_type = nil, null = true)
        default_value     = self.class.extract_value_from_default(default)

        if sql_type =~ /\[\]$/
          @array = true
          super(name, default_value, cast_type, sql_type[0..sql_type.length - 3], null)
        else
          @array = false
          super(name, default_value, cast_type, sql_type, null)
        end

        @default_function = default if has_default_function?(default_value, default)
      end

      # :stopdoc:
      class << self
        include PostgreSQL::Cast

        # Loads pg_array_parser if available. String parsing can be
        # performed quicker by a native extension, which will not create
        # a large amount of Ruby objects that will need to be garbage
        # collected. pg_array_parser has a C and Java extension
        begin
          require 'pg_array_parser'
          include PgArrayParser
        rescue LoadError
          require 'active_record/connection_adapters/postgresql/array_parser'
          include PostgreSQL::ArrayParser
        end
      end
      # :startdoc:

      # Extracts the value from a PostgreSQL column default definition.
      def self.extract_value_from_default(default)
        # This is a performance optimization for Ruby 1.9.2 in development.
        # If the value is nil, we return nil straight away without checking
        # the regular expressions. If we check each regular expression,
        # Regexp#=== will call NilClass#to_str, which will trigger
        # method_missing (defined by whiny nil in ActiveSupport) which
        # makes this method very very slow.
        return default unless default

        case default
          when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
            $1
          # Numeric types
          when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/
            $1
          # Character types
          when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
            $1.gsub(/''/, "'")
          # Binary data types
          when /\A'(.*)'::bytea\z/m
            $1
          # Date/time types
          when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
            $1
          when /\A'(.*)'::interval\z/
            $1
          # Boolean type
          when 'true'
            true
          when 'false'
            false
          # Geometric types
          when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
            $1
          # Network address types
          when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
            $1
          # Bit string types
          when /\AB'(.*)'::"?bit(?: varying)?"?\z/
            $1
          # XML type
          when /\A'(.*)'::xml\z/m
            $1
          # Arrays
          when /\A'(.*)'::"?\D+"?\[\]\z/
            $1
          # Hstore
          when /\A'(.*)'::hstore\z/
            $1
          # JSON
          when /\A'(.*)'::json\z/
            $1
          # Object identifier types
          when /\A-?\d+\z/
            $1
          else
            # Anything else is blank, some user type, or some function
            # and we can't know the value of that, so return nil.
            nil
        end
      end

      def accessor
        cast_type.accessor
      end

      private

        def has_default_function?(default_value, default)
          !default_value && (%r{\w+\(.*\)} === default)
        end
    end
  end
end