postgresql_adapter.rb 37.0 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1
require 'active_record/connection_adapters/abstract_adapter'
J
Jeremy Kemper 已提交
2
require 'active_support/core_ext/kernel/requires'
3
require 'active_support/core_ext/object/blank'
4
require 'pg'
D
Initial  
David Heinemeier Hansson 已提交
5 6 7 8 9

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

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

22
      # The postgres drivers don't allow the creation of an unconnected PGconn object,
23 24 25 26
      # 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
27

28 29 30 31 32 33 34
  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
35

36 37 38 39 40 41
      # :stopdoc:
      class << self
        attr_accessor :money_precision
      end
      # :startdoc:

42
      private
43
        def extract_limit(sql_type)
44 45 46 47 48
          case sql_type
          when /^bigint/i;    8
          when /^smallint/i;  2
          else super
          end
49 50
        end

51 52 53 54 55
        # 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
56

57 58
        # Extracts the precision from PostgreSQL-specific data types.
        def extract_precision(sql_type)
59 60 61 62 63
          if sql_type == 'money'
            self.class.money_precision
          else
            super
          end
64
        end
65

66 67 68 69 70 71 72
        # 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
73
            when 'money'
74 75 76 77 78
              :decimal
            # Character types
            when /^(?:character varying|bpchar)(?:\(\d+\))?$/
              :string
            # Binary data types
79
            when 'bytea'
80 81 82 83
              :binary
            # Date/time types
            when /^timestamp with(?:out)? time zone$/
              :datetime
84
            when 'interval'
85 86 87 88 89 90 91 92 93 94 95
              :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
96
            when 'xml'
97
              :xml
98 99
            # Arrays
            when /^\D+\[\]$/
100
              :string
101
            # Object identifier types
102
            when 'oid'
103
              :integer
104
            # UUID type
105
            when 'uuid'
106 107 108 109
              :string
            # Small and big integer types
            when /^(?:small|big)int$/
              :integer
110 111 112 113 114
            # Pass through all types that are not specific to PostgreSQL.
            else
              super
          end
        end
115

116 117 118 119
        # Extracts the value from a PostgreSQL column default definition.
        def self.extract_value_from_default(default)
          case default
            # Numeric types
120 121
            when /\A\(?(-?\d+(\.\d*)?\)?)\z/
              $1
122
            # Character types
123
            when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
124
              $1
125 126 127
            # Character types (8.1 formatting)
            when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
              $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
128
            # Binary data types
129
            when /\A'(.*)'::bytea\z/m
130 131
              $1
            # Date/time types
132
            when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
133
              $1
134
            when /\A'(.*)'::interval\z/
135 136
              $1
            # Boolean type
137
            when 'true'
138
              true
139
            when 'false'
140 141
              false
            # Geometric types
142
            when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
143 144
              $1
            # Network address types
145
            when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
146 147
              $1
            # Bit string types
148
            when /\AB'(.*)'::"?bit(?: varying)?"?\z/
149 150
              $1
            # XML type
151
            when /\A'(.*)'::xml\z/m
152 153
              $1
            # Arrays
154
            when /\A'(.*)'::"?\D+"?\[\]\z/
155 156
              $1
            # Object identifier types
157
            when /\A-?\d+\z/
158 159 160
              $1
            else
              # Anything else is blank, some user type, or some function
161
              # and we can't know the value of that, so return nil.
162 163 164
              nil
          end
        end
D
Initial  
David Heinemeier Hansson 已提交
165 166
    end

167 168
    # 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.
169 170 171
    #
    # Options:
    #
P
Pratik Naik 已提交
172 173 174 175 176
    # * <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.
177
    # * <tt>:schema_search_path</tt> - An optional schema search path for the connection given
178
    #   as a string of comma-separated schema names.  This is backward-compatible with the <tt>:schema_order</tt> option.
179
    # * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
180
    #   <encoding></tt> call on the connection.
181
    # * <tt>:min_messages</tt> - An optional client min messages that is used in a
182
    #   <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
183
    class PostgreSQLAdapter < AbstractAdapter
184 185 186 187 188 189 190
      class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
        def xml(*args)
          options = args.extract_options!
          column(args[0], 'xml', options)
        end
      end

191
      ADAPTER_NAME = 'PostgreSQL'
192 193

      NATIVE_DATABASE_TYPES = {
194
        :primary_key => "serial primary key",
195 196 197 198 199 200 201 202 203 204
        :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" },
205 206
        :boolean     => { :name => "boolean" },
        :xml         => { :name => "xml" }
207 208
      }

209
      # Returns 'PostgreSQL' as adapter name for identification purposes.
210
      def adapter_name
211
        ADAPTER_NAME
212 213
      end

214 215 216 217 218 219
      # Returns +true+ when the connection adapter supports prepared statement
      # caching, otherwise returns +false+
      def supports_statement_cache?
        true
      end

220 221
      # Initializes and connects a PostgreSQL adapter.
      def initialize(connection, logger, connection_parameters, config)
222
        super(connection, logger)
223
        @connection_parameters, @config = connection_parameters, config
224

225 226
        # @local_tz is initialized as nil to avoid warnings when connect tries to use it
        @local_tz = nil
227 228
        @table_alias_length = nil
        @postgresql_version = nil
229
        @statements = {}
230

231
        connect
232 233 234 235 236

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

237
        @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
238 239
      end

240 241
      def clear_cache!
        @statements.each_value do |value|
242
          @connection.query "DEALLOCATE #{value}"
243 244 245 246
        end
        @statements.clear
      end

247 248 249
      # Is this connection alive and ready for queries?
      def active?
        if @connection.respond_to?(:status)
250
          @connection.status == PGconn::CONNECTION_OK
251
        else
252
          # We're asking the driver, not Active Record, so use @connection.query instead of #query
253
          @connection.query 'SELECT 1'
254 255
          true
        end
256
      # postgres-pr raises a NoMethodError when querying if no connection is available.
257
      rescue PGError, NoMethodError
258
        false
259 260 261 262 263
      end

      # Close then reopen the connection.
      def reconnect!
        if @connection.respond_to?(:reset)
264
          clear_cache!
265
          @connection.reset
266
          configure_connection
267 268 269
        else
          disconnect!
          connect
270 271
        end
      end
272

273 274 275 276 277
      def reset!
        clear_cache!
        super
      end

278
      # Close the connection.
279
      def disconnect!
280
        clear_cache!
281 282
        @connection.close rescue nil
      end
283

284
      def native_database_types #:nodoc:
285
        NATIVE_DATABASE_TYPES
286
      end
287

288
      # Does PostgreSQL support migrations?
289 290
      def supports_migrations?
        true
291 292
      end

293
      # Does PostgreSQL support finding primary key on non-Active Record tables?
294 295 296 297
      def supports_primary_key? #:nodoc:
        true
      end

298 299 300
      # Enable standard-conforming strings if available.
      def set_standard_conforming_strings
        old, self.client_min_messages = client_min_messages, 'panic'
301
        execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
302 303
      ensure
        self.client_min_messages = old
304 305
      end

306
      def supports_insert_with_returning?
307
        true
308 309
      end

310 311 312
      def supports_ddl_transactions?
        true
      end
313

314 315 316
      def supports_savepoints?
        true
      end
317

318
      # Returns the configured supported identifier length supported by PostgreSQL
319
      def table_alias_length
320
        @table_alias_length ||= query('SHOW max_identifier_length')[0][0].to_i
321
      end
322

323 324
      # QUOTING ==================================================

325
      # Escapes binary strings for bytea input to the database.
326 327
      def escape_bytea(value)
        @connection.escape_bytea(value) if value
328 329 330 331 332
      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.
333 334
      def unescape_bytea(value)
        @connection.unescape_bytea(value) if value
335 336
      end

337 338
      # Quotes PostgreSQL-specific data types for SQL input.
      def quote(value, column = nil) #:nodoc:
339 340
        return super unless column

A
Aaron Patterson 已提交
341 342 343
        case value
        when Numeric
          return super unless column.sql_type == 'money'
344
          # Not truly string input, so doesn't require (or allow) escape string syntax.
345
          "'#{value}'"
A
Aaron Patterson 已提交
346 347 348 349 350 351 352 353 354 355 356
        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
357
          end
358 359 360 361 362
        else
          super
        end
      end

363 364 365 366 367 368 369 370 371 372 373 374
      def type_cast(value, column)
        return super unless column

        case value
        when String
          return super unless 'bytea' == column.sql_type
          escape_bytea(value)
        else
          super
        end
      end

375 376 377
      # Quotes strings for use in SQL input.
      def quote_string(s) #:nodoc:
        @connection.escape(s)
378 379
      end

380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
      # 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

399 400
      # Quotes column names for use in SQL queries.
      def quote_column_name(name) #:nodoc:
401
        PGconn.quote_ident(name.to_s)
402 403
      end

404 405 406
      # 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:
407 408 409 410 411
        if value.acts_like?(:time) && value.respond_to?(:usec)
          "#{super}.#{sprintf("%06d", value.usec)}"
        else
          super
        end
412 413
      end

414 415
      # Set the authorized user for this session
      def session_auth=(user)
416
        clear_cache!
A
Aaron Patterson 已提交
417
        exec_query "SET SESSION AUTHORIZATION #{user}"
418 419
      end

420 421
      # REFERENTIAL INTEGRITY ====================================

422
      def supports_disable_referential_integrity?() #:nodoc:
423
        true
424 425
      end

426
      def disable_referential_integrity #:nodoc:
427 428 429
        if supports_disable_referential_integrity?() then
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
        end
430 431
        yield
      ensure
432 433 434
        if supports_disable_referential_integrity?() then
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
        end
435
      end
436 437 438

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

439 440 441 442 443 444
      # 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

445
      # Executes an INSERT query and returns the new record's ID
446
      def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
447
        # Extract the table from the insert sql. Yuck.
448
        _, table = extract_schema_and_table(sql.split(" ", 4)[2])
449

450
        pk ||= primary_key(table)
451

452
        if pk
453 454 455
          select_value("#{sql} RETURNING #{quote_column_name(pk)}")
        else
          super
456
        end
457
      end
458
      alias :create :insert
459

460 461
      # create a 2D array representing the result set
      def result_as_array(res) #:nodoc:
462 463
        # check if we have any binary column and if they need escaping
        unescape_col = []
464
        res.nfields.times do |j|
465
          unescape_col << res.ftype(j)
466 467
        end

468
        ary = []
469
        res.ntuples.times do |i|
470
          ary << []
471
          res.nfields.times do |j|
472
            data = res.getvalue(i,j)
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
            case unescape_col[j]

            # unescape string passed BYTEA field (OID == 17)
            when BYTEA_COLUMN_TYPE_OID
              data = unescape_bytea(data) if String === data

            # 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.
            when MONEY_COLUMN_TYPE_OID
              # 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)
490 491
                data.gsub!(/[^-\d.]/, '')
              when /^-?\D+[\d.]+,\d{2}$/  # (2)
492 493 494
                data.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
              end
            end
495
            ary[i] << data
496 497 498 499 500 501 502
          end
        end
        return ary
      end


      # Queries the database and returns the results in an Array-like object
503
      def query(sql, name = nil) #:nodoc:
504 505
        log(sql, name) do
          if @async
506
            res = @connection.async_exec(sql)
507
          else
508
            res = @connection.exec(sql)
509
          end
510
          return result_as_array(res)
511
        end
512 513
      end

514
      # Executes an SQL statement, returning a PGresult object on success
515 516
      # or raising a PGError exception otherwise.
      def execute(sql, name = nil)
517 518 519 520 521 522 523
        log(sql, name) do
          if @async
            @connection.async_exec(sql)
          else
            @connection.exec(sql)
          end
        end
524 525
      end

526 527
      def substitute_at(column, index)
        Arel.sql("$#{index + 1}")
528 529
      end

A
Aaron Patterson 已提交
530
      def exec_query(sql, name = 'SQL', binds = [])
531 532
        return exec_no_cache(sql, name) if binds.empty?

533
        log(sql, name, binds) do
534
          unless @statements.key? sql
535 536 537
            nextkey = "a#{@statements.length + 1}"
            @connection.prepare nextkey, sql
            @statements[sql] = nextkey
538 539 540 541 542 543
          end

          key = @statements[sql]

          # Clear the queue
          @connection.get_last_result
A
Aaron Patterson 已提交
544
          @connection.send_query_prepared(key, binds.map { |col, val|
545
            type_cast(val, col)
A
Aaron Patterson 已提交
546
          })
547 548
          @connection.block
          result = @connection.get_last_result
549 550 551
          ret = ActiveRecord::Result.new(result.fields, result_as_array(result))
          result.clear
          return ret
552 553 554
        end
      end

555 556 557 558
      def exec_insert(sql, name, binds)
        exec_query(sql, name, binds)
      end

559 560 561 562 563 564 565 566 567 568 569 570
      def sql_for_insert(sql, pk, id_value, sequence_name, binds)
        unless pk
          _, table = extract_schema_and_table(sql.split(" ", 4)[2])

          pk = primary_key(table)
        end

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

        [sql, binds]
      end

571
      # Executes an UPDATE query and returns the number of affected tuples.
572
      def update_sql(sql, name = nil)
573
        super.cmd_tuples
574 575
      end

576 577
      # Begins a transaction.
      def begin_db_transaction
578 579 580
        execute "BEGIN"
      end

581 582
      # Commits a transaction.
      def commit_db_transaction
583 584
        execute "COMMIT"
      end
585

586 587
      # Aborts a transaction.
      def rollback_db_transaction
588 589
        execute "ROLLBACK"
      end
590

591 592
      def outside_transaction?
        @connection.transaction_status == PGconn::PQTRANS_IDLE
593
      end
594

J
Jonathan Viney 已提交
595 596 597 598 599 600 601 602
      def create_savepoint
        execute("SAVEPOINT #{current_savepoint_name}")
      end

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

603
      def release_savepoint
J
Jonathan Viney 已提交
604 605
        execute("RELEASE SAVEPOINT #{current_savepoint_name}")
      end
606

607 608
      # SCHEMA STATEMENTS ========================================

609 610 611 612 613
      def recreate_database(name) #:nodoc:
        drop_database(name)
        create_database(name)
      end

614 615 616
      # Create a new PostgreSQL database.  Options include <tt>:owner</tt>, <tt>:template</tt>,
      # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
      # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
617 618 619 620 621 622 623 624 625 626
      #
      # 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
627
            " OWNER = \"#{value}\""
628
          when :template
629
            " TEMPLATE = \"#{value}\""
630 631 632
          when :encoding
            " ENCODING = '#{value}'"
          when :tablespace
633
            " TABLESPACE = \"#{value}\""
634 635 636 637 638 639 640
          when :connection_limit
            " CONNECTION LIMIT = #{value}"
          else
            ""
          end
        end

641
        execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
642 643 644 645 646 647 648
      end

      # Drops a PostgreSQL database
      #
      # Example:
      #   drop_database 'matt_development'
      def drop_database(name) #:nodoc:
649
        execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
650 651
      end

652 653
      # Returns the list of all tables in the schema search path or a specified schema.
      def tables(name = nil)
654
        query(<<-SQL, 'SCHEMA').map { |row| row[0] }
655
          SELECT tablename
656 657 658 659 660 661
          FROM pg_tables
          WHERE schemaname = ANY (current_schemas(false))
        SQL
      end

      def table_exists?(name)
662 663
        schema, table = extract_schema_and_table(name.to_s)

664 665 666 667
        binds = [[nil, table.gsub(/(^"|"$)/,'')]]
        binds << [nil, schema] if schema

        exec_query(<<-SQL, 'SCHEMA', binds).rows.first[0].to_i > 0
668 669
            SELECT COUNT(*)
            FROM pg_tables
670 671
            WHERE tablename = $1
            #{schema ? "AND schemaname = $2" : ''}
672 673 674 675 676
        SQL
      end

      # Extracts the table and schema name from +name+
      def extract_schema_and_table(name)
677 678 679 680 681 682 683 684 685 686 687
        schema, table = name.split('.', 2)

        unless table # A table was provided without a schema
          table  = schema
          schema = nil
        end

        if name =~ /^"/ # Handle quoted table names
          table  = name
          schema = nil
        end
688
        [schema, table]
689 690
      end

691 692
      # Returns the list of all indexes for a table.
      def indexes(table_name, name = nil)
693 694
         schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
         result = query(<<-SQL, name)
695 696
           SELECT distinct i.relname, d.indisunique, d.indkey, t.oid
             FROM pg_class t, pg_class i, pg_index d
697 698 699 700 701
           WHERE i.relkind = 'i'
             AND d.indexrelid = i.oid
             AND d.indisprimary = 'f'
             AND t.oid = d.indrelid
             AND t.relname = '#{table_name}'
702
             AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (#{schemas}) )
703 704 705
          ORDER BY i.relname
        SQL

706

707
        result.map do |row|
708 709 710 711 712
          index_name = row[0]
          unique = row[1] == 't'
          indkey = row[2].split(" ")
          oid = row[3]

713 714
          columns = Hash[query(<<-SQL, "Columns for index #{row[0]} on #{table_name}")]
          SELECT a.attnum, a.attname
715 716 717 718 719
          FROM pg_attribute a
          WHERE a.attrelid = #{oid}
          AND a.attnum IN (#{indkey.join(",")})
          SQL

720 721
          column_names = columns.values_at(*indkey).compact
          column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names)
722
        end.compact
723 724
      end

725 726
      # Returns the list of all column definitions for a table.
      def columns(table_name, name = nil)
727
        # Limit, precision, and scale are all handled by the superclass.
728 729
        column_definitions(table_name).collect do |column_name, type, default, notnull|
          PostgreSQLColumn.new(column_name, default, type, notnull == 'f')
D
Initial  
David Heinemeier Hansson 已提交
730 731 732
        end
      end

733 734 735 736 737 738 739 740 741 742 743 744 745
      # Returns the current database name.
      def current_database
        query('select current_database()')[0][0]
      end

      # 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

746 747 748 749 750 751
      # 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)
752 753
        if schema_csv
          execute "SET search_path TO #{schema_csv}"
754
          @schema_search_path = schema_csv
755
        end
D
Initial  
David Heinemeier Hansson 已提交
756 757
      end

758 759
      # Returns the active schema search path.
      def schema_search_path
760
        @schema_search_path ||= query('SHOW search_path')[0][0]
761
      end
762

763 764
      # Returns the current client message level.
      def client_min_messages
765
        query('SHOW client_min_messages', 'SCHEMA')[0][0]
766 767 768 769
      end

      # Set the client message level.
      def client_min_messages=(level)
770
        execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
771 772 773 774
      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:
775 776 777 778 779 780 781 782 783 784
        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
785 786
      end

787 788
      # Resets the sequence of a table's primary key to the maximum value.
      def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
789 790
        unless pk and sequence
          default_pk, default_sequence = pk_and_sequence_for(table)
791

792 793 794
          pk ||= default_pk
          sequence ||= default_sequence
        end
795

796 797 798 799 800 801 802 803 804 805
        if @logger && pk && !sequence
          @logger.warn "#{table} has primary key #{pk} with no default sequence"
        end

        if pk && sequence
          quoted_sequence = quote_column_name(sequence)

          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
806 807 808
        end
      end

809 810
      # Returns a table's primary key and belonging sequence.
      def pk_and_sequence_for(table) #:nodoc:
811 812
        # First try looking for a sequence with a dependency on the
        # given table's primary key.
813
        result = exec_query(<<-end_sql, 'SCHEMA').rows.first
814
          SELECT attr.attname, seq.relname
815 816 817 818 819 820 821 822 823 824 825 826
          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'
827
            AND dep.refobjid      = '#{quote_table_name(table)}'::regclass
828
        end_sql
829

830
        # [primary_key, sequence]
831
        [result.first, result.last]
832 833
      rescue
        nil
834 835
      end

836 837
      # Returns just a table's primary key
      def primary_key(table)
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
        row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first
          SELECT DISTINCT(attr.attname)
          FROM pg_attribute  attr,
               pg_depend     dep,
               pg_namespace  name,
               pg_constraint cons
          WHERE 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      = $1::regclass
        end_sql

        row && row.first
853 854
      end

855
      # Renames a table.
856
      def rename_table(name, new_name)
857
        execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
858
      end
859

860 861
      # Adds a new column to the named table.
      # See TableDefinition#column for details of the options you can use.
S
Scott Barron 已提交
862
      def add_column(table_name, column_name, type, options = {})
863 864
        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)
865

866
        execute add_column_sql
S
Scott Barron 已提交
867
      end
D
Initial  
David Heinemeier Hansson 已提交
868

869 870
      # Changes the column of a table.
      def change_column(table_name, column_name, type, options = {})
871 872
        quoted_table_name = quote_table_name(table_name)

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

875 876
        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)
877
      end
878

879 880
      # Changes the default value of a table column.
      def change_column_default(table_name, column_name, default)
881
        execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
882
      end
883

884 885
      def change_column_null(table_name, column_name, null, default = nil)
        unless null || default.nil?
886
          execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
887
        end
888
        execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
889 890
      end

891 892
      # Renames a column in a table.
      def rename_column(table_name, column_name, new_column_name)
893
        execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
894
      end
895

896 897 898 899
      def remove_index!(table_name, index_name) #:nodoc:
        execute "DROP INDEX #{quote_table_name(index_name)}"
      end

900 901 902 903
      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

904 905
      def index_name_length
        63
906
      end
907

908 909
      # Maps logical Rails types to PostgreSQL-specific data types.
      def type_to_sql(type, limit = nil, precision = nil, scale = nil)
910
        return super unless type.to_s == 'integer'
911
        return 'integer' unless limit
912

913
        case limit
914 915 916
          when 1, 2; 'smallint'
          when 3, 4; 'integer'
          when 5..8; 'bigint'
917
          else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
918 919
        end
      end
920

921
      # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
922 923 924
      #
      # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
      # requires that the ORDER BY include the distinct column.
925
      #
926
      #   distinct("posts.id", "posts.created_at desc")
927 928
      def distinct(columns, orders) #:nodoc:
        return "DISTINCT #{columns}" if orders.empty?
929

930 931
        # Construct a clean list of column names from the ORDER BY clause, removing
        # any ASC/DESC modifiers
932
        order_columns = orders.collect { |s| s =~ /^(.+)\s+(ASC|DESC)\s*$/i ? $1 : s }
933
        order_columns.delete_if { |c| c.blank? }
934
        order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
935

936 937
        # Return a DISTINCT ON() clause that's distinct on the columns we want but includes
        # all the required columns for the ORDER BY to work properly.
938 939
        sql = "DISTINCT ON (#{columns}) #{columns}, "
        sql << order_columns * ', '
940
      end
941

942 943 944 945 946 947 948 949 950
      protected
        # Returns the version of the connected PostgreSQL version.
        def postgresql_version
          @postgresql_version ||=
            if @connection.respond_to?(:server_version)
              @connection.server_version
            else
              # Mimic PGconn.server_version behavior
              begin
951 952 953 954 955 956
                if query('SELECT version()')[0][0] =~ /PostgreSQL ([0-9.]+)/
                  major, minor, tiny = $1.split(".")
                  (major.to_i * 10000) + (minor.to_i * 100) + tiny.to_i
                else
                  0
                end
957 958 959 960 961 962
              rescue
                0
              end
            end
        end

963 964 965
        def translate_exception(exception, message)
          case exception.message
          when /duplicate key value violates unique constraint/
966
            RecordNotUnique.new(message, exception)
967
          when /violates foreign key constraint/
968
            InvalidForeignKey.new(message, exception)
969 970 971 972 973
          else
            super
          end
        end

D
Initial  
David Heinemeier Hansson 已提交
974
      private
975 976 977 978 979 980 981 982 983
      def exec_no_cache(sql, name)
        log(sql, name) do
          result = @connection.async_exec(sql)
          ret = ActiveRecord::Result.new(result.fields, result_as_array(result))
          result.clear
          ret
        end
      end

P
Pratik Naik 已提交
984
        # The internal PostgreSQL identifier of the money data type.
985
        MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
986 987
        # The internal PostgreSQL identifier of the BYTEA data type.
        BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
988 989 990 991 992 993 994 995

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

          # Ignore async_exec and async_query when using postgres-pr.
996
          @async = @connection.respond_to?(:async_exec)
997 998 999 1000

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

1003 1004 1005
          configure_connection
        end

1006
        # Configures the encoding, verbosity, schema search path, and time zone of the connection.
1007
        # This is called by #connect and should not be called manually.
1008 1009
        def configure_connection
          if @config[:encoding]
1010 1011 1012 1013 1014
            if @connection.respond_to?(:set_client_encoding)
              @connection.set_client_encoding(@config[:encoding])
            else
              execute("SET client_encoding TO '#{@config[:encoding]}'")
            end
1015
          end
1016 1017
          self.client_min_messages = @config[:min_messages] if @config[:min_messages]
          self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
1018 1019 1020 1021

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

1022
          # If using Active Record's time zone support configure the connection to return
1023
          # TIMESTAMP WITH ZONE types in UTC.
1024
          if ActiveRecord::Base.default_timezone == :utc
1025
            execute("SET time zone 'UTC'", 'SCHEMA')
1026
          elsif @local_tz
1027
            execute("SET time zone '#{@local_tz}'", 'SCHEMA')
1028
          end
1029 1030
        end

1031
        # Returns the current ID of a table's sequence.
1032 1033 1034
        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 已提交
1035 1036
        end

1037
        # Executes a SELECT query and returns the results, performing any data type
1038
        # conversions that are required to be performed here instead of in PostgreSQLColumn.
1039
        def select(sql, name = nil, binds = [])
A
Aaron Patterson 已提交
1040
          exec_query(sql, name, binds).to_a
1041 1042 1043
        end

        def select_raw(sql, name = nil)
1044
          res = execute(sql, name)
1045
          results = result_as_array(res)
1046
          fields = res.fields
1047
          res.clear
1048
          return fields, results
M
Marcel Molina 已提交
1049 1050
        end

1051
        # Returns the list of a table's column names, data types, and default values.
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
        #
        # 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
1069
        def column_definitions(table_name) #:nodoc:
1070
          exec_query(<<-end_sql, 'SCHEMA').rows
1071
            SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
1072 1073
              FROM pg_attribute a LEFT JOIN pg_attrdef d
                ON a.attrelid = d.adrelid AND a.attnum = d.adnum
1074
             WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
1075 1076 1077
               AND a.attnum > 0 AND NOT a.attisdropped
             ORDER BY a.attnum
          end_sql
D
Initial  
David Heinemeier Hansson 已提交
1078
        end
1079 1080

        def extract_pg_identifier_from_name(name)
1081
          match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
1082 1083

          if match_data
1084 1085
            rest = name[match_data[0].length, name.length]
            rest = rest[1, rest.length] if rest.start_with? "."
1086 1087 1088
            [match_data[1], (rest.length > 0 ? rest : nil)]
          end
        end
1089 1090 1091 1092

      def table_definition
        TableDefinition.new(self)
      end
D
Initial  
David Heinemeier Hansson 已提交
1093 1094 1095
    end
  end
end
1096