postgresql_adapter.rb 48.4 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 998 999 1000 1001
      # Creates a schema for the given schema name.
      def create_schema schema_name
        execute "CREATE SCHEMA #{schema_name}"
      end

      # Drops the schema for the given schema name.
      def drop_schema schema_name
        execute "DROP SCHEMA #{schema_name} CASCADE"
      end

1002 1003 1004 1005 1006 1007
      # 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)
1008
        if schema_csv
1009
          execute("SET search_path TO #{schema_csv}", 'SCHEMA')
1010
          @schema_search_path = schema_csv
1011
        end
D
Initial  
David Heinemeier Hansson 已提交
1012 1013
      end

1014 1015
      # Returns the active schema search path.
      def schema_search_path
X
Xavier Noria 已提交
1016
        @schema_search_path ||= query('SHOW search_path', 'SCHEMA')[0][0]
1017
      end
1018

1019 1020
      # Returns the current client message level.
      def client_min_messages
1021
        query('SHOW client_min_messages', 'SCHEMA')[0][0]
1022 1023 1024 1025
      end

      # Set the client message level.
      def client_min_messages=(level)
1026
        execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
1027 1028 1029 1030
      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:
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
        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
1041 1042
      end

1043 1044
      # Resets the sequence of a table's primary key to the maximum value.
      def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
1045 1046
        unless pk and sequence
          default_pk, default_sequence = pk_and_sequence_for(table)
1047

1048 1049 1050
          pk ||= default_pk
          sequence ||= default_sequence
        end
1051

1052 1053 1054 1055 1056
        if @logger && pk && !sequence
          @logger.warn "#{table} has primary key #{pk} with no default sequence"
        end

        if pk && sequence
1057
          quoted_sequence = quote_table_name(sequence)
G
Guillermo Iguaran 已提交
1058

1059 1060 1061
          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
1062 1063 1064
        end
      end

1065 1066
      # Returns a table's primary key and belonging sequence.
      def pk_and_sequence_for(table) #:nodoc:
1067 1068
        # First try looking for a sequence with a dependency on the
        # given table's primary key.
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
        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
1084
        end_sql
1085

1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
        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
1106
        end
G
Guillermo Iguaran 已提交
1107

1108
        [result.first, result.last]
1109 1110
      rescue
        nil
1111 1112
      end

1113 1114
      # Returns just a table's primary key
      def primary_key(table)
1115
        row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first
1116
          SELECT DISTINCT(attr.attname)
1117 1118 1119 1120 1121
          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
1122 1123 1124
        end_sql

        row && row.first
1125 1126
      end

1127
      # Renames a table.
1128 1129 1130
      #
      # Example:
      #   rename_table('octopuses', 'octopi')
1131
      def rename_table(name, new_name)
1132
        clear_cache!
1133
        execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
1134
      end
1135

1136 1137
      # Adds a new column to the named table.
      # See TableDefinition#column for details of the options you can use.
S
Scott Barron 已提交
1138
      def add_column(table_name, column_name, type, options = {})
1139
        clear_cache!
1140 1141
        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)
1142

1143
        execute add_column_sql
S
Scott Barron 已提交
1144
      end
D
Initial  
David Heinemeier Hansson 已提交
1145

1146 1147
      # Changes the column of a table.
      def change_column(table_name, column_name, type, options = {})
1148
        clear_cache!
1149 1150
        quoted_table_name = quote_table_name(table_name)

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

1153 1154
        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)
1155
      end
1156

1157 1158
      # Changes the default value of a table column.
      def change_column_default(table_name, column_name, default)
1159
        clear_cache!
1160
        execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
1161
      end
1162

1163
      def change_column_null(table_name, column_name, null, default = nil)
1164
        clear_cache!
1165
        unless null || default.nil?
1166
          execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
1167
        end
1168
        execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
1169 1170
      end

1171 1172
      # Renames a column in a table.
      def rename_column(table_name, column_name, new_column_name)
1173
        clear_cache!
1174
        execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
1175
      end
1176

1177 1178 1179 1180
      def remove_index!(table_name, index_name) #:nodoc:
        execute "DROP INDEX #{quote_table_name(index_name)}"
      end

1181 1182 1183 1184
      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

1185 1186
      def index_name_length
        63
1187
      end
1188

1189 1190
      # Maps logical Rails types to PostgreSQL-specific data types.
      def type_to_sql(type, limit = nil, precision = nil, scale = nil)
1191
        return super unless type.to_s == 'integer'
1192
        return 'integer' unless limit
1193

1194
        case limit
1195 1196 1197
          when 1, 2; 'smallint'
          when 3, 4; 'integer'
          when 5..8; 'bigint'
1198
          else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
1199 1200
        end
      end
1201

1202
      # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
1203 1204 1205
      #
      # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
      # requires that the ORDER BY include the distinct column.
1206
      #
1207
      #   distinct("posts.id", "posts.created_at desc")
1208 1209
      def distinct(columns, orders) #:nodoc:
        return "DISTINCT #{columns}" if orders.empty?
1210

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

1217
        "DISTINCT #{columns}, #{order_columns * ', '}"
1218
      end
1219

1220
      module Utils
1221 1222
        extend self

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
        # 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>
1233
        def extract_schema_and_table(name)
1234 1235 1236 1237 1238
          table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse
          [schema, table]
        end
      end

1239
      protected
1240
        # Returns the version of the connected PostgreSQL server.
1241
        def postgresql_version
1242
          @connection.server_version
1243 1244
        end

1245 1246 1247
        def translate_exception(exception, message)
          case exception.message
          when /duplicate key value violates unique constraint/
1248
            RecordNotUnique.new(message, exception)
1249
          when /violates foreign key constraint/
1250
            InvalidForeignKey.new(message, exception)
1251 1252 1253 1254 1255
          else
            super
          end
        end

D
Initial  
David Heinemeier Hansson 已提交
1256
      private
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
      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

1273 1274
        FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:

1275 1276
        def exec_no_cache(sql, binds)
          @connection.async_exec(sql)
1277
        end
1278

1279
        def exec_cache(sql, binds)
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
          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
1295 1296 1297 1298 1299
            begin
              code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
            rescue
              raise e
            end
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
            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)
1319
          unless @statements.key? sql_key
1320
            nextkey = @statements.next_key
1321
            @connection.prepare nextkey, sql
1322
            @statements[sql_key] = nextkey
1323
          end
1324
          @statements[sql_key]
1325
        end
1326

P
Pratik Naik 已提交
1327
        # The internal PostgreSQL identifier of the money data type.
1328
        MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
1329 1330
        # The internal PostgreSQL identifier of the BYTEA data type.
        BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
1331 1332 1333 1334

        # Connects to a PostgreSQL server and sets up the adapter depending on the
        # connected server's characteristics.
        def connect
1335
          @connection = PGconn.connect(@connection_parameters)
1336 1337 1338 1339

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

1342 1343 1344
          configure_connection
        end

1345
        # Configures the encoding, verbosity, schema search path, and time zone of the connection.
1346
        # This is called by #connect and should not be called manually.
1347 1348
        def configure_connection
          if @config[:encoding]
1349
            @connection.set_client_encoding(@config[:encoding])
1350
          end
1351 1352
          self.client_min_messages = @config[:min_messages] if @config[:min_messages]
          self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
1353 1354 1355 1356

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

1357
          # If using Active Record's time zone support configure the connection to return
1358
          # TIMESTAMP WITH ZONE types in UTC.
1359
          if ActiveRecord::Base.default_timezone == :utc
1360
            execute("SET time zone 'UTC'", 'SCHEMA')
1361
          elsif @local_tz
1362
            execute("SET time zone '#{@local_tz}'", 'SCHEMA')
1363
          end
1364 1365
        end

1366
        # Returns the current ID of a table's sequence.
1367 1368 1369
        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 已提交
1370 1371
        end

1372
        # Executes a SELECT query and returns the results, performing any data type
1373
        # conversions that are required to be performed here instead of in PostgreSQLColumn.
1374
        def select(sql, name = nil, binds = [])
1375
          exec_query(sql, name, binds)
1376 1377 1378
        end

        def select_raw(sql, name = nil)
1379
          res = execute(sql, name)
1380
          results = result_as_array(res)
1381
          fields = res.fields
1382
          res.clear
1383
          return fields, results
M
Marcel Molina 已提交
1384 1385
        end

1386
        # Returns the list of a table's column names, data types, and default values.
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
        #
        # 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
1404
        def column_definitions(table_name) #:nodoc:
1405
          exec_query(<<-end_sql, 'SCHEMA').rows
1406
            SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull, a.atttypid, a.atttypmod
1407 1408
              FROM pg_attribute a LEFT JOIN pg_attrdef d
                ON a.attrelid = d.adrelid AND a.attnum = d.adnum
1409
             WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
1410 1411 1412
               AND a.attnum > 0 AND NOT a.attisdropped
             ORDER BY a.attnum
          end_sql
D
Initial  
David Heinemeier Hansson 已提交
1413
        end
1414 1415

        def extract_pg_identifier_from_name(name)
1416
          match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
1417 1418

          if match_data
1419 1420
            rest = name[match_data[0].length, name.length]
            rest = rest[1, rest.length] if rest.start_with? "."
J
José Valim 已提交
1421
            [match_data[1], (rest.length > 0 ? rest : nil)]
1422 1423
          end
        end
1424

1425 1426 1427 1428 1429
        def extract_table_ref_from_insert_sql(sql)
          sql[/into\s+([^\(]*).*values\s*\(/i]
          $1.strip if $1
        end

1430 1431 1432
        def table_definition
          TableDefinition.new(self)
        end
D
Initial  
David Heinemeier Hansson 已提交
1433 1434 1435
    end
  end
end