activerecord 1.10.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +187 -19
 - data/RUNNING_UNIT_TESTS +11 -0
 - data/lib/active_record.rb +3 -1
 - data/lib/active_record/acts/list.rb +25 -14
 - data/lib/active_record/acts/nested_set.rb +4 -4
 - data/lib/active_record/acts/tree.rb +18 -1
 - data/lib/active_record/associations.rb +90 -17
 - data/lib/active_record/associations/association_collection.rb +44 -5
 - data/lib/active_record/associations/has_and_belongs_to_many_association.rb +17 -4
 - data/lib/active_record/associations/has_many_association.rb +13 -3
 - data/lib/active_record/associations/has_one_association.rb +19 -0
 - data/lib/active_record/base.rb +292 -268
 - data/lib/active_record/callbacks.rb +14 -14
 - data/lib/active_record/connection_adapters/abstract_adapter.rb +137 -75
 - data/lib/active_record/connection_adapters/db2_adapter.rb +10 -8
 - data/lib/active_record/connection_adapters/mysql_adapter.rb +91 -64
 - data/lib/active_record/connection_adapters/oci_adapter.rb +6 -6
 - data/lib/active_record/connection_adapters/postgresql_adapter.rb +113 -60
 - data/lib/active_record/connection_adapters/sqlite_adapter.rb +15 -12
 - data/lib/active_record/connection_adapters/sqlserver_adapter.rb +159 -132
 - data/lib/active_record/fixtures.rb +59 -12
 - data/lib/active_record/locking.rb +10 -9
 - data/lib/active_record/migration.rb +112 -5
 - data/lib/active_record/query_cache.rb +64 -0
 - data/lib/active_record/timestamp.rb +10 -8
 - data/lib/active_record/validations.rb +121 -26
 - data/rakefile +16 -10
 - data/test/aaa_create_tables_test.rb +26 -48
 - data/test/abstract_unit.rb +3 -0
 - data/test/aggregations_test.rb +19 -19
 - data/test/association_callbacks_test.rb +110 -0
 - data/test/associations_go_eager_test.rb +48 -14
 - data/test/associations_test.rb +344 -142
 - data/test/base_test.rb +150 -31
 - data/test/binary_test.rb +7 -0
 - data/test/callbacks_test.rb +24 -5
 - data/test/column_alias_test.rb +2 -2
 - data/test/connections/native_sqlserver_odbc/connection.rb +26 -0
 - data/test/deprecated_associations_test.rb +27 -28
 - data/test/deprecated_finder_test.rb +8 -9
 - data/test/finder_test.rb +52 -17
 - data/test/fixtures/author.rb +39 -0
 - data/test/fixtures/categories.yml +7 -0
 - data/test/fixtures/categories_posts.yml +8 -0
 - data/test/fixtures/category.rb +2 -0
 - data/test/fixtures/comment.rb +3 -1
 - data/test/fixtures/comments.yml +43 -1
 - data/test/fixtures/companies.yml +14 -0
 - data/test/fixtures/company.rb +1 -1
 - data/test/fixtures/computers.yml +2 -1
 - data/test/fixtures/db_definitions/db2.sql +7 -2
 - data/test/fixtures/db_definitions/mysql.drop.sql +2 -0
 - data/test/fixtures/db_definitions/mysql.sql +11 -6
 - data/test/fixtures/db_definitions/oci.sql +7 -2
 - data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
 - data/test/fixtures/db_definitions/postgresql.sql +8 -5
 - data/test/fixtures/db_definitions/sqlite.drop.sql +2 -0
 - data/test/fixtures/db_definitions/sqlite.sql +9 -4
 - data/test/fixtures/db_definitions/sqlserver.drop.sql +2 -0
 - data/test/fixtures/db_definitions/sqlserver.sql +12 -7
 - data/test/fixtures/developer.rb +8 -1
 - data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
 - data/test/fixtures/post.rb +8 -2
 - data/test/fixtures/posts.yml +21 -0
 - data/test/fixtures/project.rb +14 -1
 - data/test/fixtures/subscriber.rb +3 -0
 - data/test/fixtures_test.rb +14 -0
 - data/test/inheritance_test.rb +30 -22
 - data/test/lifecycle_test.rb +3 -4
 - data/test/locking_test.rb +2 -4
 - data/test/migration_test.rb +186 -0
 - data/test/mixin_nested_set_test.rb +19 -19
 - data/test/mixin_test.rb +88 -88
 - data/test/modules_test.rb +5 -10
 - data/test/multiple_db_test.rb +2 -0
 - data/test/pk_test.rb +8 -12
 - data/test/reflection_test.rb +8 -4
 - data/test/schema_test_postgresql.rb +63 -0
 - data/test/thread_safety_test.rb +4 -1
 - data/test/transactions_test.rb +9 -2
 - data/test/unconnected_test.rb +1 -0
 - data/test/validations_test.rb +151 -8
 - metadata +11 -5
 - data/test/migration_mysql.rb +0 -104
 
| 
         @@ -52,8 +52,8 @@ begin 
     | 
|
| 
       52 
52 
     | 
    
         
             
                    def execute(sql, name = nil)
         
     | 
| 
       53 
53 
     | 
    
         
             
                      rows_affected = 0
         
     | 
| 
       54 
54 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                      log(sql, name 
     | 
| 
       56 
     | 
    
         
            -
                        stmt = DB2::Statement.new(connection)
         
     | 
| 
      
 55 
     | 
    
         
            +
                      log(sql, name) do
         
     | 
| 
      
 56 
     | 
    
         
            +
                        stmt = DB2::Statement.new(@connection)
         
     | 
| 
       57 
57 
     | 
    
         
             
                        stmt.exec_direct(sql)
         
     | 
| 
       58 
58 
     | 
    
         
             
                        rows_affected = stmt.row_count
         
     | 
| 
       59 
59 
     | 
    
         
             
                        stmt.free
         
     | 
| 
         @@ -79,14 +79,16 @@ begin 
     | 
|
| 
       79 
79 
     | 
    
         
             
                      @connection.set_auto_commit_on
         
     | 
| 
       80 
80 
     | 
    
         
             
                    end
         
     | 
| 
       81 
81 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                    def quote_column_name( 
     | 
| 
      
 82 
     | 
    
         
            +
                    def quote_column_name(column_name)
         
     | 
| 
      
 83 
     | 
    
         
            +
                      column_name
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
       83 
85 
     | 
    
         | 
| 
       84 
86 
     | 
    
         
             
                    def adapter_name()
         
     | 
| 
       85 
87 
     | 
    
         
             
                      'DB2'
         
     | 
| 
       86 
88 
     | 
    
         
             
                    end
         
     | 
| 
       87 
89 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
                    def quote_string( 
     | 
| 
       89 
     | 
    
         
            -
                       
     | 
| 
      
 90 
     | 
    
         
            +
                    def quote_string(string)
         
     | 
| 
      
 91 
     | 
    
         
            +
                      string.gsub(/'/, "''") # ' (for ruby-mode)
         
     | 
| 
       90 
92 
     | 
    
         
             
                    end
         
     | 
| 
       91 
93 
     | 
    
         | 
| 
       92 
94 
     | 
    
         
             
                    def add_limit_with_offset!(sql, limit, offset)
         
     | 
| 
         @@ -124,9 +126,9 @@ begin 
     | 
|
| 
       124 
126 
     | 
    
         | 
| 
       125 
127 
     | 
    
         
             
                    def select(sql, name = nil)
         
     | 
| 
       126 
128 
     | 
    
         
             
                      stmt = nil
         
     | 
| 
       127 
     | 
    
         
            -
                      log(sql, name 
     | 
| 
       128 
     | 
    
         
            -
                        stmt = DB2::Statement.new(connection)
         
     | 
| 
       129 
     | 
    
         
            -
                        stmt.exec_direct(sql  
     | 
| 
      
 129 
     | 
    
         
            +
                      log(sql, name) do
         
     | 
| 
      
 130 
     | 
    
         
            +
                        stmt = DB2::Statement.new(@connection)
         
     | 
| 
      
 131 
     | 
    
         
            +
                        stmt.exec_direct("#{sql} with ur")
         
     | 
| 
       130 
132 
     | 
    
         
             
                      end
         
     | 
| 
       131 
133 
     | 
    
         | 
| 
       132 
134 
     | 
    
         
             
                      rows = []
         
     | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'active_record/connection_adapters/abstract_adapter'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'parsedate'
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
       4 
4 
     | 
    
         
             
            module ActiveRecord
         
     | 
| 
       5 
5 
     | 
    
         
             
              class Base
         
     | 
| 
       6 
6 
     | 
    
         
             
                # Establishes a connection to the database that's used by all Active Record objects.
         
     | 
| 
         @@ -11,7 +11,7 @@ module ActiveRecord 
     | 
|
| 
       11 
11 
     | 
    
         
             
                      require_library_or_gem 'mysql'
         
     | 
| 
       12 
12 
     | 
    
         
             
                    rescue LoadError => cannot_require_mysql
         
     | 
| 
       13 
13 
     | 
    
         
             
                      # Only use the supplied backup Ruby/MySQL driver if no driver is already in place
         
     | 
| 
       14 
     | 
    
         
            -
                      begin 
     | 
| 
      
 14 
     | 
    
         
            +
                      begin
         
     | 
| 
       15 
15 
     | 
    
         
             
                        require 'active_record/vendor/mysql'
         
     | 
| 
       16 
16 
     | 
    
         
             
                        require 'active_record/vendor/mysql411'
         
     | 
| 
       17 
17 
     | 
    
         
             
                      rescue LoadError
         
     | 
| 
         @@ -19,27 +19,27 @@ module ActiveRecord 
     | 
|
| 
       19 
19 
     | 
    
         
             
                      end
         
     | 
| 
       20 
20 
     | 
    
         
             
                    end
         
     | 
| 
       21 
21 
     | 
    
         
             
                  end
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
       23 
23 
     | 
    
         
             
                  symbolize_strings_in_hash(config)
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
       25 
25 
     | 
    
         
             
                  host     = config[:host]
         
     | 
| 
       26 
26 
     | 
    
         
             
                  port     = config[:port]
         
     | 
| 
       27 
27 
     | 
    
         
             
                  socket   = config[:socket]
         
     | 
| 
       28 
28 
     | 
    
         
             
                  username = config[:username] ? config[:username].to_s : 'root'
         
     | 
| 
       29 
29 
     | 
    
         
             
                  password = config[:password].to_s
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
       31 
31 
     | 
    
         
             
                  if config.has_key?(:database)
         
     | 
| 
       32 
32 
     | 
    
         
             
                    database = config[:database]
         
     | 
| 
       33 
33 
     | 
    
         
             
                  else
         
     | 
| 
       34 
34 
     | 
    
         
             
                    raise ArgumentError, "No database specified. Missing argument: database."
         
     | 
| 
       35 
35 
     | 
    
         
             
                  end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
       37 
37 
     | 
    
         
             
                  mysql = Mysql.init
         
     | 
| 
       38 
38 
     | 
    
         
             
                  mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey]
         
     | 
| 
       39 
39 
     | 
    
         
             
                  ConnectionAdapters::MysqlAdapter.new(mysql.real_connect(host, username, password, database, port, socket), logger, [host, username, password, database, port, socket])
         
     | 
| 
       40 
40 
     | 
    
         
             
                end
         
     | 
| 
       41 
41 
     | 
    
         
             
              end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
       43 
43 
     | 
    
         
             
              module ConnectionAdapters
         
     | 
| 
       44 
44 
     | 
    
         
             
                # The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with
         
     | 
| 
       45 
45 
     | 
    
         
             
                # the faster C-based MySQL/Ruby adapter (available both as a gem and from http://www.tmtm.org/en/mysql/ruby/).
         
     | 
| 
         @@ -57,12 +57,16 @@ module ActiveRecord 
     | 
|
| 
       57 
57 
     | 
    
         
             
                # * <tt>:sslcapath</tt> -- Necessary to use MySQL with an SSL connection
         
     | 
| 
       58 
58 
     | 
    
         
             
                # * <tt>:sslcipher</tt> -- Necessary to use MySQL with an SSL connection
         
     | 
| 
       59 
59 
     | 
    
         
             
                class MysqlAdapter < AbstractAdapter
         
     | 
| 
       60 
     | 
    
         
            -
                  LOST_CONNECTION_ERROR_MESSAGES = [ 
     | 
| 
      
 60 
     | 
    
         
            +
                  LOST_CONNECTION_ERROR_MESSAGES = [
         
     | 
| 
       61 
61 
     | 
    
         
             
                    "Server shutdown in progress",
         
     | 
| 
       62 
     | 
    
         
            -
                    "Broken pipe", 
     | 
| 
       63 
     | 
    
         
            -
                    "Lost connection to MySQL server during query", 
     | 
| 
      
 62 
     | 
    
         
            +
                    "Broken pipe",
         
     | 
| 
      
 63 
     | 
    
         
            +
                    "Lost connection to MySQL server during query",
         
     | 
| 
       64 
64 
     | 
    
         
             
                    "MySQL server has gone away"
         
     | 
| 
       65 
65 
     | 
    
         
             
                  ]
         
     | 
| 
      
 66 
     | 
    
         
            +
                  
         
     | 
| 
      
 67 
     | 
    
         
            +
                  def supports_migrations?
         
     | 
| 
      
 68 
     | 
    
         
            +
                    true
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
       66 
70 
     | 
    
         | 
| 
       67 
71 
     | 
    
         
             
                  def native_database_types
         
     | 
| 
       68 
72 
     | 
    
         
             
                    {
         
     | 
| 
         @@ -84,86 +88,85 @@ module ActiveRecord 
     | 
|
| 
       84 
88 
     | 
    
         
             
                    super(connection, logger)
         
     | 
| 
       85 
89 
     | 
    
         
             
                    @connection_options = connection_options
         
     | 
| 
       86 
90 
     | 
    
         
             
                  end
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
       88 
92 
     | 
    
         
             
                  def adapter_name
         
     | 
| 
       89 
93 
     | 
    
         
             
                    'MySQL'
         
     | 
| 
       90 
94 
     | 
    
         
             
                  end
         
     | 
| 
       91 
95 
     | 
    
         | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
96 
     | 
    
         
             
                  def select_all(sql, name = nil)
         
     | 
| 
       94 
97 
     | 
    
         
             
                    select(sql, name)
         
     | 
| 
       95 
98 
     | 
    
         
             
                  end
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
       97 
100 
     | 
    
         
             
                  def select_one(sql, name = nil)
         
     | 
| 
       98 
101 
     | 
    
         
             
                    result = select(sql, name)
         
     | 
| 
       99 
102 
     | 
    
         
             
                    result.nil? ? nil : result.first
         
     | 
| 
       100 
103 
     | 
    
         
             
                  end
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
       102 
105 
     | 
    
         
             
                  def columns(table_name, name = nil)
         
     | 
| 
       103 
     | 
    
         
            -
                    sql = "SHOW FIELDS FROM #{table_name}" 
     | 
| 
      
 106 
     | 
    
         
            +
                    sql = "SHOW FIELDS FROM #{table_name}"
         
     | 
| 
       104 
107 
     | 
    
         
             
                    columns = []
         
     | 
| 
       105 
108 
     | 
    
         
             
                    execute(sql, name).each { |field| columns << Column.new(field[0], field[4], field[1]) }
         
     | 
| 
       106 
109 
     | 
    
         
             
                    columns
         
     | 
| 
       107 
110 
     | 
    
         
             
                  end
         
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
       109 
112 
     | 
    
         
             
                  def insert(sql, name = nil, pk = nil, id_value = nil)
         
     | 
| 
       110 
113 
     | 
    
         
             
                    execute(sql, name = nil)
         
     | 
| 
       111 
     | 
    
         
            -
                     
     | 
| 
      
 114 
     | 
    
         
            +
                    id_value || @connection.insert_id
         
     | 
| 
       112 
115 
     | 
    
         
             
                  end
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                  def execute(sql, name = nil)
         
     | 
| 
       115 
     | 
    
         
            -
                     
     | 
| 
       116 
     | 
    
         
            -
                       
     | 
| 
       117 
     | 
    
         
            -
                     
     | 
| 
       118 
     | 
    
         
            -
                       
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                  def execute(sql, name = nil, retries = 2)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    unless @logger
         
     | 
| 
      
 119 
     | 
    
         
            +
                      @connection.query(sql)
         
     | 
| 
      
 120 
     | 
    
         
            +
                    else
         
     | 
| 
      
 121 
     | 
    
         
            +
                      log(sql, name) { @connection.query(sql) }
         
     | 
| 
      
 122 
     | 
    
         
            +
                    end
         
     | 
| 
      
 123 
     | 
    
         
            +
                  rescue ActiveRecord::StatementInvalid => exception
         
     | 
| 
      
 124 
     | 
    
         
            +
                    if LOST_CONNECTION_ERROR_MESSAGES.any? { |msg| exception.message.split(":").first =~ /^#{msg}/ }
         
     | 
| 
      
 125 
     | 
    
         
            +
                      @connection.real_connect(*@connection_options)
         
     | 
| 
      
 126 
     | 
    
         
            +
                      unless @logger
         
     | 
| 
      
 127 
     | 
    
         
            +
                        @connection.query(sql)
         
     | 
| 
       122 
128 
     | 
    
         
             
                      else
         
     | 
| 
       123 
     | 
    
         
            -
                         
     | 
| 
      
 129 
     | 
    
         
            +
                        @logger.info "Retrying invalid statement with reopened connection"
         
     | 
| 
      
 130 
     | 
    
         
            +
                        log(sql, name) { @connection.query(sql) }
         
     | 
| 
       124 
131 
     | 
    
         
             
                      end
         
     | 
| 
      
 132 
     | 
    
         
            +
                    else
         
     | 
| 
      
 133 
     | 
    
         
            +
                      raise
         
     | 
| 
       125 
134 
     | 
    
         
             
                    end
         
     | 
| 
       126 
135 
     | 
    
         
             
                  end
         
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
       128 
137 
     | 
    
         
             
                  def update(sql, name = nil)
         
     | 
| 
       129 
138 
     | 
    
         
             
                    execute(sql, name)
         
     | 
| 
       130 
139 
     | 
    
         
             
                    @connection.affected_rows
         
     | 
| 
       131 
140 
     | 
    
         
             
                  end
         
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
       133 
142 
     | 
    
         
             
                  alias_method :delete, :update
         
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
       136 
145 
     | 
    
         
             
                  def begin_db_transaction
         
     | 
| 
       137 
     | 
    
         
            -
                     
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
                     
     | 
| 
       140 
     | 
    
         
            -
                      # Transactions aren't supported
         
     | 
| 
       141 
     | 
    
         
            -
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
                    execute "BEGIN"
         
     | 
| 
      
 147 
     | 
    
         
            +
                  rescue Exception
         
     | 
| 
      
 148 
     | 
    
         
            +
                    # Transactions aren't supported
         
     | 
| 
       142 
149 
     | 
    
         
             
                  end
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
       144 
151 
     | 
    
         
             
                  def commit_db_transaction
         
     | 
| 
       145 
     | 
    
         
            -
                     
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
                     
     | 
| 
       148 
     | 
    
         
            -
                      # Transactions aren't supported
         
     | 
| 
       149 
     | 
    
         
            -
                    end
         
     | 
| 
      
 152 
     | 
    
         
            +
                    execute "COMMIT"
         
     | 
| 
      
 153 
     | 
    
         
            +
                  rescue Exception
         
     | 
| 
      
 154 
     | 
    
         
            +
                    # Transactions aren't supported
         
     | 
| 
       150 
155 
     | 
    
         
             
                  end
         
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
       152 
157 
     | 
    
         
             
                  def rollback_db_transaction
         
     | 
| 
       153 
     | 
    
         
            -
                     
     | 
| 
       154 
     | 
    
         
            -
             
     | 
| 
       155 
     | 
    
         
            -
                     
     | 
| 
       156 
     | 
    
         
            -
                      # Transactions aren't supported
         
     | 
| 
       157 
     | 
    
         
            -
                    end
         
     | 
| 
      
 158 
     | 
    
         
            +
                    execute "ROLLBACK"
         
     | 
| 
      
 159 
     | 
    
         
            +
                  rescue Exception
         
     | 
| 
      
 160 
     | 
    
         
            +
                    # Transactions aren't supported
         
     | 
| 
       158 
161 
     | 
    
         
             
                  end
         
     | 
| 
       159 
162 
     | 
    
         | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
       161 
164 
     | 
    
         
             
                  def quote_column_name(name)
         
     | 
| 
       162 
     | 
    
         
            -
                     
     | 
| 
      
 165 
     | 
    
         
            +
                    "`#{name}`"
         
     | 
| 
       163 
166 
     | 
    
         
             
                  end
         
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
     | 
    
         
            -
                  def quote_string( 
     | 
| 
       166 
     | 
    
         
            -
                    Mysql::quote( 
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                  def quote_string(string)
         
     | 
| 
      
 169 
     | 
    
         
            +
                    Mysql::quote(string)
         
     | 
| 
       167 
170 
     | 
    
         
             
                  end
         
     | 
| 
       168 
171 
     | 
    
         | 
| 
       169 
172 
     | 
    
         | 
| 
         @@ -172,39 +175,63 @@ module ActiveRecord 
     | 
|
| 
       172 
175 
     | 
    
         
             
                      structure += select_one("SHOW CREATE TABLE #{table.to_a.first.last}")["Create Table"] + ";\n\n"
         
     | 
| 
       173 
176 
     | 
    
         
             
                    end
         
     | 
| 
       174 
177 
     | 
    
         
             
                  end
         
     | 
| 
       175 
     | 
    
         
            -
             
     | 
| 
       176 
     | 
    
         
            -
                  def  
     | 
| 
       177 
     | 
    
         
            -
                     
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                  def add_limit_offset!(sql, options)
         
     | 
| 
      
 180 
     | 
    
         
            +
                    if options[:limit]
         
     | 
| 
      
 181 
     | 
    
         
            +
                      if options[:offset].blank?
         
     | 
| 
      
 182 
     | 
    
         
            +
                        sql << " LIMIT #{options[:limit]}"
         
     | 
| 
      
 183 
     | 
    
         
            +
                      else
         
     | 
| 
      
 184 
     | 
    
         
            +
                        sql << " LIMIT #{options[:offset]}, #{options[:limit]}"
         
     | 
| 
      
 185 
     | 
    
         
            +
                      end
         
     | 
| 
      
 186 
     | 
    
         
            +
                    end
         
     | 
| 
       178 
187 
     | 
    
         
             
                  end
         
     | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
       180 
189 
     | 
    
         
             
                  def recreate_database(name)
         
     | 
| 
       181 
190 
     | 
    
         
             
                    drop_database(name)
         
     | 
| 
       182 
191 
     | 
    
         
             
                    create_database(name)
         
     | 
| 
       183 
192 
     | 
    
         
             
                  end
         
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
       185 
194 
     | 
    
         
             
                  def drop_database(name)
         
     | 
| 
       186 
195 
     | 
    
         
             
                    execute "DROP DATABASE IF EXISTS #{name}"
         
     | 
| 
       187 
196 
     | 
    
         
             
                  end
         
     | 
| 
       188 
     | 
    
         
            -
             
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
       189 
198 
     | 
    
         
             
                  def create_database(name)
         
     | 
| 
       190 
199 
     | 
    
         
             
                    execute "CREATE DATABASE #{name}"
         
     | 
| 
       191 
200 
     | 
    
         
             
                  end
         
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
201 
     | 
    
         | 
| 
       194 
     | 
    
         
            -
                  def  
     | 
| 
       195 
     | 
    
         
            -
                     
     | 
| 
      
 202 
     | 
    
         
            +
                  def change_column_default(table_name, column_name, default)
         
     | 
| 
      
 203 
     | 
    
         
            +
                    current_type = select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["Type"]
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                    change_column(table_name, column_name, current_type, { :default => default })
         
     | 
| 
      
 206 
     | 
    
         
            +
                  end
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                  def change_column(table_name, column_name, type, options = {})
         
     | 
| 
      
 209 
     | 
    
         
            +
                    options[:default] ||= select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["Default"]
         
     | 
| 
      
 210 
     | 
    
         
            +
                    
         
     | 
| 
      
 211 
     | 
    
         
            +
                    change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit])}"
         
     | 
| 
      
 212 
     | 
    
         
            +
                    add_column_options!(change_column_sql, options)
         
     | 
| 
      
 213 
     | 
    
         
            +
                    execute(change_column_sql)
         
     | 
| 
      
 214 
     | 
    
         
            +
                  end
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                  def rename_column(table_name, column_name, new_column_name)
         
     | 
| 
      
 217 
     | 
    
         
            +
                    current_type = select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["Type"]
         
     | 
| 
      
 218 
     | 
    
         
            +
                    execute "ALTER TABLE #{table_name} CHANGE #{column_name} #{new_column_name} #{current_type}"
         
     | 
| 
      
 219 
     | 
    
         
            +
                  end
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                  def create_table(name, options = {})
         
     | 
| 
      
 222 
     | 
    
         
            +
                    super(name, {:options => "ENGINE=InnoDB"}.merge(options))
         
     | 
| 
       196 
223 
     | 
    
         
             
                  end
         
     | 
| 
       197 
224 
     | 
    
         | 
| 
       198 
225 
     | 
    
         
             
                  private
         
     | 
| 
       199 
226 
     | 
    
         
             
                    def select(sql, name = nil)
         
     | 
| 
       200 
     | 
    
         
            -
                      result = nil
         
     | 
| 
       201 
227 
     | 
    
         
             
                      @connection.query_with_result = true
         
     | 
| 
       202 
228 
     | 
    
         
             
                      result = execute(sql, name)
         
     | 
| 
       203 
229 
     | 
    
         
             
                      rows = []
         
     | 
| 
       204 
230 
     | 
    
         
             
                      all_fields_initialized = result.fetch_fields.inject({}) { |all_fields, f| all_fields[f.name] = nil; all_fields }
         
     | 
| 
       205 
231 
     | 
    
         
             
                      result.each_hash { |row| rows << all_fields_initialized.dup.update(row) }
         
     | 
| 
      
 232 
     | 
    
         
            +
                      result.free
         
     | 
| 
       206 
233 
     | 
    
         
             
                      rows
         
     | 
| 
       207 
234 
     | 
    
         
             
                    end
         
     | 
| 
       208 
235 
     | 
    
         
             
                end
         
     | 
| 
       209 
236 
     | 
    
         
             
              end
         
     | 
| 
       210 
     | 
    
         
            -
            end
         
     | 
| 
      
 237 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -99,8 +99,8 @@ begin 
     | 
|
| 
       99 
99 
     | 
    
         
             
                  # * <tt>:password</tt> -- Defaults to nothing
         
     | 
| 
       100 
100 
     | 
    
         
             
                  # * <tt>:host</tt> -- Defaults to localhost
         
     | 
| 
       101 
101 
     | 
    
         
             
                  class OCIAdapter < AbstractAdapter
         
     | 
| 
       102 
     | 
    
         
            -
                    def quote_string( 
     | 
| 
       103 
     | 
    
         
            -
                       
     | 
| 
      
 102 
     | 
    
         
            +
                    def quote_string(string)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      string.gsub(/'/, "''")
         
     | 
| 
       104 
104 
     | 
    
         
             
                    end
         
     | 
| 
       105 
105 
     | 
    
         | 
| 
       106 
106 
     | 
    
         
             
                    def quote(value, column = nil)
         
     | 
| 
         @@ -125,7 +125,7 @@ begin 
     | 
|
| 
       125 
125 
     | 
    
         
             
                      elsif offset > 0
         
     | 
| 
       126 
126 
     | 
    
         
             
                        sql = "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_) where raw_rnum_ > #{offset}"
         
     | 
| 
       127 
127 
     | 
    
         
             
                      end
         
     | 
| 
       128 
     | 
    
         
            -
                      cursor = log(sql, name 
     | 
| 
      
 128 
     | 
    
         
            +
                      cursor = log(sql, name) { @connection.exec sql }
         
     | 
| 
       129 
129 
     | 
    
         
             
                      cols = cursor.get_col_names.map { |x| x.downcase }
         
     | 
| 
       130 
130 
     | 
    
         
             
                      rows = []
         
     | 
| 
       131 
131 
     | 
    
         
             
                      while row = cursor.fetch
         
     | 
| 
         @@ -167,16 +167,16 @@ begin 
     | 
|
| 
       167 
167 
     | 
    
         
             
                      if pk.nil? # Who called us? What does the sql look like? No idea!
         
     | 
| 
       168 
168 
     | 
    
         
             
                        execute sql, name
         
     | 
| 
       169 
169 
     | 
    
         
             
                      elsif id_value # Pre-assigned id
         
     | 
| 
       170 
     | 
    
         
            -
                        log(sql, name 
     | 
| 
      
 170 
     | 
    
         
            +
                        log(sql, name) { @connection.exec sql }
         
     | 
| 
       171 
171 
     | 
    
         
             
                      else # Assume the sql contains a bind-variable for the id
         
     | 
| 
       172 
172 
     | 
    
         
             
                        id_value = select_one("select rails_sequence.nextval id from dual")['id']
         
     | 
| 
       173 
     | 
    
         
            -
                        log(sql, name 
     | 
| 
      
 173 
     | 
    
         
            +
                        log(sql, name) { @connection.exec sql, id_value }
         
     | 
| 
       174 
174 
     | 
    
         
             
                      end
         
     | 
| 
       175 
175 
     | 
    
         
             
                      id_value
         
     | 
| 
       176 
176 
     | 
    
         
             
                    end
         
     | 
| 
       177 
177 
     | 
    
         | 
| 
       178 
178 
     | 
    
         
             
                    def execute(sql, name = nil)
         
     | 
| 
       179 
     | 
    
         
            -
                      log(sql, name 
     | 
| 
      
 179 
     | 
    
         
            +
                      log(sql, name) { @connection.exec sql }
         
     | 
| 
       180 
180 
     | 
    
         
             
                    end
         
     | 
| 
       181 
181 
     | 
    
         | 
| 
       182 
182 
     | 
    
         
             
                    alias :update :execute
         
     | 
| 
         @@ -24,7 +24,8 @@ module ActiveRecord 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  username = config[:username].to_s
         
     | 
| 
       25 
25 
     | 
    
         
             
                  password = config[:password].to_s
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                   
     | 
| 
      
 27 
     | 
    
         
            +
                  encoding = config[:encoding]
         
     | 
| 
      
 28 
     | 
    
         
            +
                  min_messages = config[:min_messages]
         
     | 
| 
       28 
29 
     | 
    
         | 
| 
       29 
30 
     | 
    
         
             
                  if config.has_key?(:database)
         
     | 
| 
       30 
31 
     | 
    
         
             
                    database = config[:database]
         
     | 
| 
         @@ -36,7 +37,9 @@ module ActiveRecord 
     | 
|
| 
       36 
37 
     | 
    
         
             
                    PGconn.connect(host, port, "", "", database, username, password), logger
         
     | 
| 
       37 
38 
     | 
    
         
             
                  )
         
     | 
| 
       38 
39 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                  pga. 
     | 
| 
      
 40 
     | 
    
         
            +
                  pga.schema_search_path = config[:schema_search_path] || config[:schema_order]
         
     | 
| 
      
 41 
     | 
    
         
            +
                  pga.execute("SET client_encoding TO '#{encoding}'") if encoding
         
     | 
| 
      
 42 
     | 
    
         
            +
                  pga.execute("SET client_min_messages TO '#{min_messages}'") if min_messages
         
     | 
| 
       40 
43 
     | 
    
         | 
| 
       41 
44 
     | 
    
         
             
                  pga
         
     | 
| 
       42 
45 
     | 
    
         
             
                end
         
     | 
| 
         @@ -53,8 +56,30 @@ module ActiveRecord 
     | 
|
| 
       53 
56 
     | 
    
         
             
                # * <tt>:username</tt> -- Defaults to nothing
         
     | 
| 
       54 
57 
     | 
    
         
             
                # * <tt>:password</tt> -- Defaults to nothing
         
     | 
| 
       55 
58 
     | 
    
         
             
                # * <tt>:database</tt> -- The name of the database. No default, must be provided.
         
     | 
| 
       56 
     | 
    
         
            -
                # * <tt>: 
     | 
| 
      
 59 
     | 
    
         
            +
                # * <tt>:schema_search_path</tt> -- An optional schema search path for the connection given as a string of comma-separated schema names.  This is backward-compatible with the :schema_order option.
         
     | 
| 
      
 60 
     | 
    
         
            +
                # * <tt>:encoding</tt> -- An optional client encoding that is using in a SET client_encoding TO <encoding> call on connection.
         
     | 
| 
      
 61 
     | 
    
         
            +
                # * <tt>:min_messages</tt> -- An optional client min messages that is using in a SET client_min_messages TO <min_messages> call on connection.
         
     | 
| 
       57 
62 
     | 
    
         
             
                class PostgreSQLAdapter < AbstractAdapter
         
     | 
| 
      
 63 
     | 
    
         
            +
                  def native_database_types
         
     | 
| 
      
 64 
     | 
    
         
            +
                    {
         
     | 
| 
      
 65 
     | 
    
         
            +
                      :primary_key => "serial primary key",
         
     | 
| 
      
 66 
     | 
    
         
            +
                      :string      => { :name => "character varying", :limit => 255 },
         
     | 
| 
      
 67 
     | 
    
         
            +
                      :text        => { :name => "text" },
         
     | 
| 
      
 68 
     | 
    
         
            +
                      :integer     => { :name => "integer" },
         
     | 
| 
      
 69 
     | 
    
         
            +
                      :float       => { :name => "float" },
         
     | 
| 
      
 70 
     | 
    
         
            +
                      :datetime    => { :name => "timestamp" },
         
     | 
| 
      
 71 
     | 
    
         
            +
                      :timestamp   => { :name => "timestamp" },
         
     | 
| 
      
 72 
     | 
    
         
            +
                      :time        => { :name => "timestamp" },
         
     | 
| 
      
 73 
     | 
    
         
            +
                      :date        => { :name => "date" },
         
     | 
| 
      
 74 
     | 
    
         
            +
                      :binary      => { :name => "bytea" },
         
     | 
| 
      
 75 
     | 
    
         
            +
                      :boolean     => { :name => "boolean"}
         
     | 
| 
      
 76 
     | 
    
         
            +
                    }
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                  
         
     | 
| 
      
 79 
     | 
    
         
            +
                  def supports_migrations?
         
     | 
| 
      
 80 
     | 
    
         
            +
                    true
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end      
         
     | 
| 
      
 82 
     | 
    
         
            +
                  
         
     | 
| 
       58 
83 
     | 
    
         
             
                  def select_all(sql, name = nil)
         
     | 
| 
       59 
84 
     | 
    
         
             
                    select(sql, name)
         
     | 
| 
       60 
85 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -65,26 +90,27 @@ module ActiveRecord 
     | 
|
| 
       65 
90 
     | 
    
         
             
                  end
         
     | 
| 
       66 
91 
     | 
    
         | 
| 
       67 
92 
     | 
    
         
             
                  def columns(table_name, name = nil)
         
     | 
| 
       68 
     | 
    
         
            -
                     
     | 
| 
       69 
     | 
    
         
            -
                       
     | 
| 
       70 
     | 
    
         
            -
                      columns
         
     | 
| 
      
 93 
     | 
    
         
            +
                    column_definitions(table_name).collect do |name, type, default|
         
     | 
| 
      
 94 
     | 
    
         
            +
                      Column.new(name, default_value(default), translate_field_type(type))
         
     | 
| 
       71 
95 
     | 
    
         
             
                    end
         
     | 
| 
       72 
96 
     | 
    
         
             
                  end
         
     | 
| 
       73 
97 
     | 
    
         | 
| 
       74 
98 
     | 
    
         
             
                  def insert(sql, name = nil, pk = nil, id_value = nil)
         
     | 
| 
       75 
     | 
    
         
            -
                    execute(sql, name 
     | 
| 
      
 99 
     | 
    
         
            +
                    execute(sql, name)
         
     | 
| 
       76 
100 
     | 
    
         
             
                    table = sql.split(" ", 4)[2]
         
     | 
| 
       77 
101 
     | 
    
         
             
                    return id_value || last_insert_id(table, pk)
         
     | 
| 
       78 
102 
     | 
    
         
             
                  end
         
     | 
| 
       79 
103 
     | 
    
         | 
| 
      
 104 
     | 
    
         
            +
                  def query(sql, name = nil)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    log(sql, name) { @connection.query(sql) }
         
     | 
| 
      
 106 
     | 
    
         
            +
                  end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
       80 
108 
     | 
    
         
             
                  def execute(sql, name = nil)
         
     | 
| 
       81 
     | 
    
         
            -
                    log(sql, name 
     | 
| 
      
 109 
     | 
    
         
            +
                    log(sql, name) { @connection.exec(sql) }
         
     | 
| 
       82 
110 
     | 
    
         
             
                  end
         
     | 
| 
       83 
111 
     | 
    
         | 
| 
       84 
112 
     | 
    
         
             
                  def update(sql, name = nil)
         
     | 
| 
       85 
     | 
    
         
            -
                     
     | 
| 
       86 
     | 
    
         
            -
                    log(sql, name, @connection) { |connection| result = connection.exec(sql) }
         
     | 
| 
       87 
     | 
    
         
            -
                    result.cmdtuples
         
     | 
| 
      
 113 
     | 
    
         
            +
                    execute(sql, name).cmdtuples
         
     | 
| 
       88 
114 
     | 
    
         
             
                  end
         
     | 
| 
       89 
115 
     | 
    
         | 
| 
       90 
116 
     | 
    
         
             
                  alias_method :delete, :update
         
     | 
| 
         @@ -102,23 +128,55 @@ module ActiveRecord 
     | 
|
| 
       102 
128 
     | 
    
         
             
                  end
         
     | 
| 
       103 
129 
     | 
    
         | 
| 
       104 
130 
     | 
    
         
             
                  def quote_column_name(name)
         
     | 
| 
       105 
     | 
    
         
            -
                     
     | 
| 
      
 131 
     | 
    
         
            +
                    %("#{name}")
         
     | 
| 
       106 
132 
     | 
    
         
             
                  end
         
     | 
| 
       107 
133 
     | 
    
         | 
| 
       108 
     | 
    
         
            -
                  def adapter_name 
     | 
| 
      
 134 
     | 
    
         
            +
                  def adapter_name
         
     | 
| 
       109 
135 
     | 
    
         
             
                    'PostgreSQL'
         
     | 
| 
       110 
136 
     | 
    
         
             
                  end
         
     | 
| 
       111 
137 
     | 
    
         | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  # Set the schema search path to a string of comma-separated schema names.
         
     | 
| 
      
 140 
     | 
    
         
            +
                  # Names beginning with $ are quoted (e.g. $user => '$user')
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # See http://www.postgresql.org/docs/8.0/interactive/ddl-schemas.html
         
     | 
| 
      
 142 
     | 
    
         
            +
                  def schema_search_path=(schema_csv)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    if schema_csv
         
     | 
| 
      
 144 
     | 
    
         
            +
                      execute "SET search_path TO #{schema_csv}"
         
     | 
| 
      
 145 
     | 
    
         
            +
                      @schema_search_path = nil
         
     | 
| 
      
 146 
     | 
    
         
            +
                    end
         
     | 
| 
      
 147 
     | 
    
         
            +
                  end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                  def schema_search_path
         
     | 
| 
      
 150 
     | 
    
         
            +
                    @schema_search_path ||= query('SHOW search_path')[0][0]
         
     | 
| 
      
 151 
     | 
    
         
            +
                  end
         
     | 
| 
      
 152 
     | 
    
         
            +
                        
         
     | 
| 
      
 153 
     | 
    
         
            +
                  def change_column(table_name, column_name, type, options = {})
         
     | 
| 
      
 154 
     | 
    
         
            +
                    execute = "ALTER TABLE #{table_name} ALTER  #{column_name} TYPE #{type}"
         
     | 
| 
      
 155 
     | 
    
         
            +
                    change_column_default(table_name, column_name, options[:default]) unless options[:default].nil?
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end      
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                  def change_column_default(table_name, column_name, default)
         
     | 
| 
      
 159 
     | 
    
         
            +
                    execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT '#{default}'"
         
     | 
| 
      
 160 
     | 
    
         
            +
                  end
         
     | 
| 
      
 161 
     | 
    
         
            +
                  
         
     | 
| 
      
 162 
     | 
    
         
            +
                  def rename_column(table_name, column_name, new_column_name)
         
     | 
| 
      
 163 
     | 
    
         
            +
                    execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
         
     | 
| 
      
 164 
     | 
    
         
            +
                  end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                  def remove_index(table_name, column_name)
         
     | 
| 
      
 167 
     | 
    
         
            +
                    execute "DROP INDEX #{table_name}_#{column_name}_index"
         
     | 
| 
      
 168 
     | 
    
         
            +
                  end      
         
     | 
| 
      
 169 
     | 
    
         
            +
                  
         
     | 
| 
       112 
170 
     | 
    
         
             
                  private
         
     | 
| 
      
 171 
     | 
    
         
            +
                    BYTEA_COLUMN_TYPE_OID = 17
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
       113 
173 
     | 
    
         
             
                    def last_insert_id(table, column = "id")
         
     | 
| 
       114 
174 
     | 
    
         
             
                      sequence_name = "#{table}_#{column || 'id'}_seq"
         
     | 
| 
       115 
175 
     | 
    
         
             
                      @connection.exec("SELECT currval('#{sequence_name}')")[0][0].to_i
         
     | 
| 
       116 
176 
     | 
    
         
             
                    end
         
     | 
| 
       117 
177 
     | 
    
         | 
| 
       118 
178 
     | 
    
         
             
                    def select(sql, name = nil)
         
     | 
| 
       119 
     | 
    
         
            -
                      res =  
     | 
| 
       120 
     | 
    
         
            -
                      log(sql, name, @connection) { |connection| res = connection.exec(sql) }
         
     | 
| 
       121 
     | 
    
         
            -
              
         
     | 
| 
      
 179 
     | 
    
         
            +
                      res = execute(sql, name)
         
     | 
| 
       122 
180 
     | 
    
         
             
                      results = res.result           
         
     | 
| 
       123 
181 
     | 
    
         
             
                      rows = []
         
     | 
| 
       124 
182 
     | 
    
         
             
                      if results.length > 0
         
     | 
| 
         @@ -127,7 +185,7 @@ module ActiveRecord 
     | 
|
| 
       127 
185 
     | 
    
         
             
                          hashed_row = {}
         
     | 
| 
       128 
186 
     | 
    
         
             
                          row.each_index do |cel_index|
         
     | 
| 
       129 
187 
     | 
    
         
             
                            column = row[cel_index]
         
     | 
| 
       130 
     | 
    
         
            -
                            if res.type(cel_index) ==  
     | 
| 
      
 188 
     | 
    
         
            +
                            if res.type(cel_index) == BYTEA_COLUMN_TYPE_OID
         
     | 
| 
       131 
189 
     | 
    
         
             
                              column = unescape_bytea(column)
         
     | 
| 
       132 
190 
     | 
    
         
             
                            end
         
     | 
| 
       133 
191 
     | 
    
         
             
                            hashed_row[fields[cel_index]] = column
         
     | 
| 
         @@ -150,54 +208,49 @@ module ActiveRecord 
     | 
|
| 
       150 
208 
     | 
    
         
             
                      s.gsub(/\\([0-9][0-9][0-9])/) { $1.oct.chr }.gsub(/\\\\/) { '\\' } unless s.nil?
         
     | 
| 
       151 
209 
     | 
    
         
             
                    end
         
     | 
| 
       152 
210 
     | 
    
         | 
| 
       153 
     | 
    
         
            -
                     
     | 
| 
       154 
     | 
    
         
            -
             
     | 
| 
       155 
     | 
    
         
            -
             
     | 
| 
       156 
     | 
    
         
            -
             
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
             
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
      
 211 
     | 
    
         
            +
                    # Query a table's column names, default values, and types.
         
     | 
| 
      
 212 
     | 
    
         
            +
                    #
         
     | 
| 
      
 213 
     | 
    
         
            +
                    # The underlying query is roughly:
         
     | 
| 
      
 214 
     | 
    
         
            +
                    #  SELECT column.name, column.type, default.value
         
     | 
| 
      
 215 
     | 
    
         
            +
                    #    FROM column LEFT JOIN default
         
     | 
| 
      
 216 
     | 
    
         
            +
                    #      ON column.table_id = default.table_id
         
     | 
| 
      
 217 
     | 
    
         
            +
                    #     AND column.num = default.column_num
         
     | 
| 
      
 218 
     | 
    
         
            +
                    #   WHERE column.table_id = get_table_id('table_name')
         
     | 
| 
      
 219 
     | 
    
         
            +
                    #     AND column.num > 0
         
     | 
| 
      
 220 
     | 
    
         
            +
                    #     AND NOT column.is_dropped
         
     | 
| 
      
 221 
     | 
    
         
            +
                    #   ORDER BY column.num
         
     | 
| 
      
 222 
     | 
    
         
            +
                    #
         
     | 
| 
      
 223 
     | 
    
         
            +
                    # If the table name is not prefixed with a schema, the database will
         
     | 
| 
      
 224 
     | 
    
         
            +
                    # take the first match from the schema search path.
         
     | 
| 
      
 225 
     | 
    
         
            +
                    #
         
     | 
| 
      
 226 
     | 
    
         
            +
                    # Query implementation notes:
         
     | 
| 
      
 227 
     | 
    
         
            +
                    #  - format_type includes the column size constraint, e.g. varchar(50)
         
     | 
| 
      
 228 
     | 
    
         
            +
                    #  - ::regclass is a function that gives the id for a table name
         
     | 
| 
      
 229 
     | 
    
         
            +
                    def column_definitions(table_name)
         
     | 
| 
      
 230 
     | 
    
         
            +
                      query <<-end_sql
         
     | 
| 
      
 231 
     | 
    
         
            +
                        SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc
         
     | 
| 
      
 232 
     | 
    
         
            +
                          FROM pg_attribute a LEFT JOIN pg_attrdef d
         
     | 
| 
      
 233 
     | 
    
         
            +
                            ON a.attrelid = d.adrelid AND a.attnum = d.adnum
         
     | 
| 
      
 234 
     | 
    
         
            +
                         WHERE a.attrelid = '#{table_name}'::regclass
         
     | 
| 
      
 235 
     | 
    
         
            +
                           AND a.attnum > 0 AND NOT a.attisdropped
         
     | 
| 
      
 236 
     | 
    
         
            +
                         ORDER BY a.attnum
         
     | 
| 
      
 237 
     | 
    
         
            +
                      end_sql
         
     | 
| 
       161 
238 
     | 
    
         
             
                    end
         
     | 
| 
       162 
239 
     | 
    
         | 
| 
       163 
     | 
    
         
            -
                     
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
                      #  
     | 
| 
       168 
     | 
    
         
            -
                       
     | 
| 
       169 
     | 
    
         
            -
             
     | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
             
     | 
| 
       174 
     | 
    
         
            -
                      column_defaults = nil
         
     | 
| 
       175 
     | 
    
         
            -
                      log(sql, nil, @connection) { |connection| column_defaults = connection.query(sql) }
         
     | 
| 
       176 
     | 
    
         
            -
                      column_defaults.collect do |row|
         
     | 
| 
       177 
     | 
    
         
            -
                          field   = row[0]
         
     | 
| 
       178 
     | 
    
         
            -
                          type    = type_as_string(row[3], row[2])
         
     | 
| 
       179 
     | 
    
         
            -
                          default = default_value(row[1])
         
     | 
| 
       180 
     | 
    
         
            -
                          length  = row[2]
         
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
       182 
     | 
    
         
            -
                          [field, type, default, length]
         
     | 
| 
      
 240 
     | 
    
         
            +
                    # Translate PostgreSQL-specific types into simplified SQL types.
         
     | 
| 
      
 241 
     | 
    
         
            +
                    # These are special cases; standard types are handled by
         
     | 
| 
      
 242 
     | 
    
         
            +
                    # ConnectionAdapters::Column#simplified_type.
         
     | 
| 
      
 243 
     | 
    
         
            +
                    def translate_field_type(field_type)
         
     | 
| 
      
 244 
     | 
    
         
            +
                      # Match the beginning of field_type since it may have a size constraint on the end.
         
     | 
| 
      
 245 
     | 
    
         
            +
                      case field_type
         
     | 
| 
      
 246 
     | 
    
         
            +
                        when /^timestamp/i    then 'datetime'
         
     | 
| 
      
 247 
     | 
    
         
            +
                        when /^real|^money/i  then 'float'
         
     | 
| 
      
 248 
     | 
    
         
            +
                        when /^interval/i     then 'string'
         
     | 
| 
      
 249 
     | 
    
         
            +
                        when /^bytea/i        then 'binary'
         
     | 
| 
      
 250 
     | 
    
         
            +
                        else field_type       # Pass through standard types.
         
     | 
| 
       183 
251 
     | 
    
         
             
                      end
         
     | 
| 
       184 
252 
     | 
    
         
             
                    end
         
     | 
| 
       185 
253 
     | 
    
         | 
| 
       186 
     | 
    
         
            -
                    def type_as_string(field_type, field_length)
         
     | 
| 
       187 
     | 
    
         
            -
                      type = case field_type
         
     | 
| 
       188 
     | 
    
         
            -
                        when 'numeric', 'real', 'money'      then 'float'
         
     | 
| 
       189 
     | 
    
         
            -
                        when 'character varying', 'interval' then 'string'
         
     | 
| 
       190 
     | 
    
         
            -
                        when 'timestamp without time zone'   then 'datetime'
         
     | 
| 
       191 
     | 
    
         
            -
                        when 'timestamp with time zone'      then 'datetime'
         
     | 
| 
       192 
     | 
    
         
            -
                        when 'bytea'                         then 'binary'
         
     | 
| 
       193 
     | 
    
         
            -
                        else field_type
         
     | 
| 
       194 
     | 
    
         
            -
                      end
         
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
                      size = field_length.nil? ? "" : "(#{field_length})"
         
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
                      return type + size
         
     | 
| 
       199 
     | 
    
         
            -
                    end
         
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
254 
     | 
    
         
             
                    def default_value(value)
         
     | 
| 
       202 
255 
     | 
    
         
             
                      # Boolean types
         
     | 
| 
       203 
256 
     | 
    
         
             
                      return "t" if value =~ /true/i
         
     |