postgresql_adapter.rb 48.1 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1
require 'active_record/connection_adapters/abstract_adapter'
2
require 'active_support/core_ext/object/blank'
3
require 'active_record/connection_adapters/statement_pool'
4
require 'active_record/connection_adapters/postgresql/oid'
5
require 'arel/visitors/bind_visitor'
6 7 8

# Make sure we're using pg high enough for PGResult#values
gem 'pg', '~> 0.11'
9
require 'pg'
D
Initial  
David Heinemeier Hansson 已提交
10 11

module ActiveRecord
12
  module ConnectionHandling
D
Initial  
David Heinemeier Hansson 已提交
13
    # Establishes a connection to the database that's used by all Active Record objects
J
Jon Leighton 已提交
14
    def postgresql_connection(config) # :nodoc:
15
      conn_params = config.symbolize_keys
D
Initial  
David Heinemeier Hansson 已提交
16

17
      # Forward any unused config params to PGconn.connect.
18
      [:statement_limit, :encoding, :min_messages, :schema_search_path,
19
       :schema_order, :adapter, :pool, :wait_timeout, :template,
20 21 22
       :reaping_frequency].each do |key|
        conn_params.delete key
      end
23
      conn_params.delete_if { |k,v| v.nil? }
24 25 26 27

      # Map ActiveRecords param names to PGs.
      conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
      conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
D
Initial  
David Heinemeier Hansson 已提交
28

29
      # The postgres drivers don't allow the creation of an unconnected PGconn object,
30
      # so just pass a nil connection object for the time being.
31
      ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)
32 33
    end
  end
34

35 36 37 38
  module ConnectionAdapters
    # PostgreSQL-specific extensions to column definitions in a table.
    class PostgreSQLColumn < Column #:nodoc:
      # Instantiates a new PostgreSQL column definition in a table.
39 40
      def initialize(name, default, oid_type, sql_type = nil, null = true)
        @oid_type = oid_type
41 42
        super(name, self.class.extract_value_from_default(default), sql_type, null)
      end
43

44 45 46
      # :stopdoc:
      class << self
        attr_accessor :money_precision
47 48 49 50 51 52 53 54 55 56
        def string_to_time(string)
          return string unless String === string

          case string
          when 'infinity'  then 1.0 / 0.0
          when '-infinity' then -1.0 / 0.0
          else
            super
          end
        end
57

58
        def hstore_to_string(object)
59
          if Hash === object
A
Aaron Patterson 已提交
60 61
            object.map { |k,v|
              "#{escape_hstore(k)}=>#{escape_hstore(v)}"
62
            }.join ','
63
          else
64
            object
A
Aaron Patterson 已提交
65 66 67
          end
        end

68 69 70 71 72 73 74 75 76 77 78
        def string_to_hstore(string)
          if string.nil?
            nil
          elsif String === string
            Hash[string.scan(HstorePair).map { |k,v|
              v = v.upcase == 'NULL' ? nil : v.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
              k = k.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
              [k,v]
            }]
          else
            string
A
Aaron Patterson 已提交
79 80 81
          end
        end

82
        private
83 84 85 86
        HstorePair = begin
          quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
          unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
          /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
A
Aaron Patterson 已提交
87 88 89
        end

        def escape_hstore(value)
90 91 92
            value.nil?         ? 'NULL'
          : value =~ /[=\s,>]/ ? '"%s"' % value.gsub(/(["\\])/, '\\\\\1')
          : value == ""        ? '""'
J
Joel 已提交
93
          :                      value.to_s.gsub(/(["\\])/, '\\\\\1')
94
        end
95 96 97
      end
      # :startdoc:

98 99 100 101 102 103 104 105 106 107 108 109 110 111
      # 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
          # Numeric types
          when /\A\(?(-?\d+(\.\d*)?\)?)\z/
            $1
112
          # Character types
113 114 115 116 117
          when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
            $1
          # Character types (8.1 formatting)
          when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
            $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
118
          # Binary data types
119 120
          when /\A'(.*)'::bytea\z/m
            $1
121
          # Date/time types
122 123 124 125 126 127 128 129 130
          when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
            $1
          when /\A'(.*)'::interval\z/
            $1
          # Boolean type
          when 'true'
            true
          when 'false'
            false
131
          # Geometric types
132 133
          when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
            $1
134
          # Network address types
135 136 137 138 139
          when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
            $1
          # Bit string types
          when /\AB'(.*)'::"?bit(?: varying)?"?\z/
            $1
140
          # XML type
141 142
          when /\A'(.*)'::xml\z/m
            $1
143
          # Arrays
144 145
          when /\A'(.*)'::"?\D+"?\[\]\z/
            $1
146 147 148
          # Hstore
          when /\A'(.*)'::hstore\z/
            $1
149
          # Object identifier types
150 151
          when /\A-?\d+\z/
            $1
152
          else
153 154 155
            # Anything else is blank, some user type, or some function
            # and we can't know the value of that, so return nil.
            nil
156
        end
157
      end
158

159 160 161 162 163 164 165
      def type_cast(value)
        return if value.nil?
        return super if encoded?

        @oid_type.type_cast value
      end

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
      private
      def extract_limit(sql_type)
        case sql_type
        when /^bigint/i;    8
        when /^smallint/i;  2
        else super
        end
      end

      # Extracts the scale from PostgreSQL-specific data types.
      def extract_scale(sql_type)
        # Money type has a fixed scale of 2.
        sql_type =~ /^money/ ? 2 : super
      end

      # Extracts the precision from PostgreSQL-specific data types.
      def extract_precision(sql_type)
        if sql_type == 'money'
          self.class.money_precision
        else
          super
        end
      end

      # Maps PostgreSQL-specific data types to logical Rails types.
      def simplified_type(field_type)
        case field_type
        # Numeric and monetary types
        when /^(?:real|double precision)$/
          :float
        # Monetary types
        when 'money'
          :decimal
        when 'hstore'
          :hstore
        # Character types
        when /^(?:character varying|bpchar)(?:\(\d+\))?$/
          :string
        # Binary data types
        when 'bytea'
          :binary
        # Date/time types
        when /^timestamp with(?:out)? time zone$/
          :datetime
        when 'interval'
          :string
        # Geometric types
        when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
          :string
        # Network address types
        when /^(?:cidr|inet|macaddr)$/
          :string
        # Bit strings
        when /^bit(?: varying)?(?:\(\d+\))?$/
          :string
        # XML type
        when 'xml'
          :xml
        # tsvector type
        when 'tsvector'
          :tsvector
        # Arrays
        when /^\D+\[\]$/
          :string
        # Object identifier types
        when 'oid'
          :integer
        # UUID type
        when 'uuid'
          :string
        # Small and big integer types
        when /^(?:small|big)int$/
          :integer
        # Pass through all types that are not specific to PostgreSQL.
        else
          super
242
        end
243
      end
D
Initial  
David Heinemeier Hansson 已提交
244 245
    end

246
    # The PostgreSQL adapter works with the native C (https://bitbucket.org/ged/ruby-pg) driver.
247 248 249
    #
    # Options:
    #
250 251
    # * <tt>:host</tt> - Defaults to a Unix-domain socket in /tmp. On machines without Unix-domain sockets,
    #   the default is to connect to localhost.
P
Pratik Naik 已提交
252
    # * <tt>:port</tt> - Defaults to 5432.
253 254 255
    # * <tt>:username</tt> - Defaults to be the same as the operating system name of the user running the application.
    # * <tt>:password</tt> - Password to be used if the server demands password authentication.
    # * <tt>:database</tt> - Defaults to be the same as the user name.
256
    # * <tt>:schema_search_path</tt> - An optional schema search path for the connection given
257
    #   as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
258
    # * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
259
    #   <encoding></tt> call on the connection.
260
    # * <tt>:min_messages</tt> - An optional client min messages that is used in a
261
    #   <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
262 263 264 265 266 267 268
    #
    # Any further options are used as connection parameters to libpq. See
    # http://www.postgresql.org/docs/9.1/static/libpq-connect.html for the
    # list of parameters.
    #
    # In addition, default connection parameters of libpq can be set per environment variables.
    # See http://www.postgresql.org/docs/9.1/static/libpq-envars.html .
269
    class PostgreSQLAdapter < AbstractAdapter
270 271 272 273 274
      class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
        def xml(*args)
          options = args.extract_options!
          column(args[0], 'xml', options)
        end
275 276 277 278 279

        def tsvector(*args)
          options = args.extract_options!
          column(args[0], 'tsvector', options)
        end
280 281 282 283

        def hstore(name, options = {})
          column(name, 'hstore', options)
        end
284 285
      end

286
      ADAPTER_NAME = 'PostgreSQL'
287 288

      NATIVE_DATABASE_TYPES = {
289
        :primary_key => "serial primary key",
290 291 292 293 294 295 296 297 298 299
        :string      => { :name => "character varying", :limit => 255 },
        :text        => { :name => "text" },
        :integer     => { :name => "integer" },
        :float       => { :name => "float" },
        :decimal     => { :name => "decimal" },
        :datetime    => { :name => "timestamp" },
        :timestamp   => { :name => "timestamp" },
        :time        => { :name => "time" },
        :date        => { :name => "date" },
        :binary      => { :name => "bytea" },
300
        :boolean     => { :name => "boolean" },
301
        :xml         => { :name => "xml" },
302 303
        :tsvector    => { :name => "tsvector" },
        :hstore      => { :name => "hstore" }
304 305
      }

306
      # Returns 'PostgreSQL' as adapter name for identification purposes.
307
      def adapter_name
308
        ADAPTER_NAME
309 310
      end

311 312
      # Returns +true+, since this connection adapter supports prepared statement
      # caching.
313 314 315 316
      def supports_statement_cache?
        true
      end

317 318 319 320
      def supports_index_sort_order?
        true
      end

321 322 323 324
      def supports_partial_index?
        true
      end

325 326 327 328
      class StatementPool < ConnectionAdapters::StatementPool
        def initialize(connection, max)
          super
          @counter = 0
329
          @cache   = Hash.new { |h,pid| h[pid] = {} }
330 331
        end

332 333 334 335
        def each(&block); cache.each(&block); end
        def key?(key);    cache.key?(key); end
        def [](key);      cache[key]; end
        def length;       cache.length; end
336 337 338 339 340 341

        def next_key
          "a#{@counter + 1}"
        end

        def []=(sql, key)
342 343
          while @max <= cache.size
            dealloc(cache.shift.last)
344 345
          end
          @counter += 1
346
          cache[sql] = key
347 348 349
        end

        def clear
350
          cache.each_value do |stmt_key|
351 352
            dealloc stmt_key
          end
353
          cache.clear
354 355
        end

356 357 358 359 360
        def delete(sql_key)
          dealloc cache[sql_key]
          cache.delete sql_key
        end

361
        private
362
        def cache
A
Aaron Patterson 已提交
363
          @cache[Process.pid]
364 365
        end

366
        def dealloc(key)
367 368 369 370 371 372 373
          @connection.query "DEALLOCATE #{key}" if connection_active?
        end

        def connection_active?
          @connection.status == PGconn::CONNECTION_OK
        rescue PGError
          false
374 375 376
        end
      end

377 378 379 380
      class BindSubstitution < Arel::Visitors::PostgreSQL # :nodoc:
        include Arel::Visitors::BindVisitor
      end

381 382
      # Initializes and connects a PostgreSQL adapter.
      def initialize(connection, logger, connection_parameters, config)
383
        super(connection, logger)
384 385 386 387 388 389 390 391 392

        if config.fetch(:prepared_statements) { true }
          @visitor = Arel::Visitors::PostgreSQL.new self
        else
          @visitor = BindSubstitution.new self
        end

        connection_parameters.delete :prepared_statements

393
        @connection_parameters, @config = connection_parameters, config
394

395 396
        # @local_tz is initialized as nil to avoid warnings when connect tries to use it
        @local_tz = nil
397 398
        @table_alias_length = nil

399
        connect
400 401
        @statements = StatementPool.new @connection,
                                        config.fetch(:statement_limit) { 1000 }
402 403 404 405 406

        if postgresql_version < 80200
          raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
        end

407
        initialize_type_map
408
        @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
409 410
      end

X
Xavier Noria 已提交
411
      # Clears the prepared statements cache.
412 413 414 415
      def clear_cache!
        @statements.clear
      end

416 417
      # Is this connection alive and ready for queries?
      def active?
418 419
        @connection.status == PGconn::CONNECTION_OK
      rescue PGError
420
        false
421 422 423 424
      end

      # Close then reopen the connection.
      def reconnect!
425 426 427
        clear_cache!
        @connection.reset
        configure_connection
428
      end
429

430 431 432 433 434
      def reset!
        clear_cache!
        super
      end

435 436
      # Disconnects from the database if already connected. Otherwise, this
      # method does nothing.
437
      def disconnect!
438
        clear_cache!
439 440
        @connection.close rescue nil
      end
441

442
      def native_database_types #:nodoc:
443
        NATIVE_DATABASE_TYPES
444
      end
445

446
      # Returns true, since this connection adapter supports migrations.
447 448
      def supports_migrations?
        true
449 450
      end

451
      # Does PostgreSQL support finding primary key on non-Active Record tables?
452 453 454 455
      def supports_primary_key? #:nodoc:
        true
      end

456 457 458
      # Enable standard-conforming strings if available.
      def set_standard_conforming_strings
        old, self.client_min_messages = client_min_messages, 'panic'
459
        execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
460 461
      ensure
        self.client_min_messages = old
462 463
      end

464
      def supports_insert_with_returning?
465
        true
466 467
      end

468 469 470
      def supports_ddl_transactions?
        true
      end
471

472
      # Returns true, since this connection adapter supports savepoints.
473 474 475
      def supports_savepoints?
        true
      end
476

477 478 479 480 481
      # Returns true.
      def supports_explain?
        true
      end

482
      # Returns the configured supported identifier length supported by PostgreSQL
483
      def table_alias_length
484
        @table_alias_length ||= query('SHOW max_identifier_length')[0][0].to_i
485
      end
486

487 488
      # QUOTING ==================================================

489
      # Escapes binary strings for bytea input to the database.
490
      def escape_bytea(value)
491
        PGconn.escape_bytea(value) if value
492 493 494 495 496
      end

      # Unescapes bytea output from a database to the binary string it represents.
      # NOTE: This is NOT an inverse of escape_bytea! This is only to be used
      #       on escaped binary output from database drive.
497
      def unescape_bytea(value)
498
        PGconn.unescape_bytea(value) if value
499 500
      end

501 502
      # Quotes PostgreSQL-specific data types for SQL input.
      def quote(value, column = nil) #:nodoc:
503 504
        return super unless column

A
Aaron Patterson 已提交
505
        case value
506 507 508 509 510
        when Hash
          case column.sql_type
          when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column)
          else super
          end
511 512 513
        when Float
          return super unless value.infinite? && column.type == :datetime
          "'#{value.to_s.downcase}'"
A
Aaron Patterson 已提交
514 515
        when Numeric
          return super unless column.sql_type == 'money'
516
          # Not truly string input, so doesn't require (or allow) escape string syntax.
517
          "'#{value}'"
A
Aaron Patterson 已提交
518 519 520 521 522 523 524 525 526 527 528
        when String
          case column.sql_type
          when 'bytea' then "'#{escape_bytea(value)}'"
          when 'xml'   then "xml '#{quote_string(value)}'"
          when /^bit/
            case value
            when /^[01]*$/      then "B'#{value}'" # Bit-string notation
            when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
            end
          else
            super
529
          end
530 531 532 533 534
        else
          super
        end
      end

535 536 537 538 539 540
      def type_cast(value, column)
        return super unless column

        case value
        when String
          return super unless 'bytea' == column.sql_type
541
          { :value => value, :format => 1 }
542 543 544
        when Hash
          return super unless 'hstore' == column.sql_type
          PostgreSQLColumn.hstore_to_string(value)
545 546 547 548 549
        else
          super
        end
      end

550 551 552
      # Quotes strings for use in SQL input.
      def quote_string(s) #:nodoc:
        @connection.escape(s)
553 554
      end

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
      # Checks the following cases:
      #
      # - table_name
      # - "table.name"
      # - schema_name.table_name
      # - schema_name."table.name"
      # - "schema.name".table_name
      # - "schema.name"."table.name"
      def quote_table_name(name)
        schema, name_part = extract_pg_identifier_from_name(name.to_s)

        unless name_part
          quote_column_name(schema)
        else
          table_name, name_part = extract_pg_identifier_from_name(name_part)
          "#{quote_column_name(schema)}.#{quote_column_name(table_name)}"
        end
      end

574 575
      # Quotes column names for use in SQL queries.
      def quote_column_name(name) #:nodoc:
576
        PGconn.quote_ident(name.to_s)
577 578
      end

579 580 581
      # Quote date/time values for use in SQL input. Includes microseconds
      # if the value is a Time responding to usec.
      def quoted_date(value) #:nodoc:
582 583 584 585 586
        if value.acts_like?(:time) && value.respond_to?(:usec)
          "#{super}.#{sprintf("%06d", value.usec)}"
        else
          super
        end
587 588
      end

589 590
      # Set the authorized user for this session
      def session_auth=(user)
591
        clear_cache!
A
Aaron Patterson 已提交
592
        exec_query "SET SESSION AUTHORIZATION #{user}"
593 594
      end

595 596
      # REFERENTIAL INTEGRITY ====================================

597
      def supports_disable_referential_integrity? #:nodoc:
598
        true
599 600
      end

601
      def disable_referential_integrity #:nodoc:
602
        if supports_disable_referential_integrity? then
603 604
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
        end
605 606
        yield
      ensure
607
        if supports_disable_referential_integrity? then
608 609
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
        end
610
      end
611 612 613

      # DATABASE STATEMENTS ======================================

614
      def explain(arel, binds = [])
615
        sql = "EXPLAIN #{to_sql(arel, binds)}"
616
        ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
X
Xavier Noria 已提交
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
      end

      class ExplainPrettyPrinter # :nodoc:
        # Pretty prints the result of a EXPLAIN in a way that resembles the output of the
        # PostgreSQL shell:
        #
        #                                     QUERY PLAN
        #   ------------------------------------------------------------------------------
        #    Nested Loop Left Join  (cost=0.00..37.24 rows=8 width=0)
        #      Join Filter: (posts.user_id = users.id)
        #      ->  Index Scan using users_pkey on users  (cost=0.00..8.27 rows=1 width=4)
        #            Index Cond: (id = 1)
        #      ->  Seq Scan on posts  (cost=0.00..28.88 rows=8 width=4)
        #            Filter: (posts.user_id = 1)
        #   (6 rows)
        #
        def pp(result)
          header = result.columns.first
          lines  = result.rows.map(&:first)

          # We add 2 because there's one char of padding at both sides, note
          # the extra hyphens in the example above.
          width = [header, *lines].map(&:length).max + 2

          pp = []

          pp << header.center(width).rstrip
          pp << '-' * width

          pp += lines.map {|line| " #{line}"}

          nrows = result.rows.length
          rows_label = nrows == 1 ? 'row' : 'rows'
          pp << "(#{nrows} #{rows_label})"

          pp.join("\n") + "\n"
        end
      end

656 657 658 659 660 661
      # Executes a SELECT query and returns an array of rows. Each row is an
      # array of field values.
      def select_rows(sql, name = nil)
        select_raw(sql, name).last
      end

662
      # Executes an INSERT query and returns the new record's ID
663
      def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
664 665 666 667 668
        unless pk
          # Extract the table from the insert sql. Yuck.
          table_ref = extract_table_ref_from_insert_sql(sql)
          pk = primary_key(table_ref) if table_ref
        end
669

670
        if pk
671 672 673
          select_value("#{sql} RETURNING #{quote_column_name(pk)}")
        else
          super
674
        end
675
      end
676
      alias :create :insert
677

678 679
      # create a 2D array representing the result set
      def result_as_array(res) #:nodoc:
680
        # check if we have any binary column and if they need escaping
681 682
        ftypes = Array.new(res.nfields) do |i|
          [i, res.ftype(i)]
683 684
        end

685 686 687 688 689 690
        rows = res.values
        return rows unless ftypes.any? { |_, x|
          x == BYTEA_COLUMN_TYPE_OID || x == MONEY_COLUMN_TYPE_OID
        }

        typehash = ftypes.group_by { |_, type| type }
691 692
        binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
        monies   = typehash[MONEY_COLUMN_TYPE_OID] || []
693 694 695

        rows.each do |row|
          # unescape string passed BYTEA field (OID == 17)
696 697
          binaries.each do |index, _|
            row[index] = unescape_bytea(row[index])
698 699 700 701 702 703
          end

          # If this is a money type column and there are any currency symbols,
          # then strip them off. Indeed it would be prettier to do this in
          # PostgreSQLColumn.string_to_decimal but would break form input
          # fields that call value_before_type_cast.
704
          monies.each do |index, _|
705 706 707 708 709 710 711 712 713 714
            data = row[index]
            # Because money output is formatted according to the locale, there are two
            # cases to consider (note the decimal separators):
            #  (1) $12,345,678.12
            #  (2) $12.345.678,12
            case data
            when /^-?\D+[\d,]+\.\d{2}$/  # (1)
              data.gsub!(/[^-\d.]/, '')
            when /^-?\D+[\d.]+,\d{2}$/  # (2)
              data.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
715
            end
716 717 718 719 720 721
          end
        end
      end


      # Queries the database and returns the results in an Array-like object
722
      def query(sql, name = nil) #:nodoc:
723
        log(sql, name) do
724
          result_as_array @connection.async_exec(sql)
725
        end
726 727
      end

728
      # Executes an SQL statement, returning a PGresult object on success
729 730
      # or raising a PGError exception otherwise.
      def execute(sql, name = nil)
731
        log(sql, name) do
732
          @connection.async_exec(sql)
733
        end
734 735
      end

736
      def substitute_at(column, index)
737
        Arel::Nodes::BindParam.new "$#{index + 1}"
738 739
      end

740 741 742 743 744 745 746
      class Result < ActiveRecord::Result
        def initialize(columns, rows, column_types)
          super(columns, rows)
          @column_types = column_types
        end
      end

A
Aaron Patterson 已提交
747
      def exec_query(sql, name = 'SQL', binds = [])
748
        log(sql, name, binds) do
749 750
          result = binds.empty? ? exec_no_cache(sql, binds) :
                                  exec_cache(sql, binds)
751

752 753 754
          types = {}
          result.fields.each_with_index do |fname, i|
            ftype = result.ftype i
755 756
            fmod  = result.fmod i
            types[fname] = OID::TYPE_MAP.fetch(ftype, fmod) { |oid, mod|
757 758 759 760 761
              warn "unknown OID: #{fname}(#{oid}) (#{sql})"
              OID::Identity.new
            }
          end

762
          ret = Result.new(result.fields, result.values, types)
763 764
          result.clear
          return ret
765 766 767
        end
      end

768 769 770 771 772 773 774 775 776
      def exec_delete(sql, name = 'SQL', binds = [])
        log(sql, name, binds) do
          result = binds.empty? ? exec_no_cache(sql, binds) :
                                  exec_cache(sql, binds)
          affected = result.cmd_tuples
          result.clear
          affected
        end
      end
777
      alias :exec_update :exec_delete
778

779 780
      def sql_for_insert(sql, pk, id_value, sequence_name, binds)
        unless pk
781 782 783
          # Extract the table from the insert sql. Yuck.
          table_ref = extract_table_ref_from_insert_sql(sql)
          pk = primary_key(table_ref) if table_ref
784 785 786 787 788 789 790
        end

        sql = "#{sql} RETURNING #{quote_column_name(pk)}" if pk

        [sql, binds]
      end

791
      # Executes an UPDATE query and returns the number of affected tuples.
792
      def update_sql(sql, name = nil)
793
        super.cmd_tuples
794 795
      end

796 797
      # Begins a transaction.
      def begin_db_transaction
798 799 800
        execute "BEGIN"
      end

801 802
      # Commits a transaction.
      def commit_db_transaction
803 804
        execute "COMMIT"
      end
805

806 807
      # Aborts a transaction.
      def rollback_db_transaction
808 809
        execute "ROLLBACK"
      end
810

811 812
      def outside_transaction?
        @connection.transaction_status == PGconn::PQTRANS_IDLE
813
      end
814

J
Jonathan Viney 已提交
815 816 817 818 819 820 821 822
      def create_savepoint
        execute("SAVEPOINT #{current_savepoint_name}")
      end

      def rollback_to_savepoint
        execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
      end

823
      def release_savepoint
J
Jonathan Viney 已提交
824 825
        execute("RELEASE SAVEPOINT #{current_savepoint_name}")
      end
826

827 828
      # SCHEMA STATEMENTS ========================================

829 830 831
      # Drops the database specified on the +name+ attribute
      # and creates it again using the provided +options+.
      def recreate_database(name, options = {}) #:nodoc:
832
        drop_database(name)
833
        create_database(name, options)
834 835
      end

836
      # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
837 838
      # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
      # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
839 840 841 842 843 844 845 846 847 848
      #
      # Example:
      #   create_database config[:database], config
      #   create_database 'foo_development', :encoding => 'unicode'
      def create_database(name, options = {})
        options = options.reverse_merge(:encoding => "utf8")

        option_string = options.symbolize_keys.sum do |key, value|
          case key
          when :owner
849
            " OWNER = \"#{value}\""
850
          when :template
851
            " TEMPLATE = \"#{value}\""
852 853 854
          when :encoding
            " ENCODING = '#{value}'"
          when :tablespace
855
            " TABLESPACE = \"#{value}\""
856 857 858 859 860 861 862
          when :connection_limit
            " CONNECTION LIMIT = #{value}"
          else
            ""
          end
        end

863
        execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
864 865
      end

866
      # Drops a PostgreSQL database.
867 868 869 870
      #
      # Example:
      #   drop_database 'matt_development'
      def drop_database(name) #:nodoc:
871
        execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
872 873
      end

874 875
      # Returns the list of all tables in the schema search path or a specified schema.
      def tables(name = nil)
876
        query(<<-SQL, 'SCHEMA').map { |row| row[0] }
877
          SELECT tablename
878 879 880 881 882
          FROM pg_tables
          WHERE schemaname = ANY (current_schemas(false))
        SQL
      end

883
      # Returns true if table exists.
884 885
      # If the schema is not specified as part of +name+ then it will only find tables within
      # the current schema search path (regardless of permissions to access tables in other schemas)
886
      def table_exists?(name)
887
        schema, table = Utils.extract_schema_and_table(name.to_s)
888
        return false unless table
889

890 891
        binds = [[nil, table]]
        binds << [nil, schema] if schema
892 893

        exec_query(<<-SQL, 'SCHEMA', binds).rows.first[0].to_i > 0
894
            SELECT COUNT(*)
A
Aaron Patterson 已提交
895 896 897 898 899
            FROM pg_class c
            LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
            WHERE c.relkind in ('v','r')
            AND c.relname = $1
            AND n.nspname = #{schema ? '$2' : 'ANY (current_schemas(false))'}
900 901 902
        SQL
      end

903 904 905 906 907 908 909 910
      # Returns true if schema exists.
      def schema_exists?(name)
        exec_query(<<-SQL, 'SCHEMA', [[nil, name]]).rows.first[0].to_i > 0
          SELECT COUNT(*)
          FROM pg_namespace
          WHERE nspname = $1
        SQL
      end
911

912
      # Returns an array of indexes for the given table.
913
      def indexes(table_name, name = nil)
914
         result = query(<<-SQL, name)
915
           SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
916 917 918
           FROM pg_class t
           INNER JOIN pg_index d ON t.oid = d.indrelid
           INNER JOIN pg_class i ON d.indexrelid = i.oid
919 920 921
           WHERE i.relkind = 'i'
             AND d.indisprimary = 'f'
             AND t.relname = '#{table_name}'
922
             AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
923 924 925
          ORDER BY i.relname
        SQL

926

927
        result.map do |row|
928 929 930
          index_name = row[0]
          unique = row[1] == 't'
          indkey = row[2].split(" ")
931 932
          inddef = row[3]
          oid = row[4]
933

934 935
          columns = Hash[query(<<-SQL, "Columns for index #{row[0]} on #{table_name}")]
          SELECT a.attnum, a.attname
936 937 938 939 940
          FROM pg_attribute a
          WHERE a.attrelid = #{oid}
          AND a.attnum IN (#{indkey.join(",")})
          SQL

941
          column_names = columns.values_at(*indkey).compact
942 943 944 945

          # add info on sort order for columns (only desc order is explicitly specified, asc is the default)
          desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
          orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {}
946
          where = inddef.scan(/WHERE (.+)$/).flatten[0]
J
Jon Leighton 已提交
947

948
          column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where)
949
        end.compact
950 951
      end

952
      # Returns the list of all column definitions for a table.
953
      def columns(table_name)
954
        # Limit, precision, and scale are all handled by the superclass.
955 956 957 958 959
        column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
          oid = OID::TYPE_MAP.fetch(oid.to_i, fmod.to_i) {
            OID::Identity.new
          }
          PostgreSQLColumn.new(column_name, default, oid, type, notnull == 'f')
D
Initial  
David Heinemeier Hansson 已提交
960 961 962
        end
      end

963 964 965 966 967
      # Returns the current database name.
      def current_database
        query('select current_database()')[0][0]
      end

968 969 970 971 972
      # Returns the current schema name.
      def current_schema
        query('SELECT current_schema', 'SCHEMA')[0][0]
      end

973 974 975 976 977 978 979 980
      # Returns the current database encoding format.
      def encoding
        query(<<-end_sql)[0][0]
          SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database
          WHERE pg_database.datname LIKE '#{current_database}'
        end_sql
      end

981 982 983 984 985 986 987 988 989 990 991
      # Returns an array of schema names.
      def schema_names
        query(<<-SQL).flatten
          SELECT nspname
            FROM pg_namespace
           WHERE nspname !~ '^pg_.*'
             AND nspname NOT IN ('information_schema')
           ORDER by nspname;
        SQL
      end

992 993 994 995 996 997
      # Sets the schema search path to a string of comma-separated schema names.
      # Names beginning with $ have to be quoted (e.g. $user => '$user').
      # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
      #
      # This should be not be called manually but set in database.yml.
      def schema_search_path=(schema_csv)
998 999
        if schema_csv
          execute "SET search_path TO #{schema_csv}"
1000
          @schema_search_path = schema_csv
1001
        end
D
Initial  
David Heinemeier Hansson 已提交
1002 1003
      end

1004 1005
      # Returns the active schema search path.
      def schema_search_path
X
Xavier Noria 已提交
1006
        @schema_search_path ||= query('SHOW search_path', 'SCHEMA')[0][0]
1007
      end
1008

1009 1010
      # Returns the current client message level.
      def client_min_messages
1011
        query('SHOW client_min_messages', 'SCHEMA')[0][0]
1012 1013 1014 1015
      end

      # Set the client message level.
      def client_min_messages=(level)
1016
        execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
1017 1018 1019 1020
      end

      # Returns the sequence name for a table's primary key or some other specified key.
      def default_sequence_name(table_name, pk = nil) #:nodoc:
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
        serial_sequence(table_name, pk || 'id').split('.').last
      rescue ActiveRecord::StatementInvalid
        "#{table_name}_#{pk || 'id'}_seq"
      end

      def serial_sequence(table, column)
        result = exec_query(<<-eosql, 'SCHEMA', [[nil, table], [nil, column]])
          SELECT pg_get_serial_sequence($1, $2)
        eosql
        result.rows.first.first
1031 1032
      end

1033 1034
      # Resets the sequence of a table's primary key to the maximum value.
      def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
1035 1036
        unless pk and sequence
          default_pk, default_sequence = pk_and_sequence_for(table)
1037

1038 1039 1040
          pk ||= default_pk
          sequence ||= default_sequence
        end
1041

1042 1043 1044 1045 1046
        if @logger && pk && !sequence
          @logger.warn "#{table} has primary key #{pk} with no default sequence"
        end

        if pk && sequence
1047
          quoted_sequence = quote_table_name(sequence)
G
Guillermo Iguaran 已提交
1048

1049 1050 1051
          select_value <<-end_sql, 'Reset sequence'
            SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false)
          end_sql
1052 1053 1054
        end
      end

1055 1056
      # Returns a table's primary key and belonging sequence.
      def pk_and_sequence_for(table) #:nodoc:
1057 1058
        # First try looking for a sequence with a dependency on the
        # given table's primary key.
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
        result = query(<<-end_sql, 'PK and serial sequence')[0]
          SELECT attr.attname, seq.relname
          FROM pg_class      seq,
               pg_attribute  attr,
               pg_depend     dep,
               pg_namespace  name,
               pg_constraint cons
          WHERE seq.oid           = dep.objid
            AND seq.relkind       = 'S'
            AND attr.attrelid     = dep.refobjid
            AND attr.attnum       = dep.refobjsubid
            AND attr.attrelid     = cons.conrelid
            AND attr.attnum       = cons.conkey[1]
            AND cons.contype      = 'p'
            AND dep.refobjid      = '#{quote_table_name(table)}'::regclass
1074
        end_sql
1075

1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
        if result.nil? or result.empty?
          # If that fails, try parsing the primary key's default value.
          # Support the 7.x and 8.0 nextval('foo'::text) as well as
          # the 8.1+ nextval('foo'::regclass).
          result = query(<<-end_sql, 'PK and custom sequence')[0]
            SELECT attr.attname,
              CASE
                WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
                  substr(split_part(def.adsrc, '''', 2),
                         strpos(split_part(def.adsrc, '''', 2), '.')+1)
                ELSE split_part(def.adsrc, '''', 2)
              END
            FROM pg_class       t
            JOIN pg_attribute   attr ON (t.oid = attrelid)
            JOIN pg_attrdef     def  ON (adrelid = attrelid AND adnum = attnum)
            JOIN pg_constraint  cons ON (conrelid = adrelid AND adnum = conkey[1])
            WHERE t.oid = '#{quote_table_name(table)}'::regclass
              AND cons.contype = 'p'
              AND def.adsrc ~* 'nextval'
          end_sql
1096
        end
G
Guillermo Iguaran 已提交
1097

1098
        [result.first, result.last]
1099 1100
      rescue
        nil
1101 1102
      end

1103 1104
      # Returns just a table's primary key
      def primary_key(table)
1105
        row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first
1106
          SELECT DISTINCT(attr.attname)
1107 1108 1109 1110 1111
          FROM pg_attribute attr
          INNER JOIN pg_depend dep ON attr.attrelid = dep.refobjid AND attr.attnum = dep.refobjsubid
          INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
          WHERE cons.contype = 'p'
            AND dep.refobjid = $1::regclass
1112 1113 1114
        end_sql

        row && row.first
1115 1116
      end

1117
      # Renames a table.
1118 1119 1120
      #
      # Example:
      #   rename_table('octopuses', 'octopi')
1121
      def rename_table(name, new_name)
1122
        clear_cache!
1123
        execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
1124
      end
1125

1126 1127
      # Adds a new column to the named table.
      # See TableDefinition#column for details of the options you can use.
S
Scott Barron 已提交
1128
      def add_column(table_name, column_name, type, options = {})
1129
        clear_cache!
1130 1131
        add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
        add_column_options!(add_column_sql, options)
1132

1133
        execute add_column_sql
S
Scott Barron 已提交
1134
      end
D
Initial  
David Heinemeier Hansson 已提交
1135

1136 1137
      # Changes the column of a table.
      def change_column(table_name, column_name, type, options = {})
1138
        clear_cache!
1139 1140
        quoted_table_name = quote_table_name(table_name)

1141
        execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
1142

1143 1144
        change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
        change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
1145
      end
1146

1147 1148
      # Changes the default value of a table column.
      def change_column_default(table_name, column_name, default)
1149
        clear_cache!
1150
        execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
1151
      end
1152

1153
      def change_column_null(table_name, column_name, null, default = nil)
1154
        clear_cache!
1155
        unless null || default.nil?
1156
          execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
1157
        end
1158
        execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
1159 1160
      end

1161 1162
      # Renames a column in a table.
      def rename_column(table_name, column_name, new_column_name)
1163
        clear_cache!
1164
        execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
1165
      end
1166

1167 1168 1169 1170
      def remove_index!(table_name, index_name) #:nodoc:
        execute "DROP INDEX #{quote_table_name(index_name)}"
      end

1171 1172 1173 1174
      def rename_index(table_name, old_name, new_name)
        execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
      end

1175 1176
      def index_name_length
        63
1177
      end
1178

1179 1180
      # Maps logical Rails types to PostgreSQL-specific data types.
      def type_to_sql(type, limit = nil, precision = nil, scale = nil)
1181
        return super unless type.to_s == 'integer'
1182
        return 'integer' unless limit
1183

1184
        case limit
1185 1186 1187
          when 1, 2; 'smallint'
          when 3, 4; 'integer'
          when 5..8; 'bigint'
1188
          else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
1189 1190
        end
      end
1191

1192
      # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
1193 1194 1195
      #
      # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
      # requires that the ORDER BY include the distinct column.
1196
      #
1197
      #   distinct("posts.id", "posts.created_at desc")
1198 1199
      def distinct(columns, orders) #:nodoc:
        return "DISTINCT #{columns}" if orders.empty?
1200

1201 1202
        # Construct a clean list of column names from the ORDER BY clause, removing
        # any ASC/DESC modifiers
K
kennyj 已提交
1203
        order_columns = orders.collect { |s| s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '') }
1204
        order_columns.delete_if { |c| c.blank? }
1205
        order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
1206

1207
        "DISTINCT #{columns}, #{order_columns * ', '}"
1208
      end
1209

1210
      module Utils
1211 1212
        extend self

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
        # Returns an array of <tt>[schema_name, table_name]</tt> extracted from +name+.
        # +schema_name+ is nil if not specified in +name+.
        # +schema_name+ and +table_name+ exclude surrounding quotes (regardless of whether provided in +name+)
        # +name+ supports the range of schema/table references understood by PostgreSQL, for example:
        #
        # * <tt>table_name</tt>
        # * <tt>"table.name"</tt>
        # * <tt>schema_name.table_name</tt>
        # * <tt>schema_name."table.name"</tt>
        # * <tt>"schema.name"."table name"</tt>
1223
        def extract_schema_and_table(name)
1224 1225 1226 1227 1228
          table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse
          [schema, table]
        end
      end

1229
      protected
1230
        # Returns the version of the connected PostgreSQL server.
1231
        def postgresql_version
1232
          @connection.server_version
1233 1234
        end

1235 1236 1237
        def translate_exception(exception, message)
          case exception.message
          when /duplicate key value violates unique constraint/
1238
            RecordNotUnique.new(message, exception)
1239
          when /violates foreign key constraint/
1240
            InvalidForeignKey.new(message, exception)
1241 1242 1243 1244 1245
          else
            super
          end
        end

D
Initial  
David Heinemeier Hansson 已提交
1246
      private
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
      def initialize_type_map
        result = execute('SELECT oid, typname, typelem, typdelim FROM pg_type', 'SCHEMA')
        leaves, nodes = result.partition { |row| row['typelem'] == '0' }

        # populate the leaf nodes
        leaves.find_all { |row| OID.registered_type? row['typname'] }.each do |row|
          OID::TYPE_MAP[row['oid'].to_i] = OID::NAMES[row['typname']]
        end

        # populate composite types
        nodes.find_all { |row| OID::TYPE_MAP.key? row['typelem'].to_i }.each do |row|
          vector = OID::Vector.new row['typdelim'], OID::TYPE_MAP[row['typelem'].to_i]
          OID::TYPE_MAP[row['oid'].to_i] = vector
        end
      end

1263 1264
        FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:

1265 1266
        def exec_no_cache(sql, binds)
          @connection.async_exec(sql)
1267
        end
1268

1269
        def exec_cache(sql, binds)
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
          begin
            stmt_key = prepare_statement sql

            # Clear the queue
            @connection.get_last_result
            @connection.send_query_prepared(stmt_key, binds.map { |col, val|
              type_cast(val, col)
            })
            @connection.block
            @connection.get_last_result
          rescue PGError => e
            # Get the PG code for the failure.  Annoyingly, the code for
            # prepared statements whose return value may have changed is
            # FEATURE_NOT_SUPPORTED.  Check here for more details:
            # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
1285 1286 1287 1288 1289
            begin
              code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
            rescue
              raise e
            end
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
            if FEATURE_NOT_SUPPORTED == code
              @statements.delete sql_key(sql)
              retry
            else
              raise e
            end
          end
        end

        # Returns the statement identifier for the client side cache
        # of statements
        def sql_key(sql)
          "#{schema_search_path}-#{sql}"
        end

        # Prepare the statement if it hasn't been prepared, return
        # the statement key.
        def prepare_statement(sql)
          sql_key = sql_key(sql)
1309
          unless @statements.key? sql_key
1310
            nextkey = @statements.next_key
1311
            @connection.prepare nextkey, sql
1312
            @statements[sql_key] = nextkey
1313
          end
1314
          @statements[sql_key]
1315
        end
1316

P
Pratik Naik 已提交
1317
        # The internal PostgreSQL identifier of the money data type.
1318
        MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
1319 1320
        # The internal PostgreSQL identifier of the BYTEA data type.
        BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
1321 1322 1323 1324

        # Connects to a PostgreSQL server and sets up the adapter depending on the
        # connected server's characteristics.
        def connect
1325
          @connection = PGconn.connect(@connection_parameters)
1326 1327 1328 1329

          # 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.
1330 1331
          PostgreSQLColumn.money_precision = (postgresql_version >= 80300) ? 19 : 10

1332 1333 1334
          configure_connection
        end

1335
        # Configures the encoding, verbosity, schema search path, and time zone of the connection.
1336
        # This is called by #connect and should not be called manually.
1337 1338
        def configure_connection
          if @config[:encoding]
1339
            @connection.set_client_encoding(@config[:encoding])
1340
          end
1341 1342
          self.client_min_messages = @config[:min_messages] if @config[:min_messages]
          self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
1343 1344 1345 1346

          # Use standard-conforming strings if available so we don't have to do the E'...' dance.
          set_standard_conforming_strings

1347
          # If using Active Record's time zone support configure the connection to return
1348
          # TIMESTAMP WITH ZONE types in UTC.
1349
          if ActiveRecord::Base.default_timezone == :utc
1350
            execute("SET time zone 'UTC'", 'SCHEMA')
1351
          elsif @local_tz
1352
            execute("SET time zone '#{@local_tz}'", 'SCHEMA')
1353
          end
1354 1355
        end

1356
        # Returns the current ID of a table's sequence.
1357 1358 1359
        def last_insert_id(sequence_name) #:nodoc:
          r = exec_query("SELECT currval($1)", 'SQL', [[nil, sequence_name]])
          Integer(r.rows.first.first)
D
Initial  
David Heinemeier Hansson 已提交
1360 1361
        end

1362
        # Executes a SELECT query and returns the results, performing any data type
1363
        # conversions that are required to be performed here instead of in PostgreSQLColumn.
1364
        def select(sql, name = nil, binds = [])
1365
          exec_query(sql, name, binds)
1366 1367 1368
        end

        def select_raw(sql, name = nil)
1369
          res = execute(sql, name)
1370
          results = result_as_array(res)
1371
          fields = res.fields
1372
          res.clear
1373
          return fields, results
M
Marcel Molina 已提交
1374 1375
        end

1376
        # Returns the list of a table's column names, data types, and default values.
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
        #
        # The underlying query is roughly:
        #  SELECT column.name, column.type, default.value
        #    FROM column LEFT JOIN default
        #      ON column.table_id = default.table_id
        #     AND column.num = default.column_num
        #   WHERE column.table_id = get_table_id('table_name')
        #     AND column.num > 0
        #     AND NOT column.is_dropped
        #   ORDER BY column.num
        #
        # If the table name is not prefixed with a schema, the database will
        # take the first match from the schema search path.
        #
        # Query implementation notes:
        #  - format_type includes the column size constraint, e.g. varchar(50)
        #  - ::regclass is a function that gives the id for a table name
1394
        def column_definitions(table_name) #:nodoc:
1395
          exec_query(<<-end_sql, 'SCHEMA').rows
1396
            SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull, a.atttypid, a.atttypmod
1397 1398
              FROM pg_attribute a LEFT JOIN pg_attrdef d
                ON a.attrelid = d.adrelid AND a.attnum = d.adnum
1399
             WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
1400 1401 1402
               AND a.attnum > 0 AND NOT a.attisdropped
             ORDER BY a.attnum
          end_sql
D
Initial  
David Heinemeier Hansson 已提交
1403
        end
1404 1405

        def extract_pg_identifier_from_name(name)
1406
          match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
1407 1408

          if match_data
1409 1410
            rest = name[match_data[0].length, name.length]
            rest = rest[1, rest.length] if rest.start_with? "."
J
José Valim 已提交
1411
            [match_data[1], (rest.length > 0 ? rest : nil)]
1412 1413
          end
        end
1414

1415 1416 1417 1418 1419
        def extract_table_ref_from_insert_sql(sql)
          sql[/into\s+([^\(]*).*values\s*\(/i]
          $1.strip if $1
        end

1420 1421 1422
        def table_definition
          TableDefinition.new(self)
        end
D
Initial  
David Heinemeier Hansson 已提交
1423 1424 1425
    end
  end
end