postgresql_adapter.rb 44.4 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1
require 'active_record/connection_adapters/abstract_adapter'
2
require 'active_support/core_ext/object/blank'
3
require 'active_record/connection_adapters/statement_pool'
4 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

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

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

      # 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 已提交
26

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

33 34 35 36 37 38 39
  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
40

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

55 56
        def cast_hstore(object)
          if Hash === object
A
Aaron Patterson 已提交
57 58 59
            object.map { |k,v|
              "#{escape_hstore(k)}=>#{escape_hstore(v)}"
            }.join ', '
60
          else
A
Aaron Patterson 已提交
61 62
            kvs = object.scan(/(?<!\\)".*?(?<!\\)"/).map { |o|
              unescape_hstore(o[1...-1])
63
            }
A
Aaron Patterson 已提交
64 65 66 67 68
            Hash[kvs.each_slice(2).to_a]
          end
        end

        private
69 70 71 72 73 74 75 76 77 78
        HSTORE_ESCAPE = {
            ' '  => '\\ ',
            '\\' => '\\\\',
            '"'  => '\\"',
            '='  => '\\=',
        }
        HSTORE_ESCAPE_RE   = Regexp.union(HSTORE_ESCAPE.keys)
        HSTORE_UNESCAPE    = HSTORE_ESCAPE.invert
        HSTORE_UNESCAPE_RE = Regexp.union(HSTORE_UNESCAPE.keys)

A
Aaron Patterson 已提交
79
        def unescape_hstore(value)
80 81
          value.gsub(HSTORE_UNESCAPE_RE) do |match|
            HSTORE_UNESCAPE[match]
A
Aaron Patterson 已提交
82 83 84 85
          end
        end

        def escape_hstore(value)
86 87
          value.gsub(HSTORE_ESCAPE_RE) do |match|
            HSTORE_ESCAPE[match]
88
          end
89
        end
90 91 92
      end
      # :startdoc:

93
      private
94
        def extract_limit(sql_type)
95 96 97 98 99
          case sql_type
          when /^bigint/i;    8
          when /^smallint/i;  2
          else super
          end
100 101
        end

102 103 104 105 106
        # 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
107

108 109
        # Extracts the precision from PostgreSQL-specific data types.
        def extract_precision(sql_type)
110 111 112 113 114
          if sql_type == 'money'
            self.class.money_precision
          else
            super
          end
115
        end
116

117 118 119
        # Maps PostgreSQL-specific data types to logical Rails types.
        def simplified_type(field_type)
          case field_type
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
          # Numeric and monetary types
          when /^(?:real|double precision)$/
            :float
          # Monetary types
          when 'money'
            :decimal
          when 'hstore'
            :hstore
          # Character types
          when /^(?:character varying|bpchar)(?:\(\d+\))?$/
            :string
          # Binary data types
          when 'bytea'
            :binary
          # Date/time types
          when /^timestamp with(?:out)? time zone$/
            :datetime
          when 'interval'
            :string
          # Geometric types
          when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
            :string
          # Network address types
          when /^(?:cidr|inet|macaddr)$/
            :string
          # Bit strings
          when /^bit(?: varying)?(?:\(\d+\))?$/
            :string
          # XML type
          when 'xml'
            :xml
          # tsvector type
          when 'tsvector'
            :tsvector
          # Arrays
          when /^\D+\[\]$/
            :string
          # Object identifier types
          when 'oid'
            :integer
          # UUID type
          when 'uuid'
            :string
          # Small and big integer types
          when /^(?:small|big)int$/
            :integer
          # Pass through all types that are not specific to PostgreSQL.
          else
            super
169 170
          end
        end
171

172 173
        # Extracts the value from a PostgreSQL column default definition.
        def self.extract_value_from_default(default)
A
Aaron Patterson 已提交
174 175 176 177 178 179 180 181
          # 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

182 183
          case default
            # Numeric types
184 185
            when /\A\(?(-?\d+(\.\d*)?\)?)\z/
              $1
186
            # Character types
187
            when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
188
              $1
189 190 191
            # Character types (8.1 formatting)
            when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
              $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
192
            # Binary data types
193
            when /\A'(.*)'::bytea\z/m
194 195
              $1
            # Date/time types
196
            when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
197
              $1
198
            when /\A'(.*)'::interval\z/
199 200
              $1
            # Boolean type
201
            when 'true'
202
              true
203
            when 'false'
204 205
              false
            # Geometric types
206
            when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
207 208
              $1
            # Network address types
209
            when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
210 211
              $1
            # Bit string types
212
            when /\AB'(.*)'::"?bit(?: varying)?"?\z/
213 214
              $1
            # XML type
215
            when /\A'(.*)'::xml\z/m
216 217
              $1
            # Arrays
218
            when /\A'(.*)'::"?\D+"?\[\]\z/
219 220
              $1
            # Object identifier types
221
            when /\A-?\d+\z/
222 223 224
              $1
            else
              # Anything else is blank, some user type, or some function
225
              # and we can't know the value of that, so return nil.
226 227 228
              nil
          end
        end
D
Initial  
David Heinemeier Hansson 已提交
229 230
    end

231
    # The PostgreSQL adapter works with the native C (https://bitbucket.org/ged/ruby-pg) driver.
232 233 234
    #
    # Options:
    #
235 236
    # * <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 已提交
237
    # * <tt>:port</tt> - Defaults to 5432.
238 239 240
    # * <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.
241
    # * <tt>:schema_search_path</tt> - An optional schema search path for the connection given
242
    #   as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
243
    # * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
244
    #   <encoding></tt> call on the connection.
245
    # * <tt>:min_messages</tt> - An optional client min messages that is used in a
246
    #   <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
247 248 249 250 251 252 253
    #
    # 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 .
254
    class PostgreSQLAdapter < AbstractAdapter
255 256 257 258 259
      class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
        def xml(*args)
          options = args.extract_options!
          column(args[0], 'xml', options)
        end
260 261 262 263 264

        def tsvector(*args)
          options = args.extract_options!
          column(args[0], 'tsvector', options)
        end
265 266 267 268

        def hstore(name, options = {})
          column(name, 'hstore', options)
        end
269 270
      end

271
      ADAPTER_NAME = 'PostgreSQL'
272 273

      NATIVE_DATABASE_TYPES = {
274
        :primary_key => "serial primary key",
275 276 277 278 279 280 281 282 283 284
        :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" },
285
        :boolean     => { :name => "boolean" },
286 287
        :xml         => { :name => "xml" },
        :tsvector    => { :name => "tsvector" }
288 289
      }

290
      # Returns 'PostgreSQL' as adapter name for identification purposes.
291
      def adapter_name
292
        ADAPTER_NAME
293 294
      end

295 296
      # Returns +true+, since this connection adapter supports prepared statement
      # caching.
297 298 299 300
      def supports_statement_cache?
        true
      end

301 302 303 304
      def supports_index_sort_order?
        true
      end

305 306 307 308
      class StatementPool < ConnectionAdapters::StatementPool
        def initialize(connection, max)
          super
          @counter = 0
309
          @cache   = Hash.new { |h,pid| h[pid] = {} }
310 311
        end

312 313 314 315
        def each(&block); cache.each(&block); end
        def key?(key);    cache.key?(key); end
        def [](key);      cache[key]; end
        def length;       cache.length; end
316 317 318 319 320 321

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

        def []=(sql, key)
322 323
          while @max <= cache.size
            dealloc(cache.shift.last)
324 325
          end
          @counter += 1
326
          cache[sql] = key
327 328 329
        end

        def clear
330
          cache.each_value do |stmt_key|
331 332
            dealloc stmt_key
          end
333
          cache.clear
334 335
        end

336 337 338 339 340
        def delete(sql_key)
          dealloc cache[sql_key]
          cache.delete sql_key
        end

341
        private
342 343 344 345
        def cache
          @cache[$$]
        end

346
        def dealloc(key)
347 348 349 350 351 352 353
          @connection.query "DEALLOCATE #{key}" if connection_active?
        end

        def connection_active?
          @connection.status == PGconn::CONNECTION_OK
        rescue PGError
          false
354 355 356
        end
      end

357 358
      # Initializes and connects a PostgreSQL adapter.
      def initialize(connection, logger, connection_parameters, config)
359
        super(connection, logger)
360
        @connection_parameters, @config = connection_parameters, config
361
        @visitor = Arel::Visitors::PostgreSQL.new self
362

363 364
        # @local_tz is initialized as nil to avoid warnings when connect tries to use it
        @local_tz = nil
365 366
        @table_alias_length = nil

367
        connect
368 369
        @statements = StatementPool.new @connection,
                                        config.fetch(:statement_limit) { 1000 }
370 371 372 373 374

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

375
        @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
376 377
      end

X
Xavier Noria 已提交
378
      # Clears the prepared statements cache.
379 380 381 382
      def clear_cache!
        @statements.clear
      end

383 384
      # Is this connection alive and ready for queries?
      def active?
385 386
        @connection.status == PGconn::CONNECTION_OK
      rescue PGError
387
        false
388 389 390 391
      end

      # Close then reopen the connection.
      def reconnect!
392 393 394
        clear_cache!
        @connection.reset
        configure_connection
395
      end
396

397 398 399 400 401
      def reset!
        clear_cache!
        super
      end

402 403
      # Disconnects from the database if already connected. Otherwise, this
      # method does nothing.
404
      def disconnect!
405
        clear_cache!
406 407
        @connection.close rescue nil
      end
408

409
      def native_database_types #:nodoc:
410
        NATIVE_DATABASE_TYPES
411
      end
412

413
      # Returns true, since this connection adapter supports migrations.
414 415
      def supports_migrations?
        true
416 417
      end

418
      # Does PostgreSQL support finding primary key on non-Active Record tables?
419 420 421 422
      def supports_primary_key? #:nodoc:
        true
      end

423 424 425
      # Enable standard-conforming strings if available.
      def set_standard_conforming_strings
        old, self.client_min_messages = client_min_messages, 'panic'
426
        execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
427 428
      ensure
        self.client_min_messages = old
429 430
      end

431
      def supports_insert_with_returning?
432
        true
433 434
      end

435 436 437
      def supports_ddl_transactions?
        true
      end
438

439
      # Returns true, since this connection adapter supports savepoints.
440 441 442
      def supports_savepoints?
        true
      end
443

444 445 446 447 448
      # Returns true.
      def supports_explain?
        true
      end

449
      # Returns the configured supported identifier length supported by PostgreSQL
450
      def table_alias_length
451
        @table_alias_length ||= query('SHOW max_identifier_length')[0][0].to_i
452
      end
453

454 455
      # QUOTING ==================================================

456
      # Escapes binary strings for bytea input to the database.
457 458
      def escape_bytea(value)
        @connection.escape_bytea(value) if value
459 460 461 462 463
      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.
464 465
      def unescape_bytea(value)
        @connection.unescape_bytea(value) if value
466 467
      end

468 469
      # Quotes PostgreSQL-specific data types for SQL input.
      def quote(value, column = nil) #:nodoc:
470 471
        return super unless column

A
Aaron Patterson 已提交
472
        case value
473 474 475
        when Float
          return super unless value.infinite? && column.type == :datetime
          "'#{value.to_s.downcase}'"
A
Aaron Patterson 已提交
476 477
        when Numeric
          return super unless column.sql_type == 'money'
478
          # Not truly string input, so doesn't require (or allow) escape string syntax.
479
          "'#{value}'"
A
Aaron Patterson 已提交
480 481 482 483 484 485 486 487 488 489 490
        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
491
          end
492 493 494 495 496
        else
          super
        end
      end

497 498 499 500 501 502
      def type_cast(value, column)
        return super unless column

        case value
        when String
          return super unless 'bytea' == column.sql_type
503
          { :value => value, :format => 1 }
504 505 506 507 508
        else
          super
        end
      end

509 510 511
      # Quotes strings for use in SQL input.
      def quote_string(s) #:nodoc:
        @connection.escape(s)
512 513
      end

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
      # 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

533 534
      # Quotes column names for use in SQL queries.
      def quote_column_name(name) #:nodoc:
535
        PGconn.quote_ident(name.to_s)
536 537
      end

538 539 540
      # 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:
541 542 543 544 545
        if value.acts_like?(:time) && value.respond_to?(:usec)
          "#{super}.#{sprintf("%06d", value.usec)}"
        else
          super
        end
546 547
      end

548 549
      # Set the authorized user for this session
      def session_auth=(user)
550
        clear_cache!
A
Aaron Patterson 已提交
551
        exec_query "SET SESSION AUTHORIZATION #{user}"
552 553
      end

554 555
      # REFERENTIAL INTEGRITY ====================================

556
      def supports_disable_referential_integrity? #:nodoc:
557
        true
558 559
      end

560
      def disable_referential_integrity #:nodoc:
561
        if supports_disable_referential_integrity? then
562 563
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
        end
564 565
        yield
      ensure
566
        if supports_disable_referential_integrity? then
567 568
          execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
        end
569
      end
570 571 572

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

573
      def explain(arel, binds = [])
X
Xavier Noria 已提交
574
        sql = "EXPLAIN #{to_sql(arel)}"
575
        ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
X
Xavier Noria 已提交
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
      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

615 616 617 618 619 620
      # 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

621
      # Executes an INSERT query and returns the new record's ID
622
      def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
623 624 625 626 627
        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
628

629
        if pk
630 631 632
          select_value("#{sql} RETURNING #{quote_column_name(pk)}")
        else
          super
633
        end
634
      end
635
      alias :create :insert
636

637 638
      # create a 2D array representing the result set
      def result_as_array(res) #:nodoc:
639
        # check if we have any binary column and if they need escaping
640 641
        ftypes = Array.new(res.nfields) do |i|
          [i, res.ftype(i)]
642 643
        end

644 645 646 647 648 649
        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 }
650 651
        binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
        monies   = typehash[MONEY_COLUMN_TYPE_OID] || []
652 653 654

        rows.each do |row|
          # unescape string passed BYTEA field (OID == 17)
655 656
          binaries.each do |index, _|
            row[index] = unescape_bytea(row[index])
657 658 659 660 661 662
          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.
663
          monies.each do |index, _|
664 665 666 667 668 669 670 671 672 673
            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!(/,/, '.')
674
            end
675 676 677 678 679 680
          end
        end
      end


      # Queries the database and returns the results in an Array-like object
681
      def query(sql, name = nil) #:nodoc:
682
        log(sql, name) do
683
          result_as_array @connection.async_exec(sql)
684
        end
685 686
      end

687
      # Executes an SQL statement, returning a PGresult object on success
688 689
      # or raising a PGError exception otherwise.
      def execute(sql, name = nil)
690
        log(sql, name) do
691
          @connection.async_exec(sql)
692
        end
693 694
      end

695 696
      def substitute_at(column, index)
        Arel.sql("$#{index + 1}")
697 698
      end

A
Aaron Patterson 已提交
699
      def exec_query(sql, name = 'SQL', binds = [])
700
        log(sql, name, binds) do
701 702
          result = binds.empty? ? exec_no_cache(sql, binds) :
                                  exec_cache(sql, binds)
703

704 705 706
          ret = ActiveRecord::Result.new(result.fields, result_as_array(result))
          result.clear
          return ret
707 708 709
        end
      end

710 711 712 713 714 715 716 717 718
      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
719
      alias :exec_update :exec_delete
720

721 722
      def sql_for_insert(sql, pk, id_value, sequence_name, binds)
        unless pk
723 724 725
          # 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
726 727 728 729 730 731 732
        end

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

        [sql, binds]
      end

733
      # Executes an UPDATE query and returns the number of affected tuples.
734
      def update_sql(sql, name = nil)
735
        super.cmd_tuples
736 737
      end

738 739
      # Begins a transaction.
      def begin_db_transaction
740 741 742
        execute "BEGIN"
      end

743 744
      # Commits a transaction.
      def commit_db_transaction
745 746
        execute "COMMIT"
      end
747

748 749
      # Aborts a transaction.
      def rollback_db_transaction
750 751
        execute "ROLLBACK"
      end
752

753 754
      def outside_transaction?
        @connection.transaction_status == PGconn::PQTRANS_IDLE
755
      end
756

J
Jonathan Viney 已提交
757 758 759 760 761 762 763 764
      def create_savepoint
        execute("SAVEPOINT #{current_savepoint_name}")
      end

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

765
      def release_savepoint
J
Jonathan Viney 已提交
766 767
        execute("RELEASE SAVEPOINT #{current_savepoint_name}")
      end
768

769 770
      # SCHEMA STATEMENTS ========================================

771 772 773
      # Drops the database specified on the +name+ attribute
      # and creates it again using the provided +options+.
      def recreate_database(name, options = {}) #:nodoc:
774
        drop_database(name)
775
        create_database(name, options)
776 777
      end

778
      # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
779 780
      # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
      # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
781 782 783 784 785 786 787 788 789 790
      #
      # 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
791
            " OWNER = \"#{value}\""
792
          when :template
793
            " TEMPLATE = \"#{value}\""
794 795 796
          when :encoding
            " ENCODING = '#{value}'"
          when :tablespace
797
            " TABLESPACE = \"#{value}\""
798 799 800 801 802 803 804
          when :connection_limit
            " CONNECTION LIMIT = #{value}"
          else
            ""
          end
        end

805
        execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
806 807
      end

808
      # Drops a PostgreSQL database.
809 810 811 812
      #
      # Example:
      #   drop_database 'matt_development'
      def drop_database(name) #:nodoc:
813
        execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
814 815
      end

816 817
      # Returns the list of all tables in the schema search path or a specified schema.
      def tables(name = nil)
818
        query(<<-SQL, 'SCHEMA').map { |row| row[0] }
819
          SELECT tablename
820 821 822 823 824
          FROM pg_tables
          WHERE schemaname = ANY (current_schemas(false))
        SQL
      end

825
      # Returns true if table exists.
826 827
      # 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)
828
      def table_exists?(name)
829
        schema, table = Utils.extract_schema_and_table(name.to_s)
830
        return false unless table
831

832 833
        binds = [[nil, table]]
        binds << [nil, schema] if schema
834 835

        exec_query(<<-SQL, 'SCHEMA', binds).rows.first[0].to_i > 0
836
            SELECT COUNT(*)
A
Aaron Patterson 已提交
837 838 839 840 841
            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))'}
842 843 844
        SQL
      end

845 846 847 848 849 850 851 852
      # 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
853

854
      # Returns an array of indexes for the given table.
855
      def indexes(table_name, name = nil)
856
         result = query(<<-SQL, name)
857
           SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
858 859 860
           FROM pg_class t
           INNER JOIN pg_index d ON t.oid = d.indrelid
           INNER JOIN pg_class i ON d.indexrelid = i.oid
861 862 863
           WHERE i.relkind = 'i'
             AND d.indisprimary = 'f'
             AND t.relname = '#{table_name}'
864
             AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
865 866 867
          ORDER BY i.relname
        SQL

868

869
        result.map do |row|
870 871 872
          index_name = row[0]
          unique = row[1] == 't'
          indkey = row[2].split(" ")
873 874
          inddef = row[3]
          oid = row[4]
875

876 877
          columns = Hash[query(<<-SQL, "Columns for index #{row[0]} on #{table_name}")]
          SELECT a.attnum, a.attname
878 879 880 881 882
          FROM pg_attribute a
          WHERE a.attrelid = #{oid}
          AND a.attnum IN (#{indkey.join(",")})
          SQL

883
          column_names = columns.values_at(*indkey).compact
884 885 886 887

          # 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]}] : {}
J
Jon Leighton 已提交
888

889
          column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names, [], orders)
890
        end.compact
891 892
      end

893 894
      # Returns the list of all column definitions for a table.
      def columns(table_name, name = nil)
895
        # Limit, precision, and scale are all handled by the superclass.
896 897
        column_definitions(table_name).collect do |column_name, type, default, notnull|
          PostgreSQLColumn.new(column_name, default, type, notnull == 'f')
D
Initial  
David Heinemeier Hansson 已提交
898 899 900
        end
      end

901 902 903 904 905
      # Returns the current database name.
      def current_database
        query('select current_database()')[0][0]
      end

906 907 908 909 910
      # Returns the current schema name.
      def current_schema
        query('SELECT current_schema', 'SCHEMA')[0][0]
      end

911 912 913 914 915 916 917 918
      # 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

919 920 921 922 923 924
      # 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)
925 926
        if schema_csv
          execute "SET search_path TO #{schema_csv}"
927
          @schema_search_path = schema_csv
928
        end
D
Initial  
David Heinemeier Hansson 已提交
929 930
      end

931 932
      # Returns the active schema search path.
      def schema_search_path
X
Xavier Noria 已提交
933
        @schema_search_path ||= query('SHOW search_path', 'SCHEMA')[0][0]
934
      end
935

936 937
      # Returns the current client message level.
      def client_min_messages
938
        query('SHOW client_min_messages', 'SCHEMA')[0][0]
939 940 941 942
      end

      # Set the client message level.
      def client_min_messages=(level)
943
        execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
944 945 946 947
      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:
948 949 950 951 952 953 954 955 956 957
        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
958 959
      end

960 961
      # Resets the sequence of a table's primary key to the maximum value.
      def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
962 963
        unless pk and sequence
          default_pk, default_sequence = pk_and_sequence_for(table)
964

965 966 967
          pk ||= default_pk
          sequence ||= default_sequence
        end
968

969 970 971 972 973
        if @logger && pk && !sequence
          @logger.warn "#{table} has primary key #{pk} with no default sequence"
        end

        if pk && sequence
974
          quoted_sequence = quote_table_name(sequence)
G
Guillermo Iguaran 已提交
975

976 977 978
          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
979 980 981
        end
      end

982 983
      # Returns a table's primary key and belonging sequence.
      def pk_and_sequence_for(table) #:nodoc:
984 985
        # First try looking for a sequence with a dependency on the
        # given table's primary key.
986
        result = exec_query(<<-end_sql, 'SCHEMA').rows.first
987
          SELECT attr.attname, ns.nspname, seq.relname
988
          FROM pg_class seq
A
Akira Matsuda 已提交
989
          INNER JOIN pg_depend dep ON seq.oid = dep.objid
990 991
          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]
992
          INNER JOIN pg_namespace ns ON seq.relnamespace = ns.oid
993 994 995
          WHERE seq.relkind  = 'S'
            AND cons.contype = 'p'
            AND dep.refobjid = '#{quote_table_name(table)}'::regclass
996
        end_sql
997

998
        # [primary_key, sequence]
999 1000 1001 1002 1003
        if result.second ==  'public' then
          sequence = result.last
        else
          sequence = result.second+'.'+result.last
        end
G
Guillermo Iguaran 已提交
1004

1005
        [result.first, sequence]
1006 1007
      rescue
        nil
1008 1009
      end

1010 1011
      # Returns just a table's primary key
      def primary_key(table)
1012
        row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first
1013
          SELECT DISTINCT(attr.attname)
1014 1015 1016 1017 1018
          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
1019 1020 1021
        end_sql

        row && row.first
1022 1023
      end

1024
      # Renames a table.
1025 1026 1027
      #
      # Example:
      #   rename_table('octopuses', 'octopi')
1028
      def rename_table(name, new_name)
1029
        clear_cache!
1030
        execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
1031
      end
1032

1033 1034
      # Adds a new column to the named table.
      # See TableDefinition#column for details of the options you can use.
S
Scott Barron 已提交
1035
      def add_column(table_name, column_name, type, options = {})
1036
        clear_cache!
1037 1038
        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)
1039

1040
        execute add_column_sql
S
Scott Barron 已提交
1041
      end
D
Initial  
David Heinemeier Hansson 已提交
1042

1043 1044
      # Changes the column of a table.
      def change_column(table_name, column_name, type, options = {})
1045
        clear_cache!
1046 1047
        quoted_table_name = quote_table_name(table_name)

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

1050 1051
        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)
1052
      end
1053

1054 1055
      # Changes the default value of a table column.
      def change_column_default(table_name, column_name, default)
1056
        clear_cache!
1057
        execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
1058
      end
1059

1060
      def change_column_null(table_name, column_name, null, default = nil)
1061
        clear_cache!
1062
        unless null || default.nil?
1063
          execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
1064
        end
1065
        execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
1066 1067
      end

1068 1069
      # Renames a column in a table.
      def rename_column(table_name, column_name, new_column_name)
1070
        clear_cache!
1071
        execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
1072
      end
1073

1074 1075 1076 1077
      def remove_index!(table_name, index_name) #:nodoc:
        execute "DROP INDEX #{quote_table_name(index_name)}"
      end

1078 1079 1080 1081
      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

1082 1083
      def index_name_length
        63
1084
      end
1085

1086 1087
      # Maps logical Rails types to PostgreSQL-specific data types.
      def type_to_sql(type, limit = nil, precision = nil, scale = nil)
1088
        return super unless type.to_s == 'integer'
1089
        return 'integer' unless limit
1090

1091
        case limit
1092 1093 1094
          when 1, 2; 'smallint'
          when 3, 4; 'integer'
          when 5..8; 'bigint'
1095
          else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
1096 1097
        end
      end
1098

1099
      # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
1100 1101 1102
      #
      # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
      # requires that the ORDER BY include the distinct column.
1103
      #
1104
      #   distinct("posts.id", "posts.created_at desc")
1105 1106
      def distinct(columns, orders) #:nodoc:
        return "DISTINCT #{columns}" if orders.empty?
1107

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

1114
        "DISTINCT #{columns}, #{order_columns * ', '}"
1115
      end
1116

1117
      module Utils
1118 1119
        extend self

1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
        # 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>
1130
        def extract_schema_and_table(name)
1131 1132 1133 1134 1135
          table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse
          [schema, table]
        end
      end

1136
      protected
1137
        # Returns the version of the connected PostgreSQL server.
1138
        def postgresql_version
1139
          @connection.server_version
1140 1141
        end

1142 1143 1144
        def translate_exception(exception, message)
          case exception.message
          when /duplicate key value violates unique constraint/
1145
            RecordNotUnique.new(message, exception)
1146
          when /violates foreign key constraint/
1147
            InvalidForeignKey.new(message, exception)
1148 1149 1150 1151 1152
          else
            super
          end
        end

D
Initial  
David Heinemeier Hansson 已提交
1153
      private
1154 1155
        FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:

1156 1157
        def exec_no_cache(sql, binds)
          @connection.async_exec(sql)
1158
        end
1159

1160
        def exec_cache(sql, binds)
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
          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
            code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
            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)
1196
          unless @statements.key? sql_key
1197
            nextkey = @statements.next_key
1198
            @connection.prepare nextkey, sql
1199
            @statements[sql_key] = nextkey
1200
          end
1201
          @statements[sql_key]
1202
        end
1203

P
Pratik Naik 已提交
1204
        # The internal PostgreSQL identifier of the money data type.
1205
        MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
1206 1207
        # The internal PostgreSQL identifier of the BYTEA data type.
        BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
1208 1209 1210 1211

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

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

1219 1220 1221
          configure_connection
        end

1222
        # Configures the encoding, verbosity, schema search path, and time zone of the connection.
1223
        # This is called by #connect and should not be called manually.
1224 1225
        def configure_connection
          if @config[:encoding]
1226
            @connection.set_client_encoding(@config[:encoding])
1227
          end
1228 1229
          self.client_min_messages = @config[:min_messages] if @config[:min_messages]
          self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
1230 1231 1232 1233

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

1234
          # If using Active Record's time zone support configure the connection to return
1235
          # TIMESTAMP WITH ZONE types in UTC.
1236
          if ActiveRecord::Base.default_timezone == :utc
1237
            execute("SET time zone 'UTC'", 'SCHEMA')
1238
          elsif @local_tz
1239
            execute("SET time zone '#{@local_tz}'", 'SCHEMA')
1240
          end
1241 1242
        end

1243
        # Returns the current ID of a table's sequence.
1244 1245 1246
        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 已提交
1247 1248
        end

1249
        # Executes a SELECT query and returns the results, performing any data type
1250
        # conversions that are required to be performed here instead of in PostgreSQLColumn.
1251
        def select(sql, name = nil, binds = [])
1252
          exec_query(sql, name, binds)
1253 1254 1255
        end

        def select_raw(sql, name = nil)
1256
          res = execute(sql, name)
1257
          results = result_as_array(res)
1258
          fields = res.fields
1259
          res.clear
1260
          return fields, results
M
Marcel Molina 已提交
1261 1262
        end

1263
        # Returns the list of a table's column names, data types, and default values.
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
        #
        # 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
1281
        def column_definitions(table_name) #:nodoc:
1282
          exec_query(<<-end_sql, 'SCHEMA').rows
1283
            SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
1284 1285
              FROM pg_attribute a LEFT JOIN pg_attrdef d
                ON a.attrelid = d.adrelid AND a.attnum = d.adnum
1286
             WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
1287 1288 1289
               AND a.attnum > 0 AND NOT a.attisdropped
             ORDER BY a.attnum
          end_sql
D
Initial  
David Heinemeier Hansson 已提交
1290
        end
1291 1292

        def extract_pg_identifier_from_name(name)
1293
          match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
1294 1295

          if match_data
1296 1297
            rest = name[match_data[0].length, name.length]
            rest = rest[1, rest.length] if rest.start_with? "."
J
José Valim 已提交
1298
            [match_data[1], (rest.length > 0 ? rest : nil)]
1299 1300
          end
        end
1301

1302 1303 1304 1305 1306
        def extract_table_ref_from_insert_sql(sql)
          sql[/into\s+([^\(]*).*values\s*\(/i]
          $1.strip if $1
        end

1307 1308 1309
        def table_definition
          TableDefinition.new(self)
        end
D
Initial  
David Heinemeier Hansson 已提交
1310 1311 1312
    end
  end
end