activerecord 6.1.7.6 → 7.0.8
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 +1570 -1016
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- 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 +2 -2
- data/lib/active_record/associations/collection_association.rb +20 -22
- data/lib/active_record/associations/collection_proxy.rb +15 -5
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +8 -5
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/preloader/association.rb +186 -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 +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +138 -100
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +8 -6
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +19 -22
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +8 -23
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +14 -16
- data/lib/active_record/coders/yaml_column.rb +4 -8
- 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 +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +52 -23
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +144 -82
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +115 -85
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -25
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -23
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +19 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
- 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 +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 +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +76 -73
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +40 -21
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +33 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +19 -17
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +98 -36
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +49 -55
- data/lib/active_record/core.rb +123 -148
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +53 -12
- data/lib/active_record/destroy_association_async_job.rb +1 -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/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 +67 -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 +206 -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 +50 -43
- data/lib/active_record/errors.rb +67 -4
- 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/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +20 -23
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +5 -5
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- 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 +10 -4
- data/lib/active_record/log_subscriber.rb +23 -7
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +18 -6
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +8 -9
- data/lib/active_record/migration/compatibility.rb +93 -46
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +167 -87
- data/lib/active_record/model_schema.rb +58 -59
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +231 -61
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +149 -0
- data/lib/active_record/querying.rb +16 -6
- data/lib/active_record/railtie.rb +136 -22
- data/lib/active_record/railties/controller_runtime.rb +4 -5
- data/lib/active_record/railties/databases.rake +78 -136
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +80 -49
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +6 -6
- data/lib/active_record/relation/calculations.rb +92 -60
- data/lib/active_record/relation/delegation.rb +7 -7
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +28 -11
- data/lib/active_record/relation/query_methods.rb +304 -68
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +189 -88
- data/lib/active_record/result.rb +23 -11
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +17 -12
- data/lib/active_record/schema.rb +38 -23
- data/lib/active_record/schema_dumper.rb +29 -19
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +60 -13
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +3 -3
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/table_metadata.rb +6 -2
- data/lib/active_record/tasks/database_tasks.rb +127 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -6
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +12 -17
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +225 -27
- 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/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/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- 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 +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- 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 +55 -11
@@ -20,10 +20,9 @@ module ActiveRecord
|
|
20
20
|
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
21
21
|
end
|
22
22
|
|
23
|
-
def execute(sql, name = nil)
|
24
|
-
|
25
|
-
|
26
|
-
end
|
23
|
+
def execute(sql, name = nil) # :nodoc:
|
24
|
+
sql = transform_query(sql)
|
25
|
+
check_if_write_query(sql)
|
27
26
|
|
28
27
|
materialize_transactions
|
29
28
|
mark_transaction_written_if_write(sql)
|
@@ -35,17 +34,16 @@ module ActiveRecord
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
|
-
def exec_query(sql, name = nil, binds = [], prepare: false)
|
39
|
-
|
40
|
-
|
41
|
-
end
|
37
|
+
def exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
|
38
|
+
sql = transform_query(sql)
|
39
|
+
check_if_write_query(sql)
|
42
40
|
|
43
41
|
materialize_transactions
|
44
42
|
mark_transaction_written_if_write(sql)
|
45
43
|
|
46
44
|
type_casted_binds = type_casted_binds(binds)
|
47
45
|
|
48
|
-
log(sql, name, binds, type_casted_binds) do
|
46
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
49
47
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
50
48
|
# Don't cache statements if they are not prepared
|
51
49
|
unless prepare
|
@@ -72,49 +70,57 @@ module ActiveRecord
|
|
72
70
|
end
|
73
71
|
end
|
74
72
|
|
75
|
-
def exec_delete(sql, name = "SQL", binds = [])
|
73
|
+
def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
|
76
74
|
exec_query(sql, name, binds)
|
77
75
|
@connection.changes
|
78
76
|
end
|
79
77
|
alias :exec_update :exec_delete
|
80
78
|
|
81
|
-
def begin_isolated_db_transaction(isolation)
|
79
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
82
80
|
raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
|
83
81
|
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
82
|
|
85
|
-
|
83
|
+
ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted] = @connection.get_first_value("PRAGMA read_uncommitted")
|
86
84
|
@connection.read_uncommitted = true
|
87
85
|
begin_db_transaction
|
88
86
|
end
|
89
87
|
|
90
|
-
def begin_db_transaction
|
88
|
+
def begin_db_transaction # :nodoc:
|
91
89
|
log("begin transaction", "TRANSACTION") { @connection.transaction }
|
92
90
|
end
|
93
91
|
|
94
|
-
def commit_db_transaction
|
92
|
+
def commit_db_transaction # :nodoc:
|
95
93
|
log("commit transaction", "TRANSACTION") { @connection.commit }
|
96
94
|
reset_read_uncommitted
|
97
95
|
end
|
98
96
|
|
99
|
-
def exec_rollback_db_transaction
|
97
|
+
def exec_rollback_db_transaction # :nodoc:
|
100
98
|
log("rollback transaction", "TRANSACTION") { @connection.rollback }
|
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
|
105
112
|
def reset_read_uncommitted
|
106
|
-
read_uncommitted =
|
113
|
+
read_uncommitted = ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted]
|
107
114
|
return unless read_uncommitted
|
108
115
|
|
109
116
|
@connection.read_uncommitted = read_uncommitted
|
110
117
|
end
|
111
118
|
|
112
119
|
def execute_batch(statements, name = nil)
|
120
|
+
statements = statements.map { |sql| transform_query(sql) }
|
113
121
|
sql = combine_multi_statements(statements)
|
114
122
|
|
115
|
-
|
116
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
117
|
-
end
|
123
|
+
check_if_write_query(sql)
|
118
124
|
|
119
125
|
materialize_transactions
|
120
126
|
mark_transaction_written_if_write(sql)
|
@@ -4,6 +4,9 @@ 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
|
@connection.class.quote(s)
|
9
12
|
end
|
@@ -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
|
@@ -80,22 +111,6 @@ module ActiveRecord
|
|
80
111
|
/ix
|
81
112
|
|
82
113
|
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
114
|
end
|
100
115
|
end
|
101
116
|
end
|
@@ -4,6 +4,12 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLite3
|
6
6
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
7
|
+
def change_column(column_name, type, **options)
|
8
|
+
name = column_name.to_s
|
9
|
+
@columns_hash[name] = nil
|
10
|
+
column(name, type, **options)
|
11
|
+
end
|
12
|
+
|
7
13
|
def references(*args, **options)
|
8
14
|
super(*args, type: :integer, **options)
|
9
15
|
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
|
-
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").
|
9
|
+
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,7 +21,7 @@ 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
26
|
columns = exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
|
27
27
|
col["name"]
|
@@ -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|
|
@@ -125,20 +127,20 @@ module ActiveRecord
|
|
125
127
|
end
|
126
128
|
|
127
129
|
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
|
130
|
+
default = field["dflt_value"]
|
139
131
|
|
140
132
|
type_metadata = fetch_type_metadata(field["type"])
|
141
|
-
|
133
|
+
default_value = extract_value_from_default(default)
|
134
|
+
default_function = extract_default_function(default_value, default)
|
135
|
+
|
136
|
+
Column.new(
|
137
|
+
field["name"],
|
138
|
+
default_value,
|
139
|
+
type_metadata,
|
140
|
+
field["notnull"].to_i == 0,
|
141
|
+
default_function,
|
142
|
+
collation: field["collation"]
|
143
|
+
)
|
142
144
|
end
|
143
145
|
|
144
146
|
def data_source_sql(name = nil, type: nil)
|
@@ -47,7 +47,7 @@ module ActiveRecord
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
module ConnectionAdapters
|
50
|
+
module ConnectionAdapters # :nodoc:
|
51
51
|
# The SQLite3 adapter works with the sqlite3-ruby drivers
|
52
52
|
# (available as gem from https://rubygems.org/gems/sqlite3).
|
53
53
|
#
|
@@ -84,6 +84,7 @@ module ActiveRecord
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def initialize(connection, logger, connection_options, config)
|
87
|
+
@memory_database = config[:database] == ":memory:"
|
87
88
|
super(connection, logger, config)
|
88
89
|
configure_connection
|
89
90
|
end
|
@@ -153,6 +154,10 @@ module ActiveRecord
|
|
153
154
|
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
154
155
|
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
155
156
|
|
157
|
+
def supports_concurrent_connections?
|
158
|
+
!@memory_database
|
159
|
+
end
|
160
|
+
|
156
161
|
def active?
|
157
162
|
!@connection.closed?
|
158
163
|
end
|
@@ -173,11 +178,11 @@ module ActiveRecord
|
|
173
178
|
true
|
174
179
|
end
|
175
180
|
|
176
|
-
def native_database_types
|
181
|
+
def native_database_types # :nodoc:
|
177
182
|
NATIVE_DATABASE_TYPES
|
178
183
|
end
|
179
184
|
|
180
|
-
# Returns the current database encoding format as a string,
|
185
|
+
# Returns the current database encoding format as a string, e.g. 'UTF-8'
|
181
186
|
def encoding
|
182
187
|
@connection.encoding.to_s
|
183
188
|
end
|
@@ -206,6 +211,10 @@ module ActiveRecord
|
|
206
211
|
end
|
207
212
|
end
|
208
213
|
|
214
|
+
def all_foreign_keys_valid? # :nodoc:
|
215
|
+
execute("PRAGMA foreign_key_check").blank?
|
216
|
+
end
|
217
|
+
|
209
218
|
# SCHEMA STATEMENTS ========================================
|
210
219
|
|
211
220
|
def primary_keys(table_name) # :nodoc:
|
@@ -232,7 +241,7 @@ module ActiveRecord
|
|
232
241
|
rename_table_indexes(table_name, new_name)
|
233
242
|
end
|
234
243
|
|
235
|
-
def add_column(table_name, column_name, type, **options)
|
244
|
+
def add_column(table_name, column_name, type, **options) # :nodoc:
|
236
245
|
if invalid_alter_table_type?(type, options)
|
237
246
|
alter_table(table_name) do |definition|
|
238
247
|
definition.column(column_name, type, **options)
|
@@ -242,16 +251,24 @@ module ActiveRecord
|
|
242
251
|
end
|
243
252
|
end
|
244
253
|
|
245
|
-
def remove_column(table_name, column_name, type = nil, **options)
|
254
|
+
def remove_column(table_name, column_name, type = nil, **options) # :nodoc:
|
246
255
|
alter_table(table_name) do |definition|
|
247
256
|
definition.remove_column column_name
|
248
|
-
definition.foreign_keys.delete_if
|
249
|
-
|
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
|
250
265
|
end
|
266
|
+
column_names = column_names.map(&:to_s)
|
267
|
+
definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
|
251
268
|
end
|
252
269
|
end
|
253
270
|
|
254
|
-
def change_column_default(table_name, column_name, default_or_changes)
|
271
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
255
272
|
default = extract_new_default_value(default_or_changes)
|
256
273
|
|
257
274
|
alter_table(table_name) do |definition|
|
@@ -259,7 +276,7 @@ module ActiveRecord
|
|
259
276
|
end
|
260
277
|
end
|
261
278
|
|
262
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
279
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
263
280
|
unless null || default.nil?
|
264
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")
|
265
282
|
end
|
@@ -268,16 +285,13 @@ module ActiveRecord
|
|
268
285
|
end
|
269
286
|
end
|
270
287
|
|
271
|
-
def change_column(table_name, column_name, type, **options)
|
288
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
272
289
|
alter_table(table_name) do |definition|
|
273
|
-
definition
|
274
|
-
self.type = aliased_types(type.to_s, type)
|
275
|
-
self.options.merge!(options)
|
276
|
-
end
|
290
|
+
definition.change_column(column_name, type, **options)
|
277
291
|
end
|
278
292
|
end
|
279
293
|
|
280
|
-
def rename_column(table_name, column_name, new_column_name)
|
294
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
281
295
|
column = column_for(table_name, column_name)
|
282
296
|
alter_table(table_name, rename: { column.name => new_column_name.to_s })
|
283
297
|
rename_column_indexes(table_name, column.name, new_column_name)
|
@@ -308,8 +322,12 @@ module ActiveRecord
|
|
308
322
|
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
309
323
|
elsif insert.update_duplicates?
|
310
324
|
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
311
|
-
|
312
|
-
|
325
|
+
if insert.raw_update_sql?
|
326
|
+
sql << insert.raw_update_sql
|
327
|
+
else
|
328
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
|
329
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
330
|
+
end
|
313
331
|
end
|
314
332
|
|
315
333
|
sql
|
@@ -320,7 +338,7 @@ module ActiveRecord
|
|
320
338
|
end
|
321
339
|
|
322
340
|
def get_database_version # :nodoc:
|
323
|
-
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
341
|
+
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
|
324
342
|
end
|
325
343
|
|
326
344
|
def check_version # :nodoc:
|
@@ -329,18 +347,38 @@ module ActiveRecord
|
|
329
347
|
end
|
330
348
|
end
|
331
349
|
|
350
|
+
class SQLite3Integer < Type::Integer # :nodoc:
|
351
|
+
private
|
352
|
+
def _limit
|
353
|
+
# INTEGER storage class can be stored 8 bytes value.
|
354
|
+
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
|
355
|
+
limit || 8
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
|
360
|
+
|
361
|
+
class << self
|
362
|
+
private
|
363
|
+
def initialize_type_map(m)
|
364
|
+
super
|
365
|
+
register_class_with_limit m, %r(int)i, SQLite3Integer
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
370
|
+
|
332
371
|
private
|
372
|
+
def type_map
|
373
|
+
TYPE_MAP
|
374
|
+
end
|
375
|
+
|
333
376
|
# See https://www.sqlite.org/limits.html,
|
334
377
|
# the default value is 999 when not configured.
|
335
378
|
def bind_params_length
|
336
379
|
999
|
337
380
|
end
|
338
381
|
|
339
|
-
def initialize_type_map(m = type_map)
|
340
|
-
super
|
341
|
-
register_class_with_limit m, %r(int)i, SQLite3Integer
|
342
|
-
end
|
343
|
-
|
344
382
|
def table_structure(table_name)
|
345
383
|
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
346
384
|
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
@@ -348,6 +386,34 @@ module ActiveRecord
|
|
348
386
|
end
|
349
387
|
alias column_definitions table_structure
|
350
388
|
|
389
|
+
def extract_value_from_default(default)
|
390
|
+
case default
|
391
|
+
when /^null$/i
|
392
|
+
nil
|
393
|
+
# Quoted types
|
394
|
+
when /^'(.*)'$/m
|
395
|
+
$1.gsub("''", "'")
|
396
|
+
# Quoted types
|
397
|
+
when /^"(.*)"$/m
|
398
|
+
$1.gsub('""', '"')
|
399
|
+
# Numeric types
|
400
|
+
when /\A-?\d+(\.\d*)?\z/
|
401
|
+
$&
|
402
|
+
else
|
403
|
+
# Anything else is blank or some function
|
404
|
+
# and we can't know the value of that, so return nil.
|
405
|
+
nil
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def extract_default_function(default_value, default)
|
410
|
+
default if has_default_function?(default_value, default)
|
411
|
+
end
|
412
|
+
|
413
|
+
def has_default_function?(default_value, default)
|
414
|
+
!default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
415
|
+
end
|
416
|
+
|
351
417
|
# See: https://www.sqlite.org/lang_altertable.html
|
352
418
|
# SQLite has an additional restriction on the ALTER TABLE statement
|
353
419
|
def invalid_alter_table_type?(type, options)
|
@@ -408,8 +474,14 @@ module ActiveRecord
|
|
408
474
|
options[:rename][column.name.to_sym] ||
|
409
475
|
column.name) : column.name
|
410
476
|
|
477
|
+
if column.has_default?
|
478
|
+
type = lookup_cast_type_from_column(column)
|
479
|
+
default = type.deserialize(column.default)
|
480
|
+
default = -> { column.default_function } if default.nil?
|
481
|
+
end
|
482
|
+
|
411
483
|
@definition.column(column_name, column.type,
|
412
|
-
limit: column.limit, default:
|
484
|
+
limit: column.limit, default: default,
|
413
485
|
precision: column.precision, scale: column.scale,
|
414
486
|
null: column.null, collation: column.collation,
|
415
487
|
primary_key: column_name == from_primary_key
|
@@ -446,6 +518,7 @@ module ActiveRecord
|
|
446
518
|
options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
447
519
|
options[:unique] = true if index.unique
|
448
520
|
options[:where] = index.where if index.where
|
521
|
+
options[:order] = index.orders if index.orders
|
449
522
|
add_index(to, columns, **options)
|
450
523
|
end
|
451
524
|
end
|
@@ -482,7 +555,7 @@ module ActiveRecord
|
|
482
555
|
end
|
483
556
|
end
|
484
557
|
|
485
|
-
COLLATE_REGEX =
|
558
|
+
COLLATE_REGEX = /.*"(\w+)".*collate\s+"(\w+)".*/i.freeze
|
486
559
|
|
487
560
|
def table_structure_with_collation(table_name, basic_structure)
|
488
561
|
collation_hash = {}
|
@@ -544,17 +617,6 @@ module ActiveRecord
|
|
544
617
|
|
545
618
|
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
546
619
|
end
|
547
|
-
|
548
|
-
class SQLite3Integer < Type::Integer # :nodoc:
|
549
|
-
private
|
550
|
-
def _limit
|
551
|
-
# INTEGER storage class can be stored 8 bytes value.
|
552
|
-
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
|
553
|
-
limit || 8
|
554
|
-
end
|
555
|
-
end
|
556
|
-
|
557
|
-
ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
|
558
620
|
end
|
559
621
|
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
560
622
|
end
|
@@ -27,20 +27,21 @@ module ActiveRecord
|
|
27
27
|
autoload :ReferenceDefinition
|
28
28
|
end
|
29
29
|
|
30
|
-
autoload_at "active_record/connection_adapters/abstract/connection_pool" do
|
31
|
-
autoload :ConnectionHandler
|
32
|
-
end
|
33
|
-
|
34
30
|
autoload_under "abstract" do
|
35
31
|
autoload :SchemaStatements
|
36
32
|
autoload :DatabaseStatements
|
37
33
|
autoload :DatabaseLimits
|
38
34
|
autoload :Quoting
|
39
|
-
autoload :
|
35
|
+
autoload :ConnectionHandler
|
40
36
|
autoload :QueryCache
|
41
37
|
autoload :Savepoints
|
42
38
|
end
|
43
39
|
|
40
|
+
autoload_at "active_record/connection_adapters/abstract/connection_pool" do
|
41
|
+
autoload :ConnectionPool
|
42
|
+
autoload :NullPool
|
43
|
+
end
|
44
|
+
|
44
45
|
autoload_at "active_record/connection_adapters/abstract/transaction" do
|
45
46
|
autoload :TransactionManager
|
46
47
|
autoload :NullTransaction
|