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
      config = config.symbolize_keys
D
Initial  
David Heinemeier Hansson 已提交
14

15 16 17 18
      # Forward any unused config params to PGconn.connect.
      conn_params = config.except(:statement_limit, :encoding, :min_messages,
                                  :schema_search_path, :schema_order,
                                  :adapter, :pool, :wait_timeout)
19
      conn_params.delete_if { |k,v| v.nil? }
20 21 22 23

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

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

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

39 40 41
      # :stopdoc:
      class << self
        attr_accessor :money_precision
42 43 44 45 46 47 48 49 50 51
        def string_to_time(string)
          return string unless String === string

          case string
          when 'infinity'  then 1.0 / 0.0
          when '-infinity' then -1.0 / 0.0
          else
            super
          end
        end
52

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

        private
67 68 69 70 71 72 73 74 75 76
        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 已提交
77
        def unescape_hstore(value)
78 79
          value.gsub(HSTORE_UNESCAPE_RE) do |match|
            HSTORE_UNESCAPE[match]
A
Aaron Patterson 已提交
80 81 82 83
          end
        end

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

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

100 101 102 103 104
        # 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
105

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

115 116 117
        # Maps PostgreSQL-specific data types to logical Rails types.
        def simplified_type(field_type)
          case field_type
118 119 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
          # 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
167 168
          end
        end
169

170 171 172
        # Extracts the value from a PostgreSQL column default definition.
        def self.extract_value_from_default(default)
          case default
173 174 175 176 177 178 179 180
            # This is a performance optimization for Ruby 1.9.2 in development.
            # If the value is nil, we return nil straight away without checking
            # the regular expressions. If we check each regular expression,
            # Regexp#=== will call NilClass#to_str, which will trigger
            # method_missing (defined by whiny nil in ActiveSupport) which
            # makes this method very very slow.
            when NilClass
              nil
181
            # Numeric types
182 183
            when /\A\(?(-?\d+(\.\d*)?\)?)\z/
              $1
184
            # Character types
185
            when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
186
              $1
187 188 189
            # Character types (8.1 formatting)
            when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
              $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
190
            # Binary data types
191
            when /\A'(.*)'::bytea\z/m
192 193
              $1
            # Date/time types
194
            when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
195
              $1
196
            when /\A'(.*)'::interval\z/
197 198
              $1
            # Boolean type
199
            when 'true'
200
              true
201
            when 'false'
202 203
              false
            # Geometric types
204
            when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
205 206
              $1
            # Network address types
207
            when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
208 209
              $1
            # Bit string types
210
            when /\AB'(.*)'::"?bit(?: varying)?"?\z/
211 212
              $1
            # XML type
213
            when /\A'(.*)'::xml\z/m
214 215
              $1
            # Arrays
216
            when /\A'(.*)'::"?\D+"?\[\]\z/
217 218
              $1
            # Object identifier types
219
            when /\A-?\d+\z/
220 221 222
              $1
            else
              # Anything else is blank, some user type, or some function
223
              # and we can't know the value of that, so return nil.
224 225 226
              nil
          end
        end
D
Initial  
David Heinemeier Hansson 已提交
227 228
    end

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

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

        def hstore(name, options = {})
          column(name, 'hstore', options)
        end
267 268
      end

269
      ADAPTER_NAME = 'PostgreSQL'
270 271

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

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

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

299 300 301 302
      def supports_index_sort_order?
        true
      end

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

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

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

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

        def clear
328
          cache.each_value do |stmt_key|
329 330
            dealloc stmt_key
          end
331
          cache.clear
332 333
        end

334 335 336 337 338
        def delete(sql_key)
          dealloc cache[sql_key]
          cache.delete sql_key
        end

339
        private
340 341 342 343
        def cache
          @cache[$$]
        end

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

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

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

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

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

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

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

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

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

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

395 396 397 398 399
      def reset!
        clear_cache!
        super
      end

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

407
      def native_database_types #:nodoc:
408
        NATIVE_DATABASE_TYPES
409
      end
410

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

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

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

429
      def supports_insert_with_returning?
430
        true
431 432
      end

433 434 435
      def supports_ddl_transactions?
        true
      end
436

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

442 443 444 445 446
      # Returns true.
      def supports_explain?
        true
      end

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

452 453
      # QUOTING ==================================================

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

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

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

495 496 497 498 499 500
      def type_cast(value, column)
        return super unless column

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

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

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

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

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

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

552 553
      # REFERENTIAL INTEGRITY ====================================

554
      def supports_disable_referential_integrity? #:nodoc:
555
        true
556 557
      end

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

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

571
      def explain(arel, binds = [])
X
Xavier Noria 已提交
572
        sql = "EXPLAIN #{to_sql(arel)}"
573
        ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
X
Xavier Noria 已提交
574 575 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
      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

613 614 615 616 617 618
      # 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

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

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

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

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

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


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

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

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

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

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

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

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

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

        [sql, binds]
      end

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

736 737
      # Begins a transaction.
      def begin_db_transaction
738 739 740
        execute "BEGIN"
      end

741 742
      # Commits a transaction.
      def commit_db_transaction
743 744
        execute "COMMIT"
      end
745

746 747
      # Aborts a transaction.
      def rollback_db_transaction
748 749
        execute "ROLLBACK"
      end
750

751 752
      def outside_transaction?
        @connection.transaction_status == PGconn::PQTRANS_IDLE
753
      end
754

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

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

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

767 768
      # SCHEMA STATEMENTS ========================================

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

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

803
        execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
804 805
      end

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

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

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

830 831
        binds = [[nil, table]]
        binds << [nil, schema] if schema
832 833

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

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

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

866

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

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

881
          column_names = columns.values_at(*indkey).compact
882 883 884 885

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

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

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

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

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

909 910 911 912 913 914 915 916
      # 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

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

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

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

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

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

963 964 965
          pk ||= default_pk
          sequence ||= default_sequence
        end
966

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

        if pk && sequence
972
          quoted_sequence = quote_table_name(sequence)
G
Guillermo Iguaran 已提交
973

974 975 976
          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
977 978 979
        end
      end

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

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

1003
        [result.first, sequence]
1004 1005
      rescue
        nil
1006 1007
      end

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

        row && row.first
1020 1021
      end

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

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

1038
        execute add_column_sql
S
Scott Barron 已提交
1039
      end
D
Initial  
David Heinemeier Hansson 已提交
1040

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

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

1048 1049
        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)
1050
      end
1051

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

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

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

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

1076 1077 1078 1079
      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

1080 1081
      def index_name_length
        63
1082
      end
1083

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

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

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

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

1112
        "DISTINCT #{columns}, #{order_columns * ', '}"
1113
      end
1114

1115
      module Utils
1116 1117
        extend self

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

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

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

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

1154 1155
        def exec_no_cache(sql, binds)
          @connection.async_exec(sql)
1156
        end
1157

1158
        def exec_cache(sql, binds)
1159 1160 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
          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)
1194
          unless @statements.key? sql_key
1195
            nextkey = @statements.next_key
1196
            @connection.prepare nextkey, sql
1197
            @statements[sql_key] = nextkey
1198
          end
1199
          @statements[sql_key]
1200
        end
1201

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

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

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

1217 1218 1219
          configure_connection
        end

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

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

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

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

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

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

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

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

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

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

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