activerecord 5.1.4 → 5.1.5
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +151 -0
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/builder/belongs_to.rb +7 -3
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -9
- data/lib/active_record/associations/join_dependency.rb +3 -3
- data/lib/active_record/associations/preloader/association.rb +11 -34
- data/lib/active_record/associations/preloader/through_association.rb +10 -3
- data/lib/active_record/attribute_methods/dirty.rb +3 -2
- data/lib/active_record/collection_cache_key.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +2 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +5 -4
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +28 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +5 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +11 -4
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +3 -4
- data/lib/active_record/migration/compatibility.rb +34 -20
- data/lib/active_record/model_schema.rb +33 -33
- data/lib/active_record/persistence.rb +1 -5
- data/lib/active_record/query_cache.rb +6 -6
- data/lib/active_record/railties/databases.rake +2 -2
- data/lib/active_record/reflection.rb +24 -10
- data/lib/active_record/relation/calculations.rb +16 -11
- data/lib/active_record/relation/finder_methods.rb +1 -11
- data/lib/active_record/relation/query_methods.rb +19 -14
- data/lib/active_record/relation.rb +14 -2
- data/lib/active_record/tasks/database_tasks.rb +11 -10
- metadata +10 -8
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: c959975b61990368b7c19d60de2e6ac341e8962fe5ec6612f2c7246916343200
         | 
| 4 | 
            +
              data.tar.gz: 38b6c9d5f665a16158f3e3a663c8d1935f925d086a1b0bb954f68b94ba7c1fd0
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 154de32a9ce2ffabd8a5b33d067e206b5be1d3b50c556e361b5018ce91cf534df778537aa46e2c2e7d7e616bb0e0ded3d62ad29b3f133c1565c53e615aff1de7
         | 
| 7 | 
            +
              data.tar.gz: 42d3009be5bf1eb2c57fd712d4cfa414560bc3f0dd74d180aacb2d888f907203973f07cdf362d4ebbd1ecbf7855ae08aabe8ae9f49e6d361dd2cb840333e723a
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,154 @@ | |
| 1 | 
            +
            ## Rails 5.1.5 (February 14, 2018) ##
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            *   Fix `count(:all)` with eager loading and having an order other than the driving table.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                Fixes #31783.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                *Ryuta Kamizono*
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            *   Use `count(:all)` in `HasManyAssociation#count_records` to prevent invalid
         | 
| 10 | 
            +
                SQL queries for association counting.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                *Klas Eskilson*
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            *   Fix to invoke callbacks when using `update_attribute`.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                *Mike Busch*
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            *   Fix `count(:all)` to correctly work `distinct` with custom SELECT list.
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                *Ryuta Kamizono*
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            *   Fix conflicts `counter_cache` with `touch: true` by optimistic locking.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                ```
         | 
| 25 | 
            +
                # create_table :posts do |t|
         | 
| 26 | 
            +
                #   t.integer :comments_count, default: 0
         | 
| 27 | 
            +
                #   t.integer :lock_version
         | 
| 28 | 
            +
                #   t.timestamps
         | 
| 29 | 
            +
                # end
         | 
| 30 | 
            +
                class Post < ApplicationRecord
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                # create_table :comments do |t|
         | 
| 34 | 
            +
                #   t.belongs_to :post
         | 
| 35 | 
            +
                # end
         | 
| 36 | 
            +
                class Comment < ApplicationRecord
         | 
| 37 | 
            +
                  belongs_to :post, touch: true, counter_cache: true
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
                ```
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                Before:
         | 
| 42 | 
            +
                ```
         | 
| 43 | 
            +
                post = Post.create!
         | 
| 44 | 
            +
                # => begin transaction
         | 
| 45 | 
            +
                     INSERT INTO "posts" ("created_at", "updated_at", "lock_version")
         | 
| 46 | 
            +
                     VALUES ("2017-12-11 21:27:11.387397", "2017-12-11 21:27:11.387397", 0)
         | 
| 47 | 
            +
                     commit transaction
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                comment = Comment.create!(post: post)
         | 
| 50 | 
            +
                # => begin transaction
         | 
| 51 | 
            +
                     INSERT INTO "comments" ("post_id") VALUES (1)
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                     UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) + 1,
         | 
| 54 | 
            +
                     "lock_version" = COALESCE("lock_version", 0) + 1 WHERE "posts"."id" = 1
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                     UPDATE "posts" SET "updated_at" = '2017-12-11 21:27:11.398330',
         | 
| 57 | 
            +
                     "lock_version" = 1 WHERE "posts"."id" = 1 AND "posts"."lock_version" = 0
         | 
| 58 | 
            +
                     rollback transaction
         | 
| 59 | 
            +
                # => ActiveRecord::StaleObjectError: Attempted to touch a stale object: Post.
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                Comment.take.destroy!
         | 
| 62 | 
            +
                # => begin transaction
         | 
| 63 | 
            +
                     DELETE FROM "comments" WHERE "comments"."id" = 1
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                     UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) - 1,
         | 
| 66 | 
            +
                     "lock_version" = COALESCE("lock_version", 0) + 1 WHERE "posts"."id" = 1
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                     UPDATE "posts" SET "updated_at" = '2017-12-11 21:42:47.785901',
         | 
| 69 | 
            +
                     "lock_version" = 1 WHERE "posts"."id" = 1 AND "posts"."lock_version" = 0
         | 
| 70 | 
            +
                     rollback transaction
         | 
| 71 | 
            +
                # => ActiveRecord::StaleObjectError: Attempted to touch a stale object: Post.
         | 
| 72 | 
            +
                ```
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                After:
         | 
| 75 | 
            +
                ```
         | 
| 76 | 
            +
                post = Post.create!
         | 
| 77 | 
            +
                # => begin transaction
         | 
| 78 | 
            +
                     INSERT INTO "posts" ("created_at", "updated_at", "lock_version")
         | 
| 79 | 
            +
                     VALUES ("2017-12-11 21:27:11.387397", "2017-12-11 21:27:11.387397", 0)
         | 
| 80 | 
            +
                     commit transaction
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                comment = Comment.create!(post: post)
         | 
| 83 | 
            +
                # => begin transaction
         | 
| 84 | 
            +
                     INSERT INTO "comments" ("post_id") VALUES (1)
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                     UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) + 1,
         | 
| 87 | 
            +
                     "lock_version" = COALESCE("lock_version", 0) + 1,
         | 
| 88 | 
            +
                     "updated_at" = '2017-12-11 21:37:09.802642' WHERE "posts"."id" = 1
         | 
| 89 | 
            +
                     commit transaction
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                comment.destroy!
         | 
| 92 | 
            +
                # => begin transaction
         | 
| 93 | 
            +
                     DELETE FROM "comments" WHERE "comments"."id" = 1
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                     UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) - 1,
         | 
| 96 | 
            +
                     "lock_version" = COALESCE("lock_version", 0) + 1,
         | 
| 97 | 
            +
                     "updated_at" = '2017-12-11 21:39:02.685520' WHERE "posts"."id" = 1
         | 
| 98 | 
            +
                     commit transaction
         | 
| 99 | 
            +
                ```
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                Fixes #31199.
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                *bogdanvlviv*
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            *   Query cache was unavailable when entering the `ActiveRecord::Base.cache` block
         | 
| 106 | 
            +
                without being connected.
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                *Tsukasa Oishi*
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            *   Fix `bin/rails db:setup` and `bin/rails db:test:prepare` create  wrong
         | 
| 111 | 
            +
                ar_internal_metadata's data for a test database.
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                Before:
         | 
| 114 | 
            +
                ```
         | 
| 115 | 
            +
                $ RAILS_ENV=test rails dbconsole
         | 
| 116 | 
            +
                > SELECT * FROM ar_internal_metadata;
         | 
| 117 | 
            +
                key|value|created_at|updated_at
         | 
| 118 | 
            +
                environment|development|2017-09-11 23:14:10.815679|2017-09-11 23:14:10.815679
         | 
| 119 | 
            +
                ```
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                After:
         | 
| 122 | 
            +
                ```
         | 
| 123 | 
            +
                $ RAILS_ENV=test rails dbconsole
         | 
| 124 | 
            +
                > SELECT * FROM ar_internal_metadata;
         | 
| 125 | 
            +
                key|value|created_at|updated_at
         | 
| 126 | 
            +
                environment|test|2017-09-11 23:14:10.815679|2017-09-11 23:14:10.815679
         | 
| 127 | 
            +
                ```
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                Fixes #26731.
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                *bogdanvlviv*
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            *   Fix longer sequence name detection for serial columns.
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                Fixes #28332.
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                *Ryuta Kamizono*
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            *   MySQL: Don't lose `auto_increment: true` in the `db/schema.rb`.
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                Fixes #30894.
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                *Ryuta Kamizono*
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            *   Fix `COUNT(DISTINCT ...)` for `GROUP BY` with `ORDER BY` and `LIMIT`.
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                Fixes #30886.
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                *Ryuta Kamizono*
         | 
| 150 | 
            +
             | 
| 151 | 
            +
             | 
| 1 152 | 
             
            ## Rails 5.1.4 (September 07, 2017) ##
         | 
| 2 153 |  | 
| 3 154 | 
             
            *   No changes.
         | 
| @@ -47,9 +47,9 @@ module ActiveRecord | |
| 47 47 | 
             
                    def update_counters(by)
         | 
| 48 48 | 
             
                      if require_counter_update? && foreign_key_present?
         | 
| 49 49 | 
             
                        if target && !stale_target?
         | 
| 50 | 
            -
                          target.increment!(reflection.counter_cache_column, by)
         | 
| 50 | 
            +
                          target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch])
         | 
| 51 51 | 
             
                        else
         | 
| 52 | 
            -
                          klass.update_counters(target_id, reflection.counter_cache_column => by)
         | 
| 52 | 
            +
                          klass.update_counters(target_id, reflection.counter_cache_column => by, touch: reflection.options[:touch])
         | 
| 53 53 | 
             
                        end
         | 
| 54 54 | 
             
                      end
         | 
| 55 55 | 
             
                    end
         | 
| @@ -114,9 +114,13 @@ module ActiveRecord::Associations::Builder # :nodoc: | |
| 114 114 | 
             
                    BelongsTo.touch_record(record, record.send(changes_method), foreign_key, n, touch, belongs_to_touch_method)
         | 
| 115 115 | 
             
                  }}
         | 
| 116 116 |  | 
| 117 | 
            -
                   | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 117 | 
            +
                  unless reflection.counter_cache_column
         | 
| 118 | 
            +
                    model.after_create callback.(:saved_changes), if: :saved_changes?
         | 
| 119 | 
            +
                    model.after_destroy callback.(:changes_to_save)
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                  model.after_update callback.(:saved_changes), if: :saved_changes?
         | 
| 123 | 
            +
                  model.after_touch callback.(:changes_to_save)
         | 
| 120 124 | 
             
                end
         | 
| 121 125 |  | 
| 122 126 | 
             
                def self.add_default_callbacks(model, reflection)
         | 
| @@ -40,15 +40,7 @@ module ActiveRecord | |
| 40 40 |  | 
| 41 41 | 
             
                        constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
         | 
| 42 42 |  | 
| 43 | 
            -
                         | 
| 44 | 
            -
                        scope_chain_items = reflection.join_scopes(table, predicate_builder)
         | 
| 45 | 
            -
                        klass_scope       = reflection.klass_join_scope(table, predicate_builder)
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                        scope_chain_items.concat [klass_scope].compact
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                        rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right|
         | 
| 50 | 
            -
                          left.merge right
         | 
| 51 | 
            -
                        end
         | 
| 43 | 
            +
                        rel = reflection.join_scope(table)
         | 
| 52 44 |  | 
| 53 45 | 
             
                        if rel && !rel.arel.constraints.empty?
         | 
| 54 46 | 
             
                          binds += rel.bound_attributes
         | 
| @@ -126,7 +126,7 @@ module ActiveRecord | |
| 126 126 | 
             
                  end
         | 
| 127 127 |  | 
| 128 128 | 
             
                  def aliases
         | 
| 129 | 
            -
                    Aliases.new join_root.each_with_index.map { |join_part, i|
         | 
| 129 | 
            +
                    @aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
         | 
| 130 130 | 
             
                      columns = join_part.column_names.each_with_index.map { |column_name, j|
         | 
| 131 131 | 
             
                        Aliases::Column.new column_name, "t#{i}_r#{j}"
         | 
| 132 132 | 
             
                      }
         | 
| @@ -134,7 +134,7 @@ module ActiveRecord | |
| 134 134 | 
             
                    }
         | 
| 135 135 | 
             
                  end
         | 
| 136 136 |  | 
| 137 | 
            -
                  def instantiate(result_set,  | 
| 137 | 
            +
                  def instantiate(result_set, &block)
         | 
| 138 138 | 
             
                    primary_key = aliases.column_alias(join_root, join_root.primary_key)
         | 
| 139 139 |  | 
| 140 140 | 
             
                    seen = Hash.new { |i, object_id|
         | 
| @@ -157,7 +157,7 @@ module ActiveRecord | |
| 157 157 | 
             
                    message_bus.instrument("instantiation.active_record", payload) do
         | 
| 158 158 | 
             
                      result_set.each { |row_hash|
         | 
| 159 159 | 
             
                        parent_key = primary_key ? row_hash[primary_key] : row_hash
         | 
| 160 | 
            -
                        parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases)
         | 
| 160 | 
            +
                        parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block)
         | 
| 161 161 | 
             
                        construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
         | 
| 162 162 | 
             
                      }
         | 
| 163 163 | 
             
                    end
         | 
| @@ -90,7 +90,11 @@ module ActiveRecord | |
| 90 90 | 
             
                      end
         | 
| 91 91 |  | 
| 92 92 | 
             
                      def key_conversion_required?
         | 
| 93 | 
            -
                        @key_conversion_required | 
| 93 | 
            +
                        unless defined?(@key_conversion_required)
         | 
| 94 | 
            +
                          @key_conversion_required = (association_key_type != owner_key_type)
         | 
| 95 | 
            +
                        end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                        @key_conversion_required
         | 
| 94 98 | 
             
                      end
         | 
| 95 99 |  | 
| 96 100 | 
             
                      def convert_key(key)
         | 
| @@ -127,42 +131,15 @@ module ActiveRecord | |
| 127 131 | 
             
                      end
         | 
| 128 132 |  | 
| 129 133 | 
             
                      def build_scope
         | 
| 130 | 
            -
                        scope = klass. | 
| 131 | 
            -
             | 
| 132 | 
            -
                        values = reflection_scope.values
         | 
| 133 | 
            -
                        preload_values = preload_scope.values
         | 
| 134 | 
            -
             | 
| 135 | 
            -
                        scope.where_clause = reflection_scope.where_clause + preload_scope.where_clause
         | 
| 136 | 
            -
                        scope.references_values = Array(values[:references]) + Array(preload_values[:references])
         | 
| 137 | 
            -
             | 
| 138 | 
            -
                        if preload_values[:select] || values[:select]
         | 
| 139 | 
            -
                          scope._select!(preload_values[:select] || values[:select])
         | 
| 140 | 
            -
                        end
         | 
| 141 | 
            -
                        scope.includes! preload_values[:includes] || values[:includes]
         | 
| 142 | 
            -
                        if preload_scope.joins_values.any?
         | 
| 143 | 
            -
                          scope.joins!(preload_scope.joins_values)
         | 
| 144 | 
            -
                        else
         | 
| 145 | 
            -
                          scope.joins!(reflection_scope.joins_values)
         | 
| 146 | 
            -
                        end
         | 
| 147 | 
            -
             | 
| 148 | 
            -
                        if order_values = preload_values[:order] || values[:order]
         | 
| 149 | 
            -
                          scope.order!(order_values)
         | 
| 150 | 
            -
                        end
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                        if preload_values[:reordering] || values[:reordering]
         | 
| 153 | 
            -
                          scope.reordering_value = true
         | 
| 154 | 
            -
                        end
         | 
| 155 | 
            -
             | 
| 156 | 
            -
                        if preload_values[:readonly] || values[:readonly]
         | 
| 157 | 
            -
                          scope.readonly!
         | 
| 158 | 
            -
                        end
         | 
| 134 | 
            +
                        scope = klass.scope_for_association
         | 
| 159 135 |  | 
| 160 | 
            -
                        if  | 
| 161 | 
            -
                          scope.where!( | 
| 136 | 
            +
                        if reflection.type
         | 
| 137 | 
            +
                          scope.where!(reflection.type => model.base_class.sti_name)
         | 
| 162 138 | 
             
                        end
         | 
| 163 139 |  | 
| 164 | 
            -
                        scope. | 
| 165 | 
            -
                         | 
| 140 | 
            +
                        scope.merge!(reflection_scope)
         | 
| 141 | 
            +
                        scope.merge!(preload_scope) if preload_scope != NULL_RELATION
         | 
| 142 | 
            +
                        scope
         | 
| 166 143 | 
             
                      end
         | 
| 167 144 | 
             
                  end
         | 
| 168 145 | 
             
                end
         | 
| @@ -81,17 +81,24 @@ module ActiveRecord | |
| 81 81 |  | 
| 82 82 | 
             
                      def through_scope
         | 
| 83 83 | 
             
                        scope = through_reflection.klass.unscoped
         | 
| 84 | 
            +
                        values = reflection_scope.values
         | 
| 84 85 |  | 
| 85 86 | 
             
                        if options[:source_type]
         | 
| 86 87 | 
             
                          scope.where! reflection.foreign_type => options[:source_type]
         | 
| 87 88 | 
             
                        else
         | 
| 88 89 | 
             
                          unless reflection_scope.where_clause.empty?
         | 
| 89 | 
            -
                            scope.includes_values = Array( | 
| 90 | 
            +
                            scope.includes_values = Array(values[:includes] || options[:source])
         | 
| 90 91 | 
             
                            scope.where_clause = reflection_scope.where_clause
         | 
| 92 | 
            +
                            if joins = values[:joins]
         | 
| 93 | 
            +
                              scope.joins!(source_reflection.name => joins)
         | 
| 94 | 
            +
                            end
         | 
| 95 | 
            +
                            if left_outer_joins = values[:left_outer_joins]
         | 
| 96 | 
            +
                              scope.left_outer_joins!(source_reflection.name => left_outer_joins)
         | 
| 97 | 
            +
                            end
         | 
| 91 98 | 
             
                          end
         | 
| 92 99 |  | 
| 93 | 
            -
                          scope.references!  | 
| 94 | 
            -
                          if scope.eager_loading? && order_values =  | 
| 100 | 
            +
                          scope.references! values[:references]
         | 
| 101 | 
            +
                          if scope.eager_loading? && order_values = values[:order]
         | 
| 95 102 | 
             
                            scope = scope.order(order_values)
         | 
| 96 103 | 
             
                          end
         | 
| 97 104 | 
             
                        end
         | 
| @@ -63,7 +63,7 @@ module ActiveRecord | |
| 63 63 | 
             
                  end
         | 
| 64 64 |  | 
| 65 65 | 
             
                  def changes_internally_applied # :nodoc:
         | 
| 66 | 
            -
                    @mutations_before_last_save =  | 
| 66 | 
            +
                    @mutations_before_last_save = mutations_from_database
         | 
| 67 67 | 
             
                    forget_attribute_assignments
         | 
| 68 68 | 
             
                    @mutations_from_database = AttributeMutationTracker.new(@attributes)
         | 
| 69 69 | 
             
                  end
         | 
| @@ -71,7 +71,8 @@ module ActiveRecord | |
| 71 71 | 
             
                  def changes_applied # :nodoc:
         | 
| 72 72 | 
             
                    @previous_mutation_tracker = mutation_tracker
         | 
| 73 73 | 
             
                    @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
         | 
| 74 | 
            -
                     | 
| 74 | 
            +
                    @mutation_tracker = nil
         | 
| 75 | 
            +
                    @mutations_from_database = nil
         | 
| 75 76 | 
             
                  end
         | 
| 76 77 |  | 
| 77 78 | 
             
                  def clear_changes_information # :nodoc:
         | 
| @@ -4,8 +4,8 @@ module ActiveRecord | |
| 4 4 | 
             
                  query_signature = Digest::MD5.hexdigest(collection.to_sql)
         | 
| 5 5 | 
             
                  key = "#{collection.model_name.cache_key}/query-#{query_signature}"
         | 
| 6 6 |  | 
| 7 | 
            -
                  if collection.loaded?
         | 
| 8 | 
            -
                    size = collection.size
         | 
| 7 | 
            +
                  if collection.loaded? || collection.distinct_value
         | 
| 8 | 
            +
                    size = collection.records.size
         | 
| 9 9 | 
             
                    if size > 0
         | 
| 10 10 | 
             
                      timestamp = collection.max_by(×tamp_column)._read_attribute(timestamp_column)
         | 
| 11 11 | 
             
                    end
         | 
| @@ -4,6 +4,7 @@ require "active_record/connection_adapters/schema_cache" | |
| 4 4 | 
             
            require "active_record/connection_adapters/sql_type_metadata"
         | 
| 5 5 | 
             
            require "active_record/connection_adapters/abstract/schema_dumper"
         | 
| 6 6 | 
             
            require "active_record/connection_adapters/abstract/schema_creation"
         | 
| 7 | 
            +
            require "active_support/concurrency/load_interlock_aware_monitor"
         | 
| 7 8 | 
             
            require "arel/collectors/bind"
         | 
| 8 9 | 
             
            require "arel/collectors/sql_string"
         | 
| 9 10 |  | 
| @@ -105,7 +106,7 @@ module ActiveRecord | |
| 105 106 | 
             
                    @schema_cache        = SchemaCache.new self
         | 
| 106 107 | 
             
                    @quoted_column_names, @quoted_table_names = {}, {}
         | 
| 107 108 | 
             
                    @visitor = arel_visitor
         | 
| 108 | 
            -
                    @lock =  | 
| 109 | 
            +
                    @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
         | 
| 109 110 |  | 
| 110 111 | 
             
                    if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
         | 
| 111 112 | 
             
                      @prepared_statements = true
         | 
| @@ -140,11 +140,11 @@ module ActiveRecord | |
| 140 140 | 
             
                  end
         | 
| 141 141 |  | 
| 142 142 | 
             
                  def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
         | 
| 143 | 
            -
                    query_value("SELECT GET_LOCK(#{quote(lock_name)}, #{timeout})") == 1
         | 
| 143 | 
            +
                    query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
         | 
| 144 144 | 
             
                  end
         | 
| 145 145 |  | 
| 146 146 | 
             
                  def release_advisory_lock(lock_name) # :nodoc:
         | 
| 147 | 
            -
                    query_value("SELECT RELEASE_LOCK(#{quote(lock_name)})") == 1
         | 
| 147 | 
            +
                    query_value("SELECT RELEASE_LOCK(#{quote(lock_name.to_s)})") == 1
         | 
| 148 148 | 
             
                  end
         | 
| 149 149 |  | 
| 150 150 | 
             
                  def native_database_types
         | 
| @@ -464,12 +464,13 @@ module ActiveRecord | |
| 464 464 | 
             
                             fk.constraint_name AS 'name',
         | 
| 465 465 | 
             
                             rc.update_rule AS 'on_update',
         | 
| 466 466 | 
             
                             rc.delete_rule AS 'on_delete'
         | 
| 467 | 
            -
                      FROM information_schema. | 
| 468 | 
            -
                      JOIN information_schema. | 
| 467 | 
            +
                      FROM information_schema.referential_constraints rc
         | 
| 468 | 
            +
                      JOIN information_schema.key_column_usage fk
         | 
| 469 469 | 
             
                      USING (constraint_schema, constraint_name)
         | 
| 470 470 | 
             
                      WHERE fk.referenced_column_name IS NOT NULL
         | 
| 471 471 | 
             
                        AND fk.table_schema = #{scope[:schema]}
         | 
| 472 472 | 
             
                        AND fk.table_name = #{scope[:name]}
         | 
| 473 | 
            +
                        AND rc.constraint_schema = #{scope[:schema]}
         | 
| 473 474 | 
             
                        AND rc.table_name = #{scope[:name]}
         | 
| 474 475 | 
             
                    SQL
         | 
| 475 476 |  | 
| @@ -13,7 +13,7 @@ module ActiveRecord | |
| 13 13 | 
             
                  # +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
         | 
| 14 14 | 
             
                  # +sql_type_metadata+ is various information about the type of the column
         | 
| 15 15 | 
             
                  # +null+ determines if this column allows +NULL+ values.
         | 
| 16 | 
            -
                  def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
         | 
| 16 | 
            +
                  def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil, **)
         | 
| 17 17 | 
             
                    @name = name.freeze
         | 
| 18 18 | 
             
                    @table_name = table_name
         | 
| 19 19 | 
             
                    @sql_type_metadata = sql_type_metadata
         | 
| @@ -5,6 +5,7 @@ module ActiveRecord | |
| 5 5 | 
             
                    def prepare_column_options(column)
         | 
| 6 6 | 
             
                      spec = super
         | 
| 7 7 | 
             
                      spec[:unsigned] = "true" if column.unsigned?
         | 
| 8 | 
            +
                      spec[:auto_increment] = "true" if column.auto_increment?
         | 
| 8 9 |  | 
| 9 10 | 
             
                      if supports_virtual_columns? && column.virtual?
         | 
| 10 11 | 
             
                        spec[:as] = extract_expression_for_virtual_column(column)
         | 
| @@ -15,6 +16,12 @@ module ActiveRecord | |
| 15 16 | 
             
                      spec
         | 
| 16 17 | 
             
                    end
         | 
| 17 18 |  | 
| 19 | 
            +
                    def column_spec_for_primary_key(column)
         | 
| 20 | 
            +
                      spec = super
         | 
| 21 | 
            +
                      spec.delete(:auto_increment) if column.type == :integer && column.auto_increment?
         | 
| 22 | 
            +
                      spec
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 18 25 | 
             
                    def migration_keys
         | 
| 19 26 | 
             
                      super + [:unsigned]
         | 
| 20 27 | 
             
                    end
         | 
| @@ -5,11 +5,38 @@ module ActiveRecord | |
| 5 5 | 
             
                  delegate :array, :oid, :fmod, to: :sql_type_metadata
         | 
| 6 6 | 
             
                  alias :array? :array
         | 
| 7 7 |  | 
| 8 | 
            +
                  def initialize(*, max_identifier_length: 63, **)
         | 
| 9 | 
            +
                    super
         | 
| 10 | 
            +
                    @max_identifier_length = max_identifier_length
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 8 13 | 
             
                  def serial?
         | 
| 9 14 | 
             
                    return unless default_function
         | 
| 10 15 |  | 
| 11 | 
            -
                    %r{\Anextval\('" | 
| 16 | 
            +
                    if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
         | 
| 17 | 
            +
                      sequence_name_from_parts(table_name, name, suffix) == sequence_name
         | 
| 18 | 
            +
                    end
         | 
| 12 19 | 
             
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  protected
         | 
| 22 | 
            +
                    attr_reader :max_identifier_length
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  private
         | 
| 25 | 
            +
                    def sequence_name_from_parts(table_name, column_name, suffix)
         | 
| 26 | 
            +
                      over_length = [table_name, column_name, suffix].map(&:length).sum + 2 - max_identifier_length
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                      if over_length > 0
         | 
| 29 | 
            +
                        column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
         | 
| 30 | 
            +
                        over_length -= column_name.length - column_name_length
         | 
| 31 | 
            +
                        column_name = column_name[0, column_name_length - [over_length, 0].min]
         | 
| 32 | 
            +
                      end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                      if over_length > 0
         | 
| 35 | 
            +
                        table_name = table_name[0, table_name.length - over_length]
         | 
| 36 | 
            +
                      end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                      "#{table_name}_#{column_name}_#{suffix}"
         | 
| 39 | 
            +
                    end
         | 
| 13 40 | 
             
                end
         | 
| 14 41 | 
             
              end
         | 
| 15 42 | 
             
            end
         | 
| @@ -62,7 +62,7 @@ module ActiveRecord | |
| 62 62 | 
             
                    def quote_default_expression(value, column) # :nodoc:
         | 
| 63 63 | 
             
                      if value.is_a?(Proc)
         | 
| 64 64 | 
             
                        value.call
         | 
| 65 | 
            -
                      elsif column.type == :uuid && /\(\)/.match?(value)
         | 
| 65 | 
            +
                      elsif column.type == :uuid && value.is_a?(String) && /\(\)/.match?(value)
         | 
| 66 66 | 
             
                        value # Does not quote function default values for UUID columns
         | 
| 67 67 | 
             
                      elsif column.respond_to?(:array?)
         | 
| 68 68 | 
             
                        value = type_cast_from_column(column, value)
         | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            # Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
         | 
| 2 | 
            -
            gem "pg", " | 
| 2 | 
            +
            gem "pg", ">= 0.18", "< 2.0"
         | 
| 3 3 | 
             
            require "pg"
         | 
| 4 4 |  | 
| 5 5 | 
             
            require "active_record/connection_adapters/abstract_adapter"
         | 
| @@ -198,6 +198,7 @@ module ActiveRecord | |
| 198 198 |  | 
| 199 199 | 
             
                      def dealloc(key)
         | 
| 200 200 | 
             
                        @connection.query "DEALLOCATE #{key}" if connection_active?
         | 
| 201 | 
            +
                      rescue PG::Error
         | 
| 201 202 | 
             
                      end
         | 
| 202 203 |  | 
| 203 204 | 
             
                      def connection_active?
         | 
| @@ -364,10 +365,11 @@ module ActiveRecord | |
| 364 365 | 
             
                  end
         | 
| 365 366 |  | 
| 366 367 | 
             
                  # Returns the configured supported identifier length supported by PostgreSQL
         | 
| 367 | 
            -
                  def  | 
| 368 | 
            +
                  def max_identifier_length
         | 
| 368 369 | 
             
                    @max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
         | 
| 369 370 | 
             
                  end
         | 
| 370 | 
            -
                  alias  | 
| 371 | 
            +
                  alias table_alias_length max_identifier_length
         | 
| 372 | 
            +
                  alias index_name_length max_identifier_length
         | 
| 371 373 |  | 
| 372 374 | 
             
                  # Set the authorized user for this session
         | 
| 373 375 | 
             
                  def session_auth=(user)
         | 
| @@ -340,7 +340,7 @@ module ActiveRecord | |
| 340 340 | 
             
                  end
         | 
| 341 341 |  | 
| 342 342 | 
             
                  def add_column(table_name, column_name, type, options = {}) #:nodoc:
         | 
| 343 | 
            -
                    if valid_alter_table_type?(type)
         | 
| 343 | 
            +
                    if valid_alter_table_type?(type) && !options[:primary_key]
         | 
| 344 344 | 
             
                      super(table_name, column_name, type, options)
         | 
| 345 345 | 
             
                    else
         | 
| 346 346 | 
             
                      alter_table(table_name) do |definition|
         | 
| @@ -440,18 +440,21 @@ module ActiveRecord | |
| 440 440 | 
             
                      options[:id] = false
         | 
| 441 441 | 
             
                      create_table(to, options) do |definition|
         | 
| 442 442 | 
             
                        @definition = definition
         | 
| 443 | 
            -
                         | 
| 443 | 
            +
                        if from_primary_key.is_a?(Array)
         | 
| 444 | 
            +
                          @definition.primary_keys from_primary_key
         | 
| 445 | 
            +
                        end
         | 
| 444 446 | 
             
                        columns(from).each do |column|
         | 
| 445 447 | 
             
                          column_name = options[:rename] ?
         | 
| 446 448 | 
             
                            (options[:rename][column.name] ||
         | 
| 447 449 | 
             
                             options[:rename][column.name.to_sym] ||
         | 
| 448 450 | 
             
                             column.name) : column.name
         | 
| 449 | 
            -
                          next if column_name == from_primary_key
         | 
| 450 451 |  | 
| 451 452 | 
             
                          @definition.column(column_name, column.type,
         | 
| 452 453 | 
             
                            limit: column.limit, default: column.default,
         | 
| 453 454 | 
             
                            precision: column.precision, scale: column.scale,
         | 
| 454 | 
            -
                            null: column.null, collation: column.collation | 
| 455 | 
            +
                            null: column.null, collation: column.collation,
         | 
| 456 | 
            +
                            primary_key: column_name == from_primary_key
         | 
| 457 | 
            +
                          )
         | 
| 455 458 | 
             
                        end
         | 
| 456 459 | 
             
                        yield @definition if block_given?
         | 
| 457 460 | 
             
                      end
         | 
| @@ -464,6 +467,9 @@ module ActiveRecord | |
| 464 467 | 
             
                    def copy_table_indexes(from, to, rename = {})
         | 
| 465 468 | 
             
                      indexes(from).each do |index|
         | 
| 466 469 | 
             
                        name = index.name
         | 
| 470 | 
            +
                        # indexes sqlite creates for internal use start with `sqlite_` and
         | 
| 471 | 
            +
                        # don't need to be copied
         | 
| 472 | 
            +
                        next if name.starts_with?("sqlite_")
         | 
| 467 473 | 
             
                        if to == "a#{from}"
         | 
| 468 474 | 
             
                          name = "t#{name}"
         | 
| 469 475 | 
             
                        elsif from == "a#{to}"
         | 
| @@ -479,6 +485,7 @@ module ActiveRecord | |
| 479 485 | 
             
                          # index name can't be the same
         | 
| 480 486 | 
             
                          opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
         | 
| 481 487 | 
             
                          opts[:unique] = true if index.unique
         | 
| 488 | 
            +
                          opts[:where] = index.where if index.where
         | 
| 482 489 | 
             
                          add_index(to, columns, opts)
         | 
| 483 490 | 
             
                        end
         | 
| 484 491 | 
             
                      end
         | 
| @@ -60,7 +60,7 @@ module ActiveRecord | |
| 60 60 | 
             
                  # the locked record.
         | 
| 61 61 | 
             
                  def lock!(lock = true)
         | 
| 62 62 | 
             
                    if persisted?
         | 
| 63 | 
            -
                      if  | 
| 63 | 
            +
                      if has_changes_to_save?
         | 
| 64 64 | 
             
                        ActiveSupport::Deprecation.warn(<<-MSG.squish)
         | 
| 65 65 | 
             
                          Locking a record with unpersisted changes is deprecated and will raise an
         | 
| 66 66 | 
             
                          exception in Rails 5.2. Use `save` to persist the changes, or `reload` to
         |