activerecord 5.2.3 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +898 -532
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +5 -4
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +95 -42
- data/lib/active_record/associations/association_scope.rb +21 -21
- data/lib/active_record/associations/belongs_to_association.rb +50 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
- data/lib/active_record/associations/builder/association.rb +23 -21
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +10 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +31 -29
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +27 -28
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +71 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +48 -35
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +133 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +45 -8
- data/lib/active_record/autosave_association.rb +76 -47
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +293 -132
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +21 -17
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +203 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +381 -146
- data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
- 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/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- 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/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- 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 +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- 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 +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- 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 +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +222 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +175 -187
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +285 -33
- data/lib/active_record/core.rb +308 -100
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +71 -17
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +32 -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 +197 -481
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +26 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +26 -22
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +34 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +141 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +205 -156
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +115 -58
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +402 -78
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +113 -101
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -93
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +65 -40
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -7
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +58 -40
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +487 -199
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +108 -58
- data/lib/active_record/relation.rb +375 -104
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +6 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +51 -8
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -43
- data/lib/active_record/tasks/database_tasks.rb +276 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +59 -117
- data/lib/active_record/translation.rb +1 -1
- 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 +6 -3
- data/lib/active_record/type/time.rb +10 -0
- 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.rb +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -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/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -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 +15 -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 +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -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 +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -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 +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -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/nodes.rb +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +117 -32
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
| @@ -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?
         | 
| @@ -92,23 +92,36 @@ module ActiveRecord | |
| 92 92 | 
             
                    true
         | 
| 93 93 | 
             
                  end
         | 
| 94 94 |  | 
| 95 | 
            +
                  def supports_check_constraints?
         | 
| 96 | 
            +
                    if mariadb?
         | 
| 97 | 
            +
                      database_version >= "10.2.1"
         | 
| 98 | 
            +
                    else
         | 
| 99 | 
            +
                      database_version >= "8.0.16"
         | 
| 100 | 
            +
                    end
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
             | 
| 95 103 | 
             
                  def supports_views?
         | 
| 96 104 | 
             
                    true
         | 
| 97 105 | 
             
                  end
         | 
| 98 106 |  | 
| 99 107 | 
             
                  def supports_datetime_with_precision?
         | 
| 100 | 
            -
                     | 
| 101 | 
            -
                      version >= "5.3.0"
         | 
| 102 | 
            -
                    else
         | 
| 103 | 
            -
                      version >= "5.6.4"
         | 
| 104 | 
            -
                    end
         | 
| 108 | 
            +
                    mariadb? || database_version >= "5.6.4"
         | 
| 105 109 | 
             
                  end
         | 
| 106 110 |  | 
| 107 111 | 
             
                  def supports_virtual_columns?
         | 
| 112 | 
            +
                    mariadb? || database_version >= "5.7.5"
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  # See https://dev.mysql.com/doc/refman/en/optimizer-hints.html for more details.
         | 
| 116 | 
            +
                  def supports_optimizer_hints?
         | 
| 117 | 
            +
                    !mariadb? && database_version >= "5.7.7"
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                  def supports_common_table_expressions?
         | 
| 108 121 | 
             
                    if mariadb?
         | 
| 109 | 
            -
                       | 
| 122 | 
            +
                      database_version >= "10.2.1"
         | 
| 110 123 | 
             
                    else
         | 
| 111 | 
            -
                       | 
| 124 | 
            +
                      database_version >= "8.0.1"
         | 
| 112 125 | 
             
                    end
         | 
| 113 126 | 
             
                  end
         | 
| 114 127 |  | 
| @@ -116,6 +129,14 @@ module ActiveRecord | |
| 116 129 | 
             
                    true
         | 
| 117 130 | 
             
                  end
         | 
| 118 131 |  | 
| 132 | 
            +
                  def supports_insert_on_duplicate_skip?
         | 
| 133 | 
            +
                    true
         | 
| 134 | 
            +
                  end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                  def supports_insert_on_duplicate_update?
         | 
| 137 | 
            +
                    true
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
             | 
| 119 140 | 
             
                  def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
         | 
| 120 141 | 
             
                    query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
         | 
| 121 142 | 
             
                  end
         | 
| @@ -129,7 +150,12 @@ module ActiveRecord | |
| 129 150 | 
             
                  end
         | 
| 130 151 |  | 
| 131 152 | 
             
                  def index_algorithms
         | 
| 132 | 
            -
                    { | 
| 153 | 
            +
                    {
         | 
| 154 | 
            +
                      default: "ALGORITHM = DEFAULT",
         | 
| 155 | 
            +
                      copy:    "ALGORITHM = COPY",
         | 
| 156 | 
            +
                      inplace: "ALGORITHM = INPLACE",
         | 
| 157 | 
            +
                      instant: "ALGORITHM = INSTANT",
         | 
| 158 | 
            +
                    }
         | 
| 133 159 | 
             
                  end
         | 
| 134 160 |  | 
| 135 161 | 
             
                  # HELPER METHODS ===========================================
         | 
| @@ -161,27 +187,20 @@ module ActiveRecord | |
| 161 187 |  | 
| 162 188 | 
             
                  # CONNECTION MANAGEMENT ====================================
         | 
| 163 189 |  | 
| 164 | 
            -
                   | 
| 165 | 
            -
                  def clear_cache!
         | 
| 190 | 
            +
                  def clear_cache! # :nodoc:
         | 
| 166 191 | 
             
                    reload_type_map
         | 
| 167 | 
            -
                     | 
| 192 | 
            +
                    super
         | 
| 168 193 | 
             
                  end
         | 
| 169 194 |  | 
| 170 195 | 
             
                  #--
         | 
| 171 196 | 
             
                  # DATABASE STATEMENTS ======================================
         | 
| 172 197 | 
             
                  #++
         | 
| 173 198 |  | 
| 174 | 
            -
                  def explain(arel, binds = [])
         | 
| 175 | 
            -
                    sql     = "EXPLAIN #{to_sql(arel, binds)}"
         | 
| 176 | 
            -
                    start   = Time.now
         | 
| 177 | 
            -
                    result  = exec_query(sql, "EXPLAIN", binds)
         | 
| 178 | 
            -
                    elapsed = Time.now - start
         | 
| 179 | 
            -
             | 
| 180 | 
            -
                    MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
         | 
| 181 | 
            -
                  end
         | 
| 182 | 
            -
             | 
| 183 199 | 
             
                  # Executes the SQL statement in the context of this connection.
         | 
| 184 200 | 
             
                  def execute(sql, name = nil)
         | 
| 201 | 
            +
                    materialize_transactions
         | 
| 202 | 
            +
                    mark_transaction_written_if_write(sql)
         | 
| 203 | 
            +
             | 
| 185 204 | 
             
                    log(sql, name) do
         | 
| 186 205 | 
             
                      ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
         | 
| 187 206 | 
             
                        @connection.query(sql)
         | 
| @@ -197,7 +216,7 @@ module ActiveRecord | |
| 197 216 | 
             
                  end
         | 
| 198 217 |  | 
| 199 218 | 
             
                  def begin_db_transaction
         | 
| 200 | 
            -
                    execute | 
| 219 | 
            +
                    execute("BEGIN", "TRANSACTION")
         | 
| 201 220 | 
             
                  end
         | 
| 202 221 |  | 
| 203 222 | 
             
                  def begin_isolated_db_transaction(isolation)
         | 
| @@ -206,26 +225,14 @@ module ActiveRecord | |
| 206 225 | 
             
                  end
         | 
| 207 226 |  | 
| 208 227 | 
             
                  def commit_db_transaction #:nodoc:
         | 
| 209 | 
            -
                    execute | 
| 228 | 
            +
                    execute("COMMIT", "TRANSACTION")
         | 
| 210 229 | 
             
                  end
         | 
| 211 230 |  | 
| 212 231 | 
             
                  def exec_rollback_db_transaction #:nodoc:
         | 
| 213 | 
            -
                    execute | 
| 232 | 
            +
                    execute("ROLLBACK", "TRANSACTION")
         | 
| 214 233 | 
             
                  end
         | 
| 215 234 |  | 
| 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
         | 
| 235 | 
            +
                  def empty_insert_statement_value(primary_key = nil)
         | 
| 229 236 | 
             
                    "VALUES ()"
         | 
| 230 237 | 
             
                  end
         | 
| 231 238 |  | 
| @@ -241,7 +248,7 @@ module ActiveRecord | |
| 241 248 | 
             
                  end
         | 
| 242 249 |  | 
| 243 250 | 
             
                  # Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
         | 
| 244 | 
            -
                  # Charset defaults to  | 
| 251 | 
            +
                  # Charset defaults to utf8mb4.
         | 
| 245 252 | 
             
                  #
         | 
| 246 253 | 
             
                  # Example:
         | 
| 247 254 | 
             
                  #   create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
         | 
| @@ -250,8 +257,12 @@ module ActiveRecord | |
| 250 257 | 
             
                  def create_database(name, options = {})
         | 
| 251 258 | 
             
                    if options[:collation]
         | 
| 252 259 | 
             
                      execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT COLLATE #{quote_table_name(options[:collation])}"
         | 
| 260 | 
            +
                    elsif options[:charset]
         | 
| 261 | 
            +
                      execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset])}"
         | 
| 262 | 
            +
                    elsif row_format_dynamic_by_default?
         | 
| 263 | 
            +
                      execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET `utf8mb4`"
         | 
| 253 264 | 
             
                    else
         | 
| 254 | 
            -
                       | 
| 265 | 
            +
                      raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
         | 
| 255 266 | 
             
                    end
         | 
| 256 267 | 
             
                  end
         | 
| 257 268 |  | 
| @@ -277,14 +288,10 @@ module ActiveRecord | |
| 277 288 | 
             
                    show_variable "collation_database"
         | 
| 278 289 | 
             
                  end
         | 
| 279 290 |  | 
| 280 | 
            -
                  def truncate(table_name, name = nil)
         | 
| 281 | 
            -
                    execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
         | 
| 282 | 
            -
                  end
         | 
| 283 | 
            -
             | 
| 284 291 | 
             
                  def table_comment(table_name) # :nodoc:
         | 
| 285 292 | 
             
                    scope = quoted_scope(table_name)
         | 
| 286 293 |  | 
| 287 | 
            -
                    query_value( | 
| 294 | 
            +
                    query_value(<<~SQL, "SCHEMA").presence
         | 
| 288 295 | 
             
                      SELECT table_comment
         | 
| 289 296 | 
             
                      FROM information_schema.tables
         | 
| 290 297 | 
             
                      WHERE table_schema = #{scope[:schema]}
         | 
| @@ -292,22 +299,8 @@ module ActiveRecord | |
| 292 299 | 
             
                    SQL
         | 
| 293 300 | 
             
                  end
         | 
| 294 301 |  | 
| 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:
         | 
| 302 | 
            +
                  def change_table_comment(table_name, comment_or_changes) # :nodoc:
         | 
| 303 | 
            +
                    comment = extract_new_comment_value(comment_or_changes)
         | 
| 311 304 | 
             
                    comment = "" if comment.nil?
         | 
| 312 305 | 
             
                    execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
         | 
| 313 306 | 
             
                  end
         | 
| @@ -317,6 +310,8 @@ module ActiveRecord | |
| 317 310 | 
             
                  # Example:
         | 
| 318 311 | 
             
                  #   rename_table('octopuses', 'octopi')
         | 
| 319 312 | 
             
                  def rename_table(table_name, new_name)
         | 
| 313 | 
            +
                    schema_cache.clear_data_source_cache!(table_name.to_s)
         | 
| 314 | 
            +
                    schema_cache.clear_data_source_cache!(new_name.to_s)
         | 
| 320 315 | 
             
                    execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
         | 
| 321 316 | 
             
                    rename_table_indexes(table_name, new_name)
         | 
| 322 317 | 
             
                  end
         | 
| @@ -336,7 +331,8 @@ module ActiveRecord | |
| 336 331 | 
             
                  # Although this command ignores most +options+ and the block if one is given,
         | 
| 337 332 | 
             
                  # it can be helpful to provide these in a migration's +change+ method so it can be reverted.
         | 
| 338 333 | 
             
                  # In that case, +options+ and the block will be used by create_table.
         | 
| 339 | 
            -
                  def drop_table(table_name, options | 
| 334 | 
            +
                  def drop_table(table_name, **options)
         | 
| 335 | 
            +
                    schema_cache.clear_data_source_cache!(table_name.to_s)
         | 
| 340 336 | 
             
                    execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
         | 
| 341 337 | 
             
                  end
         | 
| 342 338 |  | 
| @@ -363,12 +359,13 @@ module ActiveRecord | |
| 363 359 | 
             
                    change_column table_name, column_name, nil, null: null
         | 
| 364 360 | 
             
                  end
         | 
| 365 361 |  | 
| 366 | 
            -
                  def change_column_comment(table_name, column_name,  | 
| 362 | 
            +
                  def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
         | 
| 363 | 
            +
                    comment = extract_new_comment_value(comment_or_changes)
         | 
| 367 364 | 
             
                    change_column table_name, column_name, nil, comment: comment
         | 
| 368 365 | 
             
                  end
         | 
| 369 366 |  | 
| 370 | 
            -
                  def change_column(table_name, column_name, type, options | 
| 371 | 
            -
                    execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}")
         | 
| 367 | 
            +
                  def change_column(table_name, column_name, type, **options) #:nodoc:
         | 
| 368 | 
            +
                    execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
         | 
| 372 369 | 
             
                  end
         | 
| 373 370 |  | 
| 374 371 | 
             
                  def rename_column(table_name, column_name, new_column_name) #:nodoc:
         | 
| @@ -376,10 +373,13 @@ module ActiveRecord | |
| 376 373 | 
             
                    rename_column_indexes(table_name, column_name, new_column_name)
         | 
| 377 374 | 
             
                  end
         | 
| 378 375 |  | 
| 379 | 
            -
                  def add_index(table_name, column_name, options | 
| 380 | 
            -
                     | 
| 381 | 
            -
             | 
| 382 | 
            -
                     | 
| 376 | 
            +
                  def add_index(table_name, column_name, **options) #:nodoc:
         | 
| 377 | 
            +
                    index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
         | 
| 378 | 
            +
             | 
| 379 | 
            +
                    return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
         | 
| 380 | 
            +
             | 
| 381 | 
            +
                    create_index = CreateIndexDefinition.new(index, algorithm)
         | 
| 382 | 
            +
                    execute schema_creation.accept(create_index)
         | 
| 383 383 | 
             
                  end
         | 
| 384 384 |  | 
| 385 385 | 
             
                  def add_sql_comment!(sql, comment) # :nodoc:
         | 
| @@ -392,7 +392,7 @@ module ActiveRecord | |
| 392 392 |  | 
| 393 393 | 
             
                    scope = quoted_scope(table_name)
         | 
| 394 394 |  | 
| 395 | 
            -
                    fk_info = exec_query( | 
| 395 | 
            +
                    fk_info = exec_query(<<~SQL, "SCHEMA")
         | 
| 396 396 | 
             
                      SELECT fk.referenced_table_name AS 'to_table',
         | 
| 397 397 | 
             
                             fk.referenced_column_name AS 'primary_key',
         | 
| 398 398 | 
             
                             fk.column_name AS 'column',
         | 
| @@ -423,51 +423,63 @@ module ActiveRecord | |
| 423 423 | 
             
                    end
         | 
| 424 424 | 
             
                  end
         | 
| 425 425 |  | 
| 426 | 
            -
                  def  | 
| 427 | 
            -
                     | 
| 426 | 
            +
                  def check_constraints(table_name)
         | 
| 427 | 
            +
                    if supports_check_constraints?
         | 
| 428 | 
            +
                      scope = quoted_scope(table_name)
         | 
| 429 | 
            +
             | 
| 430 | 
            +
                      chk_info = exec_query(<<~SQL, "SCHEMA")
         | 
| 431 | 
            +
                        SELECT cc.constraint_name AS 'name',
         | 
| 432 | 
            +
                              cc.check_clause AS 'expression'
         | 
| 433 | 
            +
                        FROM information_schema.check_constraints cc
         | 
| 434 | 
            +
                        JOIN information_schema.table_constraints tc
         | 
| 435 | 
            +
                        USING (constraint_schema, constraint_name)
         | 
| 436 | 
            +
                        WHERE tc.table_schema = #{scope[:schema]}
         | 
| 437 | 
            +
                          AND tc.table_name = #{scope[:name]}
         | 
| 438 | 
            +
                          AND cc.constraint_schema = #{scope[:schema]}
         | 
| 439 | 
            +
                      SQL
         | 
| 440 | 
            +
             | 
| 441 | 
            +
                      chk_info.map do |row|
         | 
| 442 | 
            +
                        options = {
         | 
| 443 | 
            +
                          name: row["name"]
         | 
| 444 | 
            +
                        }
         | 
| 445 | 
            +
                        expression = row["expression"]
         | 
| 446 | 
            +
                        expression = expression[1..-2] unless mariadb? # remove parentheses added by mysql
         | 
| 447 | 
            +
                        CheckConstraintDefinition.new(table_name, expression, options)
         | 
| 448 | 
            +
                      end
         | 
| 449 | 
            +
                    else
         | 
| 450 | 
            +
                      raise NotImplementedError
         | 
| 451 | 
            +
                    end
         | 
| 452 | 
            +
                  end
         | 
| 428 453 |  | 
| 454 | 
            +
                  def table_options(table_name) # :nodoc:
         | 
| 429 455 | 
             
                    create_table_info = create_table_info(table_name)
         | 
| 430 456 |  | 
| 431 457 | 
             
                    # strip create_definitions and partition_options
         | 
| 432 | 
            -
                     | 
| 458 | 
            +
                    # Be aware that `create_table_info` might not include any table options due to `NO_TABLE_OPTIONS` sql mode.
         | 
| 459 | 
            +
                    raw_table_options = create_table_info.sub(/\A.*\n\) ?/m, "").sub(/\n\/\*!.*\*\/\n\z/m, "").strip
         | 
| 460 | 
            +
             | 
| 461 | 
            +
                    return if raw_table_options.empty?
         | 
| 462 | 
            +
             | 
| 463 | 
            +
                    table_options = {}
         | 
| 464 | 
            +
             | 
| 465 | 
            +
                    if / DEFAULT CHARSET=(?<charset>\w+)(?: COLLATE=(?<collation>\w+))?/ =~ raw_table_options
         | 
| 466 | 
            +
                      raw_table_options = $` + $' # before part + after part
         | 
| 467 | 
            +
                      table_options[:charset] = charset
         | 
| 468 | 
            +
                      table_options[:collation] = collation if collation
         | 
| 469 | 
            +
                    end
         | 
| 433 470 |  | 
| 434 471 | 
             
                    # strip AUTO_INCREMENT
         | 
| 435 472 | 
             
                    raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
         | 
| 436 473 |  | 
| 437 | 
            -
                    table_options[:options] = raw_table_options
         | 
| 438 | 
            -
             | 
| 439 474 | 
             
                    # strip COMMENT
         | 
| 440 475 | 
             
                    if raw_table_options.sub!(/ COMMENT='.+'/, "")
         | 
| 441 476 | 
             
                      table_options[:comment] = table_comment(table_name)
         | 
| 442 477 | 
             
                    end
         | 
| 443 478 |  | 
| 479 | 
            +
                    table_options[:options] = raw_table_options unless raw_table_options == "ENGINE=InnoDB"
         | 
| 444 480 | 
             
                    table_options
         | 
| 445 481 | 
             
                  end
         | 
| 446 482 |  | 
| 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 483 | 
             
                  # SHOW VARIABLES LIKE 'name'
         | 
| 472 484 | 
             
                  def show_variable(name)
         | 
| 473 485 | 
             
                    query_value("SELECT @@#{name}", "SCHEMA")
         | 
| @@ -480,19 +492,21 @@ module ActiveRecord | |
| 480 492 |  | 
| 481 493 | 
             
                    scope = quoted_scope(table_name)
         | 
| 482 494 |  | 
| 483 | 
            -
                    query_values( | 
| 495 | 
            +
                    query_values(<<~SQL, "SCHEMA")
         | 
| 484 496 | 
             
                      SELECT column_name
         | 
| 485 | 
            -
                      FROM information_schema. | 
| 486 | 
            -
                      WHERE  | 
| 497 | 
            +
                      FROM information_schema.statistics
         | 
| 498 | 
            +
                      WHERE index_name = 'PRIMARY'
         | 
| 487 499 | 
             
                        AND table_schema = #{scope[:schema]}
         | 
| 488 500 | 
             
                        AND table_name = #{scope[:name]}
         | 
| 489 | 
            -
                      ORDER BY  | 
| 501 | 
            +
                      ORDER BY seq_in_index
         | 
| 490 502 | 
             
                    SQL
         | 
| 491 503 | 
             
                  end
         | 
| 492 504 |  | 
| 493 | 
            -
                  def case_sensitive_comparison( | 
| 505 | 
            +
                  def case_sensitive_comparison(attribute, value) # :nodoc:
         | 
| 506 | 
            +
                    column = column_for_attribute(attribute)
         | 
| 507 | 
            +
             | 
| 494 508 | 
             
                    if column.collation && !column.case_sensitive?
         | 
| 495 | 
            -
                       | 
| 509 | 
            +
                      attribute.eq(Arel::Nodes::Bin.new(value))
         | 
| 496 510 | 
             
                    else
         | 
| 497 511 | 
             
                      super
         | 
| 498 512 | 
             
                    end
         | 
| @@ -506,14 +520,14 @@ module ActiveRecord | |
| 506 520 | 
             
                  # In MySQL 5.7.5 and up, ONLY_FULL_GROUP_BY affects handling of queries that use
         | 
| 507 521 | 
             
                  # DISTINCT and ORDER BY. It requires the ORDER BY columns in the select list for
         | 
| 508 522 | 
             
                  # distinct queries, and requires that the ORDER BY include the distinct column.
         | 
| 509 | 
            -
                  # See https://dev.mysql.com/doc/refman/ | 
| 523 | 
            +
                  # See https://dev.mysql.com/doc/refman/en/group-by-handling.html
         | 
| 510 524 | 
             
                  def columns_for_distinct(columns, orders) # :nodoc:
         | 
| 511 | 
            -
                    order_columns = orders. | 
| 525 | 
            +
                    order_columns = orders.compact_blank.map { |s|
         | 
| 512 526 | 
             
                      # Convert Arel node to string
         | 
| 513 | 
            -
                      s = s | 
| 527 | 
            +
                      s = visitor.compile(s) unless s.is_a?(String)
         | 
| 514 528 | 
             
                      # Remove any ASC/DESC modifiers
         | 
| 515 529 | 
             
                      s.gsub(/\s+(?:ASC|DESC)\b/i, "")
         | 
| 516 | 
            -
                    }. | 
| 530 | 
            +
                    }.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
         | 
| 517 531 |  | 
| 518 532 | 
             
                    (order_columns << super).join(", ")
         | 
| 519 533 | 
             
                  end
         | 
| @@ -526,44 +540,35 @@ module ActiveRecord | |
| 526 540 | 
             
                    index.using == :btree || super
         | 
| 527 541 | 
             
                  end
         | 
| 528 542 |  | 
| 529 | 
            -
                  def  | 
| 530 | 
            -
                     | 
| 531 | 
            -
                      super { discard_remaining_results }
         | 
| 532 | 
            -
                    end
         | 
| 533 | 
            -
                  end
         | 
| 543 | 
            +
                  def build_insert_sql(insert) # :nodoc:
         | 
| 544 | 
            +
                    sql = +"INSERT #{insert.into} #{insert.values_list}"
         | 
| 534 545 |  | 
| 535 | 
            -
             | 
| 536 | 
            -
             | 
| 537 | 
            -
                       | 
| 538 | 
            -
             | 
| 539 | 
            -
             | 
| 540 | 
            -
             | 
| 541 | 
            -
             | 
| 542 | 
            -
                        else
         | 
| 543 | 
            -
                          previous_packet << sql
         | 
| 544 | 
            -
                        end
         | 
| 545 | 
            -
                      end
         | 
| 546 | 
            +
                    if insert.skip_duplicates?
         | 
| 547 | 
            +
                      no_op_column = quote_column_name(insert.keys.first)
         | 
| 548 | 
            +
                      sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
         | 
| 549 | 
            +
                    elsif insert.update_duplicates?
         | 
| 550 | 
            +
                      sql << " ON DUPLICATE KEY UPDATE "
         | 
| 551 | 
            +
                      sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
         | 
| 552 | 
            +
                      sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
         | 
| 546 553 | 
             
                    end
         | 
| 547 554 |  | 
| 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
         | 
| 555 | 
            +
                    sql
         | 
| 556 | 
            +
                  end
         | 
| 557 557 |  | 
| 558 | 
            -
             | 
| 559 | 
            -
             | 
| 560 | 
            -
                       | 
| 558 | 
            +
                  def check_version # :nodoc:
         | 
| 559 | 
            +
                    if database_version < "5.5.8"
         | 
| 560 | 
            +
                      raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
         | 
| 561 561 | 
             
                    end
         | 
| 562 | 
            +
                  end
         | 
| 562 563 |  | 
| 564 | 
            +
                  private
         | 
| 563 565 | 
             
                    def initialize_type_map(m = type_map)
         | 
| 564 566 | 
             
                      super
         | 
| 565 567 |  | 
| 566 | 
            -
                       | 
| 568 | 
            +
                      m.register_type(%r(char)i) do |sql_type|
         | 
| 569 | 
            +
                        limit = extract_limit(sql_type)
         | 
| 570 | 
            +
                        Type.lookup(:string, adapter: :mysql2, limit: limit)
         | 
| 571 | 
            +
                      end
         | 
| 567 572 |  | 
| 568 573 | 
             
                      m.register_type %r(tinytext)i,   Type::Text.new(limit: 2**8 - 1)
         | 
| 569 574 | 
             
                      m.register_type %r(tinyblob)i,   Type::Binary.new(limit: 2**8 - 1)
         | 
| @@ -583,28 +588,19 @@ module ActiveRecord | |
| 583 588 | 
             
                      register_integer_type m, %r(^tinyint)i,   limit: 1
         | 
| 584 589 |  | 
| 585 590 | 
             
                      m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
         | 
| 586 | 
            -
                      m.alias_type %r(year)i, | 
| 587 | 
            -
                      m.alias_type %r(bit)i, | 
| 588 | 
            -
             | 
| 589 | 
            -
                      m.register_type(%r(enum)i) do |sql_type|
         | 
| 590 | 
            -
                        limit = sql_type[/^enum\((.+)\)/i, 1]
         | 
| 591 | 
            -
                          .split(",").map { |enum| enum.strip.length - 2 }.max
         | 
| 592 | 
            -
                        MysqlString.new(limit: limit)
         | 
| 593 | 
            -
                      end
         | 
| 591 | 
            +
                      m.alias_type %r(year)i, "integer"
         | 
| 592 | 
            +
                      m.alias_type %r(bit)i,  "binary"
         | 
| 594 593 |  | 
| 595 | 
            -
                      m.register_type | 
| 596 | 
            -
             | 
| 597 | 
            -
                          .split(",").map { |set| set.strip.length - 1 }.sum - 1
         | 
| 598 | 
            -
                        MysqlString.new(limit: limit)
         | 
| 599 | 
            -
                      end
         | 
| 594 | 
            +
                      m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
         | 
| 595 | 
            +
                      m.register_type %r(^set)i,  Type.lookup(:string, adapter: :mysql2)
         | 
| 600 596 | 
             
                    end
         | 
| 601 597 |  | 
| 602 | 
            -
                    def register_integer_type(mapping, key, options)
         | 
| 598 | 
            +
                    def register_integer_type(mapping, key, **options)
         | 
| 603 599 | 
             
                      mapping.register_type(key) do |sql_type|
         | 
| 604 600 | 
             
                        if /\bunsigned\b/.match?(sql_type)
         | 
| 605 | 
            -
                          Type::UnsignedInteger.new(options)
         | 
| 601 | 
            +
                          Type::UnsignedInteger.new(**options)
         | 
| 606 602 | 
             
                        else
         | 
| 607 | 
            -
                          Type::Integer.new(options)
         | 
| 603 | 
            +
                          Type::Integer.new(**options)
         | 
| 608 604 | 
             
                        end
         | 
| 609 605 | 
             
                      end
         | 
| 610 606 | 
             
                    end
         | 
| @@ -617,10 +613,15 @@ module ActiveRecord | |
| 617 613 | 
             
                      end
         | 
| 618 614 | 
             
                    end
         | 
| 619 615 |  | 
| 620 | 
            -
                    # See https://dev.mysql.com/doc/ | 
| 616 | 
            +
                    # See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
         | 
| 617 | 
            +
                    ER_DB_CREATE_EXISTS     = 1007
         | 
| 618 | 
            +
                    ER_FILSORT_ABORT        = 1028
         | 
| 621 619 | 
             
                    ER_DUP_ENTRY            = 1062
         | 
| 622 620 | 
             
                    ER_NOT_NULL_VIOLATION   = 1048
         | 
| 621 | 
            +
                    ER_NO_REFERENCED_ROW    = 1216
         | 
| 622 | 
            +
                    ER_ROW_IS_REFERENCED    = 1217
         | 
| 623 623 | 
             
                    ER_DO_NOT_HAVE_DEFAULT  = 1364
         | 
| 624 | 
            +
                    ER_ROW_IS_REFERENCED_2  = 1451
         | 
| 624 625 | 
             
                    ER_NO_REFERENCED_ROW_2  = 1452
         | 
| 625 626 | 
             
                    ER_DATA_TOO_LONG        = 1406
         | 
| 626 627 | 
             
                    ER_OUT_OF_RANGE         = 1264
         | 
| @@ -630,41 +631,50 @@ module ActiveRecord | |
| 630 631 | 
             
                    ER_LOCK_WAIT_TIMEOUT    = 1205
         | 
| 631 632 | 
             
                    ER_QUERY_INTERRUPTED    = 1317
         | 
| 632 633 | 
             
                    ER_QUERY_TIMEOUT        = 3024
         | 
| 634 | 
            +
                    ER_FK_INCOMPATIBLE_COLUMNS = 3780
         | 
| 633 635 |  | 
| 634 | 
            -
                    def translate_exception(exception, message)
         | 
| 636 | 
            +
                    def translate_exception(exception, message:, sql:, binds:)
         | 
| 635 637 | 
             
                      case error_number(exception)
         | 
| 638 | 
            +
                      when nil
         | 
| 639 | 
            +
                        if exception.message.match?(/MySQL client is not connected/i)
         | 
| 640 | 
            +
                          ConnectionNotEstablished.new(exception)
         | 
| 641 | 
            +
                        else
         | 
| 642 | 
            +
                          super
         | 
| 643 | 
            +
                        end
         | 
| 644 | 
            +
                      when ER_DB_CREATE_EXISTS
         | 
| 645 | 
            +
                        DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
         | 
| 636 646 | 
             
                      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)
         | 
| 647 | 
            +
                        RecordNotUnique.new(message, sql: sql, binds: binds)
         | 
| 648 | 
            +
                      when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
         | 
| 649 | 
            +
                        InvalidForeignKey.new(message, sql: sql, binds: binds)
         | 
| 650 | 
            +
                      when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
         | 
| 651 | 
            +
                        mismatched_foreign_key(message, sql: sql, binds: binds)
         | 
| 642 652 | 
             
                      when ER_CANNOT_CREATE_TABLE
         | 
| 643 653 | 
             
                        if message.include?("errno: 150")
         | 
| 644 | 
            -
                          mismatched_foreign_key(message)
         | 
| 654 | 
            +
                          mismatched_foreign_key(message, sql: sql, binds: binds)
         | 
| 645 655 | 
             
                        else
         | 
| 646 656 | 
             
                          super
         | 
| 647 657 | 
             
                        end
         | 
| 648 658 | 
             
                      when ER_DATA_TOO_LONG
         | 
| 649 | 
            -
                        ValueTooLong.new(message)
         | 
| 659 | 
            +
                        ValueTooLong.new(message, sql: sql, binds: binds)
         | 
| 650 660 | 
             
                      when ER_OUT_OF_RANGE
         | 
| 651 | 
            -
                        RangeError.new(message)
         | 
| 661 | 
            +
                        RangeError.new(message, sql: sql, binds: binds)
         | 
| 652 662 | 
             
                      when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
         | 
| 653 | 
            -
                        NotNullViolation.new(message)
         | 
| 663 | 
            +
                        NotNullViolation.new(message, sql: sql, binds: binds)
         | 
| 654 664 | 
             
                      when ER_LOCK_DEADLOCK
         | 
| 655 | 
            -
                        Deadlocked.new(message)
         | 
| 665 | 
            +
                        Deadlocked.new(message, sql: sql, binds: binds)
         | 
| 656 666 | 
             
                      when ER_LOCK_WAIT_TIMEOUT
         | 
| 657 | 
            -
                        LockWaitTimeout.new(message)
         | 
| 658 | 
            -
                      when ER_QUERY_TIMEOUT
         | 
| 659 | 
            -
                        StatementTimeout.new(message)
         | 
| 667 | 
            +
                        LockWaitTimeout.new(message, sql: sql, binds: binds)
         | 
| 668 | 
            +
                      when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
         | 
| 669 | 
            +
                        StatementTimeout.new(message, sql: sql, binds: binds)
         | 
| 660 670 | 
             
                      when ER_QUERY_INTERRUPTED
         | 
| 661 | 
            -
                        QueryCanceled.new(message)
         | 
| 671 | 
            +
                        QueryCanceled.new(message, sql: sql, binds: binds)
         | 
| 662 672 | 
             
                      else
         | 
| 663 673 | 
             
                        super
         | 
| 664 674 | 
             
                      end
         | 
| 665 675 | 
             
                    end
         | 
| 666 676 |  | 
| 667 | 
            -
                    def change_column_for_alter(table_name, column_name, type, options | 
| 677 | 
            +
                    def change_column_for_alter(table_name, column_name, type, **options)
         | 
| 668 678 | 
             
                      column = column_for(table_name, column_name)
         | 
| 669 679 | 
             
                      type ||= column.sql_type
         | 
| 670 680 |  | 
| @@ -681,59 +691,53 @@ module ActiveRecord | |
| 681 691 | 
             
                      end
         | 
| 682 692 |  | 
| 683 693 | 
             
                      td = create_table_definition(table_name)
         | 
| 684 | 
            -
                      cd = td.new_column_definition(column.name, type, options)
         | 
| 694 | 
            +
                      cd = td.new_column_definition(column.name, type, **options)
         | 
| 685 695 | 
             
                      schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
         | 
| 686 696 | 
             
                    end
         | 
| 687 697 |  | 
| 688 698 | 
             
                    def rename_column_for_alter(table_name, column_name, new_column_name)
         | 
| 699 | 
            +
                      return rename_column_sql(table_name, column_name, new_column_name) if supports_rename_column?
         | 
| 700 | 
            +
             | 
| 689 701 | 
             
                      column  = column_for(table_name, column_name)
         | 
| 690 702 | 
             
                      options = {
         | 
| 691 703 | 
             
                        default: column.default,
         | 
| 692 704 | 
             
                        null: column.null,
         | 
| 693 | 
            -
                        auto_increment: column.auto_increment | 
| 705 | 
            +
                        auto_increment: column.auto_increment?,
         | 
| 706 | 
            +
                        comment: column.comment
         | 
| 694 707 | 
             
                      }
         | 
| 695 708 |  | 
| 696 709 | 
             
                      current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
         | 
| 697 710 | 
             
                      td = create_table_definition(table_name)
         | 
| 698 | 
            -
                      cd = td.new_column_definition(new_column_name, current_type, options)
         | 
| 711 | 
            +
                      cd = td.new_column_definition(new_column_name, current_type, **options)
         | 
| 699 712 | 
             
                      schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
         | 
| 700 713 | 
             
                    end
         | 
| 701 714 |  | 
| 702 | 
            -
                    def add_index_for_alter(table_name, column_name, options | 
| 703 | 
            -
                       | 
| 704 | 
            -
                       | 
| 705 | 
            -
                      "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
         | 
| 706 | 
            -
                    end
         | 
| 707 | 
            -
             | 
| 708 | 
            -
                    def remove_index_for_alter(table_name, options = {})
         | 
| 709 | 
            -
                      index_name = index_name_for_remove(table_name, options)
         | 
| 710 | 
            -
                      "DROP INDEX #{quote_column_name(index_name)}"
         | 
| 711 | 
            -
                    end
         | 
| 715 | 
            +
                    def add_index_for_alter(table_name, column_name, **options)
         | 
| 716 | 
            +
                      index, algorithm, _ = add_index_options(table_name, column_name, **options)
         | 
| 717 | 
            +
                      algorithm = ", #{algorithm}" if algorithm
         | 
| 712 718 |  | 
| 713 | 
            -
             | 
| 714 | 
            -
                      [add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
         | 
| 719 | 
            +
                      "ADD #{schema_creation.accept(index)}#{algorithm}"
         | 
| 715 720 | 
             
                    end
         | 
| 716 721 |  | 
| 717 | 
            -
                    def  | 
| 718 | 
            -
                       | 
| 722 | 
            +
                    def remove_index_for_alter(table_name, column_name = nil, **options)
         | 
| 723 | 
            +
                      index_name = index_name_for_remove(table_name, column_name, options)
         | 
| 724 | 
            +
                      "DROP INDEX #{quote_column_name(index_name)}"
         | 
| 719 725 | 
             
                    end
         | 
| 720 726 |  | 
| 721 | 
            -
                     | 
| 722 | 
            -
             | 
| 723 | 
            -
             | 
| 724 | 
            -
                       | 
| 725 | 
            -
             | 
| 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))
         | 
| 727 | 
            +
                    def supports_rename_index?
         | 
| 728 | 
            +
                      if mariadb?
         | 
| 729 | 
            +
                        database_version >= "10.5.2"
         | 
| 730 | 
            +
                      else
         | 
| 731 | 
            +
                        database_version >= "5.7.6"
         | 
| 732 | 
            +
                      end
         | 
| 733 733 | 
             
                    end
         | 
| 734 734 |  | 
| 735 | 
            -
                    def  | 
| 736 | 
            -
                      mariadb? | 
| 735 | 
            +
                    def supports_rename_column?
         | 
| 736 | 
            +
                      if mariadb?
         | 
| 737 | 
            +
                        database_version >= "10.5.2"
         | 
| 738 | 
            +
                      else
         | 
| 739 | 
            +
                        database_version >= "8.0.3"
         | 
| 740 | 
            +
                      end
         | 
| 737 741 | 
             
                    end
         | 
| 738 742 |  | 
| 739 743 | 
             
                    def configure_connection
         | 
| @@ -750,7 +754,7 @@ module ActiveRecord | |
| 750 754 | 
             
                      defaults = [":default", :default].to_set
         | 
| 751 755 |  | 
| 752 756 | 
             
                      # Make MySQL reject illegal values rather than truncating or blanking them, see
         | 
| 753 | 
            -
                      # https://dev.mysql.com/doc/refman/ | 
| 757 | 
            +
                      # https://dev.mysql.com/doc/refman/en/sql-mode.html#sqlmode_strict_all_tables
         | 
| 754 758 | 
             
                      # If the user has provided another value for sql_mode, don't replace it.
         | 
| 755 759 | 
             
                      if sql_mode = variables.delete("sql_mode")
         | 
| 756 760 | 
             
                        sql_mode = quote(sql_mode)
         | 
| @@ -767,10 +771,10 @@ module ActiveRecord | |
| 767 771 | 
             
                      sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
         | 
| 768 772 |  | 
| 769 773 | 
             
                      # NAMES does not have an equals sign, see
         | 
| 770 | 
            -
                      # https://dev.mysql.com/doc/refman/ | 
| 774 | 
            +
                      # https://dev.mysql.com/doc/refman/en/set-names.html
         | 
| 771 775 | 
             
                      # (trailing comma because variable_assignments will always have content)
         | 
| 772 776 | 
             
                      if @config[:encoding]
         | 
| 773 | 
            -
                        encoding = "NAMES #{@config[:encoding]}" | 
| 777 | 
            +
                        encoding = +"NAMES #{@config[:encoding]}"
         | 
| 774 778 | 
             
                        encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
         | 
| 775 779 | 
             
                        encoding << ", "
         | 
| 776 780 | 
             
                      end
         | 
| @@ -786,7 +790,7 @@ module ActiveRecord | |
| 786 790 | 
             
                      end.compact.join(", ")
         | 
| 787 791 |  | 
| 788 792 | 
             
                      # ...and send them all in one query
         | 
| 789 | 
            -
                      execute | 
| 793 | 
            +
                      execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
         | 
| 790 794 | 
             
                    end
         | 
| 791 795 |  | 
| 792 796 | 
             
                    def column_definitions(table_name) # :nodoc:
         | 
| @@ -803,15 +807,21 @@ module ActiveRecord | |
| 803 807 | 
             
                      Arel::Visitors::MySQL.new(self)
         | 
| 804 808 | 
             
                    end
         | 
| 805 809 |  | 
| 806 | 
            -
                    def  | 
| 810 | 
            +
                    def build_statement_pool
         | 
| 811 | 
            +
                      StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
         | 
| 812 | 
            +
                    end
         | 
| 813 | 
            +
             | 
| 814 | 
            +
                    def mismatched_foreign_key(message, sql:, binds:)
         | 
| 807 815 | 
             
                      match = %r/
         | 
| 808 816 | 
             
                        (?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
         | 
| 809 817 | 
             
                        FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
         | 
| 810 818 | 
             
                        REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
         | 
| 811 | 
            -
                      /xmi.match( | 
| 819 | 
            +
                      /xmi.match(sql)
         | 
| 812 820 |  | 
| 813 821 | 
             
                      options = {
         | 
| 814 822 | 
             
                        message: message,
         | 
| 823 | 
            +
                        sql: sql,
         | 
| 824 | 
            +
                        binds: binds,
         | 
| 815 825 | 
             
                      }
         | 
| 816 826 |  | 
| 817 827 | 
             
                      if match
         | 
| @@ -822,65 +832,23 @@ module ActiveRecord | |
| 822 832 | 
             
                        options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
         | 
| 823 833 | 
             
                      end
         | 
| 824 834 |  | 
| 825 | 
            -
                      MismatchedForeignKey.new(options)
         | 
| 835 | 
            +
                      MismatchedForeignKey.new(**options)
         | 
| 826 836 | 
             
                    end
         | 
| 827 837 |  | 
| 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
         | 
| 838 | 
            +
                    def version_string(full_version_string)
         | 
| 839 | 
            +
                      full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
         | 
| 837 840 | 
             
                    end
         | 
| 838 841 |  | 
| 839 | 
            -
                     | 
| 840 | 
            -
             | 
| 841 | 
            -
             | 
| 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
         | 
| 842 | 
            +
                    # Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
         | 
| 843 | 
            +
                    # TODO: Remove the constant alias once Rails 6.1 has released.
         | 
| 844 | 
            +
                    MysqlString = Type::String # :nodoc:
         | 
| 858 845 |  | 
| 859 | 
            -
                     | 
| 860 | 
            -
                       | 
| 846 | 
            +
                    ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
         | 
| 847 | 
            +
                      Type::ImmutableString.new(true: "1", false: "0", **args)
         | 
| 861 848 | 
             
                    end
         | 
| 862 | 
            -
             | 
| 863 | 
            -
             | 
| 864 | 
            -
                      def serialize(value)
         | 
| 865 | 
            -
                        case value
         | 
| 866 | 
            -
                        when true then "1"
         | 
| 867 | 
            -
                        when false then "0"
         | 
| 868 | 
            -
                        else super
         | 
| 869 | 
            -
                        end
         | 
| 870 | 
            -
                      end
         | 
| 871 | 
            -
             | 
| 872 | 
            -
                      private
         | 
| 873 | 
            -
             | 
| 874 | 
            -
                        def cast_value(value)
         | 
| 875 | 
            -
                          case value
         | 
| 876 | 
            -
                          when true then "1"
         | 
| 877 | 
            -
                          when false then "0"
         | 
| 878 | 
            -
                          else super
         | 
| 879 | 
            -
                          end
         | 
| 880 | 
            -
                        end
         | 
| 849 | 
            +
                    ActiveRecord::Type.register(:string, adapter: :mysql2) do |_, **args|
         | 
| 850 | 
            +
                      Type::String.new(true: "1", false: "0", **args)
         | 
| 881 851 | 
             
                    end
         | 
| 882 | 
            -
             | 
| 883 | 
            -
                    ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
         | 
| 884 852 | 
             
                    ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
         | 
| 885 853 | 
             
                end
         | 
| 886 854 | 
             
              end
         |