activerecord 8.0.0 → 8.1.4
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 +1381 -241
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -17
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +20 -4
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +36 -8
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +9 -5
- data/lib/active_record/associations/collection_proxy.rb +26 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +5 -4
- data/lib/active_record/associations/preloader/association.rb +1 -1
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations.rb +159 -21
- data/lib/active_record/attribute_methods/primary_key.rb +2 -1
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +19 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +10 -2
- data/lib/active_record/attribute_methods.rb +24 -17
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +22 -12
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/callbacks.rb +1 -2
- data/lib/active_record/coders/column_serializer.rb +1 -1
- data/lib/active_record/coders/json.rb +16 -6
- data/lib/active_record/coders/yaml_column.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +19 -18
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +68 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +474 -112
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +68 -41
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +31 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +94 -28
- data/lib/active_record/connection_adapters/abstract/transaction.rb +25 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -64
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +133 -40
- data/lib/active_record/connection_adapters/column.rb +14 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +40 -25
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +66 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -3
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +29 -33
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +46 -3
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +70 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +99 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +40 -12
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +39 -23
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +15 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +7 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +68 -37
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +8 -3
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +16 -2
- data/lib/active_record/connection_adapters.rb +1 -0
- data/lib/active_record/connection_handling.rb +15 -10
- data/lib/active_record/core.rb +44 -12
- data/lib/active_record/counter_cache.rb +36 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +5 -1
- data/lib/active_record/database_configurations/hash_config.rb +66 -9
- data/lib/active_record/database_configurations/url_config.rb +15 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/disable_joins_association_relation.rb +5 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- data/lib/active_record/encryption/encrypted_fixtures.rb +12 -7
- data/lib/active_record/encryption/encryptor.rb +39 -25
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +37 -20
- data/lib/active_record/errors.rb +23 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +76 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -2
- data/lib/active_record/future_result.rb +5 -3
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +9 -4
- data/lib/active_record/insert_all.rb +14 -9
- data/lib/active_record/locking/optimistic.rb +7 -0
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +30 -22
- data/lib/active_record/message_pack.rb +13 -0
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +32 -6
- data/lib/active_record/migration/compatibility.rb +34 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +31 -21
- data/lib/active_record/model_schema.rb +38 -12
- data/lib/active_record/nested_attributes.rb +10 -6
- data/lib/active_record/persistence.rb +35 -3
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +7 -7
- data/lib/active_record/querying.rb +17 -5
- data/lib/active_record/railtie.rb +35 -6
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +24 -20
- 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 +36 -1
- data/lib/active_record/relation/batches.rb +25 -11
- data/lib/active_record/relation/calculations.rb +62 -41
- data/lib/active_record/relation/delegation.rb +0 -1
- data/lib/active_record/relation/finder_methods.rb +76 -45
- data/lib/active_record/relation/merger.rb +4 -2
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +7 -7
- data/lib/active_record/relation/predicate_builder.rb +10 -8
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +106 -45
- data/lib/active_record/relation/spawn_methods.rb +6 -6
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +63 -31
- data/lib/active_record/result.rb +44 -21
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +2 -0
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +41 -21
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +48 -19
- data/lib/active_record/statement_cache.rb +16 -12
- data/lib/active_record/store.rb +46 -19
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +5 -20
- data/lib/active_record/tasks/abstract_tasks.rb +83 -0
- data/lib/active_record/tasks/database_tasks.rb +44 -45
- data/lib/active_record/tasks/mysql_database_tasks.rb +4 -56
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
- data/lib/active_record/test_databases.rb +18 -4
- data/lib/active_record/test_fixtures.rb +40 -6
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +58 -32
- 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 +13 -2
- data/lib/active_record/type/serialized.rb +16 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record.rb +72 -7
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- 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/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +7 -23
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +16 -15
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
|
@@ -5,6 +5,23 @@ module ActiveRecord
|
|
|
5
5
|
module PostgreSQL
|
|
6
6
|
class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
|
|
7
7
|
private
|
|
8
|
+
attr_accessor :schema_name
|
|
9
|
+
|
|
10
|
+
def initialize(connection, options = {})
|
|
11
|
+
super
|
|
12
|
+
|
|
13
|
+
@dump_schemas =
|
|
14
|
+
case ActiveRecord.dump_schemas
|
|
15
|
+
when :schema_search_path
|
|
16
|
+
connection.current_schemas
|
|
17
|
+
when String
|
|
18
|
+
schema_names = ActiveRecord.dump_schemas.split(",").map(&:strip)
|
|
19
|
+
schema_names & connection.schema_names
|
|
20
|
+
else
|
|
21
|
+
connection.schema_names
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
8
25
|
def extensions(stream)
|
|
9
26
|
extensions = @connection.extensions
|
|
10
27
|
if extensions.any?
|
|
@@ -17,19 +34,21 @@ module ActiveRecord
|
|
|
17
34
|
end
|
|
18
35
|
|
|
19
36
|
def types(stream)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
within_each_schema do
|
|
38
|
+
types = @connection.enum_types
|
|
39
|
+
if types.any?
|
|
40
|
+
stream.puts " # Custom types defined in this database."
|
|
41
|
+
stream.puts " # Note that some types may not work with other database engines. Be careful if changing database."
|
|
42
|
+
types.sort.each do |name, values|
|
|
43
|
+
stream.puts " create_enum #{relation_name(name).inspect}, #{values.inspect}"
|
|
44
|
+
end
|
|
45
|
+
stream.puts
|
|
26
46
|
end
|
|
27
|
-
stream.puts
|
|
28
47
|
end
|
|
29
48
|
end
|
|
30
49
|
|
|
31
50
|
def schemas(stream)
|
|
32
|
-
schema_names = @
|
|
51
|
+
schema_names = @dump_schemas - ["public"]
|
|
33
52
|
|
|
34
53
|
if schema_names.any?
|
|
35
54
|
schema_names.sort.each do |name|
|
|
@@ -39,46 +58,43 @@ module ActiveRecord
|
|
|
39
58
|
end
|
|
40
59
|
end
|
|
41
60
|
|
|
61
|
+
def tables(stream)
|
|
62
|
+
previous_schema_had_tables = false
|
|
63
|
+
within_each_schema do
|
|
64
|
+
stream.puts if previous_schema_had_tables
|
|
65
|
+
super
|
|
66
|
+
previous_schema_had_tables = @connection.tables.any?
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
42
70
|
def exclusion_constraints_in_create(table, stream)
|
|
43
71
|
if (exclusion_constraints = @connection.exclusion_constraints(table)).any?
|
|
44
|
-
|
|
45
|
-
parts = [
|
|
46
|
-
"t.exclusion_constraint #{exclusion_constraint.expression.inspect}"
|
|
47
|
-
]
|
|
48
|
-
|
|
72
|
+
exclusion_constraint_statements = exclusion_constraints.map do |exclusion_constraint|
|
|
73
|
+
parts = [ exclusion_constraint.expression.inspect ]
|
|
49
74
|
parts << "where: #{exclusion_constraint.where.inspect}" if exclusion_constraint.where
|
|
50
75
|
parts << "using: #{exclusion_constraint.using.inspect}" if exclusion_constraint.using
|
|
51
76
|
parts << "deferrable: #{exclusion_constraint.deferrable.inspect}" if exclusion_constraint.deferrable
|
|
77
|
+
parts << "name: #{exclusion_constraint.name.inspect}" if exclusion_constraint.export_name_on_schema_dump?
|
|
52
78
|
|
|
53
|
-
|
|
54
|
-
parts << "name: #{exclusion_constraint.name.inspect}"
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
" #{parts.join(', ')}"
|
|
79
|
+
" t.exclusion_constraint #{parts.join(', ')}"
|
|
58
80
|
end
|
|
59
81
|
|
|
60
|
-
stream.puts
|
|
82
|
+
stream.puts exclusion_constraint_statements.sort.join("\n")
|
|
61
83
|
end
|
|
62
84
|
end
|
|
63
85
|
|
|
64
86
|
def unique_constraints_in_create(table, stream)
|
|
65
87
|
if (unique_constraints = @connection.unique_constraints(table)).any?
|
|
66
|
-
|
|
67
|
-
parts = [
|
|
68
|
-
"t.unique_constraint #{unique_constraint.column.inspect}"
|
|
69
|
-
]
|
|
70
|
-
|
|
88
|
+
unique_constraint_statements = unique_constraints.map do |unique_constraint|
|
|
89
|
+
parts = [ unique_constraint.column.inspect ]
|
|
71
90
|
parts << "nulls_not_distinct: #{unique_constraint.nulls_not_distinct.inspect}" if unique_constraint.nulls_not_distinct
|
|
72
91
|
parts << "deferrable: #{unique_constraint.deferrable.inspect}" if unique_constraint.deferrable
|
|
92
|
+
parts << "name: #{unique_constraint.name.inspect}" if unique_constraint.export_name_on_schema_dump?
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
parts << "name: #{unique_constraint.name.inspect}"
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
" #{parts.join(', ')}"
|
|
94
|
+
" t.unique_constraint #{parts.join(', ')}"
|
|
79
95
|
end
|
|
80
96
|
|
|
81
|
-
stream.puts
|
|
97
|
+
stream.puts unique_constraint_statements.sort.join("\n")
|
|
82
98
|
end
|
|
83
99
|
end
|
|
84
100
|
|
|
@@ -88,11 +104,11 @@ module ActiveRecord
|
|
|
88
104
|
|
|
89
105
|
if @connection.supports_virtual_columns? && column.virtual?
|
|
90
106
|
spec[:as] = extract_expression_for_virtual_column(column)
|
|
91
|
-
spec[:stored] = true
|
|
107
|
+
spec[:stored] = "true" if column.virtual_stored?
|
|
92
108
|
spec = { type: schema_type(column).inspect }.merge!(spec)
|
|
93
109
|
end
|
|
94
110
|
|
|
95
|
-
spec[:enum_type] = column.sql_type.inspect if column.enum?
|
|
111
|
+
spec[:enum_type] = relation_name(column.sql_type).inspect if column.enum?
|
|
96
112
|
|
|
97
113
|
spec
|
|
98
114
|
end
|
|
@@ -122,6 +138,28 @@ module ActiveRecord
|
|
|
122
138
|
def extract_expression_for_virtual_column(column)
|
|
123
139
|
column.default_function.inspect
|
|
124
140
|
end
|
|
141
|
+
|
|
142
|
+
def within_each_schema
|
|
143
|
+
@dump_schemas.each do |schema_name|
|
|
144
|
+
old_search_path = @connection.schema_search_path
|
|
145
|
+
@connection.schema_search_path = schema_name
|
|
146
|
+
self.schema_name = schema_name
|
|
147
|
+
yield
|
|
148
|
+
ensure
|
|
149
|
+
self.schema_name = nil
|
|
150
|
+
@connection.schema_search_path = old_search_path
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def relation_name(name)
|
|
155
|
+
if @dump_schemas.size == 1
|
|
156
|
+
name
|
|
157
|
+
elsif name.include?(".")
|
|
158
|
+
name # Already schema-qualified, don't add another prefix
|
|
159
|
+
else
|
|
160
|
+
"#{schema_name}.#{name}"
|
|
161
|
+
end
|
|
162
|
+
end
|
|
125
163
|
end
|
|
126
164
|
end
|
|
127
165
|
end
|
|
@@ -12,9 +12,10 @@ module ActiveRecord
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
|
|
15
|
-
# <tt>:encoding</tt> (defaults to utf8), <tt>:
|
|
16
|
-
# <tt>:
|
|
17
|
-
# <tt>:
|
|
15
|
+
# <tt>:encoding</tt> (defaults to utf8), <tt>:locale_provider</tt>, <tt>:locale</tt>,
|
|
16
|
+
# <tt>:collation</tt>, <tt>:ctype</tt>, <tt>:tablespace</tt>, and
|
|
17
|
+
# <tt>:connection_limit</tt> (note that MySQL uses <tt>:charset</tt> while PostgreSQL
|
|
18
|
+
# uses <tt>:encoding</tt>).
|
|
18
19
|
#
|
|
19
20
|
# Example:
|
|
20
21
|
# create_database config[:database], config
|
|
@@ -30,6 +31,10 @@ module ActiveRecord
|
|
|
30
31
|
" TEMPLATE = \"#{value}\""
|
|
31
32
|
when :encoding
|
|
32
33
|
" ENCODING = '#{value}'"
|
|
34
|
+
when :locale_provider
|
|
35
|
+
" LOCALE_PROVIDER = '#{value}'"
|
|
36
|
+
when :locale
|
|
37
|
+
" LOCALE = '#{value}'"
|
|
33
38
|
when :collation
|
|
34
39
|
" LC_COLLATE = '#{value}'"
|
|
35
40
|
when :ctype
|
|
@@ -87,8 +92,13 @@ module ActiveRecord
|
|
|
87
92
|
scope = quoted_scope(table_name)
|
|
88
93
|
|
|
89
94
|
result = query(<<~SQL, "SCHEMA")
|
|
90
|
-
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid),
|
|
91
|
-
pg_catalog.obj_description(i.oid, 'pg_class') AS comment, d.indisvalid
|
|
95
|
+
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid),
|
|
96
|
+
pg_catalog.obj_description(i.oid, 'pg_class') AS comment, d.indisvalid,
|
|
97
|
+
ARRAY(
|
|
98
|
+
SELECT pg_get_indexdef(d.indexrelid, k + 1, true)
|
|
99
|
+
FROM generate_subscripts(d.indkey, 1) AS k
|
|
100
|
+
ORDER BY k
|
|
101
|
+
) AS columns
|
|
92
102
|
FROM pg_class t
|
|
93
103
|
INNER JOIN pg_index d ON t.oid = d.indrelid
|
|
94
104
|
INNER JOIN pg_class i ON d.indexrelid = i.oid
|
|
@@ -105,9 +115,10 @@ module ActiveRecord
|
|
|
105
115
|
unique = row[1]
|
|
106
116
|
indkey = row[2].split(" ").map(&:to_i)
|
|
107
117
|
inddef = row[3]
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
118
|
+
comment = row[4]
|
|
119
|
+
valid = row[5]
|
|
120
|
+
columns = decode_string_array(row[6]).map { |c| Utils.unquote_identifier(c.strip.gsub('""', '"')) }
|
|
121
|
+
|
|
111
122
|
using, expressions, include, nulls_not_distinct, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: INCLUDE \((.+?)\))?( NULLS NOT DISTINCT)?(?: WHERE (.+))?\z/m).flatten
|
|
112
123
|
|
|
113
124
|
orders = {}
|
|
@@ -117,15 +128,14 @@ module ActiveRecord
|
|
|
117
128
|
if indkey.include?(0)
|
|
118
129
|
columns = expressions
|
|
119
130
|
else
|
|
120
|
-
columns = column_names_from_column_numbers(oid, indkey)
|
|
121
|
-
|
|
122
131
|
# prevent INCLUDE columns from being matched
|
|
123
132
|
columns.reject! { |c| include_columns.include?(c) }
|
|
124
133
|
|
|
125
134
|
# add info on sort order (only desc order is explicitly specified, asc is the default)
|
|
126
135
|
# and non-default opclasses
|
|
127
|
-
expressions.scan(/(?<column>\w+)"?\s?(?<opclass
|
|
128
|
-
opclasses[column] = opclass.to_sym if opclass
|
|
136
|
+
expressions.scan(/(?<column>\w+)"?\s?(?<opclass>(?:\w+\.)?\w+_ops(_\w+)?)?\s?(?<desc>DESC)?\s?(?<nulls>NULLS (?:FIRST|LAST))?/).each do |column, opclass, desc, nulls|
|
|
137
|
+
opclasses[column] = opclass.split(".").last.to_sym if opclass
|
|
138
|
+
|
|
129
139
|
if nulls
|
|
130
140
|
orders[column] = [desc, nulls].compact.join(" ")
|
|
131
141
|
else
|
|
@@ -213,6 +223,7 @@ module ActiveRecord
|
|
|
213
223
|
WHERE child.relname = #{scope[:name]}
|
|
214
224
|
AND child.relkind IN (#{scope[:type]})
|
|
215
225
|
AND n.nspname = #{scope[:schema]}
|
|
226
|
+
ORDER BY i.inhseqno
|
|
216
227
|
SQL
|
|
217
228
|
end
|
|
218
229
|
|
|
@@ -226,6 +237,14 @@ module ActiveRecord
|
|
|
226
237
|
query_value("SELECT current_schema", "SCHEMA")
|
|
227
238
|
end
|
|
228
239
|
|
|
240
|
+
# Returns an array of the names of all schemas presently in the effective search path,
|
|
241
|
+
# in their priority order.
|
|
242
|
+
def current_schemas # :nodoc:
|
|
243
|
+
schemas = query_value("SELECT current_schemas(false)", "SCHEMA")
|
|
244
|
+
decoder = PG::TextDecoder::Array.new
|
|
245
|
+
decoder.decode(schemas)
|
|
246
|
+
end
|
|
247
|
+
|
|
229
248
|
# Returns the current database encoding format.
|
|
230
249
|
def encoding
|
|
231
250
|
query_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = current_database()", "SCHEMA")
|
|
@@ -270,12 +289,18 @@ module ActiveRecord
|
|
|
270
289
|
execute "DROP SCHEMA#{' IF EXISTS' if options[:if_exists]} #{quote_schema_name(schema_name)} CASCADE"
|
|
271
290
|
end
|
|
272
291
|
|
|
292
|
+
# Renames the schema for the given schema name.
|
|
293
|
+
def rename_schema(schema_name, new_name)
|
|
294
|
+
execute "ALTER SCHEMA #{quote_schema_name(schema_name)} RENAME TO #{quote_schema_name(new_name)}"
|
|
295
|
+
end
|
|
296
|
+
|
|
273
297
|
# Sets the schema search path to a string of comma-separated schema names.
|
|
274
298
|
# Names beginning with $ have to be quoted (e.g. $user => '$user').
|
|
275
299
|
# See: https://www.postgresql.org/docs/current/static/ddl-schemas.html
|
|
276
300
|
#
|
|
277
301
|
# This should be not be called manually but set in database.yml.
|
|
278
302
|
def schema_search_path=(schema_csv)
|
|
303
|
+
return if schema_csv == @schema_search_path
|
|
279
304
|
if schema_csv
|
|
280
305
|
internal_execute("SET search_path TO #{schema_csv}")
|
|
281
306
|
@schema_search_path = schema_csv
|
|
@@ -320,7 +345,7 @@ module ActiveRecord
|
|
|
320
345
|
if sequence
|
|
321
346
|
quoted_sequence = quote_table_name(sequence)
|
|
322
347
|
|
|
323
|
-
|
|
348
|
+
internal_execute("SELECT setval(#{quote(quoted_sequence)}, #{value})", "SCHEMA")
|
|
324
349
|
else
|
|
325
350
|
@logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger
|
|
326
351
|
end
|
|
@@ -351,7 +376,7 @@ module ActiveRecord
|
|
|
351
376
|
end
|
|
352
377
|
end
|
|
353
378
|
|
|
354
|
-
|
|
379
|
+
internal_execute("SELECT setval(#{quote(quoted_sequence)}, #{max_pk || minvalue}, #{max_pk ? true : false})", "SCHEMA")
|
|
355
380
|
end
|
|
356
381
|
end
|
|
357
382
|
|
|
@@ -412,16 +437,13 @@ module ActiveRecord
|
|
|
412
437
|
def primary_keys(table_name) # :nodoc:
|
|
413
438
|
query_values(<<~SQL, "SCHEMA")
|
|
414
439
|
SELECT a.attname
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
ON a.attrelid = i.indrelid
|
|
423
|
-
AND a.attnum = i.indkey[i.idx]
|
|
424
|
-
ORDER BY i.idx
|
|
440
|
+
FROM pg_index i
|
|
441
|
+
JOIN pg_attribute a
|
|
442
|
+
ON a.attrelid = i.indrelid
|
|
443
|
+
AND a.attnum = ANY(i.indkey)
|
|
444
|
+
WHERE i.indrelid = #{quote(quote_table_name(table_name))}::regclass
|
|
445
|
+
AND i.indisprimary
|
|
446
|
+
ORDER BY array_position(i.indkey, a.attnum)
|
|
425
447
|
SQL
|
|
426
448
|
end
|
|
427
449
|
|
|
@@ -531,7 +553,12 @@ module ActiveRecord
|
|
|
531
553
|
result = execute schema_creation.accept(create_index)
|
|
532
554
|
|
|
533
555
|
index = create_index.index
|
|
534
|
-
|
|
556
|
+
if index.comment
|
|
557
|
+
name = Utils.extract_schema_qualified_name(table_name.to_s)
|
|
558
|
+
index_name = name.schema ? PostgreSQL::Name.new(name.schema, index.name).to_s : index.name
|
|
559
|
+
execute "COMMENT ON INDEX #{quote_table_name(index_name)} IS #{quote(index.comment)}"
|
|
560
|
+
end
|
|
561
|
+
|
|
535
562
|
result
|
|
536
563
|
end
|
|
537
564
|
|
|
@@ -584,36 +611,45 @@ module ActiveRecord
|
|
|
584
611
|
def foreign_keys(table_name)
|
|
585
612
|
scope = quoted_scope(table_name)
|
|
586
613
|
fk_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
|
|
587
|
-
SELECT t2.oid::regclass::text AS to_table,
|
|
614
|
+
SELECT t2.oid::regclass::text AS to_table, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid, c.condeferrable AS deferrable, c.condeferred AS deferred, c.conrelid, c.confrelid,
|
|
615
|
+
(
|
|
616
|
+
SELECT array_agg(a.attname ORDER BY idx)
|
|
617
|
+
FROM (
|
|
618
|
+
SELECT idx, c.conkey[idx] AS conkey_elem
|
|
619
|
+
FROM generate_subscripts(c.conkey, 1) AS idx
|
|
620
|
+
) indexed_conkeys
|
|
621
|
+
JOIN pg_attribute a ON a.attrelid = t1.oid
|
|
622
|
+
AND a.attnum = indexed_conkeys.conkey_elem
|
|
623
|
+
) AS conkey_names,
|
|
624
|
+
(
|
|
625
|
+
SELECT array_agg(a.attname ORDER BY idx)
|
|
626
|
+
FROM (
|
|
627
|
+
SELECT idx, c.confkey[idx] AS confkey_elem
|
|
628
|
+
FROM generate_subscripts(c.confkey, 1) AS idx
|
|
629
|
+
) indexed_confkeys
|
|
630
|
+
JOIN pg_attribute a ON a.attrelid = t2.oid
|
|
631
|
+
AND a.attnum = indexed_confkeys.confkey_elem
|
|
632
|
+
) AS confkey_names
|
|
588
633
|
FROM pg_constraint c
|
|
589
634
|
JOIN pg_class t1 ON c.conrelid = t1.oid
|
|
590
635
|
JOIN pg_class t2 ON c.confrelid = t2.oid
|
|
591
|
-
JOIN
|
|
592
|
-
JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
|
|
593
|
-
JOIN pg_namespace t3 ON c.connamespace = t3.oid
|
|
636
|
+
JOIN pg_namespace n ON c.connamespace = n.oid
|
|
594
637
|
WHERE c.contype = 'f'
|
|
595
638
|
AND t1.relname = #{scope[:name]}
|
|
596
|
-
AND
|
|
639
|
+
AND n.nspname = #{scope[:schema]}
|
|
597
640
|
ORDER BY c.conname
|
|
598
641
|
SQL
|
|
599
642
|
|
|
600
643
|
fk_info.map do |row|
|
|
601
|
-
to_table = Utils.
|
|
602
|
-
conkey = row["conkey"].scan(/\d+/).map(&:to_i)
|
|
603
|
-
confkey = row["confkey"].scan(/\d+/).map(&:to_i)
|
|
644
|
+
to_table = Utils.extract_schema_qualified_name(row["to_table"]).to_s
|
|
604
645
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
primary_key = column_names_from_column_numbers(row["confrelid"], confkey)
|
|
608
|
-
else
|
|
609
|
-
column = Utils.unquote_identifier(row["column"])
|
|
610
|
-
primary_key = row["primary_key"]
|
|
611
|
-
end
|
|
646
|
+
column = decode_string_array(row["conkey_names"])
|
|
647
|
+
primary_key = decode_string_array(row["confkey_names"])
|
|
612
648
|
|
|
613
649
|
options = {
|
|
614
|
-
column: column,
|
|
650
|
+
column: column.size == 1 ? column.first : column,
|
|
615
651
|
name: row["name"],
|
|
616
|
-
primary_key: primary_key
|
|
652
|
+
primary_key: primary_key.size == 1 ? primary_key.first : primary_key
|
|
617
653
|
}
|
|
618
654
|
|
|
619
655
|
options[:on_delete] = extract_foreign_key_action(row["on_delete"])
|
|
@@ -675,7 +711,7 @@ module ActiveRecord
|
|
|
675
711
|
|
|
676
712
|
exclusion_info.map do |row|
|
|
677
713
|
method_and_elements, predicate = row["constraintdef"].split(" WHERE ")
|
|
678
|
-
method_and_elements_parts = method_and_elements.match(/EXCLUDE(?: USING (?<using>\S+))? \((?<expression>.+)\)/)
|
|
714
|
+
method_and_elements_parts = method_and_elements.match(/EXCLUDE(?: USING (?<using>\S+))? \((?<expression>.+)\)/m)
|
|
679
715
|
predicate.remove!(/ DEFERRABLE(?: INITIALLY (?:IMMEDIATE|DEFERRED))?/) if predicate
|
|
680
716
|
predicate = predicate.from(2).to(-3) if predicate # strip 2 opening and closing parentheses
|
|
681
717
|
|
|
@@ -698,7 +734,16 @@ module ActiveRecord
|
|
|
698
734
|
scope = quoted_scope(table_name)
|
|
699
735
|
|
|
700
736
|
unique_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
|
|
701
|
-
SELECT c.conname, c.conrelid, c.
|
|
737
|
+
SELECT c.conname, c.conrelid, c.condeferrable, c.condeferred, pg_get_constraintdef(c.oid) AS constraintdef,
|
|
738
|
+
(
|
|
739
|
+
SELECT array_agg(a.attname ORDER BY idx)
|
|
740
|
+
FROM (
|
|
741
|
+
SELECT idx, c.conkey[idx] AS conkey_elem
|
|
742
|
+
FROM generate_subscripts(c.conkey, 1) AS idx
|
|
743
|
+
) indexed_conkeys
|
|
744
|
+
JOIN pg_attribute a ON a.attrelid = t.oid
|
|
745
|
+
AND a.attnum = indexed_conkeys.conkey_elem
|
|
746
|
+
) AS conkey_names
|
|
702
747
|
FROM pg_constraint c
|
|
703
748
|
JOIN pg_class t ON c.conrelid = t.oid
|
|
704
749
|
JOIN pg_namespace n ON n.oid = c.connamespace
|
|
@@ -708,8 +753,7 @@ module ActiveRecord
|
|
|
708
753
|
SQL
|
|
709
754
|
|
|
710
755
|
unique_info.map do |row|
|
|
711
|
-
|
|
712
|
-
columns = column_names_from_column_numbers(row["conrelid"], conkey)
|
|
756
|
+
columns = decode_string_array(row["conkey_names"])
|
|
713
757
|
|
|
714
758
|
nulls_not_distinct = row["constraintdef"].start_with?("UNIQUE NULLS NOT DISTINCT")
|
|
715
759
|
deferrable = extract_constraint_deferrable(row["condeferrable"], row["condeferred"])
|
|
@@ -922,7 +966,7 @@ module ActiveRecord
|
|
|
922
966
|
#
|
|
923
967
|
# validate_check_constraint :products, name: "price_check"
|
|
924
968
|
#
|
|
925
|
-
# The +options+ hash accepts the same keys as add_check_constraint[rdoc-ref:ConnectionAdapters::SchemaStatements#add_check_constraint].
|
|
969
|
+
# The +options+ hash accepts the same keys as {add_check_constraint}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_check_constraint].
|
|
926
970
|
def validate_check_constraint(table_name, **options)
|
|
927
971
|
chk_name_to_validate = check_constraint_for!(table_name, **options).name
|
|
928
972
|
|
|
@@ -980,6 +1024,7 @@ module ActiveRecord
|
|
|
980
1024
|
|
|
981
1025
|
PostgreSQL::Column.new(
|
|
982
1026
|
column_name,
|
|
1027
|
+
get_oid_type(oid.to_i, fmod.to_i, column_name, type),
|
|
983
1028
|
default_value,
|
|
984
1029
|
type_metadata,
|
|
985
1030
|
!notnull,
|
|
@@ -1075,6 +1120,11 @@ module ActiveRecord
|
|
|
1075
1120
|
super
|
|
1076
1121
|
end
|
|
1077
1122
|
|
|
1123
|
+
def validate_table_length!(table_name)
|
|
1124
|
+
_schema, table_name = extract_schema_qualified_name(table_name)
|
|
1125
|
+
super
|
|
1126
|
+
end
|
|
1127
|
+
|
|
1078
1128
|
def exclusion_constraint_name(table_name, **options)
|
|
1079
1129
|
options.fetch(:name) do
|
|
1080
1130
|
expression = options.fetch(:expression)
|
|
@@ -1149,13 +1199,8 @@ module ActiveRecord
|
|
|
1149
1199
|
[name.schema, name.identifier]
|
|
1150
1200
|
end
|
|
1151
1201
|
|
|
1152
|
-
def
|
|
1153
|
-
|
|
1154
|
-
SELECT a.attnum, a.attname
|
|
1155
|
-
FROM pg_attribute a
|
|
1156
|
-
WHERE a.attrelid = #{table_oid}
|
|
1157
|
-
AND a.attnum IN (#{column_numbers.join(", ")})
|
|
1158
|
-
SQL
|
|
1202
|
+
def decode_string_array(value)
|
|
1203
|
+
PG::TextDecoder::Array.new.decode(value)
|
|
1159
1204
|
end
|
|
1160
1205
|
end
|
|
1161
1206
|
end
|
|
@@ -25,7 +25,7 @@ module ActiveRecord
|
|
|
25
25
|
#
|
|
26
26
|
# The PostgreSQL adapter works with the native C (https://github.com/ged/ruby-pg) driver.
|
|
27
27
|
#
|
|
28
|
-
# Options
|
|
28
|
+
# ==== Options
|
|
29
29
|
#
|
|
30
30
|
# * <tt>:host</tt> - Defaults to a Unix-domain socket in /tmp. On machines without Unix-domain sockets,
|
|
31
31
|
# the default is to connect to localhost.
|
|
@@ -288,6 +288,16 @@ module ActiveRecord
|
|
|
288
288
|
database_version >= 10_00_00 # >= 10.0
|
|
289
289
|
end
|
|
290
290
|
|
|
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
|
+
|
|
291
301
|
def index_algorithms
|
|
292
302
|
{ concurrently: "CONCURRENTLY" }
|
|
293
303
|
end
|
|
@@ -309,8 +319,12 @@ module ActiveRecord
|
|
|
309
319
|
# accessed while holding the connection's lock. (And we
|
|
310
320
|
# don't need the complication of with_raw_connection because
|
|
311
321
|
# a reconnect would invalidate the entire statement pool.)
|
|
312
|
-
if conn = @connection.instance_variable_get(:@raw_connection)
|
|
313
|
-
|
|
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
|
|
314
328
|
end
|
|
315
329
|
rescue PG::Error
|
|
316
330
|
end
|
|
@@ -349,6 +363,7 @@ module ActiveRecord
|
|
|
349
363
|
@lock.synchronize do
|
|
350
364
|
return false unless @raw_connection
|
|
351
365
|
@raw_connection.query ";"
|
|
366
|
+
verified!
|
|
352
367
|
end
|
|
353
368
|
true
|
|
354
369
|
rescue PG::Error
|
|
@@ -380,6 +395,11 @@ module ActiveRecord
|
|
|
380
395
|
end
|
|
381
396
|
end
|
|
382
397
|
|
|
398
|
+
def clear_cache!(new_connection: false)
|
|
399
|
+
super
|
|
400
|
+
@schema_search_path = nil if new_connection
|
|
401
|
+
end
|
|
402
|
+
|
|
383
403
|
# Disconnects from the database if already connected. Otherwise, this
|
|
384
404
|
# method does nothing.
|
|
385
405
|
def disconnect!
|
|
@@ -396,10 +416,6 @@ module ActiveRecord
|
|
|
396
416
|
@raw_connection = nil
|
|
397
417
|
end
|
|
398
418
|
|
|
399
|
-
def native_database_types # :nodoc:
|
|
400
|
-
self.class.native_database_types
|
|
401
|
-
end
|
|
402
|
-
|
|
403
419
|
def self.native_database_types # :nodoc:
|
|
404
420
|
@native_database_types ||= begin
|
|
405
421
|
types = NATIVE_DATABASE_TYPES.dup
|
|
@@ -520,7 +536,7 @@ module ActiveRecord
|
|
|
520
536
|
type.typname AS name,
|
|
521
537
|
type.OID AS oid,
|
|
522
538
|
n.nspname AS schema,
|
|
523
|
-
|
|
539
|
+
array_agg(enum.enumlabel ORDER BY enum.enumsortorder) AS value
|
|
524
540
|
FROM pg_enum AS enum
|
|
525
541
|
JOIN pg_type AS type ON (type.oid = enum.enumtypid)
|
|
526
542
|
JOIN pg_namespace n ON type.typnamespace = n.oid
|
|
@@ -615,7 +631,7 @@ module ActiveRecord
|
|
|
615
631
|
}
|
|
616
632
|
end
|
|
617
633
|
|
|
618
|
-
# Returns the configured supported identifier length supported by PostgreSQL
|
|
634
|
+
# Returns the configured maximum supported identifier length supported by PostgreSQL
|
|
619
635
|
def max_identifier_length
|
|
620
636
|
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
|
621
637
|
end
|
|
@@ -633,7 +649,11 @@ module ActiveRecord
|
|
|
633
649
|
# Returns the version of the connected PostgreSQL server.
|
|
634
650
|
def get_database_version # :nodoc:
|
|
635
651
|
with_raw_connection do |conn|
|
|
636
|
-
conn.server_version
|
|
652
|
+
version = conn.server_version
|
|
653
|
+
if version == 0
|
|
654
|
+
raise ActiveRecord::ConnectionNotEstablished, "Could not determine PostgreSQL version"
|
|
655
|
+
end
|
|
656
|
+
version
|
|
637
657
|
end
|
|
638
658
|
end
|
|
639
659
|
alias :postgresql_version :database_version
|
|
@@ -662,8 +682,8 @@ module ActiveRecord
|
|
|
662
682
|
end
|
|
663
683
|
|
|
664
684
|
def check_version # :nodoc:
|
|
665
|
-
if database_version <
|
|
666
|
-
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.
|
|
685
|
+
if database_version < 9_05_00 # < 9.5
|
|
686
|
+
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.5."
|
|
667
687
|
end
|
|
668
688
|
end
|
|
669
689
|
|
|
@@ -787,6 +807,8 @@ module ActiveRecord
|
|
|
787
807
|
NOT_NULL_VIOLATION = "23502"
|
|
788
808
|
FOREIGN_KEY_VIOLATION = "23503"
|
|
789
809
|
UNIQUE_VIOLATION = "23505"
|
|
810
|
+
CHECK_VIOLATION = "23514"
|
|
811
|
+
EXCLUSION_VIOLATION = "23P01"
|
|
790
812
|
SERIALIZATION_FAILURE = "40001"
|
|
791
813
|
DEADLOCK_DETECTED = "40P01"
|
|
792
814
|
DUPLICATE_DATABASE = "42P04"
|
|
@@ -818,6 +840,10 @@ module ActiveRecord
|
|
|
818
840
|
RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
819
841
|
when FOREIGN_KEY_VIOLATION
|
|
820
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)
|
|
821
847
|
when VALUE_LIMIT_VIOLATION
|
|
822
848
|
ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
823
849
|
when NUMERIC_VALUE_OUT_OF_RANGE
|
|
@@ -988,6 +1014,8 @@ module ActiveRecord
|
|
|
988
1014
|
add_pg_encoders
|
|
989
1015
|
add_pg_decoders
|
|
990
1016
|
|
|
1017
|
+
schema_search_path # populate cache
|
|
1018
|
+
|
|
991
1019
|
reload_type_map
|
|
992
1020
|
end
|
|
993
1021
|
|
|
@@ -46,7 +46,9 @@ module ActiveRecord
|
|
|
46
46
|
def ==(other)
|
|
47
47
|
other.is_a?(Column) &&
|
|
48
48
|
super &&
|
|
49
|
-
auto_increment? == other.auto_increment?
|
|
49
|
+
auto_increment? == other.auto_increment? &&
|
|
50
|
+
rowid == other.rowid &&
|
|
51
|
+
generated_type == other.generated_type
|
|
50
52
|
end
|
|
51
53
|
alias :eql? :==
|
|
52
54
|
|
|
@@ -54,8 +56,12 @@ module ActiveRecord
|
|
|
54
56
|
Column.hash ^
|
|
55
57
|
super.hash ^
|
|
56
58
|
auto_increment?.hash ^
|
|
57
|
-
rowid.hash
|
|
59
|
+
rowid.hash ^
|
|
60
|
+
virtual?.hash
|
|
58
61
|
end
|
|
62
|
+
|
|
63
|
+
protected
|
|
64
|
+
attr_reader :generated_type
|
|
59
65
|
end
|
|
60
66
|
end
|
|
61
67
|
end
|