activerecord 6.1.6 → 7.0.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1314 -975
- data/README.rdoc +1 -1
- 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 +19 -21
- data/lib/active_record/associations/collection_proxy.rb +10 -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 +49 -13
- 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 +124 -95
- 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 +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +14 -15
- 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 +2 -2
- data/lib/active_record/coders/yaml_column.rb +10 -2
- 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 +38 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -24
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +105 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
- data/lib/active_record/connection_adapters/mysql/quoting.rb +37 -21
- 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 +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- 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 +51 -51
- 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 +37 -19
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +208 -107
- 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 +28 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +96 -32
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +49 -55
- data/lib/active_record/core.rb +124 -134
- 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/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 +4 -4
- 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 +10 -9
- 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 +7 -7
- data/lib/active_record/migration/compatibility.rb +84 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +114 -83
- 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 +228 -60
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -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 +1 -1
- data/lib/active_record/railties/databases.rake +78 -136
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +73 -50
- 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 +43 -38
- 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.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +276 -67
- 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 +17 -7
- 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 +25 -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 +7 -2
- data/lib/active_record/suppressor.rb +11 -15
- 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 +16 -9
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- 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 +1 -1
- 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 +217 -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/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)
|
@@ -45,6 +45,34 @@ module ActiveRecord
|
|
45
45
|
0
|
46
46
|
end
|
47
47
|
|
48
|
+
def quote_default_expression(value, column) # :nodoc:
|
49
|
+
if value.is_a?(Proc)
|
50
|
+
value = value.call
|
51
|
+
if value.match?(/\A\w+\(.*\)\z/)
|
52
|
+
"(#{value})"
|
53
|
+
else
|
54
|
+
value
|
55
|
+
end
|
56
|
+
else
|
57
|
+
super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def type_cast(value) # :nodoc:
|
62
|
+
case value
|
63
|
+
when BigDecimal
|
64
|
+
value.to_f
|
65
|
+
when String
|
66
|
+
if value.encoding == Encoding::ASCII_8BIT
|
67
|
+
super(value.encode(Encoding::UTF_8))
|
68
|
+
else
|
69
|
+
super
|
70
|
+
end
|
71
|
+
else
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
48
76
|
def column_name_matcher
|
49
77
|
COLUMN_NAME
|
50
78
|
end
|
@@ -80,22 +108,6 @@ module ActiveRecord
|
|
80
108
|
/ix
|
81
109
|
|
82
110
|
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
111
|
end
|
100
112
|
end
|
101
113
|
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)
|
@@ -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,7 +285,7 @@ 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
290
|
definition[column_name].instance_eval do
|
274
291
|
self.type = aliased_types(type.to_s, type)
|
@@ -277,7 +294,7 @@ module ActiveRecord
|
|
277
294
|
end
|
278
295
|
end
|
279
296
|
|
280
|
-
def rename_column(table_name, column_name, new_column_name)
|
297
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
281
298
|
column = column_for(table_name, column_name)
|
282
299
|
alter_table(table_name, rename: { column.name => new_column_name.to_s })
|
283
300
|
rename_column_indexes(table_name, column.name, new_column_name)
|
@@ -308,8 +325,12 @@ module ActiveRecord
|
|
308
325
|
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
309
326
|
elsif insert.update_duplicates?
|
310
327
|
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
311
|
-
|
312
|
-
|
328
|
+
if insert.raw_update_sql?
|
329
|
+
sql << insert.raw_update_sql
|
330
|
+
else
|
331
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
|
332
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
333
|
+
end
|
313
334
|
end
|
314
335
|
|
315
336
|
sql
|
@@ -320,7 +341,7 @@ module ActiveRecord
|
|
320
341
|
end
|
321
342
|
|
322
343
|
def get_database_version # :nodoc:
|
323
|
-
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
344
|
+
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
|
324
345
|
end
|
325
346
|
|
326
347
|
def check_version # :nodoc:
|
@@ -329,18 +350,38 @@ module ActiveRecord
|
|
329
350
|
end
|
330
351
|
end
|
331
352
|
|
353
|
+
class SQLite3Integer < Type::Integer # :nodoc:
|
354
|
+
private
|
355
|
+
def _limit
|
356
|
+
# INTEGER storage class can be stored 8 bytes value.
|
357
|
+
# See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
|
358
|
+
limit || 8
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
|
363
|
+
|
364
|
+
class << self
|
365
|
+
private
|
366
|
+
def initialize_type_map(m)
|
367
|
+
super
|
368
|
+
register_class_with_limit m, %r(int)i, SQLite3Integer
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
373
|
+
|
332
374
|
private
|
375
|
+
def type_map
|
376
|
+
TYPE_MAP
|
377
|
+
end
|
378
|
+
|
333
379
|
# See https://www.sqlite.org/limits.html,
|
334
380
|
# the default value is 999 when not configured.
|
335
381
|
def bind_params_length
|
336
382
|
999
|
337
383
|
end
|
338
384
|
|
339
|
-
def initialize_type_map(m = type_map)
|
340
|
-
super
|
341
|
-
register_class_with_limit m, %r(int)i, SQLite3Integer
|
342
|
-
end
|
343
|
-
|
344
385
|
def table_structure(table_name)
|
345
386
|
structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
|
346
387
|
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
|
@@ -348,6 +389,34 @@ module ActiveRecord
|
|
348
389
|
end
|
349
390
|
alias column_definitions table_structure
|
350
391
|
|
392
|
+
def extract_value_from_default(default)
|
393
|
+
case default
|
394
|
+
when /^null$/i
|
395
|
+
nil
|
396
|
+
# Quoted types
|
397
|
+
when /^'(.*)'$/m
|
398
|
+
$1.gsub("''", "'")
|
399
|
+
# Quoted types
|
400
|
+
when /^"(.*)"$/m
|
401
|
+
$1.gsub('""', '"')
|
402
|
+
# Numeric types
|
403
|
+
when /\A-?\d+(\.\d*)?\z/
|
404
|
+
$&
|
405
|
+
else
|
406
|
+
# Anything else is blank or some function
|
407
|
+
# and we can't know the value of that, so return nil.
|
408
|
+
nil
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def extract_default_function(default_value, default)
|
413
|
+
default if has_default_function?(default_value, default)
|
414
|
+
end
|
415
|
+
|
416
|
+
def has_default_function?(default_value, default)
|
417
|
+
!default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
418
|
+
end
|
419
|
+
|
351
420
|
# See: https://www.sqlite.org/lang_altertable.html
|
352
421
|
# SQLite has an additional restriction on the ALTER TABLE statement
|
353
422
|
def invalid_alter_table_type?(type, options)
|
@@ -408,8 +477,13 @@ module ActiveRecord
|
|
408
477
|
options[:rename][column.name.to_sym] ||
|
409
478
|
column.name) : column.name
|
410
479
|
|
480
|
+
if column.has_default?
|
481
|
+
type = lookup_cast_type_from_column(column)
|
482
|
+
default = type.deserialize(column.default)
|
483
|
+
end
|
484
|
+
|
411
485
|
@definition.column(column_name, column.type,
|
412
|
-
limit: column.limit, default:
|
486
|
+
limit: column.limit, default: default,
|
413
487
|
precision: column.precision, scale: column.scale,
|
414
488
|
null: column.null, collation: column.collation,
|
415
489
|
primary_key: column_name == from_primary_key
|
@@ -446,6 +520,7 @@ module ActiveRecord
|
|
446
520
|
options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
447
521
|
options[:unique] = true if index.unique
|
448
522
|
options[:where] = index.where if index.where
|
523
|
+
options[:order] = index.orders if index.orders
|
449
524
|
add_index(to, columns, **options)
|
450
525
|
end
|
451
526
|
end
|
@@ -482,7 +557,7 @@ module ActiveRecord
|
|
482
557
|
end
|
483
558
|
end
|
484
559
|
|
485
|
-
COLLATE_REGEX =
|
560
|
+
COLLATE_REGEX = /.*"(\w+)".*collate\s+"(\w+)".*/i.freeze
|
486
561
|
|
487
562
|
def table_structure_with_collation(table_name, basic_structure)
|
488
563
|
collation_hash = {}
|
@@ -544,17 +619,6 @@ module ActiveRecord
|
|
544
619
|
|
545
620
|
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
546
621
|
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
622
|
end
|
559
623
|
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
560
624
|
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
|