activerecord 6.1.7 → 7.1.0
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 +1516 -1019
- data/MIT-LICENSE +1 -1
- data/README.rdoc +17 -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 +50 -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 +35 -31
- 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.rb +26 -16
- data/lib/active_record/associations/preloader/association.rb +207 -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 +423 -289
- 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 +61 -14
- 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 +25 -10
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +10 -13
- data/lib/active_record/attribute_methods.rb +121 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +61 -30
- 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 +96 -590
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -51
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -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 +360 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +622 -149
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
- 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 +38 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
- 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 +18 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- 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/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 +381 -69
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +492 -230
- 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 +65 -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 +294 -102
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +107 -136
- data/lib/active_record/core.rb +194 -224
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +84 -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 +61 -15
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- 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 +224 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -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 +172 -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 +96 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +156 -62
- data/lib/active_record/errors.rb +171 -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 +131 -86
- data/lib/active_record/future_result.rb +164 -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 +133 -20
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +117 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +36 -21
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +56 -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 +108 -13
- data/lib/active_record/migration/compatibility.rb +221 -48
- 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.rb +355 -171
- data/lib/active_record/model_schema.rb +116 -97
- data/lib/active_record/nested_attributes.rb +36 -15
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +159 -0
- data/lib/active_record/persistence.rb +405 -85
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- 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 +219 -43
- data/lib/active_record/railties/controller_runtime.rb +13 -9
- data/lib/active_record/railties/databases.rake +185 -249
- 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 +229 -80
- 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 +211 -90
- data/lib/active_record/relation/delegation.rb +27 -13
- 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 +4 -6
- 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 +654 -127
- 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 +262 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +18 -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 +225 -136
- 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 +116 -96
- data/lib/active_record/timestamp.rb +28 -17
- 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 +0 -8
- 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 +0 -12
- 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 +139 -19
- 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 +92 -13
- 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,7 +44,7 @@ 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)
|
@@ -72,64 +56,88 @@ module ActiveRecord
|
|
72
56
|
end
|
73
57
|
end
|
74
58
|
|
75
|
-
def exec_delete(sql, name = "SQL", binds = [])
|
76
|
-
|
77
|
-
@
|
59
|
+
def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
|
60
|
+
internal_exec_query(sql, name, binds)
|
61
|
+
@raw_connection.changes
|
78
62
|
end
|
79
63
|
alias :exec_update :exec_delete
|
80
64
|
|
81
|
-
def begin_isolated_db_transaction(isolation)
|
65
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
82
66
|
raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
|
83
67
|
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
68
|
|
85
|
-
|
86
|
-
|
87
|
-
|
69
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
70
|
+
ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted] = conn.get_first_value("PRAGMA read_uncommitted")
|
71
|
+
conn.read_uncommitted = true
|
72
|
+
begin_db_transaction
|
73
|
+
end
|
88
74
|
end
|
89
75
|
|
90
|
-
def begin_db_transaction
|
91
|
-
log("begin transaction", "TRANSACTION")
|
76
|
+
def begin_db_transaction # :nodoc:
|
77
|
+
log("begin transaction", "TRANSACTION") do
|
78
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
79
|
+
conn.transaction
|
80
|
+
end
|
81
|
+
end
|
92
82
|
end
|
93
83
|
|
94
|
-
def commit_db_transaction
|
95
|
-
log("commit transaction", "TRANSACTION")
|
84
|
+
def commit_db_transaction # :nodoc:
|
85
|
+
log("commit transaction", "TRANSACTION") do
|
86
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
87
|
+
conn.commit
|
88
|
+
end
|
89
|
+
end
|
96
90
|
reset_read_uncommitted
|
97
91
|
end
|
98
92
|
|
99
|
-
def exec_rollback_db_transaction
|
100
|
-
log("rollback transaction", "TRANSACTION")
|
93
|
+
def exec_rollback_db_transaction # :nodoc:
|
94
|
+
log("rollback transaction", "TRANSACTION") do
|
95
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
96
|
+
conn.rollback
|
97
|
+
end
|
98
|
+
end
|
101
99
|
reset_read_uncommitted
|
102
100
|
end
|
103
101
|
|
102
|
+
# https://stackoverflow.com/questions/17574784
|
103
|
+
# https://www.sqlite.org/lang_datefunc.html
|
104
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')").freeze # :nodoc:
|
105
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
106
|
+
|
107
|
+
def high_precision_current_timestamp
|
108
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
109
|
+
end
|
110
|
+
|
104
111
|
private
|
112
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: false)
|
113
|
+
log(sql, name, async: async) do
|
114
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
115
|
+
conn.execute(sql)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
105
120
|
def reset_read_uncommitted
|
106
|
-
read_uncommitted =
|
121
|
+
read_uncommitted = ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted]
|
107
122
|
return unless read_uncommitted
|
108
123
|
|
109
|
-
@
|
124
|
+
@raw_connection&.read_uncommitted = read_uncommitted
|
110
125
|
end
|
111
126
|
|
112
127
|
def execute_batch(statements, name = nil)
|
128
|
+
statements = statements.map { |sql| transform_query(sql) }
|
113
129
|
sql = combine_multi_statements(statements)
|
114
130
|
|
115
|
-
|
116
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
117
|
-
end
|
118
|
-
|
119
|
-
materialize_transactions
|
131
|
+
check_if_write_query(sql)
|
120
132
|
mark_transaction_written_if_write(sql)
|
121
133
|
|
122
134
|
log(sql, name) do
|
123
|
-
|
124
|
-
|
135
|
+
with_raw_connection do |conn|
|
136
|
+
conn.execute_batch2(sql)
|
125
137
|
end
|
126
138
|
end
|
127
139
|
end
|
128
140
|
|
129
|
-
def last_inserted_id(result)
|
130
|
-
@connection.last_insert_row_id
|
131
|
-
end
|
132
|
-
|
133
141
|
def build_fixture_statements(fixture_set)
|
134
142
|
fixture_set.flat_map do |table_name, fixtures|
|
135
143
|
next if fixtures.empty?
|
@@ -140,6 +148,10 @@ module ActiveRecord
|
|
140
148
|
def build_truncate_statement(table_name)
|
141
149
|
"DELETE FROM #{quote_table_name(table_name)}"
|
142
150
|
end
|
151
|
+
|
152
|
+
def returning_column_values(result)
|
153
|
+
result.rows.first
|
154
|
+
end
|
143
155
|
end
|
144
156
|
end
|
145
157
|
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)
|