postgresql_adapter.rb 50.2 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
       :reaping_frequency, :insert_returning].each do |key|
21 22
        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
            value.nil?         ? 'NULL'
          : value == ""        ? '""'
R
Ryan Fitzgerald 已提交
92
          :                      '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
93
        end
94 95 96
      end
      # :startdoc:

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

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

        @oid_type.type_cast value
      end

165 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
      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
200 201 202 203 204 205 206
        # Network address types
        when 'inet'
          :inet
        when 'cidr'
          :cidr
        when 'macaddr'
          :macaddr
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 242 243 244
        # 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
        # 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
245
        end
246
      end
D
Initial  
David Heinemeier Hansson 已提交
247 248
    end

249
    # The PostgreSQL adapter works with the native C (https://bitbucket.org/ged/ruby-pg) driver.
250 251 252
    #
    # Options:
    #
253 254
    # * <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 已提交
255
    # * <tt>:port</tt> - Defaults to 5432.
256 257 258
    # * <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.
259
    # * <tt>:schema_search_path</tt> - An optional schema search path for the connection given
260
    #   as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
261
    # * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
262
    #   <encoding></tt> call on the connection.
263
    # * <tt>:min_messages</tt> - An optional client min messages that is used in a
264
    #   <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
265 266
    # * <tt>:insert_returning</tt> - An optional boolean to control the use or <tt>RETURNING</tt> for <tt>INSERT<tt> statements
    #   defaults to true.
267 268 269 270 271 272 273
    #
    # 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 .
274
    class PostgreSQLAdapter < AbstractAdapter
275 276 277 278 279
      class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
        def xml(*args)
          options = args.extract_options!
          column(args[0], 'xml', options)
        end
280 281 282 283 284

        def tsvector(*args)
          options = args.extract_options!
          column(args[0], 'tsvector', options)
        end
285 286 287 288

        def hstore(name, options = {})
          column(name, 'hstore', options)
        end
289 290 291 292 293 294 295 296 297 298 299 300

        def inet(name, options = {})
          column(name, 'inet', options)
        end

        def cidr(name, options = {})
          column(name, 'cidr', options)
        end

        def macaddr(name, options = {})
          column(name, 'macaddr', options)
        end
301 302
      end

303
      ADAPTER_NAME = 'PostgreSQL'
304 305

      NATIVE_DATABASE_TYPES = {
306
        :primary_key => "serial primary key",
307 308 309 310 311 312 313 314 315 316
        :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" },
317
        :boolean     => { :name => "boolean" },
318
        :xml         => { :name => "xml" },
319
        :tsvector    => { :name => "tsvector" },
320 321 322 323
        :hstore      => { :name => "hstore" },
        :inet        => { :name => "inet" },
        :cidr        => { :name => "cidr" },
        :macaddr     => { :name => "macaddr" }
324 325
      }

326
      # Returns 'PostgreSQL' as adapter name for identification purposes.
327
      def adapter_name
328
        ADAPTER_NAME
329 330
      end

331 332
      # Returns +true+, since this connection adapter supports prepared statement
      # caching.
333 334 335 336
      def supports_statement_cache?
        true
      end

337 338 339 340
      def supports_index_sort_order?
        true
      end

341 342 343 344
      def supports_partial_index?
        true
      end

345 346 347 348
      class StatementPool < ConnectionAdapters::StatementPool
        def initialize(connection, max)
          super
          @counter = 0
349
          @cache   = Hash.new { |h,pid| h[pid] = {} }
350 351
        end

352 353 354 355
        def each(&block); cache.each(&block); end
        def key?(key);    cache.key?(key); end
        def [](key);      cache[key]; end
        def length;       cache.length; end
356 357 358 359 360 361

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

        def []=(sql, key)
362 363
          while @max <= cache.size
            dealloc(cache.shift.last)
364 365
          end
          @counter += 1
366
          cache[sql] = key
367 368 369
        end

        def clear
370
          cache.each_value do |stmt_key|
371 372
            dealloc stmt_key
          end
373
          cache.clear
374 375
        end

376 377 378 379 380
        def delete(sql_key)
          dealloc cache[sql_key]
          cache.delete sql_key
        end

381
        private
382
        def cache
A
Aaron Patterson 已提交
383
          @cache[Process.pid]
384 385
        end

386
        def dealloc(key)
387 388 389 390 391 392 393
          @connection.query "DEALLOCATE #{key}" if connection_active?
        end

        def connection_active?
          @connection.status == PGconn::CONNECTION_OK
        rescue PGError
          false
394 395 396
        end
      end

397 398 399 400
      class BindSubstitution < Arel::Visitors::PostgreSQL # :nodoc:
        include Arel::Visitors::BindVisitor
      end

401 402
      # Initializes and connects a PostgreSQL adapter.
      def initialize(connection, logger, connection_parameters, config)
403
        super(connection, logger)
404 405 406 407 408 409 410 411 412

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

        connection_parameters.delete :prepared_statements

413
        @connection_parameters, @config = connection_parameters, config
414

415 416
        # @local_tz is initialized as nil to avoid warnings when connect tries to use it
        @local_tz = nil
417 418
        @table_alias_length = nil

419
        connect
420 421
        @statements = StatementPool.new @connection,
                                        config.fetch(:statement_limit) { 1000 }
422 423 424 425 426

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

427
        initialize_type_map
428
        @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
429
        @use_insert_returning = @config.key?(:insert_returning) ? @config[:insert_returning] : true
430 431
      end

X
Xavier Noria 已提交
432
      # Clears the prepared statements cache.
433 434 435 436
      def clear_cache!
        @statements.clear
      end

437 438
      # Is this connection alive and ready for queries?
      def active?
439 440
        @connection.status == PGconn::CONNECTION_OK
      rescue PGError
441
        false
442 443 444 445
      end

      # Close then reopen the connection.
      def reconnect!
446 447 448
        clear_cache!
        @connection.reset
        configure_connection
449
      end
450

451 452 453 454 455
      def reset!
        clear_cache!
        super
      end

456 457
      # Disconnects from the database if already connected. Otherwise, this
      # method does nothing.
458
      def disconnect!
459
        clear_cache!
460 461
        @connection.close rescue nil
      end
462

463
      def native_database_types #:nodoc:
464
        NATIVE_DATABASE_TYPES
465
      end
466

467
      # Returns true, since this connection adapter supports migrations.
468 469
      def supports_migrations?
        true
470 471
      end

472
      # Does PostgreSQL support finding primary key on non-Active Record tables?
473 474 475 476
      def supports_primary_key? #:nodoc:
        true
      end

477 478 479
      # Enable standard-conforming strings if available.
      def set_standard_conforming_strings
        old, self.client_min_messages = client_min_messages, 'panic'
480
        execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
481 482
      ensure
        self.client_min_messages = old
483 484
      end

485
      def supports_insert_with_returning?
486
        true
487 488
      end

489 490 491
      def supports_ddl_transactions?
        true
      end
492

493
      # Returns true, since this connection adapter supports savepoints.
494 495 496
      def supports_savepoints?
        true
      end
497

498 499 500 501 502
      # Returns true.
      def supports_explain?
        true
      end

503
      # Returns the configured supported identifier length supported by PostgreSQL
504
      def table_alias_length
505
        @table_alias_length ||= query('SHOW max_identifier_length')[0][0].to_i
506
      end
507

508 509
      # QUOTING ==================================================

510
      # Escapes binary strings for bytea input to the database.
511
      def escape_bytea(value)
512
        PGconn.escape_bytea(value) if value
513 514 515 516 517
      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.
518
      def unescape_bytea(value)
519
        PGconn.unescape_bytea(value) if value
520 521
      end

522 523
      # Quotes PostgreSQL-specific data types for SQL input.
      def quote(value, column = nil) #:nodoc:
524 525
        return super unless column

A
Aaron Patterson 已提交
526
        case value
527 528 529 530 531
        when Hash
          case column.sql_type
          when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column)
          else super
          end
532
        when Float
533 534 535 536 537 538 539
          if value.infinite? && column.type == :datetime
            "'#{value.to_s.downcase}'"
          elsif value.infinite? || value.nan?
            "'#{value.to_s}'"
          else
            super
          end
A
Aaron Patterson 已提交
540 541
        when Numeric
          return super unless column.sql_type == 'money'
542
          # Not truly string input, so doesn't require (or allow) escape string syntax.
543
          "'#{value}'"
A
Aaron Patterson 已提交
544 545 546 547 548 549 550 551 552 553 554
        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
555
          end
556 557 558 559 560
        else
          super
        end
      end

561 562 563 564 565 566
      def type_cast(value, column)
        return super unless column

        case value
        when String
          return super unless 'bytea' == column.sql_type
567
          { :value => value, :format => 1 }
568 569 570
        when Hash
          return super unless 'hstore' == column.sql_type
          PostgreSQLColumn.hstore_to_string(value)
571 572 573 574 575
        else
          super
        end
      end

576 577 578
      # Quotes strings for use in SQL input.
      def quote_string(s) #:nodoc:
        @connection.escape(s)
579 580
      end

581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
      # 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

600 601
      # Quotes column names for use in SQL queries.
      def quote_column_name(name) #:nodoc:
602
        PGconn.quote_ident(name.to_s)
603 604
      end

605 606 607
      # 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:
608 609 610 611 612
        if value.acts_like?(:time) && value.respond_to?(:usec)
          "#{super}.#{sprintf("%06d", value.usec)}"
        else
          super
        end
613 614
      end

615 616
      # Set the authorized user for this session
      def session_auth=(user)
617
        clear_cache!
A
Aaron Patterson 已提交
618
        exec_query "SET SESSION AUTHORIZATION #{user}"
619 620
      end

621 622
      # REFERENTIAL INTEGRITY ====================================

623
      def supports_disable_referential_integrity? #:nodoc:
624
        true
625 626
      end

627
      def disable_referential_integrity #:nodoc:
628
        if supports_disable_referential_integrity? then
629 630
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
        end
631 632
        yield
      ensure
633
        if supports_disable_referential_integrity? then
634 635
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
        end
636
      end
637 638 639

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

640
      def explain(arel, binds = [])
641
        sql = "EXPLAIN #{to_sql(arel, binds)}"
642
        ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
X
Xavier Noria 已提交
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
      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

682 683 684 685 686 687
      # 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

688
      # Executes an INSERT query and returns the new record's ID
689
      def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
690 691 692 693 694
        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
695

696
        if pk && use_insert_returning?
697
          select_value("#{sql} RETURNING #{quote_column_name(pk)}")
698 699 700
        elsif pk
          super
          last_insert_id_value(sequence_name || default_sequence_name(table_ref, pk))
701 702
        else
          super
703
        end
704
      end
705
      alias :create :insert
706

707 708
      # create a 2D array representing the result set
      def result_as_array(res) #:nodoc:
709
        # check if we have any binary column and if they need escaping
710 711
        ftypes = Array.new(res.nfields) do |i|
          [i, res.ftype(i)]
712 713
        end

714 715 716 717 718 719
        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 }
720 721
        binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
        monies   = typehash[MONEY_COLUMN_TYPE_OID] || []
722 723 724

        rows.each do |row|
          # unescape string passed BYTEA field (OID == 17)
725 726
          binaries.each do |index, _|
            row[index] = unescape_bytea(row[index])
727 728 729 730 731 732
          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.
733
          monies.each do |index, _|
734 735 736 737 738 739 740 741 742 743
            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!(/,/, '.')
744
            end
745 746 747 748 749 750
          end
        end
      end


      # Queries the database and returns the results in an Array-like object
751
      def query(sql, name = nil) #:nodoc:
752
        log(sql, name) do
753
          result_as_array @connection.async_exec(sql)
754
        end
755 756
      end

757
      # Executes an SQL statement, returning a PGresult object on success
758 759
      # or raising a PGError exception otherwise.
      def execute(sql, name = nil)
760
        log(sql, name) do
761
          @connection.async_exec(sql)
762
        end
763 764
      end

765
      def substitute_at(column, index)
766
        Arel::Nodes::BindParam.new "$#{index + 1}"
767 768
      end

769 770 771 772 773 774 775
      class Result < ActiveRecord::Result
        def initialize(columns, rows, column_types)
          super(columns, rows)
          @column_types = column_types
        end
      end

A
Aaron Patterson 已提交
776
      def exec_query(sql, name = 'SQL', binds = [])
777
        log(sql, name, binds) do
778 779
          result = binds.empty? ? exec_no_cache(sql, binds) :
                                  exec_cache(sql, binds)
780

781 782 783
          types = {}
          result.fields.each_with_index do |fname, i|
            ftype = result.ftype i
784 785
            fmod  = result.fmod i
            types[fname] = OID::TYPE_MAP.fetch(ftype, fmod) { |oid, mod|
786 787 788 789 790
              warn "unknown OID: #{fname}(#{oid}) (#{sql})"
              OID::Identity.new
            }
          end

791
          ret = Result.new(result.fields, result.values, types)
792 793
          result.clear
          return ret
794 795 796
        end
      end

797 798 799 800 801 802 803 804 805
      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
806
      alias :exec_update :exec_delete
807

808 809
      def sql_for_insert(sql, pk, id_value, sequence_name, binds)
        unless pk
810 811 812
          # 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
813 814
        end

815
        if pk && use_insert_returning?
816 817
          sql = "#{sql} RETURNING #{quote_column_name(pk)}"
        end
818 819 820 821

        [sql, binds]
      end

822 823
      def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
        val = exec_query(sql, name, binds)
824
        if !use_insert_returning? && pk
D
Doug Cole 已提交
825
          unless sequence_name
826 827 828 829
            table_ref = extract_table_ref_from_insert_sql(sql)
            sequence_name = default_sequence_name(table_ref, pk)
            return val unless sequence_name
          end
D
Doug Cole 已提交
830
          last_insert_id_result(sequence_name)
831 832 833 834 835
        else
          val
        end
      end

836
      # Executes an UPDATE query and returns the number of affected tuples.
837
      def update_sql(sql, name = nil)
838
        super.cmd_tuples
839 840
      end

841 842
      # Begins a transaction.
      def begin_db_transaction
843 844 845
        execute "BEGIN"
      end

846 847
      # Commits a transaction.
      def commit_db_transaction
848 849
        execute "COMMIT"
      end
850

851 852
      # Aborts a transaction.
      def rollback_db_transaction
853 854
        execute "ROLLBACK"
      end
855

856 857
      def outside_transaction?
        @connection.transaction_status == PGconn::PQTRANS_IDLE
858
      end
859

J
Jonathan Viney 已提交
860 861 862 863 864 865 866 867
      def create_savepoint
        execute("SAVEPOINT #{current_savepoint_name}")
      end

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

868
      def release_savepoint
J
Jonathan Viney 已提交
869 870
        execute("RELEASE SAVEPOINT #{current_savepoint_name}")
      end
871

872 873
      # SCHEMA STATEMENTS ========================================

874 875 876
      # Drops the database specified on the +name+ attribute
      # and creates it again using the provided +options+.
      def recreate_database(name, options = {}) #:nodoc:
877
        drop_database(name)
878
        create_database(name, options)
879 880
      end

881
      # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
882 883
      # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
      # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
884 885 886 887 888 889 890 891 892 893
      #
      # 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
894
            " OWNER = \"#{value}\""
895
          when :template
896
            " TEMPLATE = \"#{value}\""
897 898 899
          when :encoding
            " ENCODING = '#{value}'"
          when :tablespace
900
            " TABLESPACE = \"#{value}\""
901 902 903 904 905 906 907
          when :connection_limit
            " CONNECTION LIMIT = #{value}"
          else
            ""
          end
        end

908
        execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
909 910
      end

911
      # Drops a PostgreSQL database.
912 913 914 915
      #
      # Example:
      #   drop_database 'matt_development'
      def drop_database(name) #:nodoc:
916
        execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
917 918
      end

919 920
      # Returns the list of all tables in the schema search path or a specified schema.
      def tables(name = nil)
921
        query(<<-SQL, 'SCHEMA').map { |row| row[0] }
922
          SELECT tablename
923 924 925 926 927
          FROM pg_tables
          WHERE schemaname = ANY (current_schemas(false))
        SQL
      end

928
      # Returns true if table exists.
929 930
      # 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)
931
      def table_exists?(name)
932
        schema, table = Utils.extract_schema_and_table(name.to_s)
933
        return false unless table
934

935 936
        binds = [[nil, table]]
        binds << [nil, schema] if schema
937 938

        exec_query(<<-SQL, 'SCHEMA', binds).rows.first[0].to_i > 0
939
            SELECT COUNT(*)
A
Aaron Patterson 已提交
940 941 942 943 944
            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))'}
945 946 947
        SQL
      end

948 949 950 951 952 953 954 955
      # 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
956

957
      # Returns an array of indexes for the given table.
958
      def indexes(table_name, name = nil)
959
         result = query(<<-SQL, name)
960
           SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
961 962 963
           FROM pg_class t
           INNER JOIN pg_index d ON t.oid = d.indrelid
           INNER JOIN pg_class i ON d.indexrelid = i.oid
964 965 966
           WHERE i.relkind = 'i'
             AND d.indisprimary = 'f'
             AND t.relname = '#{table_name}'
967
             AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
968 969 970
          ORDER BY i.relname
        SQL

971

972
        result.map do |row|
973 974 975
          index_name = row[0]
          unique = row[1] == 't'
          indkey = row[2].split(" ")
976 977
          inddef = row[3]
          oid = row[4]
978

979 980
          columns = Hash[query(<<-SQL, "Columns for index #{row[0]} on #{table_name}")]
          SELECT a.attnum, a.attname
981 982 983 984 985
          FROM pg_attribute a
          WHERE a.attrelid = #{oid}
          AND a.attnum IN (#{indkey.join(",")})
          SQL

986
          column_names = columns.values_at(*indkey).compact
987 988 989 990

          # 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]}] : {}
991
          where = inddef.scan(/WHERE (.+)$/).flatten[0]
J
Jon Leighton 已提交
992

993
          column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where)
994
        end.compact
995 996
      end

997
      # Returns the list of all column definitions for a table.
998
      def columns(table_name)
999
        # Limit, precision, and scale are all handled by the superclass.
1000 1001 1002 1003 1004
        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 已提交
1005 1006 1007
        end
      end

1008 1009 1010 1011 1012
      # Returns the current database name.
      def current_database
        query('select current_database()')[0][0]
      end

1013 1014 1015 1016 1017
      # Returns the current schema name.
      def current_schema
        query('SELECT current_schema', 'SCHEMA')[0][0]
      end

1018 1019 1020 1021 1022 1023 1024 1025
      # 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

1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
      # 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

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
      # 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

1047 1048 1049 1050 1051 1052
      # 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)
1053
        if schema_csv
1054
          execute("SET search_path TO #{schema_csv}", 'SCHEMA')
1055
          @schema_search_path = schema_csv
1056
        end
D
Initial  
David Heinemeier Hansson 已提交
1057 1058
      end

1059 1060
      # Returns the active schema search path.
      def schema_search_path
X
Xavier Noria 已提交
1061
        @schema_search_path ||= query('SHOW search_path', 'SCHEMA')[0][0]
1062
      end
1063

1064 1065
      # Returns the current client message level.
      def client_min_messages
1066
        query('SHOW client_min_messages', 'SCHEMA')[0][0]
1067 1068 1069 1070
      end

      # Set the client message level.
      def client_min_messages=(level)
1071
        execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
1072 1073 1074 1075
      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:
1076 1077 1078
        result = serial_sequence(table_name, pk || 'id')
        return nil unless result
        result.split('.').last
1079 1080 1081 1082 1083 1084 1085 1086 1087
      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
1088 1089
      end

1090 1091
      # Resets the sequence of a table's primary key to the maximum value.
      def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
1092 1093
        unless pk and sequence
          default_pk, default_sequence = pk_and_sequence_for(table)
1094

1095 1096 1097
          pk ||= default_pk
          sequence ||= default_sequence
        end
1098

1099 1100 1101 1102 1103
        if @logger && pk && !sequence
          @logger.warn "#{table} has primary key #{pk} with no default sequence"
        end

        if pk && sequence
1104
          quoted_sequence = quote_table_name(sequence)
G
Guillermo Iguaran 已提交
1105

1106 1107 1108
          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
1109 1110 1111
        end
      end

1112 1113
      # Returns a table's primary key and belonging sequence.
      def pk_and_sequence_for(table) #:nodoc:
1114 1115
        # First try looking for a sequence with a dependency on the
        # given table's primary key.
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
        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
1131
        end_sql
1132

1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
        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
1153
        end
G
Guillermo Iguaran 已提交
1154

1155
        [result.first, result.last]
1156 1157
      rescue
        nil
1158 1159
      end

1160 1161
      # Returns just a table's primary key
      def primary_key(table)
1162
        row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first
1163
          SELECT DISTINCT(attr.attname)
1164 1165 1166 1167 1168
          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
1169 1170 1171
        end_sql

        row && row.first
1172 1173
      end

1174
      # Renames a table.
1175 1176 1177
      #
      # Example:
      #   rename_table('octopuses', 'octopi')
1178
      def rename_table(name, new_name)
1179
        clear_cache!
1180
        execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
1181
      end
1182

1183 1184
      # Adds a new column to the named table.
      # See TableDefinition#column for details of the options you can use.
S
Scott Barron 已提交
1185
      def add_column(table_name, column_name, type, options = {})
1186
        clear_cache!
1187 1188
        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)
1189

1190
        execute add_column_sql
S
Scott Barron 已提交
1191
      end
D
Initial  
David Heinemeier Hansson 已提交
1192

1193 1194
      # Changes the column of a table.
      def change_column(table_name, column_name, type, options = {})
1195
        clear_cache!
1196 1197
        quoted_table_name = quote_table_name(table_name)

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

1200 1201
        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)
1202
      end
1203

1204 1205
      # Changes the default value of a table column.
      def change_column_default(table_name, column_name, default)
1206
        clear_cache!
1207
        execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
1208
      end
1209

1210
      def change_column_null(table_name, column_name, null, default = nil)
1211
        clear_cache!
1212
        unless null || default.nil?
1213
          execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
1214
        end
1215
        execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
1216 1217
      end

1218 1219
      # Renames a column in a table.
      def rename_column(table_name, column_name, new_column_name)
1220
        clear_cache!
1221
        execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
1222
      end
1223

1224 1225 1226 1227
      def remove_index!(table_name, index_name) #:nodoc:
        execute "DROP INDEX #{quote_table_name(index_name)}"
      end

1228 1229 1230 1231
      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

1232 1233
      def index_name_length
        63
1234
      end
1235

1236 1237
      # Maps logical Rails types to PostgreSQL-specific data types.
      def type_to_sql(type, limit = nil, precision = nil, scale = nil)
1238
        return super unless type.to_s == 'integer'
1239
        return 'integer' unless limit
1240

1241
        case limit
1242 1243 1244
          when 1, 2; 'smallint'
          when 3, 4; 'integer'
          when 5..8; 'bigint'
1245
          else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
1246 1247
        end
      end
1248

1249
      # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
1250 1251 1252
      #
      # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
      # requires that the ORDER BY include the distinct column.
1253
      #
1254
      #   distinct("posts.id", "posts.created_at desc")
1255 1256
      def distinct(columns, orders) #:nodoc:
        return "DISTINCT #{columns}" if orders.empty?
1257

1258 1259
        # Construct a clean list of column names from the ORDER BY clause, removing
        # any ASC/DESC modifiers
1260 1261 1262 1263
        order_columns = orders.collect do |s|
          s = s.to_sql unless s.is_a?(String)
          s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '')
        end
1264
        order_columns.delete_if { |c| c.blank? }
1265
        order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
1266

1267
        "DISTINCT #{columns}, #{order_columns * ', '}"
1268
      end
1269

1270
      module Utils
1271 1272
        extend self

1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
        # 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>
1283
        def extract_schema_and_table(name)
1284 1285 1286 1287 1288
          table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse
          [schema, table]
        end
      end

1289 1290
      def use_insert_returning?
        @use_insert_returning
1291 1292
      end

1293
      protected
1294
        # Returns the version of the connected PostgreSQL server.
1295
        def postgresql_version
1296
          @connection.server_version
1297 1298
        end

1299 1300 1301
        def translate_exception(exception, message)
          case exception.message
          when /duplicate key value violates unique constraint/
1302
            RecordNotUnique.new(message, exception)
1303
          when /violates foreign key constraint/
1304
            InvalidForeignKey.new(message, exception)
1305 1306 1307 1308 1309
          else
            super
          end
        end

D
Initial  
David Heinemeier Hansson 已提交
1310
      private
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
      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

1327 1328
        FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:

1329 1330
        def exec_no_cache(sql, binds)
          @connection.async_exec(sql)
1331
        end
1332

1333
        def exec_cache(sql, binds)
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
          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
1349 1350 1351 1352 1353
            begin
              code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
            rescue
              raise e
            end
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
            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)
1373
          unless @statements.key? sql_key
1374
            nextkey = @statements.next_key
1375
            @connection.prepare nextkey, sql
1376
            @statements[sql_key] = nextkey
1377
          end
1378
          @statements[sql_key]
1379
        end
1380

P
Pratik Naik 已提交
1381
        # The internal PostgreSQL identifier of the money data type.
1382
        MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
1383 1384
        # The internal PostgreSQL identifier of the BYTEA data type.
        BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
1385 1386 1387 1388

        # Connects to a PostgreSQL server and sets up the adapter depending on the
        # connected server's characteristics.
        def connect
1389
          @connection = PGconn.connect(@connection_parameters)
1390 1391 1392 1393

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

1396 1397 1398
          configure_connection
        end

1399
        # Configures the encoding, verbosity, schema search path, and time zone of the connection.
1400
        # This is called by #connect and should not be called manually.
1401 1402
        def configure_connection
          if @config[:encoding]
1403
            @connection.set_client_encoding(@config[:encoding])
1404
          end
1405 1406
          self.client_min_messages = @config[:min_messages] if @config[:min_messages]
          self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
1407 1408 1409 1410

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

1411
          # If using Active Record's time zone support configure the connection to return
1412
          # TIMESTAMP WITH ZONE types in UTC.
1413
          if ActiveRecord::Base.default_timezone == :utc
1414
            execute("SET time zone 'UTC'", 'SCHEMA')
1415
          elsif @local_tz
1416
            execute("SET time zone '#{@local_tz}'", 'SCHEMA')
1417
          end
1418 1419
        end

1420
        # Returns the current ID of a table's sequence.
1421
        def last_insert_id(sequence_name) #:nodoc:
1422 1423 1424
          Integer(last_insert_id_value(sequence_name))
        end

D
Doug Cole 已提交
1425 1426 1427 1428 1429 1430
        def last_insert_id_value(sequence_name)
          last_insert_id_result(sequence_name).rows.first.first
        end

        def last_insert_id_result(sequence_name) #:nodoc:
          exec_query("SELECT currval($1)", 'SQL', [[nil, sequence_name]])
D
Initial  
David Heinemeier Hansson 已提交
1431 1432
        end

1433
        # Executes a SELECT query and returns the results, performing any data type
1434
        # conversions that are required to be performed here instead of in PostgreSQLColumn.
1435
        def select(sql, name = nil, binds = [])
1436
          exec_query(sql, name, binds)
1437 1438 1439
        end

        def select_raw(sql, name = nil)
1440
          res = execute(sql, name)
1441
          results = result_as_array(res)
1442
          fields = res.fields
1443
          res.clear
1444
          return fields, results
M
Marcel Molina 已提交
1445 1446
        end

1447
        # Returns the list of a table's column names, data types, and default values.
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
        #
        # 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
1465
        def column_definitions(table_name) #:nodoc:
1466
          exec_query(<<-end_sql, 'SCHEMA').rows
1467
            SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull, a.atttypid, a.atttypmod
1468 1469
              FROM pg_attribute a LEFT JOIN pg_attrdef d
                ON a.attrelid = d.adrelid AND a.attnum = d.adnum
1470
             WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
1471 1472 1473
               AND a.attnum > 0 AND NOT a.attisdropped
             ORDER BY a.attnum
          end_sql
D
Initial  
David Heinemeier Hansson 已提交
1474
        end
1475 1476

        def extract_pg_identifier_from_name(name)
1477
          match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
1478 1479

          if match_data
1480 1481
            rest = name[match_data[0].length, name.length]
            rest = rest[1, rest.length] if rest.start_with? "."
J
José Valim 已提交
1482
            [match_data[1], (rest.length > 0 ? rest : nil)]
1483 1484
          end
        end
1485

1486 1487 1488 1489 1490
        def extract_table_ref_from_insert_sql(sql)
          sql[/into\s+([^\(]*).*values\s*\(/i]
          $1.strip if $1
        end

1491 1492 1493
        def table_definition
          TableDefinition.new(self)
        end
D
Initial  
David Heinemeier Hansson 已提交
1494 1495 1496
    end
  end
end