activerecord 4.2.0 → 6.1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
 - data/CHANGELOG.md +1221 -796
 - data/MIT-LICENSE +4 -2
 - data/README.rdoc +15 -14
 - data/examples/performance.rb +33 -32
 - data/examples/simple.rb +5 -4
 - data/lib/active_record/aggregations.rb +267 -249
 - data/lib/active_record/association_relation.rb +45 -7
 - data/lib/active_record/associations/alias_tracker.rb +40 -43
 - data/lib/active_record/associations/association.rb +172 -67
 - data/lib/active_record/associations/association_scope.rb +105 -129
 - data/lib/active_record/associations/belongs_to_association.rb +85 -59
 - data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
 - data/lib/active_record/associations/builder/association.rb +57 -43
 - data/lib/active_record/associations/builder/belongs_to.rb +74 -57
 - data/lib/active_record/associations/builder/collection_association.rb +15 -33
 - data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
 - data/lib/active_record/associations/builder/has_many.rb +13 -5
 - data/lib/active_record/associations/builder/has_one.rb +44 -6
 - data/lib/active_record/associations/builder/singular_association.rb +16 -10
 - data/lib/active_record/associations/collection_association.rb +168 -279
 - data/lib/active_record/associations/collection_proxy.rb +263 -155
 - data/lib/active_record/associations/foreign_association.rb +33 -0
 - data/lib/active_record/associations/has_many_association.rb +57 -84
 - data/lib/active_record/associations/has_many_through_association.rb +70 -82
 - data/lib/active_record/associations/has_one_association.rb +74 -47
 - data/lib/active_record/associations/has_one_through_association.rb +20 -11
 - data/lib/active_record/associations/join_dependency/join_association.rb +54 -73
 - 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 +175 -164
 - data/lib/active_record/associations/preloader/association.rb +107 -112
 - data/lib/active_record/associations/preloader/through_association.rb +85 -65
 - data/lib/active_record/associations/preloader.rb +99 -96
 - data/lib/active_record/associations/singular_association.rb +18 -45
 - data/lib/active_record/associations/through_association.rb +49 -24
 - data/lib/active_record/associations.rb +1845 -1597
 - data/lib/active_record/attribute_assignment.rb +59 -185
 - data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
 - data/lib/active_record/attribute_methods/dirty.rb +168 -138
 - data/lib/active_record/attribute_methods/primary_key.rb +93 -83
 - data/lib/active_record/attribute_methods/query.rb +8 -10
 - data/lib/active_record/attribute_methods/read.rb +19 -79
 - data/lib/active_record/attribute_methods/serialization.rb +49 -24
 - data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -36
 - data/lib/active_record/attribute_methods/write.rb +25 -56
 - data/lib/active_record/attribute_methods.rb +153 -162
 - data/lib/active_record/attributes.rb +234 -70
 - data/lib/active_record/autosave_association.rb +157 -69
 - data/lib/active_record/base.rb +49 -50
 - data/lib/active_record/callbacks.rb +234 -79
 - data/lib/active_record/coders/json.rb +3 -1
 - data/lib/active_record/coders/yaml_column.rb +46 -13
 - data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
 - data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
 - data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
 - data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
 - data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
 - data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
 - data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
 - data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
 - data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
 - data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
 - data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
 - data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
 - data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
 - data/lib/active_record/connection_adapters/column.rb +67 -40
 - data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
 - data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
 - data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
 - data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
 - data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
 - data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
 - data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
 - data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
 - data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
 - data/lib/active_record/connection_adapters/mysql/schema_statements.rb +271 -0
 - data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
 - data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
 - data/lib/active_record/connection_adapters/pool_config.rb +73 -0
 - data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
 - data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
 - data/lib/active_record/connection_adapters/postgresql/database_statements.rb +78 -161
 - data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
 - data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
 - data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
 - data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
 - data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
 - data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
 - data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
 - data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
 - data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
 - data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -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/macaddr.rb +25 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
 - data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
 - data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
 - data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
 - 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 +67 -51
 - data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
 - data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
 - data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
 - data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
 - data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -48
 - data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
 - data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
 - data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
 - data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
 - data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +499 -293
 - data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
 - data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
 - data/lib/active_record/connection_adapters/postgresql_adapter.rb +595 -382
 - data/lib/active_record/connection_adapters/schema_cache.rb +191 -29
 - data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
 - data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
 - data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
 - data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
 - data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
 - 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 +170 -0
 - data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -389
 - data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
 - data/lib/active_record/connection_adapters.rb +52 -0
 - data/lib/active_record/connection_handling.rb +314 -41
 - data/lib/active_record/core.rb +488 -243
 - data/lib/active_record/counter_cache.rb +71 -50
 - data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
 - data/lib/active_record/database_configurations/database_config.rb +80 -0
 - data/lib/active_record/database_configurations/hash_config.rb +96 -0
 - data/lib/active_record/database_configurations/url_config.rb +53 -0
 - data/lib/active_record/database_configurations.rb +273 -0
 - data/lib/active_record/delegated_type.rb +209 -0
 - data/lib/active_record/destroy_association_async_job.rb +36 -0
 - data/lib/active_record/dynamic_matchers.rb +87 -106
 - data/lib/active_record/enum.rb +212 -94
 - data/lib/active_record/errors.rb +225 -54
 - data/lib/active_record/explain.rb +27 -11
 - data/lib/active_record/explain_registry.rb +4 -2
 - data/lib/active_record/explain_subscriber.rb +11 -6
 - data/lib/active_record/fixture_set/file.rb +33 -14
 - data/lib/active_record/fixture_set/model_metadata.rb +32 -0
 - data/lib/active_record/fixture_set/render_context.rb +17 -0
 - data/lib/active_record/fixture_set/table_row.rb +152 -0
 - data/lib/active_record/fixture_set/table_rows.rb +46 -0
 - data/lib/active_record/fixtures.rb +273 -496
 - data/lib/active_record/gem_version.rb +6 -4
 - data/lib/active_record/inheritance.rb +175 -110
 - data/lib/active_record/insert_all.rb +212 -0
 - data/lib/active_record/integration.rb +121 -29
 - data/lib/active_record/internal_metadata.rb +64 -0
 - data/lib/active_record/legacy_yaml_adapter.rb +52 -0
 - data/lib/active_record/locale/en.yml +3 -2
 - data/lib/active_record/locking/optimistic.rb +103 -95
 - data/lib/active_record/locking/pessimistic.rb +22 -6
 - data/lib/active_record/log_subscriber.rb +93 -31
 - data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
 - data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
 - data/lib/active_record/middleware/database_selector.rb +77 -0
 - data/lib/active_record/migration/command_recorder.rb +185 -90
 - data/lib/active_record/migration/compatibility.rb +298 -0
 - data/lib/active_record/migration/join_table.rb +8 -7
 - data/lib/active_record/migration.rb +685 -309
 - data/lib/active_record/model_schema.rb +420 -113
 - data/lib/active_record/nested_attributes.rb +265 -216
 - data/lib/active_record/no_touching.rb +15 -2
 - data/lib/active_record/null_relation.rb +24 -38
 - data/lib/active_record/persistence.rb +574 -135
 - data/lib/active_record/query_cache.rb +29 -23
 - data/lib/active_record/querying.rb +50 -31
 - data/lib/active_record/railtie.rb +175 -54
 - data/lib/active_record/railties/console_sandbox.rb +3 -3
 - data/lib/active_record/railties/controller_runtime.rb +34 -33
 - data/lib/active_record/railties/databases.rake +533 -216
 - data/lib/active_record/readonly_attributes.rb +9 -4
 - data/lib/active_record/reflection.rb +485 -310
 - data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
 - data/lib/active_record/relation/batches.rb +217 -59
 - data/lib/active_record/relation/calculations.rb +326 -244
 - data/lib/active_record/relation/delegation.rb +76 -84
 - data/lib/active_record/relation/finder_methods.rb +318 -256
 - data/lib/active_record/relation/from_clause.rb +30 -0
 - data/lib/active_record/relation/merger.rb +99 -84
 - data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
 - data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
 - data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
 - data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
 - data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
 - data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
 - data/lib/active_record/relation/predicate_builder.rb +139 -96
 - data/lib/active_record/relation/query_attribute.rb +50 -0
 - data/lib/active_record/relation/query_methods.rb +757 -409
 - data/lib/active_record/relation/record_fetch_warning.rb +51 -0
 - data/lib/active_record/relation/spawn_methods.rb +23 -21
 - data/lib/active_record/relation/where_clause.rb +239 -0
 - data/lib/active_record/relation.rb +554 -342
 - data/lib/active_record/result.rb +91 -47
 - data/lib/active_record/runtime_registry.rb +6 -4
 - data/lib/active_record/sanitization.rb +134 -122
 - data/lib/active_record/schema.rb +21 -24
 - data/lib/active_record/schema_dumper.rb +141 -92
 - data/lib/active_record/schema_migration.rb +24 -26
 - data/lib/active_record/scoping/default.rb +96 -82
 - data/lib/active_record/scoping/named.rb +78 -36
 - data/lib/active_record/scoping.rb +45 -27
 - data/lib/active_record/secure_token.rb +48 -0
 - data/lib/active_record/serialization.rb +8 -6
 - data/lib/active_record/signed_id.rb +116 -0
 - data/lib/active_record/statement_cache.rb +89 -36
 - data/lib/active_record/store.rb +133 -43
 - data/lib/active_record/suppressor.rb +61 -0
 - data/lib/active_record/table_metadata.rb +81 -0
 - data/lib/active_record/tasks/database_tasks.rb +366 -129
 - data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
 - data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
 - data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
 - data/lib/active_record/test_databases.rb +24 -0
 - data/lib/active_record/test_fixtures.rb +291 -0
 - data/lib/active_record/timestamp.rb +86 -43
 - data/lib/active_record/touch_later.rb +65 -0
 - data/lib/active_record/transactions.rb +181 -152
 - data/lib/active_record/translation.rb +3 -1
 - data/lib/active_record/type/adapter_specific_registry.rb +126 -0
 - data/lib/active_record/type/date.rb +4 -41
 - data/lib/active_record/type/date_time.rb +4 -38
 - data/lib/active_record/type/decimal_without_scale.rb +6 -2
 - data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
 - data/lib/active_record/type/internal/timezone.rb +17 -0
 - data/lib/active_record/type/json.rb +30 -0
 - data/lib/active_record/type/serialized.rb +33 -15
 - data/lib/active_record/type/text.rb +2 -2
 - data/lib/active_record/type/time.rb +21 -16
 - data/lib/active_record/type/type_map.rb +16 -19
 - data/lib/active_record/type/unsigned_integer.rb +9 -8
 - data/lib/active_record/type.rb +84 -23
 - data/lib/active_record/type_caster/connection.rb +33 -0
 - data/lib/active_record/type_caster/map.rb +23 -0
 - data/lib/active_record/type_caster.rb +9 -0
 - data/lib/active_record/validations/absence.rb +25 -0
 - data/lib/active_record/validations/associated.rb +12 -4
 - data/lib/active_record/validations/length.rb +26 -0
 - data/lib/active_record/validations/numericality.rb +35 -0
 - data/lib/active_record/validations/presence.rb +14 -13
 - data/lib/active_record/validations/uniqueness.rb +65 -48
 - data/lib/active_record/validations.rb +39 -35
 - data/lib/active_record/version.rb +3 -1
 - data/lib/active_record.rb +44 -28
 - data/lib/arel/alias_predication.rb +9 -0
 - data/lib/arel/attributes/attribute.rb +41 -0
 - data/lib/arel/collectors/bind.rb +29 -0
 - data/lib/arel/collectors/composite.rb +39 -0
 - data/lib/arel/collectors/plain_string.rb +20 -0
 - data/lib/arel/collectors/sql_string.rb +27 -0
 - data/lib/arel/collectors/substitute_binds.rb +35 -0
 - data/lib/arel/crud.rb +42 -0
 - data/lib/arel/delete_manager.rb +18 -0
 - data/lib/arel/errors.rb +9 -0
 - data/lib/arel/expressions.rb +29 -0
 - data/lib/arel/factory_methods.rb +49 -0
 - data/lib/arel/insert_manager.rb +49 -0
 - data/lib/arel/math.rb +45 -0
 - data/lib/arel/nodes/and.rb +32 -0
 - data/lib/arel/nodes/ascending.rb +23 -0
 - data/lib/arel/nodes/binary.rb +126 -0
 - data/lib/arel/nodes/bind_param.rb +44 -0
 - data/lib/arel/nodes/case.rb +55 -0
 - data/lib/arel/nodes/casted.rb +62 -0
 - data/lib/arel/nodes/comment.rb +29 -0
 - data/lib/arel/nodes/count.rb +12 -0
 - data/lib/arel/nodes/delete_statement.rb +45 -0
 - data/lib/arel/nodes/descending.rb +23 -0
 - data/lib/arel/nodes/equality.rb +15 -0
 - data/lib/arel/nodes/extract.rb +24 -0
 - data/lib/arel/nodes/false.rb +16 -0
 - data/lib/arel/nodes/full_outer_join.rb +8 -0
 - data/lib/arel/nodes/function.rb +44 -0
 - data/lib/arel/nodes/grouping.rb +11 -0
 - data/lib/arel/nodes/homogeneous_in.rb +76 -0
 - data/lib/arel/nodes/in.rb +15 -0
 - data/lib/arel/nodes/infix_operation.rb +92 -0
 - data/lib/arel/nodes/inner_join.rb +8 -0
 - data/lib/arel/nodes/insert_statement.rb +37 -0
 - data/lib/arel/nodes/join_source.rb +20 -0
 - data/lib/arel/nodes/matches.rb +18 -0
 - data/lib/arel/nodes/named_function.rb +23 -0
 - data/lib/arel/nodes/node.rb +51 -0
 - data/lib/arel/nodes/node_expression.rb +13 -0
 - data/lib/arel/nodes/ordering.rb +27 -0
 - data/lib/arel/nodes/outer_join.rb +8 -0
 - data/lib/arel/nodes/over.rb +15 -0
 - data/lib/arel/nodes/regexp.rb +16 -0
 - data/lib/arel/nodes/right_outer_join.rb +8 -0
 - data/lib/arel/nodes/select_core.rb +67 -0
 - data/lib/arel/nodes/select_statement.rb +41 -0
 - data/lib/arel/nodes/sql_literal.rb +19 -0
 - data/lib/arel/nodes/string_join.rb +11 -0
 - data/lib/arel/nodes/table_alias.rb +31 -0
 - data/lib/arel/nodes/terminal.rb +16 -0
 - data/lib/arel/nodes/true.rb +16 -0
 - data/lib/arel/nodes/unary.rb +44 -0
 - data/lib/arel/nodes/unary_operation.rb +20 -0
 - data/lib/arel/nodes/unqualified_column.rb +22 -0
 - data/lib/arel/nodes/update_statement.rb +41 -0
 - data/lib/arel/nodes/values_list.rb +9 -0
 - data/lib/arel/nodes/window.rb +126 -0
 - data/lib/arel/nodes/with.rb +11 -0
 - data/lib/arel/nodes.rb +70 -0
 - data/lib/arel/order_predications.rb +13 -0
 - data/lib/arel/predications.rb +250 -0
 - data/lib/arel/select_manager.rb +270 -0
 - data/lib/arel/table.rb +118 -0
 - data/lib/arel/tree_manager.rb +72 -0
 - data/lib/arel/update_manager.rb +34 -0
 - data/lib/arel/visitors/dot.rb +308 -0
 - data/lib/arel/visitors/mysql.rb +93 -0
 - data/lib/arel/visitors/postgresql.rb +120 -0
 - data/lib/arel/visitors/sqlite.rb +38 -0
 - data/lib/arel/visitors/to_sql.rb +899 -0
 - data/lib/arel/visitors/visitor.rb +45 -0
 - data/lib/arel/visitors.rb +13 -0
 - data/lib/arel/window_predications.rb +9 -0
 - data/lib/arel.rb +54 -0
 - data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
 - data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
 - data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
 - data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
 - data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -10
 - data/lib/rails/generators/active_record/migration.rb +35 -1
 - data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
 - data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
 - data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
 - data/lib/rails/generators/active_record.rb +7 -5
 - metadata +175 -65
 - data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
 - data/lib/active_record/associations/preloader/collection_association.rb +0 -24
 - 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 -23
 - data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
 - data/lib/active_record/associations/preloader/singular_association.rb +0 -21
 - data/lib/active_record/attribute.rb +0 -149
 - data/lib/active_record/attribute_decorators.rb +0 -66
 - data/lib/active_record/attribute_set/builder.rb +0 -86
 - data/lib/active_record/attribute_set.rb +0 -77
 - data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
 - data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
 - data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
 - data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
 - data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
 - data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
 - data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
 - data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
 - data/lib/active_record/serializers/xml_serializer.rb +0 -193
 - data/lib/active_record/type/big_integer.rb +0 -13
 - data/lib/active_record/type/binary.rb +0 -50
 - data/lib/active_record/type/boolean.rb +0 -30
 - data/lib/active_record/type/decimal.rb +0 -40
 - data/lib/active_record/type/decorator.rb +0 -14
 - data/lib/active_record/type/float.rb +0 -19
 - data/lib/active_record/type/integer.rb +0 -55
 - data/lib/active_record/type/mutable.rb +0 -16
 - data/lib/active_record/type/numeric.rb +0 -36
 - data/lib/active_record/type/string.rb +0 -36
 - data/lib/active_record/type/time_value.rb +0 -38
 - data/lib/active_record/type/value.rb +0 -101
 - data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
 - data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
 - /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
 
| 
         @@ -1,4 +1,7 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "active_support/core_ext/string/access"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "digest/sha2"
         
     | 
| 
       2 
5 
     | 
    
         | 
| 
       3 
6 
     | 
    
         
             
            module ActiveRecord
         
     | 
| 
       4 
7 
     | 
    
         
             
              module ConnectionAdapters # :nodoc:
         
     | 
| 
         @@ -12,9 +15,41 @@ module ActiveRecord 
     | 
|
| 
       12 
15 
     | 
    
         
             
                    {}
         
     | 
| 
       13 
16 
     | 
    
         
             
                  end
         
     | 
| 
       14 
17 
     | 
    
         | 
| 
      
 18 
     | 
    
         
            +
                  def table_options(table_name)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  # Returns the table comment that's stored in database metadata.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  def table_comment(table_name)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
       15 
27 
     | 
    
         
             
                  # Truncates a table alias according to the limits of the current adapter.
         
     | 
| 
       16 
28 
     | 
    
         
             
                  def table_alias_for(table_name)
         
     | 
| 
       17 
     | 
    
         
            -
                    table_name[0...table_alias_length].tr( 
     | 
| 
      
 29 
     | 
    
         
            +
                    table_name[0...table_alias_length].tr(".", "_")
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  # Returns the relation names useable to back Active Record models.
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # For most adapters this means all #tables and #views.
         
     | 
| 
      
 34 
     | 
    
         
            +
                  def data_sources
         
     | 
| 
      
 35 
     | 
    
         
            +
                    query_values(data_source_sql, "SCHEMA")
         
     | 
| 
      
 36 
     | 
    
         
            +
                  rescue NotImplementedError
         
     | 
| 
      
 37 
     | 
    
         
            +
                    tables | views
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  # Checks to see if the data source +name+ exists on the database.
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   data_source_exists?(:ebooks)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #
         
     | 
| 
      
 44 
     | 
    
         
            +
                  def data_source_exists?(name)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    query_values(data_source_sql(name), "SCHEMA").any? if name.present?
         
     | 
| 
      
 46 
     | 
    
         
            +
                  rescue NotImplementedError
         
     | 
| 
      
 47 
     | 
    
         
            +
                    data_sources.include?(name.to_s)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  # Returns an array of table names defined in the database.
         
     | 
| 
      
 51 
     | 
    
         
            +
                  def tables
         
     | 
| 
      
 52 
     | 
    
         
            +
                    query_values(data_source_sql(type: "BASE TABLE"), "SCHEMA")
         
     | 
| 
       18 
53 
     | 
    
         
             
                  end
         
     | 
| 
       19 
54 
     | 
    
         | 
| 
       20 
55 
     | 
    
         
             
                  # Checks to see if the table +table_name+ exists on the database.
         
     | 
| 
         @@ -22,11 +57,30 @@ module ActiveRecord 
     | 
|
| 
       22 
57 
     | 
    
         
             
                  #   table_exists?(:developers)
         
     | 
| 
       23 
58 
     | 
    
         
             
                  #
         
     | 
| 
       24 
59 
     | 
    
         
             
                  def table_exists?(table_name)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    query_values(data_source_sql(table_name, type: "BASE TABLE"), "SCHEMA").any? if table_name.present?
         
     | 
| 
      
 61 
     | 
    
         
            +
                  rescue NotImplementedError
         
     | 
| 
       25 
62 
     | 
    
         
             
                    tables.include?(table_name.to_s)
         
     | 
| 
       26 
63 
     | 
    
         
             
                  end
         
     | 
| 
       27 
64 
     | 
    
         | 
| 
      
 65 
     | 
    
         
            +
                  # Returns an array of view names defined in the database.
         
     | 
| 
      
 66 
     | 
    
         
            +
                  def views
         
     | 
| 
      
 67 
     | 
    
         
            +
                    query_values(data_source_sql(type: "VIEW"), "SCHEMA")
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  # Checks to see if the view +view_name+ exists on the database.
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #
         
     | 
| 
      
 72 
     | 
    
         
            +
                  #   view_exists?(:ebooks)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #
         
     | 
| 
      
 74 
     | 
    
         
            +
                  def view_exists?(view_name)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    query_values(data_source_sql(view_name, type: "VIEW"), "SCHEMA").any? if view_name.present?
         
     | 
| 
      
 76 
     | 
    
         
            +
                  rescue NotImplementedError
         
     | 
| 
      
 77 
     | 
    
         
            +
                    views.include?(view_name.to_s)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
       28 
80 
     | 
    
         
             
                  # Returns an array of indexes for the given table.
         
     | 
| 
       29 
     | 
    
         
            -
                   
     | 
| 
      
 81 
     | 
    
         
            +
                  def indexes(table_name)
         
     | 
| 
      
 82 
     | 
    
         
            +
                    raise NotImplementedError, "#indexes is not implemented"
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
       30 
84 
     | 
    
         | 
| 
       31 
85 
     | 
    
         
             
                  # Checks to see if an index exists on a table for a given index definition.
         
     | 
| 
       32 
86 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -42,20 +96,27 @@ module ActiveRecord 
     | 
|
| 
       42 
96 
     | 
    
         
             
                  #   # Check an index with a custom name exists
         
     | 
| 
       43 
97 
     | 
    
         
             
                  #   index_exists?(:suppliers, :company_id, name: "idx_company_id")
         
     | 
| 
       44 
98 
     | 
    
         
             
                  #
         
     | 
| 
       45 
     | 
    
         
            -
                  def index_exists?(table_name, column_name, options 
     | 
| 
       46 
     | 
    
         
            -
                    column_names = Array(column_name).map(&:to_s)
         
     | 
| 
       47 
     | 
    
         
            -
                    index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, column: column_names)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  def index_exists?(table_name, column_name, **options)
         
     | 
| 
       48 
100 
     | 
    
         
             
                    checks = []
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                     
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    if column_name.present?
         
     | 
| 
      
 103 
     | 
    
         
            +
                      column_names = Array(column_name).map(&:to_s)
         
     | 
| 
      
 104 
     | 
    
         
            +
                      checks << lambda { |i| Array(i.columns) == column_names }
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
       51 
107 
     | 
    
         
             
                    checks << lambda { |i| i.unique } if options[:unique]
         
     | 
| 
      
 108 
     | 
    
         
            +
                    checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
         
     | 
| 
       52 
109 
     | 
    
         | 
| 
       53 
110 
     | 
    
         
             
                    indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
         
     | 
| 
       54 
111 
     | 
    
         
             
                  end
         
     | 
| 
       55 
112 
     | 
    
         | 
| 
       56 
     | 
    
         
            -
                  # Returns an array of Column objects for the table specified by +table_name+.
         
     | 
| 
       57 
     | 
    
         
            -
                   
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
      
 113 
     | 
    
         
            +
                  # Returns an array of +Column+ objects for the table specified by +table_name+.
         
     | 
| 
      
 114 
     | 
    
         
            +
                  def columns(table_name)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    table_name = table_name.to_s
         
     | 
| 
      
 116 
     | 
    
         
            +
                    column_definitions(table_name).map do |field|
         
     | 
| 
      
 117 
     | 
    
         
            +
                      new_column_from_field(table_name, field)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    end
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
       59 
120 
     | 
    
         | 
| 
       60 
121 
     | 
    
         
             
                  # Checks to see if a column exists in a given table.
         
     | 
| 
       61 
122 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -71,21 +132,29 @@ module ActiveRecord 
     | 
|
| 
       71 
132 
     | 
    
         
             
                  #   column_exists?(:suppliers, :name, :string, null: false)
         
     | 
| 
       72 
133 
     | 
    
         
             
                  #   column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
         
     | 
| 
       73 
134 
     | 
    
         
             
                  #
         
     | 
| 
       74 
     | 
    
         
            -
                  def column_exists?(table_name, column_name, type = nil, options 
     | 
| 
      
 135 
     | 
    
         
            +
                  def column_exists?(table_name, column_name, type = nil, **options)
         
     | 
| 
       75 
136 
     | 
    
         
             
                    column_name = column_name.to_s
         
     | 
| 
       76 
     | 
    
         
            -
                     
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
      
 137 
     | 
    
         
            +
                    checks = []
         
     | 
| 
      
 138 
     | 
    
         
            +
                    checks << lambda { |c| c.name == column_name }
         
     | 
| 
      
 139 
     | 
    
         
            +
                    checks << lambda { |c| c.type == type.to_sym rescue nil } if type
         
     | 
| 
      
 140 
     | 
    
         
            +
                    column_options_keys.each do |attr|
         
     | 
| 
      
 141 
     | 
    
         
            +
                      checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                    columns(table_name).any? { |c| checks.all? { |check| check[c] } }
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                  # Returns just a table's primary key
         
     | 
| 
      
 148 
     | 
    
         
            +
                  def primary_key(table_name)
         
     | 
| 
      
 149 
     | 
    
         
            +
                    pk = primary_keys(table_name)
         
     | 
| 
      
 150 
     | 
    
         
            +
                    pk = pk.first unless pk.size > 1
         
     | 
| 
      
 151 
     | 
    
         
            +
                    pk
         
     | 
| 
       83 
152 
     | 
    
         
             
                  end
         
     | 
| 
       84 
153 
     | 
    
         | 
| 
       85 
154 
     | 
    
         
             
                  # Creates a new table with the name +table_name+. +table_name+ may either
         
     | 
| 
       86 
155 
     | 
    
         
             
                  # be a String or a Symbol.
         
     | 
| 
       87 
156 
     | 
    
         
             
                  #
         
     | 
| 
       88 
     | 
    
         
            -
                  # There are two ways to work with  
     | 
| 
      
 157 
     | 
    
         
            +
                  # There are two ways to work with #create_table. You can use the block
         
     | 
| 
       89 
158 
     | 
    
         
             
                  # form or the regular form, like this:
         
     | 
| 
       90 
159 
     | 
    
         
             
                  #
         
     | 
| 
       91 
160 
     | 
    
         
             
                  # === Block form
         
     | 
| 
         @@ -117,13 +186,18 @@ module ActiveRecord 
     | 
|
| 
       117 
186 
     | 
    
         
             
                  # The +options+ hash can include the following keys:
         
     | 
| 
       118 
187 
     | 
    
         
             
                  # [<tt>:id</tt>]
         
     | 
| 
       119 
188 
     | 
    
         
             
                  #   Whether to automatically add a primary key column. Defaults to true.
         
     | 
| 
       120 
     | 
    
         
            -
                  #   Join tables for  
     | 
| 
      
 189 
     | 
    
         
            +
                  #   Join tables for {ActiveRecord::Base.has_and_belongs_to_many}[rdoc-ref:Associations::ClassMethods#has_and_belongs_to_many] should set it to false.
         
     | 
| 
      
 190 
     | 
    
         
            +
                  #
         
     | 
| 
      
 191 
     | 
    
         
            +
                  #   A Symbol can be used to specify the type of the generated primary key column.
         
     | 
| 
       121 
192 
     | 
    
         
             
                  # [<tt>:primary_key</tt>]
         
     | 
| 
       122 
193 
     | 
    
         
             
                  #   The name of the primary key, if one is to be added automatically.
         
     | 
| 
       123 
     | 
    
         
            -
                  #   Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
         
     | 
| 
      
 194 
     | 
    
         
            +
                  #   Defaults to +id+. If <tt>:id</tt> is false, then this option is ignored.
         
     | 
| 
      
 195 
     | 
    
         
            +
                  #
         
     | 
| 
      
 196 
     | 
    
         
            +
                  #   If an array is passed, a composite primary key will be created.
         
     | 
| 
       124 
197 
     | 
    
         
             
                  #
         
     | 
| 
       125 
198 
     | 
    
         
             
                  #   Note that Active Record models will automatically detect their
         
     | 
| 
       126 
     | 
    
         
            -
                  #   primary key. This can be avoided by using 
     | 
| 
      
 199 
     | 
    
         
            +
                  #   primary key. This can be avoided by using
         
     | 
| 
      
 200 
     | 
    
         
            +
                  #   {self.primary_key=}[rdoc-ref:AttributeMethods::PrimaryKey::ClassMethods#primary_key=] on the model
         
     | 
| 
       127 
201 
     | 
    
         
             
                  #   to define the key explicitly.
         
     | 
| 
       128 
202 
     | 
    
         
             
                  #
         
     | 
| 
       129 
203 
     | 
    
         
             
                  # [<tt>:options</tt>]
         
     | 
| 
         @@ -134,19 +208,22 @@ module ActiveRecord 
     | 
|
| 
       134 
208 
     | 
    
         
             
                  #   Set to true to drop the table before creating it.
         
     | 
| 
       135 
209 
     | 
    
         
             
                  #   Set to +:cascade+ to drop dependent objects as well.
         
     | 
| 
       136 
210 
     | 
    
         
             
                  #   Defaults to false.
         
     | 
| 
      
 211 
     | 
    
         
            +
                  # [<tt>:if_not_exists</tt>]
         
     | 
| 
      
 212 
     | 
    
         
            +
                  #   Set to true to avoid raising an error when the table already exists.
         
     | 
| 
      
 213 
     | 
    
         
            +
                  #   Defaults to false.
         
     | 
| 
       137 
214 
     | 
    
         
             
                  # [<tt>:as</tt>]
         
     | 
| 
       138 
215 
     | 
    
         
             
                  #   SQL to use to generate the table. When this option is used, the block is
         
     | 
| 
       139 
216 
     | 
    
         
             
                  #   ignored, as are the <tt>:id</tt> and <tt>:primary_key</tt> options.
         
     | 
| 
       140 
217 
     | 
    
         
             
                  #
         
     | 
| 
       141 
218 
     | 
    
         
             
                  # ====== Add a backend specific option to the generated SQL (MySQL)
         
     | 
| 
       142 
219 
     | 
    
         
             
                  #
         
     | 
| 
       143 
     | 
    
         
            -
                  #   create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET= 
     | 
| 
      
 220 
     | 
    
         
            +
                  #   create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4')
         
     | 
| 
       144 
221 
     | 
    
         
             
                  #
         
     | 
| 
       145 
222 
     | 
    
         
             
                  # generates:
         
     | 
| 
       146 
223 
     | 
    
         
             
                  #
         
     | 
| 
       147 
224 
     | 
    
         
             
                  #   CREATE TABLE suppliers (
         
     | 
| 
       148 
     | 
    
         
            -
                  #     id  
     | 
| 
       149 
     | 
    
         
            -
                  #   ) ENGINE=InnoDB DEFAULT CHARSET= 
     | 
| 
      
 225 
     | 
    
         
            +
                  #     id bigint auto_increment PRIMARY KEY
         
     | 
| 
      
 226 
     | 
    
         
            +
                  #   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
         
     | 
| 
       150 
227 
     | 
    
         
             
                  #
         
     | 
| 
       151 
228 
     | 
    
         
             
                  # ====== Rename the primary key column
         
     | 
| 
       152 
229 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -157,22 +234,52 @@ module ActiveRecord 
     | 
|
| 
       157 
234 
     | 
    
         
             
                  # generates:
         
     | 
| 
       158 
235 
     | 
    
         
             
                  #
         
     | 
| 
       159 
236 
     | 
    
         
             
                  #   CREATE TABLE objects (
         
     | 
| 
       160 
     | 
    
         
            -
                  #     guid  
     | 
| 
      
 237 
     | 
    
         
            +
                  #     guid bigint auto_increment PRIMARY KEY,
         
     | 
| 
       161 
238 
     | 
    
         
             
                  #     name varchar(80)
         
     | 
| 
       162 
239 
     | 
    
         
             
                  #   )
         
     | 
| 
       163 
240 
     | 
    
         
             
                  #
         
     | 
| 
      
 241 
     | 
    
         
            +
                  # ====== Change the primary key column type
         
     | 
| 
      
 242 
     | 
    
         
            +
                  #
         
     | 
| 
      
 243 
     | 
    
         
            +
                  #   create_table(:tags, id: :string) do |t|
         
     | 
| 
      
 244 
     | 
    
         
            +
                  #     t.column :label, :string
         
     | 
| 
      
 245 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 246 
     | 
    
         
            +
                  #
         
     | 
| 
      
 247 
     | 
    
         
            +
                  # generates:
         
     | 
| 
      
 248 
     | 
    
         
            +
                  #
         
     | 
| 
      
 249 
     | 
    
         
            +
                  #   CREATE TABLE tags (
         
     | 
| 
      
 250 
     | 
    
         
            +
                  #     id varchar PRIMARY KEY,
         
     | 
| 
      
 251 
     | 
    
         
            +
                  #     label varchar
         
     | 
| 
      
 252 
     | 
    
         
            +
                  #   )
         
     | 
| 
      
 253 
     | 
    
         
            +
                  #
         
     | 
| 
      
 254 
     | 
    
         
            +
                  # ====== Create a composite primary key
         
     | 
| 
      
 255 
     | 
    
         
            +
                  #
         
     | 
| 
      
 256 
     | 
    
         
            +
                  #   create_table(:orders, primary_key: [:product_id, :client_id]) do |t|
         
     | 
| 
      
 257 
     | 
    
         
            +
                  #     t.belongs_to :product
         
     | 
| 
      
 258 
     | 
    
         
            +
                  #     t.belongs_to :client
         
     | 
| 
      
 259 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 260 
     | 
    
         
            +
                  #
         
     | 
| 
      
 261 
     | 
    
         
            +
                  # generates:
         
     | 
| 
      
 262 
     | 
    
         
            +
                  #
         
     | 
| 
      
 263 
     | 
    
         
            +
                  #   CREATE TABLE order (
         
     | 
| 
      
 264 
     | 
    
         
            +
                  #       product_id bigint NOT NULL,
         
     | 
| 
      
 265 
     | 
    
         
            +
                  #       client_id bigint NOT NULL
         
     | 
| 
      
 266 
     | 
    
         
            +
                  #   );
         
     | 
| 
      
 267 
     | 
    
         
            +
                  #
         
     | 
| 
      
 268 
     | 
    
         
            +
                  #   ALTER TABLE ONLY "orders"
         
     | 
| 
      
 269 
     | 
    
         
            +
                  #     ADD CONSTRAINT orders_pkey PRIMARY KEY (product_id, client_id);
         
     | 
| 
      
 270 
     | 
    
         
            +
                  #
         
     | 
| 
       164 
271 
     | 
    
         
             
                  # ====== Do not add a primary key column
         
     | 
| 
       165 
272 
     | 
    
         
             
                  #
         
     | 
| 
       166 
273 
     | 
    
         
             
                  #   create_table(:categories_suppliers, id: false) do |t|
         
     | 
| 
       167 
     | 
    
         
            -
                  #     t.column :category_id, : 
     | 
| 
       168 
     | 
    
         
            -
                  #     t.column :supplier_id, : 
     | 
| 
      
 274 
     | 
    
         
            +
                  #     t.column :category_id, :bigint
         
     | 
| 
      
 275 
     | 
    
         
            +
                  #     t.column :supplier_id, :bigint
         
     | 
| 
       169 
276 
     | 
    
         
             
                  #   end
         
     | 
| 
       170 
277 
     | 
    
         
             
                  #
         
     | 
| 
       171 
278 
     | 
    
         
             
                  # generates:
         
     | 
| 
       172 
279 
     | 
    
         
             
                  #
         
     | 
| 
       173 
280 
     | 
    
         
             
                  #   CREATE TABLE categories_suppliers (
         
     | 
| 
       174 
     | 
    
         
            -
                  #     category_id  
     | 
| 
       175 
     | 
    
         
            -
                  #     supplier_id  
     | 
| 
      
 281 
     | 
    
         
            +
                  #     category_id bigint,
         
     | 
| 
      
 282 
     | 
    
         
            +
                  #     supplier_id bigint
         
     | 
| 
       176 
283 
     | 
    
         
             
                  #   )
         
     | 
| 
       177 
284 
     | 
    
         
             
                  #
         
     | 
| 
       178 
285 
     | 
    
         
             
                  # ====== Create a temporary table based on a query
         
     | 
| 
         @@ -186,25 +293,50 @@ module ActiveRecord 
     | 
|
| 
       186 
293 
     | 
    
         
             
                  #     SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
         
     | 
| 
       187 
294 
     | 
    
         
             
                  #
         
     | 
| 
       188 
295 
     | 
    
         
             
                  # See also TableDefinition#column for details on how to create columns.
         
     | 
| 
       189 
     | 
    
         
            -
                  def create_table(table_name,  
     | 
| 
       190 
     | 
    
         
            -
                    td = create_table_definition 
     | 
| 
      
 296 
     | 
    
         
            +
                  def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
         
     | 
| 
      
 297 
     | 
    
         
            +
                    td = create_table_definition(table_name, **extract_table_options!(options))
         
     | 
| 
       191 
298 
     | 
    
         | 
| 
       192 
     | 
    
         
            -
                    if  
     | 
| 
       193 
     | 
    
         
            -
                      pk =  
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
      
 299 
     | 
    
         
            +
                    if id && !td.as
         
     | 
| 
      
 300 
     | 
    
         
            +
                      pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
                      if id.is_a?(Hash)
         
     | 
| 
      
 303 
     | 
    
         
            +
                        options.merge!(id.except(:type))
         
     | 
| 
      
 304 
     | 
    
         
            +
                        id = id.fetch(:type, :primary_key)
         
     | 
| 
       195 
305 
     | 
    
         
             
                      end
         
     | 
| 
       196 
306 
     | 
    
         | 
| 
       197 
     | 
    
         
            -
                       
     | 
| 
      
 307 
     | 
    
         
            +
                      if pk.is_a?(Array)
         
     | 
| 
      
 308 
     | 
    
         
            +
                        td.primary_keys pk
         
     | 
| 
      
 309 
     | 
    
         
            +
                      else
         
     | 
| 
      
 310 
     | 
    
         
            +
                        td.primary_key pk, id, **options
         
     | 
| 
      
 311 
     | 
    
         
            +
                      end
         
     | 
| 
       198 
312 
     | 
    
         
             
                    end
         
     | 
| 
       199 
313 
     | 
    
         | 
| 
       200 
314 
     | 
    
         
             
                    yield td if block_given?
         
     | 
| 
       201 
315 
     | 
    
         | 
| 
       202 
     | 
    
         
            -
                    if  
     | 
| 
       203 
     | 
    
         
            -
                      drop_table(table_name,  
     | 
| 
      
 316 
     | 
    
         
            +
                    if force
         
     | 
| 
      
 317 
     | 
    
         
            +
                      drop_table(table_name, force: force, if_exists: true)
         
     | 
| 
      
 318 
     | 
    
         
            +
                    else
         
     | 
| 
      
 319 
     | 
    
         
            +
                      schema_cache.clear_data_source_cache!(table_name.to_s)
         
     | 
| 
       204 
320 
     | 
    
         
             
                    end
         
     | 
| 
       205 
321 
     | 
    
         | 
| 
       206 
322 
     | 
    
         
             
                    result = execute schema_creation.accept td
         
     | 
| 
       207 
     | 
    
         
            -
             
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
                    unless supports_indexes_in_create?
         
     | 
| 
      
 325 
     | 
    
         
            +
                      td.indexes.each do |column_name, index_options|
         
     | 
| 
      
 326 
     | 
    
         
            +
                        add_index(table_name, column_name, **index_options, if_not_exists: td.if_not_exists)
         
     | 
| 
      
 327 
     | 
    
         
            +
                      end
         
     | 
| 
      
 328 
     | 
    
         
            +
                    end
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
                    if supports_comments? && !supports_comments_in_create?
         
     | 
| 
      
 331 
     | 
    
         
            +
                      if table_comment = td.comment.presence
         
     | 
| 
      
 332 
     | 
    
         
            +
                        change_table_comment(table_name, table_comment)
         
     | 
| 
      
 333 
     | 
    
         
            +
                      end
         
     | 
| 
      
 334 
     | 
    
         
            +
             
     | 
| 
      
 335 
     | 
    
         
            +
                      td.columns.each do |column|
         
     | 
| 
      
 336 
     | 
    
         
            +
                        change_column_comment(table_name, column.name, column.comment) if column.comment.present?
         
     | 
| 
      
 337 
     | 
    
         
            +
                      end
         
     | 
| 
      
 338 
     | 
    
         
            +
                    end
         
     | 
| 
      
 339 
     | 
    
         
            +
             
     | 
| 
       208 
340 
     | 
    
         
             
                    result
         
     | 
| 
       209 
341 
     | 
    
         
             
                  end
         
     | 
| 
       210 
342 
     | 
    
         | 
| 
         @@ -214,9 +346,9 @@ module ActiveRecord 
     | 
|
| 
       214 
346 
     | 
    
         
             
                  #   # Creates a table called 'assemblies_parts' with no id.
         
     | 
| 
       215 
347 
     | 
    
         
             
                  #   create_join_table(:assemblies, :parts)
         
     | 
| 
       216 
348 
     | 
    
         
             
                  #
         
     | 
| 
       217 
     | 
    
         
            -
                  # You can pass  
     | 
| 
      
 349 
     | 
    
         
            +
                  # You can pass an +options+ hash which can include the following keys:
         
     | 
| 
       218 
350 
     | 
    
         
             
                  # [<tt>:table_name</tt>]
         
     | 
| 
       219 
     | 
    
         
            -
                  #   Sets the table name overriding the default
         
     | 
| 
      
 351 
     | 
    
         
            +
                  #   Sets the table name, overriding the default.
         
     | 
| 
       220 
352 
     | 
    
         
             
                  # [<tt>:column_options</tt>]
         
     | 
| 
       221 
353 
     | 
    
         
             
                  #   Any extra options you want appended to the columns definition.
         
     | 
| 
       222 
354 
     | 
    
         
             
                  # [<tt>:options</tt>]
         
     | 
| 
         @@ -227,7 +359,7 @@ module ActiveRecord 
     | 
|
| 
       227 
359 
     | 
    
         
             
                  #   Set to true to drop the table before creating it.
         
     | 
| 
       228 
360 
     | 
    
         
             
                  #   Defaults to false.
         
     | 
| 
       229 
361 
     | 
    
         
             
                  #
         
     | 
| 
       230 
     | 
    
         
            -
                  # Note that  
     | 
| 
      
 362 
     | 
    
         
            +
                  # Note that #create_join_table does not create any indices by default; you can use
         
     | 
| 
       231 
363 
     | 
    
         
             
                  # its block form to do so yourself:
         
     | 
| 
       232 
364 
     | 
    
         
             
                  #
         
     | 
| 
       233 
365 
     | 
    
         
             
                  #   create_join_table :products, :categories do |t|
         
     | 
| 
         @@ -242,32 +374,31 @@ module ActiveRecord 
     | 
|
| 
       242 
374 
     | 
    
         
             
                  # generates:
         
     | 
| 
       243 
375 
     | 
    
         
             
                  #
         
     | 
| 
       244 
376 
     | 
    
         
             
                  #   CREATE TABLE assemblies_parts (
         
     | 
| 
       245 
     | 
    
         
            -
                  #     assembly_id  
     | 
| 
       246 
     | 
    
         
            -
                  #     part_id  
     | 
| 
      
 377 
     | 
    
         
            +
                  #     assembly_id bigint NOT NULL,
         
     | 
| 
      
 378 
     | 
    
         
            +
                  #     part_id bigint NOT NULL,
         
     | 
| 
       247 
379 
     | 
    
         
             
                  #   ) ENGINE=InnoDB DEFAULT CHARSET=utf8
         
     | 
| 
       248 
380 
     | 
    
         
             
                  #
         
     | 
| 
       249 
     | 
    
         
            -
                  def create_join_table(table_1, table_2,  
     | 
| 
      
 381 
     | 
    
         
            +
                  def create_join_table(table_1, table_2, column_options: {}, **options)
         
     | 
| 
       250 
382 
     | 
    
         
             
                    join_table_name = find_join_table_name(table_1, table_2, options)
         
     | 
| 
       251 
383 
     | 
    
         | 
| 
       252 
     | 
    
         
            -
                    column_options 
     | 
| 
       253 
     | 
    
         
            -
                    column_options.reverse_merge!(null: false)
         
     | 
| 
      
 384 
     | 
    
         
            +
                    column_options.reverse_merge!(null: false, index: false)
         
     | 
| 
       254 
385 
     | 
    
         | 
| 
       255 
     | 
    
         
            -
                     
     | 
| 
      
 386 
     | 
    
         
            +
                    t1_ref, t2_ref = [table_1, table_2].map { |t| t.to_s.singularize }
         
     | 
| 
       256 
387 
     | 
    
         | 
| 
       257 
     | 
    
         
            -
                    create_table(join_table_name, options.merge!(id: false)) do |td|
         
     | 
| 
       258 
     | 
    
         
            -
                      td. 
     | 
| 
       259 
     | 
    
         
            -
                      td. 
     | 
| 
      
 388 
     | 
    
         
            +
                    create_table(join_table_name, **options.merge!(id: false)) do |td|
         
     | 
| 
      
 389 
     | 
    
         
            +
                      td.references t1_ref, **column_options
         
     | 
| 
      
 390 
     | 
    
         
            +
                      td.references t2_ref, **column_options
         
     | 
| 
       260 
391 
     | 
    
         
             
                      yield td if block_given?
         
     | 
| 
       261 
392 
     | 
    
         
             
                    end
         
     | 
| 
       262 
393 
     | 
    
         
             
                  end
         
     | 
| 
       263 
394 
     | 
    
         | 
| 
       264 
395 
     | 
    
         
             
                  # Drops the join table specified by the given arguments.
         
     | 
| 
       265 
     | 
    
         
            -
                  # See  
     | 
| 
      
 396 
     | 
    
         
            +
                  # See #create_join_table for details.
         
     | 
| 
       266 
397 
     | 
    
         
             
                  #
         
     | 
| 
       267 
398 
     | 
    
         
             
                  # Although this command ignores the block if one is given, it can be helpful
         
     | 
| 
       268 
399 
     | 
    
         
             
                  # to provide one in a migration's +change+ method so it can be reverted.
         
     | 
| 
       269 
     | 
    
         
            -
                  # In that case, the block will be used by create_join_table.
         
     | 
| 
       270 
     | 
    
         
            -
                  def drop_join_table(table_1, table_2, options 
     | 
| 
      
 400 
     | 
    
         
            +
                  # In that case, the block will be used by #create_join_table.
         
     | 
| 
      
 401 
     | 
    
         
            +
                  def drop_join_table(table_1, table_2, **options)
         
     | 
| 
       271 
402 
     | 
    
         
             
                    join_table_name = find_join_table_name(table_1, table_2, options)
         
     | 
| 
       272 
403 
     | 
    
         
             
                    drop_table(join_table_name)
         
     | 
| 
       273 
404 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -284,16 +415,24 @@ module ActiveRecord 
     | 
|
| 
       284 
415 
     | 
    
         
             
                  # [<tt>:bulk</tt>]
         
     | 
| 
       285 
416 
     | 
    
         
             
                  #   Set this to true to make this a bulk alter query, such as
         
     | 
| 
       286 
417 
     | 
    
         
             
                  #
         
     | 
| 
       287 
     | 
    
         
            -
                  #     ALTER TABLE `users` ADD COLUMN age INT 
     | 
| 
      
 418 
     | 
    
         
            +
                  #     ALTER TABLE `users` ADD COLUMN age INT, ADD COLUMN birthdate DATETIME ...
         
     | 
| 
       288 
419 
     | 
    
         
             
                  #
         
     | 
| 
       289 
420 
     | 
    
         
             
                  #   Defaults to false.
         
     | 
| 
       290 
421 
     | 
    
         
             
                  #
         
     | 
| 
      
 422 
     | 
    
         
            +
                  #   Only supported on the MySQL and PostgreSQL adapter, ignored elsewhere.
         
     | 
| 
      
 423 
     | 
    
         
            +
                  #
         
     | 
| 
       291 
424 
     | 
    
         
             
                  # ====== Add a column
         
     | 
| 
       292 
425 
     | 
    
         
             
                  #
         
     | 
| 
       293 
426 
     | 
    
         
             
                  #   change_table(:suppliers) do |t|
         
     | 
| 
       294 
427 
     | 
    
         
             
                  #     t.column :name, :string, limit: 60
         
     | 
| 
       295 
428 
     | 
    
         
             
                  #   end
         
     | 
| 
       296 
429 
     | 
    
         
             
                  #
         
     | 
| 
      
 430 
     | 
    
         
            +
                  # ====== Change type of a column
         
     | 
| 
      
 431 
     | 
    
         
            +
                  #
         
     | 
| 
      
 432 
     | 
    
         
            +
                  #   change_table(:suppliers) do |t|
         
     | 
| 
      
 433 
     | 
    
         
            +
                  #     t.change :metadata, :json
         
     | 
| 
      
 434 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 435 
     | 
    
         
            +
                  #
         
     | 
| 
       297 
436 
     | 
    
         
             
                  # ====== Add 2 integer columns
         
     | 
| 
       298 
437 
     | 
    
         
             
                  #
         
     | 
| 
       299 
438 
     | 
    
         
             
                  #   change_table(:suppliers) do |t|
         
     | 
| 
         @@ -312,7 +451,7 @@ module ActiveRecord 
     | 
|
| 
       312 
451 
     | 
    
         
             
                  #     t.references :company
         
     | 
| 
       313 
452 
     | 
    
         
             
                  #   end
         
     | 
| 
       314 
453 
     | 
    
         
             
                  #
         
     | 
| 
       315 
     | 
    
         
            -
                  # Creates a <tt>company_id( 
     | 
| 
      
 454 
     | 
    
         
            +
                  # Creates a <tt>company_id(bigint)</tt> column.
         
     | 
| 
       316 
455 
     | 
    
         
             
                  #
         
     | 
| 
       317 
456 
     | 
    
         
             
                  # ====== Add a polymorphic foreign key column
         
     | 
| 
       318 
457 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -320,7 +459,7 @@ module ActiveRecord 
     | 
|
| 
       320 
459 
     | 
    
         
             
                  #    t.belongs_to :company, polymorphic: true
         
     | 
| 
       321 
460 
     | 
    
         
             
                  #  end
         
     | 
| 
       322 
461 
     | 
    
         
             
                  #
         
     | 
| 
       323 
     | 
    
         
            -
                  # Creates <tt>company_type(varchar)</tt> and <tt>company_id( 
     | 
| 
      
 462 
     | 
    
         
            +
                  # Creates <tt>company_type(varchar)</tt> and <tt>company_id(bigint)</tt> columns.
         
     | 
| 
       324 
463 
     | 
    
         
             
                  #
         
     | 
| 
       325 
464 
     | 
    
         
             
                  # ====== Remove a column
         
     | 
| 
       326 
465 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -341,8 +480,8 @@ module ActiveRecord 
     | 
|
| 
       341 
480 
     | 
    
         
             
                  #    t.remove_index :company_id
         
     | 
| 
       342 
481 
     | 
    
         
             
                  #  end
         
     | 
| 
       343 
482 
     | 
    
         
             
                  #
         
     | 
| 
       344 
     | 
    
         
            -
                  # See also Table for details on all of the various column  
     | 
| 
       345 
     | 
    
         
            -
                  def change_table(table_name, options 
     | 
| 
      
 483 
     | 
    
         
            +
                  # See also Table for details on all of the various column transformations.
         
     | 
| 
      
 484 
     | 
    
         
            +
                  def change_table(table_name, **options)
         
     | 
| 
       346 
485 
     | 
    
         
             
                    if supports_bulk_alter? && options[:bulk]
         
     | 
| 
       347 
486 
     | 
    
         
             
                      recorder = ActiveRecord::Migration::CommandRecorder.new(self)
         
     | 
| 
       348 
487 
     | 
    
         
             
                      yield update_table_definition(table_name, recorder)
         
     | 
| 
         @@ -365,30 +504,133 @@ module ActiveRecord 
     | 
|
| 
       365 
504 
     | 
    
         
             
                  # [<tt>:force</tt>]
         
     | 
| 
       366 
505 
     | 
    
         
             
                  #   Set to +:cascade+ to drop dependent objects as well.
         
     | 
| 
       367 
506 
     | 
    
         
             
                  #   Defaults to false.
         
     | 
| 
      
 507 
     | 
    
         
            +
                  # [<tt>:if_exists</tt>]
         
     | 
| 
      
 508 
     | 
    
         
            +
                  #   Set to +true+ to only drop the table if it exists.
         
     | 
| 
      
 509 
     | 
    
         
            +
                  #   Defaults to false.
         
     | 
| 
       368 
510 
     | 
    
         
             
                  #
         
     | 
| 
       369 
511 
     | 
    
         
             
                  # Although this command ignores most +options+ and the block if one is given,
         
     | 
| 
       370 
512 
     | 
    
         
             
                  # it can be helpful to provide these in a migration's +change+ method so it can be reverted.
         
     | 
| 
       371 
     | 
    
         
            -
                  # In that case, +options+ and the block will be used by create_table.
         
     | 
| 
       372 
     | 
    
         
            -
                  def drop_table(table_name, options 
     | 
| 
       373 
     | 
    
         
            -
                     
     | 
| 
      
 513 
     | 
    
         
            +
                  # In that case, +options+ and the block will be used by #create_table.
         
     | 
| 
      
 514 
     | 
    
         
            +
                  def drop_table(table_name, **options)
         
     | 
| 
      
 515 
     | 
    
         
            +
                    schema_cache.clear_data_source_cache!(table_name.to_s)
         
     | 
| 
      
 516 
     | 
    
         
            +
                    execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
         
     | 
| 
       374 
517 
     | 
    
         
             
                  end
         
     | 
| 
       375 
518 
     | 
    
         | 
| 
       376 
     | 
    
         
            -
                  #  
     | 
| 
       377 
     | 
    
         
            -
                  # 
     | 
| 
       378 
     | 
    
         
            -
                   
     | 
| 
      
 519 
     | 
    
         
            +
                  # Add a new +type+ column named +column_name+ to +table_name+.
         
     | 
| 
      
 520 
     | 
    
         
            +
                  #
         
     | 
| 
      
 521 
     | 
    
         
            +
                  # The +type+ parameter is normally one of the migrations native types,
         
     | 
| 
      
 522 
     | 
    
         
            +
                  # which is one of the following:
         
     | 
| 
      
 523 
     | 
    
         
            +
                  # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
         
     | 
| 
      
 524 
     | 
    
         
            +
                  # <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
         
     | 
| 
      
 525 
     | 
    
         
            +
                  # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
         
     | 
| 
      
 526 
     | 
    
         
            +
                  # <tt>:binary</tt>, <tt>:boolean</tt>.
         
     | 
| 
      
 527 
     | 
    
         
            +
                  #
         
     | 
| 
      
 528 
     | 
    
         
            +
                  # You may use a type not in this list as long as it is supported by your
         
     | 
| 
      
 529 
     | 
    
         
            +
                  # database (for example, "polygon" in MySQL), but this will not be database
         
     | 
| 
      
 530 
     | 
    
         
            +
                  # agnostic and should usually be avoided.
         
     | 
| 
      
 531 
     | 
    
         
            +
                  #
         
     | 
| 
      
 532 
     | 
    
         
            +
                  # Available options are (none of these exists by default):
         
     | 
| 
      
 533 
     | 
    
         
            +
                  # * <tt>:limit</tt> -
         
     | 
| 
      
 534 
     | 
    
         
            +
                  #   Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
         
     | 
| 
      
 535 
     | 
    
         
            +
                  #   and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
         
     | 
| 
      
 536 
     | 
    
         
            +
                  #   This option is ignored by some backends.
         
     | 
| 
      
 537 
     | 
    
         
            +
                  # * <tt>:default</tt> -
         
     | 
| 
      
 538 
     | 
    
         
            +
                  #   The column's default value. Use +nil+ for +NULL+.
         
     | 
| 
      
 539 
     | 
    
         
            +
                  # * <tt>:null</tt> -
         
     | 
| 
      
 540 
     | 
    
         
            +
                  #   Allows or disallows +NULL+ values in the column.
         
     | 
| 
      
 541 
     | 
    
         
            +
                  # * <tt>:precision</tt> -
         
     | 
| 
      
 542 
     | 
    
         
            +
                  #   Specifies the precision for the <tt>:decimal</tt>, <tt>:numeric</tt>,
         
     | 
| 
      
 543 
     | 
    
         
            +
                  #   <tt>:datetime</tt>, and <tt>:time</tt> columns.
         
     | 
| 
      
 544 
     | 
    
         
            +
                  # * <tt>:scale</tt> -
         
     | 
| 
      
 545 
     | 
    
         
            +
                  #   Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
         
     | 
| 
      
 546 
     | 
    
         
            +
                  # * <tt>:collation</tt> -
         
     | 
| 
      
 547 
     | 
    
         
            +
                  #   Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column. If not specified, the
         
     | 
| 
      
 548 
     | 
    
         
            +
                  #   column will have the same collation as the table.
         
     | 
| 
      
 549 
     | 
    
         
            +
                  # * <tt>:comment</tt> -
         
     | 
| 
      
 550 
     | 
    
         
            +
                  #   Specifies the comment for the column. This option is ignored by some backends.
         
     | 
| 
      
 551 
     | 
    
         
            +
                  # * <tt>:if_not_exists</tt> -
         
     | 
| 
      
 552 
     | 
    
         
            +
                  #   Specifies if the column already exists to not try to re-add it. This will avoid
         
     | 
| 
      
 553 
     | 
    
         
            +
                  #   duplicate column errors.
         
     | 
| 
      
 554 
     | 
    
         
            +
                  #
         
     | 
| 
      
 555 
     | 
    
         
            +
                  # Note: The precision is the total number of significant digits,
         
     | 
| 
      
 556 
     | 
    
         
            +
                  # and the scale is the number of digits that can be stored following
         
     | 
| 
      
 557 
     | 
    
         
            +
                  # the decimal point. For example, the number 123.45 has a precision of 5
         
     | 
| 
      
 558 
     | 
    
         
            +
                  # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
         
     | 
| 
      
 559 
     | 
    
         
            +
                  # range from -999.99 to 999.99.
         
     | 
| 
      
 560 
     | 
    
         
            +
                  #
         
     | 
| 
      
 561 
     | 
    
         
            +
                  # Please be aware of different RDBMS implementations behavior with
         
     | 
| 
      
 562 
     | 
    
         
            +
                  # <tt>:decimal</tt> columns:
         
     | 
| 
      
 563 
     | 
    
         
            +
                  # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
         
     | 
| 
      
 564 
     | 
    
         
            +
                  #   <tt>:precision</tt>, and makes no comments about the requirements of
         
     | 
| 
      
 565 
     | 
    
         
            +
                  #   <tt>:precision</tt>.
         
     | 
| 
      
 566 
     | 
    
         
            +
                  # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
         
     | 
| 
      
 567 
     | 
    
         
            +
                  #   Default is (10,0).
         
     | 
| 
      
 568 
     | 
    
         
            +
                  # * PostgreSQL: <tt>:precision</tt> [1..infinity],
         
     | 
| 
      
 569 
     | 
    
         
            +
                  #   <tt>:scale</tt> [0..infinity]. No default.
         
     | 
| 
      
 570 
     | 
    
         
            +
                  # * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
         
     | 
| 
      
 571 
     | 
    
         
            +
                  #   but the maximum supported <tt>:precision</tt> is 16. No default.
         
     | 
| 
      
 572 
     | 
    
         
            +
                  # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
         
     | 
| 
      
 573 
     | 
    
         
            +
                  #   Default is (38,0).
         
     | 
| 
      
 574 
     | 
    
         
            +
                  # * SqlServer: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
         
     | 
| 
      
 575 
     | 
    
         
            +
                  #   Default (38,0).
         
     | 
| 
      
 576 
     | 
    
         
            +
                  #
         
     | 
| 
      
 577 
     | 
    
         
            +
                  # == Examples
         
     | 
| 
      
 578 
     | 
    
         
            +
                  #
         
     | 
| 
      
 579 
     | 
    
         
            +
                  #  add_column(:users, :picture, :binary, limit: 2.megabytes)
         
     | 
| 
      
 580 
     | 
    
         
            +
                  #  # ALTER TABLE "users" ADD "picture" blob(2097152)
         
     | 
| 
      
 581 
     | 
    
         
            +
                  #
         
     | 
| 
      
 582 
     | 
    
         
            +
                  #  add_column(:articles, :status, :string, limit: 20, default: 'draft', null: false)
         
     | 
| 
      
 583 
     | 
    
         
            +
                  #  # ALTER TABLE "articles" ADD "status" varchar(20) DEFAULT 'draft' NOT NULL
         
     | 
| 
      
 584 
     | 
    
         
            +
                  #
         
     | 
| 
      
 585 
     | 
    
         
            +
                  #  add_column(:answers, :bill_gates_money, :decimal, precision: 15, scale: 2)
         
     | 
| 
      
 586 
     | 
    
         
            +
                  #  # ALTER TABLE "answers" ADD "bill_gates_money" decimal(15,2)
         
     | 
| 
      
 587 
     | 
    
         
            +
                  #
         
     | 
| 
      
 588 
     | 
    
         
            +
                  #  add_column(:measurements, :sensor_reading, :decimal, precision: 30, scale: 20)
         
     | 
| 
      
 589 
     | 
    
         
            +
                  #  # ALTER TABLE "measurements" ADD "sensor_reading" decimal(30,20)
         
     | 
| 
      
 590 
     | 
    
         
            +
                  #
         
     | 
| 
      
 591 
     | 
    
         
            +
                  #  # While :scale defaults to zero on most databases, it
         
     | 
| 
      
 592 
     | 
    
         
            +
                  #  # probably wouldn't hurt to include it.
         
     | 
| 
      
 593 
     | 
    
         
            +
                  #  add_column(:measurements, :huge_integer, :decimal, precision: 30)
         
     | 
| 
      
 594 
     | 
    
         
            +
                  #  # ALTER TABLE "measurements" ADD "huge_integer" decimal(30)
         
     | 
| 
      
 595 
     | 
    
         
            +
                  #
         
     | 
| 
      
 596 
     | 
    
         
            +
                  #  # Defines a column that stores an array of a type.
         
     | 
| 
      
 597 
     | 
    
         
            +
                  #  add_column(:users, :skills, :text, array: true)
         
     | 
| 
      
 598 
     | 
    
         
            +
                  #  # ALTER TABLE "users" ADD "skills" text[]
         
     | 
| 
      
 599 
     | 
    
         
            +
                  #
         
     | 
| 
      
 600 
     | 
    
         
            +
                  #  # Defines a column with a database-specific type.
         
     | 
| 
      
 601 
     | 
    
         
            +
                  #  add_column(:shapes, :triangle, 'polygon')
         
     | 
| 
      
 602 
     | 
    
         
            +
                  #  # ALTER TABLE "shapes" ADD "triangle" polygon
         
     | 
| 
      
 603 
     | 
    
         
            +
                  #
         
     | 
| 
      
 604 
     | 
    
         
            +
                  #  # Ignores the method call if the column exists
         
     | 
| 
      
 605 
     | 
    
         
            +
                  #  add_column(:shapes, :triangle, 'polygon', if_not_exists: true)
         
     | 
| 
      
 606 
     | 
    
         
            +
                  def add_column(table_name, column_name, type, **options)
         
     | 
| 
      
 607 
     | 
    
         
            +
                    return if options[:if_not_exists] == true && column_exists?(table_name, column_name, type)
         
     | 
| 
      
 608 
     | 
    
         
            +
             
     | 
| 
       379 
609 
     | 
    
         
             
                    at = create_alter_table table_name
         
     | 
| 
       380 
     | 
    
         
            -
                    at.add_column(column_name, type, options)
         
     | 
| 
      
 610 
     | 
    
         
            +
                    at.add_column(column_name, type, **options)
         
     | 
| 
       381 
611 
     | 
    
         
             
                    execute schema_creation.accept at
         
     | 
| 
       382 
612 
     | 
    
         
             
                  end
         
     | 
| 
       383 
613 
     | 
    
         | 
| 
      
 614 
     | 
    
         
            +
                  def add_columns(table_name, *column_names, type:, **options) # :nodoc:
         
     | 
| 
      
 615 
     | 
    
         
            +
                    column_names.each do |column_name|
         
     | 
| 
      
 616 
     | 
    
         
            +
                      add_column(table_name, column_name, type, **options)
         
     | 
| 
      
 617 
     | 
    
         
            +
                    end
         
     | 
| 
      
 618 
     | 
    
         
            +
                  end
         
     | 
| 
      
 619 
     | 
    
         
            +
             
     | 
| 
       384 
620 
     | 
    
         
             
                  # Removes the given columns from the table definition.
         
     | 
| 
       385 
621 
     | 
    
         
             
                  #
         
     | 
| 
       386 
622 
     | 
    
         
             
                  #   remove_columns(:suppliers, :qualification, :experience)
         
     | 
| 
       387 
623 
     | 
    
         
             
                  #
         
     | 
| 
       388 
     | 
    
         
            -
                   
     | 
| 
       389 
     | 
    
         
            -
             
     | 
| 
      
 624 
     | 
    
         
            +
                  # +type+ and other column options can be passed to make migration reversible.
         
     | 
| 
      
 625 
     | 
    
         
            +
                  #
         
     | 
| 
      
 626 
     | 
    
         
            +
                  #    remove_columns(:suppliers, :qualification, :experience, type: :string, null: false)
         
     | 
| 
      
 627 
     | 
    
         
            +
                  def remove_columns(table_name, *column_names, type: nil, **options)
         
     | 
| 
      
 628 
     | 
    
         
            +
                    if column_names.empty?
         
     | 
| 
      
 629 
     | 
    
         
            +
                      raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
         
     | 
| 
      
 630 
     | 
    
         
            +
                    end
         
     | 
| 
      
 631 
     | 
    
         
            +
             
     | 
| 
       390 
632 
     | 
    
         
             
                    column_names.each do |column_name|
         
     | 
| 
       391 
     | 
    
         
            -
                      remove_column(table_name, column_name)
         
     | 
| 
      
 633 
     | 
    
         
            +
                      remove_column(table_name, column_name, type, **options)
         
     | 
| 
       392 
634 
     | 
    
         
             
                    end
         
     | 
| 
       393 
635 
     | 
    
         
             
                  end
         
     | 
| 
       394 
636 
     | 
    
         | 
| 
         @@ -398,9 +640,18 @@ module ActiveRecord 
     | 
|
| 
       398 
640 
     | 
    
         
             
                  #
         
     | 
| 
       399 
641 
     | 
    
         
             
                  # The +type+ and +options+ parameters will be ignored if present. It can be helpful
         
     | 
| 
       400 
642 
     | 
    
         
             
                  # to provide these in a migration's +change+ method so it can be reverted.
         
     | 
| 
       401 
     | 
    
         
            -
                  # In that case, +type+ and +options+ will be used by add_column.
         
     | 
| 
       402 
     | 
    
         
            -
                   
     | 
| 
       403 
     | 
    
         
            -
             
     | 
| 
      
 643 
     | 
    
         
            +
                  # In that case, +type+ and +options+ will be used by #add_column.
         
     | 
| 
      
 644 
     | 
    
         
            +
                  # Indexes on the column are automatically removed.
         
     | 
| 
      
 645 
     | 
    
         
            +
                  #
         
     | 
| 
      
 646 
     | 
    
         
            +
                  # If the options provided include an +if_exists+ key, it will be used to check if the
         
     | 
| 
      
 647 
     | 
    
         
            +
                  # column does not exist. This will silently ignore the migration rather than raising
         
     | 
| 
      
 648 
     | 
    
         
            +
                  # if the column was already used.
         
     | 
| 
      
 649 
     | 
    
         
            +
                  #
         
     | 
| 
      
 650 
     | 
    
         
            +
                  #   remove_column(:suppliers, :qualification, if_exists: true)
         
     | 
| 
      
 651 
     | 
    
         
            +
                  def remove_column(table_name, column_name, type = nil, **options)
         
     | 
| 
      
 652 
     | 
    
         
            +
                    return if options[:if_exists] == true && !column_exists?(table_name, column_name)
         
     | 
| 
      
 653 
     | 
    
         
            +
             
     | 
| 
      
 654 
     | 
    
         
            +
                    execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_for_alter(table_name, column_name, type, **options)}"
         
     | 
| 
       404 
655 
     | 
    
         
             
                  end
         
     | 
| 
       405 
656 
     | 
    
         | 
| 
       406 
657 
     | 
    
         
             
                  # Changes the column's definition according to the new options.
         
     | 
| 
         @@ -409,7 +660,7 @@ module ActiveRecord 
     | 
|
| 
       409 
660 
     | 
    
         
             
                  #   change_column(:suppliers, :name, :string, limit: 80)
         
     | 
| 
       410 
661 
     | 
    
         
             
                  #   change_column(:accounts, :description, :text)
         
     | 
| 
       411 
662 
     | 
    
         
             
                  #
         
     | 
| 
       412 
     | 
    
         
            -
                  def change_column(table_name, column_name, type, options 
     | 
| 
      
 663 
     | 
    
         
            +
                  def change_column(table_name, column_name, type, **options)
         
     | 
| 
       413 
664 
     | 
    
         
             
                    raise NotImplementedError, "change_column is not implemented"
         
     | 
| 
       414 
665 
     | 
    
         
             
                  end
         
     | 
| 
       415 
666 
     | 
    
         | 
| 
         @@ -422,11 +673,16 @@ module ActiveRecord 
     | 
|
| 
       422 
673 
     | 
    
         
             
                  #
         
     | 
| 
       423 
674 
     | 
    
         
             
                  #   change_column_default(:users, :email, nil)
         
     | 
| 
       424 
675 
     | 
    
         
             
                  #
         
     | 
| 
       425 
     | 
    
         
            -
                   
     | 
| 
      
 676 
     | 
    
         
            +
                  # Passing a hash containing +:from+ and +:to+ will make this change
         
     | 
| 
      
 677 
     | 
    
         
            +
                  # reversible in migration:
         
     | 
| 
      
 678 
     | 
    
         
            +
                  #
         
     | 
| 
      
 679 
     | 
    
         
            +
                  #   change_column_default(:posts, :state, from: nil, to: "draft")
         
     | 
| 
      
 680 
     | 
    
         
            +
                  #
         
     | 
| 
      
 681 
     | 
    
         
            +
                  def change_column_default(table_name, column_name, default_or_changes)
         
     | 
| 
       426 
682 
     | 
    
         
             
                    raise NotImplementedError, "change_column_default is not implemented"
         
     | 
| 
       427 
683 
     | 
    
         
             
                  end
         
     | 
| 
       428 
684 
     | 
    
         | 
| 
       429 
     | 
    
         
            -
                  # Sets or removes a  
     | 
| 
      
 685 
     | 
    
         
            +
                  # Sets or removes a <tt>NOT NULL</tt> constraint on a column. The +null+ flag
         
     | 
| 
       430 
686 
     | 
    
         
             
                  # indicates whether the value can be +NULL+. For example
         
     | 
| 
       431 
687 
     | 
    
         
             
                  #
         
     | 
| 
       432 
688 
     | 
    
         
             
                  #   change_column_null(:users, :nickname, false)
         
     | 
| 
         @@ -438,7 +694,7 @@ module ActiveRecord 
     | 
|
| 
       438 
694 
     | 
    
         
             
                  # allows them to be +NULL+ (drops the constraint).
         
     | 
| 
       439 
695 
     | 
    
         
             
                  #
         
     | 
| 
       440 
696 
     | 
    
         
             
                  # The method accepts an optional fourth argument to replace existing
         
     | 
| 
       441 
     | 
    
         
            -
                  #  
     | 
| 
      
 697 
     | 
    
         
            +
                  # <tt>NULL</tt>s with some other value. Use that one when enabling the
         
     | 
| 
       442 
698 
     | 
    
         
             
                  # constraint if needed, since otherwise those rows would not be valid.
         
     | 
| 
       443 
699 
     | 
    
         
             
                  #
         
     | 
| 
       444 
700 
     | 
    
         
             
                  # Please note the fourth argument does not set a column's default.
         
     | 
| 
         @@ -466,7 +722,17 @@ module ActiveRecord 
     | 
|
| 
       466 
722 
     | 
    
         
             
                  #
         
     | 
| 
       467 
723 
     | 
    
         
             
                  # generates:
         
     | 
| 
       468 
724 
     | 
    
         
             
                  #
         
     | 
| 
       469 
     | 
    
         
            -
                  #   CREATE INDEX  
     | 
| 
      
 725 
     | 
    
         
            +
                  #   CREATE INDEX index_suppliers_on_name ON suppliers(name)
         
     | 
| 
      
 726 
     | 
    
         
            +
                  #
         
     | 
| 
      
 727 
     | 
    
         
            +
                  # ====== Creating a index which already exists
         
     | 
| 
      
 728 
     | 
    
         
            +
                  #
         
     | 
| 
      
 729 
     | 
    
         
            +
                  #   add_index(:suppliers, :name, if_not_exists: true)
         
     | 
| 
      
 730 
     | 
    
         
            +
                  #
         
     | 
| 
      
 731 
     | 
    
         
            +
                  # generates:
         
     | 
| 
      
 732 
     | 
    
         
            +
                  #
         
     | 
| 
      
 733 
     | 
    
         
            +
                  #   CREATE INDEX IF NOT EXISTS index_suppliers_on_name ON suppliers(name)
         
     | 
| 
      
 734 
     | 
    
         
            +
                  #
         
     | 
| 
      
 735 
     | 
    
         
            +
                  # Note: Not supported by MySQL.
         
     | 
| 
       470 
736 
     | 
    
         
             
                  #
         
     | 
| 
       471 
737 
     | 
    
         
             
                  # ====== Creating a unique index
         
     | 
| 
       472 
738 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -474,7 +740,7 @@ module ActiveRecord 
     | 
|
| 
       474 
740 
     | 
    
         
             
                  #
         
     | 
| 
       475 
741 
     | 
    
         
             
                  # generates:
         
     | 
| 
       476 
742 
     | 
    
         
             
                  #
         
     | 
| 
       477 
     | 
    
         
            -
                  #   CREATE UNIQUE INDEX  
     | 
| 
      
 743 
     | 
    
         
            +
                  #   CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id)
         
     | 
| 
       478 
744 
     | 
    
         
             
                  #
         
     | 
| 
       479 
745 
     | 
    
         
             
                  # ====== Creating a named index
         
     | 
| 
       480 
746 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -492,6 +758,8 @@ module ActiveRecord 
     | 
|
| 
       492 
758 
     | 
    
         
             
                  #
         
     | 
| 
       493 
759 
     | 
    
         
             
                  #   CREATE INDEX by_name ON accounts(name(10))
         
     | 
| 
       494 
760 
     | 
    
         
             
                  #
         
     | 
| 
      
 761 
     | 
    
         
            +
                  # ====== Creating an index with specific key lengths for multiple keys
         
     | 
| 
      
 762 
     | 
    
         
            +
                  #
         
     | 
| 
       495 
763 
     | 
    
         
             
                  #   add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
         
     | 
| 
       496 
764 
     | 
    
         
             
                  #
         
     | 
| 
       497 
765 
     | 
    
         
             
                  # generates:
         
     | 
| 
         @@ -502,13 +770,13 @@ module ActiveRecord 
     | 
|
| 
       502 
770 
     | 
    
         
             
                  #
         
     | 
| 
       503 
771 
     | 
    
         
             
                  # ====== Creating an index with a sort order (desc or asc, asc is the default)
         
     | 
| 
       504 
772 
     | 
    
         
             
                  #
         
     | 
| 
       505 
     | 
    
         
            -
                  #   add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})
         
     | 
| 
      
 773 
     | 
    
         
            +
                  #   add_index(:accounts, [:branch_id, :party_id, :surname], name: 'by_branch_desc_party', order: {branch_id: :desc, party_id: :asc})
         
     | 
| 
       506 
774 
     | 
    
         
             
                  #
         
     | 
| 
       507 
775 
     | 
    
         
             
                  # generates:
         
     | 
| 
       508 
776 
     | 
    
         
             
                  #
         
     | 
| 
       509 
777 
     | 
    
         
             
                  #   CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
         
     | 
| 
       510 
778 
     | 
    
         
             
                  #
         
     | 
| 
       511 
     | 
    
         
            -
                  # Note: MySQL  
     | 
| 
      
 779 
     | 
    
         
            +
                  # Note: MySQL only supports index order from 8.0.1 onwards (earlier versions accepted the syntax but ignored it).
         
     | 
| 
       512 
780 
     | 
    
         
             
                  #
         
     | 
| 
       513 
781 
     | 
    
         
             
                  # ====== Creating a partial index
         
     | 
| 
       514 
782 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -518,6 +786,8 @@ module ActiveRecord 
     | 
|
| 
       518 
786 
     | 
    
         
             
                  #
         
     | 
| 
       519 
787 
     | 
    
         
             
                  #   CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
         
     | 
| 
       520 
788 
     | 
    
         
             
                  #
         
     | 
| 
      
 789 
     | 
    
         
            +
                  # Note: Partial indexes are only supported for PostgreSQL and SQLite.
         
     | 
| 
      
 790 
     | 
    
         
            +
                  #
         
     | 
| 
       521 
791 
     | 
    
         
             
                  # ====== Creating an index with a specific method
         
     | 
| 
       522 
792 
     | 
    
         
             
                  #
         
     | 
| 
       523 
793 
     | 
    
         
             
                  #   add_index(:developers, :name, using: 'btree')
         
     | 
| 
         @@ -529,6 +799,19 @@ module ActiveRecord 
     | 
|
| 
       529 
799 
     | 
    
         
             
                  #
         
     | 
| 
       530 
800 
     | 
    
         
             
                  # Note: only supported by PostgreSQL and MySQL
         
     | 
| 
       531 
801 
     | 
    
         
             
                  #
         
     | 
| 
      
 802 
     | 
    
         
            +
                  # ====== Creating an index with a specific operator class
         
     | 
| 
      
 803 
     | 
    
         
            +
                  #
         
     | 
| 
      
 804 
     | 
    
         
            +
                  #   add_index(:developers, :name, using: 'gist', opclass: :gist_trgm_ops)
         
     | 
| 
      
 805 
     | 
    
         
            +
                  #   # CREATE INDEX developers_on_name ON developers USING gist (name gist_trgm_ops) -- PostgreSQL
         
     | 
| 
      
 806 
     | 
    
         
            +
                  #
         
     | 
| 
      
 807 
     | 
    
         
            +
                  #   add_index(:developers, [:name, :city], using: 'gist', opclass: { city: :gist_trgm_ops })
         
     | 
| 
      
 808 
     | 
    
         
            +
                  #   # CREATE INDEX developers_on_name_and_city ON developers USING gist (name, city gist_trgm_ops) -- PostgreSQL
         
     | 
| 
      
 809 
     | 
    
         
            +
                  #
         
     | 
| 
      
 810 
     | 
    
         
            +
                  #   add_index(:developers, [:name, :city], using: 'gist', opclass: :gist_trgm_ops)
         
     | 
| 
      
 811 
     | 
    
         
            +
                  #   # CREATE INDEX developers_on_name_and_city ON developers USING gist (name gist_trgm_ops, city gist_trgm_ops) -- PostgreSQL
         
     | 
| 
      
 812 
     | 
    
         
            +
                  #
         
     | 
| 
      
 813 
     | 
    
         
            +
                  # Note: only supported by PostgreSQL
         
     | 
| 
      
 814 
     | 
    
         
            +
                  #
         
     | 
| 
       532 
815 
     | 
    
         
             
                  # ====== Creating an index with a specific type
         
     | 
| 
       533 
816 
     | 
    
         
             
                  #
         
     | 
| 
       534 
817 
     | 
    
         
             
                  #   add_index(:developers, :name, type: :fulltext)
         
     | 
| 
         @@ -537,23 +820,36 @@ module ActiveRecord 
     | 
|
| 
       537 
820 
     | 
    
         
             
                  #
         
     | 
| 
       538 
821 
     | 
    
         
             
                  #   CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
         
     | 
| 
       539 
822 
     | 
    
         
             
                  #
         
     | 
| 
       540 
     | 
    
         
            -
                  # Note: only supported by MySQL. 
     | 
| 
       541 
     | 
    
         
            -
                   
     | 
| 
       542 
     | 
    
         
            -
             
     | 
| 
       543 
     | 
    
         
            -
             
     | 
| 
      
 823 
     | 
    
         
            +
                  # Note: only supported by MySQL.
         
     | 
| 
      
 824 
     | 
    
         
            +
                  #
         
     | 
| 
      
 825 
     | 
    
         
            +
                  # ====== Creating an index with a specific algorithm
         
     | 
| 
      
 826 
     | 
    
         
            +
                  #
         
     | 
| 
      
 827 
     | 
    
         
            +
                  #  add_index(:developers, :name, algorithm: :concurrently)
         
     | 
| 
      
 828 
     | 
    
         
            +
                  #  # CREATE INDEX CONCURRENTLY developers_on_name on developers (name)
         
     | 
| 
      
 829 
     | 
    
         
            +
                  #
         
     | 
| 
      
 830 
     | 
    
         
            +
                  # Note: only supported by PostgreSQL.
         
     | 
| 
      
 831 
     | 
    
         
            +
                  #
         
     | 
| 
      
 832 
     | 
    
         
            +
                  # Concurrently adding an index is not supported in a transaction.
         
     | 
| 
      
 833 
     | 
    
         
            +
                  #
         
     | 
| 
      
 834 
     | 
    
         
            +
                  # For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
         
     | 
| 
      
 835 
     | 
    
         
            +
                  def add_index(table_name, column_name, **options)
         
     | 
| 
      
 836 
     | 
    
         
            +
                    index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
         
     | 
| 
      
 837 
     | 
    
         
            +
             
     | 
| 
      
 838 
     | 
    
         
            +
                    create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
         
     | 
| 
      
 839 
     | 
    
         
            +
                    execute schema_creation.accept(create_index)
         
     | 
| 
       544 
840 
     | 
    
         
             
                  end
         
     | 
| 
       545 
841 
     | 
    
         | 
| 
       546 
842 
     | 
    
         
             
                  # Removes the given index from the table.
         
     | 
| 
       547 
843 
     | 
    
         
             
                  #
         
     | 
| 
       548 
     | 
    
         
            -
                  # Removes the + 
     | 
| 
      
 844 
     | 
    
         
            +
                  # Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
         
     | 
| 
       549 
845 
     | 
    
         
             
                  #
         
     | 
| 
       550 
     | 
    
         
            -
                  #   remove_index :accounts, : 
     | 
| 
      
 846 
     | 
    
         
            +
                  #   remove_index :accounts, :branch_id
         
     | 
| 
       551 
847 
     | 
    
         
             
                  #
         
     | 
| 
       552 
     | 
    
         
            -
                  # Removes the index  
     | 
| 
      
 848 
     | 
    
         
            +
                  # Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
         
     | 
| 
       553 
849 
     | 
    
         
             
                  #
         
     | 
| 
       554 
850 
     | 
    
         
             
                  #   remove_index :accounts, column: :branch_id
         
     | 
| 
       555 
851 
     | 
    
         
             
                  #
         
     | 
| 
       556 
     | 
    
         
            -
                  # Removes the index  
     | 
| 
      
 852 
     | 
    
         
            +
                  # Removes the index on +branch_id+ and +party_id+ in the +accounts+ table if exactly one such index exists.
         
     | 
| 
       557 
853 
     | 
    
         
             
                  #
         
     | 
| 
       558 
854 
     | 
    
         
             
                  #   remove_index :accounts, column: [:branch_id, :party_id]
         
     | 
| 
       559 
855 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -561,11 +857,29 @@ module ActiveRecord 
     | 
|
| 
       561 
857 
     | 
    
         
             
                  #
         
     | 
| 
       562 
858 
     | 
    
         
             
                  #   remove_index :accounts, name: :by_branch_party
         
     | 
| 
       563 
859 
     | 
    
         
             
                  #
         
     | 
| 
       564 
     | 
    
         
            -
                   
     | 
| 
       565 
     | 
    
         
            -
             
     | 
| 
       566 
     | 
    
         
            -
                   
     | 
| 
      
 860 
     | 
    
         
            +
                  # Removes the index on +branch_id+ named +by_branch_party+ in the +accounts+ table.
         
     | 
| 
      
 861 
     | 
    
         
            +
                  #
         
     | 
| 
      
 862 
     | 
    
         
            +
                  #   remove_index :accounts, :branch_id, name: :by_branch_party
         
     | 
| 
      
 863 
     | 
    
         
            +
                  #
         
     | 
| 
      
 864 
     | 
    
         
            +
                  # Checks if the index exists before trying to remove it. Will silently ignore indexes that
         
     | 
| 
      
 865 
     | 
    
         
            +
                  # don't exist.
         
     | 
| 
      
 866 
     | 
    
         
            +
                  #
         
     | 
| 
      
 867 
     | 
    
         
            +
                  #   remove_index :accounts, if_exists: true
         
     | 
| 
      
 868 
     | 
    
         
            +
                  #
         
     | 
| 
      
 869 
     | 
    
         
            +
                  # Removes the index named +by_branch_party+ in the +accounts+ table +concurrently+.
         
     | 
| 
      
 870 
     | 
    
         
            +
                  #
         
     | 
| 
      
 871 
     | 
    
         
            +
                  #   remove_index :accounts, name: :by_branch_party, algorithm: :concurrently
         
     | 
| 
      
 872 
     | 
    
         
            +
                  #
         
     | 
| 
      
 873 
     | 
    
         
            +
                  # Note: only supported by PostgreSQL.
         
     | 
| 
      
 874 
     | 
    
         
            +
                  #
         
     | 
| 
      
 875 
     | 
    
         
            +
                  # Concurrently removing an index is not supported in a transaction.
         
     | 
| 
      
 876 
     | 
    
         
            +
                  #
         
     | 
| 
      
 877 
     | 
    
         
            +
                  # For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
         
     | 
| 
      
 878 
     | 
    
         
            +
                  def remove_index(table_name, column_name = nil, **options)
         
     | 
| 
      
 879 
     | 
    
         
            +
                    return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
         
     | 
| 
      
 880 
     | 
    
         
            +
             
     | 
| 
      
 881 
     | 
    
         
            +
                    index_name = index_name_for_remove(table_name, column_name, options)
         
     | 
| 
       567 
882 
     | 
    
         | 
| 
       568 
     | 
    
         
            -
                  def remove_index!(table_name, index_name) #:nodoc:
         
     | 
| 
       569 
883 
     | 
    
         
             
                    execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
         
     | 
| 
       570 
884 
     | 
    
         
             
                  end
         
     | 
| 
       571 
885 
     | 
    
         | 
| 
         @@ -576,10 +890,11 @@ module ActiveRecord 
     | 
|
| 
       576 
890 
     | 
    
         
             
                  #   rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
         
     | 
| 
       577 
891 
     | 
    
         
             
                  #
         
     | 
| 
       578 
892 
     | 
    
         
             
                  def rename_index(table_name, old_name, new_name)
         
     | 
| 
       579 
     | 
    
         
            -
                     
     | 
| 
       580 
     | 
    
         
            -
             
     | 
| 
       581 
     | 
    
         
            -
                     
     | 
| 
       582 
     | 
    
         
            -
             
     | 
| 
      
 893 
     | 
    
         
            +
                    old_name = old_name.to_s
         
     | 
| 
      
 894 
     | 
    
         
            +
                    new_name = new_name.to_s
         
     | 
| 
      
 895 
     | 
    
         
            +
                    validate_index_length!(table_name, new_name)
         
     | 
| 
      
 896 
     | 
    
         
            +
             
     | 
| 
      
 897 
     | 
    
         
            +
                    # this is a naive implementation; some DBs may support this more efficiently (PostgreSQL, for instance)
         
     | 
| 
       583 
898 
     | 
    
         
             
                    old_index_def = indexes(table_name).detect { |i| i.name == old_name }
         
     | 
| 
       584 
899 
     | 
    
         
             
                    return unless old_index_def
         
     | 
| 
       585 
900 
     | 
    
         
             
                    add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique)
         
     | 
| 
         @@ -596,70 +911,103 @@ module ActiveRecord 
     | 
|
| 
       596 
911 
     | 
    
         
             
                        raise ArgumentError, "You must specify the index name"
         
     | 
| 
       597 
912 
     | 
    
         
             
                      end
         
     | 
| 
       598 
913 
     | 
    
         
             
                    else
         
     | 
| 
       599 
     | 
    
         
            -
                      index_name(table_name,  
     | 
| 
      
 914 
     | 
    
         
            +
                      index_name(table_name, index_name_options(options))
         
     | 
| 
       600 
915 
     | 
    
         
             
                    end
         
     | 
| 
       601 
916 
     | 
    
         
             
                  end
         
     | 
| 
       602 
917 
     | 
    
         | 
| 
       603 
918 
     | 
    
         
             
                  # Verifies the existence of an index with a given name.
         
     | 
| 
       604 
     | 
    
         
            -
                   
     | 
| 
       605 
     | 
    
         
            -
                  # The default argument is returned if the underlying implementation does not define the indexes method,
         
     | 
| 
       606 
     | 
    
         
            -
                  # as there's no way to determine the correct answer in that case.
         
     | 
| 
       607 
     | 
    
         
            -
                  def index_name_exists?(table_name, index_name, default)
         
     | 
| 
       608 
     | 
    
         
            -
                    return default unless respond_to?(:indexes)
         
     | 
| 
      
 919 
     | 
    
         
            +
                  def index_name_exists?(table_name, index_name)
         
     | 
| 
       609 
920 
     | 
    
         
             
                    index_name = index_name.to_s
         
     | 
| 
       610 
921 
     | 
    
         
             
                    indexes(table_name).detect { |i| i.name == index_name }
         
     | 
| 
       611 
922 
     | 
    
         
             
                  end
         
     | 
| 
       612 
923 
     | 
    
         | 
| 
       613 
     | 
    
         
            -
                  # Adds a reference.  
     | 
| 
       614 
     | 
    
         
            -
                  #  
     | 
| 
       615 
     | 
    
         
            -
                  # a  
     | 
| 
       616 
     | 
    
         
            -
                  #  
     | 
| 
      
 924 
     | 
    
         
            +
                  # Adds a reference. The reference column is a bigint by default,
         
     | 
| 
      
 925 
     | 
    
         
            +
                  # the <tt>:type</tt> option can be used to specify a different type.
         
     | 
| 
      
 926 
     | 
    
         
            +
                  # Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
         
     | 
| 
      
 927 
     | 
    
         
            +
                  # #add_reference and #add_belongs_to are acceptable.
         
     | 
| 
       617 
928 
     | 
    
         
             
                  #
         
     | 
| 
       618 
     | 
    
         
            -
                  #  
     | 
| 
       619 
     | 
    
         
            -
                  #
         
     | 
| 
       620 
     | 
    
         
            -
                  #    
     | 
| 
      
 929 
     | 
    
         
            +
                  # The +options+ hash can include the following keys:
         
     | 
| 
      
 930 
     | 
    
         
            +
                  # [<tt>:type</tt>]
         
     | 
| 
      
 931 
     | 
    
         
            +
                  #   The reference column type. Defaults to +:bigint+.
         
     | 
| 
      
 932 
     | 
    
         
            +
                  # [<tt>:index</tt>]
         
     | 
| 
      
 933 
     | 
    
         
            +
                  #   Add an appropriate index. Defaults to true.
         
     | 
| 
      
 934 
     | 
    
         
            +
                  #   See #add_index for usage of this option.
         
     | 
| 
      
 935 
     | 
    
         
            +
                  # [<tt>:foreign_key</tt>]
         
     | 
| 
      
 936 
     | 
    
         
            +
                  #   Add an appropriate foreign key constraint. Defaults to false, pass true
         
     | 
| 
      
 937 
     | 
    
         
            +
                  #   to add. In case the join table can't be inferred from the association
         
     | 
| 
      
 938 
     | 
    
         
            +
                  #   pass <tt>:to_table</tt> with the appropriate table name.
         
     | 
| 
      
 939 
     | 
    
         
            +
                  # [<tt>:polymorphic</tt>]
         
     | 
| 
      
 940 
     | 
    
         
            +
                  #   Whether an additional +_type+ column should be added. Defaults to false.
         
     | 
| 
      
 941 
     | 
    
         
            +
                  # [<tt>:null</tt>]
         
     | 
| 
      
 942 
     | 
    
         
            +
                  #   Whether the column allows nulls. Defaults to true.
         
     | 
| 
      
 943 
     | 
    
         
            +
                  #
         
     | 
| 
      
 944 
     | 
    
         
            +
                  # ====== Create a user_id bigint column without an index
         
     | 
| 
      
 945 
     | 
    
         
            +
                  #
         
     | 
| 
      
 946 
     | 
    
         
            +
                  #   add_reference(:products, :user, index: false)
         
     | 
| 
       621 
947 
     | 
    
         
             
                  #
         
     | 
| 
       622 
948 
     | 
    
         
             
                  # ====== Create a user_id string column
         
     | 
| 
       623 
949 
     | 
    
         
             
                  #
         
     | 
| 
       624 
950 
     | 
    
         
             
                  #   add_reference(:products, :user, type: :string)
         
     | 
| 
       625 
951 
     | 
    
         
             
                  #
         
     | 
| 
       626 
     | 
    
         
            -
                  # ====== Create  
     | 
| 
      
 952 
     | 
    
         
            +
                  # ====== Create supplier_id, supplier_type columns
         
     | 
| 
      
 953 
     | 
    
         
            +
                  #
         
     | 
| 
      
 954 
     | 
    
         
            +
                  #   add_reference(:products, :supplier, polymorphic: true)
         
     | 
| 
      
 955 
     | 
    
         
            +
                  #
         
     | 
| 
      
 956 
     | 
    
         
            +
                  # ====== Create a supplier_id column with a unique index
         
     | 
| 
       627 
957 
     | 
    
         
             
                  #
         
     | 
| 
       628 
     | 
    
         
            -
                  #    
     | 
| 
      
 958 
     | 
    
         
            +
                  #   add_reference(:products, :supplier, index: { unique: true })
         
     | 
| 
       629 
959 
     | 
    
         
             
                  #
         
     | 
| 
       630 
     | 
    
         
            -
                  # ====== Create a supplier_id 
     | 
| 
      
 960 
     | 
    
         
            +
                  # ====== Create a supplier_id column with a named index
         
     | 
| 
       631 
961 
     | 
    
         
             
                  #
         
     | 
| 
       632 
     | 
    
         
            -
                  #   add_reference(:products, :supplier,  
     | 
| 
      
 962 
     | 
    
         
            +
                  #   add_reference(:products, :supplier, index: { name: "my_supplier_index" })
         
     | 
| 
       633 
963 
     | 
    
         
             
                  #
         
     | 
| 
       634 
     | 
    
         
            -
                   
     | 
| 
       635 
     | 
    
         
            -
             
     | 
| 
       636 
     | 
    
         
            -
             
     | 
| 
       637 
     | 
    
         
            -
             
     | 
| 
       638 
     | 
    
         
            -
             
     | 
| 
       639 
     | 
    
         
            -
             
     | 
| 
       640 
     | 
    
         
            -
             
     | 
| 
      
 964 
     | 
    
         
            +
                  # ====== Create a supplier_id column and appropriate foreign key
         
     | 
| 
      
 965 
     | 
    
         
            +
                  #
         
     | 
| 
      
 966 
     | 
    
         
            +
                  #   add_reference(:products, :supplier, foreign_key: true)
         
     | 
| 
      
 967 
     | 
    
         
            +
                  #
         
     | 
| 
      
 968 
     | 
    
         
            +
                  # ====== Create a supplier_id column and a foreign key to the firms table
         
     | 
| 
      
 969 
     | 
    
         
            +
                  #
         
     | 
| 
      
 970 
     | 
    
         
            +
                  #   add_reference(:products, :supplier, foreign_key: { to_table: :firms })
         
     | 
| 
      
 971 
     | 
    
         
            +
                  #
         
     | 
| 
      
 972 
     | 
    
         
            +
                  def add_reference(table_name, ref_name, **options)
         
     | 
| 
      
 973 
     | 
    
         
            +
                    ReferenceDefinition.new(ref_name, **options).add_to(update_table_definition(table_name, self))
         
     | 
| 
       641 
974 
     | 
    
         
             
                  end
         
     | 
| 
       642 
975 
     | 
    
         
             
                  alias :add_belongs_to :add_reference
         
     | 
| 
       643 
976 
     | 
    
         | 
| 
       644 
977 
     | 
    
         
             
                  # Removes the reference(s). Also removes a +type+ column if one exists.
         
     | 
| 
       645 
     | 
    
         
            -
                  #  
     | 
| 
      
 978 
     | 
    
         
            +
                  # #remove_reference and #remove_belongs_to are acceptable.
         
     | 
| 
       646 
979 
     | 
    
         
             
                  #
         
     | 
| 
       647 
980 
     | 
    
         
             
                  # ====== Remove the reference
         
     | 
| 
       648 
981 
     | 
    
         
             
                  #
         
     | 
| 
       649 
     | 
    
         
            -
                  #   remove_reference(:products, :user, index:  
     | 
| 
      
 982 
     | 
    
         
            +
                  #   remove_reference(:products, :user, index: false)
         
     | 
| 
       650 
983 
     | 
    
         
             
                  #
         
     | 
| 
       651 
984 
     | 
    
         
             
                  # ====== Remove polymorphic reference
         
     | 
| 
       652 
985 
     | 
    
         
             
                  #
         
     | 
| 
       653 
986 
     | 
    
         
             
                  #   remove_reference(:products, :supplier, polymorphic: true)
         
     | 
| 
       654 
987 
     | 
    
         
             
                  #
         
     | 
| 
       655 
     | 
    
         
            -
                   
     | 
| 
      
 988 
     | 
    
         
            +
                  # ====== Remove the reference with a foreign key
         
     | 
| 
      
 989 
     | 
    
         
            +
                  #
         
     | 
| 
      
 990 
     | 
    
         
            +
                  #   remove_reference(:products, :user, foreign_key: true)
         
     | 
| 
      
 991 
     | 
    
         
            +
                  #
         
     | 
| 
      
 992 
     | 
    
         
            +
                  def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
         
     | 
| 
      
 993 
     | 
    
         
            +
                    if foreign_key
         
     | 
| 
      
 994 
     | 
    
         
            +
                      reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
         
     | 
| 
      
 995 
     | 
    
         
            +
                      if foreign_key.is_a?(Hash)
         
     | 
| 
      
 996 
     | 
    
         
            +
                        foreign_key_options = foreign_key
         
     | 
| 
      
 997 
     | 
    
         
            +
                      else
         
     | 
| 
      
 998 
     | 
    
         
            +
                        foreign_key_options = { to_table: reference_name }
         
     | 
| 
      
 999 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1000 
     | 
    
         
            +
                      foreign_key_options[:column] ||= "#{ref_name}_id"
         
     | 
| 
      
 1001 
     | 
    
         
            +
                      remove_foreign_key(table_name, **foreign_key_options)
         
     | 
| 
      
 1002 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1003 
     | 
    
         
            +
             
     | 
| 
       656 
1004 
     | 
    
         
             
                    remove_column(table_name, "#{ref_name}_id")
         
     | 
| 
       657 
     | 
    
         
            -
                    remove_column(table_name, "#{ref_name}_type") if  
     | 
| 
      
 1005 
     | 
    
         
            +
                    remove_column(table_name, "#{ref_name}_type") if polymorphic
         
     | 
| 
       658 
1006 
     | 
    
         
             
                  end
         
     | 
| 
       659 
1007 
     | 
    
         
             
                  alias :remove_belongs_to :remove_reference
         
     | 
| 
       660 
1008 
     | 
    
         | 
| 
       661 
1009 
     | 
    
         
             
                  # Returns an array of foreign keys for the given table.
         
     | 
| 
       662 
     | 
    
         
            -
                  # The foreign keys are represented as  
     | 
| 
      
 1010 
     | 
    
         
            +
                  # The foreign keys are represented as ForeignKeyDefinition objects.
         
     | 
| 
       663 
1011 
     | 
    
         
             
                  def foreign_keys(table_name)
         
     | 
| 
       664 
1012 
     | 
    
         
             
                    raise NotImplementedError, "foreign_keys is not implemented"
         
     | 
| 
       665 
1013 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -668,8 +1016,8 @@ module ActiveRecord 
     | 
|
| 
       668 
1016 
     | 
    
         
             
                  # +to_table+ contains the referenced primary key.
         
     | 
| 
       669 
1017 
     | 
    
         
             
                  #
         
     | 
| 
       670 
1018 
     | 
    
         
             
                  # The foreign key will be named after the following pattern: <tt>fk_rails_<identifier></tt>.
         
     | 
| 
       671 
     | 
    
         
            -
                  # +identifier+ is a 10 character long  
     | 
| 
       672 
     | 
    
         
            -
                  # the <tt>:name</tt> option.
         
     | 
| 
      
 1019 
     | 
    
         
            +
                  # +identifier+ is a 10 character long string which is deterministically generated from the
         
     | 
| 
      
 1020 
     | 
    
         
            +
                  # +from_table+ and +column+. A custom name can be specified with the <tt>:name</tt> option.
         
     | 
| 
       673 
1021 
     | 
    
         
             
                  #
         
     | 
| 
       674 
1022 
     | 
    
         
             
                  # ====== Creating a simple foreign key
         
     | 
| 
       675 
1023 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -677,7 +1025,7 @@ module ActiveRecord 
     | 
|
| 
       677 
1025 
     | 
    
         
             
                  #
         
     | 
| 
       678 
1026 
     | 
    
         
             
                  # generates:
         
     | 
| 
       679 
1027 
     | 
    
         
             
                  #
         
     | 
| 
       680 
     | 
    
         
            -
                  #   ALTER TABLE "articles" ADD CONSTRAINT  
     | 
| 
      
 1028 
     | 
    
         
            +
                  #   ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
         
     | 
| 
       681 
1029 
     | 
    
         
             
                  #
         
     | 
| 
       682 
1030 
     | 
    
         
             
                  # ====== Creating a foreign key on a specific column
         
     | 
| 
       683 
1031 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -693,7 +1041,7 @@ module ActiveRecord 
     | 
|
| 
       693 
1041 
     | 
    
         
             
                  #
         
     | 
| 
       694 
1042 
     | 
    
         
             
                  # generates:
         
     | 
| 
       695 
1043 
     | 
    
         
             
                  #
         
     | 
| 
       696 
     | 
    
         
            -
                  #   ALTER TABLE "articles" ADD CONSTRAINT  
     | 
| 
      
 1044 
     | 
    
         
            +
                  #   ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE
         
     | 
| 
       697 
1045 
     | 
    
         
             
                  #
         
     | 
| 
       698 
1046 
     | 
    
         
             
                  # The +options+ hash can include the following keys:
         
     | 
| 
       699 
1047 
     | 
    
         
             
                  # [<tt>:column</tt>]
         
     | 
| 
         @@ -703,28 +1051,25 @@ module ActiveRecord 
     | 
|
| 
       703 
1051 
     | 
    
         
             
                  # [<tt>:name</tt>]
         
     | 
| 
       704 
1052 
     | 
    
         
             
                  #   The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
         
     | 
| 
       705 
1053 
     | 
    
         
             
                  # [<tt>:on_delete</tt>]
         
     | 
| 
       706 
     | 
    
         
            -
                  #   Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade 
     | 
| 
      
 1054 
     | 
    
         
            +
                  #   Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
         
     | 
| 
       707 
1055 
     | 
    
         
             
                  # [<tt>:on_update</tt>]
         
     | 
| 
       708 
     | 
    
         
            -
                  #   Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade 
     | 
| 
       709 
     | 
    
         
            -
                   
     | 
| 
      
 1056 
     | 
    
         
            +
                  #   Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
         
     | 
| 
      
 1057 
     | 
    
         
            +
                  # [<tt>:validate</tt>]
         
     | 
| 
      
 1058 
     | 
    
         
            +
                  #   (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
         
     | 
| 
      
 1059 
     | 
    
         
            +
                  def add_foreign_key(from_table, to_table, **options)
         
     | 
| 
       710 
1060 
     | 
    
         
             
                    return unless supports_foreign_keys?
         
     | 
| 
       711 
1061 
     | 
    
         | 
| 
       712 
     | 
    
         
            -
                    options 
     | 
| 
       713 
     | 
    
         
            -
             
     | 
| 
       714 
     | 
    
         
            -
                    options = {
         
     | 
| 
       715 
     | 
    
         
            -
                      column: options[:column],
         
     | 
| 
       716 
     | 
    
         
            -
                      primary_key: options[:primary_key],
         
     | 
| 
       717 
     | 
    
         
            -
                      name: foreign_key_name(from_table, options),
         
     | 
| 
       718 
     | 
    
         
            -
                      on_delete: options[:on_delete],
         
     | 
| 
       719 
     | 
    
         
            -
                      on_update: options[:on_update]
         
     | 
| 
       720 
     | 
    
         
            -
                    }
         
     | 
| 
      
 1062 
     | 
    
         
            +
                    options = foreign_key_options(from_table, to_table, options)
         
     | 
| 
       721 
1063 
     | 
    
         
             
                    at = create_alter_table from_table
         
     | 
| 
       722 
1064 
     | 
    
         
             
                    at.add_foreign_key to_table, options
         
     | 
| 
       723 
1065 
     | 
    
         | 
| 
       724 
1066 
     | 
    
         
             
                    execute schema_creation.accept(at)
         
     | 
| 
       725 
1067 
     | 
    
         
             
                  end
         
     | 
| 
       726 
1068 
     | 
    
         | 
| 
       727 
     | 
    
         
            -
                  # Removes the given foreign key from the table.
         
     | 
| 
      
 1069 
     | 
    
         
            +
                  # Removes the given foreign key from the table. Any option parameters provided
         
     | 
| 
      
 1070 
     | 
    
         
            +
                  # will be used to re-add the foreign key in case of a migration rollback.
         
     | 
| 
      
 1071 
     | 
    
         
            +
                  # It is recommended that you provide any options used when creating the foreign
         
     | 
| 
      
 1072 
     | 
    
         
            +
                  # key so that the migration can be reverted properly.
         
     | 
| 
       728 
1073 
     | 
    
         
             
                  #
         
     | 
| 
       729 
1074 
     | 
    
         
             
                  # Removes the foreign key on +accounts.branch_id+.
         
     | 
| 
       730 
1075 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -734,28 +1079,22 @@ module ActiveRecord 
     | 
|
| 
       734 
1079 
     | 
    
         
             
                  #
         
     | 
| 
       735 
1080 
     | 
    
         
             
                  #   remove_foreign_key :accounts, column: :owner_id
         
     | 
| 
       736 
1081 
     | 
    
         
             
                  #
         
     | 
| 
      
 1082 
     | 
    
         
            +
                  # Removes the foreign key on +accounts.owner_id+.
         
     | 
| 
      
 1083 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1084 
     | 
    
         
            +
                  #   remove_foreign_key :accounts, to_table: :owners
         
     | 
| 
      
 1085 
     | 
    
         
            +
                  #
         
     | 
| 
       737 
1086 
     | 
    
         
             
                  # Removes the foreign key named +special_fk_name+ on the +accounts+ table.
         
     | 
| 
       738 
1087 
     | 
    
         
             
                  #
         
     | 
| 
       739 
1088 
     | 
    
         
             
                  #   remove_foreign_key :accounts, name: :special_fk_name
         
     | 
| 
       740 
1089 
     | 
    
         
             
                  #
         
     | 
| 
       741 
     | 
    
         
            -
                   
     | 
| 
      
 1090 
     | 
    
         
            +
                  # The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
         
     | 
| 
      
 1091 
     | 
    
         
            +
                  # with an addition of
         
     | 
| 
      
 1092 
     | 
    
         
            +
                  # [<tt>:to_table</tt>]
         
     | 
| 
      
 1093 
     | 
    
         
            +
                  #   The name of the table that contains the referenced primary key.
         
     | 
| 
      
 1094 
     | 
    
         
            +
                  def remove_foreign_key(from_table, to_table = nil, **options)
         
     | 
| 
       742 
1095 
     | 
    
         
             
                    return unless supports_foreign_keys?
         
     | 
| 
       743 
1096 
     | 
    
         | 
| 
       744 
     | 
    
         
            -
                     
     | 
| 
       745 
     | 
    
         
            -
                      options = options_or_to_table
         
     | 
| 
       746 
     | 
    
         
            -
                    else
         
     | 
| 
       747 
     | 
    
         
            -
                      options = { column: foreign_key_column_for(options_or_to_table) }
         
     | 
| 
       748 
     | 
    
         
            -
                    end
         
     | 
| 
       749 
     | 
    
         
            -
             
     | 
| 
       750 
     | 
    
         
            -
                    fk_name_to_delete = options.fetch(:name) do
         
     | 
| 
       751 
     | 
    
         
            -
                      fk_to_delete = foreign_keys(from_table).detect {|fk| fk.column == options[:column].to_s }
         
     | 
| 
       752 
     | 
    
         
            -
             
     | 
| 
       753 
     | 
    
         
            -
                      if fk_to_delete
         
     | 
| 
       754 
     | 
    
         
            -
                        fk_to_delete.name
         
     | 
| 
       755 
     | 
    
         
            -
                      else
         
     | 
| 
       756 
     | 
    
         
            -
                        raise ArgumentError, "Table '#{from_table}' has no foreign key on column '#{options[:column]}'"
         
     | 
| 
       757 
     | 
    
         
            -
                      end
         
     | 
| 
       758 
     | 
    
         
            -
                    end
         
     | 
| 
      
 1097 
     | 
    
         
            +
                    fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
         
     | 
| 
       759 
1098 
     | 
    
         | 
| 
       760 
1099 
     | 
    
         
             
                    at = create_alter_table from_table
         
     | 
| 
       761 
1100 
     | 
    
         
             
                    at.drop_foreign_key fk_name_to_delete
         
     | 
| 
         @@ -763,52 +1102,119 @@ module ActiveRecord 
     | 
|
| 
       763 
1102 
     | 
    
         
             
                    execute schema_creation.accept(at)
         
     | 
| 
       764 
1103 
     | 
    
         
             
                  end
         
     | 
| 
       765 
1104 
     | 
    
         | 
| 
      
 1105 
     | 
    
         
            +
                  # Checks to see if a foreign key exists on a table for a given foreign key definition.
         
     | 
| 
      
 1106 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1107 
     | 
    
         
            +
                  #   # Checks to see if a foreign key exists.
         
     | 
| 
      
 1108 
     | 
    
         
            +
                  #   foreign_key_exists?(:accounts, :branches)
         
     | 
| 
      
 1109 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1110 
     | 
    
         
            +
                  #   # Checks to see if a foreign key on a specified column exists.
         
     | 
| 
      
 1111 
     | 
    
         
            +
                  #   foreign_key_exists?(:accounts, column: :owner_id)
         
     | 
| 
      
 1112 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1113 
     | 
    
         
            +
                  #   # Checks to see if a foreign key with a custom name exists.
         
     | 
| 
      
 1114 
     | 
    
         
            +
                  #   foreign_key_exists?(:accounts, name: "special_fk_name")
         
     | 
| 
      
 1115 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1116 
     | 
    
         
            +
                  def foreign_key_exists?(from_table, to_table = nil, **options)
         
     | 
| 
      
 1117 
     | 
    
         
            +
                    foreign_key_for(from_table, to_table: to_table, **options).present?
         
     | 
| 
      
 1118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1119 
     | 
    
         
            +
             
     | 
| 
       766 
1120 
     | 
    
         
             
                  def foreign_key_column_for(table_name) # :nodoc:
         
     | 
| 
       767 
     | 
    
         
            -
                     
     | 
| 
      
 1121 
     | 
    
         
            +
                    name = strip_table_name_prefix_and_suffix(table_name)
         
     | 
| 
      
 1122 
     | 
    
         
            +
                    "#{name.singularize}_id"
         
     | 
| 
      
 1123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1124 
     | 
    
         
            +
             
     | 
| 
      
 1125 
     | 
    
         
            +
                  def foreign_key_options(from_table, to_table, options) # :nodoc:
         
     | 
| 
      
 1126 
     | 
    
         
            +
                    options = options.dup
         
     | 
| 
      
 1127 
     | 
    
         
            +
                    options[:column] ||= foreign_key_column_for(to_table)
         
     | 
| 
      
 1128 
     | 
    
         
            +
                    options[:name]   ||= foreign_key_name(from_table, options)
         
     | 
| 
      
 1129 
     | 
    
         
            +
                    options
         
     | 
| 
      
 1130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1131 
     | 
    
         
            +
             
     | 
| 
      
 1132 
     | 
    
         
            +
                  # Returns an array of check constraints for the given table.
         
     | 
| 
      
 1133 
     | 
    
         
            +
                  # The check constraints are represented as CheckConstraintDefinition objects.
         
     | 
| 
      
 1134 
     | 
    
         
            +
                  def check_constraints(table_name)
         
     | 
| 
      
 1135 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 1136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1137 
     | 
    
         
            +
             
     | 
| 
      
 1138 
     | 
    
         
            +
                  # Adds a new check constraint to the table. +expression+ is a String
         
     | 
| 
      
 1139 
     | 
    
         
            +
                  # representation of verifiable boolean condition.
         
     | 
| 
      
 1140 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1141 
     | 
    
         
            +
                  #   add_check_constraint :products, "price > 0", name: "price_check"
         
     | 
| 
      
 1142 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1143 
     | 
    
         
            +
                  # generates:
         
     | 
| 
      
 1144 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1145 
     | 
    
         
            +
                  #   ALTER TABLE "products" ADD CONSTRAINT price_check CHECK (price > 0)
         
     | 
| 
      
 1146 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1147 
     | 
    
         
            +
                  # The +options+ hash can include the following keys:
         
     | 
| 
      
 1148 
     | 
    
         
            +
                  # [<tt>:name</tt>]
         
     | 
| 
      
 1149 
     | 
    
         
            +
                  #   The constraint name. Defaults to <tt>chk_rails_<identifier></tt>.
         
     | 
| 
      
 1150 
     | 
    
         
            +
                  # [<tt>:validate</tt>]
         
     | 
| 
      
 1151 
     | 
    
         
            +
                  #   (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
         
     | 
| 
      
 1152 
     | 
    
         
            +
                  def add_check_constraint(table_name, expression, **options)
         
     | 
| 
      
 1153 
     | 
    
         
            +
                    return unless supports_check_constraints?
         
     | 
| 
      
 1154 
     | 
    
         
            +
             
     | 
| 
      
 1155 
     | 
    
         
            +
                    options = check_constraint_options(table_name, expression, options)
         
     | 
| 
      
 1156 
     | 
    
         
            +
                    at = create_alter_table(table_name)
         
     | 
| 
      
 1157 
     | 
    
         
            +
                    at.add_check_constraint(expression, options)
         
     | 
| 
      
 1158 
     | 
    
         
            +
             
     | 
| 
      
 1159 
     | 
    
         
            +
                    execute schema_creation.accept(at)
         
     | 
| 
       768 
1160 
     | 
    
         
             
                  end
         
     | 
| 
       769 
1161 
     | 
    
         | 
| 
       770 
     | 
    
         
            -
                  def  
     | 
| 
       771 
     | 
    
         
            -
                     
     | 
| 
      
 1162 
     | 
    
         
            +
                  def check_constraint_options(table_name, expression, options) # :nodoc:
         
     | 
| 
      
 1163 
     | 
    
         
            +
                    options = options.dup
         
     | 
| 
      
 1164 
     | 
    
         
            +
                    options[:name] ||= check_constraint_name(table_name, expression: expression, **options)
         
     | 
| 
      
 1165 
     | 
    
         
            +
                    options
         
     | 
| 
      
 1166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1167 
     | 
    
         
            +
             
     | 
| 
      
 1168 
     | 
    
         
            +
                  # Removes the given check constraint from the table.
         
     | 
| 
      
 1169 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1170 
     | 
    
         
            +
                  #   remove_check_constraint :products, name: "price_check"
         
     | 
| 
      
 1171 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1172 
     | 
    
         
            +
                  # The +expression+ parameter will be ignored if present. It can be helpful
         
     | 
| 
      
 1173 
     | 
    
         
            +
                  # to provide this in a migration's +change+ method so it can be reverted.
         
     | 
| 
      
 1174 
     | 
    
         
            +
                  # In that case, +expression+ will be used by #add_check_constraint.
         
     | 
| 
      
 1175 
     | 
    
         
            +
                  def remove_check_constraint(table_name, expression = nil, **options)
         
     | 
| 
      
 1176 
     | 
    
         
            +
                    return unless supports_check_constraints?
         
     | 
| 
      
 1177 
     | 
    
         
            +
             
     | 
| 
      
 1178 
     | 
    
         
            +
                    chk_name_to_delete = check_constraint_for!(table_name, expression: expression, **options).name
         
     | 
| 
      
 1179 
     | 
    
         
            +
             
     | 
| 
      
 1180 
     | 
    
         
            +
                    at = create_alter_table(table_name)
         
     | 
| 
      
 1181 
     | 
    
         
            +
                    at.drop_check_constraint(chk_name_to_delete)
         
     | 
| 
      
 1182 
     | 
    
         
            +
             
     | 
| 
      
 1183 
     | 
    
         
            +
                    execute schema_creation.accept(at)
         
     | 
| 
      
 1184 
     | 
    
         
            +
                  end
         
     | 
| 
       772 
1185 
     | 
    
         | 
| 
       773 
     | 
    
         
            -
             
     | 
| 
       774 
     | 
    
         
            -
             
     | 
| 
       775 
     | 
    
         
            -
                     
     | 
| 
      
 1186 
     | 
    
         
            +
                  def dump_schema_information # :nodoc:
         
     | 
| 
      
 1187 
     | 
    
         
            +
                    versions = schema_migration.all_versions
         
     | 
| 
      
 1188 
     | 
    
         
            +
                    insert_versions_sql(versions) if versions.any?
         
     | 
| 
       776 
1189 
     | 
    
         
             
                  end
         
     | 
| 
       777 
1190 
     | 
    
         | 
| 
       778 
     | 
    
         
            -
                   
     | 
| 
       779 
     | 
    
         
            -
             
     | 
| 
       780 
     | 
    
         
            -
                  def initialize_schema_migrations_table
         
     | 
| 
       781 
     | 
    
         
            -
                    ActiveRecord::SchemaMigration.create_table
         
     | 
| 
      
 1191 
     | 
    
         
            +
                  def internal_string_options_for_primary_key # :nodoc:
         
     | 
| 
      
 1192 
     | 
    
         
            +
                    { primary_key: true }
         
     | 
| 
       782 
1193 
     | 
    
         
             
                  end
         
     | 
| 
       783 
1194 
     | 
    
         | 
| 
       784 
     | 
    
         
            -
                  def assume_migrated_upto_version(version 
     | 
| 
       785 
     | 
    
         
            -
                    migrations_paths = Array(migrations_paths)
         
     | 
| 
      
 1195 
     | 
    
         
            +
                  def assume_migrated_upto_version(version)
         
     | 
| 
       786 
1196 
     | 
    
         
             
                    version = version.to_i
         
     | 
| 
       787 
     | 
    
         
            -
                    sm_table = quote_table_name( 
     | 
| 
      
 1197 
     | 
    
         
            +
                    sm_table = quote_table_name(schema_migration.table_name)
         
     | 
| 
       788 
1198 
     | 
    
         | 
| 
       789 
     | 
    
         
            -
                    migrated =  
     | 
| 
       790 
     | 
    
         
            -
                     
     | 
| 
       791 
     | 
    
         
            -
                    versions = Dir[*paths].map do |filename|
         
     | 
| 
       792 
     | 
    
         
            -
                      filename.split('/').last.split('_').first.to_i
         
     | 
| 
       793 
     | 
    
         
            -
                    end
         
     | 
| 
      
 1199 
     | 
    
         
            +
                    migrated = migration_context.get_all_versions
         
     | 
| 
      
 1200 
     | 
    
         
            +
                    versions = migration_context.migrations.map(&:version)
         
     | 
| 
       794 
1201 
     | 
    
         | 
| 
       795 
1202 
     | 
    
         
             
                    unless migrated.include?(version)
         
     | 
| 
       796 
     | 
    
         
            -
                      execute "INSERT INTO #{sm_table} (version) VALUES ( 
     | 
| 
      
 1203 
     | 
    
         
            +
                      execute "INSERT INTO #{sm_table} (version) VALUES (#{quote(version)})"
         
     | 
| 
       797 
1204 
     | 
    
         
             
                    end
         
     | 
| 
       798 
1205 
     | 
    
         | 
| 
       799 
     | 
    
         
            -
                     
     | 
| 
       800 
     | 
    
         
            -
                     
     | 
| 
       801 
     | 
    
         
            -
                      if  
     | 
| 
       802 
     | 
    
         
            -
                        raise "Duplicate migration #{ 
     | 
| 
       803 
     | 
    
         
            -
                      elsif v < version
         
     | 
| 
       804 
     | 
    
         
            -
                        execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
         
     | 
| 
       805 
     | 
    
         
            -
                        inserted << v
         
     | 
| 
      
 1206 
     | 
    
         
            +
                    inserting = (versions - migrated).select { |v| v < version }
         
     | 
| 
      
 1207 
     | 
    
         
            +
                    if inserting.any?
         
     | 
| 
      
 1208 
     | 
    
         
            +
                      if (duplicate = inserting.detect { |v| inserting.count(v) > 1 })
         
     | 
| 
      
 1209 
     | 
    
         
            +
                        raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
         
     | 
| 
       806 
1210 
     | 
    
         
             
                      end
         
     | 
| 
      
 1211 
     | 
    
         
            +
                      execute insert_versions_sql(inserting)
         
     | 
| 
       807 
1212 
     | 
    
         
             
                    end
         
     | 
| 
       808 
1213 
     | 
    
         
             
                  end
         
     | 
| 
       809 
1214 
     | 
    
         | 
| 
       810 
     | 
    
         
            -
                  def type_to_sql(type, limit  
     | 
| 
       811 
     | 
    
         
            -
                     
     | 
| 
      
 1215 
     | 
    
         
            +
                  def type_to_sql(type, limit: nil, precision: nil, scale: nil, **) # :nodoc:
         
     | 
| 
      
 1216 
     | 
    
         
            +
                    type = type.to_sym if type
         
     | 
| 
      
 1217 
     | 
    
         
            +
                    if native = native_database_types[type]
         
     | 
| 
       812 
1218 
     | 
    
         
             
                      column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
         
     | 
| 
       813 
1219 
     | 
    
         | 
| 
       814 
1220 
     | 
    
         
             
                      if type == :decimal # ignore limit, use precision and scale
         
     | 
| 
         @@ -824,6 +1230,12 @@ module ActiveRecord 
     | 
|
| 
       824 
1230 
     | 
    
         
             
                          raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
         
     | 
| 
       825 
1231 
     | 
    
         
             
                        end
         
     | 
| 
       826 
1232 
     | 
    
         | 
| 
      
 1233 
     | 
    
         
            +
                      elsif [:datetime, :timestamp, :time, :interval].include?(type) && precision ||= native[:precision]
         
     | 
| 
      
 1234 
     | 
    
         
            +
                        if (0..6) === precision
         
     | 
| 
      
 1235 
     | 
    
         
            +
                          column_type_sql << "(#{precision})"
         
     | 
| 
      
 1236 
     | 
    
         
            +
                        else
         
     | 
| 
      
 1237 
     | 
    
         
            +
                          raise ArgumentError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6"
         
     | 
| 
      
 1238 
     | 
    
         
            +
                        end
         
     | 
| 
       827 
1239 
     | 
    
         
             
                      elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
         
     | 
| 
       828 
1240 
     | 
    
         
             
                        column_type_sql << "(#{limit})"
         
     | 
| 
       829 
1241 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -835,31 +1247,36 @@ module ActiveRecord 
     | 
|
| 
       835 
1247 
     | 
    
         
             
                  end
         
     | 
| 
       836 
1248 
     | 
    
         | 
| 
       837 
1249 
     | 
    
         
             
                  # Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT.
         
     | 
| 
       838 
     | 
    
         
            -
                  #  
     | 
| 
      
 1250 
     | 
    
         
            +
                  # PostgreSQL, MySQL, and Oracle override this for custom DISTINCT syntax - they
         
     | 
| 
       839 
1251 
     | 
    
         
             
                  # require the order columns appear in the SELECT.
         
     | 
| 
       840 
1252 
     | 
    
         
             
                  #
         
     | 
| 
       841 
1253 
     | 
    
         
             
                  #   columns_for_distinct("posts.id", ["posts.created_at desc"])
         
     | 
| 
       842 
     | 
    
         
            -
                   
     | 
| 
      
 1254 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1255 
     | 
    
         
            +
                  def columns_for_distinct(columns, orders) # :nodoc:
         
     | 
| 
       843 
1256 
     | 
    
         
             
                    columns
         
     | 
| 
       844 
1257 
     | 
    
         
             
                  end
         
     | 
| 
       845 
1258 
     | 
    
         | 
| 
       846 
     | 
    
         
            -
                  include TimestampDefaultDeprecation
         
     | 
| 
       847 
1259 
     | 
    
         
             
                  # Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
         
     | 
| 
       848 
     | 
    
         
            -
                  # Additional options (like  
     | 
| 
      
 1260 
     | 
    
         
            +
                  # Additional options (like +:null+) are forwarded to #add_column.
         
     | 
| 
       849 
1261 
     | 
    
         
             
                  #
         
     | 
| 
       850 
     | 
    
         
            -
                  #   add_timestamps(:suppliers, null:  
     | 
| 
      
 1262 
     | 
    
         
            +
                  #   add_timestamps(:suppliers, null: true)
         
     | 
| 
       851 
1263 
     | 
    
         
             
                  #
         
     | 
| 
       852 
     | 
    
         
            -
                  def add_timestamps(table_name, options 
     | 
| 
       853 
     | 
    
         
            -
                     
     | 
| 
       854 
     | 
    
         
            -
             
     | 
| 
       855 
     | 
    
         
            -
                     
     | 
| 
      
 1264 
     | 
    
         
            +
                  def add_timestamps(table_name, **options)
         
     | 
| 
      
 1265 
     | 
    
         
            +
                    options[:null] = false if options[:null].nil?
         
     | 
| 
      
 1266 
     | 
    
         
            +
             
     | 
| 
      
 1267 
     | 
    
         
            +
                    if !options.key?(:precision) && supports_datetime_with_precision?
         
     | 
| 
      
 1268 
     | 
    
         
            +
                      options[:precision] = 6
         
     | 
| 
      
 1269 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1270 
     | 
    
         
            +
             
     | 
| 
      
 1271 
     | 
    
         
            +
                    add_column table_name, :created_at, :datetime, **options
         
     | 
| 
      
 1272 
     | 
    
         
            +
                    add_column table_name, :updated_at, :datetime, **options
         
     | 
| 
       856 
1273 
     | 
    
         
             
                  end
         
     | 
| 
       857 
1274 
     | 
    
         | 
| 
       858 
1275 
     | 
    
         
             
                  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table definition.
         
     | 
| 
       859 
1276 
     | 
    
         
             
                  #
         
     | 
| 
       860 
1277 
     | 
    
         
             
                  #  remove_timestamps(:suppliers)
         
     | 
| 
       861 
1278 
     | 
    
         
             
                  #
         
     | 
| 
       862 
     | 
    
         
            -
                  def remove_timestamps(table_name, options 
     | 
| 
      
 1279 
     | 
    
         
            +
                  def remove_timestamps(table_name, **options)
         
     | 
| 
       863 
1280 
     | 
    
         
             
                    remove_column table_name, :updated_at
         
     | 
| 
       864 
1281 
     | 
    
         
             
                    remove_column table_name, :created_at
         
     | 
| 
       865 
1282 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -868,86 +1285,133 @@ module ActiveRecord 
     | 
|
| 
       868 
1285 
     | 
    
         
             
                    Table.new(table_name, base)
         
     | 
| 
       869 
1286 
     | 
    
         
             
                  end
         
     | 
| 
       870 
1287 
     | 
    
         | 
| 
       871 
     | 
    
         
            -
                  def add_index_options(table_name, column_name,  
     | 
| 
       872 
     | 
    
         
            -
                     
     | 
| 
       873 
     | 
    
         
            -
                    index_name   = index_name(table_name, column: column_names)
         
     | 
| 
      
 1288 
     | 
    
         
            +
                  def add_index_options(table_name, column_name, name: nil, if_not_exists: false, internal: false, **options) # :nodoc:
         
     | 
| 
      
 1289 
     | 
    
         
            +
                    options.assert_valid_keys(:unique, :length, :order, :opclass, :where, :type, :using, :comment, :algorithm)
         
     | 
| 
       874 
1290 
     | 
    
         | 
| 
       875 
     | 
    
         
            -
                     
     | 
| 
      
 1291 
     | 
    
         
            +
                    column_names = index_column_names(column_name)
         
     | 
| 
       876 
1292 
     | 
    
         | 
| 
       877 
     | 
    
         
            -
                     
     | 
| 
       878 
     | 
    
         
            -
                     
     | 
| 
       879 
     | 
    
         
            -
                    index_name = options[:name].to_s if options.key?(:name)
         
     | 
| 
       880 
     | 
    
         
            -
                    max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
         
     | 
| 
      
 1293 
     | 
    
         
            +
                    index_name = name&.to_s
         
     | 
| 
      
 1294 
     | 
    
         
            +
                    index_name ||= index_name(table_name, column_names)
         
     | 
| 
       881 
1295 
     | 
    
         | 
| 
       882 
     | 
    
         
            -
                     
     | 
| 
       883 
     | 
    
         
            -
                      algorithm = index_algorithms.fetch(options[:algorithm]) {
         
     | 
| 
       884 
     | 
    
         
            -
                        raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
         
     | 
| 
       885 
     | 
    
         
            -
                      }
         
     | 
| 
       886 
     | 
    
         
            -
                    end
         
     | 
| 
      
 1296 
     | 
    
         
            +
                    validate_index_length!(table_name, index_name, internal)
         
     | 
| 
       887 
1297 
     | 
    
         | 
| 
       888 
     | 
    
         
            -
                     
     | 
| 
      
 1298 
     | 
    
         
            +
                    index = IndexDefinition.new(
         
     | 
| 
      
 1299 
     | 
    
         
            +
                      table_name, index_name,
         
     | 
| 
      
 1300 
     | 
    
         
            +
                      options[:unique],
         
     | 
| 
      
 1301 
     | 
    
         
            +
                      column_names,
         
     | 
| 
      
 1302 
     | 
    
         
            +
                      lengths: options[:length] || {},
         
     | 
| 
      
 1303 
     | 
    
         
            +
                      orders: options[:order] || {},
         
     | 
| 
      
 1304 
     | 
    
         
            +
                      opclasses: options[:opclass] || {},
         
     | 
| 
      
 1305 
     | 
    
         
            +
                      where: options[:where],
         
     | 
| 
      
 1306 
     | 
    
         
            +
                      type: options[:type],
         
     | 
| 
      
 1307 
     | 
    
         
            +
                      using: options[:using],
         
     | 
| 
      
 1308 
     | 
    
         
            +
                      comment: options[:comment]
         
     | 
| 
      
 1309 
     | 
    
         
            +
                    )
         
     | 
| 
       889 
1310 
     | 
    
         | 
| 
       890 
     | 
    
         
            -
                     
     | 
| 
       891 
     | 
    
         
            -
             
     | 
| 
       892 
     | 
    
         
            -
                    end
         
     | 
| 
      
 1311 
     | 
    
         
            +
                    [index, index_algorithm(options[:algorithm]), if_not_exists]
         
     | 
| 
      
 1312 
     | 
    
         
            +
                  end
         
     | 
| 
       893 
1313 
     | 
    
         | 
| 
       894 
     | 
    
         
            -
             
     | 
| 
       895 
     | 
    
         
            -
             
     | 
| 
       896 
     | 
    
         
            -
             
     | 
| 
       897 
     | 
    
         
            -
                    if  
     | 
| 
       898 
     | 
    
         
            -
             
     | 
| 
      
 1314 
     | 
    
         
            +
                  def index_algorithm(algorithm) # :nodoc:
         
     | 
| 
      
 1315 
     | 
    
         
            +
                    index_algorithms.fetch(algorithm) do
         
     | 
| 
      
 1316 
     | 
    
         
            +
                      raise ArgumentError, "Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}"
         
     | 
| 
      
 1317 
     | 
    
         
            +
                    end if algorithm
         
     | 
| 
      
 1318 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1319 
     | 
    
         
            +
             
     | 
| 
      
 1320 
     | 
    
         
            +
                  def quoted_columns_for_index(column_names, options) # :nodoc:
         
     | 
| 
      
 1321 
     | 
    
         
            +
                    quoted_columns = column_names.each_with_object({}) do |name, result|
         
     | 
| 
      
 1322 
     | 
    
         
            +
                      result[name.to_sym] = quote_column_name(name).dup
         
     | 
| 
       899 
1323 
     | 
    
         
             
                    end
         
     | 
| 
       900 
     | 
    
         
            -
                     
     | 
| 
      
 1324 
     | 
    
         
            +
                    add_options_for_index_columns(quoted_columns, **options).values.join(", ")
         
     | 
| 
      
 1325 
     | 
    
         
            +
                  end
         
     | 
| 
       901 
1326 
     | 
    
         | 
| 
       902 
     | 
    
         
            -
             
     | 
| 
      
 1327 
     | 
    
         
            +
                  def options_include_default?(options)
         
     | 
| 
      
 1328 
     | 
    
         
            +
                    options.include?(:default) && !(options[:null] == false && options[:default].nil?)
         
     | 
| 
       903 
1329 
     | 
    
         
             
                  end
         
     | 
| 
       904 
1330 
     | 
    
         | 
| 
       905 
     | 
    
         
            -
                   
     | 
| 
       906 
     | 
    
         
            -
             
     | 
| 
       907 
     | 
    
         
            -
             
     | 
| 
       908 
     | 
    
         
            -
             
     | 
| 
       909 
     | 
    
         
            -
             
     | 
| 
       910 
     | 
    
         
            -
             
     | 
| 
       911 
     | 
    
         
            -
             
     | 
| 
       912 
     | 
    
         
            -
             
     | 
| 
       913 
     | 
    
         
            -
             
     | 
| 
       914 
     | 
    
         
            -
             
     | 
| 
      
 1331 
     | 
    
         
            +
                  # Changes the comment for a table or removes it if +nil+.
         
     | 
| 
      
 1332 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1333 
     | 
    
         
            +
                  # Passing a hash containing +:from+ and +:to+ will make this change
         
     | 
| 
      
 1334 
     | 
    
         
            +
                  # reversible in migration:
         
     | 
| 
      
 1335 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1336 
     | 
    
         
            +
                  #   change_table_comment(:posts, from: "old_comment", to: "new_comment")
         
     | 
| 
      
 1337 
     | 
    
         
            +
                  def change_table_comment(table_name, comment_or_changes)
         
     | 
| 
      
 1338 
     | 
    
         
            +
                    raise NotImplementedError, "#{self.class} does not support changing table comments"
         
     | 
| 
      
 1339 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1340 
     | 
    
         
            +
             
     | 
| 
      
 1341 
     | 
    
         
            +
                  # Changes the comment for a column or removes it if +nil+.
         
     | 
| 
      
 1342 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1343 
     | 
    
         
            +
                  # Passing a hash containing +:from+ and +:to+ will make this change
         
     | 
| 
      
 1344 
     | 
    
         
            +
                  # reversible in migration:
         
     | 
| 
      
 1345 
     | 
    
         
            +
                  #
         
     | 
| 
      
 1346 
     | 
    
         
            +
                  #   change_column_comment(:posts, :state, from: "old_comment", to: "new_comment")
         
     | 
| 
      
 1347 
     | 
    
         
            +
                  def change_column_comment(table_name, column_name, comment_or_changes)
         
     | 
| 
      
 1348 
     | 
    
         
            +
                    raise NotImplementedError, "#{self.class} does not support changing column comments"
         
     | 
| 
      
 1349 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1350 
     | 
    
         
            +
             
     | 
| 
      
 1351 
     | 
    
         
            +
                  def create_schema_dumper(options) # :nodoc:
         
     | 
| 
      
 1352 
     | 
    
         
            +
                    SchemaDumper.create(self, options)
         
     | 
| 
      
 1353 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1354 
     | 
    
         
            +
             
     | 
| 
      
 1355 
     | 
    
         
            +
                  private
         
     | 
| 
      
 1356 
     | 
    
         
            +
                    def column_options_keys
         
     | 
| 
      
 1357 
     | 
    
         
            +
                      [:limit, :precision, :scale, :default, :null, :collation, :comment]
         
     | 
| 
      
 1358 
     | 
    
         
            +
                    end
         
     | 
| 
       915 
1359 
     | 
    
         | 
| 
       916 
     | 
    
         
            -
             
     | 
| 
      
 1360 
     | 
    
         
            +
                    def add_index_sort_order(quoted_columns, **options)
         
     | 
| 
      
 1361 
     | 
    
         
            +
                      orders = options_for_index_columns(options[:order])
         
     | 
| 
      
 1362 
     | 
    
         
            +
                      quoted_columns.each do |name, column|
         
     | 
| 
      
 1363 
     | 
    
         
            +
                        column << " #{orders[name].upcase}" if orders[name].present?
         
     | 
| 
      
 1364 
     | 
    
         
            +
                      end
         
     | 
| 
       917 
1365 
     | 
    
         
             
                    end
         
     | 
| 
       918 
1366 
     | 
    
         | 
| 
       919 
     | 
    
         
            -
                     
     | 
| 
       920 
     | 
    
         
            -
             
     | 
| 
       921 
     | 
    
         
            -
             
     | 
| 
      
 1367 
     | 
    
         
            +
                    def options_for_index_columns(options)
         
     | 
| 
      
 1368 
     | 
    
         
            +
                      if options.is_a?(Hash)
         
     | 
| 
      
 1369 
     | 
    
         
            +
                        options.symbolize_keys
         
     | 
| 
      
 1370 
     | 
    
         
            +
                      else
         
     | 
| 
      
 1371 
     | 
    
         
            +
                        Hash.new { |hash, column| hash[column] = options }
         
     | 
| 
      
 1372 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1373 
     | 
    
         
            +
                    end
         
     | 
| 
       922 
1374 
     | 
    
         | 
| 
       923 
     | 
    
         
            -
             
     | 
| 
      
 1375 
     | 
    
         
            +
                    # Overridden by the MySQL adapter for supporting index lengths and by
         
     | 
| 
      
 1376 
     | 
    
         
            +
                    # the PostgreSQL adapter for supporting operator classes.
         
     | 
| 
      
 1377 
     | 
    
         
            +
                    def add_options_for_index_columns(quoted_columns, **options)
         
     | 
| 
       924 
1378 
     | 
    
         
             
                      if supports_index_sort_order?
         
     | 
| 
       925 
     | 
    
         
            -
                         
     | 
| 
      
 1379 
     | 
    
         
            +
                        quoted_columns = add_index_sort_order(quoted_columns, **options)
         
     | 
| 
       926 
1380 
     | 
    
         
             
                      end
         
     | 
| 
       927 
1381 
     | 
    
         | 
| 
       928 
     | 
    
         
            -
                       
     | 
| 
      
 1382 
     | 
    
         
            +
                      quoted_columns
         
     | 
| 
       929 
1383 
     | 
    
         
             
                    end
         
     | 
| 
       930 
1384 
     | 
    
         | 
| 
       931 
     | 
    
         
            -
                    def  
     | 
| 
       932 
     | 
    
         
            -
                       
     | 
| 
       933 
     | 
    
         
            -
                    end
         
     | 
| 
      
 1385 
     | 
    
         
            +
                    def index_name_for_remove(table_name, column_name, options)
         
     | 
| 
      
 1386 
     | 
    
         
            +
                      return options[:name] if can_remove_index_by_name?(column_name, options)
         
     | 
| 
       934 
1387 
     | 
    
         | 
| 
       935 
     | 
    
         
            -
             
     | 
| 
       936 
     | 
    
         
            -
                      index_name = index_name(table_name, options)
         
     | 
| 
      
 1388 
     | 
    
         
            +
                      checks = []
         
     | 
| 
       937 
1389 
     | 
    
         | 
| 
       938 
     | 
    
         
            -
                       
     | 
| 
       939 
     | 
    
         
            -
                         
     | 
| 
       940 
     | 
    
         
            -
             
     | 
| 
       941 
     | 
    
         
            -
             
     | 
| 
       942 
     | 
    
         
            -
             
     | 
| 
      
 1390 
     | 
    
         
            +
                      if !options.key?(:name) && column_name.is_a?(String) && /\W/.match?(column_name)
         
     | 
| 
      
 1391 
     | 
    
         
            +
                        options[:name] = index_name(table_name, column_name)
         
     | 
| 
      
 1392 
     | 
    
         
            +
                        column_names = []
         
     | 
| 
      
 1393 
     | 
    
         
            +
                      else
         
     | 
| 
      
 1394 
     | 
    
         
            +
                        column_names = index_column_names(column_name || options[:column])
         
     | 
| 
      
 1395 
     | 
    
         
            +
                      end
         
     | 
| 
       943 
1396 
     | 
    
         | 
| 
       944 
     | 
    
         
            -
             
     | 
| 
       945 
     | 
    
         
            -
                        end
         
     | 
| 
      
 1397 
     | 
    
         
            +
                      checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
         
     | 
| 
       946 
1398 
     | 
    
         | 
| 
       947 
     | 
    
         
            -
             
     | 
| 
      
 1399 
     | 
    
         
            +
                      if column_names.present?
         
     | 
| 
      
 1400 
     | 
    
         
            +
                        checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
         
     | 
| 
       948 
1401 
     | 
    
         
             
                      end
         
     | 
| 
       949 
1402 
     | 
    
         | 
| 
       950 
     | 
    
         
            -
                       
     | 
| 
      
 1403 
     | 
    
         
            +
                      raise ArgumentError, "No name or columns specified" if checks.none?
         
     | 
| 
      
 1404 
     | 
    
         
            +
             
     | 
| 
      
 1405 
     | 
    
         
            +
                      matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } }
         
     | 
| 
      
 1406 
     | 
    
         
            +
             
     | 
| 
      
 1407 
     | 
    
         
            +
                      if matching_indexes.count > 1
         
     | 
| 
      
 1408 
     | 
    
         
            +
                        raise ArgumentError, "Multiple indexes found on #{table_name} columns #{column_names}. " \
         
     | 
| 
      
 1409 
     | 
    
         
            +
                                             "Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
         
     | 
| 
      
 1410 
     | 
    
         
            +
                      elsif matching_indexes.none?
         
     | 
| 
      
 1411 
     | 
    
         
            +
                        raise ArgumentError, "No indexes found on #{table_name} with the options provided."
         
     | 
| 
      
 1412 
     | 
    
         
            +
                      else
         
     | 
| 
      
 1413 
     | 
    
         
            +
                        matching_indexes.first.name
         
     | 
| 
      
 1414 
     | 
    
         
            +
                      end
         
     | 
| 
       951 
1415 
     | 
    
         
             
                    end
         
     | 
| 
       952 
1416 
     | 
    
         | 
| 
       953 
1417 
     | 
    
         
             
                    def rename_table_indexes(table_name, new_name)
         
     | 
| 
         @@ -972,20 +1436,202 @@ module ActiveRecord 
     | 
|
| 
       972 
1436 
     | 
    
         
             
                      end
         
     | 
| 
       973 
1437 
     | 
    
         
             
                    end
         
     | 
| 
       974 
1438 
     | 
    
         | 
| 
       975 
     | 
    
         
            -
             
     | 
| 
       976 
     | 
    
         
            -
             
     | 
| 
       977 
     | 
    
         
            -
                     
     | 
| 
       978 
     | 
    
         
            -
                  end
         
     | 
| 
      
 1439 
     | 
    
         
            +
                    def schema_creation
         
     | 
| 
      
 1440 
     | 
    
         
            +
                      SchemaCreation.new(self)
         
     | 
| 
      
 1441 
     | 
    
         
            +
                    end
         
     | 
| 
       979 
1442 
     | 
    
         | 
| 
       980 
     | 
    
         
            -
             
     | 
| 
       981 
     | 
    
         
            -
             
     | 
| 
       982 
     | 
    
         
            -
             
     | 
| 
      
 1443 
     | 
    
         
            +
                    def create_table_definition(name, **options)
         
     | 
| 
      
 1444 
     | 
    
         
            +
                      TableDefinition.new(self, name, **options)
         
     | 
| 
      
 1445 
     | 
    
         
            +
                    end
         
     | 
| 
       983 
1446 
     | 
    
         | 
| 
       984 
     | 
    
         
            -
             
     | 
| 
       985 
     | 
    
         
            -
             
     | 
| 
       986 
     | 
    
         
            -
             
     | 
| 
      
 1447 
     | 
    
         
            +
                    def create_alter_table(name)
         
     | 
| 
      
 1448 
     | 
    
         
            +
                      AlterTable.new create_table_definition(name)
         
     | 
| 
      
 1449 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1450 
     | 
    
         
            +
             
     | 
| 
      
 1451 
     | 
    
         
            +
                    def extract_table_options!(options)
         
     | 
| 
      
 1452 
     | 
    
         
            +
                      options.extract!(:temporary, :if_not_exists, :options, :as, :comment, :charset, :collation)
         
     | 
| 
      
 1453 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1454 
     | 
    
         
            +
             
     | 
| 
      
 1455 
     | 
    
         
            +
                    def fetch_type_metadata(sql_type)
         
     | 
| 
      
 1456 
     | 
    
         
            +
                      cast_type = lookup_cast_type(sql_type)
         
     | 
| 
      
 1457 
     | 
    
         
            +
                      SqlTypeMetadata.new(
         
     | 
| 
      
 1458 
     | 
    
         
            +
                        sql_type: sql_type,
         
     | 
| 
      
 1459 
     | 
    
         
            +
                        type: cast_type.type,
         
     | 
| 
      
 1460 
     | 
    
         
            +
                        limit: cast_type.limit,
         
     | 
| 
      
 1461 
     | 
    
         
            +
                        precision: cast_type.precision,
         
     | 
| 
      
 1462 
     | 
    
         
            +
                        scale: cast_type.scale,
         
     | 
| 
      
 1463 
     | 
    
         
            +
                      )
         
     | 
| 
      
 1464 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1465 
     | 
    
         
            +
             
     | 
| 
      
 1466 
     | 
    
         
            +
                    def index_column_names(column_names)
         
     | 
| 
      
 1467 
     | 
    
         
            +
                      if column_names.is_a?(String) && /\W/.match?(column_names)
         
     | 
| 
      
 1468 
     | 
    
         
            +
                        column_names
         
     | 
| 
      
 1469 
     | 
    
         
            +
                      else
         
     | 
| 
      
 1470 
     | 
    
         
            +
                        Array(column_names)
         
     | 
| 
      
 1471 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1472 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1473 
     | 
    
         
            +
             
     | 
| 
      
 1474 
     | 
    
         
            +
                    def index_name_options(column_names)
         
     | 
| 
      
 1475 
     | 
    
         
            +
                      if column_names.is_a?(String) && /\W/.match?(column_names)
         
     | 
| 
      
 1476 
     | 
    
         
            +
                        column_names = column_names.scan(/\w+/).join("_")
         
     | 
| 
      
 1477 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1478 
     | 
    
         
            +
             
     | 
| 
      
 1479 
     | 
    
         
            +
                      { column: column_names }
         
     | 
| 
      
 1480 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1481 
     | 
    
         
            +
             
     | 
| 
      
 1482 
     | 
    
         
            +
                    def strip_table_name_prefix_and_suffix(table_name)
         
     | 
| 
      
 1483 
     | 
    
         
            +
                      prefix = Base.table_name_prefix
         
     | 
| 
      
 1484 
     | 
    
         
            +
                      suffix = Base.table_name_suffix
         
     | 
| 
      
 1485 
     | 
    
         
            +
                      table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
         
     | 
| 
      
 1486 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1487 
     | 
    
         
            +
             
     | 
| 
      
 1488 
     | 
    
         
            +
                    def foreign_key_name(table_name, options)
         
     | 
| 
      
 1489 
     | 
    
         
            +
                      options.fetch(:name) do
         
     | 
| 
      
 1490 
     | 
    
         
            +
                        identifier = "#{table_name}_#{options.fetch(:column)}_fk"
         
     | 
| 
      
 1491 
     | 
    
         
            +
                        hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
         
     | 
| 
      
 1492 
     | 
    
         
            +
             
     | 
| 
      
 1493 
     | 
    
         
            +
                        "fk_rails_#{hashed_identifier}"
         
     | 
| 
      
 1494 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1495 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1496 
     | 
    
         
            +
             
     | 
| 
      
 1497 
     | 
    
         
            +
                    def foreign_key_for(from_table, **options)
         
     | 
| 
      
 1498 
     | 
    
         
            +
                      return unless supports_foreign_keys?
         
     | 
| 
      
 1499 
     | 
    
         
            +
                      foreign_keys(from_table).detect { |fk| fk.defined_for?(**options) }
         
     | 
| 
      
 1500 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1501 
     | 
    
         
            +
             
     | 
| 
      
 1502 
     | 
    
         
            +
                    def foreign_key_for!(from_table, to_table: nil, **options)
         
     | 
| 
      
 1503 
     | 
    
         
            +
                      foreign_key_for(from_table, to_table: to_table, **options) ||
         
     | 
| 
      
 1504 
     | 
    
         
            +
                        raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
         
     | 
| 
      
 1505 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1506 
     | 
    
         
            +
             
     | 
| 
      
 1507 
     | 
    
         
            +
                    def extract_foreign_key_action(specifier)
         
     | 
| 
      
 1508 
     | 
    
         
            +
                      case specifier
         
     | 
| 
      
 1509 
     | 
    
         
            +
                      when "CASCADE"; :cascade
         
     | 
| 
      
 1510 
     | 
    
         
            +
                      when "SET NULL"; :nullify
         
     | 
| 
      
 1511 
     | 
    
         
            +
                      when "RESTRICT"; :restrict
         
     | 
| 
      
 1512 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1513 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1514 
     | 
    
         
            +
             
     | 
| 
      
 1515 
     | 
    
         
            +
                    def check_constraint_name(table_name, **options)
         
     | 
| 
      
 1516 
     | 
    
         
            +
                      options.fetch(:name) do
         
     | 
| 
      
 1517 
     | 
    
         
            +
                        expression = options.fetch(:expression)
         
     | 
| 
      
 1518 
     | 
    
         
            +
                        identifier = "#{table_name}_#{expression}_chk"
         
     | 
| 
      
 1519 
     | 
    
         
            +
                        hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
         
     | 
| 
      
 1520 
     | 
    
         
            +
             
     | 
| 
      
 1521 
     | 
    
         
            +
                        "chk_rails_#{hashed_identifier}"
         
     | 
| 
      
 1522 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1523 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1524 
     | 
    
         
            +
             
     | 
| 
      
 1525 
     | 
    
         
            +
                    def check_constraint_for(table_name, **options)
         
     | 
| 
      
 1526 
     | 
    
         
            +
                      return unless supports_check_constraints?
         
     | 
| 
      
 1527 
     | 
    
         
            +
                      chk_name = check_constraint_name(table_name, **options)
         
     | 
| 
      
 1528 
     | 
    
         
            +
                      check_constraints(table_name).detect { |chk| chk.name == chk_name }
         
     | 
| 
      
 1529 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1530 
     | 
    
         
            +
             
     | 
| 
      
 1531 
     | 
    
         
            +
                    def check_constraint_for!(table_name, expression: nil, **options)
         
     | 
| 
      
 1532 
     | 
    
         
            +
                      check_constraint_for(table_name, expression: expression, **options) ||
         
     | 
| 
      
 1533 
     | 
    
         
            +
                        raise(ArgumentError, "Table '#{table_name}' has no check constraint for #{expression || options}")
         
     | 
| 
      
 1534 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1535 
     | 
    
         
            +
             
     | 
| 
      
 1536 
     | 
    
         
            +
                    def validate_index_length!(table_name, new_name, internal = false)
         
     | 
| 
      
 1537 
     | 
    
         
            +
                      if new_name.length > index_name_length
         
     | 
| 
      
 1538 
     | 
    
         
            +
                        raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters"
         
     | 
| 
      
 1539 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1540 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1541 
     | 
    
         
            +
             
     | 
| 
      
 1542 
     | 
    
         
            +
                    def extract_new_default_value(default_or_changes)
         
     | 
| 
      
 1543 
     | 
    
         
            +
                      if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
         
     | 
| 
      
 1544 
     | 
    
         
            +
                        default_or_changes[:to]
         
     | 
| 
      
 1545 
     | 
    
         
            +
                      else
         
     | 
| 
      
 1546 
     | 
    
         
            +
                        default_or_changes
         
     | 
| 
      
 1547 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1548 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1549 
     | 
    
         
            +
                    alias :extract_new_comment_value :extract_new_default_value
         
     | 
| 
      
 1550 
     | 
    
         
            +
             
     | 
| 
      
 1551 
     | 
    
         
            +
                    def can_remove_index_by_name?(column_name, options)
         
     | 
| 
      
 1552 
     | 
    
         
            +
                      column_name.nil? && options.key?(:name) && options.except(:name, :algorithm).empty?
         
     | 
| 
      
 1553 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1554 
     | 
    
         
            +
             
     | 
| 
      
 1555 
     | 
    
         
            +
                    def bulk_change_table(table_name, operations)
         
     | 
| 
      
 1556 
     | 
    
         
            +
                      sql_fragments = []
         
     | 
| 
      
 1557 
     | 
    
         
            +
                      non_combinable_operations = []
         
     | 
| 
      
 1558 
     | 
    
         
            +
             
     | 
| 
      
 1559 
     | 
    
         
            +
                      operations.each do |command, args|
         
     | 
| 
      
 1560 
     | 
    
         
            +
                        table, arguments = args.shift, args
         
     | 
| 
      
 1561 
     | 
    
         
            +
                        method = :"#{command}_for_alter"
         
     | 
| 
      
 1562 
     | 
    
         
            +
             
     | 
| 
      
 1563 
     | 
    
         
            +
                        if respond_to?(method, true)
         
     | 
| 
      
 1564 
     | 
    
         
            +
                          sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
         
     | 
| 
      
 1565 
     | 
    
         
            +
                          sql_fragments << sqls
         
     | 
| 
      
 1566 
     | 
    
         
            +
                          non_combinable_operations.concat(procs)
         
     | 
| 
      
 1567 
     | 
    
         
            +
                        else
         
     | 
| 
      
 1568 
     | 
    
         
            +
                          execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
         
     | 
| 
      
 1569 
     | 
    
         
            +
                          non_combinable_operations.each(&:call)
         
     | 
| 
      
 1570 
     | 
    
         
            +
                          sql_fragments = []
         
     | 
| 
      
 1571 
     | 
    
         
            +
                          non_combinable_operations = []
         
     | 
| 
      
 1572 
     | 
    
         
            +
                          send(command, table, *arguments)
         
     | 
| 
      
 1573 
     | 
    
         
            +
                        end
         
     | 
| 
      
 1574 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1575 
     | 
    
         
            +
             
     | 
| 
      
 1576 
     | 
    
         
            +
                      execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
         
     | 
| 
      
 1577 
     | 
    
         
            +
                      non_combinable_operations.each(&:call)
         
     | 
| 
      
 1578 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1579 
     | 
    
         
            +
             
     | 
| 
      
 1580 
     | 
    
         
            +
                    def add_column_for_alter(table_name, column_name, type, **options)
         
     | 
| 
      
 1581 
     | 
    
         
            +
                      td = create_table_definition(table_name)
         
     | 
| 
      
 1582 
     | 
    
         
            +
                      cd = td.new_column_definition(column_name, type, **options)
         
     | 
| 
      
 1583 
     | 
    
         
            +
                      schema_creation.accept(AddColumnDefinition.new(cd))
         
     | 
| 
      
 1584 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1585 
     | 
    
         
            +
             
     | 
| 
      
 1586 
     | 
    
         
            +
                    def rename_column_sql(table_name, column_name, new_column_name)
         
     | 
| 
      
 1587 
     | 
    
         
            +
                      "RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
         
     | 
| 
      
 1588 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1589 
     | 
    
         
            +
             
     | 
| 
      
 1590 
     | 
    
         
            +
                    def remove_column_for_alter(table_name, column_name, type = nil, **options)
         
     | 
| 
      
 1591 
     | 
    
         
            +
                      "DROP COLUMN #{quote_column_name(column_name)}"
         
     | 
| 
      
 1592 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1593 
     | 
    
         
            +
             
     | 
| 
      
 1594 
     | 
    
         
            +
                    def remove_columns_for_alter(table_name, *column_names, **options)
         
     | 
| 
      
 1595 
     | 
    
         
            +
                      column_names.map { |column_name| remove_column_for_alter(table_name, column_name) }
         
     | 
| 
      
 1596 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1597 
     | 
    
         
            +
             
     | 
| 
      
 1598 
     | 
    
         
            +
                    def add_timestamps_for_alter(table_name, **options)
         
     | 
| 
      
 1599 
     | 
    
         
            +
                      options[:null] = false if options[:null].nil?
         
     | 
| 
      
 1600 
     | 
    
         
            +
             
     | 
| 
      
 1601 
     | 
    
         
            +
                      if !options.key?(:precision) && supports_datetime_with_precision?
         
     | 
| 
      
 1602 
     | 
    
         
            +
                        options[:precision] = 6
         
     | 
| 
      
 1603 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1604 
     | 
    
         
            +
             
     | 
| 
      
 1605 
     | 
    
         
            +
                      [
         
     | 
| 
      
 1606 
     | 
    
         
            +
                        add_column_for_alter(table_name, :created_at, :datetime, **options),
         
     | 
| 
      
 1607 
     | 
    
         
            +
                        add_column_for_alter(table_name, :updated_at, :datetime, **options)
         
     | 
| 
      
 1608 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 1609 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1610 
     | 
    
         
            +
             
     | 
| 
      
 1611 
     | 
    
         
            +
                    def remove_timestamps_for_alter(table_name, **options)
         
     | 
| 
      
 1612 
     | 
    
         
            +
                      remove_columns_for_alter(table_name, :updated_at, :created_at)
         
     | 
| 
      
 1613 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1614 
     | 
    
         
            +
             
     | 
| 
      
 1615 
     | 
    
         
            +
                    def insert_versions_sql(versions)
         
     | 
| 
      
 1616 
     | 
    
         
            +
                      sm_table = quote_table_name(schema_migration.table_name)
         
     | 
| 
      
 1617 
     | 
    
         
            +
             
     | 
| 
      
 1618 
     | 
    
         
            +
                      if versions.is_a?(Array)
         
     | 
| 
      
 1619 
     | 
    
         
            +
                        sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
         
     | 
| 
      
 1620 
     | 
    
         
            +
                        sql << versions.map { |v| "(#{quote(v)})" }.join(",\n")
         
     | 
| 
      
 1621 
     | 
    
         
            +
                        sql << ";\n\n"
         
     | 
| 
      
 1622 
     | 
    
         
            +
                        sql
         
     | 
| 
      
 1623 
     | 
    
         
            +
                      else
         
     | 
| 
      
 1624 
     | 
    
         
            +
                        "INSERT INTO #{sm_table} (version) VALUES (#{quote(versions)});"
         
     | 
| 
      
 1625 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1626 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1627 
     | 
    
         
            +
             
     | 
| 
      
 1628 
     | 
    
         
            +
                    def data_source_sql(name = nil, type: nil)
         
     | 
| 
      
 1629 
     | 
    
         
            +
                      raise NotImplementedError
         
     | 
| 
      
 1630 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1631 
     | 
    
         
            +
             
     | 
| 
      
 1632 
     | 
    
         
            +
                    def quoted_scope(name = nil, type: nil)
         
     | 
| 
      
 1633 
     | 
    
         
            +
                      raise NotImplementedError
         
     | 
| 
       987 
1634 
     | 
    
         
             
                    end
         
     | 
| 
       988 
     | 
    
         
            -
                  end
         
     | 
| 
       989 
1635 
     | 
    
         
             
                end
         
     | 
| 
       990 
1636 
     | 
    
         
             
              end
         
     | 
| 
       991 
1637 
     | 
    
         
             
            end
         
     |