postgresql_adapter.rb 39.5 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 5 6

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

module ActiveRecord
  class Base
    # Establishes a connection to the database that's used by all Active Record objects
    def self.postgresql_connection(config) # :nodoc:
13
      config = config.symbolize_keys
D
Initial  
David Heinemeier Hansson 已提交
14
      host     = config[:host]
15
      port     = config[:port] || 5432
16 17
      username = config[:username].to_s if config[:username]
      password = config[:password].to_s if config[:password]
D
Initial  
David Heinemeier Hansson 已提交
18

19
      if config.key?(:database)
D
Initial  
David Heinemeier Hansson 已提交
20 21 22 23 24
        database = config[:database]
      else
        raise ArgumentError, "No database specified. Missing argument: database."
      end

25
      # The postgres drivers don't allow the creation of an unconnected PGconn object,
26 27 28 29
      # so just pass a nil connection object for the time being.
      ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, [host, port, nil, nil, database, username, password], config)
    end
  end
30

31 32 33 34 35 36 37
  module ConnectionAdapters
    # PostgreSQL-specific extensions to column definitions in a table.
    class PostgreSQLColumn < Column #:nodoc:
      # Instantiates a new PostgreSQL column definition in a table.
      def initialize(name, default, sql_type = nil, null = true)
        super(name, self.class.extract_value_from_default(default), sql_type, null)
      end
38

39 40 41
      # :stopdoc:
      class << self
        attr_accessor :money_precision
42 43 44 45 46 47 48 49 50 51
        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
52 53 54
      end
      # :startdoc:

55
      private
56
        def extract_limit(sql_type)
57 58 59 60 61
          case sql_type
          when /^bigint/i;    8
          when /^smallint/i;  2
          else super
          end
62 63
        end

64 65 66 67 68
        # 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
69

70 71
        # Extracts the precision from PostgreSQL-specific data types.
        def extract_precision(sql_type)
72 73 74 75 76
          if sql_type == 'money'
            self.class.money_precision
          else
            super
          end
77
        end
78

79 80 81 82 83 84 85
        # 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
86
            when 'money'
87 88 89 90 91
              :decimal
            # Character types
            when /^(?:character varying|bpchar)(?:\(\d+\))?$/
              :string
            # Binary data types
92
            when 'bytea'
93 94 95 96
              :binary
            # Date/time types
            when /^timestamp with(?:out)? time zone$/
              :datetime
97
            when 'interval'
98 99 100 101 102 103 104 105 106 107 108
              :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
109
            when 'xml'
110
              :xml
111 112 113
            # tsvector type
            when 'tsvector'
              :tsvector
114 115
            # Arrays
            when /^\D+\[\]$/
116
              :string
117
            # Object identifier types
118
            when 'oid'
119
              :integer
120
            # UUID type
121
            when 'uuid'
122 123 124 125
              :string
            # Small and big integer types
            when /^(?:small|big)int$/
              :integer
126 127 128 129 130
            # Pass through all types that are not specific to PostgreSQL.
            else
              super
          end
        end
131

132 133 134
        # Extracts the value from a PostgreSQL column default definition.
        def self.extract_value_from_default(default)
          case default
135 136 137 138 139 140 141 142
            # 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.
            when NilClass
              nil
143
            # Numeric types
144 145
            when /\A\(?(-?\d+(\.\d*)?\)?)\z/
              $1
146
            # Character types
147
            when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
148
              $1
149 150 151
            # Character types (8.1 formatting)
            when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
              $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
152
            # Binary data types
153
            when /\A'(.*)'::bytea\z/m
154 155
              $1
            # Date/time types
156
            when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
157
              $1
158
            when /\A'(.*)'::interval\z/
159 160
              $1
            # Boolean type
161
            when 'true'
162
              true
163
            when 'false'
164 165
              false
            # Geometric types
166
            when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
167 168
              $1
            # Network address types
169
            when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
170 171
              $1
            # Bit string types
172
            when /\AB'(.*)'::"?bit(?: varying)?"?\z/
173 174
              $1
            # XML type
175
            when /\A'(.*)'::xml\z/m
176 177
              $1
            # Arrays
178
            when /\A'(.*)'::"?\D+"?\[\]\z/
179 180
              $1
            # Object identifier types
181
            when /\A-?\d+\z/
182 183 184
              $1
            else
              # Anything else is blank, some user type, or some function
185
              # and we can't know the value of that, so return nil.
186 187 188
              nil
          end
        end
D
Initial  
David Heinemeier Hansson 已提交
189 190
    end

191 192
    # The PostgreSQL adapter works both with the native C (http://ruby.scripting.ca/postgres/) and the pure
    # Ruby (available both as gem and from http://rubyforge.org/frs/?group_id=234&release_id=1944) drivers.
193 194 195
    #
    # Options:
    #
P
Pratik Naik 已提交
196 197 198 199 200
    # * <tt>:host</tt> - Defaults to "localhost".
    # * <tt>:port</tt> - Defaults to 5432.
    # * <tt>:username</tt> - Defaults to nothing.
    # * <tt>:password</tt> - Defaults to nothing.
    # * <tt>:database</tt> - The name of the database. No default, must be provided.
201
    # * <tt>:schema_search_path</tt> - An optional schema search path for the connection given
202
    #   as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
203
    # * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
204
    #   <encoding></tt> call on the connection.
205
    # * <tt>:min_messages</tt> - An optional client min messages that is used in a
206
    #   <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
207
    class PostgreSQLAdapter < AbstractAdapter
208 209 210 211 212
      class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
        def xml(*args)
          options = args.extract_options!
          column(args[0], 'xml', options)
        end
213 214 215 216 217

        def tsvector(*args)
          options = args.extract_options!
          column(args[0], 'tsvector', options)
        end
218 219
      end

220
      ADAPTER_NAME = 'PostgreSQL'
221 222

      NATIVE_DATABASE_TYPES = {
223
        :primary_key => "serial primary key",
224 225 226 227 228 229 230 231 232 233
        :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" },
234
        :boolean     => { :name => "boolean" },
235 236
        :xml         => { :name => "xml" },
        :tsvector    => { :name => "tsvector" }
237 238
      }

239
      # Returns 'PostgreSQL' as adapter name for identification purposes.
240
      def adapter_name
241
        ADAPTER_NAME
242 243
      end

244 245
      # Returns +true+, since this connection adapter supports prepared statement
      # caching.
246 247 248 249
      def supports_statement_cache?
        true
      end

250 251 252 253
      class StatementPool < ConnectionAdapters::StatementPool
        def initialize(connection, max)
          super
          @counter = 0
254
          @cache   = Hash.new { |h,pid| h[pid] = {} }
255 256
        end

257 258 259 260
        def each(&block); cache.each(&block); end
        def key?(key);    cache.key?(key); end
        def [](key);      cache[key]; end
        def length;       cache.length; end
261 262 263 264 265 266

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

        def []=(sql, key)
267 268
          while @max <= cache.size
            dealloc(cache.shift.last)
269 270
          end
          @counter += 1
271
          cache[sql] = key
272 273 274
        end

        def clear
275
          cache.each_value do |stmt_key|
276 277
            dealloc stmt_key
          end
278
          cache.clear
279 280 281
        end

        private
282 283 284 285
        def cache
          @cache[$$]
        end

286 287 288 289 290
        def dealloc(key)
          @connection.query "DEALLOCATE #{key}"
        end
      end

291 292
      # Initializes and connects a PostgreSQL adapter.
      def initialize(connection, logger, connection_parameters, config)
293
        super(connection, logger)
294
        @connection_parameters, @config = connection_parameters, config
295

296 297
        # @local_tz is initialized as nil to avoid warnings when connect tries to use it
        @local_tz = nil
298 299
        @table_alias_length = nil

300
        connect
301 302
        @statements = StatementPool.new @connection,
                                        config.fetch(:statement_limit) { 1000 }
303 304 305 306 307

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

308
        @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
309 310
      end

311 312 313 314
      def self.visitor_for(pool) # :nodoc:
        Arel::Visitors::PostgreSQL.new(pool)
      end

X
Xavier Noria 已提交
315
      # Clears the prepared statements cache.
316 317 318 319
      def clear_cache!
        @statements.clear
      end

320 321
      # Is this connection alive and ready for queries?
      def active?
322 323
        @connection.status == PGconn::CONNECTION_OK
      rescue PGError
324
        false
325 326 327 328
      end

      # Close then reopen the connection.
      def reconnect!
329 330 331
        clear_cache!
        @connection.reset
        configure_connection
332
      end
333

334 335 336 337 338
      def reset!
        clear_cache!
        super
      end

339 340
      # Disconnects from the database if already connected. Otherwise, this
      # method does nothing.
341
      def disconnect!
342
        clear_cache!
343 344
        @connection.close rescue nil
      end
345

346
      def native_database_types #:nodoc:
347
        NATIVE_DATABASE_TYPES
348
      end
349

350
      # Returns true, since this connection adapter supports migrations.
351 352
      def supports_migrations?
        true
353 354
      end

355
      # Does PostgreSQL support finding primary key on non-Active Record tables?
356 357 358 359
      def supports_primary_key? #:nodoc:
        true
      end

360 361 362
      # Enable standard-conforming strings if available.
      def set_standard_conforming_strings
        old, self.client_min_messages = client_min_messages, 'panic'
363
        execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
364 365
      ensure
        self.client_min_messages = old
366 367
      end

368
      def supports_insert_with_returning?
369
        true
370 371
      end

372 373 374
      def supports_ddl_transactions?
        true
      end
375

376
      # Returns true, since this connection adapter supports savepoints.
377 378 379
      def supports_savepoints?
        true
      end
380

381
      # Returns the configured supported identifier length supported by PostgreSQL
382
      def table_alias_length
383
        @table_alias_length ||= query('SHOW max_identifier_length')[0][0].to_i
384
      end
385

386 387
      # QUOTING ==================================================

388
      # Escapes binary strings for bytea input to the database.
389 390
      def escape_bytea(value)
        @connection.escape_bytea(value) if value
391 392 393 394 395
      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.
396 397
      def unescape_bytea(value)
        @connection.unescape_bytea(value) if value
398 399
      end

400 401
      # Quotes PostgreSQL-specific data types for SQL input.
      def quote(value, column = nil) #:nodoc:
402 403
        return super unless column

A
Aaron Patterson 已提交
404
        case value
405 406 407
        when Float
          return super unless value.infinite? && column.type == :datetime
          "'#{value.to_s.downcase}'"
A
Aaron Patterson 已提交
408 409
        when Numeric
          return super unless column.sql_type == 'money'
410
          # Not truly string input, so doesn't require (or allow) escape string syntax.
411
          "'#{value}'"
A
Aaron Patterson 已提交
412 413 414 415 416 417 418 419 420 421 422
        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
423
          end
424 425 426 427 428
        else
          super
        end
      end

429 430 431 432 433 434
      def type_cast(value, column)
        return super unless column

        case value
        when String
          return super unless 'bytea' == column.sql_type
435
          { :value => value, :format => 1 }
436 437 438 439 440
        else
          super
        end
      end

441 442 443
      # Quotes strings for use in SQL input.
      def quote_string(s) #:nodoc:
        @connection.escape(s)
444 445
      end

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
      # 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

465 466
      # Quotes column names for use in SQL queries.
      def quote_column_name(name) #:nodoc:
467
        PGconn.quote_ident(name.to_s)
468 469
      end

470 471 472
      # 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:
473 474 475 476 477
        if value.acts_like?(:time) && value.respond_to?(:usec)
          "#{super}.#{sprintf("%06d", value.usec)}"
        else
          super
        end
478 479
      end

480 481
      # Set the authorized user for this session
      def session_auth=(user)
482
        clear_cache!
A
Aaron Patterson 已提交
483
        exec_query "SET SESSION AUTHORIZATION #{user}"
484 485
      end

486 487
      # REFERENTIAL INTEGRITY ====================================

488
      def supports_disable_referential_integrity? #:nodoc:
489
        true
490 491
      end

492
      def disable_referential_integrity #:nodoc:
493
        if supports_disable_referential_integrity? then
494 495
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
        end
496 497
        yield
      ensure
498
        if supports_disable_referential_integrity? then
499 500
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
        end
501
      end
502 503 504

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

505 506 507 508 509 510
      # 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

511
      # Executes an INSERT query and returns the new record's ID
512
      def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
513 514 515 516 517
        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
518

519
        if pk
520 521 522
          select_value("#{sql} RETURNING #{quote_column_name(pk)}")
        else
          super
523
        end
524
      end
525
      alias :create :insert
526

527 528
      # create a 2D array representing the result set
      def result_as_array(res) #:nodoc:
529
        # check if we have any binary column and if they need escaping
530 531
        ftypes = Array.new(res.nfields) do |i|
          [i, res.ftype(i)]
532 533
        end

534 535 536 537 538 539
        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 }
540 541
        binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
        monies   = typehash[MONEY_COLUMN_TYPE_OID] || []
542 543 544

        rows.each do |row|
          # unescape string passed BYTEA field (OID == 17)
545 546
          binaries.each do |index, _|
            row[index] = unescape_bytea(row[index])
547 548 549 550 551 552
          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.
553
          monies.each do |index, _|
554 555 556 557 558 559 560 561 562 563
            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!(/,/, '.')
564
            end
565 566 567 568 569 570
          end
        end
      end


      # Queries the database and returns the results in an Array-like object
571
      def query(sql, name = nil) #:nodoc:
572
        log(sql, name) do
573
          result_as_array @connection.async_exec(sql)
574
        end
575 576
      end

577
      # Executes an SQL statement, returning a PGresult object on success
578 579
      # or raising a PGError exception otherwise.
      def execute(sql, name = nil)
580
        log(sql, name) do
581
          @connection.async_exec(sql)
582
        end
583 584
      end

585 586
      def substitute_at(column, index)
        Arel.sql("$#{index + 1}")
587 588
      end

A
Aaron Patterson 已提交
589
      def exec_query(sql, name = 'SQL', binds = [])
590
        log(sql, name, binds) do
591 592
          result = binds.empty? ? exec_no_cache(sql, binds) :
                                  exec_cache(sql, binds)
593

594 595 596
          ret = ActiveRecord::Result.new(result.fields, result_as_array(result))
          result.clear
          return ret
597 598 599
        end
      end

600 601 602 603 604 605 606 607 608
      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
609
      alias :exec_update :exec_delete
610

611 612
      def sql_for_insert(sql, pk, id_value, sequence_name, binds)
        unless pk
613 614 615
          # 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
616 617 618 619 620 621 622
        end

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

        [sql, binds]
      end

623
      # Executes an UPDATE query and returns the number of affected tuples.
624
      def update_sql(sql, name = nil)
625
        super.cmd_tuples
626 627
      end

628 629
      # Begins a transaction.
      def begin_db_transaction
630 631 632
        execute "BEGIN"
      end

633 634
      # Commits a transaction.
      def commit_db_transaction
635 636
        execute "COMMIT"
      end
637

638 639
      # Aborts a transaction.
      def rollback_db_transaction
640 641
        execute "ROLLBACK"
      end
642

643 644
      def outside_transaction?
        @connection.transaction_status == PGconn::PQTRANS_IDLE
645
      end
646

J
Jonathan Viney 已提交
647 648 649 650 651 652 653 654
      def create_savepoint
        execute("SAVEPOINT #{current_savepoint_name}")
      end

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

655
      def release_savepoint
J
Jonathan Viney 已提交
656 657
        execute("RELEASE SAVEPOINT #{current_savepoint_name}")
      end
658

659 660
      # SCHEMA STATEMENTS ========================================

661 662 663
      # Drops the database specified on the +name+ attribute
      # and creates it again using the provided +options+.
      def recreate_database(name, options = {}) #:nodoc:
664
        drop_database(name)
665
        create_database(name, options)
666 667
      end

668
      # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
669 670
      # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
      # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
671 672 673 674 675 676 677 678 679 680
      #
      # 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
681
            " OWNER = \"#{value}\""
682
          when :template
683
            " TEMPLATE = \"#{value}\""
684 685 686
          when :encoding
            " ENCODING = '#{value}'"
          when :tablespace
687
            " TABLESPACE = \"#{value}\""
688 689 690 691 692 693 694
          when :connection_limit
            " CONNECTION LIMIT = #{value}"
          else
            ""
          end
        end

695
        execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
696 697
      end

698
      # Drops a PostgreSQL database.
699 700 701 702
      #
      # Example:
      #   drop_database 'matt_development'
      def drop_database(name) #:nodoc:
703
        execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
704 705
      end

706 707
      # Returns the list of all tables in the schema search path or a specified schema.
      def tables(name = nil)
708
        query(<<-SQL, 'SCHEMA').map { |row| row[0] }
709
          SELECT tablename
710 711 712 713 714
          FROM pg_tables
          WHERE schemaname = ANY (current_schemas(false))
        SQL
      end

715
      # Returns true if table exists.
716 717
      # 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)
718
      def table_exists?(name)
719
        schema, table = Utils.extract_schema_and_table(name.to_s)
720
        return false unless table
721

722 723
        binds = [[nil, table]]
        binds << [nil, schema] if schema
724 725

        exec_query(<<-SQL, 'SCHEMA', binds).rows.first[0].to_i > 0
726
            SELECT COUNT(*)
A
Aaron Patterson 已提交
727 728 729 730 731
            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))'}
732 733 734
        SQL
      end

735 736 737 738 739 740 741 742
      # 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
743

744
      # Returns an array of indexes for the given table.
745
      def indexes(table_name, name = nil)
746 747
         schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
         result = query(<<-SQL, name)
748
           SELECT distinct i.relname, d.indisunique, d.indkey, t.oid
749 750 751
           FROM pg_class t
           INNER JOIN pg_index d ON t.oid = d.indrelid
           INNER JOIN pg_class i ON d.indexrelid = i.oid
752 753 754
           WHERE i.relkind = 'i'
             AND d.indisprimary = 'f'
             AND t.relname = '#{table_name}'
755
             AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (#{schemas}) )
756 757 758
          ORDER BY i.relname
        SQL

759

760
        result.map do |row|
761 762 763 764 765
          index_name = row[0]
          unique = row[1] == 't'
          indkey = row[2].split(" ")
          oid = row[3]

766 767
          columns = Hash[query(<<-SQL, "Columns for index #{row[0]} on #{table_name}")]
          SELECT a.attnum, a.attname
768 769 770 771 772
          FROM pg_attribute a
          WHERE a.attrelid = #{oid}
          AND a.attnum IN (#{indkey.join(",")})
          SQL

773 774
          column_names = columns.values_at(*indkey).compact
          column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names)
775
        end.compact
776 777
      end

778 779
      # Returns the list of all column definitions for a table.
      def columns(table_name, name = nil)
780
        # Limit, precision, and scale are all handled by the superclass.
781 782
        column_definitions(table_name).collect do |column_name, type, default, notnull|
          PostgreSQLColumn.new(column_name, default, type, notnull == 'f')
D
Initial  
David Heinemeier Hansson 已提交
783 784 785
        end
      end

786 787 788 789 790
      # Returns the current database name.
      def current_database
        query('select current_database()')[0][0]
      end

791 792 793 794 795
      # Returns the current schema name.
      def current_schema
        query('SELECT current_schema', 'SCHEMA')[0][0]
      end

796 797 798 799 800 801 802 803
      # 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

804 805 806 807 808 809
      # 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)
810 811
        if schema_csv
          execute "SET search_path TO #{schema_csv}"
812
          @schema_search_path = schema_csv
813
        end
D
Initial  
David Heinemeier Hansson 已提交
814 815
      end

816 817
      # Returns the active schema search path.
      def schema_search_path
818
        @schema_search_path ||= query('SHOW search_path')[0][0]
819
      end
820

821 822
      # Returns the current client message level.
      def client_min_messages
823
        query('SHOW client_min_messages', 'SCHEMA')[0][0]
824 825 826 827
      end

      # Set the client message level.
      def client_min_messages=(level)
828
        execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
829 830 831 832
      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:
833 834 835 836 837 838 839 840 841 842
        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
843 844
      end

845 846
      # Resets the sequence of a table's primary key to the maximum value.
      def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
847 848
        unless pk and sequence
          default_pk, default_sequence = pk_and_sequence_for(table)
849

850 851 852
          pk ||= default_pk
          sequence ||= default_sequence
        end
853

854 855 856 857 858
        if @logger && pk && !sequence
          @logger.warn "#{table} has primary key #{pk} with no default sequence"
        end

        if pk && sequence
859
          quoted_sequence = quote_table_name(sequence)
G
Guillermo Iguaran 已提交
860

861 862 863
          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
864 865 866
        end
      end

867 868
      # Returns a table's primary key and belonging sequence.
      def pk_and_sequence_for(table) #:nodoc:
869 870
        # First try looking for a sequence with a dependency on the
        # given table's primary key.
871
        result = exec_query(<<-end_sql, 'SCHEMA').rows.first
872
          SELECT attr.attname, ns.nspname, seq.relname
873
          FROM pg_class seq
A
Akira Matsuda 已提交
874
          INNER JOIN pg_depend dep ON seq.oid = dep.objid
875 876
          INNER JOIN pg_attribute attr 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]
877
          INNER JOIN pg_namespace ns ON seq.relnamespace = ns.oid
878 879 880
          WHERE seq.relkind  = 'S'
            AND cons.contype = 'p'
            AND dep.refobjid = '#{quote_table_name(table)}'::regclass
881
        end_sql
882

883
        # [primary_key, sequence]
884 885 886 887 888
        if result.second ==  'public' then
          sequence = result.last
        else
          sequence = result.second+'.'+result.last
        end
G
Guillermo Iguaran 已提交
889

890
        [result.first, sequence]
891 892
      rescue
        nil
893 894
      end

895 896
      # Returns just a table's primary key
      def primary_key(table)
897
        row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first
898
          SELECT DISTINCT(attr.attname)
899 900 901 902 903
          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
904 905 906
        end_sql

        row && row.first
907 908
      end

909
      # Renames a table.
910 911 912
      #
      # Example:
      #   rename_table('octopuses', 'octopi')
913
      def rename_table(name, new_name)
914
        execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
915
      end
916

917 918
      # Adds a new column to the named table.
      # See TableDefinition#column for details of the options you can use.
S
Scott Barron 已提交
919
      def add_column(table_name, column_name, type, options = {})
920 921
        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)
922

923
        execute add_column_sql
S
Scott Barron 已提交
924
      end
D
Initial  
David Heinemeier Hansson 已提交
925

926 927
      # Changes the column of a table.
      def change_column(table_name, column_name, type, options = {})
928 929
        quoted_table_name = quote_table_name(table_name)

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

932 933
        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)
934
      end
935

936 937
      # Changes the default value of a table column.
      def change_column_default(table_name, column_name, default)
938
        execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
939
      end
940

941 942
      def change_column_null(table_name, column_name, null, default = nil)
        unless null || default.nil?
943
          execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
944
        end
945
        execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
946 947
      end

948 949
      # Renames a column in a table.
      def rename_column(table_name, column_name, new_column_name)
950
        execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
951
      end
952

953 954 955 956
      def remove_index!(table_name, index_name) #:nodoc:
        execute "DROP INDEX #{quote_table_name(index_name)}"
      end

957 958 959 960
      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

961 962
      def index_name_length
        63
963
      end
964

965 966
      # Maps logical Rails types to PostgreSQL-specific data types.
      def type_to_sql(type, limit = nil, precision = nil, scale = nil)
967
        return super unless type.to_s == 'integer'
968
        return 'integer' unless limit
969

970
        case limit
971 972 973
          when 1, 2; 'smallint'
          when 3, 4; 'integer'
          when 5..8; 'bigint'
974
          else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
975 976
        end
      end
977

978
      # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
979 980 981
      #
      # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
      # requires that the ORDER BY include the distinct column.
982
      #
983
      #   distinct("posts.id", "posts.created_at desc")
984 985
      def distinct(columns, orders) #:nodoc:
        return "DISTINCT #{columns}" if orders.empty?
986

987 988
        # Construct a clean list of column names from the ORDER BY clause, removing
        # any ASC/DESC modifiers
989
        order_columns = orders.collect { |s| s.gsub(/\s+(ASC|DESC)\s*/i, '') }
990
        order_columns.delete_if { |c| c.blank? }
991
        order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
992

993
        "DISTINCT #{columns}, #{order_columns * ', '}"
994
      end
995

996
      module Utils
997 998
        extend self

999 1000 1001 1002 1003 1004 1005 1006 1007 1008
        # 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>
1009
        def extract_schema_and_table(name)
1010 1011 1012 1013 1014
          table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse
          [schema, table]
        end
      end

1015
      protected
1016
        # Returns the version of the connected PostgreSQL server.
1017
        def postgresql_version
1018
          @connection.server_version
1019 1020
        end

1021 1022 1023
        def translate_exception(exception, message)
          case exception.message
          when /duplicate key value violates unique constraint/
1024
            RecordNotUnique.new(message, exception)
1025
          when /violates foreign key constraint/
1026
            InvalidForeignKey.new(message, exception)
1027 1028 1029 1030 1031
          else
            super
          end
        end

D
Initial  
David Heinemeier Hansson 已提交
1032
      private
1033 1034
        def exec_no_cache(sql, binds)
          @connection.async_exec(sql)
1035
        end
1036

1037 1038
        def exec_cache(sql, binds)
          unless @statements.key? sql
1039
            nextkey = @statements.next_key
1040 1041 1042
            @connection.prepare nextkey, sql
            @statements[sql] = nextkey
          end
1043

1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
          key = @statements[sql]

          # Clear the queue
          @connection.get_last_result
          @connection.send_query_prepared(key, binds.map { |col, val|
            type_cast(val, col)
          })
          @connection.block
          @connection.get_last_result
        end
1054

P
Pratik Naik 已提交
1055
        # The internal PostgreSQL identifier of the money data type.
1056
        MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
1057 1058
        # The internal PostgreSQL identifier of the BYTEA data type.
        BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
1059 1060 1061 1062 1063 1064 1065 1066 1067

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

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

1070 1071 1072
          configure_connection
        end

1073
        # Configures the encoding, verbosity, schema search path, and time zone of the connection.
1074
        # This is called by #connect and should not be called manually.
1075 1076
        def configure_connection
          if @config[:encoding]
1077
            @connection.set_client_encoding(@config[:encoding])
1078
          end
1079 1080
          self.client_min_messages = @config[:min_messages] if @config[:min_messages]
          self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
1081 1082 1083 1084

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

1085
          # If using Active Record's time zone support configure the connection to return
1086
          # TIMESTAMP WITH ZONE types in UTC.
1087
          if ActiveRecord::Base.default_timezone == :utc
1088
            execute("SET time zone 'UTC'", 'SCHEMA')
1089
          elsif @local_tz
1090
            execute("SET time zone '#{@local_tz}'", 'SCHEMA')
1091
          end
1092 1093
        end

1094
        # Returns the current ID of a table's sequence.
1095 1096 1097
        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 已提交
1098 1099
        end

1100
        # Executes a SELECT query and returns the results, performing any data type
1101
        # conversions that are required to be performed here instead of in PostgreSQLColumn.
1102
        def select(sql, name = nil, binds = [])
A
Aaron Patterson 已提交
1103
          exec_query(sql, name, binds).to_a
1104 1105 1106
        end

        def select_raw(sql, name = nil)
1107
          res = execute(sql, name)
1108
          results = result_as_array(res)
1109
          fields = res.fields
1110
          res.clear
1111
          return fields, results
M
Marcel Molina 已提交
1112 1113
        end

1114
        # Returns the list of a table's column names, data types, and default values.
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
        #
        # 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
1132
        def column_definitions(table_name) #:nodoc:
1133
          exec_query(<<-end_sql, 'SCHEMA').rows
1134
            SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
1135 1136
              FROM pg_attribute a LEFT JOIN pg_attrdef d
                ON a.attrelid = d.adrelid AND a.attnum = d.adnum
1137
             WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
1138 1139 1140
               AND a.attnum > 0 AND NOT a.attisdropped
             ORDER BY a.attnum
          end_sql
D
Initial  
David Heinemeier Hansson 已提交
1141
        end
1142 1143

        def extract_pg_identifier_from_name(name)
1144
          match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
1145 1146

          if match_data
1147 1148
            rest = name[match_data[0].length, name.length]
            rest = rest[1, rest.length] if rest.start_with? "."
1149 1150 1151
            [match_data[1], (rest.length > 0 ? rest : nil)]
          end
        end
1152

1153 1154 1155 1156 1157
        def extract_table_ref_from_insert_sql(sql)
          sql[/into\s+([^\(]*).*values\s*\(/i]
          $1.strip if $1
        end

1158 1159 1160
        def table_definition
          TableDefinition.new(self)
        end
D
Initial  
David Heinemeier Hansson 已提交
1161 1162 1163
    end
  end
end