activerecord 6.1.3.2 → 7.0.0.alpha2
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 +734 -1058
- 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 +35 -7
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +16 -6
- 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 +1 -1
- 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 +24 -25
- 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/preloader/association.rb +161 -49
- data/lib/active_record/associations/preloader/batch.rb +51 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +37 -11
- data/lib/active_record/associations/preloader.rb +46 -110
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +76 -81
- data/lib/active_record/asynchronous_queries_tracker.rb +57 -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 +41 -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 +6 -9
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +3 -18
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +11 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -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 +31 -558
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -7
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +1 -3
- data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -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 +6 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +8 -5
- data/lib/active_record/connection_handling.rb +20 -38
- data/lib/active_record/core.rb +129 -117
- data/lib/active_record/database_configurations/database_config.rb +12 -0
- data/lib/active_record/database_configurations/hash_config.rb +27 -1
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +18 -9
- data/lib/active_record/delegated_type.rb +33 -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 +29 -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 +80 -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 +44 -46
- data/lib/active_record/errors.rb +66 -3
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +40 -5
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +16 -11
- 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 +39 -6
- data/lib/active_record/integration.rb +1 -1
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/log_subscriber.rb +6 -2
- 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/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +83 -1
- 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 +46 -32
- data/lib/active_record/nested_attributes.rb +3 -3
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +134 -45
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +203 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +117 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +83 -58
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +45 -44
- 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 +42 -25
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +32 -23
- 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 +233 -50
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +22 -15
- data/lib/active_record/relation.rb +170 -87
- data/lib/active_record/result.rb +17 -2
- data/lib/active_record/runtime_registry.rb +2 -4
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +3 -3
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/default.rb +62 -15
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +40 -22
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +107 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +45 -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/numericality.rb +1 -1
- data/lib/active_record.rb +170 -2
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/composite.rb +3 -3
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +18 -22
- data/lib/arel/delete_manager.rb +2 -4
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +8 -13
- data/lib/arel/nodes/homogeneous_in.rb +4 -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 +3 -2
- data/lib/arel/predications.rb +3 -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 +2 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +6 -1
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +44 -3
- data/lib/arel.rb +1 -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
- metadata +55 -16
@@ -0,0 +1,28 @@
|
|
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
|
+
time = super
|
14
|
+
return time if time.is_a?(ActiveSupport::TimeWithZone)
|
15
|
+
|
16
|
+
# While in UTC mode, the PG gem may not return times back in "UTC" even if they were provided to Postgres in UTC.
|
17
|
+
# We prefer times always in UTC, so here we convert back.
|
18
|
+
if is_utc?
|
19
|
+
time.getutc
|
20
|
+
else
|
21
|
+
time.getlocal
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
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"
|
@@ -17,7 +17,7 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# Quotes strings for use in SQL input.
|
20
|
-
def quote_string(s)
|
20
|
+
def quote_string(s) # :nodoc:
|
21
21
|
PG::Connection.escape(s)
|
22
22
|
end
|
23
23
|
|
@@ -48,7 +48,7 @@ module ActiveRecord
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# Quote date/time values for use in SQL input.
|
51
|
-
def quoted_date(value)
|
51
|
+
def quoted_date(value) # :nodoc:
|
52
52
|
if value.year <= 0
|
53
53
|
bce_year = format("%04d", -value.year + 1)
|
54
54
|
super.sub(/^-?\d+/, bce_year) + " BC"
|
@@ -90,8 +90,8 @@ module ActiveRecord
|
|
90
90
|
\A
|
91
91
|
(
|
92
92
|
(?:
|
93
|
-
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
94
|
-
((?:\w+\.|"\w+"\.)
|
93
|
+
# "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
|
94
|
+
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
95
95
|
)
|
96
96
|
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
97
97
|
)
|
@@ -103,8 +103,8 @@ module ActiveRecord
|
|
103
103
|
\A
|
104
104
|
(
|
105
105
|
(?:
|
106
|
-
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
107
|
-
((?:\w+\.|"\w+"\.)
|
106
|
+
# "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
|
107
|
+
((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
108
108
|
)
|
109
109
|
(?:\s+ASC|\s+DESC)?
|
110
110
|
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
@@ -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
|
@@ -177,7 +177,7 @@ module ActiveRecord
|
|
177
177
|
define_column_methods :bigserial, :bit, :bit_varying, :cidr, :citext, :daterange,
|
178
178
|
:hstore, :inet, :interval, :int4range, :int8range, :jsonb, :ltree, :macaddr,
|
179
179
|
:money, :numrange, :oid, :point, :line, :lseg, :box, :path, :polygon, :circle,
|
180
|
-
:serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml
|
180
|
+
:serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml, :timestamptz
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
@@ -192,6 +192,10 @@ module ActiveRecord
|
|
192
192
|
end
|
193
193
|
|
194
194
|
private
|
195
|
+
def aliased_types(name, fallback)
|
196
|
+
fallback
|
197
|
+
end
|
198
|
+
|
195
199
|
def integer_like_primary_key_type(type, options)
|
196
200
|
if type == :bigint || options[:limit] == 8
|
197
201
|
:bigserial
|
@@ -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)
|
@@ -576,7 +576,7 @@ module ActiveRecord
|
|
576
576
|
|
577
577
|
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
|
578
578
|
# requires that the ORDER BY include the distinct column.
|
579
|
-
def columns_for_distinct(columns, orders)
|
579
|
+
def columns_for_distinct(columns, orders) # :nodoc:
|
580
580
|
order_columns = orders.compact_blank.map { |s|
|
581
581
|
# Convert Arel node to string
|
582
582
|
s = visitor.compile(s) unless s.is_a?(String)
|
@@ -52,7 +52,7 @@ module ActiveRecord
|
|
52
52
|
# * <tt>:port</tt> - Defaults to 5432.
|
53
53
|
# * <tt>:username</tt> - Defaults to be the same as the operating system name of the user running the application.
|
54
54
|
# * <tt>:password</tt> - Password to be used if the server demands password authentication.
|
55
|
-
# * <tt>:database</tt> - Defaults to be the same as the
|
55
|
+
# * <tt>:database</tt> - Defaults to be the same as the username.
|
56
56
|
# * <tt>:schema_search_path</tt> - An optional schema search path for the connection given
|
57
57
|
# as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
|
58
58
|
# * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
|
@@ -78,7 +78,11 @@ module ActiveRecord
|
|
78
78
|
PG.connect(conn_params)
|
79
79
|
rescue ::PG::Error => error
|
80
80
|
if conn_params && conn_params[:dbname] && error.message.include?(conn_params[:dbname])
|
81
|
-
raise ActiveRecord::NoDatabaseError
|
81
|
+
raise ActiveRecord::NoDatabaseError.db_error(conn_params[:dbname])
|
82
|
+
elsif conn_params && conn_params[:user] && error.message.include?(conn_params[:user])
|
83
|
+
raise ActiveRecord::DatabaseConnectionError.username_error(conn_params[:user])
|
84
|
+
elsif conn_params && conn_params[:hostname] && error.message.include?(conn_params[:hostname])
|
85
|
+
raise ActiveRecord::DatabaseConnectionError.hostname_error(conn_params[:hostname])
|
82
86
|
else
|
83
87
|
raise ActiveRecord::ConnectionNotEstablished, error.message
|
84
88
|
end
|
@@ -98,6 +102,24 @@ module ActiveRecord
|
|
98
102
|
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
99
103
|
class_attribute :create_unlogged_tables, default: false
|
100
104
|
|
105
|
+
##
|
106
|
+
# :singleton-method:
|
107
|
+
# PostgreSQL supports multiple types for DateTimes. By default if you use `datetime`
|
108
|
+
# in migrations, Rails will translate this to a PostgreSQL "timestamp without time zone".
|
109
|
+
# Change this in an initializer to use another NATIVE_DATABASE_TYPES. For example, to
|
110
|
+
# store DateTimes as "timestamp with time zone":
|
111
|
+
#
|
112
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :timestamptz
|
113
|
+
#
|
114
|
+
# Or if you are adding a custom type:
|
115
|
+
#
|
116
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:my_custom_type] = { name: "my_custom_type_name" }
|
117
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :my_custom_type
|
118
|
+
#
|
119
|
+
# If you're using :ruby as your config.active_record.schema_format and you change this
|
120
|
+
# setting, you should immediately run bin/rails db:migrate to update the types in your schema.rb.
|
121
|
+
class_attribute :datetime_type, default: :timestamp
|
122
|
+
|
101
123
|
NATIVE_DATABASE_TYPES = {
|
102
124
|
primary_key: "bigserial primary key",
|
103
125
|
string: { name: "character varying" },
|
@@ -105,7 +127,9 @@ module ActiveRecord
|
|
105
127
|
integer: { name: "integer", limit: 4 },
|
106
128
|
float: { name: "float" },
|
107
129
|
decimal: { name: "decimal" },
|
108
|
-
datetime: {
|
130
|
+
datetime: {}, # set dynamically based on datetime_type
|
131
|
+
timestamp: { name: "timestamp" },
|
132
|
+
timestamptz: { name: "timestamptz" },
|
109
133
|
time: { name: "time" },
|
110
134
|
date: { name: "date" },
|
111
135
|
daterange: { name: "daterange" },
|
@@ -141,7 +165,7 @@ module ActiveRecord
|
|
141
165
|
oid: { name: "oid" },
|
142
166
|
}
|
143
167
|
|
144
|
-
OID = PostgreSQL::OID
|
168
|
+
OID = PostgreSQL::OID # :nodoc:
|
145
169
|
|
146
170
|
include PostgreSQL::Quoting
|
147
171
|
include PostgreSQL::ReferentialIntegrity
|
@@ -272,19 +296,25 @@ module ActiveRecord
|
|
272
296
|
# Is this connection alive and ready for queries?
|
273
297
|
def active?
|
274
298
|
@lock.synchronize do
|
275
|
-
@connection.query "
|
299
|
+
@connection.query ";"
|
276
300
|
end
|
277
301
|
true
|
278
302
|
rescue PG::Error
|
279
303
|
false
|
280
304
|
end
|
281
305
|
|
306
|
+
def reload_type_map # :nodoc:
|
307
|
+
type_map.clear
|
308
|
+
initialize_type_map
|
309
|
+
end
|
310
|
+
|
282
311
|
# Close then reopen the connection.
|
283
312
|
def reconnect!
|
284
313
|
@lock.synchronize do
|
285
314
|
super
|
286
315
|
@connection.reset
|
287
316
|
configure_connection
|
317
|
+
reload_type_map
|
288
318
|
rescue PG::ConnectionBad
|
289
319
|
connect
|
290
320
|
end
|
@@ -317,8 +347,16 @@ module ActiveRecord
|
|
317
347
|
@connection = nil
|
318
348
|
end
|
319
349
|
|
320
|
-
def native_database_types
|
321
|
-
|
350
|
+
def native_database_types # :nodoc:
|
351
|
+
self.class.native_database_types
|
352
|
+
end
|
353
|
+
|
354
|
+
def self.native_database_types # :nodoc:
|
355
|
+
@native_database_types ||= begin
|
356
|
+
types = NATIVE_DATABASE_TYPES.dup
|
357
|
+
types[:datetime] = types[datetime_type]
|
358
|
+
types
|
359
|
+
end
|
322
360
|
end
|
323
361
|
|
324
362
|
def set_standard_conforming_strings
|
@@ -438,8 +476,12 @@ module ActiveRecord
|
|
438
476
|
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
439
477
|
elsif insert.update_duplicates?
|
440
478
|
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
441
|
-
|
442
|
-
|
479
|
+
if insert.raw_update_sql?
|
480
|
+
sql << insert.raw_update_sql
|
481
|
+
else
|
482
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
|
483
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
484
|
+
end
|
443
485
|
end
|
444
486
|
|
445
487
|
sql << " RETURNING #{insert.returning}" if insert.returning
|
@@ -452,68 +494,8 @@ module ActiveRecord
|
|
452
494
|
end
|
453
495
|
end
|
454
496
|
|
455
|
-
|
456
|
-
#
|
457
|
-
VALUE_LIMIT_VIOLATION = "22001"
|
458
|
-
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
|
459
|
-
NOT_NULL_VIOLATION = "23502"
|
460
|
-
FOREIGN_KEY_VIOLATION = "23503"
|
461
|
-
UNIQUE_VIOLATION = "23505"
|
462
|
-
SERIALIZATION_FAILURE = "40001"
|
463
|
-
DEADLOCK_DETECTED = "40P01"
|
464
|
-
DUPLICATE_DATABASE = "42P04"
|
465
|
-
LOCK_NOT_AVAILABLE = "55P03"
|
466
|
-
QUERY_CANCELED = "57014"
|
467
|
-
|
468
|
-
def translate_exception(exception, message:, sql:, binds:)
|
469
|
-
return exception unless exception.respond_to?(:result)
|
470
|
-
|
471
|
-
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
472
|
-
when nil
|
473
|
-
if exception.message.match?(/connection is closed/i)
|
474
|
-
ConnectionNotEstablished.new(exception)
|
475
|
-
else
|
476
|
-
super
|
477
|
-
end
|
478
|
-
when UNIQUE_VIOLATION
|
479
|
-
RecordNotUnique.new(message, sql: sql, binds: binds)
|
480
|
-
when FOREIGN_KEY_VIOLATION
|
481
|
-
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
482
|
-
when VALUE_LIMIT_VIOLATION
|
483
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
484
|
-
when NUMERIC_VALUE_OUT_OF_RANGE
|
485
|
-
RangeError.new(message, sql: sql, binds: binds)
|
486
|
-
when NOT_NULL_VIOLATION
|
487
|
-
NotNullViolation.new(message, sql: sql, binds: binds)
|
488
|
-
when SERIALIZATION_FAILURE
|
489
|
-
SerializationFailure.new(message, sql: sql, binds: binds)
|
490
|
-
when DEADLOCK_DETECTED
|
491
|
-
Deadlocked.new(message, sql: sql, binds: binds)
|
492
|
-
when DUPLICATE_DATABASE
|
493
|
-
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
494
|
-
when LOCK_NOT_AVAILABLE
|
495
|
-
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
496
|
-
when QUERY_CANCELED
|
497
|
-
QueryCanceled.new(message, sql: sql, binds: binds)
|
498
|
-
else
|
499
|
-
super
|
500
|
-
end
|
501
|
-
end
|
502
|
-
|
503
|
-
def get_oid_type(oid, fmod, column_name, sql_type = "")
|
504
|
-
if !type_map.key?(oid)
|
505
|
-
load_additional_types([oid])
|
506
|
-
end
|
507
|
-
|
508
|
-
type_map.fetch(oid, fmod, sql_type) {
|
509
|
-
warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
|
510
|
-
Type.default_value.tap do |cast_type|
|
511
|
-
type_map.register_type(oid, cast_type)
|
512
|
-
end
|
513
|
-
}
|
514
|
-
end
|
515
|
-
|
516
|
-
def initialize_type_map(m = type_map)
|
497
|
+
class << self
|
498
|
+
def initialize_type_map(m) # :nodoc:
|
517
499
|
m.register_type "int2", Type::Integer.new(limit: 2)
|
518
500
|
m.register_type "int4", Type::Integer.new(limit: 4)
|
519
501
|
m.register_type "int8", Type::Integer.new(limit: 8)
|
@@ -528,7 +510,6 @@ module ActiveRecord
|
|
528
510
|
m.register_type "bool", Type::Boolean.new
|
529
511
|
register_class_with_limit m, "bit", OID::Bit
|
530
512
|
register_class_with_limit m, "varbit", OID::BitVarying
|
531
|
-
m.alias_type "timestamptz", "timestamp"
|
532
513
|
m.register_type "date", OID::Date.new
|
533
514
|
|
534
515
|
m.register_type "money", OID::Money.new
|
@@ -553,7 +534,8 @@ module ActiveRecord
|
|
553
534
|
m.register_type "circle", OID::SpecializedString.new(:circle)
|
554
535
|
|
555
536
|
register_class_with_precision m, "time", Type::Time
|
556
|
-
register_class_with_precision m, "timestamp", OID::
|
537
|
+
register_class_with_precision m, "timestamp", OID::Timestamp
|
538
|
+
register_class_with_precision m, "timestamptz", OID::TimestampWithTimeZone
|
557
539
|
|
558
540
|
m.register_type "numeric" do |_, fmod, sql_type|
|
559
541
|
precision = extract_precision(sql_type)
|
@@ -579,7 +561,16 @@ module ActiveRecord
|
|
579
561
|
precision = extract_precision(sql_type)
|
580
562
|
OID::Interval.new(precision: precision)
|
581
563
|
end
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
private
|
568
|
+
def type_map
|
569
|
+
@type_map ||= Type::HashLookupTypeMap.new
|
570
|
+
end
|
582
571
|
|
572
|
+
def initialize_type_map(m = type_map)
|
573
|
+
self.class.initialize_type_map(m)
|
583
574
|
load_additional_types
|
584
575
|
end
|
585
576
|
|
@@ -587,7 +578,7 @@ module ActiveRecord
|
|
587
578
|
def extract_value_from_default(default)
|
588
579
|
case default
|
589
580
|
# Quoted types
|
590
|
-
when /\A[
|
581
|
+
when /\A[(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
|
591
582
|
# The default 'now'::date is CURRENT_DATE
|
592
583
|
if $1 == "now" && $2 == "date"
|
593
584
|
nil
|
@@ -618,37 +609,100 @@ module ActiveRecord
|
|
618
609
|
!default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
619
610
|
end
|
620
611
|
|
612
|
+
# See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
613
|
+
VALUE_LIMIT_VIOLATION = "22001"
|
614
|
+
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
|
615
|
+
NOT_NULL_VIOLATION = "23502"
|
616
|
+
FOREIGN_KEY_VIOLATION = "23503"
|
617
|
+
UNIQUE_VIOLATION = "23505"
|
618
|
+
SERIALIZATION_FAILURE = "40001"
|
619
|
+
DEADLOCK_DETECTED = "40P01"
|
620
|
+
DUPLICATE_DATABASE = "42P04"
|
621
|
+
LOCK_NOT_AVAILABLE = "55P03"
|
622
|
+
QUERY_CANCELED = "57014"
|
623
|
+
|
624
|
+
def translate_exception(exception, message:, sql:, binds:)
|
625
|
+
return exception unless exception.respond_to?(:result)
|
626
|
+
|
627
|
+
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
628
|
+
when nil
|
629
|
+
if exception.message.match?(/connection is closed/i)
|
630
|
+
ConnectionNotEstablished.new(exception)
|
631
|
+
else
|
632
|
+
super
|
633
|
+
end
|
634
|
+
when UNIQUE_VIOLATION
|
635
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
636
|
+
when FOREIGN_KEY_VIOLATION
|
637
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
638
|
+
when VALUE_LIMIT_VIOLATION
|
639
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
640
|
+
when NUMERIC_VALUE_OUT_OF_RANGE
|
641
|
+
RangeError.new(message, sql: sql, binds: binds)
|
642
|
+
when NOT_NULL_VIOLATION
|
643
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
644
|
+
when SERIALIZATION_FAILURE
|
645
|
+
SerializationFailure.new(message, sql: sql, binds: binds)
|
646
|
+
when DEADLOCK_DETECTED
|
647
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
648
|
+
when DUPLICATE_DATABASE
|
649
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
650
|
+
when LOCK_NOT_AVAILABLE
|
651
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
652
|
+
when QUERY_CANCELED
|
653
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
654
|
+
else
|
655
|
+
super
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
def get_oid_type(oid, fmod, column_name, sql_type = "")
|
660
|
+
if !type_map.key?(oid)
|
661
|
+
load_additional_types([oid])
|
662
|
+
end
|
663
|
+
|
664
|
+
type_map.fetch(oid, fmod, sql_type) {
|
665
|
+
warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
|
666
|
+
Type.default_value.tap do |cast_type|
|
667
|
+
type_map.register_type(oid, cast_type)
|
668
|
+
end
|
669
|
+
}
|
670
|
+
end
|
671
|
+
|
621
672
|
def load_additional_types(oids = nil)
|
622
673
|
initializer = OID::TypeMapInitializer.new(type_map)
|
674
|
+
load_types_queries(initializer, oids) do |query|
|
675
|
+
execute_and_clear(query, "SCHEMA", []) do |records|
|
676
|
+
initializer.run(records)
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
623
680
|
|
681
|
+
def load_types_queries(initializer, oids)
|
624
682
|
query = <<~SQL
|
625
683
|
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
626
684
|
FROM pg_type as t
|
627
685
|
LEFT JOIN pg_range as r ON oid = rngtypid
|
628
686
|
SQL
|
629
|
-
|
630
687
|
if oids
|
631
|
-
query
|
688
|
+
yield query + "WHERE t.oid IN (%s)" % oids.join(", ")
|
632
689
|
else
|
633
|
-
query
|
634
|
-
|
635
|
-
|
636
|
-
execute_and_clear(query, "SCHEMA", []) do |records|
|
637
|
-
initializer.run(records)
|
690
|
+
yield query + initializer.query_conditions_for_known_type_names
|
691
|
+
yield query + initializer.query_conditions_for_known_type_types
|
692
|
+
yield query + initializer.query_conditions_for_array_types
|
638
693
|
end
|
639
694
|
end
|
640
695
|
|
641
|
-
FEATURE_NOT_SUPPORTED = "0A000"
|
696
|
+
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
|
642
697
|
|
643
|
-
def execute_and_clear(sql, name, binds, prepare: false)
|
644
|
-
|
645
|
-
|
646
|
-
end
|
698
|
+
def execute_and_clear(sql, name, binds, prepare: false, async: false)
|
699
|
+
sql = transform_query(sql)
|
700
|
+
check_if_write_query(sql)
|
647
701
|
|
648
702
|
if !prepare || without_prepared_statement?(binds)
|
649
|
-
result = exec_no_cache(sql, name, binds)
|
703
|
+
result = exec_no_cache(sql, name, binds, async: async)
|
650
704
|
else
|
651
|
-
result = exec_cache(sql, name, binds)
|
705
|
+
result = exec_cache(sql, name, binds, async: async)
|
652
706
|
end
|
653
707
|
begin
|
654
708
|
ret = yield result
|
@@ -658,23 +712,23 @@ module ActiveRecord
|
|
658
712
|
ret
|
659
713
|
end
|
660
714
|
|
661
|
-
def exec_no_cache(sql, name, binds)
|
715
|
+
def exec_no_cache(sql, name, binds, async: false)
|
662
716
|
materialize_transactions
|
663
717
|
mark_transaction_written_if_write(sql)
|
664
718
|
|
665
|
-
# make sure we carry over any changes to ActiveRecord
|
719
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
666
720
|
# made since we established the connection
|
667
721
|
update_typemap_for_default_timezone
|
668
722
|
|
669
723
|
type_casted_binds = type_casted_binds(binds)
|
670
|
-
log(sql, name, binds, type_casted_binds) do
|
724
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
671
725
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
672
726
|
@connection.exec_params(sql, type_casted_binds)
|
673
727
|
end
|
674
728
|
end
|
675
729
|
end
|
676
730
|
|
677
|
-
def exec_cache(sql, name, binds)
|
731
|
+
def exec_cache(sql, name, binds, async: false)
|
678
732
|
materialize_transactions
|
679
733
|
mark_transaction_written_if_write(sql)
|
680
734
|
update_typemap_for_default_timezone
|
@@ -682,7 +736,7 @@ module ActiveRecord
|
|
682
736
|
stmt_key = prepare_statement(sql, binds)
|
683
737
|
type_casted_binds = type_casted_binds(binds)
|
684
738
|
|
685
|
-
log(sql, name, binds, type_casted_binds, stmt_key) do
|
739
|
+
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do
|
686
740
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
687
741
|
@connection.exec_prepared(stmt_key, type_casted_binds)
|
688
742
|
end
|
@@ -776,7 +830,7 @@ module ActiveRecord
|
|
776
830
|
# If using Active Record's time zone support configure the connection to return
|
777
831
|
# TIMESTAMP WITH ZONE types in UTC.
|
778
832
|
unless variables["timezone"]
|
779
|
-
if ActiveRecord
|
833
|
+
if ActiveRecord.default_timezone == :utc
|
780
834
|
variables["timezone"] = "UTC"
|
781
835
|
elsif @local_tz
|
782
836
|
variables["timezone"] = @local_tz
|
@@ -875,14 +929,19 @@ module ActiveRecord
|
|
875
929
|
end
|
876
930
|
|
877
931
|
def update_typemap_for_default_timezone
|
878
|
-
if @default_timezone != ActiveRecord
|
879
|
-
decoder_class = ActiveRecord
|
932
|
+
if @default_timezone != ActiveRecord.default_timezone && @timestamp_decoder
|
933
|
+
decoder_class = ActiveRecord.default_timezone == :utc ?
|
880
934
|
PG::TextDecoder::TimestampUtc :
|
881
935
|
PG::TextDecoder::TimestampWithoutTimeZone
|
882
936
|
|
883
937
|
@timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
|
884
938
|
@connection.type_map_for_results.add_coder(@timestamp_decoder)
|
885
|
-
|
939
|
+
|
940
|
+
@default_timezone = ActiveRecord.default_timezone
|
941
|
+
|
942
|
+
# if default timezone has changed, we need to reconfigure the connection
|
943
|
+
# (specifically, the session time zone)
|
944
|
+
configure_connection
|
886
945
|
end
|
887
946
|
end
|
888
947
|
|
@@ -910,9 +969,7 @@ module ActiveRecord
|
|
910
969
|
WHERE t.typname IN (%s)
|
911
970
|
SQL
|
912
971
|
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
913
|
-
result
|
914
|
-
.map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
915
|
-
.compact
|
972
|
+
result.filter_map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
916
973
|
end
|
917
974
|
|
918
975
|
map = PG::TypeMapByOid.new
|