activerecord 6.1.7 → 7.1.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -52
- 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 +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- 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 +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -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 +157 -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 +53 -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 +92 -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 +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- 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 +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -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 +96 -16
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -15,41 +15,25 @@ module ActiveRecord
|
|
15
15
|
!READ_QUERY.match?(sql.b)
|
16
16
|
end
|
17
17
|
|
18
|
-
def explain(arel, binds = [])
|
19
|
-
sql
|
20
|
-
|
18
|
+
def explain(arel, binds = [], _options = [])
|
19
|
+
sql = "EXPLAIN QUERY PLAN " + to_sql(arel, binds)
|
20
|
+
result = internal_exec_query(sql, "EXPLAIN", [])
|
21
|
+
SQLite3::ExplainPrettyPrinter.new.pp(result)
|
21
22
|
end
|
22
23
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
end
|
24
|
+
def internal_exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
|
25
|
+
sql = transform_query(sql)
|
26
|
+
check_if_write_query(sql)
|
27
27
|
|
28
|
-
materialize_transactions
|
29
|
-
mark_transaction_written_if_write(sql)
|
30
|
-
|
31
|
-
log(sql, name) do
|
32
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
33
|
-
@connection.execute(sql)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def exec_query(sql, name = nil, binds = [], prepare: false)
|
39
|
-
if preventing_writes? && write_query?(sql)
|
40
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
41
|
-
end
|
42
|
-
|
43
|
-
materialize_transactions
|
44
28
|
mark_transaction_written_if_write(sql)
|
45
29
|
|
46
30
|
type_casted_binds = type_casted_binds(binds)
|
47
31
|
|
48
|
-
log(sql, name, binds, type_casted_binds) do
|
49
|
-
|
32
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
33
|
+
with_raw_connection do |conn|
|
50
34
|
# Don't cache statements if they are not prepared
|
51
35
|
unless prepare
|
52
|
-
stmt =
|
36
|
+
stmt = conn.prepare(sql)
|
53
37
|
begin
|
54
38
|
cols = stmt.columns
|
55
39
|
unless without_prepared_statement?(binds)
|
@@ -60,76 +44,107 @@ module ActiveRecord
|
|
60
44
|
stmt.close
|
61
45
|
end
|
62
46
|
else
|
63
|
-
stmt = @statements[sql] ||=
|
47
|
+
stmt = @statements[sql] ||= conn.prepare(sql)
|
64
48
|
cols = stmt.columns
|
65
49
|
stmt.reset!
|
66
50
|
stmt.bind_params(type_casted_binds)
|
67
51
|
records = stmt.to_a
|
68
52
|
end
|
53
|
+
verified!
|
69
54
|
|
70
55
|
build_result(columns: cols, rows: records)
|
71
56
|
end
|
72
57
|
end
|
73
58
|
end
|
74
59
|
|
75
|
-
def exec_delete(sql, name = "SQL", binds = [])
|
76
|
-
|
77
|
-
@
|
60
|
+
def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
|
61
|
+
internal_exec_query(sql, name, binds)
|
62
|
+
@raw_connection.changes
|
78
63
|
end
|
79
64
|
alias :exec_update :exec_delete
|
80
65
|
|
81
|
-
def begin_isolated_db_transaction(isolation)
|
66
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
82
67
|
raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
|
83
68
|
raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
|
84
69
|
|
85
|
-
|
86
|
-
|
87
|
-
|
70
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
71
|
+
ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted] = conn.get_first_value("PRAGMA read_uncommitted")
|
72
|
+
conn.read_uncommitted = true
|
73
|
+
begin_db_transaction
|
74
|
+
end
|
88
75
|
end
|
89
76
|
|
90
|
-
def begin_db_transaction
|
91
|
-
log("begin transaction", "TRANSACTION")
|
77
|
+
def begin_db_transaction # :nodoc:
|
78
|
+
log("begin transaction", "TRANSACTION") do
|
79
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
80
|
+
result = conn.transaction
|
81
|
+
verified!
|
82
|
+
result
|
83
|
+
end
|
84
|
+
end
|
92
85
|
end
|
93
86
|
|
94
|
-
def commit_db_transaction
|
95
|
-
log("commit transaction", "TRANSACTION")
|
87
|
+
def commit_db_transaction # :nodoc:
|
88
|
+
log("commit transaction", "TRANSACTION") do
|
89
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
90
|
+
conn.commit
|
91
|
+
end
|
92
|
+
end
|
96
93
|
reset_read_uncommitted
|
97
94
|
end
|
98
95
|
|
99
|
-
def exec_rollback_db_transaction
|
100
|
-
log("rollback transaction", "TRANSACTION")
|
96
|
+
def exec_rollback_db_transaction # :nodoc:
|
97
|
+
log("rollback transaction", "TRANSACTION") do
|
98
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
99
|
+
conn.rollback
|
100
|
+
end
|
101
|
+
end
|
101
102
|
reset_read_uncommitted
|
102
103
|
end
|
103
104
|
|
105
|
+
# https://stackoverflow.com/questions/17574784
|
106
|
+
# https://www.sqlite.org/lang_datefunc.html
|
107
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')").freeze # :nodoc:
|
108
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
109
|
+
|
110
|
+
def high_precision_current_timestamp
|
111
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
112
|
+
end
|
113
|
+
|
104
114
|
private
|
115
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: false)
|
116
|
+
log(sql, name, async: async) do
|
117
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
118
|
+
result = conn.execute(sql)
|
119
|
+
verified!
|
120
|
+
result
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
105
125
|
def reset_read_uncommitted
|
106
|
-
read_uncommitted =
|
126
|
+
read_uncommitted = ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted]
|
107
127
|
return unless read_uncommitted
|
108
128
|
|
109
|
-
@
|
129
|
+
@raw_connection&.read_uncommitted = read_uncommitted
|
110
130
|
end
|
111
131
|
|
112
132
|
def execute_batch(statements, name = nil)
|
133
|
+
statements = statements.map { |sql| transform_query(sql) }
|
113
134
|
sql = combine_multi_statements(statements)
|
114
135
|
|
115
|
-
|
116
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
117
|
-
end
|
118
|
-
|
119
|
-
materialize_transactions
|
136
|
+
check_if_write_query(sql)
|
120
137
|
mark_transaction_written_if_write(sql)
|
121
138
|
|
122
139
|
log(sql, name) do
|
123
|
-
|
124
|
-
|
140
|
+
with_raw_connection do |conn|
|
141
|
+
result = conn.execute_batch2(sql)
|
142
|
+
verified!
|
143
|
+
result
|
125
144
|
end
|
126
145
|
end
|
127
146
|
end
|
128
147
|
|
129
|
-
def last_inserted_id(result)
|
130
|
-
@connection.last_insert_row_id
|
131
|
-
end
|
132
|
-
|
133
148
|
def build_fixture_statements(fixture_set)
|
134
149
|
fixture_set.flat_map do |table_name, fixtures|
|
135
150
|
next if fixtures.empty?
|
@@ -140,6 +155,10 @@ module ActiveRecord
|
|
140
155
|
def build_truncate_statement(table_name)
|
141
156
|
"DELETE FROM #{quote_table_name(table_name)}"
|
142
157
|
end
|
158
|
+
|
159
|
+
def returning_column_values(result)
|
160
|
+
result.rows.first
|
161
|
+
end
|
143
162
|
end
|
144
163
|
end
|
145
164
|
end
|
@@ -4,8 +4,11 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLite3
|
6
6
|
module Quoting # :nodoc:
|
7
|
+
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
8
|
+
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
9
|
+
|
7
10
|
def quote_string(s)
|
8
|
-
|
11
|
+
::SQLite3::Database.quote(s)
|
9
12
|
end
|
10
13
|
|
11
14
|
def quote_table_name_for_assignment(table, attr)
|
@@ -13,11 +16,11 @@ module ActiveRecord
|
|
13
16
|
end
|
14
17
|
|
15
18
|
def quote_table_name(name)
|
16
|
-
|
19
|
+
QUOTED_TABLE_NAMES[name] ||= super.gsub(".", "\".\"").freeze
|
17
20
|
end
|
18
21
|
|
19
22
|
def quote_column_name(name)
|
20
|
-
|
23
|
+
QUOTED_COLUMN_NAMES[name] ||= %Q("#{super.gsub('"', '""')}")
|
21
24
|
end
|
22
25
|
|
23
26
|
def quoted_time(value)
|
@@ -45,6 +48,34 @@ module ActiveRecord
|
|
45
48
|
0
|
46
49
|
end
|
47
50
|
|
51
|
+
def quote_default_expression(value, column) # :nodoc:
|
52
|
+
if value.is_a?(Proc)
|
53
|
+
value = value.call
|
54
|
+
if value.match?(/\A\w+\(.*\)\z/)
|
55
|
+
"(#{value})"
|
56
|
+
else
|
57
|
+
value
|
58
|
+
end
|
59
|
+
else
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def type_cast(value) # :nodoc:
|
65
|
+
case value
|
66
|
+
when BigDecimal
|
67
|
+
value.to_f
|
68
|
+
when String
|
69
|
+
if value.encoding == Encoding::ASCII_8BIT
|
70
|
+
super(value.encode(Encoding::UTF_8))
|
71
|
+
else
|
72
|
+
super
|
73
|
+
end
|
74
|
+
else
|
75
|
+
super
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
48
79
|
def column_name_matcher
|
49
80
|
COLUMN_NAME
|
50
81
|
end
|
@@ -58,7 +89,7 @@ module ActiveRecord
|
|
58
89
|
(
|
59
90
|
(?:
|
60
91
|
# "table_name"."column_name" | function(one or no argument)
|
61
|
-
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")
|
92
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
62
93
|
)
|
63
94
|
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
64
95
|
)
|
@@ -71,8 +102,9 @@ module ActiveRecord
|
|
71
102
|
(
|
72
103
|
(?:
|
73
104
|
# "table_name"."column_name" | function(one or no argument)
|
74
|
-
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")
|
105
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
75
106
|
)
|
107
|
+
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
76
108
|
(?:\s+ASC|\s+DESC)?
|
77
109
|
)
|
78
110
|
(?:\s*,\s*\g<1>)*
|
@@ -80,22 +112,6 @@ module ActiveRecord
|
|
80
112
|
/ix
|
81
113
|
|
82
114
|
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
83
|
-
|
84
|
-
private
|
85
|
-
def _type_cast(value)
|
86
|
-
case value
|
87
|
-
when BigDecimal
|
88
|
-
value.to_f
|
89
|
-
when String
|
90
|
-
if value.encoding == Encoding::ASCII_8BIT
|
91
|
-
super(value.encode(Encoding::UTF_8))
|
92
|
-
else
|
93
|
-
super
|
94
|
-
end
|
95
|
-
else
|
96
|
-
super
|
97
|
-
end
|
98
|
-
end
|
99
115
|
end
|
100
116
|
end
|
101
117
|
end
|
@@ -3,7 +3,14 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLite3
|
6
|
+
# = Active Record SQLite3 Adapter \Table Definition
|
6
7
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
8
|
+
def change_column(column_name, type, **options)
|
9
|
+
name = column_name.to_s
|
10
|
+
@columns_hash[name] = nil
|
11
|
+
column(name, type, **options)
|
12
|
+
end
|
13
|
+
|
7
14
|
def references(*args, **options)
|
8
15
|
super(*args, type: :integer, **options)
|
9
16
|
end
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
module SchemaStatements # :nodoc:
|
7
7
|
# Returns an array of indexes for the given table.
|
8
8
|
def indexes(table_name)
|
9
|
-
|
9
|
+
internal_exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").filter_map do |row|
|
10
10
|
# Indexes SQLite creates implicitly for internal use start with "sqlite_".
|
11
11
|
# See https://www.sqlite.org/fileformat2.html#intschema
|
12
12
|
next if row["name"].start_with?("sqlite_")
|
@@ -21,9 +21,9 @@ module ActiveRecord
|
|
21
21
|
WHERE name = #{quote(row['name'])} AND type = 'index'
|
22
22
|
SQL
|
23
23
|
|
24
|
-
/\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?\z/i =~ index_sql
|
24
|
+
/\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?(?:\s*\/\*.*\*\/)?\z/i =~ index_sql
|
25
25
|
|
26
|
-
columns =
|
26
|
+
columns = internal_exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
|
27
27
|
col["name"]
|
28
28
|
end
|
29
29
|
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
where: where,
|
50
50
|
orders: orders
|
51
51
|
)
|
52
|
-
end
|
52
|
+
end
|
53
53
|
end
|
54
54
|
|
55
55
|
def add_foreign_key(from_table, to_table, **options)
|
@@ -60,6 +60,8 @@ module ActiveRecord
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
63
|
+
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
|
64
|
+
|
63
65
|
to_table ||= options[:to_table]
|
64
66
|
options = options.except(:name, :to_table, :validate)
|
65
67
|
foreign_keys = foreign_keys(from_table)
|
@@ -82,11 +84,11 @@ module ActiveRecord
|
|
82
84
|
table_sql = query_value(<<-SQL, "SCHEMA")
|
83
85
|
SELECT sql
|
84
86
|
FROM sqlite_master
|
85
|
-
WHERE name = #{
|
87
|
+
WHERE name = #{quote(table_name)} AND type = 'table'
|
86
88
|
UNION ALL
|
87
89
|
SELECT sql
|
88
90
|
FROM sqlite_temp_master
|
89
|
-
WHERE name = #{
|
91
|
+
WHERE name = #{quote(table_name)} AND type = 'table'
|
90
92
|
SQL
|
91
93
|
|
92
94
|
table_sql.to_s.scan(/CONSTRAINT\s+(?<name>\w+)\s+CHECK\s+\((?<expression>(:?[^()]|\(\g<expression>\))+)\)/i).map do |name, expression|
|
@@ -100,7 +102,9 @@ module ActiveRecord
|
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
103
|
-
def remove_check_constraint(table_name, expression = nil, **options)
|
105
|
+
def remove_check_constraint(table_name, expression = nil, if_exists: false, **options)
|
106
|
+
return if if_exists && !check_constraint_exists?(table_name, **options)
|
107
|
+
|
104
108
|
check_constraints = check_constraints(table_name)
|
105
109
|
chk_name_to_delete = check_constraint_for!(table_name, expression: expression, **options).name
|
106
110
|
check_constraints.delete_if { |chk| chk.name == chk_name_to_delete }
|
@@ -111,9 +115,13 @@ module ActiveRecord
|
|
111
115
|
SQLite3::SchemaDumper.create(self, options)
|
112
116
|
end
|
113
117
|
|
118
|
+
def schema_creation # :nodoc
|
119
|
+
SQLite3::SchemaCreation.new(self)
|
120
|
+
end
|
121
|
+
|
114
122
|
private
|
115
|
-
def
|
116
|
-
|
123
|
+
def valid_table_definition_options
|
124
|
+
super + [:rename]
|
117
125
|
end
|
118
126
|
|
119
127
|
def create_table_definition(name, **options)
|
@@ -124,21 +132,34 @@ module ActiveRecord
|
|
124
132
|
super unless internal
|
125
133
|
end
|
126
134
|
|
127
|
-
def new_column_from_field(table_name, field)
|
128
|
-
default =
|
129
|
-
case field["dflt_value"]
|
130
|
-
when /^null$/i
|
131
|
-
nil
|
132
|
-
when /^'(.*)'$/m
|
133
|
-
$1.gsub("''", "'")
|
134
|
-
when /^"(.*)"$/m
|
135
|
-
$1.gsub('""', '"')
|
136
|
-
else
|
137
|
-
field["dflt_value"]
|
138
|
-
end
|
135
|
+
def new_column_from_field(table_name, field, definitions)
|
136
|
+
default = field["dflt_value"]
|
139
137
|
|
140
138
|
type_metadata = fetch_type_metadata(field["type"])
|
141
|
-
|
139
|
+
default_value = extract_value_from_default(default)
|
140
|
+
default_function = extract_default_function(default_value, default)
|
141
|
+
rowid = is_column_the_rowid?(field, definitions)
|
142
|
+
|
143
|
+
Column.new(
|
144
|
+
field["name"],
|
145
|
+
default_value,
|
146
|
+
type_metadata,
|
147
|
+
field["notnull"].to_i == 0,
|
148
|
+
default_function,
|
149
|
+
collation: field["collation"],
|
150
|
+
auto_increment: field["auto_increment"],
|
151
|
+
rowid: rowid
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
INTEGER_REGEX = /integer/i
|
156
|
+
# if a rowid table has a primary key that consists of a single column
|
157
|
+
# and the declared type of that column is "INTEGER" in any mixture of upper and lower case,
|
158
|
+
# then the column becomes an alias for the rowid.
|
159
|
+
def is_column_the_rowid?(field, column_definitions)
|
160
|
+
return false unless INTEGER_REGEX.match?(field["type"]) && field["pk"] == 1
|
161
|
+
# is the primary key a single column?
|
162
|
+
column_definitions.one? { |c| c["pk"] > 0 }
|
142
163
|
end
|
143
164
|
|
144
165
|
def data_source_sql(name = nil, type: nil)
|