activerecord 5.0.7.2 → 6.0.6.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +844 -1944
- data/MIT-LICENSE +3 -1
- data/README.rdoc +9 -7
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +249 -247
- data/lib/active_record/association_relation.rb +18 -14
- data/lib/active_record/associations/alias_tracker.rb +24 -34
- data/lib/active_record/associations/association.rb +113 -55
- data/lib/active_record/associations/association_scope.rb +102 -96
- data/lib/active_record/associations/belongs_to_association.rb +58 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +18 -25
- data/lib/active_record/associations/builder/belongs_to.rb +43 -54
- data/lib/active_record/associations/builder/collection_association.rb +7 -18
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +41 -62
- data/lib/active_record/associations/builder/has_many.rb +4 -0
- data/lib/active_record/associations/builder/has_one.rb +37 -1
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +93 -254
- data/lib/active_record/associations/collection_proxy.rb +159 -122
- data/lib/active_record/associations/foreign_association.rb +9 -0
- data/lib/active_record/associations/has_many_association.rb +23 -30
- data/lib/active_record/associations/has_many_through_association.rb +58 -44
- data/lib/active_record/associations/has_one_association.rb +59 -54
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +43 -85
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/join_dependency.rb +152 -177
- data/lib/active_record/associations/preloader/association.rb +101 -97
- data/lib/active_record/associations/preloader/through_association.rb +77 -76
- data/lib/active_record/associations/preloader.rb +94 -103
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +27 -15
- data/lib/active_record/associations.rb +1603 -1592
- data/lib/active_record/attribute_assignment.rb +54 -61
- data/lib/active_record/attribute_decorators.rb +38 -17
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -8
- data/lib/active_record/attribute_methods/dirty.rb +179 -109
- data/lib/active_record/attribute_methods/primary_key.rb +85 -92
- data/lib/active_record/attribute_methods/query.rb +4 -3
- data/lib/active_record/attribute_methods/read.rb +20 -49
- data/lib/active_record/attribute_methods/serialization.rb +29 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -66
- data/lib/active_record/attribute_methods/write.rb +34 -33
- data/lib/active_record/attribute_methods.rb +66 -106
- data/lib/active_record/attributes.rb +38 -25
- data/lib/active_record/autosave_association.rb +58 -39
- data/lib/active_record/base.rb +27 -24
- data/lib/active_record/callbacks.rb +64 -35
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +558 -323
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +215 -94
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -35
- data/lib/active_record/connection_adapters/abstract/quoting.rb +128 -75
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -28
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +233 -147
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +400 -213
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -79
- data/lib/active_record/connection_adapters/abstract_adapter.rb +373 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -562
- data/lib/active_record/connection_adapters/column.rb +41 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +172 -139
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +137 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +48 -30
- data/lib/active_record/connection_adapters/postgresql/column.rb +19 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -54
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +12 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +20 -26
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +378 -308
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +383 -275
- data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +261 -267
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
- data/lib/active_record/connection_handling.rb +143 -40
- data/lib/active_record/core.rb +207 -160
- data/lib/active_record/counter_cache.rb +60 -28
- 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/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -87
- data/lib/active_record/enum.rb +67 -23
- data/lib/active_record/errors.rb +114 -18
- data/lib/active_record/explain.rb +4 -4
- data/lib/active_record/explain_registry.rb +3 -1
- data/lib/active_record/explain_subscriber.rb +9 -4
- data/lib/active_record/fixture_set/file.rb +13 -8
- 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 +194 -504
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +150 -99
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +116 -25
- data/lib/active_record/internal_metadata.rb +16 -19
- data/lib/active_record/legacy_yaml_adapter.rb +4 -2
- data/lib/active_record/locking/optimistic.rb +85 -86
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +48 -29
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +134 -100
- data/lib/active_record/migration/compatibility.rb +174 -56
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +369 -302
- data/lib/active_record/model_schema.rb +160 -127
- data/lib/active_record/nested_attributes.rb +213 -202
- data/lib/active_record/no_touching.rb +12 -3
- data/lib/active_record/null_relation.rb +12 -34
- data/lib/active_record/persistence.rb +446 -77
- data/lib/active_record/query_cache.rb +13 -12
- data/lib/active_record/querying.rb +37 -24
- data/lib/active_record/railtie.rb +128 -36
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +312 -177
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +214 -254
- data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
- data/lib/active_record/relation/batches.rb +98 -52
- data/lib/active_record/relation/calculations.rb +212 -173
- data/lib/active_record/relation/delegation.rb +73 -69
- data/lib/active_record/relation/finder_methods.rb +207 -247
- data/lib/active_record/relation/from_clause.rb +6 -8
- data/lib/active_record/relation/merger.rb +82 -61
- data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +83 -105
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +488 -332
- data/lib/active_record/relation/record_fetch_warning.rb +5 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +111 -96
- data/lib/active_record/relation/where_clause_factory.rb +6 -11
- data/lib/active_record/relation.rb +443 -318
- data/lib/active_record/result.rb +69 -40
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +83 -99
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +71 -69
- data/lib/active_record/schema_migration.rb +16 -6
- data/lib/active_record/scoping/default.rb +92 -95
- data/lib/active_record/scoping/named.rb +51 -26
- data/lib/active_record/scoping.rb +20 -20
- data/lib/active_record/secure_token.rb +4 -2
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +63 -28
- data/lib/active_record/store.rb +121 -41
- data/lib/active_record/suppressor.rb +6 -3
- data/lib/active_record/table_metadata.rb +39 -18
- data/lib/active_record/tasks/database_tasks.rb +271 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +54 -91
- data/lib/active_record/tasks/postgresql_database_tasks.rb +77 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +33 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +70 -36
- data/lib/active_record/touch_later.rb +8 -6
- data/lib/active_record/transactions.rb +141 -157
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +44 -48
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +16 -9
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +12 -1
- data/lib/active_record/type/type_map.rb +14 -17
- data/lib/active_record/type/unsigned_integer.rb +16 -0
- data/lib/active_record/type.rb +23 -18
- data/lib/active_record/type_caster/connection.rb +17 -12
- data/lib/active_record/type_caster/map.rb +5 -4
- data/lib/active_record/type_caster.rb +4 -2
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +3 -2
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +29 -42
- data/lib/active_record/validations.rb +7 -5
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +37 -22
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -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/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/nodes.rb +68 -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/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/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
- data/lib/rails/generators/active_record/migration.rb +17 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -30
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +138 -52
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -20
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute.rb +0 -213
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set/builder.rb +0 -132
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
- /data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,32 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
|
11
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/connection_adapters/abstract_adapter"
|
4
|
+
require "active_record/connection_adapters/statement_pool"
|
5
|
+
require "active_record/connection_adapters/mysql/column"
|
6
|
+
require "active_record/connection_adapters/mysql/explain_pretty_printer"
|
7
|
+
require "active_record/connection_adapters/mysql/quoting"
|
8
|
+
require "active_record/connection_adapters/mysql/schema_creation"
|
9
|
+
require "active_record/connection_adapters/mysql/schema_definitions"
|
10
|
+
require "active_record/connection_adapters/mysql/schema_dumper"
|
11
|
+
require "active_record/connection_adapters/mysql/schema_statements"
|
12
|
+
require "active_record/connection_adapters/mysql/type_metadata"
|
12
13
|
|
13
14
|
module ActiveRecord
|
14
15
|
module ConnectionAdapters
|
15
16
|
class AbstractMysqlAdapter < AbstractAdapter
|
16
17
|
include MySQL::Quoting
|
17
|
-
include MySQL::
|
18
|
-
|
19
|
-
def update_table_definition(table_name, base) # :nodoc:
|
20
|
-
MySQL::Table.new(table_name, base)
|
21
|
-
end
|
22
|
-
|
23
|
-
def schema_creation # :nodoc:
|
24
|
-
MySQL::SchemaCreation.new(self)
|
25
|
-
end
|
26
|
-
|
27
|
-
def arel_visitor # :nodoc:
|
28
|
-
Arel::Visitors::MySQL.new(self)
|
29
|
-
end
|
18
|
+
include MySQL::SchemaStatements
|
30
19
|
|
31
20
|
##
|
32
21
|
# :singleton-method:
|
@@ -35,82 +24,56 @@ module ActiveRecord
|
|
35
24
|
# to your application.rb file:
|
36
25
|
#
|
37
26
|
# ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans = false
|
38
|
-
class_attribute :emulate_booleans
|
39
|
-
self.emulate_booleans = true
|
27
|
+
class_attribute :emulate_booleans, default: true
|
40
28
|
|
41
29
|
NATIVE_DATABASE_TYPES = {
|
42
|
-
primary_key: "
|
30
|
+
primary_key: "bigint auto_increment PRIMARY KEY",
|
43
31
|
string: { name: "varchar", limit: 255 },
|
44
32
|
text: { name: "text" },
|
45
33
|
integer: { name: "int", limit: 4 },
|
46
|
-
float: { name: "float" },
|
34
|
+
float: { name: "float", limit: 24 },
|
47
35
|
decimal: { name: "decimal" },
|
48
36
|
datetime: { name: "datetime" },
|
37
|
+
timestamp: { name: "timestamp" },
|
49
38
|
time: { name: "time" },
|
50
39
|
date: { name: "date" },
|
51
40
|
binary: { name: "blob" },
|
41
|
+
blob: { name: "blob" },
|
52
42
|
boolean: { name: "tinyint", limit: 1 },
|
53
43
|
json: { name: "json" },
|
54
44
|
}
|
55
45
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
stmt[:stmt].close
|
62
|
-
end
|
46
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
47
|
+
private
|
48
|
+
def dealloc(stmt)
|
49
|
+
stmt.close
|
50
|
+
end
|
63
51
|
end
|
64
52
|
|
65
53
|
def initialize(connection, logger, connection_options, config)
|
66
54
|
super(connection, logger, config)
|
67
|
-
|
68
|
-
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
69
|
-
|
70
|
-
if version < '5.0.0'
|
71
|
-
raise "Your version of MySQL (#{version_string}) is too old. Active Record supports MySQL >= 5.0."
|
72
|
-
end
|
73
55
|
end
|
74
56
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
options[:collation] = collation.sub(/\A[^_]+/, 'utf8') if CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
|
80
|
-
}
|
81
|
-
end
|
82
|
-
|
83
|
-
def version #:nodoc:
|
84
|
-
@version ||= Version.new(version_string)
|
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)
|
85
61
|
end
|
86
62
|
|
87
63
|
def mariadb? # :nodoc:
|
88
|
-
|
64
|
+
/mariadb/i.match?(full_version)
|
89
65
|
end
|
90
66
|
|
91
|
-
|
92
|
-
def supports_migrations?
|
67
|
+
def supports_bulk_alter?
|
93
68
|
true
|
94
69
|
end
|
95
70
|
|
96
|
-
def
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
def supports_bulk_alter? #:nodoc:
|
101
|
-
true
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns true, since this connection adapter supports prepared statement
|
105
|
-
# caching.
|
106
|
-
def supports_statement_cache?
|
107
|
-
true
|
71
|
+
def supports_index_sort_order?
|
72
|
+
!mariadb? && database_version >= "8.0.1"
|
108
73
|
end
|
109
74
|
|
110
|
-
|
111
|
-
|
112
|
-
def supports_index_sort_order?
|
113
|
-
true
|
75
|
+
def supports_expression_index?
|
76
|
+
!mariadb? && database_version >= "8.0.13"
|
114
77
|
end
|
115
78
|
|
116
79
|
def supports_transaction_isolation?
|
@@ -134,10 +97,23 @@ module ActiveRecord
|
|
134
97
|
end
|
135
98
|
|
136
99
|
def supports_datetime_with_precision?
|
100
|
+
mariadb? || database_version >= "5.6.4"
|
101
|
+
end
|
102
|
+
|
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?
|
137
113
|
if mariadb?
|
138
|
-
|
114
|
+
database_version >= "10.2.1"
|
139
115
|
else
|
140
|
-
|
116
|
+
database_version >= "8.0.1"
|
141
117
|
end
|
142
118
|
end
|
143
119
|
|
@@ -145,12 +121,20 @@ module ActiveRecord
|
|
145
121
|
true
|
146
122
|
end
|
147
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
|
+
|
148
132
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
149
|
-
|
133
|
+
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
150
134
|
end
|
151
135
|
|
152
136
|
def release_advisory_lock(lock_name) # :nodoc:
|
153
|
-
|
137
|
+
query_value("SELECT RELEASE_LOCK(#{quote(lock_name.to_s)})") == 1
|
154
138
|
end
|
155
139
|
|
156
140
|
def native_database_types
|
@@ -158,7 +142,7 @@ module ActiveRecord
|
|
158
142
|
end
|
159
143
|
|
160
144
|
def index_algorithms
|
161
|
-
{ default:
|
145
|
+
{ default: +"ALGORITHM = DEFAULT", copy: +"ALGORITHM = COPY", inplace: +"ALGORITHM = INPLACE" }
|
162
146
|
end
|
163
147
|
|
164
148
|
# HELPER METHODS ===========================================
|
@@ -169,10 +153,6 @@ module ActiveRecord
|
|
169
153
|
raise NotImplementedError
|
170
154
|
end
|
171
155
|
|
172
|
-
def new_column(*args) #:nodoc:
|
173
|
-
MySQL::Column.new(*args)
|
174
|
-
end
|
175
|
-
|
176
156
|
# Must return the MySQL error number from the exception, if the exception has an
|
177
157
|
# error number.
|
178
158
|
def error_number(exception) # :nodoc:
|
@@ -182,7 +162,7 @@ module ActiveRecord
|
|
182
162
|
# REFERENTIAL INTEGRITY ====================================
|
183
163
|
|
184
164
|
def disable_referential_integrity #:nodoc:
|
185
|
-
old =
|
165
|
+
old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
|
186
166
|
|
187
167
|
begin
|
188
168
|
update("SET FOREIGN_KEY_CHECKS = 0")
|
@@ -194,10 +174,9 @@ module ActiveRecord
|
|
194
174
|
|
195
175
|
# CONNECTION MANAGEMENT ====================================
|
196
176
|
|
197
|
-
|
198
|
-
def clear_cache!
|
177
|
+
def clear_cache! # :nodoc:
|
199
178
|
reload_type_map
|
200
|
-
|
179
|
+
super
|
201
180
|
end
|
202
181
|
|
203
182
|
#--
|
@@ -206,16 +185,22 @@ module ActiveRecord
|
|
206
185
|
|
207
186
|
def explain(arel, binds = [])
|
208
187
|
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
209
|
-
start =
|
210
|
-
result = exec_query(sql,
|
211
|
-
elapsed =
|
188
|
+
start = Concurrent.monotonic_time
|
189
|
+
result = exec_query(sql, "EXPLAIN", binds)
|
190
|
+
elapsed = Concurrent.monotonic_time - start
|
212
191
|
|
213
192
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
214
193
|
end
|
215
194
|
|
216
195
|
# Executes the SQL statement in the context of this connection.
|
217
196
|
def execute(sql, name = nil)
|
218
|
-
|
197
|
+
materialize_transactions
|
198
|
+
|
199
|
+
log(sql, name) do
|
200
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
201
|
+
@connection.query(sql)
|
202
|
+
end
|
203
|
+
end
|
219
204
|
end
|
220
205
|
|
221
206
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
@@ -242,19 +227,7 @@ module ActiveRecord
|
|
242
227
|
execute "ROLLBACK"
|
243
228
|
end
|
244
229
|
|
245
|
-
|
246
|
-
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
|
247
|
-
# these, we must use a subquery.
|
248
|
-
def join_to_update(update, select, key) # :nodoc:
|
249
|
-
if select.limit || select.offset || select.orders.any?
|
250
|
-
super
|
251
|
-
else
|
252
|
-
update.table select.source
|
253
|
-
update.wheres = select.constraints
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
def empty_insert_statement_value
|
230
|
+
def empty_insert_statement_value(primary_key = nil)
|
258
231
|
"VALUES ()"
|
259
232
|
end
|
260
233
|
|
@@ -270,7 +243,7 @@ module ActiveRecord
|
|
270
243
|
end
|
271
244
|
|
272
245
|
# Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
|
273
|
-
# Charset defaults to
|
246
|
+
# Charset defaults to utf8mb4.
|
274
247
|
#
|
275
248
|
# Example:
|
276
249
|
# create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
|
@@ -278,9 +251,13 @@ module ActiveRecord
|
|
278
251
|
# create_database 'matt_development', charset: :big5
|
279
252
|
def create_database(name, options = {})
|
280
253
|
if options[:collation]
|
281
|
-
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT
|
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`"
|
282
259
|
else
|
283
|
-
|
260
|
+
raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
|
284
261
|
end
|
285
262
|
end
|
286
263
|
|
@@ -293,149 +270,34 @@ module ActiveRecord
|
|
293
270
|
end
|
294
271
|
|
295
272
|
def current_database
|
296
|
-
|
273
|
+
query_value("SELECT database()", "SCHEMA")
|
297
274
|
end
|
298
275
|
|
299
276
|
# Returns the database character set.
|
300
277
|
def charset
|
301
|
-
show_variable
|
278
|
+
show_variable "character_set_database"
|
302
279
|
end
|
303
280
|
|
304
281
|
# Returns the database collation strategy.
|
305
282
|
def collation
|
306
|
-
show_variable
|
307
|
-
end
|
308
|
-
|
309
|
-
def tables(name = nil) # :nodoc:
|
310
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
311
|
-
#tables currently returns both tables and views.
|
312
|
-
This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
|
313
|
-
Use #data_sources instead.
|
314
|
-
MSG
|
315
|
-
|
316
|
-
if name
|
317
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
318
|
-
Passing arguments to #tables is deprecated without replacement.
|
319
|
-
MSG
|
320
|
-
end
|
321
|
-
|
322
|
-
data_sources
|
323
|
-
end
|
324
|
-
|
325
|
-
def data_sources
|
326
|
-
sql = "SELECT table_name FROM information_schema.tables "
|
327
|
-
sql << "WHERE table_schema = DATABASE()"
|
328
|
-
|
329
|
-
select_values(sql, 'SCHEMA')
|
330
|
-
end
|
331
|
-
|
332
|
-
def truncate(table_name, name = nil)
|
333
|
-
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
334
|
-
end
|
335
|
-
|
336
|
-
def table_exists?(table_name)
|
337
|
-
# Update lib/active_record/internal_metadata.rb when this gets removed
|
338
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
339
|
-
#table_exists? currently checks both tables and views.
|
340
|
-
This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
|
341
|
-
Use #data_source_exists? instead.
|
342
|
-
MSG
|
343
|
-
|
344
|
-
data_source_exists?(table_name)
|
345
|
-
end
|
346
|
-
|
347
|
-
def data_source_exists?(table_name)
|
348
|
-
return false unless table_name.present?
|
349
|
-
|
350
|
-
schema, name = extract_schema_qualified_name(table_name)
|
351
|
-
|
352
|
-
sql = "SELECT table_name FROM information_schema.tables "
|
353
|
-
sql << "WHERE table_schema = #{schema} AND table_name = #{name}"
|
354
|
-
|
355
|
-
select_values(sql, 'SCHEMA').any?
|
356
|
-
end
|
357
|
-
|
358
|
-
def views # :nodoc:
|
359
|
-
select_values("SHOW FULL TABLES WHERE table_type = 'VIEW'", 'SCHEMA')
|
360
|
-
end
|
361
|
-
|
362
|
-
def view_exists?(view_name) # :nodoc:
|
363
|
-
return false unless view_name.present?
|
364
|
-
|
365
|
-
schema, name = extract_schema_qualified_name(view_name)
|
366
|
-
|
367
|
-
sql = "SELECT table_name FROM information_schema.tables WHERE table_type = 'VIEW'"
|
368
|
-
sql << " AND table_schema = #{schema} AND table_name = #{name}"
|
369
|
-
|
370
|
-
select_values(sql, 'SCHEMA').any?
|
371
|
-
end
|
372
|
-
|
373
|
-
# Returns an array of indexes for the given table.
|
374
|
-
def indexes(table_name, name = nil) #:nodoc:
|
375
|
-
indexes = []
|
376
|
-
current_index = nil
|
377
|
-
execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result|
|
378
|
-
each_hash(result) do |row|
|
379
|
-
if current_index != row[:Key_name]
|
380
|
-
next if row[:Key_name] == 'PRIMARY' # skip the primary key
|
381
|
-
current_index = row[:Key_name]
|
382
|
-
|
383
|
-
mysql_index_type = row[:Index_type].downcase.to_sym
|
384
|
-
index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
|
385
|
-
index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
|
386
|
-
indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], {}, nil, nil, index_type, index_using, row[:Index_comment].presence)
|
387
|
-
end
|
388
|
-
|
389
|
-
indexes.last.columns << row[:Column_name]
|
390
|
-
indexes.last.lengths.merge!(row[:Column_name] => row[:Sub_part].to_i) if row[:Sub_part]
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
indexes
|
395
|
-
end
|
396
|
-
|
397
|
-
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
398
|
-
def columns(table_name) # :nodoc:
|
399
|
-
table_name = table_name.to_s
|
400
|
-
column_definitions(table_name).map do |field|
|
401
|
-
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
402
|
-
if type_metadata.type == :datetime && field[:Default] =~ /\ACURRENT_TIMESTAMP(?:\(\))?\z/i
|
403
|
-
default, default_function = nil, "CURRENT_TIMESTAMP"
|
404
|
-
else
|
405
|
-
default, default_function = field[:Default], nil
|
406
|
-
end
|
407
|
-
new_column(field[:Field], default, type_metadata, field[:Null] == "YES", table_name, default_function, field[:Collation], comment: field[:Comment].presence)
|
408
|
-
end
|
283
|
+
show_variable "collation_database"
|
409
284
|
end
|
410
285
|
|
411
286
|
def table_comment(table_name) # :nodoc:
|
412
|
-
|
287
|
+
scope = quoted_scope(table_name)
|
413
288
|
|
414
|
-
|
289
|
+
query_value(<<~SQL, "SCHEMA").presence
|
415
290
|
SELECT table_comment
|
416
291
|
FROM information_schema.tables
|
417
|
-
WHERE table_schema = #{schema}
|
418
|
-
AND table_name = #{name}
|
292
|
+
WHERE table_schema = #{scope[:schema]}
|
293
|
+
AND table_name = #{scope[:name]}
|
419
294
|
SQL
|
420
295
|
end
|
421
296
|
|
422
|
-
def
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
def bulk_change_table(table_name, operations) #:nodoc:
|
427
|
-
sqls = operations.flat_map do |command, args|
|
428
|
-
table, arguments = args.shift, args
|
429
|
-
method = :"#{command}_sql"
|
430
|
-
|
431
|
-
if respond_to?(method, true)
|
432
|
-
send(method, table, *arguments)
|
433
|
-
else
|
434
|
-
raise "Unknown method called : #{method}(#{arguments.inspect})"
|
435
|
-
end
|
436
|
-
end.join(", ")
|
437
|
-
|
438
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
|
297
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
298
|
+
comment = extract_new_comment_value(comment_or_changes)
|
299
|
+
comment = "" if comment.nil?
|
300
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
|
439
301
|
end
|
440
302
|
|
441
303
|
# Renames a table.
|
@@ -478,32 +340,34 @@ module ActiveRecord
|
|
478
340
|
|
479
341
|
def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
|
480
342
|
default = extract_new_default_value(default_or_changes)
|
481
|
-
|
482
|
-
change_column table_name, column_name, column.sql_type, :default => default
|
343
|
+
change_column table_name, column_name, nil, default: default
|
483
344
|
end
|
484
345
|
|
485
346
|
def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
|
486
|
-
column = column_for(table_name, column_name)
|
487
|
-
|
488
347
|
unless null || default.nil?
|
489
348
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
490
349
|
end
|
491
350
|
|
492
|
-
change_column table_name, column_name,
|
351
|
+
change_column table_name, column_name, nil, null: null
|
352
|
+
end
|
353
|
+
|
354
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
355
|
+
comment = extract_new_comment_value(comment_or_changes)
|
356
|
+
change_column table_name, column_name, nil, comment: comment
|
493
357
|
end
|
494
358
|
|
495
359
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
496
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{
|
360
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}")
|
497
361
|
end
|
498
362
|
|
499
363
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
500
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{
|
364
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
501
365
|
rename_column_indexes(table_name, column_name, new_column_name)
|
502
366
|
end
|
503
367
|
|
504
368
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
505
|
-
index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
|
506
|
-
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}"
|
507
371
|
execute add_sql_comment!(sql, comment)
|
508
372
|
end
|
509
373
|
|
@@ -515,35 +379,36 @@ module ActiveRecord
|
|
515
379
|
def foreign_keys(table_name)
|
516
380
|
raise ArgumentError unless table_name.present?
|
517
381
|
|
518
|
-
|
382
|
+
scope = quoted_scope(table_name)
|
519
383
|
|
520
|
-
fk_info =
|
384
|
+
fk_info = exec_query(<<~SQL, "SCHEMA")
|
521
385
|
SELECT fk.referenced_table_name AS 'to_table',
|
522
386
|
fk.referenced_column_name AS 'primary_key',
|
523
387
|
fk.column_name AS 'column',
|
524
388
|
fk.constraint_name AS 'name',
|
525
389
|
rc.update_rule AS 'on_update',
|
526
390
|
rc.delete_rule AS 'on_delete'
|
527
|
-
FROM information_schema.
|
528
|
-
JOIN information_schema.
|
391
|
+
FROM information_schema.referential_constraints rc
|
392
|
+
JOIN information_schema.key_column_usage fk
|
529
393
|
USING (constraint_schema, constraint_name)
|
530
394
|
WHERE fk.referenced_column_name IS NOT NULL
|
531
|
-
AND fk.table_schema = #{schema}
|
532
|
-
AND fk.table_name = #{name}
|
533
|
-
AND rc.
|
395
|
+
AND fk.table_schema = #{scope[:schema]}
|
396
|
+
AND fk.table_name = #{scope[:name]}
|
397
|
+
AND rc.constraint_schema = #{scope[:schema]}
|
398
|
+
AND rc.table_name = #{scope[:name]}
|
534
399
|
SQL
|
535
400
|
|
536
401
|
fk_info.map do |row|
|
537
402
|
options = {
|
538
|
-
column: row[
|
539
|
-
name: row[
|
540
|
-
primary_key: row[
|
403
|
+
column: row["column"],
|
404
|
+
name: row["name"],
|
405
|
+
primary_key: row["primary_key"]
|
541
406
|
}
|
542
407
|
|
543
|
-
options[:on_update] = extract_foreign_key_action(row[
|
544
|
-
options[:on_delete] = extract_foreign_key_action(row[
|
408
|
+
options[:on_update] = extract_foreign_key_action(row["on_update"])
|
409
|
+
options[:on_delete] = extract_foreign_key_action(row["on_delete"])
|
545
410
|
|
546
|
-
ForeignKeyDefinition.new(table_name, row[
|
411
|
+
ForeignKeyDefinition.new(table_name, row["to_table"], options)
|
547
412
|
end
|
548
413
|
end
|
549
414
|
|
@@ -553,47 +418,25 @@ module ActiveRecord
|
|
553
418
|
create_table_info = create_table_info(table_name)
|
554
419
|
|
555
420
|
# strip create_definitions and partition_options
|
556
|
-
|
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
|
557
423
|
|
558
424
|
# strip AUTO_INCREMENT
|
559
425
|
raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
|
560
426
|
|
561
|
-
table_options[:options] = raw_table_options
|
427
|
+
table_options[:options] = raw_table_options unless raw_table_options.blank?
|
562
428
|
|
563
429
|
# strip COMMENT
|
564
|
-
if raw_table_options.sub!(/ COMMENT='.+'/,
|
430
|
+
if raw_table_options.sub!(/ COMMENT='.+'/, "")
|
565
431
|
table_options[:comment] = table_comment(table_name)
|
566
432
|
end
|
567
433
|
|
568
434
|
table_options
|
569
435
|
end
|
570
436
|
|
571
|
-
# Maps logical Rails types to MySQL-specific data types.
|
572
|
-
def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = nil)
|
573
|
-
sql = case type.to_s
|
574
|
-
when 'integer'
|
575
|
-
integer_to_sql(limit)
|
576
|
-
when 'text'
|
577
|
-
text_to_sql(limit)
|
578
|
-
when 'blob'
|
579
|
-
binary_to_sql(limit)
|
580
|
-
when 'binary'
|
581
|
-
if (0..0xfff) === limit
|
582
|
-
"varbinary(#{limit})"
|
583
|
-
else
|
584
|
-
binary_to_sql(limit)
|
585
|
-
end
|
586
|
-
else
|
587
|
-
super(type, limit, precision, scale)
|
588
|
-
end
|
589
|
-
|
590
|
-
sql << ' unsigned' if unsigned && type != :primary_key
|
591
|
-
sql
|
592
|
-
end
|
593
|
-
|
594
437
|
# SHOW VARIABLES LIKE 'name'
|
595
438
|
def show_variable(name)
|
596
|
-
|
439
|
+
query_value("SELECT @@#{name}", "SCHEMA")
|
597
440
|
rescue ActiveRecord::StatementInvalid
|
598
441
|
nil
|
599
442
|
end
|
@@ -601,21 +444,38 @@ module ActiveRecord
|
|
601
444
|
def primary_keys(table_name) # :nodoc:
|
602
445
|
raise ArgumentError unless table_name.present?
|
603
446
|
|
604
|
-
|
447
|
+
scope = quoted_scope(table_name)
|
605
448
|
|
606
|
-
|
449
|
+
query_values(<<~SQL, "SCHEMA")
|
607
450
|
SELECT column_name
|
608
|
-
FROM information_schema.
|
609
|
-
WHERE
|
610
|
-
AND table_schema = #{schema}
|
611
|
-
AND table_name = #{name}
|
612
|
-
ORDER BY
|
451
|
+
FROM information_schema.statistics
|
452
|
+
WHERE index_name = 'PRIMARY'
|
453
|
+
AND table_schema = #{scope[:schema]}
|
454
|
+
AND table_name = #{scope[:name]}
|
455
|
+
ORDER BY seq_in_index
|
613
456
|
SQL
|
614
457
|
end
|
615
458
|
|
616
|
-
def
|
617
|
-
|
618
|
-
|
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
|
+
|
477
|
+
if column.collation && !column.case_sensitive?
|
478
|
+
attribute.eq(Arel::Nodes::Bin.new(value))
|
619
479
|
else
|
620
480
|
super
|
621
481
|
end
|
@@ -633,348 +493,327 @@ module ActiveRecord
|
|
633
493
|
def columns_for_distinct(columns, orders) # :nodoc:
|
634
494
|
order_columns = orders.reject(&:blank?).map { |s|
|
635
495
|
# Convert Arel node to string
|
636
|
-
s = s
|
496
|
+
s = visitor.compile(s) unless s.is_a?(String)
|
637
497
|
# Remove any ASC/DESC modifiers
|
638
|
-
s.gsub(/\s+(?:ASC|DESC)\b/i,
|
498
|
+
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
|
639
499
|
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
640
500
|
|
641
|
-
|
501
|
+
(order_columns << super).join(", ")
|
642
502
|
end
|
643
503
|
|
644
504
|
def strict_mode?
|
645
505
|
self.class.type_cast_config_to_boolean(@config.fetch(:strict, true))
|
646
506
|
end
|
647
507
|
|
648
|
-
def
|
649
|
-
|
508
|
+
def default_index_type?(index) # :nodoc:
|
509
|
+
index.using == :btree || super
|
650
510
|
end
|
651
511
|
|
652
|
-
|
512
|
+
def build_insert_sql(insert) # :nodoc:
|
513
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
653
514
|
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
661
|
-
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
662
|
-
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
|
663
|
-
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
|
664
|
-
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
665
|
-
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
666
|
-
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
667
|
-
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
668
|
-
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
669
|
-
m.register_type %r(^json)i, MysqlJson.new
|
670
|
-
|
671
|
-
register_integer_type m, %r(^bigint)i, limit: 8
|
672
|
-
register_integer_type m, %r(^int)i, limit: 4
|
673
|
-
register_integer_type m, %r(^mediumint)i, limit: 3
|
674
|
-
register_integer_type m, %r(^smallint)i, limit: 2
|
675
|
-
register_integer_type m, %r(^tinyint)i, limit: 1
|
676
|
-
|
677
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
678
|
-
m.alias_type %r(year)i, 'integer'
|
679
|
-
m.alias_type %r(bit)i, 'binary'
|
680
|
-
|
681
|
-
m.register_type(%r(enum)i) do |sql_type|
|
682
|
-
limit = sql_type[/^enum\((.+)\)/i, 1]
|
683
|
-
.split(',').map{|enum| enum.strip.length - 2}.max
|
684
|
-
MysqlString.new(limit: limit)
|
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(",")
|
685
521
|
end
|
686
522
|
|
687
|
-
|
688
|
-
limit = sql_type[/^set\((.+)\)/i, 1]
|
689
|
-
.split(',').map{|set| set.strip.length - 1}.sum - 1
|
690
|
-
MysqlString.new(limit: limit)
|
691
|
-
end
|
523
|
+
sql
|
692
524
|
end
|
693
525
|
|
694
|
-
def
|
695
|
-
|
696
|
-
|
697
|
-
Type::UnsignedInteger.new(options)
|
698
|
-
else
|
699
|
-
Type::Integer.new(options)
|
700
|
-
end
|
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."
|
701
529
|
end
|
702
530
|
end
|
703
531
|
|
704
|
-
|
705
|
-
|
706
|
-
super || 0
|
707
|
-
else
|
532
|
+
private
|
533
|
+
def initialize_type_map(m = type_map)
|
708
534
|
super
|
709
|
-
end
|
710
|
-
end
|
711
535
|
|
712
|
-
|
713
|
-
|
714
|
-
|
536
|
+
register_class_with_limit m, %r(char)i, MysqlString
|
537
|
+
|
538
|
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
539
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
540
|
+
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
541
|
+
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
|
542
|
+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
|
543
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
544
|
+
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
545
|
+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
546
|
+
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
547
|
+
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
548
|
+
|
549
|
+
register_integer_type m, %r(^bigint)i, limit: 8
|
550
|
+
register_integer_type m, %r(^int)i, limit: 4
|
551
|
+
register_integer_type m, %r(^mediumint)i, limit: 3
|
552
|
+
register_integer_type m, %r(^smallint)i, limit: 2
|
553
|
+
register_integer_type m, %r(^tinyint)i, limit: 1
|
554
|
+
|
555
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
556
|
+
m.alias_type %r(year)i, "integer"
|
557
|
+
m.alias_type %r(bit)i, "binary"
|
558
|
+
|
559
|
+
m.register_type(%r(enum)i) do |sql_type|
|
560
|
+
limit = sql_type[/^enum\s*\((.+)\)/i, 1]
|
561
|
+
.split(",").map { |enum| enum.strip.length - 2 }.max
|
562
|
+
MysqlString.new(limit: limit)
|
563
|
+
end
|
715
564
|
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
length = length.symbolize_keys
|
721
|
-
quoted_columns.each { |name, column| column << "(#{length[name]})" if length[name].present? }
|
722
|
-
when Integer
|
723
|
-
quoted_columns.each { |name, column| column << "(#{length})" }
|
565
|
+
m.register_type(%r(^set)i) do |sql_type|
|
566
|
+
limit = sql_type[/^set\s*\((.+)\)/i, 1]
|
567
|
+
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
568
|
+
MysqlString.new(limit: limit)
|
724
569
|
end
|
725
570
|
end
|
726
571
|
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
def translate_exception(exception, message)
|
736
|
-
case error_number(exception)
|
737
|
-
when 1062
|
738
|
-
RecordNotUnique.new(message)
|
739
|
-
when 1452
|
740
|
-
InvalidForeignKey.new(message)
|
741
|
-
when 1406
|
742
|
-
ValueTooLong.new(message)
|
743
|
-
else
|
744
|
-
super
|
572
|
+
def register_integer_type(mapping, key, **options)
|
573
|
+
mapping.register_type(key) do |sql_type|
|
574
|
+
if /\bunsigned\b/.match?(sql_type)
|
575
|
+
Type::UnsignedInteger.new(**options)
|
576
|
+
else
|
577
|
+
Type::Integer.new(**options)
|
578
|
+
end
|
579
|
+
end
|
745
580
|
end
|
746
|
-
end
|
747
|
-
|
748
|
-
def add_column_sql(table_name, column_name, type, options = {})
|
749
|
-
td = create_table_definition(table_name)
|
750
|
-
cd = td.new_column_definition(column_name, type, options)
|
751
|
-
schema_creation.accept(AddColumnDefinition.new(cd))
|
752
|
-
end
|
753
|
-
|
754
|
-
def change_column_sql(table_name, column_name, type, options = {})
|
755
|
-
column = column_for(table_name, column_name)
|
756
581
|
|
757
|
-
|
758
|
-
|
582
|
+
def extract_precision(sql_type)
|
583
|
+
if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
|
584
|
+
super || 0
|
585
|
+
else
|
586
|
+
super
|
587
|
+
end
|
759
588
|
end
|
760
589
|
|
761
|
-
|
762
|
-
|
590
|
+
# See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
|
591
|
+
ER_FILSORT_ABORT = 1028
|
592
|
+
ER_DUP_ENTRY = 1062
|
593
|
+
ER_NOT_NULL_VIOLATION = 1048
|
594
|
+
ER_NO_REFERENCED_ROW = 1216
|
595
|
+
ER_ROW_IS_REFERENCED = 1217
|
596
|
+
ER_DO_NOT_HAVE_DEFAULT = 1364
|
597
|
+
ER_ROW_IS_REFERENCED_2 = 1451
|
598
|
+
ER_NO_REFERENCED_ROW_2 = 1452
|
599
|
+
ER_DATA_TOO_LONG = 1406
|
600
|
+
ER_OUT_OF_RANGE = 1264
|
601
|
+
ER_LOCK_DEADLOCK = 1213
|
602
|
+
ER_CANNOT_ADD_FOREIGN = 1215
|
603
|
+
ER_CANNOT_CREATE_TABLE = 1005
|
604
|
+
ER_LOCK_WAIT_TIMEOUT = 1205
|
605
|
+
ER_QUERY_INTERRUPTED = 1317
|
606
|
+
ER_QUERY_TIMEOUT = 3024
|
607
|
+
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
608
|
+
|
609
|
+
def translate_exception(exception, message:, sql:, binds:)
|
610
|
+
case error_number(exception)
|
611
|
+
when ER_DUP_ENTRY
|
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)
|
617
|
+
when ER_CANNOT_CREATE_TABLE
|
618
|
+
if message.include?("errno: 150")
|
619
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
620
|
+
else
|
621
|
+
super
|
622
|
+
end
|
623
|
+
when ER_DATA_TOO_LONG
|
624
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
625
|
+
when ER_OUT_OF_RANGE
|
626
|
+
RangeError.new(message, sql: sql, binds: binds)
|
627
|
+
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
628
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
629
|
+
when ER_LOCK_DEADLOCK
|
630
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
631
|
+
when ER_LOCK_WAIT_TIMEOUT
|
632
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
633
|
+
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
634
|
+
StatementTimeout.new(message, sql: sql, binds: binds)
|
635
|
+
when ER_QUERY_INTERRUPTED
|
636
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
637
|
+
else
|
638
|
+
super
|
639
|
+
end
|
763
640
|
end
|
764
641
|
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
end
|
769
|
-
|
770
|
-
def rename_column_sql(table_name, column_name, new_column_name)
|
771
|
-
column = column_for(table_name, column_name)
|
772
|
-
options = {
|
773
|
-
default: column.default,
|
774
|
-
null: column.null,
|
775
|
-
auto_increment: column.auto_increment?
|
776
|
-
}
|
777
|
-
|
778
|
-
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", 'SCHEMA')["Type"]
|
779
|
-
td = create_table_definition(table_name)
|
780
|
-
cd = td.new_column_definition(new_column_name, current_type, options)
|
781
|
-
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
782
|
-
end
|
783
|
-
|
784
|
-
def remove_column_sql(table_name, column_name, type = nil, options = {})
|
785
|
-
"DROP #{quote_column_name(column_name)}"
|
786
|
-
end
|
787
|
-
|
788
|
-
def remove_columns_sql(table_name, *column_names)
|
789
|
-
column_names.map {|column_name| remove_column_sql(table_name, column_name) }
|
790
|
-
end
|
642
|
+
def change_column_for_alter(table_name, column_name, type, options = {})
|
643
|
+
column = column_for(table_name, column_name)
|
644
|
+
type ||= column.sql_type
|
791
645
|
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
796
|
-
end
|
646
|
+
unless options.key?(:default)
|
647
|
+
options[:default] = column.default
|
648
|
+
end
|
797
649
|
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
end
|
650
|
+
unless options.key?(:null)
|
651
|
+
options[:null] = column.null
|
652
|
+
end
|
802
653
|
|
803
|
-
|
804
|
-
|
805
|
-
|
654
|
+
unless options.key?(:comment)
|
655
|
+
options[:comment] = column.comment
|
656
|
+
end
|
806
657
|
|
807
|
-
|
808
|
-
|
809
|
-
|
658
|
+
td = create_table_definition(table_name)
|
659
|
+
cd = td.new_column_definition(column.name, type, **options)
|
660
|
+
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
661
|
+
end
|
810
662
|
|
811
|
-
|
663
|
+
def rename_column_for_alter(table_name, column_name, new_column_name)
|
664
|
+
column = column_for(table_name, column_name)
|
665
|
+
options = {
|
666
|
+
default: column.default,
|
667
|
+
null: column.null,
|
668
|
+
auto_increment: column.auto_increment?
|
669
|
+
}
|
812
670
|
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
671
|
+
current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
672
|
+
td = create_table_definition(table_name)
|
673
|
+
cd = td.new_column_definition(new_column_name, current_type, **options)
|
674
|
+
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
675
|
+
end
|
818
676
|
|
819
|
-
|
820
|
-
|
821
|
-
|
677
|
+
def add_index_for_alter(table_name, column_name, options = {})
|
678
|
+
index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, **options)
|
679
|
+
index_algorithm[0, 0] = ", " if index_algorithm.present?
|
680
|
+
sql = +"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
681
|
+
add_sql_comment!(sql, comment)
|
682
|
+
end
|
822
683
|
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
684
|
+
def remove_index_for_alter(table_name, options = {})
|
685
|
+
index_name = index_name_for_remove(table_name, options)
|
686
|
+
"DROP INDEX #{quote_column_name(index_name)}"
|
687
|
+
end
|
827
688
|
|
828
|
-
|
829
|
-
|
830
|
-
|
689
|
+
def supports_rename_index?
|
690
|
+
if mariadb?
|
691
|
+
database_version >= "10.5.2"
|
692
|
+
else
|
693
|
+
database_version >= "5.7.6"
|
694
|
+
end
|
695
|
+
end
|
831
696
|
|
832
|
-
|
833
|
-
|
697
|
+
def configure_connection
|
698
|
+
variables = @config.fetch(:variables, {}).stringify_keys
|
834
699
|
|
835
|
-
|
836
|
-
|
700
|
+
# By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
|
701
|
+
variables["sql_auto_is_null"] = 0
|
837
702
|
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
703
|
+
# Increase timeout so the server doesn't disconnect us.
|
704
|
+
wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
|
705
|
+
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
706
|
+
variables["wait_timeout"] = wait_timeout
|
842
707
|
|
843
|
-
|
708
|
+
defaults = [":default", :default].to_set
|
844
709
|
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
710
|
+
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
711
|
+
# https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
|
712
|
+
# If the user has provided another value for sql_mode, don't replace it.
|
713
|
+
if sql_mode = variables.delete("sql_mode")
|
714
|
+
sql_mode = quote(sql_mode)
|
715
|
+
elsif !defaults.include?(strict_mode?)
|
716
|
+
if strict_mode?
|
717
|
+
sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')"
|
718
|
+
else
|
719
|
+
sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')"
|
720
|
+
sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')"
|
721
|
+
sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')"
|
722
|
+
end
|
723
|
+
sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')"
|
857
724
|
end
|
858
|
-
sql_mode =
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
868
|
-
encoding << ", "
|
869
|
-
end
|
870
|
-
|
871
|
-
# Gather up all of the SET variables...
|
872
|
-
variable_assignments = variables.map do |k, v|
|
873
|
-
if defaults.include?(v)
|
874
|
-
"@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
|
875
|
-
elsif !v.nil?
|
876
|
-
"@@SESSION.#{k} = #{quote(v)}"
|
725
|
+
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
726
|
+
|
727
|
+
# NAMES does not have an equals sign, see
|
728
|
+
# https://dev.mysql.com/doc/refman/5.7/en/set-names.html
|
729
|
+
# (trailing comma because variable_assignments will always have content)
|
730
|
+
if @config[:encoding]
|
731
|
+
encoding = +"NAMES #{@config[:encoding]}"
|
732
|
+
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
733
|
+
encoding << ", "
|
877
734
|
end
|
878
|
-
# or else nil; compact to clear nils out
|
879
|
-
end.compact.join(', ')
|
880
735
|
|
881
|
-
|
882
|
-
|
883
|
-
|
736
|
+
# Gather up all of the SET variables...
|
737
|
+
variable_assignments = variables.map do |k, v|
|
738
|
+
if defaults.include?(v)
|
739
|
+
"@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
|
740
|
+
elsif !v.nil?
|
741
|
+
"@@SESSION.#{k} = #{quote(v)}"
|
742
|
+
end
|
743
|
+
# or else nil; compact to clear nils out
|
744
|
+
end.compact.join(", ")
|
884
745
|
|
885
|
-
|
886
|
-
|
887
|
-
each_hash(result)
|
746
|
+
# ...and send them all in one query
|
747
|
+
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
888
748
|
end
|
889
|
-
end
|
890
749
|
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
750
|
+
def column_definitions(table_name) # :nodoc:
|
751
|
+
execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result|
|
752
|
+
each_hash(result)
|
753
|
+
end
|
895
754
|
end
|
896
|
-
end
|
897
755
|
|
898
|
-
|
899
|
-
|
900
|
-
end
|
901
|
-
|
902
|
-
def create_table_definition(*args) # :nodoc:
|
903
|
-
MySQL::TableDefinition.new(*args)
|
904
|
-
end
|
905
|
-
|
906
|
-
def extract_schema_qualified_name(string) # :nodoc:
|
907
|
-
schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/).map { |s| quote(s) }
|
908
|
-
schema, name = "DATABASE()", schema unless name
|
909
|
-
[schema, name]
|
910
|
-
end
|
911
|
-
|
912
|
-
def integer_to_sql(limit) # :nodoc:
|
913
|
-
case limit
|
914
|
-
when 1; 'tinyint'
|
915
|
-
when 2; 'smallint'
|
916
|
-
when 3; 'mediumint'
|
917
|
-
when nil, 4; 'int'
|
918
|
-
when 5..8; 'bigint'
|
919
|
-
else raise(ActiveRecordError, "No integer type has byte size #{limit}")
|
756
|
+
def create_table_info(table_name) # :nodoc:
|
757
|
+
exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
|
920
758
|
end
|
921
|
-
end
|
922
759
|
|
923
|
-
|
924
|
-
|
925
|
-
when 0..0xff; 'tinytext'
|
926
|
-
when nil, 0x100..0xffff; 'text'
|
927
|
-
when 0x10000..0xffffff; 'mediumtext'
|
928
|
-
when 0x1000000..0xffffffff; 'longtext'
|
929
|
-
else raise(ActiveRecordError, "No text type has byte length #{limit}")
|
760
|
+
def arel_visitor
|
761
|
+
Arel::Visitors::MySQL.new(self)
|
930
762
|
end
|
931
|
-
end
|
932
763
|
|
933
|
-
|
934
|
-
|
935
|
-
when 0..0xff; 'tinyblob'
|
936
|
-
when nil, 0x100..0xffff; 'blob'
|
937
|
-
when 0x10000..0xffffff; 'mediumblob'
|
938
|
-
when 0x1000000..0xffffffff; 'longblob'
|
939
|
-
else raise(ActiveRecordError, "No binary type has byte length #{limit}")
|
764
|
+
def build_statement_pool
|
765
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
940
766
|
end
|
941
|
-
end
|
942
767
|
|
943
|
-
|
944
|
-
|
945
|
-
|
768
|
+
def mismatched_foreign_key(message, sql:, binds:)
|
769
|
+
match = %r/
|
770
|
+
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
771
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
|
772
|
+
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
773
|
+
/xmi.match(sql)
|
946
774
|
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
end
|
953
|
-
end
|
775
|
+
options = {
|
776
|
+
message: message,
|
777
|
+
sql: sql,
|
778
|
+
binds: binds,
|
779
|
+
}
|
954
780
|
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
781
|
+
if match
|
782
|
+
options[:table] = match[:table]
|
783
|
+
options[:foreign_key] = match[:foreign_key]
|
784
|
+
options[:target_table] = match[:target_table]
|
785
|
+
options[:primary_key] = match[:primary_key]
|
786
|
+
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
961
787
|
end
|
788
|
+
|
789
|
+
MismatchedForeignKey.new(**options)
|
962
790
|
end
|
963
791
|
|
964
|
-
|
792
|
+
def version_string(full_version_string)
|
793
|
+
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
794
|
+
end
|
965
795
|
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
796
|
+
class MysqlString < Type::String # :nodoc:
|
797
|
+
def serialize(value)
|
798
|
+
case value
|
799
|
+
when true then "1"
|
800
|
+
when false then "0"
|
801
|
+
else super
|
802
|
+
end
|
971
803
|
end
|
804
|
+
|
805
|
+
private
|
806
|
+
def cast_value(value)
|
807
|
+
case value
|
808
|
+
when true then "1"
|
809
|
+
when false then "0"
|
810
|
+
else super
|
811
|
+
end
|
812
|
+
end
|
972
813
|
end
|
973
|
-
end
|
974
814
|
|
975
|
-
|
976
|
-
|
977
|
-
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
815
|
+
ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
|
816
|
+
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
978
817
|
end
|
979
818
|
end
|
980
819
|
end
|