activerecord 6.0.0 → 6.1.3
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 +1045 -575
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_record.rb +7 -13
- data/lib/active_record/aggregations.rb +5 -6
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations.rb +120 -13
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -29
- data/lib/active_record/associations/association_scope.rb +19 -15
- data/lib/active_record/associations/belongs_to_association.rb +22 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency.rb +77 -42
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attributes.rb +33 -9
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +141 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -77
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -65
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +219 -81
- data/lib/active_record/core.rb +253 -67
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +82 -38
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +58 -12
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +39 -10
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +33 -18
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +28 -9
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +115 -85
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +71 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +277 -97
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation.rb +107 -67
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder.rb +59 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +343 -180
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +107 -61
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -36
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +26 -73
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +15 -12
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +30 -27
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -7,6 +7,8 @@ module ActiveRecord
|
|
7
7
|
class TypeMetadata < DelegateClass(SqlTypeMetadata)
|
8
8
|
undef to_yaml if method_defined?(:to_yaml)
|
9
9
|
|
10
|
+
include Deduplicable
|
11
|
+
|
10
12
|
attr_reader :oid, :fmod
|
11
13
|
|
12
14
|
def initialize(type_metadata, oid: nil, fmod: nil)
|
@@ -29,6 +31,12 @@ module ActiveRecord
|
|
29
31
|
oid.hash ^
|
30
32
|
fmod.hash
|
31
33
|
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def deduplicated
|
37
|
+
__setobj__(__getobj__.deduplicate)
|
38
|
+
super
|
39
|
+
end
|
32
40
|
end
|
33
41
|
end
|
34
42
|
PostgreSQLTypeMetadata = PostgreSQL::TypeMetadata
|
@@ -1,17 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
gem "pg", ">= 0.18", "< 2.0"
|
3
|
+
gem "pg", "~> 1.1"
|
5
4
|
require "pg"
|
6
5
|
|
7
|
-
|
8
|
-
class ::PG::Connection # :nodoc:
|
9
|
-
unless self.public_method_defined?(:async_exec_params)
|
10
|
-
remove_method :exec_params
|
11
|
-
alias exec_params async_exec
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
6
|
+
require "active_support/core_ext/object/try"
|
15
7
|
require "active_record/connection_adapters/abstract_adapter"
|
16
8
|
require "active_record/connection_adapters/statement_pool"
|
17
9
|
require "active_record/connection_adapters/postgresql/column"
|
@@ -31,9 +23,7 @@ module ActiveRecord
|
|
31
23
|
module ConnectionHandling # :nodoc:
|
32
24
|
# Establishes a connection to the database that's used by all Active Record objects
|
33
25
|
def postgresql_connection(config)
|
34
|
-
conn_params = config.symbolize_keys
|
35
|
-
|
36
|
-
conn_params.delete_if { |_, v| v.nil? }
|
26
|
+
conn_params = config.symbolize_keys.compact
|
37
27
|
|
38
28
|
# Map ActiveRecords param names to PGs.
|
39
29
|
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
@@ -43,19 +33,17 @@ module ActiveRecord
|
|
43
33
|
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
44
34
|
conn_params.slice!(*valid_conn_param_keys)
|
45
35
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
raise
|
53
|
-
end
|
36
|
+
ConnectionAdapters::PostgreSQLAdapter.new(
|
37
|
+
ConnectionAdapters::PostgreSQLAdapter.new_client(conn_params),
|
38
|
+
logger,
|
39
|
+
conn_params,
|
40
|
+
config,
|
41
|
+
)
|
54
42
|
end
|
55
43
|
end
|
56
44
|
|
57
45
|
module ConnectionAdapters
|
58
|
-
# The PostgreSQL adapter works with the native C (https://
|
46
|
+
# The PostgreSQL adapter works with the native C (https://github.com/ged/ruby-pg) driver.
|
59
47
|
#
|
60
48
|
# Options:
|
61
49
|
#
|
@@ -85,6 +73,18 @@ module ActiveRecord
|
|
85
73
|
class PostgreSQLAdapter < AbstractAdapter
|
86
74
|
ADAPTER_NAME = "PostgreSQL"
|
87
75
|
|
76
|
+
class << self
|
77
|
+
def new_client(conn_params)
|
78
|
+
PG.connect(conn_params)
|
79
|
+
rescue ::PG::Error => error
|
80
|
+
if conn_params && conn_params[:dbname] && error.message.include?(conn_params[:dbname])
|
81
|
+
raise ActiveRecord::NoDatabaseError
|
82
|
+
else
|
83
|
+
raise ActiveRecord::ConnectionNotEstablished, error.message
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
88
|
##
|
89
89
|
# :singleton-method:
|
90
90
|
# PostgreSQL allows the creation of "unlogged" tables, which do not record
|
@@ -156,6 +156,10 @@ module ActiveRecord
|
|
156
156
|
true
|
157
157
|
end
|
158
158
|
|
159
|
+
def supports_partitioned_indexes?
|
160
|
+
database_version >= 110_000
|
161
|
+
end
|
162
|
+
|
159
163
|
def supports_partial_index?
|
160
164
|
true
|
161
165
|
end
|
@@ -172,6 +176,10 @@ module ActiveRecord
|
|
172
176
|
true
|
173
177
|
end
|
174
178
|
|
179
|
+
def supports_check_constraints?
|
180
|
+
true
|
181
|
+
end
|
182
|
+
|
175
183
|
def supports_validate_constraints?
|
176
184
|
true
|
177
185
|
end
|
@@ -219,11 +227,7 @@ module ActiveRecord
|
|
219
227
|
end
|
220
228
|
|
221
229
|
def next_key
|
222
|
-
"a#{@counter
|
223
|
-
end
|
224
|
-
|
225
|
-
def []=(sql, key)
|
226
|
-
super.tap { @counter += 1 }
|
230
|
+
"a#{@counter += 1}"
|
227
231
|
end
|
228
232
|
|
229
233
|
private
|
@@ -337,11 +341,6 @@ module ActiveRecord
|
|
337
341
|
true
|
338
342
|
end
|
339
343
|
|
340
|
-
def supports_ranges?
|
341
|
-
true
|
342
|
-
end
|
343
|
-
deprecate :supports_ranges?
|
344
|
-
|
345
344
|
def supports_materialized_views?
|
346
345
|
true
|
347
346
|
end
|
@@ -361,6 +360,10 @@ module ActiveRecord
|
|
361
360
|
@has_pg_hint_plan
|
362
361
|
end
|
363
362
|
|
363
|
+
def supports_common_table_expressions?
|
364
|
+
true
|
365
|
+
end
|
366
|
+
|
364
367
|
def supports_lazy_transactions?
|
365
368
|
true
|
366
369
|
end
|
@@ -418,16 +421,6 @@ module ActiveRecord
|
|
418
421
|
@use_insert_returning
|
419
422
|
end
|
420
423
|
|
421
|
-
def column_name_for_operation(operation, node) # :nodoc:
|
422
|
-
OPERATION_ALIASES.fetch(operation) { operation.downcase }
|
423
|
-
end
|
424
|
-
|
425
|
-
OPERATION_ALIASES = { # :nodoc:
|
426
|
-
"maximum" => "max",
|
427
|
-
"minimum" => "min",
|
428
|
-
"average" => "avg",
|
429
|
-
}
|
430
|
-
|
431
424
|
# Returns the version of the connected PostgreSQL server.
|
432
425
|
def get_database_version # :nodoc:
|
433
426
|
@connection.server_version
|
@@ -445,6 +438,7 @@ module ActiveRecord
|
|
445
438
|
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
446
439
|
elsif insert.update_duplicates?
|
447
440
|
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
441
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
|
448
442
|
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
449
443
|
end
|
450
444
|
|
@@ -459,7 +453,6 @@ module ActiveRecord
|
|
459
453
|
end
|
460
454
|
|
461
455
|
private
|
462
|
-
|
463
456
|
# See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
464
457
|
VALUE_LIMIT_VIOLATION = "22001"
|
465
458
|
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
|
@@ -468,6 +461,7 @@ module ActiveRecord
|
|
468
461
|
UNIQUE_VIOLATION = "23505"
|
469
462
|
SERIALIZATION_FAILURE = "40001"
|
470
463
|
DEADLOCK_DETECTED = "40P01"
|
464
|
+
DUPLICATE_DATABASE = "42P04"
|
471
465
|
LOCK_NOT_AVAILABLE = "55P03"
|
472
466
|
QUERY_CANCELED = "57014"
|
473
467
|
|
@@ -475,6 +469,12 @@ module ActiveRecord
|
|
475
469
|
return exception unless exception.respond_to?(:result)
|
476
470
|
|
477
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
478
|
when UNIQUE_VIOLATION
|
479
479
|
RecordNotUnique.new(message, sql: sql, binds: binds)
|
480
480
|
when FOREIGN_KEY_VIOLATION
|
@@ -489,6 +489,8 @@ module ActiveRecord
|
|
489
489
|
SerializationFailure.new(message, sql: sql, binds: binds)
|
490
490
|
when DEADLOCK_DETECTED
|
491
491
|
Deadlocked.new(message, sql: sql, binds: binds)
|
492
|
+
when DUPLICATE_DATABASE
|
493
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
492
494
|
when LOCK_NOT_AVAILABLE
|
493
495
|
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
494
496
|
when QUERY_CANCELED
|
@@ -540,7 +542,7 @@ module ActiveRecord
|
|
540
542
|
m.register_type "uuid", OID::Uuid.new
|
541
543
|
m.register_type "xml", OID::Xml.new
|
542
544
|
m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
|
543
|
-
m.register_type "macaddr", OID::
|
545
|
+
m.register_type "macaddr", OID::Macaddr.new
|
544
546
|
m.register_type "citext", OID::SpecializedString.new(:citext)
|
545
547
|
m.register_type "ltree", OID::SpecializedString.new(:ltree)
|
546
548
|
m.register_type "line", OID::SpecializedString.new(:line)
|
@@ -550,11 +552,6 @@ module ActiveRecord
|
|
550
552
|
m.register_type "polygon", OID::SpecializedString.new(:polygon)
|
551
553
|
m.register_type "circle", OID::SpecializedString.new(:circle)
|
552
554
|
|
553
|
-
m.register_type "interval" do |_, _, sql_type|
|
554
|
-
precision = extract_precision(sql_type)
|
555
|
-
OID::SpecializedString.new(:interval, precision: precision)
|
556
|
-
end
|
557
|
-
|
558
555
|
register_class_with_precision m, "time", Type::Time
|
559
556
|
register_class_with_precision m, "timestamp", OID::DateTime
|
560
557
|
|
@@ -578,6 +575,11 @@ module ActiveRecord
|
|
578
575
|
end
|
579
576
|
end
|
580
577
|
|
578
|
+
m.register_type "interval" do |*args, sql_type|
|
579
|
+
precision = extract_precision(sql_type)
|
580
|
+
OID::Interval.new(precision: precision)
|
581
|
+
end
|
582
|
+
|
581
583
|
load_additional_types
|
582
584
|
end
|
583
585
|
|
@@ -626,7 +628,7 @@ module ActiveRecord
|
|
626
628
|
SQL
|
627
629
|
|
628
630
|
if oids
|
629
|
-
query += "WHERE t.oid
|
631
|
+
query += "WHERE t.oid IN (%s)" % oids.join(", ")
|
630
632
|
else
|
631
633
|
query += initializer.query_conditions_for_initial_load
|
632
634
|
end
|
@@ -643,20 +645,22 @@ module ActiveRecord
|
|
643
645
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
644
646
|
end
|
645
647
|
|
646
|
-
if without_prepared_statement?(binds)
|
647
|
-
result = exec_no_cache(sql, name, [])
|
648
|
-
elsif !prepare
|
648
|
+
if !prepare || without_prepared_statement?(binds)
|
649
649
|
result = exec_no_cache(sql, name, binds)
|
650
650
|
else
|
651
651
|
result = exec_cache(sql, name, binds)
|
652
652
|
end
|
653
|
-
|
654
|
-
|
653
|
+
begin
|
654
|
+
ret = yield result
|
655
|
+
ensure
|
656
|
+
result.clear
|
657
|
+
end
|
655
658
|
ret
|
656
659
|
end
|
657
660
|
|
658
661
|
def exec_no_cache(sql, name, binds)
|
659
662
|
materialize_transactions
|
663
|
+
mark_transaction_written_if_write(sql)
|
660
664
|
|
661
665
|
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
662
666
|
# made since we established the connection
|
@@ -672,6 +676,7 @@ module ActiveRecord
|
|
672
676
|
|
673
677
|
def exec_cache(sql, name, binds)
|
674
678
|
materialize_transactions
|
679
|
+
mark_transaction_written_if_write(sql)
|
675
680
|
update_typemap_for_default_timezone
|
676
681
|
|
677
682
|
stmt_key = prepare_statement(sql, binds)
|
@@ -707,11 +712,10 @@ module ActiveRecord
|
|
707
712
|
#
|
708
713
|
# Check here for more details:
|
709
714
|
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
710
|
-
CACHED_PLAN_HEURISTIC = "cached plan must not change result type"
|
711
715
|
def is_cached_plan_failure?(e)
|
712
716
|
pgerror = e.cause
|
713
|
-
|
714
|
-
|
717
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
|
718
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "RevalidateCachedQuery"
|
715
719
|
rescue
|
716
720
|
false
|
717
721
|
end
|
@@ -749,7 +753,7 @@ module ActiveRecord
|
|
749
753
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
750
754
|
# connected server's characteristics.
|
751
755
|
def connect
|
752
|
-
@connection =
|
756
|
+
@connection = self.class.new_client(@connection_parameters)
|
753
757
|
configure_connection
|
754
758
|
add_pg_encoders
|
755
759
|
add_pg_decoders
|
@@ -779,6 +783,9 @@ module ActiveRecord
|
|
779
783
|
end
|
780
784
|
end
|
781
785
|
|
786
|
+
# Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
|
787
|
+
execute("SET intervalstyle = iso_8601", "SCHEMA")
|
788
|
+
|
782
789
|
# SET statements from :variables config hash
|
783
790
|
# https://www.postgresql.org/docs/current/static/sql-set.html
|
784
791
|
variables.map do |k, v|
|
@@ -890,15 +897,12 @@ module ActiveRecord
|
|
890
897
|
"oid" => PG::TextDecoder::Integer,
|
891
898
|
"float4" => PG::TextDecoder::Float,
|
892
899
|
"float8" => PG::TextDecoder::Float,
|
900
|
+
"numeric" => PG::TextDecoder::Numeric,
|
893
901
|
"bool" => PG::TextDecoder::Boolean,
|
902
|
+
"timestamp" => PG::TextDecoder::TimestampUtc,
|
903
|
+
"timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
|
894
904
|
}
|
895
905
|
|
896
|
-
if defined?(PG::TextDecoder::TimestampUtc)
|
897
|
-
# Use native PG encoders available since pg-1.1
|
898
|
-
coders_by_name["timestamp"] = PG::TextDecoder::TimestampUtc
|
899
|
-
coders_by_name["timestamptz"] = PG::TextDecoder::TimestampWithTimeZone
|
900
|
-
end
|
901
|
-
|
902
906
|
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
903
907
|
query = <<~SQL % known_coder_types.join(", ")
|
904
908
|
SELECT t.oid, t.typname
|
@@ -915,6 +919,11 @@ module ActiveRecord
|
|
915
919
|
coders.each { |coder| map.add_coder(coder) }
|
916
920
|
@connection.type_map_for_results = map
|
917
921
|
|
922
|
+
@type_map_for_results = PG::TypeMapByOid.new
|
923
|
+
@type_map_for_results.default_type_map = map
|
924
|
+
@type_map_for_results.add_coder(PG::TextDecoder::Bytea.new(oid: 17, name: "bytea"))
|
925
|
+
@type_map_for_results.add_coder(MoneyDecoder.new(oid: 790, name: "money"))
|
926
|
+
|
918
927
|
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
919
928
|
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
920
929
|
update_typemap_for_default_timezone
|
@@ -925,6 +934,14 @@ module ActiveRecord
|
|
925
934
|
coder_class.new(oid: row["oid"].to_i, name: row["typname"])
|
926
935
|
end
|
927
936
|
|
937
|
+
class MoneyDecoder < PG::SimpleDecoder # :nodoc:
|
938
|
+
TYPE = OID::Money.new
|
939
|
+
|
940
|
+
def decode(value, tuple = nil, field = nil)
|
941
|
+
TYPE.deserialize(value)
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
928
945
|
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
929
946
|
ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
|
930
947
|
ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
|
@@ -937,6 +954,7 @@ module ActiveRecord
|
|
937
954
|
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
938
955
|
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
|
939
956
|
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
|
957
|
+
ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
|
940
958
|
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
|
941
959
|
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
|
942
960
|
ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
|
@@ -1,8 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/file/atomic"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters
|
5
7
|
class SchemaCache
|
8
|
+
def self.load_from(filename)
|
9
|
+
return unless File.file?(filename)
|
10
|
+
|
11
|
+
read(filename) do |file|
|
12
|
+
filename.include?(".dump") ? Marshal.load(file) : YAML.load(file)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.read(filename, &block)
|
17
|
+
if File.extname(filename) == ".gz"
|
18
|
+
Zlib::GzipReader.open(filename) { |gz|
|
19
|
+
yield gz.read
|
20
|
+
}
|
21
|
+
else
|
22
|
+
yield File.read(filename)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
private_class_method :read
|
26
|
+
|
6
27
|
attr_reader :version
|
7
28
|
attr_accessor :connection
|
8
29
|
|
@@ -26,27 +47,33 @@ module ActiveRecord
|
|
26
47
|
end
|
27
48
|
|
28
49
|
def encode_with(coder)
|
50
|
+
reset_version!
|
51
|
+
|
29
52
|
coder["columns"] = @columns
|
30
|
-
coder["columns_hash"] = @columns_hash
|
31
53
|
coder["primary_keys"] = @primary_keys
|
32
54
|
coder["data_sources"] = @data_sources
|
33
55
|
coder["indexes"] = @indexes
|
34
|
-
coder["version"] =
|
56
|
+
coder["version"] = @version
|
35
57
|
coder["database_version"] = database_version
|
36
58
|
end
|
37
59
|
|
38
60
|
def init_with(coder)
|
39
61
|
@columns = coder["columns"]
|
40
|
-
@columns_hash = coder["columns_hash"]
|
41
62
|
@primary_keys = coder["primary_keys"]
|
42
63
|
@data_sources = coder["data_sources"]
|
43
64
|
@indexes = coder["indexes"] || {}
|
44
65
|
@version = coder["version"]
|
45
66
|
@database_version = coder["database_version"]
|
67
|
+
|
68
|
+
derive_columns_hash_and_deduplicate_values
|
46
69
|
end
|
47
70
|
|
48
71
|
def primary_keys(table_name)
|
49
|
-
@primary_keys
|
72
|
+
@primary_keys.fetch(table_name) do
|
73
|
+
if data_source_exists?(table_name)
|
74
|
+
@primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
|
75
|
+
end
|
76
|
+
end
|
50
77
|
end
|
51
78
|
|
52
79
|
# A cached lookup for table existence.
|
@@ -54,7 +81,7 @@ module ActiveRecord
|
|
54
81
|
prepare_data_sources if @data_sources.empty?
|
55
82
|
return @data_sources[name] if @data_sources.key? name
|
56
83
|
|
57
|
-
@data_sources[name] = connection.data_source_exists?(name)
|
84
|
+
@data_sources[deep_deduplicate(name)] = connection.data_source_exists?(name)
|
58
85
|
end
|
59
86
|
|
60
87
|
# Add internal cache for table with +table_name+.
|
@@ -73,15 +100,17 @@ module ActiveRecord
|
|
73
100
|
|
74
101
|
# Get the columns for a table
|
75
102
|
def columns(table_name)
|
76
|
-
@columns
|
103
|
+
@columns.fetch(table_name) do
|
104
|
+
@columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
|
105
|
+
end
|
77
106
|
end
|
78
107
|
|
79
108
|
# Get the columns for a table as a hash, key is the column name
|
80
109
|
# value is the column object.
|
81
110
|
def columns_hash(table_name)
|
82
|
-
@columns_hash
|
83
|
-
[
|
84
|
-
|
111
|
+
@columns_hash.fetch(table_name) do
|
112
|
+
@columns_hash[deep_deduplicate(table_name)] = columns(table_name).index_by(&:name).freeze
|
113
|
+
end
|
85
114
|
end
|
86
115
|
|
87
116
|
# Checks whether the columns hash is already cached for a table.
|
@@ -90,7 +119,9 @@ module ActiveRecord
|
|
90
119
|
end
|
91
120
|
|
92
121
|
def indexes(table_name)
|
93
|
-
@indexes
|
122
|
+
@indexes.fetch(table_name) do
|
123
|
+
@indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
|
124
|
+
end
|
94
125
|
end
|
95
126
|
|
96
127
|
def database_version # :nodoc:
|
@@ -121,21 +152,73 @@ module ActiveRecord
|
|
121
152
|
@indexes.delete name
|
122
153
|
end
|
123
154
|
|
155
|
+
def dump_to(filename)
|
156
|
+
clear!
|
157
|
+
connection.data_sources.each { |table| add(table) }
|
158
|
+
open(filename) { |f|
|
159
|
+
if filename.include?(".dump")
|
160
|
+
f.write(Marshal.dump(self))
|
161
|
+
else
|
162
|
+
f.write(YAML.dump(self))
|
163
|
+
end
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
124
167
|
def marshal_dump
|
125
|
-
|
126
|
-
|
127
|
-
[@version, @columns,
|
168
|
+
reset_version!
|
169
|
+
|
170
|
+
[@version, @columns, {}, @primary_keys, @data_sources, @indexes, database_version]
|
128
171
|
end
|
129
172
|
|
130
173
|
def marshal_load(array)
|
131
|
-
@version, @columns,
|
132
|
-
@indexes
|
174
|
+
@version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes, @database_version = array
|
175
|
+
@indexes ||= {}
|
176
|
+
|
177
|
+
derive_columns_hash_and_deduplicate_values
|
133
178
|
end
|
134
179
|
|
135
180
|
private
|
181
|
+
def reset_version!
|
182
|
+
@version = connection.migration_context.current_version
|
183
|
+
end
|
184
|
+
|
185
|
+
def derive_columns_hash_and_deduplicate_values
|
186
|
+
@columns = deep_deduplicate(@columns)
|
187
|
+
@columns_hash = @columns.transform_values { |columns| columns.index_by(&:name) }
|
188
|
+
@primary_keys = deep_deduplicate(@primary_keys)
|
189
|
+
@data_sources = deep_deduplicate(@data_sources)
|
190
|
+
@indexes = deep_deduplicate(@indexes)
|
191
|
+
end
|
192
|
+
|
193
|
+
def deep_deduplicate(value)
|
194
|
+
case value
|
195
|
+
when Hash
|
196
|
+
value.transform_keys { |k| deep_deduplicate(k) }.transform_values { |v| deep_deduplicate(v) }
|
197
|
+
when Array
|
198
|
+
value.map { |i| deep_deduplicate(i) }
|
199
|
+
when String, Deduplicable
|
200
|
+
-value
|
201
|
+
else
|
202
|
+
value
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
136
206
|
def prepare_data_sources
|
137
207
|
connection.data_sources.each { |source| @data_sources[source] = true }
|
138
208
|
end
|
209
|
+
|
210
|
+
def open(filename)
|
211
|
+
File.atomic_write(filename) do |file|
|
212
|
+
if File.extname(filename) == ".gz"
|
213
|
+
zipper = Zlib::GzipWriter.new file
|
214
|
+
yield zipper
|
215
|
+
zipper.flush
|
216
|
+
zipper.close
|
217
|
+
else
|
218
|
+
yield file
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
139
222
|
end
|
140
223
|
end
|
141
224
|
end
|