activerecord 7.1.5.2 → 8.1.2.1
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 +567 -2443
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +3 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +18 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +36 -5
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +268 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +8 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +250 -315
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +20 -27
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +96 -68
- data/lib/active_record/autosave_association.rb +93 -58
- data/lib/active_record/base.rb +5 -7
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +136 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +44 -41
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
- data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +66 -0
- data/lib/active_record/connection_handling.rb +88 -46
- data/lib/active_record/core.rb +142 -58
- data/lib/active_record/counter_cache.rb +52 -18
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +28 -5
- data/lib/active_record/database_configurations/hash_config.rb +103 -41
- data/lib/active_record/database_configurations/url_config.rb +30 -1
- data/lib/active_record/database_configurations.rb +8 -4
- data/lib/active_record/delegated_type.rb +43 -19
- data/lib/active_record/dynamic_matchers.rb +56 -71
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +12 -12
- data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
- data/lib/active_record/encryption/encryptor.rb +58 -22
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +57 -36
- data/lib/active_record/errors.rb +76 -26
- data/lib/active_record/explain.rb +14 -25
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +39 -35
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +5 -3
- data/lib/active_record/insert_all.rb +28 -20
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +15 -7
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -34
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +46 -14
- data/lib/active_record/migration/compatibility.rb +40 -25
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +119 -103
- data/lib/active_record/model_schema.rb +66 -78
- data/lib/active_record/nested_attributes.rb +17 -9
- data/lib/active_record/persistence.rb +161 -454
- data/lib/active_record/query_cache.rb +33 -15
- data/lib/active_record/query_logs.rb +106 -39
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +28 -16
- data/lib/active_record/railtie.rb +61 -74
- data/lib/active_record/railties/controller_runtime.rb +19 -5
- data/lib/active_record/railties/databases.rake +64 -78
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +147 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +153 -73
- data/lib/active_record/relation/calculations.rb +146 -96
- data/lib/active_record/relation/delegation.rb +30 -23
- data/lib/active_record/relation/finder_methods.rb +64 -34
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +25 -10
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +351 -124
- data/lib/active_record/relation/spawn_methods.rb +9 -25
- data/lib/active_record/relation/where_clause.rb +17 -30
- data/lib/active_record/relation.rb +590 -124
- data/lib/active_record/result.rb +131 -59
- data/lib/active_record/runtime_registry.rb +44 -21
- data/lib/active_record/sanitization.rb +33 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +66 -31
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +68 -20
- data/lib/active_record/statement_cache.rb +29 -25
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +7 -33
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +118 -90
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +17 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +123 -89
- data/lib/active_record/testing/query_assertions.rb +127 -0
- data/lib/active_record/timestamp.rb +6 -4
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +129 -0
- data/lib/active_record/transactions.rb +97 -18
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +12 -7
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +5 -4
- data/lib/active_record/validations/associated.rb +10 -4
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +203 -59
- data/lib/arel/alias_predication.rb +3 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +6 -5
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -4
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +14 -5
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -3
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +56 -12
- data/lib/arel/visitors/sqlite.rb +80 -8
- data/lib/arel/visitors/to_sql.rb +34 -37
- data/lib/arel.rb +10 -4
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +23 -14
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -167
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
|
@@ -20,23 +20,12 @@ require "active_record/connection_adapters/postgresql/type_metadata"
|
|
|
20
20
|
require "active_record/connection_adapters/postgresql/utils"
|
|
21
21
|
|
|
22
22
|
module ActiveRecord
|
|
23
|
-
module ConnectionHandling # :nodoc:
|
|
24
|
-
def postgresql_adapter_class
|
|
25
|
-
ConnectionAdapters::PostgreSQLAdapter
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Establishes a connection to the database that's used by all Active Record objects
|
|
29
|
-
def postgresql_connection(config)
|
|
30
|
-
postgresql_adapter_class.new(config)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
23
|
module ConnectionAdapters
|
|
35
24
|
# = Active Record PostgreSQL Adapter
|
|
36
25
|
#
|
|
37
26
|
# The PostgreSQL adapter works with the native C (https://github.com/ged/ruby-pg) driver.
|
|
38
27
|
#
|
|
39
|
-
# Options
|
|
28
|
+
# ==== Options
|
|
40
29
|
#
|
|
41
30
|
# * <tt>:host</tt> - Defaults to a Unix-domain socket in /tmp. On machines without Unix-domain sockets,
|
|
42
31
|
# the default is to connect to localhost.
|
|
@@ -97,7 +86,7 @@ module ActiveRecord
|
|
|
97
86
|
"-c #{name}=#{value.to_s.gsub(/[ \\]/, '\\\\\0')}" unless value == ":default" || value == :default
|
|
98
87
|
end.join(" ")
|
|
99
88
|
end
|
|
100
|
-
find_cmd_and_exec(
|
|
89
|
+
find_cmd_and_exec(ActiveRecord.database_cli[:postgresql], config.database)
|
|
101
90
|
end
|
|
102
91
|
end
|
|
103
92
|
|
|
@@ -133,6 +122,15 @@ module ActiveRecord
|
|
|
133
122
|
# setting, you should immediately run <tt>bin/rails db:migrate</tt> to update the types in your schema.rb.
|
|
134
123
|
class_attribute :datetime_type, default: :timestamp
|
|
135
124
|
|
|
125
|
+
##
|
|
126
|
+
# :singleton-method:
|
|
127
|
+
# Toggles automatic decoding of date columns.
|
|
128
|
+
#
|
|
129
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.select_value("select '2024-01-01'::date").class #=> String
|
|
130
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.decode_dates = true
|
|
131
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.select_value("select '2024-01-01'::date").class #=> Date
|
|
132
|
+
class_attribute :decode_dates, default: false
|
|
133
|
+
|
|
136
134
|
NATIVE_DATABASE_TYPES = {
|
|
137
135
|
primary_key: "bigserial primary key",
|
|
138
136
|
string: { name: "character varying" },
|
|
@@ -286,12 +284,22 @@ module ActiveRecord
|
|
|
286
284
|
database_version >= 15_00_00 # >= 15.0
|
|
287
285
|
end
|
|
288
286
|
|
|
289
|
-
def
|
|
290
|
-
|
|
287
|
+
def supports_native_partitioning? # :nodoc:
|
|
288
|
+
database_version >= 10_00_00 # >= 10.0
|
|
291
289
|
end
|
|
292
290
|
|
|
293
|
-
|
|
294
|
-
|
|
291
|
+
if PG::Connection.method_defined?(:close_prepared) # pg 1.6.0 & libpq 17
|
|
292
|
+
def supports_close_prepared? # :nodoc:
|
|
293
|
+
database_version >= 17_00_00
|
|
294
|
+
end
|
|
295
|
+
else
|
|
296
|
+
def supports_close_prepared? # :nodoc:
|
|
297
|
+
false
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def index_algorithms
|
|
302
|
+
{ concurrently: "CONCURRENTLY" }
|
|
295
303
|
end
|
|
296
304
|
|
|
297
305
|
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
|
@@ -311,8 +319,12 @@ module ActiveRecord
|
|
|
311
319
|
# accessed while holding the connection's lock. (And we
|
|
312
320
|
# don't need the complication of with_raw_connection because
|
|
313
321
|
# a reconnect would invalidate the entire statement pool.)
|
|
314
|
-
if conn = @connection.instance_variable_get(:@raw_connection)
|
|
315
|
-
|
|
322
|
+
if (conn = @connection.instance_variable_get(:@raw_connection)) && conn.status == PG::CONNECTION_OK
|
|
323
|
+
if @connection.supports_close_prepared?
|
|
324
|
+
conn.close_prepared key
|
|
325
|
+
else
|
|
326
|
+
conn.query "DEALLOCATE #{key}"
|
|
327
|
+
end
|
|
316
328
|
end
|
|
317
329
|
rescue PG::Error
|
|
318
330
|
end
|
|
@@ -342,11 +354,16 @@ module ActiveRecord
|
|
|
342
354
|
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
|
343
355
|
end
|
|
344
356
|
|
|
357
|
+
def connected?
|
|
358
|
+
!(@raw_connection.nil? || @raw_connection.finished?)
|
|
359
|
+
end
|
|
360
|
+
|
|
345
361
|
# Is this connection alive and ready for queries?
|
|
346
362
|
def active?
|
|
347
363
|
@lock.synchronize do
|
|
348
364
|
return false unless @raw_connection
|
|
349
365
|
@raw_connection.query ";"
|
|
366
|
+
verified!
|
|
350
367
|
end
|
|
351
368
|
true
|
|
352
369
|
rescue PG::Error
|
|
@@ -378,6 +395,11 @@ module ActiveRecord
|
|
|
378
395
|
end
|
|
379
396
|
end
|
|
380
397
|
|
|
398
|
+
def clear_cache!(new_connection: false)
|
|
399
|
+
super
|
|
400
|
+
@schema_search_path = nil if new_connection
|
|
401
|
+
end
|
|
402
|
+
|
|
381
403
|
# Disconnects from the database if already connected. Otherwise, this
|
|
382
404
|
# method does nothing.
|
|
383
405
|
def disconnect!
|
|
@@ -394,10 +416,6 @@ module ActiveRecord
|
|
|
394
416
|
@raw_connection = nil
|
|
395
417
|
end
|
|
396
418
|
|
|
397
|
-
def native_database_types # :nodoc:
|
|
398
|
-
self.class.native_database_types
|
|
399
|
-
end
|
|
400
|
-
|
|
401
419
|
def self.native_database_types # :nodoc:
|
|
402
420
|
@native_database_types ||= begin
|
|
403
421
|
types = NATIVE_DATABASE_TYPES.dup
|
|
@@ -407,7 +425,7 @@ module ActiveRecord
|
|
|
407
425
|
end
|
|
408
426
|
|
|
409
427
|
def set_standard_conforming_strings
|
|
410
|
-
internal_execute("SET standard_conforming_strings = on")
|
|
428
|
+
internal_execute("SET standard_conforming_strings = on", "SCHEMA")
|
|
411
429
|
end
|
|
412
430
|
|
|
413
431
|
def supports_ddl_transactions?
|
|
@@ -481,6 +499,7 @@ module ActiveRecord
|
|
|
481
499
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
482
500
|
# Defaults to false.
|
|
483
501
|
def disable_extension(name, force: false)
|
|
502
|
+
_schema, name = name.to_s.split(".").values_at(-2, -1)
|
|
484
503
|
internal_exec_query("DROP EXTENSION IF EXISTS \"#{name}\"#{' CASCADE' if force == :cascade}").tap {
|
|
485
504
|
reload_type_map
|
|
486
505
|
}
|
|
@@ -495,7 +514,19 @@ module ActiveRecord
|
|
|
495
514
|
end
|
|
496
515
|
|
|
497
516
|
def extensions
|
|
498
|
-
|
|
517
|
+
query = <<~SQL
|
|
518
|
+
SELECT
|
|
519
|
+
pg_extension.extname,
|
|
520
|
+
n.nspname AS schema
|
|
521
|
+
FROM pg_extension
|
|
522
|
+
JOIN pg_namespace n ON pg_extension.extnamespace = n.oid
|
|
523
|
+
SQL
|
|
524
|
+
|
|
525
|
+
internal_exec_query(query, "SCHEMA", allow_retry: true, materialize_transactions: false).cast_values.map do |row|
|
|
526
|
+
name, schema = row[0], row[1]
|
|
527
|
+
schema = nil if schema == current_schema
|
|
528
|
+
[schema, name].compact.join(".")
|
|
529
|
+
end
|
|
499
530
|
end
|
|
500
531
|
|
|
501
532
|
# Returns a list of defined enum types, and their values.
|
|
@@ -505,7 +536,7 @@ module ActiveRecord
|
|
|
505
536
|
type.typname AS name,
|
|
506
537
|
type.OID AS oid,
|
|
507
538
|
n.nspname AS schema,
|
|
508
|
-
|
|
539
|
+
array_agg(enum.enumlabel ORDER BY enum.enumsortorder) AS value
|
|
509
540
|
FROM pg_enum AS enum
|
|
510
541
|
JOIN pg_type AS type ON (type.oid = enum.enumtypid)
|
|
511
542
|
JOIN pg_namespace n ON type.typnamespace = n.oid
|
|
@@ -560,30 +591,34 @@ module ActiveRecord
|
|
|
560
591
|
end
|
|
561
592
|
|
|
562
593
|
# Rename an existing enum type to something else.
|
|
563
|
-
def rename_enum(name,
|
|
564
|
-
|
|
594
|
+
def rename_enum(name, new_name = nil, **options)
|
|
595
|
+
new_name ||= options.fetch(:to) do
|
|
596
|
+
raise ArgumentError, "rename_enum requires two from/to name positional arguments."
|
|
597
|
+
end
|
|
565
598
|
|
|
566
|
-
exec_query("ALTER TYPE #{quote_table_name(name)} RENAME TO #{
|
|
599
|
+
exec_query("ALTER TYPE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}").tap { reload_type_map }
|
|
567
600
|
end
|
|
568
601
|
|
|
569
602
|
# Add enum value to an existing enum type.
|
|
570
|
-
def add_enum_value(type_name, value, options
|
|
603
|
+
def add_enum_value(type_name, value, **options)
|
|
571
604
|
before, after = options.values_at(:before, :after)
|
|
572
|
-
sql = +"ALTER TYPE #{quote_table_name(type_name)} ADD VALUE
|
|
605
|
+
sql = +"ALTER TYPE #{quote_table_name(type_name)} ADD VALUE"
|
|
606
|
+
sql << " IF NOT EXISTS" if options[:if_not_exists]
|
|
607
|
+
sql << " #{quote(value)}"
|
|
573
608
|
|
|
574
609
|
if before && after
|
|
575
610
|
raise ArgumentError, "Cannot have both :before and :after at the same time"
|
|
576
611
|
elsif before
|
|
577
|
-
sql << " BEFORE
|
|
612
|
+
sql << " BEFORE #{quote(before)}"
|
|
578
613
|
elsif after
|
|
579
|
-
sql << " AFTER
|
|
614
|
+
sql << " AFTER #{quote(after)}"
|
|
580
615
|
end
|
|
581
616
|
|
|
582
617
|
execute(sql).tap { reload_type_map }
|
|
583
618
|
end
|
|
584
619
|
|
|
585
620
|
# Rename enum value on an existing enum type.
|
|
586
|
-
def rename_enum_value(type_name, options
|
|
621
|
+
def rename_enum_value(type_name, **options)
|
|
587
622
|
unless database_version >= 10_00_00 # >= 10.0
|
|
588
623
|
raise ArgumentError, "Renaming enum values is only supported in PostgreSQL 10 or later"
|
|
589
624
|
end
|
|
@@ -591,12 +626,12 @@ module ActiveRecord
|
|
|
591
626
|
from = options.fetch(:from) { raise ArgumentError, ":from is required" }
|
|
592
627
|
to = options.fetch(:to) { raise ArgumentError, ":to is required" }
|
|
593
628
|
|
|
594
|
-
execute("ALTER TYPE #{quote_table_name(type_name)} RENAME VALUE
|
|
629
|
+
execute("ALTER TYPE #{quote_table_name(type_name)} RENAME VALUE #{quote(from)} TO #{quote(to)}").tap {
|
|
595
630
|
reload_type_map
|
|
596
631
|
}
|
|
597
632
|
end
|
|
598
633
|
|
|
599
|
-
# Returns the configured supported identifier length supported by PostgreSQL
|
|
634
|
+
# Returns the configured maximum supported identifier length supported by PostgreSQL
|
|
600
635
|
def max_identifier_length
|
|
601
636
|
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
|
602
637
|
end
|
|
@@ -613,7 +648,13 @@ module ActiveRecord
|
|
|
613
648
|
|
|
614
649
|
# Returns the version of the connected PostgreSQL server.
|
|
615
650
|
def get_database_version # :nodoc:
|
|
616
|
-
|
|
651
|
+
with_raw_connection do |conn|
|
|
652
|
+
version = conn.server_version
|
|
653
|
+
if version == 0
|
|
654
|
+
raise ActiveRecord::ConnectionNotEstablished, "Could not determine PostgreSQL version"
|
|
655
|
+
end
|
|
656
|
+
version
|
|
657
|
+
end
|
|
617
658
|
end
|
|
618
659
|
alias :postgresql_version :database_version
|
|
619
660
|
|
|
@@ -652,8 +693,8 @@ module ActiveRecord
|
|
|
652
693
|
m.register_type "int4", Type::Integer.new(limit: 4)
|
|
653
694
|
m.register_type "int8", Type::Integer.new(limit: 8)
|
|
654
695
|
m.register_type "oid", OID::Oid.new
|
|
655
|
-
m.register_type "float4", Type::Float.new
|
|
656
|
-
m.
|
|
696
|
+
m.register_type "float4", Type::Float.new(limit: 24)
|
|
697
|
+
m.register_type "float8", Type::Float.new
|
|
657
698
|
m.register_type "text", Type::Text.new
|
|
658
699
|
register_class_with_limit m, "varchar", Type::String
|
|
659
700
|
m.alias_type "char", "varchar"
|
|
@@ -766,6 +807,8 @@ module ActiveRecord
|
|
|
766
807
|
NOT_NULL_VIOLATION = "23502"
|
|
767
808
|
FOREIGN_KEY_VIOLATION = "23503"
|
|
768
809
|
UNIQUE_VIOLATION = "23505"
|
|
810
|
+
CHECK_VIOLATION = "23514"
|
|
811
|
+
EXCLUSION_VIOLATION = "23P01"
|
|
769
812
|
SERIALIZATION_FAILURE = "40001"
|
|
770
813
|
DEADLOCK_DETECTED = "40P01"
|
|
771
814
|
DUPLICATE_DATABASE = "42P04"
|
|
@@ -777,7 +820,7 @@ module ActiveRecord
|
|
|
777
820
|
|
|
778
821
|
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
|
779
822
|
when nil
|
|
780
|
-
if exception.message.match?(/connection is closed/i)
|
|
823
|
+
if exception.message.match?(/connection is closed/i) || exception.message.match?(/no connection to the server/i)
|
|
781
824
|
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
|
782
825
|
elsif exception.is_a?(PG::ConnectionBad)
|
|
783
826
|
# libpq message style always ends with a newline; the pg gem's internal
|
|
@@ -797,6 +840,10 @@ module ActiveRecord
|
|
|
797
840
|
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
798
841
|
when FOREIGN_KEY_VIOLATION
|
|
799
842
|
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
843
|
+
when CHECK_VIOLATION
|
|
844
|
+
CheckViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
845
|
+
when EXCLUSION_VIOLATION
|
|
846
|
+
ExclusionViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
800
847
|
when VALUE_LIMIT_VIOLATION
|
|
801
848
|
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
802
849
|
when NUMERIC_VALUE_OUT_OF_RANGE
|
|
@@ -841,9 +888,8 @@ module ActiveRecord
|
|
|
841
888
|
def load_additional_types(oids = nil)
|
|
842
889
|
initializer = OID::TypeMapInitializer.new(type_map)
|
|
843
890
|
load_types_queries(initializer, oids) do |query|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
end
|
|
891
|
+
records = internal_execute(query, "SCHEMA", [], allow_retry: true, materialize_transactions: false)
|
|
892
|
+
initializer.run(records)
|
|
847
893
|
end
|
|
848
894
|
end
|
|
849
895
|
|
|
@@ -864,71 +910,6 @@ module ActiveRecord
|
|
|
864
910
|
|
|
865
911
|
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
|
|
866
912
|
|
|
867
|
-
def execute_and_clear(sql, name, binds, prepare: false, async: false, allow_retry: false, materialize_transactions: true)
|
|
868
|
-
sql = transform_query(sql)
|
|
869
|
-
check_if_write_query(sql)
|
|
870
|
-
|
|
871
|
-
if !prepare || without_prepared_statement?(binds)
|
|
872
|
-
result = exec_no_cache(sql, name, binds, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions)
|
|
873
|
-
else
|
|
874
|
-
result = exec_cache(sql, name, binds, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions)
|
|
875
|
-
end
|
|
876
|
-
begin
|
|
877
|
-
ret = yield result
|
|
878
|
-
ensure
|
|
879
|
-
result.clear
|
|
880
|
-
end
|
|
881
|
-
ret
|
|
882
|
-
end
|
|
883
|
-
|
|
884
|
-
def exec_no_cache(sql, name, binds, async:, allow_retry:, materialize_transactions:)
|
|
885
|
-
mark_transaction_written_if_write(sql)
|
|
886
|
-
|
|
887
|
-
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
888
|
-
# made since we established the connection
|
|
889
|
-
update_typemap_for_default_timezone
|
|
890
|
-
|
|
891
|
-
type_casted_binds = type_casted_binds(binds)
|
|
892
|
-
log(sql, name, binds, type_casted_binds, async: async) do
|
|
893
|
-
with_raw_connection do |conn|
|
|
894
|
-
result = conn.exec_params(sql, type_casted_binds)
|
|
895
|
-
verified!
|
|
896
|
-
result
|
|
897
|
-
end
|
|
898
|
-
end
|
|
899
|
-
end
|
|
900
|
-
|
|
901
|
-
def exec_cache(sql, name, binds, async:, allow_retry:, materialize_transactions:)
|
|
902
|
-
mark_transaction_written_if_write(sql)
|
|
903
|
-
|
|
904
|
-
update_typemap_for_default_timezone
|
|
905
|
-
|
|
906
|
-
with_raw_connection do |conn|
|
|
907
|
-
stmt_key = prepare_statement(sql, binds, conn)
|
|
908
|
-
type_casted_binds = type_casted_binds(binds)
|
|
909
|
-
|
|
910
|
-
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do
|
|
911
|
-
result = conn.exec_prepared(stmt_key, type_casted_binds)
|
|
912
|
-
verified!
|
|
913
|
-
result
|
|
914
|
-
end
|
|
915
|
-
end
|
|
916
|
-
rescue ActiveRecord::StatementInvalid => e
|
|
917
|
-
raise unless is_cached_plan_failure?(e)
|
|
918
|
-
|
|
919
|
-
# Nothing we can do if we are in a transaction because all commands
|
|
920
|
-
# will raise InFailedSQLTransaction
|
|
921
|
-
if in_transaction?
|
|
922
|
-
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
|
923
|
-
else
|
|
924
|
-
@lock.synchronize do
|
|
925
|
-
# outside of transactions we can simply flush this query and retry
|
|
926
|
-
@statements.delete sql_key(sql)
|
|
927
|
-
end
|
|
928
|
-
retry
|
|
929
|
-
end
|
|
930
|
-
end
|
|
931
|
-
|
|
932
913
|
# Annoyingly, the code for prepared statements whose return value may
|
|
933
914
|
# have changed is FEATURE_NOT_SUPPORTED.
|
|
934
915
|
#
|
|
@@ -938,8 +919,7 @@ module ActiveRecord
|
|
|
938
919
|
#
|
|
939
920
|
# Check here for more details:
|
|
940
921
|
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
|
941
|
-
def is_cached_plan_failure?(
|
|
942
|
-
pgerror = e.cause
|
|
922
|
+
def is_cached_plan_failure?(pgerror)
|
|
943
923
|
pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
|
|
944
924
|
pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "RevalidateCachedQuery"
|
|
945
925
|
rescue
|
|
@@ -995,6 +975,8 @@ module ActiveRecord
|
|
|
995
975
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
|
996
976
|
# This is called by #connect and should not be called manually.
|
|
997
977
|
def configure_connection
|
|
978
|
+
super
|
|
979
|
+
|
|
998
980
|
if @config[:encoding]
|
|
999
981
|
@raw_connection.set_client_encoding(@config[:encoding])
|
|
1000
982
|
end
|
|
@@ -1016,22 +998,24 @@ module ActiveRecord
|
|
|
1016
998
|
variables = @config.fetch(:variables, {}).stringify_keys
|
|
1017
999
|
|
|
1018
1000
|
# Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
|
|
1019
|
-
internal_execute("SET intervalstyle = iso_8601")
|
|
1001
|
+
internal_execute("SET intervalstyle = iso_8601", "SCHEMA")
|
|
1020
1002
|
|
|
1021
1003
|
# SET statements from :variables config hash
|
|
1022
1004
|
# https://www.postgresql.org/docs/current/static/sql-set.html
|
|
1023
1005
|
variables.map do |k, v|
|
|
1024
1006
|
if v == ":default" || v == :default
|
|
1025
1007
|
# Sets the value to the global or compile default
|
|
1026
|
-
internal_execute("SET SESSION #{k} TO DEFAULT")
|
|
1008
|
+
internal_execute("SET SESSION #{k} TO DEFAULT", "SCHEMA")
|
|
1027
1009
|
elsif !v.nil?
|
|
1028
|
-
internal_execute("SET SESSION #{k} TO #{quote(v)}")
|
|
1010
|
+
internal_execute("SET SESSION #{k} TO #{quote(v)}", "SCHEMA")
|
|
1029
1011
|
end
|
|
1030
1012
|
end
|
|
1031
1013
|
|
|
1032
1014
|
add_pg_encoders
|
|
1033
1015
|
add_pg_decoders
|
|
1034
1016
|
|
|
1017
|
+
schema_search_path # populate cache
|
|
1018
|
+
|
|
1035
1019
|
reload_type_map
|
|
1036
1020
|
end
|
|
1037
1021
|
|
|
@@ -1046,9 +1030,9 @@ module ActiveRecord
|
|
|
1046
1030
|
# If using Active Record's time zone support configure the connection
|
|
1047
1031
|
# to return TIMESTAMP WITH ZONE types in UTC.
|
|
1048
1032
|
if default_timezone == :utc
|
|
1049
|
-
|
|
1033
|
+
raw_execute("SET SESSION timezone TO 'UTC'", "SCHEMA")
|
|
1050
1034
|
else
|
|
1051
|
-
|
|
1035
|
+
raw_execute("SET SESSION timezone TO DEFAULT", "SCHEMA")
|
|
1052
1036
|
end
|
|
1053
1037
|
end
|
|
1054
1038
|
|
|
@@ -1115,9 +1099,8 @@ module ActiveRecord
|
|
|
1115
1099
|
AND castsource = #{quote column.sql_type}::regtype
|
|
1116
1100
|
)
|
|
1117
1101
|
SQL
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
end
|
|
1102
|
+
result = internal_execute(sql, "SCHEMA", [], allow_retry: true, materialize_transactions: false)
|
|
1103
|
+
result.getvalue(0, 0)
|
|
1121
1104
|
end
|
|
1122
1105
|
end
|
|
1123
1106
|
end
|
|
@@ -1165,6 +1148,7 @@ module ActiveRecord
|
|
|
1165
1148
|
"timestamp" => PG::TextDecoder::TimestampUtc,
|
|
1166
1149
|
"timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
|
|
1167
1150
|
}
|
|
1151
|
+
coders_by_name["date"] = PG::TextDecoder::Date if decode_dates
|
|
1168
1152
|
|
|
1169
1153
|
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
|
1170
1154
|
query = <<~SQL % known_coder_types.join(", ")
|
|
@@ -1172,9 +1156,8 @@ module ActiveRecord
|
|
|
1172
1156
|
FROM pg_type as t
|
|
1173
1157
|
WHERE t.typname IN (%s)
|
|
1174
1158
|
SQL
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
end
|
|
1159
|
+
result = internal_execute(query, "SCHEMA", [], allow_retry: true, materialize_transactions: false)
|
|
1160
|
+
coders = result.filter_map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
|
1178
1161
|
|
|
1179
1162
|
map = PG::TypeMapByOid.new
|
|
1180
1163
|
coders.each { |coder| map.add_coder(coder) }
|