activerecord 6.1.4.1 → 7.0.1
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 +1132 -936
- data/MIT-LICENSE +1 -1
- 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 +34 -27
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- 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 +6 -2
- data/lib/active_record/associations/preloader/association.rb +187 -55
- 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 +118 -90
- 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 +66 -12
- 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 +13 -14
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +6 -21
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -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 +34 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +78 -22
- 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 +97 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +5 -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 +21 -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 +50 -50
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -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 +29 -18
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +205 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +27 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +16 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +89 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +47 -53
- data/lib/active_record/core.rb +122 -132
- 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 +16 -32
- data/lib/active_record/delegated_type.rb +52 -11
- 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 +61 -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 +208 -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 +49 -42
- 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 +17 -20
- 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 +3 -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 +9 -3
- data/lib/active_record/log_subscriber.rb +14 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +107 -3
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +45 -58
- 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 +219 -52
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +127 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +66 -129
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +67 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +43 -38
- data/lib/active_record/relation/delegation.rb +6 -6
- 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 +243 -61
- 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 +184 -84
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +10 -3
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +61 -12
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +120 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +4 -4
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- 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 +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +204 -28
- 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 +59 -14
@@ -16,8 +16,33 @@ module ActiveRecord
|
|
16
16
|
@connection.unescape_bytea(value) if value
|
17
17
|
end
|
18
18
|
|
19
|
+
def quote(value) # :nodoc:
|
20
|
+
case value
|
21
|
+
when OID::Xml::Data
|
22
|
+
"xml '#{quote_string(value.to_s)}'"
|
23
|
+
when OID::Bit::Data
|
24
|
+
if value.binary?
|
25
|
+
"B'#{value}'"
|
26
|
+
elsif value.hex?
|
27
|
+
"X'#{value}'"
|
28
|
+
end
|
29
|
+
when Numeric
|
30
|
+
if value.finite?
|
31
|
+
super
|
32
|
+
else
|
33
|
+
"'#{value}'"
|
34
|
+
end
|
35
|
+
when OID::Array::Data
|
36
|
+
quote(encode_array(value))
|
37
|
+
when Range
|
38
|
+
quote(encode_range(value))
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
19
44
|
# Quotes strings for use in SQL input.
|
20
|
-
def quote_string(s)
|
45
|
+
def quote_string(s) # :nodoc:
|
21
46
|
PG::Connection.escape(s)
|
22
47
|
end
|
23
48
|
|
@@ -48,7 +73,7 @@ module ActiveRecord
|
|
48
73
|
end
|
49
74
|
|
50
75
|
# Quote date/time values for use in SQL input.
|
51
|
-
def quoted_date(value)
|
76
|
+
def quoted_date(value) # :nodoc:
|
52
77
|
if value.year <= 0
|
53
78
|
bce_year = format("%04d", -value.year + 1)
|
54
79
|
super.sub(/^-?\d+/, bce_year) + " BC"
|
@@ -74,6 +99,24 @@ module ActiveRecord
|
|
74
99
|
end
|
75
100
|
end
|
76
101
|
|
102
|
+
def type_cast(value) # :nodoc:
|
103
|
+
case value
|
104
|
+
when Type::Binary::Data
|
105
|
+
# Return a bind param hash with format as binary.
|
106
|
+
# See https://deveiate.org/code/pg/PG/Connection.html#method-i-exec_prepared-doc
|
107
|
+
# for more information
|
108
|
+
{ value: value.to_s, format: 1 }
|
109
|
+
when OID::Xml::Data, OID::Bit::Data
|
110
|
+
value.to_s
|
111
|
+
when OID::Array::Data
|
112
|
+
encode_array(value)
|
113
|
+
when Range
|
114
|
+
encode_range(value)
|
115
|
+
else
|
116
|
+
super
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
77
120
|
def lookup_cast_type_from_column(column) # :nodoc:
|
78
121
|
type_map.lookup(column.oid, column.fmod, column.sql_type)
|
79
122
|
end
|
@@ -90,8 +133,8 @@ module ActiveRecord
|
|
90
133
|
\A
|
91
134
|
(
|
92
135
|
(?:
|
93
|
-
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
94
|
-
((?:\w+\.|"\w+"\.)
|
136
|
+
# "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
|
137
|
+
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
95
138
|
)
|
96
139
|
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
97
140
|
)
|
@@ -103,8 +146,8 @@ module ActiveRecord
|
|
103
146
|
\A
|
104
147
|
(
|
105
148
|
(?:
|
106
|
-
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
107
|
-
((?:\w+\.|"\w+"\.)
|
149
|
+
# "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
|
150
|
+
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
108
151
|
)
|
109
152
|
(?:\s+ASC|\s+DESC)?
|
110
153
|
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
@@ -120,49 +163,6 @@ module ActiveRecord
|
|
120
163
|
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
|
121
164
|
end
|
122
165
|
|
123
|
-
def _quote(value)
|
124
|
-
case value
|
125
|
-
when OID::Xml::Data
|
126
|
-
"xml '#{quote_string(value.to_s)}'"
|
127
|
-
when OID::Bit::Data
|
128
|
-
if value.binary?
|
129
|
-
"B'#{value}'"
|
130
|
-
elsif value.hex?
|
131
|
-
"X'#{value}'"
|
132
|
-
end
|
133
|
-
when Numeric
|
134
|
-
if value.finite?
|
135
|
-
super
|
136
|
-
else
|
137
|
-
"'#{value}'"
|
138
|
-
end
|
139
|
-
when OID::Array::Data
|
140
|
-
_quote(encode_array(value))
|
141
|
-
when Range
|
142
|
-
_quote(encode_range(value))
|
143
|
-
else
|
144
|
-
super
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def _type_cast(value)
|
149
|
-
case value
|
150
|
-
when Type::Binary::Data
|
151
|
-
# Return a bind param hash with format as binary.
|
152
|
-
# See https://deveiate.org/code/pg/PG/Connection.html#method-i-exec_prepared-doc
|
153
|
-
# for more information
|
154
|
-
{ value: value.to_s, format: 1 }
|
155
|
-
when OID::Xml::Data, OID::Bit::Data
|
156
|
-
value.to_s
|
157
|
-
when OID::Array::Data
|
158
|
-
encode_array(value)
|
159
|
-
when Range
|
160
|
-
encode_range(value)
|
161
|
-
else
|
162
|
-
super
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
166
|
def encode_array(array_data)
|
167
167
|
encoder = array_data.encoder
|
168
168
|
values = type_cast_array(array_data.values)
|
@@ -188,7 +188,7 @@ module ActiveRecord
|
|
188
188
|
def type_cast_array(values)
|
189
189
|
case values
|
190
190
|
when ::Array then values.map { |item| type_cast_array(item) }
|
191
|
-
else
|
191
|
+
else type_cast(values)
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
@@ -37,6 +37,38 @@ Rails needs superuser privileges to disable referential integrity.
|
|
37
37
|
rescue ActiveRecord::ActiveRecordError
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
def all_foreign_keys_valid? # :nodoc:
|
42
|
+
sql = <<~SQL
|
43
|
+
do $$
|
44
|
+
declare r record;
|
45
|
+
BEGIN
|
46
|
+
FOR r IN (
|
47
|
+
SELECT FORMAT(
|
48
|
+
'UPDATE pg_constraint SET convalidated=false WHERE conname = ''%I''; ALTER TABLE %I VALIDATE CONSTRAINT %I;',
|
49
|
+
constraint_name,
|
50
|
+
table_name,
|
51
|
+
constraint_name
|
52
|
+
) AS constraint_check
|
53
|
+
FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'
|
54
|
+
)
|
55
|
+
LOOP
|
56
|
+
EXECUTE (r.constraint_check);
|
57
|
+
END LOOP;
|
58
|
+
END;
|
59
|
+
$$;
|
60
|
+
SQL
|
61
|
+
|
62
|
+
begin
|
63
|
+
transaction(requires_new: true) do
|
64
|
+
execute(sql)
|
65
|
+
end
|
66
|
+
|
67
|
+
true
|
68
|
+
rescue ActiveRecord::StatementInvalid
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
40
72
|
end
|
41
73
|
end
|
42
74
|
end
|
@@ -10,7 +10,14 @@ module ActiveRecord
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def visit_AddForeignKey(o)
|
13
|
-
super.dup.tap
|
13
|
+
super.dup.tap do |sql|
|
14
|
+
if o.deferrable
|
15
|
+
sql << " DEFERRABLE"
|
16
|
+
sql << " INITIALLY #{o.deferrable.to_s.upcase}" unless o.deferrable == true
|
17
|
+
end
|
18
|
+
|
19
|
+
sql << " NOT VALID" unless o.validate?
|
20
|
+
end
|
14
21
|
end
|
15
22
|
|
16
23
|
def visit_CheckConstraintDefinition(o)
|
@@ -61,6 +68,19 @@ module ActiveRecord
|
|
61
68
|
if options[:collation]
|
62
69
|
sql << " COLLATE \"#{options[:collation]}\""
|
63
70
|
end
|
71
|
+
|
72
|
+
if as = options[:as]
|
73
|
+
sql << " GENERATED ALWAYS AS (#{as})"
|
74
|
+
|
75
|
+
if options[:stored]
|
76
|
+
sql << " STORED"
|
77
|
+
else
|
78
|
+
raise ArgumentError, <<~MSG
|
79
|
+
PostgreSQL currently does not support VIRTUAL (not persisted) generated columns.
|
80
|
+
Specify 'stored: true' option for '#{options[:column].name}'
|
81
|
+
MSG
|
82
|
+
end
|
83
|
+
end
|
64
84
|
super
|
65
85
|
end
|
66
86
|
|
@@ -173,11 +173,19 @@ module ActiveRecord
|
|
173
173
|
# :method: xml
|
174
174
|
# :call-seq: xml(*names, **options)
|
175
175
|
|
176
|
+
##
|
177
|
+
# :method: timestamptz
|
178
|
+
# :call-seq: timestamptz(*names, **options)
|
179
|
+
|
180
|
+
##
|
181
|
+
# :method: enum
|
182
|
+
# :call-seq: enum(*names, **options)
|
183
|
+
|
176
184
|
included do
|
177
185
|
define_column_methods :bigserial, :bit, :bit_varying, :cidr, :citext, :daterange,
|
178
186
|
:hstore, :inet, :interval, :int4range, :int8range, :jsonb, :ltree, :macaddr,
|
179
187
|
:money, :numrange, :oid, :point, :line, :lseg, :box, :path, :polygon, :circle,
|
180
|
-
:serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml
|
188
|
+
:serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml, :timestamptz, :enum
|
181
189
|
end
|
182
190
|
end
|
183
191
|
|
@@ -191,7 +199,20 @@ module ActiveRecord
|
|
191
199
|
@unlogged = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables
|
192
200
|
end
|
193
201
|
|
202
|
+
def new_column_definition(name, type, **options) # :nodoc:
|
203
|
+
case type
|
204
|
+
when :virtual
|
205
|
+
type = options[:type]
|
206
|
+
end
|
207
|
+
|
208
|
+
super
|
209
|
+
end
|
210
|
+
|
194
211
|
private
|
212
|
+
def aliased_types(name, fallback)
|
213
|
+
fallback
|
214
|
+
end
|
215
|
+
|
195
216
|
def integer_like_primary_key_type(type, options)
|
196
217
|
if type == :bigint || options[:limit] == 8
|
197
218
|
:bigserial
|
@@ -16,9 +16,30 @@ module ActiveRecord
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
def types(stream)
|
20
|
+
types = @connection.enum_types
|
21
|
+
if types.any?
|
22
|
+
stream.puts " # Custom types defined in this database."
|
23
|
+
stream.puts " # Note that some types may not work with other database engines. Be careful if changing database."
|
24
|
+
types.sort.each do |name, values|
|
25
|
+
stream.puts " create_enum #{name.inspect}, #{values.split(",").inspect}"
|
26
|
+
end
|
27
|
+
stream.puts
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
19
31
|
def prepare_column_options(column)
|
20
32
|
spec = super
|
21
33
|
spec[:array] = "true" if column.array?
|
34
|
+
|
35
|
+
if @connection.supports_virtual_columns? && column.virtual?
|
36
|
+
spec[:as] = extract_expression_for_virtual_column(column)
|
37
|
+
spec[:stored] = true
|
38
|
+
spec = { type: schema_type(column).inspect }.merge!(spec)
|
39
|
+
end
|
40
|
+
|
41
|
+
spec[:enum_type] = "\"#{column.sql_type}\"" if column.enum?
|
42
|
+
|
22
43
|
spec
|
23
44
|
end
|
24
45
|
|
@@ -43,6 +64,10 @@ module ActiveRecord
|
|
43
64
|
def schema_expression(column)
|
44
65
|
super unless column.serial?
|
45
66
|
end
|
67
|
+
|
68
|
+
def extract_expression_for_virtual_column(column)
|
69
|
+
column.default_function.inspect
|
70
|
+
end
|
46
71
|
end
|
47
72
|
end
|
48
73
|
end
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
module SchemaStatements
|
7
7
|
# Drops the database specified on the +name+ attribute
|
8
8
|
# and creates it again using the provided +options+.
|
9
|
-
def recreate_database(name, options = {})
|
9
|
+
def recreate_database(name, options = {}) # :nodoc:
|
10
10
|
drop_database(name)
|
11
11
|
create_database(name, options)
|
12
12
|
end
|
@@ -50,7 +50,7 @@ module ActiveRecord
|
|
50
50
|
#
|
51
51
|
# Example:
|
52
52
|
# drop_database 'matt_development'
|
53
|
-
def drop_database(name)
|
53
|
+
def drop_database(name) # :nodoc:
|
54
54
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
55
55
|
end
|
56
56
|
|
@@ -244,7 +244,7 @@ module ActiveRecord
|
|
244
244
|
end
|
245
245
|
|
246
246
|
# Returns the sequence name for a table's primary key or some other specified key.
|
247
|
-
def default_sequence_name(table_name, pk = "id")
|
247
|
+
def default_sequence_name(table_name, pk = "id") # :nodoc:
|
248
248
|
result = serial_sequence(table_name, pk)
|
249
249
|
return nil unless result
|
250
250
|
Utils.extract_schema_qualified_name(result).to_s
|
@@ -257,7 +257,7 @@ module ActiveRecord
|
|
257
257
|
end
|
258
258
|
|
259
259
|
# Sets the sequence of a table's primary key to the specified value.
|
260
|
-
def set_pk_sequence!(table, value)
|
260
|
+
def set_pk_sequence!(table, value) # :nodoc:
|
261
261
|
pk, sequence = pk_and_sequence_for(table)
|
262
262
|
|
263
263
|
if pk
|
@@ -272,7 +272,7 @@ module ActiveRecord
|
|
272
272
|
end
|
273
273
|
|
274
274
|
# Resets the sequence of a table's primary key to the maximum value.
|
275
|
-
def reset_pk_sequence!(table, pk = nil, sequence = nil)
|
275
|
+
def reset_pk_sequence!(table, pk = nil, sequence = nil) # :nodoc:
|
276
276
|
unless pk && sequence
|
277
277
|
default_pk, default_sequence = pk_and_sequence_for(table)
|
278
278
|
|
@@ -300,7 +300,7 @@ module ActiveRecord
|
|
300
300
|
end
|
301
301
|
|
302
302
|
# Returns a table's primary key and belonging sequence.
|
303
|
-
def pk_and_sequence_for(table)
|
303
|
+
def pk_and_sequence_for(table) # :nodoc:
|
304
304
|
# First try looking for a sequence with a dependency on the
|
305
305
|
# given table's primary key.
|
306
306
|
result = query(<<~SQL, "SCHEMA")[0]
|
@@ -393,13 +393,13 @@ module ActiveRecord
|
|
393
393
|
rename_table_indexes(table_name, new_name)
|
394
394
|
end
|
395
395
|
|
396
|
-
def add_column(table_name, column_name, type, **options)
|
396
|
+
def add_column(table_name, column_name, type, **options) # :nodoc:
|
397
397
|
clear_cache!
|
398
398
|
super
|
399
399
|
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
400
400
|
end
|
401
401
|
|
402
|
-
def change_column(table_name, column_name, type, **options)
|
402
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
403
403
|
clear_cache!
|
404
404
|
sqls, procs = Array(change_column_for_alter(table_name, column_name, type, **options)).partition { |v| v.is_a?(String) }
|
405
405
|
execute "ALTER TABLE #{quote_table_name(table_name)} #{sqls.join(", ")}"
|
@@ -411,7 +411,7 @@ module ActiveRecord
|
|
411
411
|
execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}"
|
412
412
|
end
|
413
413
|
|
414
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
414
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
415
415
|
clear_cache!
|
416
416
|
unless null || default.nil?
|
417
417
|
column = column_for(table_name, column_name)
|
@@ -435,13 +435,13 @@ module ActiveRecord
|
|
435
435
|
end
|
436
436
|
|
437
437
|
# Renames a column in a table.
|
438
|
-
def rename_column(table_name, column_name, new_column_name)
|
438
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
439
439
|
clear_cache!
|
440
440
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_sql(table_name, column_name, new_column_name)}")
|
441
441
|
rename_column_indexes(table_name, column_name, new_column_name)
|
442
442
|
end
|
443
443
|
|
444
|
-
def add_index(table_name, column_name, **options)
|
444
|
+
def add_index(table_name, column_name, **options) # :nodoc:
|
445
445
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
446
446
|
|
447
447
|
create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
|
@@ -483,7 +483,7 @@ module ActiveRecord
|
|
483
483
|
def foreign_keys(table_name)
|
484
484
|
scope = quoted_scope(table_name)
|
485
485
|
fk_info = exec_query(<<~SQL, "SCHEMA")
|
486
|
-
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid
|
486
|
+
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid, c.condeferrable AS deferrable, c.condeferred AS deferred
|
487
487
|
FROM pg_constraint c
|
488
488
|
JOIN pg_class t1 ON c.conrelid = t1.oid
|
489
489
|
JOIN pg_class t2 ON c.confrelid = t2.oid
|
@@ -505,6 +505,8 @@ module ActiveRecord
|
|
505
505
|
|
506
506
|
options[:on_delete] = extract_foreign_key_action(row["on_delete"])
|
507
507
|
options[:on_update] = extract_foreign_key_action(row["on_update"])
|
508
|
+
options[:deferrable] = extract_foreign_key_deferrable(row["deferrable"], row["deferred"])
|
509
|
+
|
508
510
|
options[:validate] = row["valid"]
|
509
511
|
|
510
512
|
ForeignKeyDefinition.new(table_name, row["to_table"], options)
|
@@ -523,7 +525,7 @@ module ActiveRecord
|
|
523
525
|
scope = quoted_scope(table_name)
|
524
526
|
|
525
527
|
check_info = exec_query(<<-SQL, "SCHEMA")
|
526
|
-
SELECT conname, pg_get_constraintdef(c.oid) AS constraintdef, c.convalidated AS valid
|
528
|
+
SELECT conname, pg_get_constraintdef(c.oid, true) AS constraintdef, c.convalidated AS valid
|
527
529
|
FROM pg_constraint c
|
528
530
|
JOIN pg_class t ON c.conrelid = t.oid
|
529
531
|
WHERE c.contype = 'c'
|
@@ -535,14 +537,14 @@ module ActiveRecord
|
|
535
537
|
name: row["conname"],
|
536
538
|
validate: row["valid"]
|
537
539
|
}
|
538
|
-
expression = row["constraintdef"][/CHECK \(
|
540
|
+
expression = row["constraintdef"][/CHECK \((.+)\)/m, 1]
|
539
541
|
|
540
542
|
CheckConstraintDefinition.new(table_name, expression, options)
|
541
543
|
end
|
542
544
|
end
|
543
545
|
|
544
546
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
545
|
-
def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
|
547
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, enum_type: nil, **) # :nodoc:
|
546
548
|
sql = \
|
547
549
|
case type.to_s
|
548
550
|
when "binary"
|
@@ -566,6 +568,10 @@ module ActiveRecord
|
|
566
568
|
when 5..8; "bigint"
|
567
569
|
else raise ArgumentError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead."
|
568
570
|
end
|
571
|
+
when "enum"
|
572
|
+
raise ArgumentError, "enum_type is required for enums" if enum_type.nil?
|
573
|
+
|
574
|
+
enum_type
|
569
575
|
else
|
570
576
|
super
|
571
577
|
end
|
@@ -576,7 +582,7 @@ module ActiveRecord
|
|
576
582
|
|
577
583
|
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
|
578
584
|
# requires that the ORDER BY include the distinct column.
|
579
|
-
def columns_for_distinct(columns, orders)
|
585
|
+
def columns_for_distinct(columns, orders) # :nodoc:
|
580
586
|
order_columns = orders.compact_blank.map { |s|
|
581
587
|
# Convert Arel node to string
|
582
588
|
s = visitor.compile(s) unless s.is_a?(String)
|
@@ -654,7 +660,7 @@ module ActiveRecord
|
|
654
660
|
end
|
655
661
|
|
656
662
|
def new_column_from_field(table_name, field)
|
657
|
-
column_name, type, default, notnull, oid, fmod, collation, comment = field
|
663
|
+
column_name, type, default, notnull, oid, fmod, collation, comment, attgenerated = field
|
658
664
|
type_metadata = fetch_type_metadata(column_name, type, oid.to_i, fmod.to_i)
|
659
665
|
default_value = extract_value_from_default(default)
|
660
666
|
default_function = extract_default_function(default_value, default)
|
@@ -671,7 +677,8 @@ module ActiveRecord
|
|
671
677
|
default_function,
|
672
678
|
collation: collation,
|
673
679
|
comment: comment.presence,
|
674
|
-
serial: serial
|
680
|
+
serial: serial,
|
681
|
+
generated: attgenerated
|
675
682
|
)
|
676
683
|
end
|
677
684
|
|
@@ -711,6 +718,10 @@ module ActiveRecord
|
|
711
718
|
end
|
712
719
|
end
|
713
720
|
|
721
|
+
def extract_foreign_key_deferrable(deferrable, deferred)
|
722
|
+
deferrable && (deferred ? :deferred : true)
|
723
|
+
end
|
724
|
+
|
714
725
|
def add_column_for_alter(table_name, column_name, type, **options)
|
715
726
|
return super unless options.key?(:comment)
|
716
727
|
[super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
|