activerecord 5.2.0 → 5.2.3
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 +4 -4
 - data/CHANGELOG.md +214 -0
 - data/lib/active_record/association_relation.rb +3 -3
 - data/lib/active_record/associations.rb +9 -9
 - data/lib/active_record/associations/alias_tracker.rb +1 -1
 - data/lib/active_record/associations/association.rb +25 -10
 - data/lib/active_record/associations/belongs_to_association.rb +14 -5
 - data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
 - data/lib/active_record/associations/builder/belongs_to.rb +11 -2
 - data/lib/active_record/associations/collection_association.rb +19 -15
 - data/lib/active_record/associations/collection_proxy.rb +8 -34
 - data/lib/active_record/associations/has_many_association.rb +9 -0
 - data/lib/active_record/associations/has_many_through_association.rb +25 -1
 - data/lib/active_record/associations/has_one_association.rb +8 -0
 - data/lib/active_record/associations/has_one_through_association.rb +5 -1
 - data/lib/active_record/associations/join_dependency.rb +39 -64
 - data/lib/active_record/associations/join_dependency/join_association.rb +12 -18
 - data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
 - data/lib/active_record/associations/singular_association.rb +4 -10
 - data/lib/active_record/associations/through_association.rb +1 -1
 - data/lib/active_record/attribute_methods/dirty.rb +15 -10
 - data/lib/active_record/attribute_methods/read.rb +1 -1
 - data/lib/active_record/autosave_association.rb +7 -2
 - data/lib/active_record/callbacks.rb +4 -0
 - data/lib/active_record/collection_cache_key.rb +2 -2
 - data/lib/active_record/connection_adapters/abstract/connection_pool.rb +14 -8
 - data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
 - data/lib/active_record/connection_adapters/abstract/database_statements.rb +19 -6
 - data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -0
 - data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
 - data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
 - data/lib/active_record/connection_adapters/abstract/schema_statements.rb +5 -14
 - data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
 - data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
 - data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -19
 - data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
 - data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -2
 - data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
 - data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
 - data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
 - data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
 - data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
 - data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -26
 - data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
 - data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
 - data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -0
 - data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
 - data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -4
 - data/lib/active_record/core.rb +2 -1
 - data/lib/active_record/counter_cache.rb +17 -13
 - data/lib/active_record/enum.rb +1 -0
 - data/lib/active_record/errors.rb +18 -12
 - data/lib/active_record/gem_version.rb +1 -1
 - data/lib/active_record/log_subscriber.rb +1 -1
 - data/lib/active_record/migration.rb +1 -1
 - data/lib/active_record/migration/compatibility.rb +15 -15
 - data/lib/active_record/model_schema.rb +1 -1
 - data/lib/active_record/persistence.rb +6 -5
 - data/lib/active_record/query_cache.rb +4 -11
 - data/lib/active_record/querying.rb +1 -1
 - data/lib/active_record/railtie.rb +1 -3
 - data/lib/active_record/relation.rb +39 -20
 - data/lib/active_record/relation/calculations.rb +11 -8
 - data/lib/active_record/relation/delegation.rb +30 -0
 - data/lib/active_record/relation/finder_methods.rb +10 -8
 - data/lib/active_record/relation/merger.rb +10 -11
 - data/lib/active_record/relation/predicate_builder.rb +20 -14
 - data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
 - data/lib/active_record/relation/query_attribute.rb +5 -3
 - data/lib/active_record/relation/query_methods.rb +45 -19
 - data/lib/active_record/relation/spawn_methods.rb +1 -1
 - data/lib/active_record/scoping/named.rb +2 -0
 - data/lib/active_record/tasks/database_tasks.rb +1 -1
 - data/lib/active_record/timestamp.rb +8 -1
 - data/lib/active_record/transactions.rb +23 -20
 - data/lib/active_record/type/serialized.rb +4 -0
 - metadata +9 -10
 
| 
         @@ -560,17 +560,6 @@ module ActiveRecord 
     | 
|
| 
       560 
560 
     | 
    
         
             
                      @max_allowed_packet ||= (show_variable("max_allowed_packet") - bytes_margin)
         
     | 
| 
       561 
561 
     | 
    
         
             
                    end
         
     | 
| 
       562 
562 
     | 
    
         | 
| 
       563 
     | 
    
         
            -
                    def with_multi_statements
         
     | 
| 
       564 
     | 
    
         
            -
                      previous_flags = @config[:flags]
         
     | 
| 
       565 
     | 
    
         
            -
                      @config[:flags] = Mysql2::Client::MULTI_STATEMENTS
         
     | 
| 
       566 
     | 
    
         
            -
                      reconnect!
         
     | 
| 
       567 
     | 
    
         
            -
             
     | 
| 
       568 
     | 
    
         
            -
                      yield
         
     | 
| 
       569 
     | 
    
         
            -
                    ensure
         
     | 
| 
       570 
     | 
    
         
            -
                      @config[:flags] = previous_flags
         
     | 
| 
       571 
     | 
    
         
            -
                      reconnect!
         
     | 
| 
       572 
     | 
    
         
            -
                    end
         
     | 
| 
       573 
     | 
    
         
            -
             
     | 
| 
       574 
563 
     | 
    
         
             
                    def initialize_type_map(m = type_map)
         
     | 
| 
       575 
564 
     | 
    
         
             
                      super
         
     | 
| 
       576 
565 
     | 
    
         | 
| 
         @@ -815,15 +804,25 @@ module ActiveRecord 
     | 
|
| 
       815 
804 
     | 
    
         
             
                    end
         
     | 
| 
       816 
805 
     | 
    
         | 
| 
       817 
806 
     | 
    
         
             
                    def mismatched_foreign_key(message)
         
     | 
| 
       818 
     | 
    
         
            -
                       
     | 
| 
       819 
     | 
    
         
            -
             
     | 
| 
       820 
     | 
    
         
            -
                         
     | 
| 
      
 807 
     | 
    
         
            +
                      match = %r/
         
     | 
| 
      
 808 
     | 
    
         
            +
                        (?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
         
     | 
| 
      
 809 
     | 
    
         
            +
                        FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
         
     | 
| 
      
 810 
     | 
    
         
            +
                        REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
         
     | 
| 
      
 811 
     | 
    
         
            +
                      /xmi.match(message)
         
     | 
| 
      
 812 
     | 
    
         
            +
             
     | 
| 
      
 813 
     | 
    
         
            +
                      options = {
         
     | 
| 
       821 
814 
     | 
    
         
             
                        message: message,
         
     | 
| 
       822 
     | 
    
         
            -
             
     | 
| 
       823 
     | 
    
         
            -
             
     | 
| 
       824 
     | 
    
         
            -
             
     | 
| 
       825 
     | 
    
         
            -
                         
     | 
| 
       826 
     | 
    
         
            -
             
     | 
| 
      
 815 
     | 
    
         
            +
                      }
         
     | 
| 
      
 816 
     | 
    
         
            +
             
     | 
| 
      
 817 
     | 
    
         
            +
                      if match
         
     | 
| 
      
 818 
     | 
    
         
            +
                        options[:table] = match[:table]
         
     | 
| 
      
 819 
     | 
    
         
            +
                        options[:foreign_key] = match[:foreign_key]
         
     | 
| 
      
 820 
     | 
    
         
            +
                        options[:target_table] = match[:target_table]
         
     | 
| 
      
 821 
     | 
    
         
            +
                        options[:primary_key] = match[:primary_key]
         
     | 
| 
      
 822 
     | 
    
         
            +
                        options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
         
     | 
| 
      
 823 
     | 
    
         
            +
                      end
         
     | 
| 
      
 824 
     | 
    
         
            +
             
     | 
| 
      
 825 
     | 
    
         
            +
                      MismatchedForeignKey.new(options)
         
     | 
| 
       827 
826 
     | 
    
         
             
                    end
         
     | 
| 
       828 
827 
     | 
    
         | 
| 
       829 
828 
     | 
    
         
             
                    def integer_to_sql(limit) # :nodoc:
         
     | 
| 
         @@ -195,12 +195,12 @@ module ActiveRecord 
     | 
|
| 
       195 
195 
     | 
    
         
             
                        if e.path == path_to_adapter
         
     | 
| 
       196 
196 
     | 
    
         
             
                          # We can assume that a non-builtin adapter was specified, so it's
         
     | 
| 
       197 
197 
     | 
    
         
             
                          # either misspelled or missing from Gemfile.
         
     | 
| 
       198 
     | 
    
         
            -
                          raise  
     | 
| 
      
 198 
     | 
    
         
            +
                          raise LoadError, "Could not load the '#{spec[:adapter]}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
         
     | 
| 
       199 
199 
     | 
    
         | 
| 
       200 
200 
     | 
    
         
             
                        # Bubbled up from the adapter require. Prefix the exception message
         
     | 
| 
       201 
201 
     | 
    
         
             
                        # with some guidance about how to address it and reraise.
         
     | 
| 
       202 
202 
     | 
    
         
             
                        else
         
     | 
| 
       203 
     | 
    
         
            -
                          raise  
     | 
| 
      
 203 
     | 
    
         
            +
                          raise LoadError, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
         
     | 
| 
       204 
204 
     | 
    
         
             
                        end
         
     | 
| 
       205 
205 
     | 
    
         
             
                      end
         
     | 
| 
       206 
206 
     | 
    
         | 
| 
         @@ -3,15 +3,24 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module ActiveRecord
         
     | 
| 
       4 
4 
     | 
    
         
             
              module ConnectionAdapters
         
     | 
| 
       5 
5 
     | 
    
         
             
                module DetermineIfPreparableVisitor
         
     | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_accessor :preparable
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                  def accept(*)
         
     | 
| 
       9 
9 
     | 
    
         
             
                    @preparable = true
         
     | 
| 
       10 
10 
     | 
    
         
             
                    super
         
     | 
| 
       11 
11 
     | 
    
         
             
                  end
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                  def visit_Arel_Nodes_In( 
     | 
| 
      
 13 
     | 
    
         
            +
                  def visit_Arel_Nodes_In(o, collector)
         
     | 
| 
       14 
14 
     | 
    
         
             
                    @preparable = false
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    if Array === o.right && !o.right.empty?
         
     | 
| 
      
 17 
     | 
    
         
            +
                      o.right.delete_if do |bind|
         
     | 
| 
      
 18 
     | 
    
         
            +
                        if Arel::Nodes::BindParam === bind && Relation::QueryAttribute === bind.value
         
     | 
| 
      
 19 
     | 
    
         
            +
                          !bind.value.boundable?
         
     | 
| 
      
 20 
     | 
    
         
            +
                        end
         
     | 
| 
      
 21 
     | 
    
         
            +
                      end
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
       15 
24 
     | 
    
         
             
                    super
         
     | 
| 
       16 
25 
     | 
    
         
             
                  end
         
     | 
| 
       17 
26 
     | 
    
         | 
| 
         @@ -62,6 +62,42 @@ module ActiveRecord 
     | 
|
| 
       62 
62 
     | 
    
         
             
                        @connection.next_result while @connection.more_results?
         
     | 
| 
       63 
63 
     | 
    
         
             
                      end
         
     | 
| 
       64 
64 
     | 
    
         | 
| 
      
 65 
     | 
    
         
            +
                      def supports_set_server_option?
         
     | 
| 
      
 66 
     | 
    
         
            +
                        @connection.respond_to?(:set_server_option)
         
     | 
| 
      
 67 
     | 
    
         
            +
                      end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                      def multi_statements_enabled?(flags)
         
     | 
| 
      
 70 
     | 
    
         
            +
                        if flags.is_a?(Array)
         
     | 
| 
      
 71 
     | 
    
         
            +
                          flags.include?("MULTI_STATEMENTS")
         
     | 
| 
      
 72 
     | 
    
         
            +
                        else
         
     | 
| 
      
 73 
     | 
    
         
            +
                          (flags & Mysql2::Client::MULTI_STATEMENTS) != 0
         
     | 
| 
      
 74 
     | 
    
         
            +
                        end
         
     | 
| 
      
 75 
     | 
    
         
            +
                      end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                      def with_multi_statements
         
     | 
| 
      
 78 
     | 
    
         
            +
                        previous_flags = @config[:flags]
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                        unless multi_statements_enabled?(previous_flags)
         
     | 
| 
      
 81 
     | 
    
         
            +
                          if supports_set_server_option?
         
     | 
| 
      
 82 
     | 
    
         
            +
                            @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
         
     | 
| 
      
 83 
     | 
    
         
            +
                          else
         
     | 
| 
      
 84 
     | 
    
         
            +
                            @config[:flags] = Mysql2::Client::MULTI_STATEMENTS
         
     | 
| 
      
 85 
     | 
    
         
            +
                            reconnect!
         
     | 
| 
      
 86 
     | 
    
         
            +
                          end
         
     | 
| 
      
 87 
     | 
    
         
            +
                        end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                        yield
         
     | 
| 
      
 90 
     | 
    
         
            +
                      ensure
         
     | 
| 
      
 91 
     | 
    
         
            +
                        unless multi_statements_enabled?(previous_flags)
         
     | 
| 
      
 92 
     | 
    
         
            +
                          if supports_set_server_option?
         
     | 
| 
      
 93 
     | 
    
         
            +
                            @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
         
     | 
| 
      
 94 
     | 
    
         
            +
                          else
         
     | 
| 
      
 95 
     | 
    
         
            +
                            @config[:flags] = previous_flags
         
     | 
| 
      
 96 
     | 
    
         
            +
                            reconnect!
         
     | 
| 
      
 97 
     | 
    
         
            +
                          end
         
     | 
| 
      
 98 
     | 
    
         
            +
                        end
         
     | 
| 
      
 99 
     | 
    
         
            +
                      end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
       65 
101 
     | 
    
         
             
                      def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
         
     | 
| 
       66 
102 
     | 
    
         
             
                        # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
         
     | 
| 
       67 
103 
     | 
    
         
             
                        # made since we established the connection
         
     | 
| 
         @@ -80,8 +80,8 @@ module ActiveRecord 
     | 
|
| 
       80 
80 
     | 
    
         | 
| 
       81 
81 
     | 
    
         
             
                      def new_column_from_field(table_name, field)
         
     | 
| 
       82 
82 
     | 
    
         
             
                        type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
         
     | 
| 
       83 
     | 
    
         
            -
                        if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\( 
     | 
| 
       84 
     | 
    
         
            -
                          default, default_function = nil,  
     | 
| 
      
 83 
     | 
    
         
            +
                        if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(field[:Default])
         
     | 
| 
      
 84 
     | 
    
         
            +
                          default, default_function = nil, field[:Default]
         
     | 
| 
       85 
85 
     | 
    
         
             
                        else
         
     | 
| 
       86 
86 
     | 
    
         
             
                          default, default_function = field[:Default], nil
         
     | 
| 
       87 
87 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -33,7 +33,13 @@ module ActiveRecord 
     | 
|
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
                      def cast(value)
         
     | 
| 
       35 
35 
     | 
    
         
             
                        if value.is_a?(::String)
         
     | 
| 
       36 
     | 
    
         
            -
                          value =  
     | 
| 
      
 36 
     | 
    
         
            +
                          value = begin
         
     | 
| 
      
 37 
     | 
    
         
            +
                            @pg_decoder.decode(value)
         
     | 
| 
      
 38 
     | 
    
         
            +
                          rescue TypeError
         
     | 
| 
      
 39 
     | 
    
         
            +
                            # malformed array string is treated as [], will raise in PG 2.0 gem
         
     | 
| 
      
 40 
     | 
    
         
            +
                            # this keeps a consistent implementation
         
     | 
| 
      
 41 
     | 
    
         
            +
                            []
         
     | 
| 
      
 42 
     | 
    
         
            +
                          end
         
     | 
| 
       37 
43 
     | 
    
         
             
                        end
         
     | 
| 
       38 
44 
     | 
    
         
             
                        type_cast_array(value, :cast)
         
     | 
| 
       39 
45 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -66,6 +72,10 @@ module ActiveRecord 
     | 
|
| 
       66 
72 
     | 
    
         
             
                        deserialize(raw_old_value) != new_value
         
     | 
| 
       67 
73 
     | 
    
         
             
                      end
         
     | 
| 
       68 
74 
     | 
    
         | 
| 
      
 75 
     | 
    
         
            +
                      def force_equality?(value)
         
     | 
| 
      
 76 
     | 
    
         
            +
                        value.is_a?(::Array)
         
     | 
| 
      
 77 
     | 
    
         
            +
                      end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
       69 
79 
     | 
    
         
             
                      private
         
     | 
| 
       70 
80 
     | 
    
         | 
| 
       71 
81 
     | 
    
         
             
                        def type_cast_array(value, method)
         
     | 
| 
         @@ -17,6 +17,42 @@ module ActiveRecord 
     | 
|
| 
       17 
17 
     | 
    
         
             
                        "VALIDATE CONSTRAINT #{quote_column_name(name)}"
         
     | 
| 
       18 
18 
     | 
    
         
             
                      end
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
      
 20 
     | 
    
         
            +
                      def visit_ChangeColumnDefinition(o)
         
     | 
| 
      
 21 
     | 
    
         
            +
                        column = o.column
         
     | 
| 
      
 22 
     | 
    
         
            +
                        column.sql_type = type_to_sql(column.type, column.options)
         
     | 
| 
      
 23 
     | 
    
         
            +
                        quoted_column_name = quote_column_name(o.name)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                        change_column_sql = "ALTER COLUMN #{quoted_column_name} TYPE #{column.sql_type}".dup
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                        options = column_options(column)
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                        if options[:collation]
         
     | 
| 
      
 30 
     | 
    
         
            +
                          change_column_sql << " COLLATE \"#{options[:collation]}\""
         
     | 
| 
      
 31 
     | 
    
         
            +
                        end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                        if options[:using]
         
     | 
| 
      
 34 
     | 
    
         
            +
                          change_column_sql << " USING #{options[:using]}"
         
     | 
| 
      
 35 
     | 
    
         
            +
                        elsif options[:cast_as]
         
     | 
| 
      
 36 
     | 
    
         
            +
                          cast_as_type = type_to_sql(options[:cast_as], options)
         
     | 
| 
      
 37 
     | 
    
         
            +
                          change_column_sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
         
     | 
| 
      
 38 
     | 
    
         
            +
                        end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                        if options.key?(:default)
         
     | 
| 
      
 41 
     | 
    
         
            +
                          if options[:default].nil?
         
     | 
| 
      
 42 
     | 
    
         
            +
                            change_column_sql << ", ALTER COLUMN #{quoted_column_name} DROP DEFAULT"
         
     | 
| 
      
 43 
     | 
    
         
            +
                          else
         
     | 
| 
      
 44 
     | 
    
         
            +
                            quoted_default = quote_default_expression(options[:default], column)
         
     | 
| 
      
 45 
     | 
    
         
            +
                            change_column_sql << ", ALTER COLUMN #{quoted_column_name} SET DEFAULT #{quoted_default}"
         
     | 
| 
      
 46 
     | 
    
         
            +
                          end
         
     | 
| 
      
 47 
     | 
    
         
            +
                        end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                        if options.key?(:null)
         
     | 
| 
      
 50 
     | 
    
         
            +
                          change_column_sql << ", ALTER COLUMN #{quoted_column_name} #{options[:null] ? 'DROP' : 'SET'} NOT NULL"
         
     | 
| 
      
 51 
     | 
    
         
            +
                        end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                        change_column_sql
         
     | 
| 
      
 54 
     | 
    
         
            +
                      end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
       20 
56 
     | 
    
         
             
                      def add_column_options!(sql, options)
         
     | 
| 
       21 
57 
     | 
    
         
             
                        if options[:collation]
         
     | 
| 
       22 
58 
     | 
    
         
             
                          sql << " COLLATE \"#{options[:collation]}\""
         
     | 
| 
         @@ -124,7 +124,7 @@ module ActiveRecord 
     | 
|
| 
       124 
124 
     | 
    
         | 
| 
       125 
125 
     | 
    
         
             
                          # add info on sort order (only desc order is explicitly specified, asc is the default)
         
     | 
| 
       126 
126 
     | 
    
         
             
                          # and non-default opclasses
         
     | 
| 
       127 
     | 
    
         
            -
                          expressions.scan(/(?<column>\w+) 
     | 
| 
      
 127 
     | 
    
         
            +
                          expressions.scan(/(?<column>\w+)"?\s?(?<opclass>\w+_ops)?\s?(?<desc>DESC)?\s?(?<nulls>NULLS (?:FIRST|LAST))?/).each do |column, opclass, desc, nulls|
         
     | 
| 
       128 
128 
     | 
    
         
             
                            opclasses[column] = opclass.to_sym if opclass
         
     | 
| 
       129 
129 
     | 
    
         
             
                            if nulls
         
     | 
| 
       130 
130 
     | 
    
         
             
                              orders[column] = [desc, nulls].compact.join(" ")
         
     | 
| 
         @@ -683,34 +683,20 @@ module ActiveRecord 
     | 
|
| 
       683 
683 
     | 
    
         
             
                        end
         
     | 
| 
       684 
684 
     | 
    
         
             
                      end
         
     | 
| 
       685 
685 
     | 
    
         | 
| 
       686 
     | 
    
         
            -
                      def  
     | 
| 
       687 
     | 
    
         
            -
                         
     | 
| 
       688 
     | 
    
         
            -
                         
     | 
| 
       689 
     | 
    
         
            -
                        sql = "ALTER COLUMN #{quoted_column_name} TYPE #{sql_type}".dup
         
     | 
| 
       690 
     | 
    
         
            -
                        if options[:collation]
         
     | 
| 
       691 
     | 
    
         
            -
                          sql << " COLLATE \"#{options[:collation]}\""
         
     | 
| 
       692 
     | 
    
         
            -
                        end
         
     | 
| 
       693 
     | 
    
         
            -
                        if options[:using]
         
     | 
| 
       694 
     | 
    
         
            -
                          sql << " USING #{options[:using]}"
         
     | 
| 
       695 
     | 
    
         
            -
                        elsif options[:cast_as]
         
     | 
| 
       696 
     | 
    
         
            -
                          cast_as_type = type_to_sql(options[:cast_as], options)
         
     | 
| 
       697 
     | 
    
         
            -
                          sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
         
     | 
| 
       698 
     | 
    
         
            -
                        end
         
     | 
| 
       699 
     | 
    
         
            -
             
     | 
| 
       700 
     | 
    
         
            -
                        sql
         
     | 
| 
      
 686 
     | 
    
         
            +
                      def add_column_for_alter(table_name, column_name, type, options = {})
         
     | 
| 
      
 687 
     | 
    
         
            +
                        return super unless options.key?(:comment)
         
     | 
| 
      
 688 
     | 
    
         
            +
                        [super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
         
     | 
| 
       701 
689 
     | 
    
         
             
                      end
         
     | 
| 
       702 
690 
     | 
    
         | 
| 
       703 
691 
     | 
    
         
             
                      def change_column_for_alter(table_name, column_name, type, options = {})
         
     | 
| 
       704 
     | 
    
         
            -
                         
     | 
| 
       705 
     | 
    
         
            -
                         
     | 
| 
       706 
     | 
    
         
            -
                        sqls  
     | 
| 
      
 692 
     | 
    
         
            +
                        td = create_table_definition(table_name)
         
     | 
| 
      
 693 
     | 
    
         
            +
                        cd = td.new_column_definition(column_name, type, options)
         
     | 
| 
      
 694 
     | 
    
         
            +
                        sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
         
     | 
| 
       707 
695 
     | 
    
         
             
                        sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
         
     | 
| 
       708 
696 
     | 
    
         
             
                        sqls
         
     | 
| 
       709 
697 
     | 
    
         
             
                      end
         
     | 
| 
       710 
698 
     | 
    
         | 
| 
       711 
     | 
    
         
            -
             
     | 
| 
       712 
     | 
    
         
            -
                      # Changes the default value of a table column.
         
     | 
| 
       713 
     | 
    
         
            -
                      def change_column_default_for_alter(table_name, column_name, default_or_changes) # :nodoc:
         
     | 
| 
      
 699 
     | 
    
         
            +
                      def change_column_default_for_alter(table_name, column_name, default_or_changes)
         
     | 
| 
       714 
700 
     | 
    
         
             
                        column = column_for(table_name, column_name)
         
     | 
| 
       715 
701 
     | 
    
         
             
                        return unless column
         
     | 
| 
       716 
702 
     | 
    
         | 
| 
         @@ -725,8 +711,8 @@ module ActiveRecord 
     | 
|
| 
       725 
711 
     | 
    
         
             
                        end
         
     | 
| 
       726 
712 
     | 
    
         
             
                      end
         
     | 
| 
       727 
713 
     | 
    
         | 
| 
       728 
     | 
    
         
            -
                      def change_column_null_for_alter(table_name, column_name, null, default = nil) 
     | 
| 
       729 
     | 
    
         
            -
                        "ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
         
     | 
| 
      
 714 
     | 
    
         
            +
                      def change_column_null_for_alter(table_name, column_name, null, default = nil)
         
     | 
| 
      
 715 
     | 
    
         
            +
                        "ALTER COLUMN #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
         
     | 
| 
       730 
716 
     | 
    
         
             
                      end
         
     | 
| 
       731 
717 
     | 
    
         | 
| 
       732 
718 
     | 
    
         
             
                      def add_timestamps_for_alter(table_name, options = {})
         
     | 
| 
         @@ -751,7 +737,7 @@ module ActiveRecord 
     | 
|
| 
       751 
737 
     | 
    
         | 
| 
       752 
738 
     | 
    
         
             
                      def data_source_sql(name = nil, type: nil)
         
     | 
| 
       753 
739 
     | 
    
         
             
                        scope = quoted_scope(name, type: type)
         
     | 
| 
       754 
     | 
    
         
            -
                        scope[:type] ||= "'r','v','m','f'" # (r)elation/table, (v)iew, (m)aterialized view, (f)oreign table
         
     | 
| 
      
 740 
     | 
    
         
            +
                        scope[:type] ||= "'r','v','m','p','f'" # (r)elation/table, (v)iew, (m)aterialized view, (p)artitioned table, (f)oreign table
         
     | 
| 
       755 
741 
     | 
    
         | 
| 
       756 
742 
     | 
    
         
             
                        sql = "SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace".dup
         
     | 
| 
       757 
743 
     | 
    
         
             
                        sql << " WHERE n.nspname = #{scope[:schema]}"
         
     | 
| 
         @@ -765,7 +751,7 @@ module ActiveRecord 
     | 
|
| 
       765 
751 
     | 
    
         
             
                        type = \
         
     | 
| 
       766 
752 
     | 
    
         
             
                          case type
         
     | 
| 
       767 
753 
     | 
    
         
             
                          when "BASE TABLE"
         
     | 
| 
       768 
     | 
    
         
            -
                            "'r'"
         
     | 
| 
      
 754 
     | 
    
         
            +
                            "'r','p'"
         
     | 
| 
       769 
755 
     | 
    
         
             
                          when "VIEW"
         
     | 
| 
       770 
756 
     | 
    
         
             
                            "'v','m'"
         
     | 
| 
       771 
757 
     | 
    
         
             
                          when "FOREIGN TABLE"
         
     | 
| 
         @@ -68,7 +68,7 @@ module ActiveRecord 
     | 
|
| 
       68 
68 
     | 
    
         
             
                    # * <tt>"schema_name".table_name</tt>
         
     | 
| 
       69 
69 
     | 
    
         
             
                    # * <tt>"schema.name"."table name"</tt>
         
     | 
| 
       70 
70 
     | 
    
         
             
                    def extract_schema_qualified_name(string)
         
     | 
| 
       71 
     | 
    
         
            -
                      schema, table = string.scan(/[^" 
     | 
| 
      
 71 
     | 
    
         
            +
                      schema, table = string.scan(/[^".]+|"[^"]*"/)
         
     | 
| 
       72 
72 
     | 
    
         
             
                      if table.nil?
         
     | 
| 
       73 
73 
     | 
    
         
             
                        table = schema
         
     | 
| 
       74 
74 
     | 
    
         
             
                        schema = nil
         
     | 
| 
         @@ -4,6 +4,14 @@ 
     | 
|
| 
       4 
4 
     | 
    
         
             
            gem "pg", ">= 0.18", "< 2.0"
         
     | 
| 
       5 
5 
     | 
    
         
             
            require "pg"
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
      
 7 
     | 
    
         
            +
            # Use async_exec instead of exec_params on pg versions before 1.1
         
     | 
| 
      
 8 
     | 
    
         
            +
            class ::PG::Connection
         
     | 
| 
      
 9 
     | 
    
         
            +
              unless self.public_method_defined?(:async_exec_params)
         
     | 
| 
      
 10 
     | 
    
         
            +
                remove_method :exec_params
         
     | 
| 
      
 11 
     | 
    
         
            +
                alias exec_params async_exec
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       7 
15 
     | 
    
         
             
            require "active_record/connection_adapters/abstract_adapter"
         
     | 
| 
       8 
16 
     | 
    
         
             
            require "active_record/connection_adapters/statement_pool"
         
     | 
| 
       9 
17 
     | 
    
         
             
            require "active_record/connection_adapters/postgresql/column"
         
     | 
| 
         @@ -600,7 +608,7 @@ module ActiveRecord 
     | 
|
| 
       600 
608 
     | 
    
         
             
                      type_casted_binds = type_casted_binds(binds)
         
     | 
| 
       601 
609 
     | 
    
         
             
                      log(sql, name, binds, type_casted_binds) do
         
     | 
| 
       602 
610 
     | 
    
         
             
                        ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
         
     | 
| 
       603 
     | 
    
         
            -
                          @connection. 
     | 
| 
      
 611 
     | 
    
         
            +
                          @connection.exec_params(sql, type_casted_binds)
         
     | 
| 
       604 
612 
     | 
    
         
             
                        end
         
     | 
| 
       605 
613 
     | 
    
         
             
                      end
         
     | 
| 
       606 
614 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -12,11 +12,16 @@ module ActiveRecord 
     | 
|
| 
       12 
12 
     | 
    
         
             
                      quote_column_name(attr)
         
     | 
| 
       13 
13 
     | 
    
         
             
                    end
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
                    def quote_table_name(name)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      @quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       15 
19 
     | 
    
         
             
                    def quote_column_name(name)
         
     | 
| 
       16 
20 
     | 
    
         
             
                      @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}").freeze
         
     | 
| 
       17 
21 
     | 
    
         
             
                    end
         
     | 
| 
       18 
22 
     | 
    
         | 
| 
       19 
23 
     | 
    
         
             
                    def quoted_time(value)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      value = value.change(year: 2000, month: 1, day: 1)
         
     | 
| 
       20 
25 
     | 
    
         
             
                      quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
         
     | 
| 
       21 
26 
     | 
    
         
             
                    end
         
     | 
| 
       22 
27 
     | 
    
         | 
| 
         @@ -7,6 +7,10 @@ module ActiveRecord 
     | 
|
| 
       7 
7 
     | 
    
         
             
                    # Returns an array of indexes for the given table.
         
     | 
| 
       8 
8 
     | 
    
         
             
                    def indexes(table_name)
         
     | 
| 
       9 
9 
     | 
    
         
             
                      exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
         
     | 
| 
      
 10 
     | 
    
         
            +
                        # Indexes SQLite creates implicitly for internal use start with "sqlite_".
         
     | 
| 
      
 11 
     | 
    
         
            +
                        # See https://www.sqlite.org/fileformat2.html#intschema
         
     | 
| 
      
 12 
     | 
    
         
            +
                        next if row["name"].starts_with?("sqlite_")
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
       10 
14 
     | 
    
         
             
                        index_sql = query_value(<<-SQL, "SCHEMA")
         
     | 
| 
       11 
15 
     | 
    
         
             
                          SELECT sql
         
     | 
| 
       12 
16 
     | 
    
         
             
                          FROM sqlite_master
         
     | 
| 
         @@ -40,7 +44,7 @@ module ActiveRecord 
     | 
|
| 
       40 
44 
     | 
    
         
             
                          where: where,
         
     | 
| 
       41 
45 
     | 
    
         
             
                          orders: orders
         
     | 
| 
       42 
46 
     | 
    
         
             
                        )
         
     | 
| 
       43 
     | 
    
         
            -
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
                      end.compact
         
     | 
| 
       44 
48 
     | 
    
         
             
                    end
         
     | 
| 
       45 
49 
     | 
    
         | 
| 
       46 
50 
     | 
    
         
             
                    def create_schema_dumper(options)
         
     | 
| 
         @@ -9,7 +9,7 @@ require "active_record/connection_adapters/sqlite3/schema_definitions" 
     | 
|
| 
       9 
9 
     | 
    
         
             
            require "active_record/connection_adapters/sqlite3/schema_dumper"
         
     | 
| 
       10 
10 
     | 
    
         
             
            require "active_record/connection_adapters/sqlite3/schema_statements"
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            gem "sqlite3", "~> 1.3.6"
         
     | 
| 
      
 12 
     | 
    
         
            +
            gem "sqlite3", "~> 1.3", ">= 1.3.6"
         
     | 
| 
       13 
13 
     | 
    
         
             
            require "sqlite3"
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
            module ActiveRecord
         
     | 
| 
         @@ -453,9 +453,6 @@ module ActiveRecord 
     | 
|
| 
       453 
453 
     | 
    
         
             
                    def copy_table_indexes(from, to, rename = {})
         
     | 
| 
       454 
454 
     | 
    
         
             
                      indexes(from).each do |index|
         
     | 
| 
       455 
455 
     | 
    
         
             
                        name = index.name
         
     | 
| 
       456 
     | 
    
         
            -
                        # indexes sqlite creates for internal use start with `sqlite_` and
         
     | 
| 
       457 
     | 
    
         
            -
                        # don't need to be copied
         
     | 
| 
       458 
     | 
    
         
            -
                        next if name.starts_with?("sqlite_")
         
     | 
| 
       459 
456 
     | 
    
         
             
                        if to == "a#{from}"
         
     | 
| 
       460 
457 
     | 
    
         
             
                          name = "t#{name}"
         
     | 
| 
       461 
458 
     | 
    
         
             
                        elsif from == "a#{to}"
         
     | 
    
        data/lib/active_record/core.rb
    CHANGED
    
    | 
         @@ -184,7 +184,8 @@ module ActiveRecord 
     | 
|
| 
       184 
184 
     | 
    
         
             
                  end
         
     | 
| 
       185 
185 
     | 
    
         | 
| 
       186 
186 
     | 
    
         
             
                  def find_by(*args) # :nodoc:
         
     | 
| 
       187 
     | 
    
         
            -
                    return super if scope_attributes? || reflect_on_all_aggregations.any?
         
     | 
| 
      
 187 
     | 
    
         
            +
                    return super if scope_attributes? || reflect_on_all_aggregations.any? ||
         
     | 
| 
      
 188 
     | 
    
         
            +
                                    columns_hash.key?(inheritance_column) && base_class != self
         
     | 
| 
       188 
189 
     | 
    
         | 
| 
       189 
190 
     | 
    
         
             
                    hash = args.first
         
     | 
| 
       190 
191 
     | 
    
         | 
| 
         @@ -47,8 +47,12 @@ module ActiveRecord 
     | 
|
| 
       47 
47 
     | 
    
         
             
                      reflection   = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
         
     | 
| 
       48 
48 
     | 
    
         
             
                      counter_name = reflection.counter_cache_column
         
     | 
| 
       49 
49 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                      updates = { counter_name 
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
      
 50 
     | 
    
         
            +
                      updates = { counter_name => object.send(counter_association).count(:all) }
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                      if touch
         
     | 
| 
      
 53 
     | 
    
         
            +
                        names = touch if touch != true
         
     | 
| 
      
 54 
     | 
    
         
            +
                        updates.merge!(touch_attributes_with_time(*names))
         
     | 
| 
      
 55 
     | 
    
         
            +
                      end
         
     | 
| 
       52 
56 
     | 
    
         | 
| 
       53 
57 
     | 
    
         
             
                      unscoped.where(primary_key => object.id).update_all(updates)
         
     | 
| 
       54 
58 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -68,8 +72,8 @@ module ActiveRecord 
     | 
|
| 
       68 
72 
     | 
    
         
             
                  # * +counters+ - A Hash containing the names of the fields
         
     | 
| 
       69 
73 
     | 
    
         
             
                  #   to update as keys and the amount to update the field by as values.
         
     | 
| 
       70 
74 
     | 
    
         
             
                  # * <tt>:touch</tt> option - Touch timestamp columns when updating.
         
     | 
| 
       71 
     | 
    
         
            -
                  #    
     | 
| 
       72 
     | 
    
         
            -
                  #    
     | 
| 
      
 75 
     | 
    
         
            +
                  #   If attribute names are passed, they are updated along with updated_at/on
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #   attributes.
         
     | 
| 
       73 
77 
     | 
    
         
             
                  #
         
     | 
| 
       74 
78 
     | 
    
         
             
                  # ==== Examples
         
     | 
| 
       75 
79 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -107,11 +111,18 @@ module ActiveRecord 
     | 
|
| 
       107 
111 
     | 
    
         
             
                    end
         
     | 
| 
       108 
112 
     | 
    
         | 
| 
       109 
113 
     | 
    
         
             
                    if touch
         
     | 
| 
       110 
     | 
    
         
            -
                       
     | 
| 
      
 114 
     | 
    
         
            +
                      names = touch if touch != true
         
     | 
| 
      
 115 
     | 
    
         
            +
                      touch_updates = touch_attributes_with_time(*names)
         
     | 
| 
       111 
116 
     | 
    
         
             
                      updates << sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty?
         
     | 
| 
       112 
117 
     | 
    
         
             
                    end
         
     | 
| 
       113 
118 
     | 
    
         | 
| 
       114 
     | 
    
         
            -
                     
     | 
| 
      
 119 
     | 
    
         
            +
                    if id.is_a?(Relation) && self == id.klass
         
     | 
| 
      
 120 
     | 
    
         
            +
                      relation = id
         
     | 
| 
      
 121 
     | 
    
         
            +
                    else
         
     | 
| 
      
 122 
     | 
    
         
            +
                      relation = unscoped.where!(primary_key => id)
         
     | 
| 
      
 123 
     | 
    
         
            +
                    end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                    relation.update_all updates.join(", ")
         
     | 
| 
       115 
126 
     | 
    
         
             
                  end
         
     | 
| 
       116 
127 
     | 
    
         | 
| 
       117 
128 
     | 
    
         
             
                  # Increment a numeric field by one, via a direct SQL update.
         
     | 
| 
         @@ -165,13 +176,6 @@ module ActiveRecord 
     | 
|
| 
       165 
176 
     | 
    
         
             
                  def decrement_counter(counter_name, id, touch: nil)
         
     | 
| 
       166 
177 
     | 
    
         
             
                    update_counters(id, counter_name => -1, touch: touch)
         
     | 
| 
       167 
178 
     | 
    
         
             
                  end
         
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
                  private
         
     | 
| 
       170 
     | 
    
         
            -
                    def touch_updates(touch)
         
     | 
| 
       171 
     | 
    
         
            -
                      touch = timestamp_attributes_for_update_in_model if touch == true
         
     | 
| 
       172 
     | 
    
         
            -
                      touch_time = current_time_from_proper_timezone
         
     | 
| 
       173 
     | 
    
         
            -
                      Array(touch).map { |column| [ column, touch_time ] }.to_h
         
     | 
| 
       174 
     | 
    
         
            -
                    end
         
     | 
| 
       175 
179 
     | 
    
         
             
                end
         
     | 
| 
       176 
180 
     | 
    
         | 
| 
       177 
181 
     | 
    
         
             
                private
         
     |