activerecord 6.0.0 → 6.1.0
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 +872 -582
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations.rb +116 -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 +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- 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 +36 -14
- 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 +32 -8
- 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 +86 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +4 -9
- 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 +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -76
- 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 +1 -1
- 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 +1 -1
- 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 +63 -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/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 +81 -57
- 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 +211 -81
- data/lib/active_record/core.rb +237 -69
- 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 +40 -16
- 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 +54 -11
- data/lib/active_record/gem_version.rb +1 -1
- 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 +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -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 +114 -84
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -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/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation.rb +108 -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 +55 -35
- 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 +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +340 -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 +104 -58
- 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 +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -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 +22 -71
- 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 +27 -24
- 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
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/duration"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module ConnectionAdapters
|
7
|
+
module PostgreSQL
|
8
|
+
module OID # :nodoc:
|
9
|
+
class Interval < Type::Value # :nodoc:
|
10
|
+
def type
|
11
|
+
:interval
|
12
|
+
end
|
13
|
+
|
14
|
+
def cast_value(value)
|
15
|
+
case value
|
16
|
+
when ::ActiveSupport::Duration
|
17
|
+
value
|
18
|
+
when ::String
|
19
|
+
begin
|
20
|
+
::ActiveSupport::Duration.parse(value)
|
21
|
+
rescue ::ActiveSupport::Duration::ISO8601Parser::ParsingError
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
else
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def serialize(value)
|
30
|
+
case value
|
31
|
+
when ::ActiveSupport::Duration
|
32
|
+
value.iso8601(precision: self.precision)
|
33
|
+
when ::Numeric
|
34
|
+
# Sometimes operations on Times returns just float number of seconds so we need to handle that.
|
35
|
+
# Example: Time.current - (Time.current + 1.hour) # => -3600.000001776 (Float)
|
36
|
+
value.seconds.iso8601(precision: self.precision)
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def type_cast_for_schema(value)
|
43
|
+
serialize(value).inspect
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
14
14
|
def cast(value)
|
15
15
|
case value
|
16
16
|
when ::String
|
17
|
-
if value
|
17
|
+
if value.start_with?("(") && value.end_with?(")")
|
18
18
|
value = value[1...-1]
|
19
19
|
end
|
20
20
|
cast(value.split(","))
|
@@ -34,9 +34,8 @@ module ActiveRecord
|
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
|
-
|
38
37
|
def number_for_point(number)
|
39
|
-
number.to_s.
|
38
|
+
number.to_s.delete_suffix(".0")
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module OID # :nodoc:
|
7
|
+
class Macaddr < Type::String # :nodoc:
|
8
|
+
def type
|
9
|
+
:macaddr
|
10
|
+
end
|
11
|
+
|
12
|
+
def changed?(old_value, new_value, _new_value_before_type_cast)
|
13
|
+
old_value.class != new_value.class ||
|
14
|
+
new_value && old_value.casecmp(new_value) != 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def changed_in_place?(raw_old_value, new_value)
|
18
|
+
raw_old_value.class != new_value.class ||
|
19
|
+
new_value && raw_old_value.casecmp(new_value) != 0
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -18,7 +18,7 @@ module ActiveRecord
|
|
18
18
|
when ::String
|
19
19
|
return if value.blank?
|
20
20
|
|
21
|
-
if value
|
21
|
+
if value.start_with?("(") && value.end_with?(")")
|
22
22
|
value = value[1...-1]
|
23
23
|
end
|
24
24
|
x, y = value.split(",")
|
@@ -50,9 +50,8 @@ module ActiveRecord
|
|
50
50
|
end
|
51
51
|
|
52
52
|
private
|
53
|
-
|
54
53
|
def number_for_point(number)
|
55
|
-
number.to_s.
|
54
|
+
number.to_s.delete_suffix(".0")
|
56
55
|
end
|
57
56
|
|
58
57
|
def build_point(x, y)
|
@@ -58,7 +58,6 @@ module ActiveRecord
|
|
58
58
|
end
|
59
59
|
|
60
60
|
private
|
61
|
-
|
62
61
|
def type_cast_single(value)
|
63
62
|
infinity?(value) ? value : @subtype.deserialize(value)
|
64
63
|
end
|
@@ -68,15 +67,34 @@ module ActiveRecord
|
|
68
67
|
end
|
69
68
|
|
70
69
|
def extract_bounds(value)
|
71
|
-
from, to = value[1..-2].split(",")
|
70
|
+
from, to = value[1..-2].split(",", 2)
|
72
71
|
{
|
73
|
-
from: (
|
74
|
-
to: (
|
75
|
-
exclude_start: (
|
76
|
-
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?(")")
|
77
76
|
}
|
78
77
|
end
|
79
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
|
+
|
80
98
|
def infinity(negative: false)
|
81
99
|
if subtype.respond_to?(:infinity)
|
82
100
|
subtype.infinity(negative: negative)
|
@@ -7,14 +7,23 @@ 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
|
-
|
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
|
17
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
|
+
|
26
|
+
private
|
18
27
|
def cast_value(value)
|
19
28
|
casted = value.to_s
|
20
29
|
casted if casted.match?(ACCEPTABLE_UUID)
|
@@ -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,9 +24,9 @@ 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
|
31
31
|
end
|
32
32
|
|
@@ -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,13 +13,17 @@ 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
|
19
23
|
|
20
24
|
def visit_ChangeColumnDefinition(o)
|
21
25
|
column = o.column
|
22
|
-
column.sql_type = type_to_sql(column.type, column.options)
|
26
|
+
column.sql_type = type_to_sql(column.type, **column.options)
|
23
27
|
quoted_column_name = quote_column_name(o.name)
|
24
28
|
|
25
29
|
change_column_sql = +"ALTER COLUMN #{quoted_column_name} TYPE #{column.sql_type}"
|
@@ -33,7 +37,7 @@ module ActiveRecord
|
|
33
37
|
if options[:using]
|
34
38
|
change_column_sql << " USING #{options[:using]}"
|
35
39
|
elsif options[:cast_as]
|
36
|
-
cast_as_type = type_to_sql(options[:cast_as], options)
|
40
|
+
cast_as_type = type_to_sql(options[:cast_as], **options)
|
37
41
|
change_column_sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
|
38
42
|
end
|
39
43
|
|
@@ -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
|
|
@@ -74,7 +75,7 @@ module ActiveRecord
|
|
74
75
|
INNER JOIN pg_index d ON t.oid = d.indrelid
|
75
76
|
INNER JOIN pg_class i ON d.indexrelid = i.oid
|
76
77
|
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
|
77
|
-
WHERE i.relkind
|
78
|
+
WHERE i.relkind IN ('i', 'I')
|
78
79
|
AND i.relname = #{index[:name]}
|
79
80
|
AND t.relname = #{table[:name]}
|
80
81
|
AND n.nspname = #{index[:schema]}
|
@@ -92,7 +93,7 @@ module ActiveRecord
|
|
92
93
|
INNER JOIN pg_index d ON t.oid = d.indrelid
|
93
94
|
INNER JOIN pg_class i ON d.indexrelid = i.oid
|
94
95
|
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
|
95
|
-
WHERE i.relkind
|
96
|
+
WHERE i.relkind IN ('i', 'I')
|
96
97
|
AND d.indisprimary = 'f'
|
97
98
|
AND t.relname = #{scope[:name]}
|
98
99
|
AND n.nspname = #{scope[:schema]}
|
@@ -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
|
@@ -390,15 +393,15 @@ module ActiveRecord
|
|
390
393
|
rename_table_indexes(table_name, new_name)
|
391
394
|
end
|
392
395
|
|
393
|
-
def add_column(table_name, column_name, type, options
|
396
|
+
def add_column(table_name, column_name, type, **options) #:nodoc:
|
394
397
|
clear_cache!
|
395
398
|
super
|
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.
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
580
|
+
order_columns = orders.compact_blank.map { |s|
|
581
|
+
# Convert Arel node to string
|
582
|
+
s = visitor.compile(s) unless s.is_a?(String)
|
583
|
+
# Remove any ASC/DESC modifiers
|
584
|
+
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
|
585
|
+
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
|
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)
|
@@ -679,14 +711,14 @@ module ActiveRecord
|
|
679
711
|
end
|
680
712
|
end
|
681
713
|
|
682
|
-
def add_column_for_alter(table_name, column_name, type, options
|
714
|
+
def add_column_for_alter(table_name, column_name, type, **options)
|
683
715
|
return super unless options.key?(:comment)
|
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
|
-
cd = td.new_column_definition(column_name, type, options)
|
721
|
+
cd = td.new_column_definition(column_name, type, **options)
|
690
722
|
sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
|
691
723
|
sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
|
692
724
|
sqls
|
@@ -711,20 +743,6 @@ module ActiveRecord
|
|
711
743
|
"ALTER COLUMN #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
|
712
744
|
end
|
713
745
|
|
714
|
-
def add_timestamps_for_alter(table_name, options = {})
|
715
|
-
options[:null] = false if options[:null].nil?
|
716
|
-
|
717
|
-
if !options.key?(:precision) && supports_datetime_with_precision?
|
718
|
-
options[:precision] = 6
|
719
|
-
end
|
720
|
-
|
721
|
-
[add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
|
722
|
-
end
|
723
|
-
|
724
|
-
def remove_timestamps_for_alter(table_name, options = {})
|
725
|
-
[remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
|
726
|
-
end
|
727
|
-
|
728
746
|
def add_index_opclass(quoted_columns, **options)
|
729
747
|
opclasses = options_for_index_columns(options[:opclass])
|
730
748
|
quoted_columns.each do |name, column|
|
@@ -733,7 +751,7 @@ module ActiveRecord
|
|
733
751
|
end
|
734
752
|
|
735
753
|
def add_options_for_index_columns(quoted_columns, **options)
|
736
|
-
quoted_columns = add_index_opclass(quoted_columns, options)
|
754
|
+
quoted_columns = add_index_opclass(quoted_columns, **options)
|
737
755
|
super
|
738
756
|
end
|
739
757
|
|