activerecord 6.0.0 → 6.1.0
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 +872 -582
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations.rb +116 -13
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -29
- data/lib/active_record/associations/association_scope.rb +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency.rb +77 -42
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +86 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +4 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -76
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +81 -57
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +211 -81
- data/lib/active_record/core.rb +237 -69
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +39 -10
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation.rb +108 -67
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder.rb +55 -35
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +340 -180
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +22 -71
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +15 -12
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +27 -24
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -1,9 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_record/connection_adapters/deduplicable"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
# :stopdoc:
|
5
7
|
module ConnectionAdapters
|
6
8
|
class SqlTypeMetadata
|
9
|
+
include Deduplicable
|
10
|
+
|
7
11
|
attr_reader :sql_type, :type, :limit, :precision, :scale
|
8
12
|
|
9
13
|
def initialize(sql_type: nil, type: nil, limit: nil, precision: nil, scale: nil)
|
@@ -32,6 +36,12 @@ module ActiveRecord
|
|
32
36
|
precision.hash >> 1 ^
|
33
37
|
scale.hash >> 2
|
34
38
|
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def deduplicated
|
42
|
+
@sql_type = -sql_type
|
43
|
+
super
|
44
|
+
end
|
35
45
|
end
|
36
46
|
end
|
37
47
|
end
|
@@ -4,19 +4,27 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLite3
|
6
6
|
module DatabaseStatements
|
7
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
7
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
8
|
+
:pragma
|
9
|
+
) # :nodoc:
|
8
10
|
private_constant :READ_QUERY
|
9
11
|
|
10
12
|
def write_query?(sql) # :nodoc:
|
11
13
|
!READ_QUERY.match?(sql)
|
12
14
|
end
|
13
15
|
|
16
|
+
def explain(arel, binds = [])
|
17
|
+
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
18
|
+
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
19
|
+
end
|
20
|
+
|
14
21
|
def execute(sql, name = nil) #:nodoc:
|
15
22
|
if preventing_writes? && write_query?(sql)
|
16
23
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
17
24
|
end
|
18
25
|
|
19
26
|
materialize_transactions
|
27
|
+
mark_transaction_written_if_write(sql)
|
20
28
|
|
21
29
|
log(sql, name) do
|
22
30
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -31,6 +39,7 @@ module ActiveRecord
|
|
31
39
|
end
|
32
40
|
|
33
41
|
materialize_transactions
|
42
|
+
mark_transaction_written_if_write(sql)
|
34
43
|
|
35
44
|
type_casted_binds = type_casted_binds(binds)
|
36
45
|
|
@@ -56,7 +65,7 @@ module ActiveRecord
|
|
56
65
|
records = stmt.to_a
|
57
66
|
end
|
58
67
|
|
59
|
-
|
68
|
+
build_result(columns: cols, rows: records)
|
60
69
|
end
|
61
70
|
end
|
62
71
|
end
|
@@ -67,26 +76,46 @@ module ActiveRecord
|
|
67
76
|
end
|
68
77
|
alias :exec_update :exec_delete
|
69
78
|
|
79
|
+
def begin_isolated_db_transaction(isolation) #:nodoc
|
80
|
+
raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
|
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?
|
82
|
+
|
83
|
+
Thread.current.thread_variable_set("read_uncommitted", @connection.get_first_value("PRAGMA read_uncommitted"))
|
84
|
+
@connection.read_uncommitted = true
|
85
|
+
begin_db_transaction
|
86
|
+
end
|
87
|
+
|
70
88
|
def begin_db_transaction #:nodoc:
|
71
|
-
log("begin transaction",
|
89
|
+
log("begin transaction", "TRANSACTION") { @connection.transaction }
|
72
90
|
end
|
73
91
|
|
74
92
|
def commit_db_transaction #:nodoc:
|
75
|
-
log("commit transaction",
|
93
|
+
log("commit transaction", "TRANSACTION") { @connection.commit }
|
94
|
+
reset_read_uncommitted
|
76
95
|
end
|
77
96
|
|
78
97
|
def exec_rollback_db_transaction #:nodoc:
|
79
|
-
log("rollback transaction",
|
98
|
+
log("rollback transaction", "TRANSACTION") { @connection.rollback }
|
99
|
+
reset_read_uncommitted
|
80
100
|
end
|
81
101
|
|
82
|
-
|
83
102
|
private
|
84
|
-
def
|
103
|
+
def reset_read_uncommitted
|
104
|
+
read_uncommitted = Thread.current.thread_variable_get("read_uncommitted")
|
105
|
+
return unless read_uncommitted
|
106
|
+
|
107
|
+
@connection.read_uncommitted = read_uncommitted
|
108
|
+
end
|
109
|
+
|
110
|
+
def execute_batch(statements, name = nil)
|
111
|
+
sql = combine_multi_statements(statements)
|
112
|
+
|
85
113
|
if preventing_writes? && write_query?(sql)
|
86
114
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
87
115
|
end
|
88
116
|
|
89
117
|
materialize_transactions
|
118
|
+
mark_transaction_written_if_write(sql)
|
90
119
|
|
91
120
|
log(sql, name) do
|
92
121
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -106,11 +135,8 @@ module ActiveRecord
|
|
106
135
|
end.compact
|
107
136
|
end
|
108
137
|
|
109
|
-
def
|
110
|
-
|
111
|
-
"DELETE FROM #{quote_table_name(table_name)}"
|
112
|
-
end
|
113
|
-
combine_multi_statements(truncate_tables)
|
138
|
+
def build_truncate_statement(table_name)
|
139
|
+
"DELETE FROM #{quote_table_name(table_name)}"
|
114
140
|
end
|
115
141
|
end
|
116
142
|
end
|
@@ -60,7 +60,7 @@ module ActiveRecord
|
|
60
60
|
# "table_name"."column_name" | function(one or no argument)
|
61
61
|
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
|
62
62
|
)
|
63
|
-
(?:\s+AS
|
63
|
+
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
64
64
|
)
|
65
65
|
(?:\s*,\s*\g<1>)*
|
66
66
|
\z
|
@@ -82,7 +82,6 @@ module ActiveRecord
|
|
82
82
|
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
83
83
|
|
84
84
|
private
|
85
|
-
|
86
85
|
def _type_cast(value)
|
87
86
|
case value
|
88
87
|
when BigDecimal
|
@@ -3,8 +3,12 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLite3
|
6
|
-
class SchemaCreation <
|
6
|
+
class SchemaCreation < SchemaCreation # :nodoc:
|
7
7
|
private
|
8
|
+
def supports_index_using?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
8
12
|
def add_column_options!(sql, options)
|
9
13
|
if options[:collation]
|
10
14
|
sql << " COLLATE \"#{options[:collation]}\""
|
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
9
9
|
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").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
|
-
next if row["name"].
|
12
|
+
next if row["name"].start_with?("sqlite_")
|
13
13
|
|
14
14
|
index_sql = query_value(<<~SQL, "SCHEMA")
|
15
15
|
SELECT sql
|
@@ -55,13 +55,13 @@ module ActiveRecord
|
|
55
55
|
def add_foreign_key(from_table, to_table, **options)
|
56
56
|
alter_table(from_table) do |definition|
|
57
57
|
to_table = strip_table_name_prefix_and_suffix(to_table)
|
58
|
-
definition.foreign_key(to_table, options)
|
58
|
+
definition.foreign_key(to_table, **options)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
62
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
63
63
|
to_table ||= options[:to_table]
|
64
|
-
options = options.except(:name, :to_table)
|
64
|
+
options = options.except(:name, :to_table, :validate)
|
65
65
|
foreign_keys = foreign_keys(from_table)
|
66
66
|
|
67
67
|
fkey = foreign_keys.detect do |fk|
|
@@ -78,6 +78,35 @@ module ActiveRecord
|
|
78
78
|
alter_table(from_table, foreign_keys)
|
79
79
|
end
|
80
80
|
|
81
|
+
def check_constraints(table_name)
|
82
|
+
table_sql = query_value(<<-SQL, "SCHEMA")
|
83
|
+
SELECT sql
|
84
|
+
FROM sqlite_master
|
85
|
+
WHERE name = #{quote_table_name(table_name)} AND type = 'table'
|
86
|
+
UNION ALL
|
87
|
+
SELECT sql
|
88
|
+
FROM sqlite_temp_master
|
89
|
+
WHERE name = #{quote_table_name(table_name)} AND type = 'table'
|
90
|
+
SQL
|
91
|
+
|
92
|
+
table_sql.to_s.scan(/CONSTRAINT\s+(?<name>\w+)\s+CHECK\s+\((?<expression>(:?[^()]|\(\g<expression>\))+)\)/i).map do |name, expression|
|
93
|
+
CheckConstraintDefinition.new(table_name, expression, name: name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_check_constraint(table_name, expression, **options)
|
98
|
+
alter_table(table_name) do |definition|
|
99
|
+
definition.check_constraint(expression, **options)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def remove_check_constraint(table_name, expression = nil, **options)
|
104
|
+
check_constraints = check_constraints(table_name)
|
105
|
+
chk_name_to_delete = check_constraint_for!(table_name, expression: expression, **options).name
|
106
|
+
check_constraints.delete_if { |chk| chk.name == chk_name_to_delete }
|
107
|
+
alter_table(table_name, foreign_keys(table_name), check_constraints)
|
108
|
+
end
|
109
|
+
|
81
110
|
def create_schema_dumper(options)
|
82
111
|
SQLite3::SchemaDumper.create(self, options)
|
83
112
|
end
|
@@ -87,8 +116,12 @@ module ActiveRecord
|
|
87
116
|
SQLite3::SchemaCreation.new(self)
|
88
117
|
end
|
89
118
|
|
90
|
-
def create_table_definition(
|
91
|
-
SQLite3::TableDefinition.new(self,
|
119
|
+
def create_table_definition(name, **options)
|
120
|
+
SQLite3::TableDefinition.new(self, name, **options)
|
121
|
+
end
|
122
|
+
|
123
|
+
def validate_index_length!(table_name, new_name, internal = false)
|
124
|
+
super unless internal
|
92
125
|
end
|
93
126
|
|
94
127
|
def new_column_from_field(table_name, field)
|
@@ -26,7 +26,7 @@ module ActiveRecord
|
|
26
26
|
# Allow database path relative to Rails.root, but only if the database
|
27
27
|
# path is not the special path that tells sqlite to build a database only
|
28
28
|
# in memory.
|
29
|
-
if ":memory:" != config[:database]
|
29
|
+
if ":memory:" != config[:database] && !config[:database].to_s.start_with?("file:")
|
30
30
|
config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
|
31
31
|
dirname = File.dirname(config[:database])
|
32
32
|
Dir.mkdir(dirname) unless File.directory?(dirname)
|
@@ -48,8 +48,8 @@ module ActiveRecord
|
|
48
48
|
end
|
49
49
|
|
50
50
|
module ConnectionAdapters #:nodoc:
|
51
|
-
# The SQLite3 adapter works
|
52
|
-
#
|
51
|
+
# The SQLite3 adapter works with the sqlite3-ruby drivers
|
52
|
+
# (available as gem from https://rubygems.org/gems/sqlite3).
|
53
53
|
#
|
54
54
|
# Options:
|
55
55
|
#
|
@@ -76,16 +76,6 @@ module ActiveRecord
|
|
76
76
|
json: { name: "json" },
|
77
77
|
}
|
78
78
|
|
79
|
-
def self.represent_boolean_as_integer=(value) # :nodoc:
|
80
|
-
if value == false
|
81
|
-
raise "`.represent_boolean_as_integer=` is now always true, so make sure your application can work with it and remove this settings."
|
82
|
-
end
|
83
|
-
|
84
|
-
ActiveSupport::Deprecation.warn(
|
85
|
-
"`.represent_boolean_as_integer=` is now always true, so setting this is deprecated and will be removed in Rails 6.1."
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
79
|
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
90
80
|
private
|
91
81
|
def dealloc(stmt)
|
@@ -101,7 +91,7 @@ module ActiveRecord
|
|
101
91
|
def self.database_exists?(config)
|
102
92
|
config = config.symbolize_keys
|
103
93
|
if config[:database] == ":memory:"
|
104
|
-
|
94
|
+
true
|
105
95
|
else
|
106
96
|
database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
|
107
97
|
File.exist?(database_file)
|
@@ -116,6 +106,10 @@ module ActiveRecord
|
|
116
106
|
true
|
117
107
|
end
|
118
108
|
|
109
|
+
def supports_transaction_isolation?
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
119
113
|
def supports_partial_index?
|
120
114
|
true
|
121
115
|
end
|
@@ -132,6 +126,10 @@ module ActiveRecord
|
|
132
126
|
true
|
133
127
|
end
|
134
128
|
|
129
|
+
def supports_check_constraints?
|
130
|
+
true
|
131
|
+
end
|
132
|
+
|
135
133
|
def supports_views?
|
136
134
|
true
|
137
135
|
end
|
@@ -144,6 +142,10 @@ module ActiveRecord
|
|
144
142
|
true
|
145
143
|
end
|
146
144
|
|
145
|
+
def supports_common_table_expressions?
|
146
|
+
database_version >= "3.8.3"
|
147
|
+
end
|
148
|
+
|
147
149
|
def supports_insert_on_conflict?
|
148
150
|
database_version >= "3.24.0"
|
149
151
|
end
|
@@ -171,13 +173,6 @@ module ActiveRecord
|
|
171
173
|
true
|
172
174
|
end
|
173
175
|
|
174
|
-
# Returns 62. SQLite supports index names up to 64
|
175
|
-
# characters. The rest is used by Rails internally to perform
|
176
|
-
# temporary rename operations
|
177
|
-
def allowed_index_name_length
|
178
|
-
index_name_length - 2
|
179
|
-
end
|
180
|
-
|
181
176
|
def native_database_types #:nodoc:
|
182
177
|
NATIVE_DATABASE_TYPES
|
183
178
|
end
|
@@ -211,14 +206,6 @@ module ActiveRecord
|
|
211
206
|
end
|
212
207
|
end
|
213
208
|
|
214
|
-
#--
|
215
|
-
# DATABASE STATEMENTS ======================================
|
216
|
-
#++
|
217
|
-
def explain(arel, binds = [])
|
218
|
-
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
219
|
-
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
220
|
-
end
|
221
|
-
|
222
209
|
# SCHEMA STATEMENTS ========================================
|
223
210
|
|
224
211
|
def primary_keys(table_name) # :nodoc:
|
@@ -226,8 +213,11 @@ module ActiveRecord
|
|
226
213
|
pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
|
227
214
|
end
|
228
215
|
|
229
|
-
def remove_index(table_name,
|
230
|
-
|
216
|
+
def remove_index(table_name, column_name = nil, **options) # :nodoc:
|
217
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
218
|
+
|
219
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
220
|
+
|
231
221
|
exec_query "DROP INDEX #{quote_column_name(index_name)}"
|
232
222
|
end
|
233
223
|
|
@@ -236,21 +226,23 @@ module ActiveRecord
|
|
236
226
|
# Example:
|
237
227
|
# rename_table('octopuses', 'octopi')
|
238
228
|
def rename_table(table_name, new_name)
|
229
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
230
|
+
schema_cache.clear_data_source_cache!(new_name.to_s)
|
239
231
|
exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
|
240
232
|
rename_table_indexes(table_name, new_name)
|
241
233
|
end
|
242
234
|
|
243
|
-
def add_column(table_name, column_name, type, options
|
235
|
+
def add_column(table_name, column_name, type, **options) #:nodoc:
|
244
236
|
if invalid_alter_table_type?(type, options)
|
245
237
|
alter_table(table_name) do |definition|
|
246
|
-
definition.column(column_name, type, options)
|
238
|
+
definition.column(column_name, type, **options)
|
247
239
|
end
|
248
240
|
else
|
249
241
|
super
|
250
242
|
end
|
251
243
|
end
|
252
244
|
|
253
|
-
def remove_column(table_name, column_name, type = nil, options
|
245
|
+
def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
|
254
246
|
alter_table(table_name) do |definition|
|
255
247
|
definition.remove_column column_name
|
256
248
|
definition.foreign_keys.delete_if do |_, fk_options|
|
@@ -276,16 +268,11 @@ module ActiveRecord
|
|
276
268
|
end
|
277
269
|
end
|
278
270
|
|
279
|
-
def change_column(table_name, column_name, type, options
|
271
|
+
def change_column(table_name, column_name, type, **options) #:nodoc:
|
280
272
|
alter_table(table_name) do |definition|
|
281
273
|
definition[column_name].instance_eval do
|
282
|
-
self.type
|
283
|
-
self.
|
284
|
-
self.default = options[:default] if options.include?(:default)
|
285
|
-
self.null = options[:null] if options.include?(:null)
|
286
|
-
self.precision = options[:precision] if options.include?(:precision)
|
287
|
-
self.scale = options[:scale] if options.include?(:scale)
|
288
|
-
self.collation = options[:collation] if options.include?(:collation)
|
274
|
+
self.type = type
|
275
|
+
self.options.merge!(options)
|
289
276
|
end
|
290
277
|
end
|
291
278
|
end
|
@@ -321,12 +308,17 @@ module ActiveRecord
|
|
321
308
|
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
322
309
|
elsif insert.update_duplicates?
|
323
310
|
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
311
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
|
324
312
|
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
325
313
|
end
|
326
314
|
|
327
315
|
sql
|
328
316
|
end
|
329
317
|
|
318
|
+
def shared_cache? # :nodoc:
|
319
|
+
@config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
|
320
|
+
end
|
321
|
+
|
330
322
|
def get_database_version # :nodoc:
|
331
323
|
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
332
324
|
end
|
@@ -359,10 +351,16 @@ module ActiveRecord
|
|
359
351
|
# See: https://www.sqlite.org/lang_altertable.html
|
360
352
|
# SQLite has an additional restriction on the ALTER TABLE statement
|
361
353
|
def invalid_alter_table_type?(type, options)
|
362
|
-
type.to_sym == :primary_key || options[:primary_key]
|
354
|
+
type.to_sym == :primary_key || options[:primary_key] ||
|
355
|
+
options[:null] == false && options[:default].nil?
|
363
356
|
end
|
364
357
|
|
365
|
-
def alter_table(
|
358
|
+
def alter_table(
|
359
|
+
table_name,
|
360
|
+
foreign_keys = foreign_keys(table_name),
|
361
|
+
check_constraints = check_constraints(table_name),
|
362
|
+
**options
|
363
|
+
)
|
366
364
|
altered_table_name = "a#{table_name}"
|
367
365
|
|
368
366
|
caller = lambda do |definition|
|
@@ -372,7 +370,11 @@ module ActiveRecord
|
|
372
370
|
fk.options[:column] = column
|
373
371
|
end
|
374
372
|
to_table = strip_table_name_prefix_and_suffix(fk.to_table)
|
375
|
-
definition.foreign_key(to_table, fk.options)
|
373
|
+
definition.foreign_key(to_table, **fk.options)
|
374
|
+
end
|
375
|
+
|
376
|
+
check_constraints.each do |chk|
|
377
|
+
definition.check_constraint(chk.expression, **chk.options)
|
376
378
|
end
|
377
379
|
|
378
380
|
yield definition if block_given?
|
@@ -394,11 +396,12 @@ module ActiveRecord
|
|
394
396
|
def copy_table(from, to, options = {})
|
395
397
|
from_primary_key = primary_key(from)
|
396
398
|
options[:id] = false
|
397
|
-
create_table(to, options) do |definition|
|
399
|
+
create_table(to, **options) do |definition|
|
398
400
|
@definition = definition
|
399
401
|
if from_primary_key.is_a?(Array)
|
400
402
|
@definition.primary_keys from_primary_key
|
401
403
|
end
|
404
|
+
|
402
405
|
columns(from).each do |column|
|
403
406
|
column_name = options[:rename] ?
|
404
407
|
(options[:rename][column.name] ||
|
@@ -440,10 +443,10 @@ module ActiveRecord
|
|
440
443
|
|
441
444
|
unless columns.empty?
|
442
445
|
# index name can't be the same
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
add_index(to, columns,
|
446
|
+
options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
447
|
+
options[:unique] = true if index.unique
|
448
|
+
options[:where] = index.where if index.where
|
449
|
+
add_index(to, columns, **options)
|
447
450
|
end
|
448
451
|
end
|
449
452
|
end
|
@@ -462,17 +465,18 @@ module ActiveRecord
|
|
462
465
|
end
|
463
466
|
|
464
467
|
def translate_exception(exception, message:, sql:, binds:)
|
465
|
-
case exception.message
|
466
468
|
# SQLite 3.8.2 returns a newly formatted error message:
|
467
469
|
# UNIQUE constraint failed: *table_name*.*column_name*
|
468
470
|
# Older versions of SQLite return:
|
469
471
|
# column *column_name* is not unique
|
470
|
-
|
472
|
+
if exception.message.match?(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i)
|
471
473
|
RecordNotUnique.new(message, sql: sql, binds: binds)
|
472
|
-
|
474
|
+
elsif exception.message.match?(/(.* may not be NULL|NOT NULL constraint failed: .*)/i)
|
473
475
|
NotNullViolation.new(message, sql: sql, binds: binds)
|
474
|
-
|
476
|
+
elsif exception.message.match?(/FOREIGN KEY constraint failed/i)
|
475
477
|
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
478
|
+
elsif exception.message.match?(/called on a closed database/i)
|
479
|
+
ConnectionNotEstablished.new(exception)
|
476
480
|
else
|
477
481
|
super
|
478
482
|
end
|
@@ -492,12 +496,12 @@ module ActiveRecord
|
|
492
496
|
# Result will have following sample string
|
493
497
|
# CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
494
498
|
# "password_digest" varchar COLLATE "NOCASE");
|
495
|
-
result =
|
499
|
+
result = query_value(sql, "SCHEMA")
|
496
500
|
|
497
501
|
if result
|
498
502
|
# Splitting with left parentheses and discarding the first part will return all
|
499
503
|
# columns separated with comma(,).
|
500
|
-
columns_string = result
|
504
|
+
columns_string = result.split("(", 2).last
|
501
505
|
|
502
506
|
columns_string.split(",").each do |column_string|
|
503
507
|
# This regex will match the column name and collation type and will save
|
@@ -505,7 +509,7 @@ module ActiveRecord
|
|
505
509
|
collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
|
506
510
|
end
|
507
511
|
|
508
|
-
basic_structure.map
|
512
|
+
basic_structure.map do |column|
|
509
513
|
column_name = column["name"]
|
510
514
|
|
511
515
|
if collation_hash.has_key? column_name
|