activerecord 5.0.6 → 6.0.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 +5 -5
- data/CHANGELOG.md +638 -2023
- data/MIT-LICENSE +3 -1
- data/README.rdoc +8 -6
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record/aggregations.rb +249 -246
- data/lib/active_record/association_relation.rb +24 -13
- data/lib/active_record/associations/alias_tracker.rb +24 -33
- data/lib/active_record/associations/association.rb +119 -56
- data/lib/active_record/associations/association_scope.rb +94 -94
- 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 +42 -61
- 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 +80 -252
- data/lib/active_record/associations/collection_proxy.rb +158 -121
- data/lib/active_record/associations/foreign_association.rb +9 -0
- data/lib/active_record/associations/has_many_association.rb +23 -29
- 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 +38 -90
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -176
- data/lib/active_record/associations/preloader/association.rb +84 -125
- data/lib/active_record/associations/preloader/through_association.rb +82 -75
- data/lib/active_record/associations/preloader.rb +90 -102
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +26 -14
- data/lib/active_record/associations.rb +1603 -1592
- data/lib/active_record/attribute_assignment.rb +54 -60
- data/lib/active_record/attribute_decorators.rb +38 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
- data/lib/active_record/attribute_methods/dirty.rb +179 -109
- data/lib/active_record/attribute_methods/primary_key.rb +86 -91
- data/lib/active_record/attribute_methods/query.rb +4 -3
- data/lib/active_record/attribute_methods/read.rb +21 -49
- data/lib/active_record/attribute_methods/serialization.rb +30 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
- data/lib/active_record/attribute_methods/write.rb +35 -33
- data/lib/active_record/attribute_methods.rb +66 -106
- data/lib/active_record/attributes.rb +38 -24
- data/lib/active_record/autosave_association.rb +53 -32
- data/lib/active_record/base.rb +27 -24
- data/lib/active_record/callbacks.rb +63 -33
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +11 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
- data/lib/active_record/connection_adapters/column.rb +41 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
- 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 +143 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -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 +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
- data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -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 -10
- 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 +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
- 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 +45 -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 +31 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -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 +9 -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 +19 -25
- 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 +35 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
- data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -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 +120 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
- 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 +254 -262
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
- data/lib/active_record/connection_handling.rb +159 -40
- data/lib/active_record/core.rb +202 -162
- data/lib/active_record/counter_cache.rb +57 -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 +79 -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 -86
- data/lib/active_record/enum.rb +60 -23
- data/lib/active_record/errors.rb +114 -18
- data/lib/active_record/explain.rb +4 -3
- 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 +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +195 -502
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +151 -97
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +116 -25
- data/lib/active_record/internal_metadata.rb +15 -18
- data/lib/active_record/legacy_yaml_adapter.rb +4 -2
- data/lib/active_record/locking/optimistic.rb +78 -87
- 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 +88 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +143 -97
- data/lib/active_record/migration/compatibility.rb +174 -56
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +367 -300
- data/lib/active_record/model_schema.rb +145 -139
- data/lib/active_record/nested_attributes.rb +214 -201
- data/lib/active_record/no_touching.rb +10 -1
- data/lib/active_record/null_relation.rb +13 -34
- data/lib/active_record/persistence.rb +442 -72
- data/lib/active_record/query_cache.rb +15 -14
- data/lib/active_record/querying.rb +36 -23
- 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 +309 -177
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +211 -249
- data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
- data/lib/active_record/relation/batches.rb +99 -52
- data/lib/active_record/relation/calculations.rb +211 -172
- data/lib/active_record/relation/delegation.rb +67 -65
- data/lib/active_record/relation/finder_methods.rb +208 -247
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +78 -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 +86 -104
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +458 -329
- data/lib/active_record/relation/record_fetch_warning.rb +5 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -95
- data/lib/active_record/relation/where_clause_factory.rb +6 -11
- data/lib/active_record/relation.rb +429 -318
- data/lib/active_record/result.rb +69 -39
- 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 +15 -5
- data/lib/active_record/scoping/default.rb +93 -95
- data/lib/active_record/scoping/named.rb +45 -25
- data/lib/active_record/scoping.rb +20 -19
- 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 +4 -1
- data/lib/active_record/table_metadata.rb +26 -20
- data/lib/active_record/tasks/database_tasks.rb +276 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
- data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +70 -35
- data/lib/active_record/touch_later.rb +7 -4
- data/lib/active_record/transactions.rb +133 -149
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +44 -45
- 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 -3
- 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 -8
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +2 -1
- data/lib/active_record/type/type_map.rb +13 -15
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +23 -17
- 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 -1
- 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 -4
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -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 +257 -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 +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +58 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- 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/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 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +133 -50
- 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 -130
- 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
@@ -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,57 @@ 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
|
-
|
46
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
47
|
+
private
|
58
48
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
49
|
+
def dealloc(stmt)
|
50
|
+
stmt.close
|
51
|
+
end
|
63
52
|
end
|
64
53
|
|
65
54
|
def initialize(connection, logger, connection_options, config)
|
66
55
|
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 (#{full_version.match(/^\d+\.\d+\.\d+/)[0]}) is too old. Active Record supports MySQL >= 5.0."
|
72
|
-
end
|
73
56
|
end
|
74
57
|
|
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(full_version.match(/^\d+\.\d+\.\d+/)[0])
|
58
|
+
def get_database_version #:nodoc:
|
59
|
+
full_version_string = get_full_version
|
60
|
+
version_string = version_string(full_version_string)
|
61
|
+
Version.new(version_string, full_version_string)
|
85
62
|
end
|
86
63
|
|
87
64
|
def mariadb? # :nodoc:
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
# Returns true, since this connection adapter supports migrations.
|
92
|
-
def supports_migrations?
|
93
|
-
true
|
94
|
-
end
|
95
|
-
|
96
|
-
def supports_primary_key?
|
97
|
-
true
|
65
|
+
/mariadb/i.match?(full_version)
|
98
66
|
end
|
99
67
|
|
100
|
-
def supports_bulk_alter?
|
68
|
+
def supports_bulk_alter?
|
101
69
|
true
|
102
70
|
end
|
103
71
|
|
104
|
-
|
105
|
-
|
106
|
-
def supports_statement_cache?
|
107
|
-
true
|
72
|
+
def supports_index_sort_order?
|
73
|
+
!mariadb? && database_version >= "8.0.1"
|
108
74
|
end
|
109
75
|
|
110
|
-
|
111
|
-
|
112
|
-
def supports_index_sort_order?
|
113
|
-
true
|
76
|
+
def supports_expression_index?
|
77
|
+
!mariadb? && database_version >= "8.0.13"
|
114
78
|
end
|
115
79
|
|
116
80
|
def supports_transaction_isolation?
|
@@ -134,10 +98,23 @@ module ActiveRecord
|
|
134
98
|
end
|
135
99
|
|
136
100
|
def supports_datetime_with_precision?
|
101
|
+
mariadb? || database_version >= "5.6.4"
|
102
|
+
end
|
103
|
+
|
104
|
+
def supports_virtual_columns?
|
105
|
+
mariadb? || database_version >= "5.7.5"
|
106
|
+
end
|
107
|
+
|
108
|
+
# See https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html for more details.
|
109
|
+
def supports_optimizer_hints?
|
110
|
+
!mariadb? && database_version >= "5.7.7"
|
111
|
+
end
|
112
|
+
|
113
|
+
def supports_common_table_expressions?
|
137
114
|
if mariadb?
|
138
|
-
|
115
|
+
database_version >= "10.2.1"
|
139
116
|
else
|
140
|
-
|
117
|
+
database_version >= "8.0.1"
|
141
118
|
end
|
142
119
|
end
|
143
120
|
|
@@ -145,12 +122,20 @@ module ActiveRecord
|
|
145
122
|
true
|
146
123
|
end
|
147
124
|
|
125
|
+
def supports_insert_on_duplicate_skip?
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
129
|
+
def supports_insert_on_duplicate_update?
|
130
|
+
true
|
131
|
+
end
|
132
|
+
|
148
133
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
149
|
-
|
134
|
+
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
150
135
|
end
|
151
136
|
|
152
137
|
def release_advisory_lock(lock_name) # :nodoc:
|
153
|
-
|
138
|
+
query_value("SELECT RELEASE_LOCK(#{quote(lock_name.to_s)})") == 1
|
154
139
|
end
|
155
140
|
|
156
141
|
def native_database_types
|
@@ -158,7 +143,7 @@ module ActiveRecord
|
|
158
143
|
end
|
159
144
|
|
160
145
|
def index_algorithms
|
161
|
-
{ default:
|
146
|
+
{ default: +"ALGORITHM = DEFAULT", copy: +"ALGORITHM = COPY", inplace: +"ALGORITHM = INPLACE" }
|
162
147
|
end
|
163
148
|
|
164
149
|
# HELPER METHODS ===========================================
|
@@ -169,10 +154,6 @@ module ActiveRecord
|
|
169
154
|
raise NotImplementedError
|
170
155
|
end
|
171
156
|
|
172
|
-
def new_column(*args) #:nodoc:
|
173
|
-
MySQL::Column.new(*args)
|
174
|
-
end
|
175
|
-
|
176
157
|
# Must return the MySQL error number from the exception, if the exception has an
|
177
158
|
# error number.
|
178
159
|
def error_number(exception) # :nodoc:
|
@@ -182,7 +163,7 @@ module ActiveRecord
|
|
182
163
|
# REFERENTIAL INTEGRITY ====================================
|
183
164
|
|
184
165
|
def disable_referential_integrity #:nodoc:
|
185
|
-
old =
|
166
|
+
old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
|
186
167
|
|
187
168
|
begin
|
188
169
|
update("SET FOREIGN_KEY_CHECKS = 0")
|
@@ -194,10 +175,9 @@ module ActiveRecord
|
|
194
175
|
|
195
176
|
# CONNECTION MANAGEMENT ====================================
|
196
177
|
|
197
|
-
|
198
|
-
def clear_cache!
|
178
|
+
def clear_cache! # :nodoc:
|
199
179
|
reload_type_map
|
200
|
-
|
180
|
+
super
|
201
181
|
end
|
202
182
|
|
203
183
|
#--
|
@@ -206,16 +186,22 @@ module ActiveRecord
|
|
206
186
|
|
207
187
|
def explain(arel, binds = [])
|
208
188
|
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
209
|
-
start =
|
210
|
-
result = exec_query(sql,
|
211
|
-
elapsed =
|
189
|
+
start = Concurrent.monotonic_time
|
190
|
+
result = exec_query(sql, "EXPLAIN", binds)
|
191
|
+
elapsed = Concurrent.monotonic_time - start
|
212
192
|
|
213
193
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
214
194
|
end
|
215
195
|
|
216
196
|
# Executes the SQL statement in the context of this connection.
|
217
197
|
def execute(sql, name = nil)
|
218
|
-
|
198
|
+
materialize_transactions
|
199
|
+
|
200
|
+
log(sql, name) do
|
201
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
202
|
+
@connection.query(sql)
|
203
|
+
end
|
204
|
+
end
|
219
205
|
end
|
220
206
|
|
221
207
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
@@ -242,19 +228,7 @@ module ActiveRecord
|
|
242
228
|
execute "ROLLBACK"
|
243
229
|
end
|
244
230
|
|
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
|
231
|
+
def empty_insert_statement_value(primary_key = nil)
|
258
232
|
"VALUES ()"
|
259
233
|
end
|
260
234
|
|
@@ -270,7 +244,7 @@ module ActiveRecord
|
|
270
244
|
end
|
271
245
|
|
272
246
|
# Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
|
273
|
-
# Charset defaults to
|
247
|
+
# Charset defaults to utf8mb4.
|
274
248
|
#
|
275
249
|
# Example:
|
276
250
|
# create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
|
@@ -278,9 +252,13 @@ module ActiveRecord
|
|
278
252
|
# create_database 'matt_development', charset: :big5
|
279
253
|
def create_database(name, options = {})
|
280
254
|
if options[:collation]
|
281
|
-
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT
|
255
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT COLLATE #{quote_table_name(options[:collation])}"
|
256
|
+
elsif options[:charset]
|
257
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset])}"
|
258
|
+
elsif row_format_dynamic_by_default?
|
259
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET `utf8mb4`"
|
282
260
|
else
|
283
|
-
|
261
|
+
raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
|
284
262
|
end
|
285
263
|
end
|
286
264
|
|
@@ -293,149 +271,34 @@ module ActiveRecord
|
|
293
271
|
end
|
294
272
|
|
295
273
|
def current_database
|
296
|
-
|
274
|
+
query_value("SELECT database()", "SCHEMA")
|
297
275
|
end
|
298
276
|
|
299
277
|
# Returns the database character set.
|
300
278
|
def charset
|
301
|
-
show_variable
|
279
|
+
show_variable "character_set_database"
|
302
280
|
end
|
303
281
|
|
304
282
|
# Returns the database collation strategy.
|
305
283
|
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] == "CURRENT_TIMESTAMP"
|
403
|
-
default, default_function = nil, field[:Default]
|
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
|
284
|
+
show_variable "collation_database"
|
409
285
|
end
|
410
286
|
|
411
287
|
def table_comment(table_name) # :nodoc:
|
412
|
-
|
288
|
+
scope = quoted_scope(table_name)
|
413
289
|
|
414
|
-
|
290
|
+
query_value(<<~SQL, "SCHEMA").presence
|
415
291
|
SELECT table_comment
|
416
292
|
FROM information_schema.tables
|
417
|
-
WHERE table_schema = #{schema}
|
418
|
-
AND table_name = #{name}
|
293
|
+
WHERE table_schema = #{scope[:schema]}
|
294
|
+
AND table_name = #{scope[:name]}
|
419
295
|
SQL
|
420
296
|
end
|
421
297
|
|
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}")
|
298
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
299
|
+
comment = extract_new_comment_value(comment_or_changes)
|
300
|
+
comment = "" if comment.nil?
|
301
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
|
439
302
|
end
|
440
303
|
|
441
304
|
# Renames a table.
|
@@ -478,32 +341,34 @@ module ActiveRecord
|
|
478
341
|
|
479
342
|
def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
|
480
343
|
default = extract_new_default_value(default_or_changes)
|
481
|
-
|
482
|
-
change_column table_name, column_name, column.sql_type, :default => default
|
344
|
+
change_column table_name, column_name, nil, default: default
|
483
345
|
end
|
484
346
|
|
485
347
|
def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
|
486
|
-
column = column_for(table_name, column_name)
|
487
|
-
|
488
348
|
unless null || default.nil?
|
489
349
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
490
350
|
end
|
491
351
|
|
492
|
-
change_column table_name, column_name,
|
352
|
+
change_column table_name, column_name, nil, null: null
|
353
|
+
end
|
354
|
+
|
355
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
356
|
+
comment = extract_new_comment_value(comment_or_changes)
|
357
|
+
change_column table_name, column_name, nil, comment: comment
|
493
358
|
end
|
494
359
|
|
495
360
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
496
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{
|
361
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}")
|
497
362
|
end
|
498
363
|
|
499
364
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
500
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{
|
365
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
501
366
|
rename_column_indexes(table_name, column_name, new_column_name)
|
502
367
|
end
|
503
368
|
|
504
369
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
505
370
|
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}"
|
371
|
+
sql = +"CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
|
507
372
|
execute add_sql_comment!(sql, comment)
|
508
373
|
end
|
509
374
|
|
@@ -515,35 +380,36 @@ module ActiveRecord
|
|
515
380
|
def foreign_keys(table_name)
|
516
381
|
raise ArgumentError unless table_name.present?
|
517
382
|
|
518
|
-
|
383
|
+
scope = quoted_scope(table_name)
|
519
384
|
|
520
|
-
fk_info =
|
385
|
+
fk_info = exec_query(<<~SQL, "SCHEMA")
|
521
386
|
SELECT fk.referenced_table_name AS 'to_table',
|
522
387
|
fk.referenced_column_name AS 'primary_key',
|
523
388
|
fk.column_name AS 'column',
|
524
389
|
fk.constraint_name AS 'name',
|
525
390
|
rc.update_rule AS 'on_update',
|
526
391
|
rc.delete_rule AS 'on_delete'
|
527
|
-
FROM information_schema.
|
528
|
-
JOIN information_schema.
|
392
|
+
FROM information_schema.referential_constraints rc
|
393
|
+
JOIN information_schema.key_column_usage fk
|
529
394
|
USING (constraint_schema, constraint_name)
|
530
395
|
WHERE fk.referenced_column_name IS NOT NULL
|
531
|
-
AND fk.table_schema = #{schema}
|
532
|
-
AND fk.table_name = #{name}
|
533
|
-
AND rc.
|
396
|
+
AND fk.table_schema = #{scope[:schema]}
|
397
|
+
AND fk.table_name = #{scope[:name]}
|
398
|
+
AND rc.constraint_schema = #{scope[:schema]}
|
399
|
+
AND rc.table_name = #{scope[:name]}
|
534
400
|
SQL
|
535
401
|
|
536
402
|
fk_info.map do |row|
|
537
403
|
options = {
|
538
|
-
column: row[
|
539
|
-
name: row[
|
540
|
-
primary_key: row[
|
404
|
+
column: row["column"],
|
405
|
+
name: row["name"],
|
406
|
+
primary_key: row["primary_key"]
|
541
407
|
}
|
542
408
|
|
543
|
-
options[:on_update] = extract_foreign_key_action(row[
|
544
|
-
options[:on_delete] = extract_foreign_key_action(row[
|
409
|
+
options[:on_update] = extract_foreign_key_action(row["on_update"])
|
410
|
+
options[:on_delete] = extract_foreign_key_action(row["on_delete"])
|
545
411
|
|
546
|
-
ForeignKeyDefinition.new(table_name, row[
|
412
|
+
ForeignKeyDefinition.new(table_name, row["to_table"], options)
|
547
413
|
end
|
548
414
|
end
|
549
415
|
|
@@ -553,7 +419,7 @@ module ActiveRecord
|
|
553
419
|
create_table_info = create_table_info(table_name)
|
554
420
|
|
555
421
|
# strip create_definitions and partition_options
|
556
|
-
raw_table_options = create_table_info.sub(/\A.*\n\) /m,
|
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')
|
@@ -561,39 +427,16 @@ module ActiveRecord
|
|
561
427
|
table_options[:options] = raw_table_options
|
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
|
@@ -635,342 +495,336 @@ module ActiveRecord
|
|
635
495
|
# Convert Arel node to string
|
636
496
|
s = s.to_sql 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
|
-
|
707
|
-
else
|
532
|
+
private
|
533
|
+
|
534
|
+
def initialize_type_map(m = type_map)
|
708
535
|
super
|
709
|
-
end
|
710
|
-
end
|
711
536
|
|
712
|
-
|
713
|
-
|
714
|
-
|
537
|
+
register_class_with_limit m, %r(char)i, MysqlString
|
538
|
+
|
539
|
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
540
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
541
|
+
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
542
|
+
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
|
543
|
+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
|
544
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
545
|
+
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
546
|
+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
547
|
+
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
548
|
+
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
549
|
+
|
550
|
+
register_integer_type m, %r(^bigint)i, limit: 8
|
551
|
+
register_integer_type m, %r(^int)i, limit: 4
|
552
|
+
register_integer_type m, %r(^mediumint)i, limit: 3
|
553
|
+
register_integer_type m, %r(^smallint)i, limit: 2
|
554
|
+
register_integer_type m, %r(^tinyint)i, limit: 1
|
555
|
+
|
556
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
557
|
+
m.alias_type %r(year)i, "integer"
|
558
|
+
m.alias_type %r(bit)i, "binary"
|
559
|
+
|
560
|
+
m.register_type(%r(enum)i) do |sql_type|
|
561
|
+
limit = sql_type[/^enum\s*\((.+)\)/i, 1]
|
562
|
+
.split(",").map { |enum| enum.strip.length - 2 }.max
|
563
|
+
MysqlString.new(limit: limit)
|
564
|
+
end
|
715
565
|
|
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})" }
|
566
|
+
m.register_type(%r(^set)i) do |sql_type|
|
567
|
+
limit = sql_type[/^set\s*\((.+)\)/i, 1]
|
568
|
+
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
569
|
+
MysqlString.new(limit: limit)
|
724
570
|
end
|
725
571
|
end
|
726
572
|
|
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
|
573
|
+
def register_integer_type(mapping, key, options)
|
574
|
+
mapping.register_type(key) do |sql_type|
|
575
|
+
if /\bunsigned\b/.match?(sql_type)
|
576
|
+
Type::UnsignedInteger.new(options)
|
577
|
+
else
|
578
|
+
Type::Integer.new(options)
|
579
|
+
end
|
580
|
+
end
|
745
581
|
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
582
|
|
757
|
-
|
758
|
-
|
583
|
+
def extract_precision(sql_type)
|
584
|
+
if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
|
585
|
+
super || 0
|
586
|
+
else
|
587
|
+
super
|
588
|
+
end
|
759
589
|
end
|
760
590
|
|
761
|
-
|
762
|
-
|
591
|
+
# See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
|
592
|
+
ER_FILSORT_ABORT = 1028
|
593
|
+
ER_DUP_ENTRY = 1062
|
594
|
+
ER_NOT_NULL_VIOLATION = 1048
|
595
|
+
ER_NO_REFERENCED_ROW = 1216
|
596
|
+
ER_ROW_IS_REFERENCED = 1217
|
597
|
+
ER_DO_NOT_HAVE_DEFAULT = 1364
|
598
|
+
ER_ROW_IS_REFERENCED_2 = 1451
|
599
|
+
ER_NO_REFERENCED_ROW_2 = 1452
|
600
|
+
ER_DATA_TOO_LONG = 1406
|
601
|
+
ER_OUT_OF_RANGE = 1264
|
602
|
+
ER_LOCK_DEADLOCK = 1213
|
603
|
+
ER_CANNOT_ADD_FOREIGN = 1215
|
604
|
+
ER_CANNOT_CREATE_TABLE = 1005
|
605
|
+
ER_LOCK_WAIT_TIMEOUT = 1205
|
606
|
+
ER_QUERY_INTERRUPTED = 1317
|
607
|
+
ER_QUERY_TIMEOUT = 3024
|
608
|
+
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
609
|
+
|
610
|
+
def translate_exception(exception, message:, sql:, binds:)
|
611
|
+
case error_number(exception)
|
612
|
+
when ER_DUP_ENTRY
|
613
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
614
|
+
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
615
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
616
|
+
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
617
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
618
|
+
when ER_CANNOT_CREATE_TABLE
|
619
|
+
if message.include?("errno: 150")
|
620
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
621
|
+
else
|
622
|
+
super
|
623
|
+
end
|
624
|
+
when ER_DATA_TOO_LONG
|
625
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
626
|
+
when ER_OUT_OF_RANGE
|
627
|
+
RangeError.new(message, sql: sql, binds: binds)
|
628
|
+
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
629
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
630
|
+
when ER_LOCK_DEADLOCK
|
631
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
632
|
+
when ER_LOCK_WAIT_TIMEOUT
|
633
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
634
|
+
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
635
|
+
StatementTimeout.new(message, sql: sql, binds: binds)
|
636
|
+
when ER_QUERY_INTERRUPTED
|
637
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
638
|
+
else
|
639
|
+
super
|
640
|
+
end
|
763
641
|
end
|
764
642
|
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
end
|
643
|
+
def change_column_for_alter(table_name, column_name, type, options = {})
|
644
|
+
column = column_for(table_name, column_name)
|
645
|
+
type ||= column.sql_type
|
769
646
|
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
default: column.default,
|
774
|
-
null: column.null,
|
775
|
-
auto_increment: column.auto_increment?
|
776
|
-
}
|
647
|
+
unless options.key?(:default)
|
648
|
+
options[:default] = column.default
|
649
|
+
end
|
777
650
|
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
782
|
-
end
|
651
|
+
unless options.key?(:null)
|
652
|
+
options[:null] = column.null
|
653
|
+
end
|
783
654
|
|
784
|
-
|
785
|
-
|
786
|
-
|
655
|
+
unless options.key?(:comment)
|
656
|
+
options[:comment] = column.comment
|
657
|
+
end
|
787
658
|
|
788
|
-
|
789
|
-
|
790
|
-
|
659
|
+
td = create_table_definition(table_name)
|
660
|
+
cd = td.new_column_definition(column.name, type, options)
|
661
|
+
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
662
|
+
end
|
791
663
|
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
664
|
+
def rename_column_for_alter(table_name, column_name, new_column_name)
|
665
|
+
column = column_for(table_name, column_name)
|
666
|
+
options = {
|
667
|
+
default: column.default,
|
668
|
+
null: column.null,
|
669
|
+
auto_increment: column.auto_increment?
|
670
|
+
}
|
797
671
|
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
672
|
+
current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
|
673
|
+
td = create_table_definition(table_name)
|
674
|
+
cd = td.new_column_definition(new_column_name, current_type, options)
|
675
|
+
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
676
|
+
end
|
802
677
|
|
803
|
-
|
804
|
-
|
805
|
-
|
678
|
+
def add_index_for_alter(table_name, column_name, options = {})
|
679
|
+
index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options)
|
680
|
+
index_algorithm[0, 0] = ", " if index_algorithm.present?
|
681
|
+
"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
682
|
+
end
|
806
683
|
|
807
|
-
|
808
|
-
|
809
|
-
|
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
|
810
688
|
|
811
|
-
|
689
|
+
def add_timestamps_for_alter(table_name, options = {})
|
690
|
+
options[:null] = false if options[:null].nil?
|
812
691
|
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
subsubselect = select.clone
|
817
|
-
subsubselect.projections = [key]
|
692
|
+
if !options.key?(:precision) && supports_datetime_with_precision?
|
693
|
+
options[:precision] = 6
|
694
|
+
end
|
818
695
|
|
819
|
-
|
820
|
-
|
821
|
-
subsubselect.distinct unless select.limit || select.offset || select.orders.any?
|
696
|
+
[add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
|
697
|
+
end
|
822
698
|
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
end
|
699
|
+
def remove_timestamps_for_alter(table_name, options = {})
|
700
|
+
[remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
|
701
|
+
end
|
827
702
|
|
828
|
-
|
829
|
-
|
830
|
-
|
703
|
+
def supports_rename_index?
|
704
|
+
mariadb? ? false : database_version >= "5.7.6"
|
705
|
+
end
|
831
706
|
|
832
|
-
|
833
|
-
|
707
|
+
def configure_connection
|
708
|
+
variables = @config.fetch(:variables, {}).stringify_keys
|
834
709
|
|
835
|
-
|
836
|
-
|
710
|
+
# By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
|
711
|
+
variables["sql_auto_is_null"] = 0
|
837
712
|
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
713
|
+
# Increase timeout so the server doesn't disconnect us.
|
714
|
+
wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
|
715
|
+
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
716
|
+
variables["wait_timeout"] = wait_timeout
|
842
717
|
|
843
|
-
|
718
|
+
defaults = [":default", :default].to_set
|
844
719
|
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
720
|
+
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
721
|
+
# https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
|
722
|
+
# If the user has provided another value for sql_mode, don't replace it.
|
723
|
+
if sql_mode = variables.delete("sql_mode")
|
724
|
+
sql_mode = quote(sql_mode)
|
725
|
+
elsif !defaults.include?(strict_mode?)
|
726
|
+
if strict_mode?
|
727
|
+
sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')"
|
728
|
+
else
|
729
|
+
sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')"
|
730
|
+
sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')"
|
731
|
+
sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')"
|
732
|
+
end
|
733
|
+
sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')"
|
857
734
|
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)}"
|
735
|
+
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
736
|
+
|
737
|
+
# NAMES does not have an equals sign, see
|
738
|
+
# https://dev.mysql.com/doc/refman/5.7/en/set-names.html
|
739
|
+
# (trailing comma because variable_assignments will always have content)
|
740
|
+
if @config[:encoding]
|
741
|
+
encoding = +"NAMES #{@config[:encoding]}"
|
742
|
+
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
743
|
+
encoding << ", "
|
877
744
|
end
|
878
|
-
# or else nil; compact to clear nils out
|
879
|
-
end.compact.join(', ')
|
880
745
|
|
881
|
-
|
882
|
-
|
883
|
-
|
746
|
+
# Gather up all of the SET variables...
|
747
|
+
variable_assignments = variables.map do |k, v|
|
748
|
+
if defaults.include?(v)
|
749
|
+
"@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
|
750
|
+
elsif !v.nil?
|
751
|
+
"@@SESSION.#{k} = #{quote(v)}"
|
752
|
+
end
|
753
|
+
# or else nil; compact to clear nils out
|
754
|
+
end.compact.join(", ")
|
884
755
|
|
885
|
-
|
886
|
-
|
887
|
-
each_hash(result)
|
756
|
+
# ...and send them all in one query
|
757
|
+
execute "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
|
888
758
|
end
|
889
|
-
end
|
890
759
|
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
760
|
+
def column_definitions(table_name) # :nodoc:
|
761
|
+
execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result|
|
762
|
+
each_hash(result)
|
763
|
+
end
|
895
764
|
end
|
896
|
-
end
|
897
|
-
|
898
|
-
def create_table_info(table_name) # :nodoc:
|
899
|
-
select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
|
900
|
-
end
|
901
|
-
|
902
|
-
def create_table_definition(*args) # :nodoc:
|
903
|
-
MySQL::TableDefinition.new(*args)
|
904
|
-
end
|
905
765
|
|
906
|
-
|
907
|
-
|
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}")
|
766
|
+
def create_table_info(table_name) # :nodoc:
|
767
|
+
exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
|
920
768
|
end
|
921
|
-
end
|
922
769
|
|
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}")
|
770
|
+
def arel_visitor
|
771
|
+
Arel::Visitors::MySQL.new(self)
|
930
772
|
end
|
931
|
-
end
|
932
773
|
|
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}")
|
774
|
+
def build_statement_pool
|
775
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
940
776
|
end
|
941
|
-
end
|
942
777
|
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
778
|
+
def mismatched_foreign_key(message, sql:, binds:)
|
779
|
+
match = %r/
|
780
|
+
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
781
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
|
782
|
+
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
783
|
+
/xmi.match(sql)
|
784
|
+
|
785
|
+
options = {
|
786
|
+
message: message,
|
787
|
+
sql: sql,
|
788
|
+
binds: binds,
|
789
|
+
}
|
950
790
|
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
791
|
+
if match
|
792
|
+
options[:table] = match[:table]
|
793
|
+
options[:foreign_key] = match[:foreign_key]
|
794
|
+
options[:target_table] = match[:target_table]
|
795
|
+
options[:primary_key] = match[:primary_key]
|
796
|
+
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
957
797
|
end
|
798
|
+
|
799
|
+
MismatchedForeignKey.new(options)
|
958
800
|
end
|
959
801
|
|
960
|
-
|
802
|
+
def version_string(full_version_string)
|
803
|
+
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
804
|
+
end
|
961
805
|
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
806
|
+
class MysqlString < Type::String # :nodoc:
|
807
|
+
def serialize(value)
|
808
|
+
case value
|
809
|
+
when true then "1"
|
810
|
+
when false then "0"
|
811
|
+
else super
|
812
|
+
end
|
967
813
|
end
|
814
|
+
|
815
|
+
private
|
816
|
+
|
817
|
+
def cast_value(value)
|
818
|
+
case value
|
819
|
+
when true then "1"
|
820
|
+
when false then "0"
|
821
|
+
else super
|
822
|
+
end
|
823
|
+
end
|
968
824
|
end
|
969
|
-
end
|
970
825
|
|
971
|
-
|
972
|
-
|
973
|
-
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
826
|
+
ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
|
827
|
+
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
|
974
828
|
end
|
975
829
|
end
|
976
830
|
end
|