activerecord 5.2.8 → 7.0.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1393 -587
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +10 -9
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +122 -47
- data/lib/active_record/associations/association_scope.rb +24 -24
- data/lib/active_record/associations/belongs_to_association.rb +67 -49
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -7
- data/lib/active_record/associations/builder/association.rb +52 -23
- data/lib/active_record/associations/builder/belongs_to.rb +44 -61
- data/lib/active_record/associations/builder/collection_association.rb +17 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +10 -3
- data/lib/active_record/associations/builder/has_one.rb +35 -3
- data/lib/active_record/associations/builder/singular_association.rb +5 -3
- data/lib/active_record/associations/collection_association.rb +59 -50
- data/lib/active_record/associations/collection_proxy.rb +32 -23
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +27 -14
- data/lib/active_record/associations/has_many_through_association.rb +26 -19
- data/lib/active_record/associations/has_one_association.rb +52 -37
- data/lib/active_record/associations/has_one_through_association.rb +6 -6
- data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +97 -62
- data/lib/active_record/associations/preloader/association.rb +220 -60
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +85 -40
- data/lib/active_record/associations/preloader.rb +44 -105
- data/lib/active_record/associations/singular_association.rb +9 -17
- data/lib/active_record/associations/through_association.rb +4 -4
- data/lib/active_record/associations.rb +207 -66
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +19 -8
- data/lib/active_record/attribute_methods/dirty.rb +141 -47
- data/lib/active_record/attribute_methods/primary_key.rb +22 -27
- data/lib/active_record/attribute_methods/query.rb +6 -10
- data/lib/active_record/attribute_methods/read.rb +15 -55
- data/lib/active_record/attribute_methods/serialization.rb +77 -18
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +16 -18
- data/lib/active_record/attribute_methods/write.rb +18 -37
- data/lib/active_record/attribute_methods.rb +90 -153
- data/lib/active_record/attributes.rb +38 -12
- data/lib/active_record/autosave_association.rb +50 -50
- data/lib/active_record/base.rb +23 -18
- data/lib/active_record/callbacks.rb +159 -44
- data/lib/active_record/coders/yaml_column.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +92 -464
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -51
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +209 -164
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +38 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +103 -82
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +140 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -94
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +16 -5
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +456 -159
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -162
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +311 -327
- data/lib/active_record/connection_adapters/column.rb +33 -11
- 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 +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +113 -45
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +71 -5
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +25 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +143 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +63 -22
- 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 +53 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +56 -63
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +54 -16
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +26 -12
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +128 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +149 -113
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +386 -182
- data/lib/active_record/connection_adapters/schema_cache.rb +161 -22
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +65 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +92 -26
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +251 -204
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +53 -0
- data/lib/active_record/connection_handling.rb +292 -38
- data/lib/active_record/core.rb +385 -158
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +100 -0
- data/lib/active_record/database_configurations/database_config.rb +83 -0
- data/lib/active_record/database_configurations/hash_config.rb +154 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +256 -0
- data/lib/active_record/delegated_type.rb +250 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +4 -5
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +130 -51
- data/lib/active_record/errors.rb +129 -23
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +22 -15
- 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 +187 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +206 -490
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +104 -37
- data/lib/active_record/insert_all.rb +278 -0
- data/lib/active_record/integration.rb +69 -18
- data/lib/active_record/internal_metadata.rb +24 -9
- data/lib/active_record/legacy_yaml_adapter.rb +3 -36
- data/lib/active_record/locking/optimistic.rb +41 -26
- data/lib/active_record/locking/pessimistic.rb +18 -8
- data/lib/active_record/log_subscriber.rb +46 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector.rb +82 -0
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +246 -64
- data/lib/active_record/migration/join_table.rb +1 -2
- data/lib/active_record/migration.rb +266 -187
- data/lib/active_record/model_schema.rb +165 -52
- data/lib/active_record/nested_attributes.rb +17 -19
- data/lib/active_record/no_touching.rb +11 -4
- data/lib/active_record/null_relation.rb +2 -7
- data/lib/active_record/persistence.rb +467 -92
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +51 -24
- data/lib/active_record/railtie.rb +224 -57
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +31 -36
- data/lib/active_record/railties/databases.rake +369 -101
- data/lib/active_record/readonly_attributes.rb +15 -0
- data/lib/active_record/reflection.rb +170 -137
- data/lib/active_record/relation/batches/batch_enumerator.rb +44 -14
- data/lib/active_record/relation/batches.rb +46 -37
- data/lib/active_record/relation/calculations.rb +168 -96
- data/lib/active_record/relation/delegation.rb +37 -52
- data/lib/active_record/relation/finder_methods.rb +79 -58
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +50 -51
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +58 -46
- data/lib/active_record/relation/query_attribute.rb +9 -10
- data/lib/active_record/relation/query_methods.rb +685 -208
- data/lib/active_record/relation/record_fetch_warning.rb +9 -11
- data/lib/active_record/relation/spawn_methods.rb +10 -10
- data/lib/active_record/relation/where_clause.rb +108 -64
- data/lib/active_record/relation.rb +515 -151
- data/lib/active_record/result.rb +78 -42
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +29 -44
- data/lib/active_record/schema.rb +37 -31
- data/lib/active_record/schema_dumper.rb +74 -23
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +62 -17
- data/lib/active_record/scoping/named.rb +17 -32
- data/lib/active_record/scoping.rb +70 -41
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +6 -4
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +49 -6
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +13 -17
- data/lib/active_record/table_metadata.rb +42 -43
- data/lib/active_record/tasks/database_tasks.rb +352 -94
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +41 -39
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +44 -34
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +67 -128
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +34 -19
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +7 -4
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +17 -21
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +9 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +2 -3
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +39 -31
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +209 -32
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +33 -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 +48 -0
- data/lib/arel/delete_manager.rb +32 -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/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +48 -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 +44 -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/filter.rb +10 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +45 -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 +46 -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 +71 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +258 -0
- data/lib/arel/select_manager.rb +276 -0
- data/lib/arel/table.rb +117 -0
- data/lib/arel/tree_manager.rb +60 -0
- data/lib/arel/update_manager.rb +48 -0
- data/lib/arel/visitors/dot.rb +298 -0
- data/lib/arel/visitors/mysql.rb +99 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +955 -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 +55 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +162 -32
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -4,17 +4,20 @@ require "active_record/connection_adapters/abstract_adapter"
|
|
4
4
|
require "active_record/connection_adapters/statement_pool"
|
5
5
|
require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
|
6
6
|
require "active_record/connection_adapters/sqlite3/quoting"
|
7
|
+
require "active_record/connection_adapters/sqlite3/database_statements"
|
7
8
|
require "active_record/connection_adapters/sqlite3/schema_creation"
|
8
9
|
require "active_record/connection_adapters/sqlite3/schema_definitions"
|
9
10
|
require "active_record/connection_adapters/sqlite3/schema_dumper"
|
10
11
|
require "active_record/connection_adapters/sqlite3/schema_statements"
|
11
12
|
|
12
|
-
gem "sqlite3", "~> 1.
|
13
|
+
gem "sqlite3", "~> 1.4"
|
13
14
|
require "sqlite3"
|
14
15
|
|
15
16
|
module ActiveRecord
|
16
17
|
module ConnectionHandling # :nodoc:
|
17
18
|
def sqlite3_connection(config)
|
19
|
+
config = config.symbolize_keys
|
20
|
+
|
18
21
|
# Require database.
|
19
22
|
unless config[:database]
|
20
23
|
raise ArgumentError, "No database file specified. Missing argument: database"
|
@@ -23,7 +26,7 @@ module ActiveRecord
|
|
23
26
|
# Allow database path relative to Rails.root, but only if the database
|
24
27
|
# path is not the special path that tells sqlite to build a database only
|
25
28
|
# in memory.
|
26
|
-
if ":memory:" != config[:database]
|
29
|
+
if ":memory:" != config[:database] && !config[:database].to_s.start_with?("file:")
|
27
30
|
config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
|
28
31
|
dirname = File.dirname(config[:database])
|
29
32
|
Dir.mkdir(dirname) unless File.directory?(dirname)
|
@@ -31,11 +34,9 @@ module ActiveRecord
|
|
31
34
|
|
32
35
|
db = SQLite3::Database.new(
|
33
36
|
config[:database].to_s,
|
34
|
-
results_as_hash: true
|
37
|
+
config.merge(results_as_hash: true)
|
35
38
|
)
|
36
39
|
|
37
|
-
db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
|
38
|
-
|
39
40
|
ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
|
40
41
|
rescue Errno::ENOENT => error
|
41
42
|
if error.message.include?("No such file or directory")
|
@@ -46,18 +47,19 @@ module ActiveRecord
|
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
|
-
module ConnectionAdapters
|
50
|
-
# The SQLite3 adapter works
|
51
|
-
#
|
50
|
+
module ConnectionAdapters # :nodoc:
|
51
|
+
# The SQLite3 adapter works with the sqlite3-ruby drivers
|
52
|
+
# (available as gem from https://rubygems.org/gems/sqlite3).
|
52
53
|
#
|
53
54
|
# Options:
|
54
55
|
#
|
55
56
|
# * <tt>:database</tt> - Path to the database file.
|
56
57
|
class SQLite3Adapter < AbstractAdapter
|
57
|
-
ADAPTER_NAME = "SQLite"
|
58
|
+
ADAPTER_NAME = "SQLite"
|
58
59
|
|
59
60
|
include SQLite3::Quoting
|
60
61
|
include SQLite3::SchemaStatements
|
62
|
+
include SQLite3::DatabaseStatements
|
61
63
|
|
62
64
|
NATIVE_DATABASE_TYPES = {
|
63
65
|
primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
|
@@ -74,39 +76,29 @@ module ActiveRecord
|
|
74
76
|
json: { name: "json" },
|
75
77
|
}
|
76
78
|
|
77
|
-
##
|
78
|
-
# :singleton-method:
|
79
|
-
# Indicates whether boolean values are stored in sqlite3 databases as 1
|
80
|
-
# and 0 or 't' and 'f'. Leaving <tt>ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer</tt>
|
81
|
-
# set to false is deprecated. SQLite databases have used 't' and 'f' to
|
82
|
-
# serialize boolean values and must have old data converted to 1 and 0
|
83
|
-
# (its native boolean serialization) before setting this flag to true.
|
84
|
-
# Conversion can be accomplished by setting up a rake task which runs
|
85
|
-
#
|
86
|
-
# ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
|
87
|
-
# ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
|
88
|
-
# for all models and all boolean columns, after which the flag must be set
|
89
|
-
# to true by adding the following to your <tt>application.rb</tt> file:
|
90
|
-
#
|
91
|
-
# Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
|
92
|
-
class_attribute :represent_boolean_as_integer, default: false
|
93
|
-
|
94
79
|
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
95
80
|
private
|
96
81
|
def dealloc(stmt)
|
97
|
-
stmt
|
82
|
+
stmt.close unless stmt.closed?
|
98
83
|
end
|
99
84
|
end
|
100
85
|
|
101
86
|
def initialize(connection, logger, connection_options, config)
|
87
|
+
@memory_database = config[:database] == ":memory:"
|
102
88
|
super(connection, logger, config)
|
103
|
-
|
104
|
-
@active = true
|
105
|
-
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
106
|
-
|
107
89
|
configure_connection
|
108
90
|
end
|
109
91
|
|
92
|
+
def self.database_exists?(config)
|
93
|
+
config = config.symbolize_keys
|
94
|
+
if config[:database] == ":memory:"
|
95
|
+
true
|
96
|
+
else
|
97
|
+
database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
|
98
|
+
File.exist?(database_file)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
110
102
|
def supports_ddl_transactions?
|
111
103
|
true
|
112
104
|
end
|
@@ -115,16 +107,28 @@ module ActiveRecord
|
|
115
107
|
true
|
116
108
|
end
|
117
109
|
|
110
|
+
def supports_transaction_isolation?
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
118
114
|
def supports_partial_index?
|
119
|
-
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
def supports_expression_index?
|
119
|
+
database_version >= "3.9.0"
|
120
120
|
end
|
121
121
|
|
122
122
|
def requires_reloading?
|
123
123
|
true
|
124
124
|
end
|
125
125
|
|
126
|
-
def
|
127
|
-
|
126
|
+
def supports_foreign_keys?
|
127
|
+
true
|
128
|
+
end
|
129
|
+
|
130
|
+
def supports_check_constraints?
|
131
|
+
true
|
128
132
|
end
|
129
133
|
|
130
134
|
def supports_views?
|
@@ -139,43 +143,46 @@ module ActiveRecord
|
|
139
143
|
true
|
140
144
|
end
|
141
145
|
|
142
|
-
def
|
143
|
-
|
146
|
+
def supports_common_table_expressions?
|
147
|
+
database_version >= "3.8.3"
|
148
|
+
end
|
149
|
+
|
150
|
+
def supports_insert_on_conflict?
|
151
|
+
database_version >= "3.24.0"
|
152
|
+
end
|
153
|
+
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
154
|
+
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
155
|
+
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
156
|
+
|
157
|
+
def supports_concurrent_connections?
|
158
|
+
!@memory_database
|
144
159
|
end
|
145
160
|
|
146
161
|
def active?
|
147
|
-
|
162
|
+
!@connection.closed?
|
163
|
+
end
|
164
|
+
|
165
|
+
def reconnect!
|
166
|
+
super
|
167
|
+
connect if @connection.closed?
|
148
168
|
end
|
149
169
|
|
150
170
|
# Disconnects from the database if already connected. Otherwise, this
|
151
171
|
# method does nothing.
|
152
172
|
def disconnect!
|
153
173
|
super
|
154
|
-
@active = false
|
155
174
|
@connection.close rescue nil
|
156
175
|
end
|
157
176
|
|
158
|
-
# Clears the prepared statements cache.
|
159
|
-
def clear_cache!
|
160
|
-
@statements.clear
|
161
|
-
end
|
162
|
-
|
163
177
|
def supports_index_sort_order?
|
164
178
|
true
|
165
179
|
end
|
166
180
|
|
167
|
-
|
168
|
-
# characters. The rest is used by Rails internally to perform
|
169
|
-
# temporary rename operations
|
170
|
-
def allowed_index_name_length
|
171
|
-
index_name_length - 2
|
172
|
-
end
|
173
|
-
|
174
|
-
def native_database_types #:nodoc:
|
181
|
+
def native_database_types # :nodoc:
|
175
182
|
NATIVE_DATABASE_TYPES
|
176
183
|
end
|
177
184
|
|
178
|
-
# Returns the current database encoding format as a string,
|
185
|
+
# Returns the current database encoding format as a string, e.g. 'UTF-8'
|
179
186
|
def encoding
|
180
187
|
@connection.encoding.to_s
|
181
188
|
end
|
@@ -184,89 +191,28 @@ module ActiveRecord
|
|
184
191
|
true
|
185
192
|
end
|
186
193
|
|
194
|
+
def supports_lazy_transactions?
|
195
|
+
true
|
196
|
+
end
|
197
|
+
|
187
198
|
# REFERENTIAL INTEGRITY ====================================
|
188
199
|
|
189
200
|
def disable_referential_integrity # :nodoc:
|
190
|
-
|
201
|
+
old_foreign_keys = query_value("PRAGMA foreign_keys")
|
202
|
+
old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
|
191
203
|
|
192
204
|
begin
|
205
|
+
execute("PRAGMA defer_foreign_keys = ON")
|
193
206
|
execute("PRAGMA foreign_keys = OFF")
|
194
207
|
yield
|
195
208
|
ensure
|
196
|
-
execute("PRAGMA
|
197
|
-
|
198
|
-
end
|
199
|
-
|
200
|
-
#--
|
201
|
-
# DATABASE STATEMENTS ======================================
|
202
|
-
#++
|
203
|
-
|
204
|
-
def explain(arel, binds = [])
|
205
|
-
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
206
|
-
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
207
|
-
end
|
208
|
-
|
209
|
-
def exec_query(sql, name = nil, binds = [], prepare: false)
|
210
|
-
type_casted_binds = type_casted_binds(binds)
|
211
|
-
|
212
|
-
log(sql, name, binds, type_casted_binds) do
|
213
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
214
|
-
# Don't cache statements if they are not prepared
|
215
|
-
unless prepare
|
216
|
-
stmt = @connection.prepare(sql)
|
217
|
-
begin
|
218
|
-
cols = stmt.columns
|
219
|
-
unless without_prepared_statement?(binds)
|
220
|
-
stmt.bind_params(type_casted_binds)
|
221
|
-
end
|
222
|
-
records = stmt.to_a
|
223
|
-
ensure
|
224
|
-
stmt.close
|
225
|
-
end
|
226
|
-
else
|
227
|
-
cache = @statements[sql] ||= {
|
228
|
-
stmt: @connection.prepare(sql)
|
229
|
-
}
|
230
|
-
stmt = cache[:stmt]
|
231
|
-
cols = cache[:cols] ||= stmt.columns
|
232
|
-
stmt.reset!
|
233
|
-
stmt.bind_params(type_casted_binds)
|
234
|
-
records = stmt.to_a
|
235
|
-
end
|
236
|
-
|
237
|
-
ActiveRecord::Result.new(cols, records)
|
238
|
-
end
|
209
|
+
execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
|
210
|
+
execute("PRAGMA foreign_keys = #{old_foreign_keys}")
|
239
211
|
end
|
240
212
|
end
|
241
213
|
|
242
|
-
def
|
243
|
-
|
244
|
-
@connection.changes
|
245
|
-
end
|
246
|
-
alias :exec_update :exec_delete
|
247
|
-
|
248
|
-
def last_inserted_id(result)
|
249
|
-
@connection.last_insert_row_id
|
250
|
-
end
|
251
|
-
|
252
|
-
def execute(sql, name = nil) #:nodoc:
|
253
|
-
log(sql, name) do
|
254
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
255
|
-
@connection.execute(sql)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
def begin_db_transaction #:nodoc:
|
261
|
-
log("begin transaction", nil) { @connection.transaction }
|
262
|
-
end
|
263
|
-
|
264
|
-
def commit_db_transaction #:nodoc:
|
265
|
-
log("commit transaction", nil) { @connection.commit }
|
266
|
-
end
|
267
|
-
|
268
|
-
def exec_rollback_db_transaction #:nodoc:
|
269
|
-
log("rollback transaction", nil) { @connection.rollback }
|
214
|
+
def all_foreign_keys_valid? # :nodoc:
|
215
|
+
execute("PRAGMA foreign_key_check").blank?
|
270
216
|
end
|
271
217
|
|
272
218
|
# SCHEMA STATEMENTS ========================================
|
@@ -276,8 +222,11 @@ module ActiveRecord
|
|
276
222
|
pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
|
277
223
|
end
|
278
224
|
|
279
|
-
def remove_index(table_name,
|
280
|
-
|
225
|
+
def remove_index(table_name, column_name = nil, **options) # :nodoc:
|
226
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
227
|
+
|
228
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
229
|
+
|
281
230
|
exec_query "DROP INDEX #{quote_column_name(index_name)}"
|
282
231
|
end
|
283
232
|
|
@@ -286,32 +235,40 @@ module ActiveRecord
|
|
286
235
|
# Example:
|
287
236
|
# rename_table('octopuses', 'octopi')
|
288
237
|
def rename_table(table_name, new_name)
|
238
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
239
|
+
schema_cache.clear_data_source_cache!(new_name.to_s)
|
289
240
|
exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
|
290
241
|
rename_table_indexes(table_name, new_name)
|
291
242
|
end
|
292
243
|
|
293
|
-
def
|
294
|
-
!invalid_alter_table_type?(type, options)
|
295
|
-
end
|
296
|
-
deprecate :valid_alter_table_type?
|
297
|
-
|
298
|
-
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
244
|
+
def add_column(table_name, column_name, type, **options) # :nodoc:
|
299
245
|
if invalid_alter_table_type?(type, options)
|
300
246
|
alter_table(table_name) do |definition|
|
301
|
-
definition.column(column_name, type, options)
|
247
|
+
definition.column(column_name, type, **options)
|
302
248
|
end
|
303
249
|
else
|
304
250
|
super
|
305
251
|
end
|
306
252
|
end
|
307
253
|
|
308
|
-
def remove_column(table_name, column_name, type = nil, options
|
254
|
+
def remove_column(table_name, column_name, type = nil, **options) # :nodoc:
|
309
255
|
alter_table(table_name) do |definition|
|
310
256
|
definition.remove_column column_name
|
257
|
+
definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
|
262
|
+
alter_table(table_name) do |definition|
|
263
|
+
column_names.each do |column_name|
|
264
|
+
definition.remove_column column_name
|
265
|
+
end
|
266
|
+
column_names = column_names.map(&:to_s)
|
267
|
+
definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
|
311
268
|
end
|
312
269
|
end
|
313
270
|
|
314
|
-
def change_column_default(table_name, column_name, default_or_changes)
|
271
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
315
272
|
default = extract_new_default_value(default_or_changes)
|
316
273
|
|
317
274
|
alter_table(table_name) do |definition|
|
@@ -319,7 +276,7 @@ module ActiveRecord
|
|
319
276
|
end
|
320
277
|
end
|
321
278
|
|
322
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
279
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
323
280
|
unless null || default.nil?
|
324
281
|
exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
325
282
|
end
|
@@ -328,21 +285,16 @@ module ActiveRecord
|
|
328
285
|
end
|
329
286
|
end
|
330
287
|
|
331
|
-
def change_column(table_name, column_name, type, options
|
288
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
332
289
|
alter_table(table_name) do |definition|
|
333
290
|
definition[column_name].instance_eval do
|
334
|
-
self.type
|
335
|
-
self.
|
336
|
-
self.default = options[:default] if options.include?(:default)
|
337
|
-
self.null = options[:null] if options.include?(:null)
|
338
|
-
self.precision = options[:precision] if options.include?(:precision)
|
339
|
-
self.scale = options[:scale] if options.include?(:scale)
|
340
|
-
self.collation = options[:collation] if options.include?(:collation)
|
291
|
+
self.type = aliased_types(type.to_s, type)
|
292
|
+
self.options.merge!(options)
|
341
293
|
end
|
342
294
|
end
|
343
295
|
end
|
344
296
|
|
345
|
-
def rename_column(table_name, column_name, new_column_name)
|
297
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
346
298
|
column = column_for(table_name, column_name)
|
347
299
|
alter_table(table_name, rename: { column.name => new_column_name.to_s })
|
348
300
|
rename_column_indexes(table_name, column.name, new_column_name)
|
@@ -366,30 +318,68 @@ module ActiveRecord
|
|
366
318
|
end
|
367
319
|
end
|
368
320
|
|
369
|
-
def
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
321
|
+
def build_insert_sql(insert) # :nodoc:
|
322
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
323
|
+
|
324
|
+
if insert.skip_duplicates?
|
325
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
326
|
+
elsif insert.update_duplicates?
|
327
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
328
|
+
if insert.raw_update_sql?
|
329
|
+
sql << insert.raw_update_sql
|
330
|
+
else
|
331
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
|
332
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
sql
|
375
337
|
end
|
376
338
|
|
377
|
-
def
|
378
|
-
|
379
|
-
|
380
|
-
tables_to_delete.each { |table| delete "DELETE FROM #{quote_table_name(table)}", "Fixture Delete" }
|
339
|
+
def shared_cache? # :nodoc:
|
340
|
+
@config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
|
341
|
+
end
|
381
342
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
343
|
+
def get_database_version # :nodoc:
|
344
|
+
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
345
|
+
end
|
346
|
+
|
347
|
+
def check_version # :nodoc:
|
348
|
+
if database_version < "3.8.0"
|
349
|
+
raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
|
386
350
|
end
|
387
351
|
end
|
388
352
|
|
353
|
+
class SQLite3Integer < Type::Integer # :nodoc:
|
354
|
+
private
|
355
|
+
def _limit
|
356
|
+
# INTEGER storage class can be stored 8 bytes value.
|
357
|
+
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
|
358
|
+
limit || 8
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
|
363
|
+
|
364
|
+
class << self
|
365
|
+
private
|
366
|
+
def initialize_type_map(m)
|
367
|
+
super
|
368
|
+
register_class_with_limit m, %r(int)i, SQLite3Integer
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
373
|
+
|
389
374
|
private
|
390
|
-
def
|
391
|
-
|
392
|
-
|
375
|
+
def type_map
|
376
|
+
TYPE_MAP
|
377
|
+
end
|
378
|
+
|
379
|
+
# See https://www.sqlite.org/limits.html,
|
380
|
+
# the default value is 999 when not configured.
|
381
|
+
def bind_params_length
|
382
|
+
999
|
393
383
|
end
|
394
384
|
|
395
385
|
def table_structure(table_name)
|
@@ -399,20 +389,71 @@ module ActiveRecord
|
|
399
389
|
end
|
400
390
|
alias column_definitions table_structure
|
401
391
|
|
392
|
+
def extract_value_from_default(default)
|
393
|
+
case default
|
394
|
+
when /^null$/i
|
395
|
+
nil
|
396
|
+
# Quoted types
|
397
|
+
when /^'(.*)'$/m
|
398
|
+
$1.gsub("''", "'")
|
399
|
+
# Quoted types
|
400
|
+
when /^"(.*)"$/m
|
401
|
+
$1.gsub('""', '"')
|
402
|
+
# Numeric types
|
403
|
+
when /\A-?\d+(\.\d*)?\z/
|
404
|
+
$&
|
405
|
+
else
|
406
|
+
# Anything else is blank or some function
|
407
|
+
# and we can't know the value of that, so return nil.
|
408
|
+
nil
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def extract_default_function(default_value, default)
|
413
|
+
default if has_default_function?(default_value, default)
|
414
|
+
end
|
415
|
+
|
416
|
+
def has_default_function?(default_value, default)
|
417
|
+
!default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
418
|
+
end
|
419
|
+
|
402
420
|
# See: https://www.sqlite.org/lang_altertable.html
|
403
421
|
# SQLite has an additional restriction on the ALTER TABLE statement
|
404
422
|
def invalid_alter_table_type?(type, options)
|
405
|
-
type.to_sym == :primary_key || options[:primary_key]
|
423
|
+
type.to_sym == :primary_key || options[:primary_key] ||
|
424
|
+
options[:null] == false && options[:default].nil?
|
406
425
|
end
|
407
426
|
|
408
|
-
def alter_table(
|
427
|
+
def alter_table(
|
428
|
+
table_name,
|
429
|
+
foreign_keys = foreign_keys(table_name),
|
430
|
+
check_constraints = check_constraints(table_name),
|
431
|
+
**options
|
432
|
+
)
|
409
433
|
altered_table_name = "a#{table_name}"
|
410
|
-
|
434
|
+
|
435
|
+
caller = lambda do |definition|
|
436
|
+
rename = options[:rename] || {}
|
437
|
+
foreign_keys.each do |fk|
|
438
|
+
if column = rename[fk.options[:column]]
|
439
|
+
fk.options[:column] = column
|
440
|
+
end
|
441
|
+
to_table = strip_table_name_prefix_and_suffix(fk.to_table)
|
442
|
+
definition.foreign_key(to_table, **fk.options)
|
443
|
+
end
|
444
|
+
|
445
|
+
check_constraints.each do |chk|
|
446
|
+
definition.check_constraint(chk.expression, **chk.options)
|
447
|
+
end
|
448
|
+
|
449
|
+
yield definition if block_given?
|
450
|
+
end
|
411
451
|
|
412
452
|
transaction do
|
413
|
-
|
414
|
-
options.merge(temporary: true))
|
415
|
-
|
453
|
+
disable_referential_integrity do
|
454
|
+
move_table(table_name, altered_table_name, options.merge(temporary: true))
|
455
|
+
move_table(altered_table_name, table_name, &caller)
|
456
|
+
end
|
416
457
|
end
|
417
458
|
end
|
418
459
|
|
@@ -424,11 +465,12 @@ module ActiveRecord
|
|
424
465
|
def copy_table(from, to, options = {})
|
425
466
|
from_primary_key = primary_key(from)
|
426
467
|
options[:id] = false
|
427
|
-
create_table(to, options) do |definition|
|
468
|
+
create_table(to, **options) do |definition|
|
428
469
|
@definition = definition
|
429
470
|
if from_primary_key.is_a?(Array)
|
430
471
|
@definition.primary_keys from_primary_key
|
431
472
|
end
|
473
|
+
|
432
474
|
columns(from).each do |column|
|
433
475
|
column_name = options[:rename] ?
|
434
476
|
(options[:rename][column.name] ||
|
@@ -442,6 +484,7 @@ module ActiveRecord
|
|
442
484
|
primary_key: column_name == from_primary_key
|
443
485
|
)
|
444
486
|
end
|
487
|
+
|
445
488
|
yield @definition if block_given?
|
446
489
|
end
|
447
490
|
copy_table_indexes(from, to, options[:rename] || {})
|
@@ -459,17 +502,21 @@ module ActiveRecord
|
|
459
502
|
name = name[1..-1]
|
460
503
|
end
|
461
504
|
|
462
|
-
|
463
|
-
|
464
|
-
to_column_names.
|
505
|
+
columns = index.columns
|
506
|
+
if columns.is_a?(Array)
|
507
|
+
to_column_names = columns(to).map(&:name)
|
508
|
+
columns = columns.map { |c| rename[c] || c }.select do |column|
|
509
|
+
to_column_names.include?(column)
|
510
|
+
end
|
465
511
|
end
|
466
512
|
|
467
513
|
unless columns.empty?
|
468
514
|
# index name can't be the same
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
515
|
+
options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
516
|
+
options[:unique] = true if index.unique
|
517
|
+
options[:where] = index.where if index.where
|
518
|
+
options[:order] = index.orders if index.orders
|
519
|
+
add_index(to, columns, **options)
|
473
520
|
end
|
474
521
|
end
|
475
522
|
end
|
@@ -487,32 +534,29 @@ module ActiveRecord
|
|
487
534
|
SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
|
488
535
|
end
|
489
536
|
|
490
|
-
def
|
491
|
-
@sqlite_version ||= SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
492
|
-
end
|
493
|
-
|
494
|
-
def translate_exception(exception, message)
|
495
|
-
case exception.message
|
537
|
+
def translate_exception(exception, message:, sql:, binds:)
|
496
538
|
# SQLite 3.8.2 returns a newly formatted error message:
|
497
539
|
# UNIQUE constraint failed: *table_name*.*column_name*
|
498
540
|
# Older versions of SQLite return:
|
499
541
|
# column *column_name* is not unique
|
500
|
-
|
501
|
-
RecordNotUnique.new(message)
|
502
|
-
|
503
|
-
NotNullViolation.new(message)
|
504
|
-
|
505
|
-
InvalidForeignKey.new(message)
|
542
|
+
if exception.message.match?(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i)
|
543
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
544
|
+
elsif exception.message.match?(/(.* may not be NULL|NOT NULL constraint failed: .*)/i)
|
545
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
546
|
+
elsif exception.message.match?(/FOREIGN KEY constraint failed/i)
|
547
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
548
|
+
elsif exception.message.match?(/called on a closed database/i)
|
549
|
+
ConnectionNotEstablished.new(exception)
|
506
550
|
else
|
507
551
|
super
|
508
552
|
end
|
509
553
|
end
|
510
554
|
|
511
|
-
COLLATE_REGEX =
|
555
|
+
COLLATE_REGEX = /.*"(\w+)".*collate\s+"(\w+)".*/i.freeze
|
512
556
|
|
513
557
|
def table_structure_with_collation(table_name, basic_structure)
|
514
558
|
collation_hash = {}
|
515
|
-
sql =
|
559
|
+
sql = <<~SQL
|
516
560
|
SELECT sql FROM
|
517
561
|
(SELECT * FROM sqlite_master UNION ALL
|
518
562
|
SELECT * FROM sqlite_temp_master)
|
@@ -522,12 +566,12 @@ module ActiveRecord
|
|
522
566
|
# Result will have following sample string
|
523
567
|
# CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
524
568
|
# "password_digest" varchar COLLATE "NOCASE");
|
525
|
-
result =
|
569
|
+
result = query_value(sql, "SCHEMA")
|
526
570
|
|
527
571
|
if result
|
528
572
|
# Splitting with left parentheses and discarding the first part will return all
|
529
573
|
# columns separated with comma(,).
|
530
|
-
columns_string = result
|
574
|
+
columns_string = result.split("(", 2).last
|
531
575
|
|
532
576
|
columns_string.split(",").each do |column_string|
|
533
577
|
# This regex will match the column name and collation type and will save
|
@@ -535,7 +579,7 @@ module ActiveRecord
|
|
535
579
|
collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
|
536
580
|
end
|
537
581
|
|
538
|
-
basic_structure.map
|
582
|
+
basic_structure.map do |column|
|
539
583
|
column_name = column["name"]
|
540
584
|
|
541
585
|
if collation_hash.has_key? column_name
|
@@ -545,7 +589,7 @@ module ActiveRecord
|
|
545
589
|
column
|
546
590
|
end
|
547
591
|
else
|
548
|
-
basic_structure.
|
592
|
+
basic_structure.to_a
|
549
593
|
end
|
550
594
|
end
|
551
595
|
|
@@ -553,20 +597,23 @@ module ActiveRecord
|
|
553
597
|
Arel::Visitors::SQLite.new(self)
|
554
598
|
end
|
555
599
|
|
556
|
-
def
|
557
|
-
|
600
|
+
def build_statement_pool
|
601
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
558
602
|
end
|
559
603
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
end
|
604
|
+
def connect
|
605
|
+
@connection = ::SQLite3::Database.new(
|
606
|
+
@config[:database].to_s,
|
607
|
+
@config.merge(results_as_hash: true)
|
608
|
+
)
|
609
|
+
configure_connection
|
567
610
|
end
|
568
611
|
|
569
|
-
|
612
|
+
def configure_connection
|
613
|
+
@connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
|
614
|
+
|
615
|
+
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
616
|
+
end
|
570
617
|
end
|
571
618
|
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
572
619
|
end
|