activerecord 6.0.3.4 → 6.1.2
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 +891 -695
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record.rb +7 -14
- data/lib/active_record/aggregations.rb +5 -5
- data/lib/active_record/association_relation.rb +30 -12
- data/lib/active_record/associations.rb +118 -11
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +44 -28
- 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 -1
- 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 +19 -6
- data/lib/active_record/associations/collection_proxy.rb +13 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- 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 +72 -50
- 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 +11 -5
- 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 -8
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attributes.rb +33 -8
- data/lib/active_record/autosave_association.rb +57 -40
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +191 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
- 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 +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +116 -27
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +54 -72
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +133 -96
- 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/database_statements.rb +23 -25
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- 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 +11 -7
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- 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 +13 -54
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- 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/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -58
- 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 +31 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
- data/lib/active_record/connection_handling.rb +218 -71
- data/lib/active_record/core.rb +245 -61
- 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 -40
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +82 -38
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- 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 -2
- data/lib/active_record/fixtures.rb +58 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +35 -6
- 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 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -8
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +68 -17
- data/lib/active_record/model_schema.rb +117 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +276 -99
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +71 -57
- data/lib/active_record/relation.rb +96 -67
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +101 -44
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +45 -15
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +27 -25
- data/lib/active_record/relation/predicate_builder.rb +59 -38
- 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 +333 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/result.rb +41 -33
- 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/named.rb +6 -17
- 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 +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -51
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +37 -16
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +19 -66
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type/time.rb +10 -0
- 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 +1 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +5 -13
- 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 +12 -18
- 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 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/rails/generators/active_record/migration.rb +6 -1
- 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 +3 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +25 -26
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- 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 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -67,15 +67,34 @@ module ActiveRecord
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def extract_bounds(value)
|
70
|
-
from, to = value[1..-2].split(",")
|
70
|
+
from, to = value[1..-2].split(",", 2)
|
71
71
|
{
|
72
|
-
from: (
|
73
|
-
to: (
|
74
|
-
exclude_start: (
|
75
|
-
exclude_end: (
|
72
|
+
from: (from == "" || from == "-infinity") ? infinity(negative: true) : unquote(from),
|
73
|
+
to: (to == "" || to == "infinity") ? infinity : unquote(to),
|
74
|
+
exclude_start: value.start_with?("("),
|
75
|
+
exclude_end: value.end_with?(")")
|
76
76
|
}
|
77
77
|
end
|
78
78
|
|
79
|
+
# When formatting the bound values of range types, PostgreSQL quotes
|
80
|
+
# the bound value using double-quotes in certain conditions. Within
|
81
|
+
# a double-quoted string, literal " and \ characters are themselves
|
82
|
+
# escaped. In input, PostgreSQL accepts multiple escape styles for "
|
83
|
+
# (either \" or "") but in output always uses "".
|
84
|
+
# See:
|
85
|
+
# * https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-IO
|
86
|
+
# * https://www.postgresql.org/docs/current/rowtypes.html#ROWTYPES-IO-SYNTAX
|
87
|
+
def unquote(value)
|
88
|
+
if value.start_with?('"') && value.end_with?('"')
|
89
|
+
unquoted_value = value[1..-2]
|
90
|
+
unquoted_value.gsub!('""', '"')
|
91
|
+
unquoted_value.gsub!('\\\\', '\\')
|
92
|
+
unquoted_value
|
93
|
+
else
|
94
|
+
value
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
79
98
|
def infinity(negative: false)
|
80
99
|
if subtype.respond_to?(:infinity)
|
81
100
|
subtype.infinity(negative: negative)
|
@@ -7,12 +7,22 @@ module ActiveRecord
|
|
7
7
|
class Uuid < Type::Value # :nodoc:
|
8
8
|
ACCEPTABLE_UUID = %r{\A(\{)?([a-fA-F0-9]{4}-?){8}(?(1)\}|)\z}
|
9
9
|
|
10
|
-
|
10
|
+
alias :serialize :deserialize
|
11
11
|
|
12
12
|
def type
|
13
13
|
:uuid
|
14
14
|
end
|
15
15
|
|
16
|
+
def changed?(old_value, new_value, _new_value_before_type_cast)
|
17
|
+
old_value.class != new_value.class ||
|
18
|
+
new_value && old_value.casecmp(new_value) != 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def changed_in_place?(raw_old_value, new_value)
|
22
|
+
raw_old_value.class != new_value.class ||
|
23
|
+
new_value && raw_old_value.casecmp(new_value) != 0
|
24
|
+
end
|
25
|
+
|
16
26
|
private
|
17
27
|
def cast_value(value)
|
18
28
|
casted = value.to_s
|
@@ -18,7 +18,7 @@ module ActiveRecord
|
|
18
18
|
|
19
19
|
# Quotes strings for use in SQL input.
|
20
20
|
def quote_string(s) #:nodoc:
|
21
|
-
|
21
|
+
PG::Connection.escape(s)
|
22
22
|
end
|
23
23
|
|
24
24
|
# Checks the following cases:
|
@@ -67,8 +67,8 @@ module ActiveRecord
|
|
67
67
|
elsif column.type == :uuid && value.is_a?(String) && /\(\)/.match?(value)
|
68
68
|
value # Does not quote function default values for UUID columns
|
69
69
|
elsif column.respond_to?(:array?)
|
70
|
-
|
71
|
-
quote(value)
|
70
|
+
type = lookup_cast_type_from_column(column)
|
71
|
+
quote(type.serialize(value))
|
72
72
|
else
|
73
73
|
super
|
74
74
|
end
|
@@ -93,7 +93,7 @@ module ActiveRecord
|
|
93
93
|
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
94
94
|
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
95
95
|
)
|
96
|
-
(?:\s+AS
|
96
|
+
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
97
97
|
)
|
98
98
|
(?:\s*,\s*\g<1>)*
|
99
99
|
\z
|
@@ -24,7 +24,7 @@ WARNING: Rails was not able to disable referential integrity.
|
|
24
24
|
This is most likely caused due to missing permissions.
|
25
25
|
Rails needs superuser privileges to disable referential integrity.
|
26
26
|
|
27
|
-
cause: #{original_exception
|
27
|
+
cause: #{original_exception&.message}
|
28
28
|
|
29
29
|
WARNING
|
30
30
|
raise e
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
5
|
module PostgreSQL
|
6
|
-
class SchemaCreation <
|
6
|
+
class SchemaCreation < SchemaCreation # :nodoc:
|
7
7
|
private
|
8
8
|
def visit_AlterTable(o)
|
9
9
|
super << o.constraint_validations.map { |fk| visit_ValidateConstraint fk }.join(" ")
|
@@ -13,6 +13,10 @@ module ActiveRecord
|
|
13
13
|
super.dup.tap { |sql| sql << " NOT VALID" unless o.validate? }
|
14
14
|
end
|
15
15
|
|
16
|
+
def visit_CheckConstraintDefinition(o)
|
17
|
+
super.dup.tap { |sql| sql << " NOT VALID" unless o.validate? }
|
18
|
+
end
|
19
|
+
|
16
20
|
def visit_ValidateConstraint(name)
|
17
21
|
"VALIDATE CONSTRAINT #{quote_column_name(name)}"
|
18
22
|
end
|
@@ -54,7 +54,8 @@ module ActiveRecord
|
|
54
54
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
55
55
|
end
|
56
56
|
|
57
|
-
def drop_table(table_name, options
|
57
|
+
def drop_table(table_name, **options) # :nodoc:
|
58
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
58
59
|
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
59
60
|
end
|
60
61
|
|
@@ -211,7 +212,7 @@ module ActiveRecord
|
|
211
212
|
end
|
212
213
|
|
213
214
|
# Drops the schema for the given schema name.
|
214
|
-
def drop_schema(schema_name, options
|
215
|
+
def drop_schema(schema_name, **options)
|
215
216
|
execute "DROP SCHEMA#{' IF EXISTS' if options[:if_exists]} #{quote_schema_name(schema_name)} CASCADE"
|
216
217
|
end
|
217
218
|
|
@@ -376,6 +377,8 @@ module ActiveRecord
|
|
376
377
|
# rename_table('octopuses', 'octopi')
|
377
378
|
def rename_table(table_name, new_name)
|
378
379
|
clear_cache!
|
380
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
381
|
+
schema_cache.clear_data_source_cache!(new_name.to_s)
|
379
382
|
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
|
380
383
|
pk, seq = pk_and_sequence_for(new_name)
|
381
384
|
if pk
|
@@ -396,9 +399,9 @@ module ActiveRecord
|
|
396
399
|
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
397
400
|
end
|
398
401
|
|
399
|
-
def change_column(table_name, column_name, type, options
|
402
|
+
def change_column(table_name, column_name, type, **options) #:nodoc:
|
400
403
|
clear_cache!
|
401
|
-
sqls, procs = Array(change_column_for_alter(table_name, column_name, type, options)).partition { |v| v.is_a?(String) }
|
404
|
+
sqls, procs = Array(change_column_for_alter(table_name, column_name, type, **options)).partition { |v| v.is_a?(String) }
|
402
405
|
execute "ALTER TABLE #{quote_table_name(table_name)} #{sqls.join(", ")}"
|
403
406
|
procs.each(&:call)
|
404
407
|
end
|
@@ -434,21 +437,24 @@ module ActiveRecord
|
|
434
437
|
# Renames a column in a table.
|
435
438
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
436
439
|
clear_cache!
|
437
|
-
execute
|
440
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_sql(table_name, column_name, new_column_name)}")
|
438
441
|
rename_column_indexes(table_name, column_name, new_column_name)
|
439
442
|
end
|
440
443
|
|
441
|
-
def add_index(table_name, column_name, options
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
444
|
+
def add_index(table_name, column_name, **options) #:nodoc:
|
445
|
+
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
446
|
+
|
447
|
+
create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
|
448
|
+
result = execute schema_creation.accept(create_index)
|
449
|
+
|
450
|
+
execute "COMMENT ON INDEX #{quote_column_name(index.name)} IS #{quote(index.comment)}" if index.comment
|
451
|
+
result
|
446
452
|
end
|
447
453
|
|
448
|
-
def remove_index(table_name,
|
454
|
+
def remove_index(table_name, column_name = nil, **options) # :nodoc:
|
449
455
|
table = Utils.extract_schema_qualified_name(table_name.to_s)
|
450
456
|
|
451
|
-
if options.
|
457
|
+
if options.key?(:name)
|
452
458
|
provided_index = Utils.extract_schema_qualified_name(options[:name].to_s)
|
453
459
|
|
454
460
|
options[:name] = provided_index.identifier
|
@@ -459,14 +465,11 @@ module ActiveRecord
|
|
459
465
|
end
|
460
466
|
end
|
461
467
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
end
|
468
|
-
end
|
469
|
-
execute "DROP INDEX #{algorithm} #{quote_table_name(index_to_remove)}"
|
468
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
469
|
+
|
470
|
+
index_to_remove = PostgreSQL::Name.new(table.schema, index_name_for_remove(table.to_s, column_name, options))
|
471
|
+
|
472
|
+
execute "DROP INDEX #{index_algorithm(options[:algorithm])} #{quote_table_name(index_to_remove)}"
|
470
473
|
end
|
471
474
|
|
472
475
|
# Renames an index of a table. Raises error if length of new
|
@@ -516,6 +519,28 @@ module ActiveRecord
|
|
516
519
|
query_values(data_source_sql(table_name, type: "FOREIGN TABLE"), "SCHEMA").any? if table_name.present?
|
517
520
|
end
|
518
521
|
|
522
|
+
def check_constraints(table_name) # :nodoc:
|
523
|
+
scope = quoted_scope(table_name)
|
524
|
+
|
525
|
+
check_info = exec_query(<<-SQL, "SCHEMA")
|
526
|
+
SELECT conname, pg_get_constraintdef(c.oid) AS constraintdef, c.convalidated AS valid
|
527
|
+
FROM pg_constraint c
|
528
|
+
JOIN pg_class t ON c.conrelid = t.oid
|
529
|
+
WHERE c.contype = 'c'
|
530
|
+
AND t.relname = #{scope[:name]}
|
531
|
+
SQL
|
532
|
+
|
533
|
+
check_info.map do |row|
|
534
|
+
options = {
|
535
|
+
name: row["conname"],
|
536
|
+
validate: row["valid"]
|
537
|
+
}
|
538
|
+
expression = row["constraintdef"][/CHECK \({2}(.+)\){2}/, 1]
|
539
|
+
|
540
|
+
CheckConstraintDefinition.new(table_name, expression, options)
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
519
544
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
520
545
|
def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
|
521
546
|
sql = \
|
@@ -552,13 +577,13 @@ module ActiveRecord
|
|
552
577
|
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
|
553
578
|
# requires that the ORDER BY include the distinct column.
|
554
579
|
def columns_for_distinct(columns, orders) #:nodoc:
|
555
|
-
order_columns = orders.
|
580
|
+
order_columns = orders.compact_blank.map { |s|
|
556
581
|
# Convert Arel node to string
|
557
582
|
s = visitor.compile(s) unless s.is_a?(String)
|
558
583
|
# Remove any ASC/DESC modifiers
|
559
584
|
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
|
560
585
|
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
|
561
|
-
}.
|
586
|
+
}.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
562
587
|
|
563
588
|
(order_columns << super).join(", ")
|
564
589
|
end
|
@@ -577,8 +602,6 @@ module ActiveRecord
|
|
577
602
|
#
|
578
603
|
# validate_constraint :accounts, :constraint_name
|
579
604
|
def validate_constraint(table_name, constraint_name)
|
580
|
-
return unless supports_validate_constraints?
|
581
|
-
|
582
605
|
at = create_alter_table table_name
|
583
606
|
at.validate_constraint constraint_name
|
584
607
|
|
@@ -601,20 +624,29 @@ module ActiveRecord
|
|
601
624
|
#
|
602
625
|
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key.
|
603
626
|
def validate_foreign_key(from_table, to_table = nil, **options)
|
604
|
-
return unless supports_validate_constraints?
|
605
|
-
|
606
627
|
fk_name_to_validate = foreign_key_for!(from_table, to_table: to_table, **options).name
|
607
628
|
|
608
629
|
validate_constraint from_table, fk_name_to_validate
|
609
630
|
end
|
610
631
|
|
632
|
+
# Validates the given check constraint.
|
633
|
+
#
|
634
|
+
# validate_check_constraint :products, name: "price_check"
|
635
|
+
#
|
636
|
+
# The +options+ hash accepts the same keys as add_check_constraint[rdoc-ref:ConnectionAdapters::SchemaStatements#add_check_constraint].
|
637
|
+
def validate_check_constraint(table_name, **options)
|
638
|
+
chk_name_to_validate = check_constraint_for!(table_name, **options).name
|
639
|
+
|
640
|
+
validate_constraint table_name, chk_name_to_validate
|
641
|
+
end
|
642
|
+
|
611
643
|
private
|
612
644
|
def schema_creation
|
613
645
|
PostgreSQL::SchemaCreation.new(self)
|
614
646
|
end
|
615
647
|
|
616
|
-
def create_table_definition(
|
617
|
-
PostgreSQL::TableDefinition.new(self,
|
648
|
+
def create_table_definition(name, **options)
|
649
|
+
PostgreSQL::TableDefinition.new(self, name, **options)
|
618
650
|
end
|
619
651
|
|
620
652
|
def create_alter_table(name)
|
@@ -684,7 +716,7 @@ module ActiveRecord
|
|
684
716
|
[super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
|
685
717
|
end
|
686
718
|
|
687
|
-
def change_column_for_alter(table_name, column_name, type, options
|
719
|
+
def change_column_for_alter(table_name, column_name, type, **options)
|
688
720
|
td = create_table_definition(table_name)
|
689
721
|
cd = td.new_column_definition(column_name, type, **options)
|
690
722
|
sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
|
@@ -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
|
@@ -176,6 +176,10 @@ module ActiveRecord
|
|
176
176
|
true
|
177
177
|
end
|
178
178
|
|
179
|
+
def supports_check_constraints?
|
180
|
+
true
|
181
|
+
end
|
182
|
+
|
179
183
|
def supports_validate_constraints?
|
180
184
|
true
|
181
185
|
end
|
@@ -341,11 +345,6 @@ module ActiveRecord
|
|
341
345
|
true
|
342
346
|
end
|
343
347
|
|
344
|
-
def supports_ranges?
|
345
|
-
true
|
346
|
-
end
|
347
|
-
deprecate :supports_ranges?
|
348
|
-
|
349
348
|
def supports_materialized_views?
|
350
349
|
true
|
351
350
|
end
|
@@ -426,16 +425,6 @@ module ActiveRecord
|
|
426
425
|
@use_insert_returning
|
427
426
|
end
|
428
427
|
|
429
|
-
def column_name_for_operation(operation, node) # :nodoc:
|
430
|
-
OPERATION_ALIASES.fetch(operation) { operation.downcase }
|
431
|
-
end
|
432
|
-
|
433
|
-
OPERATION_ALIASES = { # :nodoc:
|
434
|
-
"maximum" => "max",
|
435
|
-
"minimum" => "min",
|
436
|
-
"average" => "avg",
|
437
|
-
}
|
438
|
-
|
439
428
|
# Returns the version of the connected PostgreSQL server.
|
440
429
|
def get_database_version # :nodoc:
|
441
430
|
@connection.server_version
|
@@ -453,6 +442,7 @@ module ActiveRecord
|
|
453
442
|
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
454
443
|
elsif insert.update_duplicates?
|
455
444
|
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
445
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
|
456
446
|
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
457
447
|
end
|
458
448
|
|
@@ -475,6 +465,7 @@ module ActiveRecord
|
|
475
465
|
UNIQUE_VIOLATION = "23505"
|
476
466
|
SERIALIZATION_FAILURE = "40001"
|
477
467
|
DEADLOCK_DETECTED = "40P01"
|
468
|
+
DUPLICATE_DATABASE = "42P04"
|
478
469
|
LOCK_NOT_AVAILABLE = "55P03"
|
479
470
|
QUERY_CANCELED = "57014"
|
480
471
|
|
@@ -482,6 +473,12 @@ module ActiveRecord
|
|
482
473
|
return exception unless exception.respond_to?(:result)
|
483
474
|
|
484
475
|
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
476
|
+
when nil
|
477
|
+
if exception.message.match?(/connection is closed/i)
|
478
|
+
ConnectionNotEstablished.new(exception)
|
479
|
+
else
|
480
|
+
super
|
481
|
+
end
|
485
482
|
when UNIQUE_VIOLATION
|
486
483
|
RecordNotUnique.new(message, sql: sql, binds: binds)
|
487
484
|
when FOREIGN_KEY_VIOLATION
|
@@ -496,6 +493,8 @@ module ActiveRecord
|
|
496
493
|
SerializationFailure.new(message, sql: sql, binds: binds)
|
497
494
|
when DEADLOCK_DETECTED
|
498
495
|
Deadlocked.new(message, sql: sql, binds: binds)
|
496
|
+
when DUPLICATE_DATABASE
|
497
|
+
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
|
499
498
|
when LOCK_NOT_AVAILABLE
|
500
499
|
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
501
500
|
when QUERY_CANCELED
|
@@ -547,7 +546,7 @@ module ActiveRecord
|
|
547
546
|
m.register_type "uuid", OID::Uuid.new
|
548
547
|
m.register_type "xml", OID::Xml.new
|
549
548
|
m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
|
550
|
-
m.register_type "macaddr", OID::
|
549
|
+
m.register_type "macaddr", OID::Macaddr.new
|
551
550
|
m.register_type "citext", OID::SpecializedString.new(:citext)
|
552
551
|
m.register_type "ltree", OID::SpecializedString.new(:ltree)
|
553
552
|
m.register_type "line", OID::SpecializedString.new(:line)
|
@@ -557,11 +556,6 @@ module ActiveRecord
|
|
557
556
|
m.register_type "polygon", OID::SpecializedString.new(:polygon)
|
558
557
|
m.register_type "circle", OID::SpecializedString.new(:circle)
|
559
558
|
|
560
|
-
m.register_type "interval" do |_, _, sql_type|
|
561
|
-
precision = extract_precision(sql_type)
|
562
|
-
OID::SpecializedString.new(:interval, precision: precision)
|
563
|
-
end
|
564
|
-
|
565
559
|
register_class_with_precision m, "time", Type::Time
|
566
560
|
register_class_with_precision m, "timestamp", OID::DateTime
|
567
561
|
|
@@ -585,6 +579,11 @@ module ActiveRecord
|
|
585
579
|
end
|
586
580
|
end
|
587
581
|
|
582
|
+
m.register_type "interval" do |*args, sql_type|
|
583
|
+
precision = extract_precision(sql_type)
|
584
|
+
OID::Interval.new(precision: precision)
|
585
|
+
end
|
586
|
+
|
588
587
|
load_additional_types
|
589
588
|
end
|
590
589
|
|
@@ -650,20 +649,22 @@ module ActiveRecord
|
|
650
649
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
651
650
|
end
|
652
651
|
|
653
|
-
if without_prepared_statement?(binds)
|
654
|
-
result = exec_no_cache(sql, name, [])
|
655
|
-
elsif !prepare
|
652
|
+
if !prepare || without_prepared_statement?(binds)
|
656
653
|
result = exec_no_cache(sql, name, binds)
|
657
654
|
else
|
658
655
|
result = exec_cache(sql, name, binds)
|
659
656
|
end
|
660
|
-
|
661
|
-
|
657
|
+
begin
|
658
|
+
ret = yield result
|
659
|
+
ensure
|
660
|
+
result.clear
|
661
|
+
end
|
662
662
|
ret
|
663
663
|
end
|
664
664
|
|
665
665
|
def exec_no_cache(sql, name, binds)
|
666
666
|
materialize_transactions
|
667
|
+
mark_transaction_written_if_write(sql)
|
667
668
|
|
668
669
|
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
669
670
|
# made since we established the connection
|
@@ -679,6 +680,7 @@ module ActiveRecord
|
|
679
680
|
|
680
681
|
def exec_cache(sql, name, binds)
|
681
682
|
materialize_transactions
|
683
|
+
mark_transaction_written_if_write(sql)
|
682
684
|
update_typemap_for_default_timezone
|
683
685
|
|
684
686
|
stmt_key = prepare_statement(sql, binds)
|
@@ -714,11 +716,10 @@ module ActiveRecord
|
|
714
716
|
#
|
715
717
|
# Check here for more details:
|
716
718
|
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
717
|
-
CACHED_PLAN_HEURISTIC = "cached plan must not change result type"
|
718
719
|
def is_cached_plan_failure?(e)
|
719
720
|
pgerror = e.cause
|
720
|
-
|
721
|
-
|
721
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
|
722
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "RevalidateCachedQuery"
|
722
723
|
rescue
|
723
724
|
false
|
724
725
|
end
|
@@ -756,7 +757,7 @@ module ActiveRecord
|
|
756
757
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
757
758
|
# connected server's characteristics.
|
758
759
|
def connect
|
759
|
-
@connection =
|
760
|
+
@connection = self.class.new_client(@connection_parameters)
|
760
761
|
configure_connection
|
761
762
|
add_pg_encoders
|
762
763
|
add_pg_decoders
|
@@ -786,6 +787,9 @@ module ActiveRecord
|
|
786
787
|
end
|
787
788
|
end
|
788
789
|
|
790
|
+
# Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
|
791
|
+
execute("SET intervalstyle = iso_8601", "SCHEMA")
|
792
|
+
|
789
793
|
# SET statements from :variables config hash
|
790
794
|
# https://www.postgresql.org/docs/current/static/sql-set.html
|
791
795
|
variables.map do |k, v|
|
@@ -897,15 +901,12 @@ module ActiveRecord
|
|
897
901
|
"oid" => PG::TextDecoder::Integer,
|
898
902
|
"float4" => PG::TextDecoder::Float,
|
899
903
|
"float8" => PG::TextDecoder::Float,
|
904
|
+
"numeric" => PG::TextDecoder::Numeric,
|
900
905
|
"bool" => PG::TextDecoder::Boolean,
|
906
|
+
"timestamp" => PG::TextDecoder::TimestampUtc,
|
907
|
+
"timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
|
901
908
|
}
|
902
909
|
|
903
|
-
if defined?(PG::TextDecoder::TimestampUtc)
|
904
|
-
# Use native PG encoders available since pg-1.1
|
905
|
-
coders_by_name["timestamp"] = PG::TextDecoder::TimestampUtc
|
906
|
-
coders_by_name["timestamptz"] = PG::TextDecoder::TimestampWithTimeZone
|
907
|
-
end
|
908
|
-
|
909
910
|
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
910
911
|
query = <<~SQL % known_coder_types.join(", ")
|
911
912
|
SELECT t.oid, t.typname
|
@@ -922,6 +923,11 @@ module ActiveRecord
|
|
922
923
|
coders.each { |coder| map.add_coder(coder) }
|
923
924
|
@connection.type_map_for_results = map
|
924
925
|
|
926
|
+
@type_map_for_results = PG::TypeMapByOid.new
|
927
|
+
@type_map_for_results.default_type_map = map
|
928
|
+
@type_map_for_results.add_coder(PG::TextDecoder::Bytea.new(oid: 17, name: "bytea"))
|
929
|
+
@type_map_for_results.add_coder(MoneyDecoder.new(oid: 790, name: "money"))
|
930
|
+
|
925
931
|
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
926
932
|
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
927
933
|
update_typemap_for_default_timezone
|
@@ -932,6 +938,14 @@ module ActiveRecord
|
|
932
938
|
coder_class.new(oid: row["oid"].to_i, name: row["typname"])
|
933
939
|
end
|
934
940
|
|
941
|
+
class MoneyDecoder < PG::SimpleDecoder # :nodoc:
|
942
|
+
TYPE = OID::Money.new
|
943
|
+
|
944
|
+
def decode(value, tuple = nil, field = nil)
|
945
|
+
TYPE.deserialize(value)
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
935
949
|
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
936
950
|
ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
|
937
951
|
ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
|
@@ -944,6 +958,7 @@ module ActiveRecord
|
|
944
958
|
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
945
959
|
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
|
946
960
|
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
|
961
|
+
ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
|
947
962
|
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
|
948
963
|
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
|
949
964
|
ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
|