activerecord 6.1.7 → 7.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -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 +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +92 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +96 -16
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -28,6 +28,12 @@ module ActiveRecord
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
# TODO: Remove when IPAddr#== compares IPAddr#prefix. See
|
32
|
+
# https://github.com/ruby/ipaddr/issues/21
|
33
|
+
def changed?(old_value, new_value, _new_value_before_type_cast)
|
34
|
+
!old_value.eql?(new_value) || !old_value.nil? && old_value.prefix != new_value.prefix
|
35
|
+
end
|
36
|
+
|
31
37
|
def cast_value(value)
|
32
38
|
if value.nil?
|
33
39
|
nil
|
@@ -16,6 +16,14 @@ module ActiveRecord
|
|
16
16
|
super
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def type_cast_for_schema(value)
|
21
|
+
case value
|
22
|
+
when ::Float::INFINITY then "::Float::INFINITY"
|
23
|
+
when -::Float::INFINITY then "-::Float::INFINITY"
|
24
|
+
else super
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "strscan"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters
|
5
7
|
module PostgreSQL
|
6
8
|
module OID # :nodoc:
|
7
9
|
class Hstore < Type::Value # :nodoc:
|
10
|
+
ERROR = "Invalid Hstore document: %s"
|
11
|
+
|
8
12
|
include ActiveModel::Type::Helpers::Mutable
|
9
13
|
|
10
14
|
def type
|
@@ -12,15 +16,56 @@ module ActiveRecord
|
|
12
16
|
end
|
13
17
|
|
14
18
|
def deserialize(value)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
return value unless value.is_a?(::String)
|
20
|
+
|
21
|
+
scanner = StringScanner.new(value)
|
22
|
+
hash = {}
|
23
|
+
|
24
|
+
until scanner.eos?
|
25
|
+
unless scanner.skip(/"/)
|
26
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
27
|
+
end
|
28
|
+
|
29
|
+
unless key = scanner.scan(/^(\\[\\"]|[^\\"])*?(?=")/)
|
30
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
31
|
+
end
|
32
|
+
|
33
|
+
unless scanner.skip(/"=>?/)
|
34
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
35
|
+
end
|
36
|
+
|
37
|
+
if scanner.scan(/NULL/)
|
38
|
+
value = nil
|
39
|
+
else
|
40
|
+
unless scanner.skip(/"/)
|
41
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
42
|
+
end
|
43
|
+
|
44
|
+
unless value = scanner.scan(/^(\\[\\"]|[^\\"])*?(?=")/)
|
45
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
46
|
+
end
|
47
|
+
|
48
|
+
unless scanner.skip(/"/)
|
49
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
key.gsub!('\"', '"')
|
54
|
+
key.gsub!("\\\\", "\\")
|
55
|
+
|
56
|
+
if value
|
57
|
+
value.gsub!('\"', '"')
|
58
|
+
value.gsub!("\\\\", "\\")
|
59
|
+
end
|
60
|
+
|
61
|
+
hash[key] = value
|
62
|
+
|
63
|
+
unless scanner.skip(/, /) || scanner.eos?
|
64
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
65
|
+
end
|
23
66
|
end
|
67
|
+
|
68
|
+
hash
|
24
69
|
end
|
25
70
|
|
26
71
|
def serialize(value)
|
@@ -46,12 +91,6 @@ module ActiveRecord
|
|
46
91
|
end
|
47
92
|
|
48
93
|
private
|
49
|
-
HstorePair = begin
|
50
|
-
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
|
51
|
-
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
|
52
|
-
/(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
|
53
|
-
end
|
54
|
-
|
55
94
|
def escape_hstore(value)
|
56
95
|
if value.nil?
|
57
96
|
"NULL"
|
@@ -27,9 +27,10 @@ module ActiveRecord
|
|
27
27
|
value = value.sub(/^\((.+)\)$/, '-\1') # (4)
|
28
28
|
case value
|
29
29
|
when /^-?\D*+[\d,]+\.\d{2}$/ # (1)
|
30
|
-
value.
|
30
|
+
value.delete!("^-0-9.")
|
31
31
|
when /^-?\D*+[\d.]+,\d{2}$/ # (2)
|
32
|
-
value.
|
32
|
+
value.delete!("^-0-9,")
|
33
|
+
value.tr!(",", ".")
|
33
34
|
end
|
34
35
|
|
35
36
|
super(value)
|
@@ -18,7 +18,7 @@ module ActiveRecord
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def cast_value(value)
|
21
|
-
return if
|
21
|
+
return if ["empty", ""].include? value
|
22
22
|
return value unless value.is_a?(::String)
|
23
23
|
|
24
24
|
extracted = extract_bounds(value)
|
@@ -28,7 +28,7 @@ module ActiveRecord
|
|
28
28
|
if !infinity?(from) && extracted[:exclude_start]
|
29
29
|
raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
|
30
30
|
end
|
31
|
-
::Range.new(from, to, extracted[:exclude_end])
|
31
|
+
::Range.new(*sanitize_bounds(from, to), extracted[:exclude_end])
|
32
32
|
end
|
33
33
|
|
34
34
|
def serialize(value)
|
@@ -76,6 +76,15 @@ module ActiveRecord
|
|
76
76
|
}
|
77
77
|
end
|
78
78
|
|
79
|
+
INFINITE_FLOAT_RANGE = (-::Float::INFINITY)..(::Float::INFINITY) # :nodoc:
|
80
|
+
|
81
|
+
def sanitize_bounds(from, to)
|
82
|
+
[
|
83
|
+
(from == -::Float::INFINITY && !INFINITE_FLOAT_RANGE.cover?(to)) ? nil : from,
|
84
|
+
(to == ::Float::INFINITY && !INFINITE_FLOAT_RANGE.cover?(from)) ? nil : to
|
85
|
+
]
|
86
|
+
end
|
87
|
+
|
79
88
|
# When formatting the bound values of range types, PostgreSQL quotes
|
80
89
|
# the bound value using double-quotes in certain conditions. Within
|
81
90
|
# a double-quoted string, literal " and \ characters are themselves
|
@@ -88,7 +97,7 @@ module ActiveRecord
|
|
88
97
|
if value.start_with?('"') && value.end_with?('"')
|
89
98
|
unquoted_value = value[1..-2]
|
90
99
|
unquoted_value.gsub!('""', '"')
|
91
|
-
unquoted_value.gsub!(
|
100
|
+
unquoted_value.gsub!("\\\\", "\\")
|
92
101
|
unquoted_value
|
93
102
|
else
|
94
103
|
value
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module OID # :nodoc:
|
7
|
+
class Timestamp < DateTime # :nodoc:
|
8
|
+
def type
|
9
|
+
real_type_unless_aliased(:timestamp)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module OID # :nodoc:
|
7
|
+
class TimestampWithTimeZone < DateTime # :nodoc:
|
8
|
+
def type
|
9
|
+
real_type_unless_aliased(:timestamptz)
|
10
|
+
end
|
11
|
+
|
12
|
+
def cast_value(value)
|
13
|
+
return if value.blank?
|
14
|
+
|
15
|
+
time = super
|
16
|
+
return time if time.is_a?(ActiveSupport::TimeWithZone) || !time.acts_like?(:time)
|
17
|
+
|
18
|
+
# While in UTC mode, the PG gem may not return times back in "UTC" even if they were provided to PostgreSQL in UTC.
|
19
|
+
# We prefer times always in UTC, so here we convert back.
|
20
|
+
if is_utc?
|
21
|
+
time.getutc
|
22
|
+
else
|
23
|
+
time.getlocal
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -33,15 +33,27 @@ module ActiveRecord
|
|
33
33
|
composites.each { |row| register_composite_type(row) }
|
34
34
|
end
|
35
35
|
|
36
|
-
def
|
36
|
+
def query_conditions_for_known_type_names
|
37
37
|
known_type_names = @store.keys.map { |n| "'#{n}'" }
|
38
|
-
|
39
|
-
<<~SQL % [known_type_names.join(", "), known_type_types.join(", ")]
|
38
|
+
<<~SQL % known_type_names.join(", ")
|
40
39
|
WHERE
|
41
40
|
t.typname IN (%s)
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
SQL
|
42
|
+
end
|
43
|
+
|
44
|
+
def query_conditions_for_known_type_types
|
45
|
+
known_type_types = %w('r' 'e' 'd')
|
46
|
+
<<~SQL % known_type_types.join(", ")
|
47
|
+
WHERE
|
48
|
+
t.typtype IN (%s)
|
49
|
+
SQL
|
50
|
+
end
|
51
|
+
|
52
|
+
def query_conditions_for_array_types
|
53
|
+
known_type_oids = @store.keys.reject { |k| k.is_a?(String) }
|
54
|
+
<<~SQL % [known_type_oids.join(", ")]
|
55
|
+
WHERE
|
56
|
+
t.typelem IN (%s)
|
45
57
|
SQL
|
46
58
|
end
|
47
59
|
|
@@ -20,6 +20,8 @@ require "active_record/connection_adapters/postgresql/oid/point"
|
|
20
20
|
require "active_record/connection_adapters/postgresql/oid/legacy_point"
|
21
21
|
require "active_record/connection_adapters/postgresql/oid/range"
|
22
22
|
require "active_record/connection_adapters/postgresql/oid/specialized_string"
|
23
|
+
require "active_record/connection_adapters/postgresql/oid/timestamp"
|
24
|
+
require "active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone"
|
23
25
|
require "active_record/connection_adapters/postgresql/oid/uuid"
|
24
26
|
require "active_record/connection_adapters/postgresql/oid/vector"
|
25
27
|
require "active_record/connection_adapters/postgresql/oid/xml"
|
@@ -4,21 +4,77 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module PostgreSQL
|
6
6
|
module Quoting
|
7
|
+
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
8
|
+
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
9
|
+
|
10
|
+
class IntegerOutOf64BitRange < StandardError
|
11
|
+
def initialize(msg)
|
12
|
+
super(msg)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
7
16
|
# Escapes binary strings for bytea input to the database.
|
8
17
|
def escape_bytea(value)
|
9
|
-
|
18
|
+
valid_raw_connection.escape_bytea(value) if value
|
10
19
|
end
|
11
20
|
|
12
21
|
# Unescapes bytea output from a database to the binary string it represents.
|
13
22
|
# NOTE: This is NOT an inverse of escape_bytea! This is only to be used
|
14
23
|
# on escaped binary output from database drive.
|
15
24
|
def unescape_bytea(value)
|
16
|
-
|
25
|
+
valid_raw_connection.unescape_bytea(value) if value
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_int_in_range(value)
|
29
|
+
if value.to_int > 9223372036854775807 || value.to_int < -9223372036854775808
|
30
|
+
exception = <<~ERROR
|
31
|
+
Provided value outside of the range of a signed 64bit integer.
|
32
|
+
|
33
|
+
PostgreSQL will treat the column type in question as a numeric.
|
34
|
+
This may result in a slow sequential scan due to a comparison
|
35
|
+
being performed between an integer or bigint value and a numeric value.
|
36
|
+
|
37
|
+
To allow for this potentially unwanted behavior, set
|
38
|
+
ActiveRecord.raise_int_wider_than_64bit to false.
|
39
|
+
ERROR
|
40
|
+
raise IntegerOutOf64BitRange.new exception
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def quote(value) # :nodoc:
|
45
|
+
if ActiveRecord.raise_int_wider_than_64bit && value.is_a?(Integer)
|
46
|
+
check_int_in_range(value)
|
47
|
+
end
|
48
|
+
|
49
|
+
case value
|
50
|
+
when OID::Xml::Data
|
51
|
+
"xml '#{quote_string(value.to_s)}'"
|
52
|
+
when OID::Bit::Data
|
53
|
+
if value.binary?
|
54
|
+
"B'#{value}'"
|
55
|
+
elsif value.hex?
|
56
|
+
"X'#{value}'"
|
57
|
+
end
|
58
|
+
when Numeric
|
59
|
+
if value.finite?
|
60
|
+
super
|
61
|
+
else
|
62
|
+
"'#{value}'"
|
63
|
+
end
|
64
|
+
when OID::Array::Data
|
65
|
+
quote(encode_array(value))
|
66
|
+
when Range
|
67
|
+
quote(encode_range(value))
|
68
|
+
else
|
69
|
+
super
|
70
|
+
end
|
17
71
|
end
|
18
72
|
|
19
73
|
# Quotes strings for use in SQL input.
|
20
|
-
def quote_string(s)
|
21
|
-
|
74
|
+
def quote_string(s) # :nodoc:
|
75
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |connection|
|
76
|
+
connection.escape(s)
|
77
|
+
end
|
22
78
|
end
|
23
79
|
|
24
80
|
# Checks the following cases:
|
@@ -30,7 +86,7 @@ module ActiveRecord
|
|
30
86
|
# - "schema.name".table_name
|
31
87
|
# - "schema.name"."table.name"
|
32
88
|
def quote_table_name(name) # :nodoc:
|
33
|
-
|
89
|
+
QUOTED_TABLE_NAMES[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
|
34
90
|
end
|
35
91
|
|
36
92
|
# Quotes schema names for use in SQL queries.
|
@@ -44,11 +100,11 @@ module ActiveRecord
|
|
44
100
|
|
45
101
|
# Quotes column names for use in SQL queries.
|
46
102
|
def quote_column_name(name) # :nodoc:
|
47
|
-
|
103
|
+
QUOTED_COLUMN_NAMES[name] ||= PG::Connection.quote_ident(super).freeze
|
48
104
|
end
|
49
105
|
|
50
106
|
# Quote date/time values for use in SQL input.
|
51
|
-
def quoted_date(value)
|
107
|
+
def quoted_date(value) # :nodoc:
|
52
108
|
if value.year <= 0
|
53
109
|
bce_year = format("%04d", -value.year + 1)
|
54
110
|
super.sub(/^-?\d+/, bce_year) + " BC"
|
@@ -64,7 +120,7 @@ module ActiveRecord
|
|
64
120
|
def quote_default_expression(value, column) # :nodoc:
|
65
121
|
if value.is_a?(Proc)
|
66
122
|
value.call
|
67
|
-
elsif column.type == :uuid && value.is_a?(String) &&
|
123
|
+
elsif column.type == :uuid && value.is_a?(String) && value.include?("()")
|
68
124
|
value # Does not quote function default values for UUID columns
|
69
125
|
elsif column.respond_to?(:array?)
|
70
126
|
type = lookup_cast_type_from_column(column)
|
@@ -74,7 +130,26 @@ module ActiveRecord
|
|
74
130
|
end
|
75
131
|
end
|
76
132
|
|
133
|
+
def type_cast(value) # :nodoc:
|
134
|
+
case value
|
135
|
+
when Type::Binary::Data
|
136
|
+
# Return a bind param hash with format as binary.
|
137
|
+
# See https://deveiate.org/code/pg/PG/Connection.html#method-i-exec_prepared-doc
|
138
|
+
# for more information
|
139
|
+
{ value: value.to_s, format: 1 }
|
140
|
+
when OID::Xml::Data, OID::Bit::Data
|
141
|
+
value.to_s
|
142
|
+
when OID::Array::Data
|
143
|
+
encode_array(value)
|
144
|
+
when Range
|
145
|
+
encode_range(value)
|
146
|
+
else
|
147
|
+
super
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
77
151
|
def lookup_cast_type_from_column(column) # :nodoc:
|
152
|
+
verify! if type_map.nil?
|
78
153
|
type_map.lookup(column.oid, column.fmod, column.sql_type)
|
79
154
|
end
|
80
155
|
|
@@ -90,8 +165,8 @@ module ActiveRecord
|
|
90
165
|
\A
|
91
166
|
(
|
92
167
|
(?:
|
93
|
-
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
94
|
-
((?:\w+\.|"\w+"\.)
|
168
|
+
# "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
|
169
|
+
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)? | \w+\((?:|\g<2>)\)(?:::\w+)?)
|
95
170
|
)
|
96
171
|
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
97
172
|
)
|
@@ -103,9 +178,10 @@ module ActiveRecord
|
|
103
178
|
\A
|
104
179
|
(
|
105
180
|
(?:
|
106
|
-
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
107
|
-
((?:\w+\.|"\w+"\.)
|
181
|
+
# "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
|
182
|
+
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)? | \w+\((?:|\g<2>)\)(?:::\w+)?)
|
108
183
|
)
|
184
|
+
(?:\s+COLLATE\s+"\w+")?
|
109
185
|
(?:\s+ASC|\s+DESC)?
|
110
186
|
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
111
187
|
)
|
@@ -120,49 +196,6 @@ module ActiveRecord
|
|
120
196
|
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
|
121
197
|
end
|
122
198
|
|
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
199
|
def encode_array(array_data)
|
167
200
|
encoder = array_data.encoder
|
168
201
|
values = type_cast_array(array_data.values)
|
@@ -188,7 +221,7 @@ module ActiveRecord
|
|
188
221
|
def type_cast_array(values)
|
189
222
|
case values
|
190
223
|
when ::Array then values.map { |item| type_cast_array(item) }
|
191
|
-
else
|
224
|
+
else type_cast(values)
|
192
225
|
end
|
193
226
|
end
|
194
227
|
|
@@ -37,6 +37,34 @@ Rails needs superuser privileges to disable referential integrity.
|
|
37
37
|
rescue ActiveRecord::ActiveRecordError
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
def check_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'' AND connamespace::regnamespace = ''%I''::regnamespace; ALTER TABLE %I.%I VALIDATE CONSTRAINT %I;',
|
49
|
+
constraint_name,
|
50
|
+
table_schema,
|
51
|
+
table_schema,
|
52
|
+
table_name,
|
53
|
+
constraint_name
|
54
|
+
) AS constraint_check
|
55
|
+
FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'
|
56
|
+
)
|
57
|
+
LOOP
|
58
|
+
EXECUTE (r.constraint_check);
|
59
|
+
END LOOP;
|
60
|
+
END;
|
61
|
+
$$;
|
62
|
+
SQL
|
63
|
+
|
64
|
+
transaction(requires_new: true) do
|
65
|
+
execute(sql)
|
66
|
+
end
|
67
|
+
end
|
40
68
|
end
|
41
69
|
end
|
42
70
|
end
|
@@ -5,12 +5,28 @@ module ActiveRecord
|
|
5
5
|
module PostgreSQL
|
6
6
|
class SchemaCreation < SchemaCreation # :nodoc:
|
7
7
|
private
|
8
|
+
delegate :quoted_include_columns_for_index, to: :@conn
|
9
|
+
|
8
10
|
def visit_AlterTable(o)
|
9
|
-
|
11
|
+
sql = super
|
12
|
+
sql << o.constraint_validations.map { |fk| visit_ValidateConstraint fk }.join(" ")
|
13
|
+
sql << o.exclusion_constraint_adds.map { |con| visit_AddExclusionConstraint con }.join(" ")
|
14
|
+
sql << o.exclusion_constraint_drops.map { |con| visit_DropExclusionConstraint con }.join(" ")
|
15
|
+
sql << o.unique_constraint_adds.map { |con| visit_AddUniqueConstraint con }.join(" ")
|
16
|
+
sql << o.unique_constraint_drops.map { |con| visit_DropUniqueConstraint con }.join(" ")
|
10
17
|
end
|
11
18
|
|
12
19
|
def visit_AddForeignKey(o)
|
13
|
-
super.dup.tap
|
20
|
+
super.dup.tap do |sql|
|
21
|
+
sql << " DEFERRABLE INITIALLY #{o.options[:deferrable].to_s.upcase}" if o.deferrable
|
22
|
+
sql << " NOT VALID" unless o.validate?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def visit_ForeignKeyDefinition(o)
|
27
|
+
super.dup.tap do |sql|
|
28
|
+
sql << " DEFERRABLE INITIALLY #{o.deferrable.to_s.upcase}" if o.deferrable
|
29
|
+
end
|
14
30
|
end
|
15
31
|
|
16
32
|
def visit_CheckConstraintDefinition(o)
|
@@ -21,6 +37,54 @@ module ActiveRecord
|
|
21
37
|
"VALIDATE CONSTRAINT #{quote_column_name(name)}"
|
22
38
|
end
|
23
39
|
|
40
|
+
def visit_ExclusionConstraintDefinition(o)
|
41
|
+
sql = ["CONSTRAINT"]
|
42
|
+
sql << quote_column_name(o.name)
|
43
|
+
sql << "EXCLUDE"
|
44
|
+
sql << "USING #{o.using}" if o.using
|
45
|
+
sql << "(#{o.expression})"
|
46
|
+
sql << "WHERE (#{o.where})" if o.where
|
47
|
+
sql << "DEFERRABLE INITIALLY #{o.deferrable.to_s.upcase}" if o.deferrable
|
48
|
+
|
49
|
+
sql.join(" ")
|
50
|
+
end
|
51
|
+
|
52
|
+
def visit_UniqueConstraintDefinition(o)
|
53
|
+
column_name = Array(o.column).map { |column| quote_column_name(column) }.join(", ")
|
54
|
+
|
55
|
+
sql = ["CONSTRAINT"]
|
56
|
+
sql << quote_column_name(o.name)
|
57
|
+
sql << "UNIQUE"
|
58
|
+
|
59
|
+
if o.using_index
|
60
|
+
sql << "USING INDEX #{quote_column_name(o.using_index)}"
|
61
|
+
else
|
62
|
+
sql << "(#{column_name})"
|
63
|
+
end
|
64
|
+
|
65
|
+
if o.deferrable
|
66
|
+
sql << "DEFERRABLE INITIALLY #{o.deferrable.to_s.upcase}"
|
67
|
+
end
|
68
|
+
|
69
|
+
sql.join(" ")
|
70
|
+
end
|
71
|
+
|
72
|
+
def visit_AddExclusionConstraint(o)
|
73
|
+
"ADD #{accept(o)}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def visit_DropExclusionConstraint(name)
|
77
|
+
"DROP CONSTRAINT #{quote_column_name(name)}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def visit_AddUniqueConstraint(o)
|
81
|
+
"ADD #{accept(o)}"
|
82
|
+
end
|
83
|
+
|
84
|
+
def visit_DropUniqueConstraint(name)
|
85
|
+
"DROP CONSTRAINT #{quote_column_name(name)}"
|
86
|
+
end
|
87
|
+
|
24
88
|
def visit_ChangeColumnDefinition(o)
|
25
89
|
column = o.column
|
26
90
|
column.sql_type = type_to_sql(column.type, **column.options)
|
@@ -57,13 +121,39 @@ module ActiveRecord
|
|
57
121
|
change_column_sql
|
58
122
|
end
|
59
123
|
|
124
|
+
def visit_ChangeColumnDefaultDefinition(o)
|
125
|
+
sql = +"ALTER COLUMN #{quote_column_name(o.column.name)} "
|
126
|
+
if o.default.nil?
|
127
|
+
sql << "DROP DEFAULT"
|
128
|
+
else
|
129
|
+
sql << "SET DEFAULT #{quote_default_expression(o.default, o.column)}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
60
133
|
def add_column_options!(sql, options)
|
61
134
|
if options[:collation]
|
62
135
|
sql << " COLLATE \"#{options[:collation]}\""
|
63
136
|
end
|
137
|
+
|
138
|
+
if as = options[:as]
|
139
|
+
sql << " GENERATED ALWAYS AS (#{as})"
|
140
|
+
|
141
|
+
if options[:stored]
|
142
|
+
sql << " STORED"
|
143
|
+
else
|
144
|
+
raise ArgumentError, <<~MSG
|
145
|
+
PostgreSQL currently does not support VIRTUAL (not persisted) generated columns.
|
146
|
+
Specify 'stored: true' option for '#{options[:column].name}'
|
147
|
+
MSG
|
148
|
+
end
|
149
|
+
end
|
64
150
|
super
|
65
151
|
end
|
66
152
|
|
153
|
+
def quoted_include_columns(o)
|
154
|
+
String === o ? o : quoted_include_columns_for_index(o)
|
155
|
+
end
|
156
|
+
|
67
157
|
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
68
158
|
def table_modifier_in_create(o)
|
69
159
|
# A table cannot be both TEMPORARY and UNLOGGED, since all TEMPORARY
|