activerecord 5.2.4.4 → 6.0.3.4
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 +777 -552
- data/MIT-LICENSE +3 -1
- data/README.rdoc +5 -3
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +10 -2
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations.rb +21 -16
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +56 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +12 -23
- data/lib/active_record/associations/collection_proxy.rb +13 -17
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -11
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +37 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +39 -32
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -11
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -24
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -54
- data/lib/active_record/attribute_methods/serialization.rb +1 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
- data/lib/active_record/attribute_methods/write.rb +17 -25
- data/lib/active_record/attributes.rb +13 -1
- data/lib/active_record/autosave_association.rb +3 -5
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -21
- data/lib/active_record/coders/yaml_column.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +103 -18
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +100 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +191 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +142 -215
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +132 -16
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +135 -146
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +139 -26
- data/lib/active_record/core.rb +103 -61
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +144 -474
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -6
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +11 -3
- data/lib/active_record/locking/optimistic.rb +5 -7
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +8 -27
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +104 -85
- data/lib/active_record/migration/command_recorder.rb +54 -22
- data/lib/active_record/migration/compatibility.rb +79 -52
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +33 -11
- data/lib/active_record/nested_attributes.rb +2 -4
- data/lib/active_record/no_touching.rb +9 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +232 -29
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +40 -38
- data/lib/active_record/relation.rb +322 -80
- data/lib/active_record/relation/batches.rb +13 -11
- data/lib/active_record/relation/calculations.rb +54 -48
- data/lib/active_record/relation/delegation.rb +33 -49
- data/lib/active_record/relation/finder_methods.rb +23 -28
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +11 -21
- data/lib/active_record/relation/predicate_builder.rb +5 -11
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +221 -70
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/relation/where_clause.rb +14 -11
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -12
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +6 -2
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +21 -17
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +23 -15
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +39 -26
- data/lib/active_record/touch_later.rb +5 -4
- data/lib/active_record/transactions.rb +64 -73
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +0 -1
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +62 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +14 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +115 -29
- data/lib/active_record/collection_cache_key.rb +0 -53
| @@ -11,8 +11,6 @@ require "active_record/connection_adapters/mysql/schema_dumper" | |
| 11 11 | 
             
            require "active_record/connection_adapters/mysql/schema_statements"
         | 
| 12 12 | 
             
            require "active_record/connection_adapters/mysql/type_metadata"
         | 
| 13 13 |  | 
| 14 | 
            -
            require "active_support/core_ext/string/strip"
         | 
| 15 | 
            -
             | 
| 16 14 | 
             
            module ActiveRecord
         | 
| 17 15 | 
             
              module ConnectionAdapters
         | 
| 18 16 | 
             
                class AbstractMysqlAdapter < AbstractAdapter
         | 
| @@ -31,7 +29,7 @@ module ActiveRecord | |
| 31 29 | 
             
                  NATIVE_DATABASE_TYPES = {
         | 
| 32 30 | 
             
                    primary_key: "bigint auto_increment PRIMARY KEY",
         | 
| 33 31 | 
             
                    string:      { name: "varchar", limit: 255 },
         | 
| 34 | 
            -
                    text:        { name: "text" | 
| 32 | 
            +
                    text:        { name: "text" },
         | 
| 35 33 | 
             
                    integer:     { name: "int", limit: 4 },
         | 
| 36 34 | 
             
                    float:       { name: "float", limit: 24 },
         | 
| 37 35 | 
             
                    decimal:     { name: "decimal" },
         | 
| @@ -39,41 +37,43 @@ module ActiveRecord | |
| 39 37 | 
             
                    timestamp:   { name: "timestamp" },
         | 
| 40 38 | 
             
                    time:        { name: "time" },
         | 
| 41 39 | 
             
                    date:        { name: "date" },
         | 
| 42 | 
            -
                    binary:      { name: "blob" | 
| 40 | 
            +
                    binary:      { name: "blob" },
         | 
| 41 | 
            +
                    blob:        { name: "blob" },
         | 
| 43 42 | 
             
                    boolean:     { name: "tinyint", limit: 1 },
         | 
| 44 43 | 
             
                    json:        { name: "json" },
         | 
| 45 44 | 
             
                  }
         | 
| 46 45 |  | 
| 47 46 | 
             
                  class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
         | 
| 48 | 
            -
                    private | 
| 49 | 
            -
                      stmt | 
| 50 | 
            -
             | 
| 47 | 
            +
                    private
         | 
| 48 | 
            +
                      def dealloc(stmt)
         | 
| 49 | 
            +
                        stmt.close
         | 
| 50 | 
            +
                      end
         | 
| 51 51 | 
             
                  end
         | 
| 52 52 |  | 
| 53 53 | 
             
                  def initialize(connection, logger, connection_options, config)
         | 
| 54 54 | 
             
                    super(connection, logger, config)
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                    if version < "5.1.10"
         | 
| 59 | 
            -
                      raise "Your version of MySQL (#{version_string}) is too old. Active Record supports MySQL >= 5.1.10."
         | 
| 60 | 
            -
                    end
         | 
| 61 55 | 
             
                  end
         | 
| 62 56 |  | 
| 63 | 
            -
                  def  | 
| 64 | 
            -
                     | 
| 57 | 
            +
                  def get_database_version #:nodoc:
         | 
| 58 | 
            +
                    full_version_string = get_full_version
         | 
| 59 | 
            +
                    version_string = version_string(full_version_string)
         | 
| 60 | 
            +
                    Version.new(version_string, full_version_string)
         | 
| 65 61 | 
             
                  end
         | 
| 66 62 |  | 
| 67 63 | 
             
                  def mariadb? # :nodoc:
         | 
| 68 64 | 
             
                    /mariadb/i.match?(full_version)
         | 
| 69 65 | 
             
                  end
         | 
| 70 66 |  | 
| 71 | 
            -
                  def supports_bulk_alter? | 
| 67 | 
            +
                  def supports_bulk_alter?
         | 
| 72 68 | 
             
                    true
         | 
| 73 69 | 
             
                  end
         | 
| 74 70 |  | 
| 75 71 | 
             
                  def supports_index_sort_order?
         | 
| 76 | 
            -
                    !mariadb? &&  | 
| 72 | 
            +
                    !mariadb? && database_version >= "8.0.1"
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  def supports_expression_index?
         | 
| 76 | 
            +
                    !mariadb? && database_version >= "8.0.13"
         | 
| 77 77 | 
             
                  end
         | 
| 78 78 |  | 
| 79 79 | 
             
                  def supports_transaction_isolation?
         | 
| @@ -97,18 +97,23 @@ module ActiveRecord | |
| 97 97 | 
             
                  end
         | 
| 98 98 |  | 
| 99 99 | 
             
                  def supports_datetime_with_precision?
         | 
| 100 | 
            -
                     | 
| 101 | 
            -
                      version >= "5.3.0"
         | 
| 102 | 
            -
                    else
         | 
| 103 | 
            -
                      version >= "5.6.4"
         | 
| 104 | 
            -
                    end
         | 
| 100 | 
            +
                    mariadb? || database_version >= "5.6.4"
         | 
| 105 101 | 
             
                  end
         | 
| 106 102 |  | 
| 107 103 | 
             
                  def supports_virtual_columns?
         | 
| 104 | 
            +
                    mariadb? || database_version >= "5.7.5"
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  # See https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html for more details.
         | 
| 108 | 
            +
                  def supports_optimizer_hints?
         | 
| 109 | 
            +
                    !mariadb? && database_version >= "5.7.7"
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  def supports_common_table_expressions?
         | 
| 108 113 | 
             
                    if mariadb?
         | 
| 109 | 
            -
                       | 
| 114 | 
            +
                      database_version >= "10.2.1"
         | 
| 110 115 | 
             
                    else
         | 
| 111 | 
            -
                       | 
| 116 | 
            +
                      database_version >= "8.0.1"
         | 
| 112 117 | 
             
                    end
         | 
| 113 118 | 
             
                  end
         | 
| 114 119 |  | 
| @@ -116,6 +121,14 @@ module ActiveRecord | |
| 116 121 | 
             
                    true
         | 
| 117 122 | 
             
                  end
         | 
| 118 123 |  | 
| 124 | 
            +
                  def supports_insert_on_duplicate_skip?
         | 
| 125 | 
            +
                    true
         | 
| 126 | 
            +
                  end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  def supports_insert_on_duplicate_update?
         | 
| 129 | 
            +
                    true
         | 
| 130 | 
            +
                  end
         | 
| 131 | 
            +
             | 
| 119 132 | 
             
                  def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
         | 
| 120 133 | 
             
                    query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
         | 
| 121 134 | 
             
                  end
         | 
| @@ -129,7 +142,7 @@ module ActiveRecord | |
| 129 142 | 
             
                  end
         | 
| 130 143 |  | 
| 131 144 | 
             
                  def index_algorithms
         | 
| 132 | 
            -
                    { default: "ALGORITHM = DEFAULT" | 
| 145 | 
            +
                    { default: +"ALGORITHM = DEFAULT", copy: +"ALGORITHM = COPY", inplace: +"ALGORITHM = INPLACE" }
         | 
| 133 146 | 
             
                  end
         | 
| 134 147 |  | 
| 135 148 | 
             
                  # HELPER METHODS ===========================================
         | 
| @@ -161,10 +174,9 @@ module ActiveRecord | |
| 161 174 |  | 
| 162 175 | 
             
                  # CONNECTION MANAGEMENT ====================================
         | 
| 163 176 |  | 
| 164 | 
            -
                   | 
| 165 | 
            -
                  def clear_cache!
         | 
| 177 | 
            +
                  def clear_cache! # :nodoc:
         | 
| 166 178 | 
             
                    reload_type_map
         | 
| 167 | 
            -
                     | 
| 179 | 
            +
                    super
         | 
| 168 180 | 
             
                  end
         | 
| 169 181 |  | 
| 170 182 | 
             
                  #--
         | 
| @@ -173,15 +185,17 @@ module ActiveRecord | |
| 173 185 |  | 
| 174 186 | 
             
                  def explain(arel, binds = [])
         | 
| 175 187 | 
             
                    sql     = "EXPLAIN #{to_sql(arel, binds)}"
         | 
| 176 | 
            -
                    start   =  | 
| 188 | 
            +
                    start   = Concurrent.monotonic_time
         | 
| 177 189 | 
             
                    result  = exec_query(sql, "EXPLAIN", binds)
         | 
| 178 | 
            -
                    elapsed =  | 
| 190 | 
            +
                    elapsed = Concurrent.monotonic_time - start
         | 
| 179 191 |  | 
| 180 192 | 
             
                    MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
         | 
| 181 193 | 
             
                  end
         | 
| 182 194 |  | 
| 183 195 | 
             
                  # Executes the SQL statement in the context of this connection.
         | 
| 184 196 | 
             
                  def execute(sql, name = nil)
         | 
| 197 | 
            +
                    materialize_transactions
         | 
| 198 | 
            +
             | 
| 185 199 | 
             
                    log(sql, name) do
         | 
| 186 200 | 
             
                      ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
         | 
| 187 201 | 
             
                        @connection.query(sql)
         | 
| @@ -213,19 +227,7 @@ module ActiveRecord | |
| 213 227 | 
             
                    execute "ROLLBACK"
         | 
| 214 228 | 
             
                  end
         | 
| 215 229 |  | 
| 216 | 
            -
                   | 
| 217 | 
            -
                  # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
         | 
| 218 | 
            -
                  # these, we must use a subquery.
         | 
| 219 | 
            -
                  def join_to_update(update, select, key) # :nodoc:
         | 
| 220 | 
            -
                    if select.limit || select.offset || select.orders.any?
         | 
| 221 | 
            -
                      super
         | 
| 222 | 
            -
                    else
         | 
| 223 | 
            -
                      update.table select.source
         | 
| 224 | 
            -
                      update.wheres = select.constraints
         | 
| 225 | 
            -
                    end
         | 
| 226 | 
            -
                  end
         | 
| 227 | 
            -
             | 
| 228 | 
            -
                  def empty_insert_statement_value
         | 
| 230 | 
            +
                  def empty_insert_statement_value(primary_key = nil)
         | 
| 229 231 | 
             
                    "VALUES ()"
         | 
| 230 232 | 
             
                  end
         | 
| 231 233 |  | 
| @@ -241,7 +243,7 @@ module ActiveRecord | |
| 241 243 | 
             
                  end
         | 
| 242 244 |  | 
| 243 245 | 
             
                  # Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
         | 
| 244 | 
            -
                  # Charset defaults to  | 
| 246 | 
            +
                  # Charset defaults to utf8mb4.
         | 
| 245 247 | 
             
                  #
         | 
| 246 248 | 
             
                  # Example:
         | 
| 247 249 | 
             
                  #   create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
         | 
| @@ -250,8 +252,12 @@ module ActiveRecord | |
| 250 252 | 
             
                  def create_database(name, options = {})
         | 
| 251 253 | 
             
                    if options[:collation]
         | 
| 252 254 | 
             
                      execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT COLLATE #{quote_table_name(options[:collation])}"
         | 
| 255 | 
            +
                    elsif options[:charset]
         | 
| 256 | 
            +
                      execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset])}"
         | 
| 257 | 
            +
                    elsif row_format_dynamic_by_default?
         | 
| 258 | 
            +
                      execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET `utf8mb4`"
         | 
| 253 259 | 
             
                    else
         | 
| 254 | 
            -
                       | 
| 260 | 
            +
                      raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
         | 
| 255 261 | 
             
                    end
         | 
| 256 262 | 
             
                  end
         | 
| 257 263 |  | 
| @@ -277,14 +283,10 @@ module ActiveRecord | |
| 277 283 | 
             
                    show_variable "collation_database"
         | 
| 278 284 | 
             
                  end
         | 
| 279 285 |  | 
| 280 | 
            -
                  def truncate(table_name, name = nil)
         | 
| 281 | 
            -
                    execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
         | 
| 282 | 
            -
                  end
         | 
| 283 | 
            -
             | 
| 284 286 | 
             
                  def table_comment(table_name) # :nodoc:
         | 
| 285 287 | 
             
                    scope = quoted_scope(table_name)
         | 
| 286 288 |  | 
| 287 | 
            -
                    query_value( | 
| 289 | 
            +
                    query_value(<<~SQL, "SCHEMA").presence
         | 
| 288 290 | 
             
                      SELECT table_comment
         | 
| 289 291 | 
             
                      FROM information_schema.tables
         | 
| 290 292 | 
             
                      WHERE table_schema = #{scope[:schema]}
         | 
| @@ -292,22 +294,8 @@ module ActiveRecord | |
| 292 294 | 
             
                    SQL
         | 
| 293 295 | 
             
                  end
         | 
| 294 296 |  | 
| 295 | 
            -
                  def  | 
| 296 | 
            -
                     | 
| 297 | 
            -
                      table, arguments = args.shift, args
         | 
| 298 | 
            -
                      method = :"#{command}_for_alter"
         | 
| 299 | 
            -
             | 
| 300 | 
            -
                      if respond_to?(method, true)
         | 
| 301 | 
            -
                        send(method, table, *arguments)
         | 
| 302 | 
            -
                      else
         | 
| 303 | 
            -
                        raise "Unknown method called : #{method}(#{arguments.inspect})"
         | 
| 304 | 
            -
                      end
         | 
| 305 | 
            -
                    end.join(", ")
         | 
| 306 | 
            -
             | 
| 307 | 
            -
                    execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
         | 
| 308 | 
            -
                  end
         | 
| 309 | 
            -
             | 
| 310 | 
            -
                  def change_table_comment(table_name, comment) #:nodoc:
         | 
| 297 | 
            +
                  def change_table_comment(table_name, comment_or_changes) # :nodoc:
         | 
| 298 | 
            +
                    comment = extract_new_comment_value(comment_or_changes)
         | 
| 311 299 | 
             
                    comment = "" if comment.nil?
         | 
| 312 300 | 
             
                    execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
         | 
| 313 301 | 
             
                  end
         | 
| @@ -363,7 +351,8 @@ module ActiveRecord | |
| 363 351 | 
             
                    change_column table_name, column_name, nil, null: null
         | 
| 364 352 | 
             
                  end
         | 
| 365 353 |  | 
| 366 | 
            -
                  def change_column_comment(table_name, column_name,  | 
| 354 | 
            +
                  def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
         | 
| 355 | 
            +
                    comment = extract_new_comment_value(comment_or_changes)
         | 
| 367 356 | 
             
                    change_column table_name, column_name, nil, comment: comment
         | 
| 368 357 | 
             
                  end
         | 
| 369 358 |  | 
| @@ -377,8 +366,8 @@ module ActiveRecord | |
| 377 366 | 
             
                  end
         | 
| 378 367 |  | 
| 379 368 | 
             
                  def add_index(table_name, column_name, options = {}) #:nodoc:
         | 
| 380 | 
            -
                    index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
         | 
| 381 | 
            -
                    sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}" | 
| 369 | 
            +
                    index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, **options)
         | 
| 370 | 
            +
                    sql = +"CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
         | 
| 382 371 | 
             
                    execute add_sql_comment!(sql, comment)
         | 
| 383 372 | 
             
                  end
         | 
| 384 373 |  | 
| @@ -392,7 +381,7 @@ module ActiveRecord | |
| 392 381 |  | 
| 393 382 | 
             
                    scope = quoted_scope(table_name)
         | 
| 394 383 |  | 
| 395 | 
            -
                    fk_info = exec_query( | 
| 384 | 
            +
                    fk_info = exec_query(<<~SQL, "SCHEMA")
         | 
| 396 385 | 
             
                      SELECT fk.referenced_table_name AS 'to_table',
         | 
| 397 386 | 
             
                             fk.referenced_column_name AS 'primary_key',
         | 
| 398 387 | 
             
                             fk.column_name AS 'column',
         | 
| @@ -429,12 +418,13 @@ module ActiveRecord | |
| 429 418 | 
             
                    create_table_info = create_table_info(table_name)
         | 
| 430 419 |  | 
| 431 420 | 
             
                    # strip create_definitions and partition_options
         | 
| 432 | 
            -
                     | 
| 421 | 
            +
                    # Be aware that `create_table_info` might not include any table options due to `NO_TABLE_OPTIONS` sql mode.
         | 
| 422 | 
            +
                    raw_table_options = create_table_info.sub(/\A.*\n\) ?/m, "").sub(/\n\/\*!.*\*\/\n\z/m, "").strip
         | 
| 433 423 |  | 
| 434 424 | 
             
                    # strip AUTO_INCREMENT
         | 
| 435 425 | 
             
                    raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
         | 
| 436 426 |  | 
| 437 | 
            -
                    table_options[:options] = raw_table_options
         | 
| 427 | 
            +
                    table_options[:options] = raw_table_options unless raw_table_options.blank?
         | 
| 438 428 |  | 
| 439 429 | 
             
                    # strip COMMENT
         | 
| 440 430 | 
             
                    if raw_table_options.sub!(/ COMMENT='.+'/, "")
         | 
| @@ -444,30 +434,6 @@ module ActiveRecord | |
| 444 434 | 
             
                    table_options
         | 
| 445 435 | 
             
                  end
         | 
| 446 436 |  | 
| 447 | 
            -
                  # Maps logical Rails types to MySQL-specific data types.
         | 
| 448 | 
            -
                  def type_to_sql(type, limit: nil, precision: nil, scale: nil, unsigned: nil, **) # :nodoc:
         | 
| 449 | 
            -
                    sql = \
         | 
| 450 | 
            -
                      case type.to_s
         | 
| 451 | 
            -
                      when "integer"
         | 
| 452 | 
            -
                        integer_to_sql(limit)
         | 
| 453 | 
            -
                      when "text"
         | 
| 454 | 
            -
                        text_to_sql(limit)
         | 
| 455 | 
            -
                      when "blob"
         | 
| 456 | 
            -
                        binary_to_sql(limit)
         | 
| 457 | 
            -
                      when "binary"
         | 
| 458 | 
            -
                        if (0..0xfff) === limit
         | 
| 459 | 
            -
                          "varbinary(#{limit})"
         | 
| 460 | 
            -
                        else
         | 
| 461 | 
            -
                          binary_to_sql(limit)
         | 
| 462 | 
            -
                        end
         | 
| 463 | 
            -
                      else
         | 
| 464 | 
            -
                        super
         | 
| 465 | 
            -
                      end
         | 
| 466 | 
            -
             | 
| 467 | 
            -
                    sql = "#{sql} unsigned" if unsigned && type != :primary_key
         | 
| 468 | 
            -
                    sql
         | 
| 469 | 
            -
                  end
         | 
| 470 | 
            -
             | 
| 471 437 | 
             
                  # SHOW VARIABLES LIKE 'name'
         | 
| 472 438 | 
             
                  def show_variable(name)
         | 
| 473 439 | 
             
                    query_value("SELECT @@#{name}", "SCHEMA")
         | 
| @@ -480,19 +446,36 @@ module ActiveRecord | |
| 480 446 |  | 
| 481 447 | 
             
                    scope = quoted_scope(table_name)
         | 
| 482 448 |  | 
| 483 | 
            -
                    query_values( | 
| 449 | 
            +
                    query_values(<<~SQL, "SCHEMA")
         | 
| 484 450 | 
             
                      SELECT column_name
         | 
| 485 | 
            -
                      FROM information_schema. | 
| 486 | 
            -
                      WHERE  | 
| 451 | 
            +
                      FROM information_schema.statistics
         | 
| 452 | 
            +
                      WHERE index_name = 'PRIMARY'
         | 
| 487 453 | 
             
                        AND table_schema = #{scope[:schema]}
         | 
| 488 454 | 
             
                        AND table_name = #{scope[:name]}
         | 
| 489 | 
            -
                      ORDER BY  | 
| 455 | 
            +
                      ORDER BY seq_in_index
         | 
| 490 456 | 
             
                    SQL
         | 
| 491 457 | 
             
                  end
         | 
| 492 458 |  | 
| 493 | 
            -
                  def  | 
| 459 | 
            +
                  def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
         | 
| 460 | 
            +
                    column = column_for_attribute(attribute)
         | 
| 461 | 
            +
             | 
| 462 | 
            +
                    if column.collation && !column.case_sensitive? && !value.nil?
         | 
| 463 | 
            +
                      ActiveSupport::Deprecation.warn(<<~MSG.squish)
         | 
| 464 | 
            +
                        Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
         | 
| 465 | 
            +
                        To continue case sensitive comparison on the :#{attribute.name} attribute in #{klass} model,
         | 
| 466 | 
            +
                        pass `case_sensitive: true` option explicitly to the uniqueness validator.
         | 
| 467 | 
            +
                      MSG
         | 
| 468 | 
            +
                      attribute.eq(Arel::Nodes::Bin.new(value))
         | 
| 469 | 
            +
                    else
         | 
| 470 | 
            +
                      super
         | 
| 471 | 
            +
                    end
         | 
| 472 | 
            +
                  end
         | 
| 473 | 
            +
             | 
| 474 | 
            +
                  def case_sensitive_comparison(attribute, value) # :nodoc:
         | 
| 475 | 
            +
                    column = column_for_attribute(attribute)
         | 
| 476 | 
            +
             | 
| 494 477 | 
             
                    if column.collation && !column.case_sensitive?
         | 
| 495 | 
            -
                       | 
| 478 | 
            +
                      attribute.eq(Arel::Nodes::Bin.new(value))
         | 
| 496 479 | 
             
                    else
         | 
| 497 480 | 
             
                      super
         | 
| 498 481 | 
             
                    end
         | 
| @@ -510,7 +493,7 @@ module ActiveRecord | |
| 510 493 | 
             
                  def columns_for_distinct(columns, orders) # :nodoc:
         | 
| 511 494 | 
             
                    order_columns = orders.reject(&:blank?).map { |s|
         | 
| 512 495 | 
             
                      # Convert Arel node to string
         | 
| 513 | 
            -
                      s = s | 
| 496 | 
            +
                      s = visitor.compile(s) unless s.is_a?(String)
         | 
| 514 497 | 
             
                      # Remove any ASC/DESC modifiers
         | 
| 515 498 | 
             
                      s.gsub(/\s+(?:ASC|DESC)\b/i, "")
         | 
| 516 499 | 
             
                    }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
         | 
| @@ -526,40 +509,27 @@ module ActiveRecord | |
| 526 509 | 
             
                    index.using == :btree || super
         | 
| 527 510 | 
             
                  end
         | 
| 528 511 |  | 
| 529 | 
            -
                  def  | 
| 530 | 
            -
                     | 
| 531 | 
            -
                      super { discard_remaining_results }
         | 
| 532 | 
            -
                    end
         | 
| 533 | 
            -
                  end
         | 
| 512 | 
            +
                  def build_insert_sql(insert) # :nodoc:
         | 
| 513 | 
            +
                    sql = +"INSERT #{insert.into} #{insert.values_list}"
         | 
| 534 514 |  | 
| 535 | 
            -
             | 
| 536 | 
            -
             | 
| 537 | 
            -
                       | 
| 538 | 
            -
             | 
| 539 | 
            -
             | 
| 540 | 
            -
             | 
| 541 | 
            -
                          total_sql_chunks << sql
         | 
| 542 | 
            -
                        else
         | 
| 543 | 
            -
                          previous_packet << sql
         | 
| 544 | 
            -
                        end
         | 
| 545 | 
            -
                      end
         | 
| 515 | 
            +
                    if insert.skip_duplicates?
         | 
| 516 | 
            +
                      no_op_column = quote_column_name(insert.keys.first)
         | 
| 517 | 
            +
                      sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
         | 
| 518 | 
            +
                    elsif insert.update_duplicates?
         | 
| 519 | 
            +
                      sql << " ON DUPLICATE KEY UPDATE "
         | 
| 520 | 
            +
                      sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
         | 
| 546 521 | 
             
                    end
         | 
| 547 522 |  | 
| 548 | 
            -
                     | 
| 549 | 
            -
             | 
| 550 | 
            -
                        raise ActiveRecordError, "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
         | 
| 551 | 
            -
                      elsif previous_packet.nil?
         | 
| 552 | 
            -
                        false
         | 
| 553 | 
            -
                      else
         | 
| 554 | 
            -
                        (current_packet.bytesize + previous_packet.bytesize) > max_allowed_packet
         | 
| 555 | 
            -
                      end
         | 
| 556 | 
            -
                    end
         | 
| 523 | 
            +
                    sql
         | 
| 524 | 
            +
                  end
         | 
| 557 525 |  | 
| 558 | 
            -
             | 
| 559 | 
            -
             | 
| 560 | 
            -
                       | 
| 526 | 
            +
                  def check_version # :nodoc:
         | 
| 527 | 
            +
                    if database_version < "5.5.8"
         | 
| 528 | 
            +
                      raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
         | 
| 561 529 | 
             
                    end
         | 
| 530 | 
            +
                  end
         | 
| 562 531 |  | 
| 532 | 
            +
                  private
         | 
| 563 533 | 
             
                    def initialize_type_map(m = type_map)
         | 
| 564 534 | 
             
                      super
         | 
| 565 535 |  | 
| @@ -587,24 +557,24 @@ module ActiveRecord | |
| 587 557 | 
             
                      m.alias_type %r(bit)i,           "binary"
         | 
| 588 558 |  | 
| 589 559 | 
             
                      m.register_type(%r(enum)i) do |sql_type|
         | 
| 590 | 
            -
                        limit = sql_type[/^enum\((.+)\)/i, 1]
         | 
| 560 | 
            +
                        limit = sql_type[/^enum\s*\((.+)\)/i, 1]
         | 
| 591 561 | 
             
                          .split(",").map { |enum| enum.strip.length - 2 }.max
         | 
| 592 562 | 
             
                        MysqlString.new(limit: limit)
         | 
| 593 563 | 
             
                      end
         | 
| 594 564 |  | 
| 595 565 | 
             
                      m.register_type(%r(^set)i) do |sql_type|
         | 
| 596 | 
            -
                        limit = sql_type[/^set\((.+)\)/i, 1]
         | 
| 566 | 
            +
                        limit = sql_type[/^set\s*\((.+)\)/i, 1]
         | 
| 597 567 | 
             
                          .split(",").map { |set| set.strip.length - 1 }.sum - 1
         | 
| 598 568 | 
             
                        MysqlString.new(limit: limit)
         | 
| 599 569 | 
             
                      end
         | 
| 600 570 | 
             
                    end
         | 
| 601 571 |  | 
| 602 | 
            -
                    def register_integer_type(mapping, key, options)
         | 
| 572 | 
            +
                    def register_integer_type(mapping, key, **options)
         | 
| 603 573 | 
             
                      mapping.register_type(key) do |sql_type|
         | 
| 604 574 | 
             
                        if /\bunsigned\b/.match?(sql_type)
         | 
| 605 | 
            -
                          Type::UnsignedInteger.new(options)
         | 
| 575 | 
            +
                          Type::UnsignedInteger.new(**options)
         | 
| 606 576 | 
             
                        else
         | 
| 607 | 
            -
                          Type::Integer.new(options)
         | 
| 577 | 
            +
                          Type::Integer.new(**options)
         | 
| 608 578 | 
             
                        end
         | 
| 609 579 | 
             
                      end
         | 
| 610 580 | 
             
                    end
         | 
| @@ -618,9 +588,13 @@ module ActiveRecord | |
| 618 588 | 
             
                    end
         | 
| 619 589 |  | 
| 620 590 | 
             
                    # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
         | 
| 591 | 
            +
                    ER_FILSORT_ABORT        = 1028
         | 
| 621 592 | 
             
                    ER_DUP_ENTRY            = 1062
         | 
| 622 593 | 
             
                    ER_NOT_NULL_VIOLATION   = 1048
         | 
| 594 | 
            +
                    ER_NO_REFERENCED_ROW    = 1216
         | 
| 595 | 
            +
                    ER_ROW_IS_REFERENCED    = 1217
         | 
| 623 596 | 
             
                    ER_DO_NOT_HAVE_DEFAULT  = 1364
         | 
| 597 | 
            +
                    ER_ROW_IS_REFERENCED_2  = 1451
         | 
| 624 598 | 
             
                    ER_NO_REFERENCED_ROW_2  = 1452
         | 
| 625 599 | 
             
                    ER_DATA_TOO_LONG        = 1406
         | 
| 626 600 | 
             
                    ER_OUT_OF_RANGE         = 1264
         | 
| @@ -630,35 +604,36 @@ module ActiveRecord | |
| 630 604 | 
             
                    ER_LOCK_WAIT_TIMEOUT    = 1205
         | 
| 631 605 | 
             
                    ER_QUERY_INTERRUPTED    = 1317
         | 
| 632 606 | 
             
                    ER_QUERY_TIMEOUT        = 3024
         | 
| 607 | 
            +
                    ER_FK_INCOMPATIBLE_COLUMNS = 3780
         | 
| 633 608 |  | 
| 634 | 
            -
                    def translate_exception(exception, message)
         | 
| 609 | 
            +
                    def translate_exception(exception, message:, sql:, binds:)
         | 
| 635 610 | 
             
                      case error_number(exception)
         | 
| 636 611 | 
             
                      when ER_DUP_ENTRY
         | 
| 637 | 
            -
                        RecordNotUnique.new(message)
         | 
| 638 | 
            -
                      when ER_NO_REFERENCED_ROW_2
         | 
| 639 | 
            -
                        InvalidForeignKey.new(message)
         | 
| 640 | 
            -
                      when ER_CANNOT_ADD_FOREIGN
         | 
| 641 | 
            -
                        mismatched_foreign_key(message)
         | 
| 612 | 
            +
                        RecordNotUnique.new(message, sql: sql, binds: binds)
         | 
| 613 | 
            +
                      when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
         | 
| 614 | 
            +
                        InvalidForeignKey.new(message, sql: sql, binds: binds)
         | 
| 615 | 
            +
                      when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
         | 
| 616 | 
            +
                        mismatched_foreign_key(message, sql: sql, binds: binds)
         | 
| 642 617 | 
             
                      when ER_CANNOT_CREATE_TABLE
         | 
| 643 618 | 
             
                        if message.include?("errno: 150")
         | 
| 644 | 
            -
                          mismatched_foreign_key(message)
         | 
| 619 | 
            +
                          mismatched_foreign_key(message, sql: sql, binds: binds)
         | 
| 645 620 | 
             
                        else
         | 
| 646 621 | 
             
                          super
         | 
| 647 622 | 
             
                        end
         | 
| 648 623 | 
             
                      when ER_DATA_TOO_LONG
         | 
| 649 | 
            -
                        ValueTooLong.new(message)
         | 
| 624 | 
            +
                        ValueTooLong.new(message, sql: sql, binds: binds)
         | 
| 650 625 | 
             
                      when ER_OUT_OF_RANGE
         | 
| 651 | 
            -
                        RangeError.new(message)
         | 
| 626 | 
            +
                        RangeError.new(message, sql: sql, binds: binds)
         | 
| 652 627 | 
             
                      when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
         | 
| 653 | 
            -
                        NotNullViolation.new(message)
         | 
| 628 | 
            +
                        NotNullViolation.new(message, sql: sql, binds: binds)
         | 
| 654 629 | 
             
                      when ER_LOCK_DEADLOCK
         | 
| 655 | 
            -
                        Deadlocked.new(message)
         | 
| 630 | 
            +
                        Deadlocked.new(message, sql: sql, binds: binds)
         | 
| 656 631 | 
             
                      when ER_LOCK_WAIT_TIMEOUT
         | 
| 657 | 
            -
                        LockWaitTimeout.new(message)
         | 
| 658 | 
            -
                      when ER_QUERY_TIMEOUT
         | 
| 659 | 
            -
                        StatementTimeout.new(message)
         | 
| 632 | 
            +
                        LockWaitTimeout.new(message, sql: sql, binds: binds)
         | 
| 633 | 
            +
                      when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
         | 
| 634 | 
            +
                        StatementTimeout.new(message, sql: sql, binds: binds)
         | 
| 660 635 | 
             
                      when ER_QUERY_INTERRUPTED
         | 
| 661 | 
            -
                        QueryCanceled.new(message)
         | 
| 636 | 
            +
                        QueryCanceled.new(message, sql: sql, binds: binds)
         | 
| 662 637 | 
             
                      else
         | 
| 663 638 | 
             
                        super
         | 
| 664 639 | 
             
                      end
         | 
| @@ -681,7 +656,7 @@ module ActiveRecord | |
| 681 656 | 
             
                      end
         | 
| 682 657 |  | 
| 683 658 | 
             
                      td = create_table_definition(table_name)
         | 
| 684 | 
            -
                      cd = td.new_column_definition(column.name, type, options)
         | 
| 659 | 
            +
                      cd = td.new_column_definition(column.name, type, **options)
         | 
| 685 660 | 
             
                      schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
         | 
| 686 661 | 
             
                    end
         | 
| 687 662 |  | 
| @@ -695,12 +670,12 @@ module ActiveRecord | |
| 695 670 |  | 
| 696 671 | 
             
                      current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
         | 
| 697 672 | 
             
                      td = create_table_definition(table_name)
         | 
| 698 | 
            -
                      cd = td.new_column_definition(new_column_name, current_type, options)
         | 
| 673 | 
            +
                      cd = td.new_column_definition(new_column_name, current_type, **options)
         | 
| 699 674 | 
             
                      schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
         | 
| 700 675 | 
             
                    end
         | 
| 701 676 |  | 
| 702 677 | 
             
                    def add_index_for_alter(table_name, column_name, options = {})
         | 
| 703 | 
            -
                      index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options)
         | 
| 678 | 
            +
                      index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, **options)
         | 
| 704 679 | 
             
                      index_algorithm[0, 0] = ", " if index_algorithm.present?
         | 
| 705 680 | 
             
                      "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
         | 
| 706 681 | 
             
                    end
         | 
| @@ -710,30 +685,8 @@ module ActiveRecord | |
| 710 685 | 
             
                      "DROP INDEX #{quote_column_name(index_name)}"
         | 
| 711 686 | 
             
                    end
         | 
| 712 687 |  | 
| 713 | 
            -
                    def add_timestamps_for_alter(table_name, options = {})
         | 
| 714 | 
            -
                      [add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
         | 
| 715 | 
            -
                    end
         | 
| 716 | 
            -
             | 
| 717 | 
            -
                    def remove_timestamps_for_alter(table_name, options = {})
         | 
| 718 | 
            -
                      [remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
         | 
| 719 | 
            -
                    end
         | 
| 720 | 
            -
             | 
| 721 | 
            -
                    # MySQL is too stupid to create a temporary table for use subquery, so we have
         | 
| 722 | 
            -
                    # to give it some prompting in the form of a subsubquery. Ugh!
         | 
| 723 | 
            -
                    def subquery_for(key, select)
         | 
| 724 | 
            -
                      subselect = select.clone
         | 
| 725 | 
            -
                      subselect.projections = [key]
         | 
| 726 | 
            -
             | 
| 727 | 
            -
                      # Materialize subquery by adding distinct
         | 
| 728 | 
            -
                      # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
         | 
| 729 | 
            -
                      subselect.distinct unless select.limit || select.offset || select.orders.any?
         | 
| 730 | 
            -
             | 
| 731 | 
            -
                      key_name = quote_column_name(key.name)
         | 
| 732 | 
            -
                      Arel::SelectManager.new(subselect.as("__active_record_temp")).project(Arel.sql(key_name))
         | 
| 733 | 
            -
                    end
         | 
| 734 | 
            -
             | 
| 735 688 | 
             
                    def supports_rename_index?
         | 
| 736 | 
            -
                      mariadb? ? false :  | 
| 689 | 
            +
                      mariadb? ? false : database_version >= "5.7.6"
         | 
| 737 690 | 
             
                    end
         | 
| 738 691 |  | 
| 739 692 | 
             
                    def configure_connection
         | 
| @@ -770,7 +723,7 @@ module ActiveRecord | |
| 770 723 | 
             
                      # https://dev.mysql.com/doc/refman/5.7/en/set-names.html
         | 
| 771 724 | 
             
                      # (trailing comma because variable_assignments will always have content)
         | 
| 772 725 | 
             
                      if @config[:encoding]
         | 
| 773 | 
            -
                        encoding = "NAMES #{@config[:encoding]}" | 
| 726 | 
            +
                        encoding = +"NAMES #{@config[:encoding]}"
         | 
| 774 727 | 
             
                        encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
         | 
| 775 728 | 
             
                        encoding << ", "
         | 
| 776 729 | 
             
                      end
         | 
| @@ -803,15 +756,21 @@ module ActiveRecord | |
| 803 756 | 
             
                      Arel::Visitors::MySQL.new(self)
         | 
| 804 757 | 
             
                    end
         | 
| 805 758 |  | 
| 806 | 
            -
                    def  | 
| 759 | 
            +
                    def build_statement_pool
         | 
| 760 | 
            +
                      StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
         | 
| 761 | 
            +
                    end
         | 
| 762 | 
            +
             | 
| 763 | 
            +
                    def mismatched_foreign_key(message, sql:, binds:)
         | 
| 807 764 | 
             
                      match = %r/
         | 
| 808 765 | 
             
                        (?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
         | 
| 809 766 | 
             
                        FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
         | 
| 810 767 | 
             
                        REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
         | 
| 811 | 
            -
                      /xmi.match( | 
| 768 | 
            +
                      /xmi.match(sql)
         | 
| 812 769 |  | 
| 813 770 | 
             
                      options = {
         | 
| 814 771 | 
             
                        message: message,
         | 
| 772 | 
            +
                        sql: sql,
         | 
| 773 | 
            +
                        binds: binds,
         | 
| 815 774 | 
             
                      }
         | 
| 816 775 |  | 
| 817 776 | 
             
                      if match
         | 
| @@ -822,42 +781,11 @@ module ActiveRecord | |
| 822 781 | 
             
                        options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
         | 
| 823 782 | 
             
                      end
         | 
| 824 783 |  | 
| 825 | 
            -
                      MismatchedForeignKey.new(options)
         | 
| 784 | 
            +
                      MismatchedForeignKey.new(**options)
         | 
| 826 785 | 
             
                    end
         | 
| 827 786 |  | 
| 828 | 
            -
                    def  | 
| 829 | 
            -
                       | 
| 830 | 
            -
                      when 1; "tinyint"
         | 
| 831 | 
            -
                      when 2; "smallint"
         | 
| 832 | 
            -
                      when 3; "mediumint"
         | 
| 833 | 
            -
                      when nil, 4; "int"
         | 
| 834 | 
            -
                      when 5..8; "bigint"
         | 
| 835 | 
            -
                      else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead.")
         | 
| 836 | 
            -
                      end
         | 
| 837 | 
            -
                    end
         | 
| 838 | 
            -
             | 
| 839 | 
            -
                    def text_to_sql(limit) # :nodoc:
         | 
| 840 | 
            -
                      case limit
         | 
| 841 | 
            -
                      when 0..0xff;               "tinytext"
         | 
| 842 | 
            -
                      when nil, 0x100..0xffff;    "text"
         | 
| 843 | 
            -
                      when 0x10000..0xffffff;     "mediumtext"
         | 
| 844 | 
            -
                      when 0x1000000..0xffffffff; "longtext"
         | 
| 845 | 
            -
                      else raise(ActiveRecordError, "No text type has byte length #{limit}")
         | 
| 846 | 
            -
                      end
         | 
| 847 | 
            -
                    end
         | 
| 848 | 
            -
             | 
| 849 | 
            -
                    def binary_to_sql(limit) # :nodoc:
         | 
| 850 | 
            -
                      case limit
         | 
| 851 | 
            -
                      when 0..0xff;               "tinyblob"
         | 
| 852 | 
            -
                      when nil, 0x100..0xffff;    "blob"
         | 
| 853 | 
            -
                      when 0x10000..0xffffff;     "mediumblob"
         | 
| 854 | 
            -
                      when 0x1000000..0xffffffff; "longblob"
         | 
| 855 | 
            -
                      else raise(ActiveRecordError, "No binary type has byte length #{limit}")
         | 
| 856 | 
            -
                      end
         | 
| 857 | 
            -
                    end
         | 
| 858 | 
            -
             | 
| 859 | 
            -
                    def version_string
         | 
| 860 | 
            -
                      full_version.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
         | 
| 787 | 
            +
                    def version_string(full_version_string)
         | 
| 788 | 
            +
                      full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
         | 
| 861 789 | 
             
                    end
         | 
| 862 790 |  | 
| 863 791 | 
             
                    class MysqlString < Type::String # :nodoc:
         | 
| @@ -870,7 +798,6 @@ module ActiveRecord | |
| 870 798 | 
             
                      end
         | 
| 871 799 |  | 
| 872 800 | 
             
                      private
         | 
| 873 | 
            -
             | 
| 874 801 | 
             
                        def cast_value(value)
         | 
| 875 802 | 
             
                          case value
         | 
| 876 803 | 
             
                          when true then "1"
         |