activerecord 5.0.7.2 → 5.1.0.beta1
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 +5 -5
- data/CHANGELOG.md +389 -2252
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record.rb +20 -20
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations.rb +1579 -1569
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +23 -15
- data/lib/active_record/associations/association_scope.rb +83 -81
- data/lib/active_record/associations/belongs_to_association.rb +0 -1
- data/lib/active_record/associations/builder/belongs_to.rb +16 -14
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +74 -241
- data/lib/active_record/associations/collection_proxy.rb +144 -70
- data/lib/active_record/associations/has_many_association.rb +15 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -5
- data/lib/active_record/associations/has_one_association.rb +22 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency.rb +117 -115
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -13
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/preloader/association.rb +87 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +34 -41
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +3 -6
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +216 -34
- data/lib/active_record/attribute_methods/primary_key.rb +78 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +36 -30
- data/lib/active_record/attribute_mutation_tracker.rb +53 -10
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attribute_set/builder.rb +41 -49
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attributes.rb +21 -21
- data/lib/active_record/autosave_association.rb +13 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +52 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +6 -17
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +320 -278
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -34
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -57
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +78 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +99 -93
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +156 -128
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +424 -382
- data/lib/active_record/connection_adapters/column.rb +27 -5
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -43
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +49 -31
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +5 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -26
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -35
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +9 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +28 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +38 -36
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +161 -170
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +179 -152
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -20
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +187 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +110 -93
- data/lib/active_record/counter_cache.rb +62 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +58 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +64 -56
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +29 -29
- data/lib/active_record/migration.rb +155 -172
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +76 -37
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/model_schema.rb +85 -119
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +10 -33
- data/lib/active_record/persistence.rb +45 -38
- data/lib/active_record/query_cache.rb +4 -8
- data/lib/active_record/querying.rb +2 -3
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +125 -140
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +79 -96
- data/lib/active_record/relation.rb +72 -115
- data/lib/active_record/relation/batches.rb +87 -58
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/calculations.rb +154 -160
- data/lib/active_record/relation/delegation.rb +30 -29
- data/lib/active_record/relation/finder_methods.rb +195 -226
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +247 -295
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +79 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/result.rb +29 -31
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +182 -197
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +14 -37
- data/lib/active_record/schema_migration.rb +3 -3
- data/lib/active_record/scoping.rb +9 -10
- data/lib/active_record/scoping/default.rb +87 -91
- data/lib/active_record/scoping/named.rb +16 -28
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +72 -65
- data/lib/active_record/tasks/mysql_database_tasks.rb +75 -72
- data/lib/active_record/tasks/postgresql_database_tasks.rb +53 -48
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +98 -110
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +9 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/serialized.rb +8 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record.rb +4 -4
- data/lib/rails/generators/active_record/migration.rb +2 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- metadata +22 -13
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/core_ext/string/filters"
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Integration
|
@@ -11,13 +11,13 @@ module ActiveRecord
|
|
11
11
|
# Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
|
12
12
|
#
|
13
13
|
# This is +:usec+, by default.
|
14
|
-
class_attribute :cache_timestamp_format, :
|
14
|
+
class_attribute :cache_timestamp_format, instance_writer: false
|
15
15
|
self.cache_timestamp_format = :usec
|
16
16
|
end
|
17
17
|
|
18
|
-
# Returns a String
|
19
|
-
# object. The default implementation returns this record's id as a String
|
20
|
-
# or nil if this record's unsaved.
|
18
|
+
# Returns a +String+, which Action Pack uses for constructing a URL to this
|
19
|
+
# object. The default implementation returns this record's id as a +String+,
|
20
|
+
# or +nil+ if this record's unsaved.
|
21
21
|
#
|
22
22
|
# For example, suppose that you have a User model, and that you have a
|
23
23
|
# <tt>resources :users</tt> route. Normally, +user_path+ will
|
@@ -89,7 +89,7 @@ module ActiveRecord
|
|
89
89
|
#
|
90
90
|
# user = User.find_by(name: 'David Heinemeier Hansson')
|
91
91
|
# user.id # => 125
|
92
|
-
# user_path(user) # => "/users/125-david"
|
92
|
+
# user_path(user) # => "/users/125-david-heinemeier"
|
93
93
|
#
|
94
94
|
# Because the generated param begins with the record's +id+, it is
|
95
95
|
# suitable for passing to +find+. In a controller, for example:
|
@@ -103,7 +103,7 @@ module ActiveRecord
|
|
103
103
|
define_method :to_param do
|
104
104
|
if (default = super()) &&
|
105
105
|
(result = send(method_name).to_s).present? &&
|
106
|
-
(param = result.squish.truncate(20, separator:
|
106
|
+
(param = result.squish.parameterize.truncate(20, separator: /-/, omission: "")).present?
|
107
107
|
"#{default}-#{param}"
|
108
108
|
else
|
109
109
|
default
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "active_record/scoping/default"
|
2
|
+
require "active_record/scoping/named"
|
3
3
|
|
4
4
|
module ActiveRecord
|
5
5
|
# This class is used to create a table that keeps track of values and keys such
|
@@ -14,10 +14,6 @@ module ActiveRecord
|
|
14
14
|
"#{table_name_prefix}#{ActiveRecord::Base.internal_metadata_table_name}#{table_name_suffix}"
|
15
15
|
end
|
16
16
|
|
17
|
-
def original_table_name
|
18
|
-
"#{table_name_prefix}active_record_internal_metadatas#{table_name_suffix}"
|
19
|
-
end
|
20
|
-
|
21
17
|
def []=(key, value)
|
22
18
|
find_or_initialize_by(key: key).update_attributes!(value: value)
|
23
19
|
end
|
@@ -27,20 +23,11 @@ module ActiveRecord
|
|
27
23
|
end
|
28
24
|
|
29
25
|
def table_exists?
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
def original_table_exists?
|
34
|
-
# This method will be removed in Rails 5.1
|
35
|
-
# Since it is only necessary when `active_record_internal_metadatas` could exist
|
36
|
-
ActiveSupport::Deprecation.silence { connection.table_exists?(original_table_name) }
|
26
|
+
connection.table_exists?(table_name)
|
37
27
|
end
|
38
28
|
|
39
29
|
# Creates an internal metadata table with columns +key+ and +value+
|
40
30
|
def create_table
|
41
|
-
if original_table_exists?
|
42
|
-
connection.rename_table(original_table_name, table_name)
|
43
|
-
end
|
44
31
|
unless table_exists?
|
45
32
|
key_options = connection.internal_string_options_for_primary_key
|
46
33
|
|
@@ -47,6 +47,8 @@ module ActiveRecord
|
|
47
47
|
# self.locking_column = :lock_person
|
48
48
|
# end
|
49
49
|
#
|
50
|
+
# Please note that the optimistic locking will be ignored if you update the
|
51
|
+
# locking column's value.
|
50
52
|
module Optimistic
|
51
53
|
extend ActiveSupport::Concern
|
52
54
|
|
@@ -60,13 +62,14 @@ module ActiveRecord
|
|
60
62
|
end
|
61
63
|
|
62
64
|
private
|
65
|
+
|
63
66
|
def increment_lock
|
64
67
|
lock_col = self.class.locking_column
|
65
68
|
previous_lock_value = send(lock_col).to_i
|
66
|
-
send(lock_col +
|
69
|
+
send(lock_col + "=", previous_lock_value + 1)
|
67
70
|
end
|
68
71
|
|
69
|
-
def _create_record(attribute_names = self.attribute_names, *)
|
72
|
+
def _create_record(attribute_names = self.attribute_names, *)
|
70
73
|
if locking_enabled?
|
71
74
|
# We always want to persist the locking version, even if we don't detect
|
72
75
|
# a change from the default, since the database might have no default
|
@@ -75,23 +78,26 @@ module ActiveRecord
|
|
75
78
|
super
|
76
79
|
end
|
77
80
|
|
78
|
-
def _update_record(attribute_names = self.attribute_names)
|
81
|
+
def _update_record(attribute_names = self.attribute_names)
|
79
82
|
return super unless locking_enabled?
|
80
|
-
return 0 if attribute_names.empty?
|
81
83
|
|
82
84
|
lock_col = self.class.locking_column
|
83
|
-
previous_lock_value = send(lock_col).to_i
|
84
|
-
increment_lock
|
85
85
|
|
86
|
-
|
87
|
-
attribute_names.
|
86
|
+
return super if attribute_names.include?(lock_col)
|
87
|
+
return 0 if attribute_names.empty?
|
88
88
|
|
89
89
|
begin
|
90
|
+
previous_lock_value = read_attribute_before_type_cast(lock_col)
|
91
|
+
|
92
|
+
increment_lock
|
93
|
+
|
94
|
+
attribute_names.push(lock_col)
|
95
|
+
|
90
96
|
relation = self.class.unscoped
|
91
97
|
|
92
98
|
affected_rows = relation.where(
|
93
99
|
self.class.primary_key => id,
|
94
|
-
lock_col => previous_lock_value
|
100
|
+
lock_col => previous_lock_value
|
95
101
|
).update_all(
|
96
102
|
attributes_for_update(attribute_names).map do |name|
|
97
103
|
[name, _read_attribute(name)]
|
@@ -104,9 +110,9 @@ module ActiveRecord
|
|
104
110
|
|
105
111
|
affected_rows
|
106
112
|
|
107
|
-
# If something went wrong, revert the
|
113
|
+
# If something went wrong, revert the locking_column value.
|
108
114
|
rescue Exception
|
109
|
-
send(lock_col +
|
115
|
+
send(lock_col + "=", previous_lock_value.to_i)
|
110
116
|
raise
|
111
117
|
end
|
112
118
|
end
|
@@ -132,61 +138,63 @@ module ActiveRecord
|
|
132
138
|
relation
|
133
139
|
end
|
134
140
|
|
135
|
-
|
136
|
-
|
141
|
+
module ClassMethods
|
142
|
+
DEFAULT_LOCKING_COLUMN = "lock_version"
|
137
143
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
+
# Returns true if the +lock_optimistically+ flag is set to true
|
145
|
+
# (which it is, by default) and the table includes the
|
146
|
+
# +locking_column+ column (defaults to +lock_version+).
|
147
|
+
def locking_enabled?
|
148
|
+
lock_optimistically && columns_hash[locking_column]
|
149
|
+
end
|
144
150
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
151
|
+
# Set the column to use for optimistic locking. Defaults to +lock_version+.
|
152
|
+
def locking_column=(value)
|
153
|
+
reload_schema_from_cache
|
154
|
+
@locking_column = value.to_s
|
155
|
+
end
|
150
156
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
157
|
+
# The version column used for optimistic locking. Defaults to +lock_version+.
|
158
|
+
def locking_column
|
159
|
+
@locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column)
|
160
|
+
@locking_column
|
161
|
+
end
|
156
162
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
163
|
+
# Reset the column used for optimistic locking back to the +lock_version+ default.
|
164
|
+
def reset_locking_column
|
165
|
+
self.locking_column = DEFAULT_LOCKING_COLUMN
|
166
|
+
end
|
161
167
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
+
# Make sure the lock version column gets updated when counters are
|
169
|
+
# updated.
|
170
|
+
def update_counters(id, counters)
|
171
|
+
counters = counters.merge(locking_column => 1) if locking_enabled?
|
172
|
+
super
|
173
|
+
end
|
168
174
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
175
|
+
private
|
176
|
+
|
177
|
+
# We need to apply this decorator here, rather than on module inclusion. The closure
|
178
|
+
# created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
|
179
|
+
# sub class being decorated. As such, changes to `lock_optimistically`, or
|
180
|
+
# `locking_column` would not be picked up.
|
181
|
+
def inherited(subclass)
|
182
|
+
subclass.class_eval do
|
183
|
+
is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
|
184
|
+
decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type|
|
185
|
+
LockingType.new(type)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
super
|
180
189
|
end
|
181
|
-
end
|
182
|
-
super
|
183
190
|
end
|
184
|
-
end
|
185
191
|
end
|
186
192
|
|
193
|
+
# In de/serialize we change `nil` to 0, so that we can allow passing
|
194
|
+
# `nil` values to `lock_version`, and not result in `ActiveRecord::StaleObjectError`
|
195
|
+
# during update record.
|
187
196
|
class LockingType < DelegateClass(Type::Value) # :nodoc:
|
188
197
|
def deserialize(value)
|
189
|
-
# `nil` *should* be changed to 0
|
190
198
|
super.to_i
|
191
199
|
end
|
192
200
|
|
@@ -195,11 +203,11 @@ module ActiveRecord
|
|
195
203
|
end
|
196
204
|
|
197
205
|
def init_with(coder)
|
198
|
-
__setobj__(coder[
|
206
|
+
__setobj__(coder["subtype"])
|
199
207
|
end
|
200
208
|
|
201
209
|
def encode_with(coder)
|
202
|
-
coder[
|
210
|
+
coder["subtype"] = __getobj__
|
203
211
|
end
|
204
212
|
end
|
205
213
|
end
|
@@ -59,7 +59,16 @@ module ActiveRecord
|
|
59
59
|
# or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
|
60
60
|
# the locked record.
|
61
61
|
def lock!(lock = true)
|
62
|
-
|
62
|
+
if persisted?
|
63
|
+
if changed?
|
64
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
65
|
+
Locking a record with unpersisted changes is deprecated and will raise an
|
66
|
+
exception in Rails 5.2. Use `save` to persist the changes, or `reload` to
|
67
|
+
discard them explicitly.
|
68
|
+
MSG
|
69
|
+
end
|
70
|
+
reload(lock: lock)
|
71
|
+
end
|
63
72
|
self
|
64
73
|
end
|
65
74
|
|
@@ -15,11 +15,6 @@ module ActiveRecord
|
|
15
15
|
rt
|
16
16
|
end
|
17
17
|
|
18
|
-
def initialize
|
19
|
-
super
|
20
|
-
@odd = false
|
21
|
-
end
|
22
|
-
|
23
18
|
def sql(event)
|
24
19
|
self.class.runtime += event.duration
|
25
20
|
return unless logger.debug?
|
@@ -29,11 +24,12 @@ module ActiveRecord
|
|
29
24
|
return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
|
30
25
|
|
31
26
|
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
27
|
+
name = "CACHE #{name}" if payload[:cached]
|
32
28
|
sql = payload[:sql]
|
33
29
|
binds = nil
|
34
30
|
|
35
31
|
unless (payload[:binds] || []).empty?
|
36
|
-
casted_params = type_casted_binds(payload[:type_casted_binds])
|
32
|
+
casted_params = type_casted_binds(payload[:binds], payload[:type_casted_binds])
|
37
33
|
binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
|
38
34
|
render_bind(attr, value)
|
39
35
|
}.inspect
|
@@ -47,30 +43,30 @@ module ActiveRecord
|
|
47
43
|
|
48
44
|
private
|
49
45
|
|
50
|
-
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
def render_bind(attr, value)
|
55
|
-
if attr.is_a?(Array)
|
56
|
-
attr = attr.first
|
57
|
-
elsif attr.type.binary? && attr.value
|
58
|
-
value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
46
|
+
def type_casted_binds(binds, casted_binds)
|
47
|
+
casted_binds || binds.map { |attr| type_cast attr.value_for_database }
|
59
48
|
end
|
60
49
|
|
61
|
-
|
62
|
-
|
50
|
+
def render_bind(attr, type_casted_value)
|
51
|
+
value = if attr.type.binary? && attr.value
|
52
|
+
"<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
53
|
+
else
|
54
|
+
type_casted_value
|
55
|
+
end
|
63
56
|
|
64
|
-
|
65
|
-
if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
|
66
|
-
color(name, MAGENTA, true)
|
67
|
-
else
|
68
|
-
color(name, CYAN, true)
|
57
|
+
[attr.name, value]
|
69
58
|
end
|
70
|
-
end
|
71
59
|
|
72
|
-
|
73
|
-
|
60
|
+
def colorize_payload_name(name, payload_name)
|
61
|
+
if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
|
62
|
+
color(name, MAGENTA, true)
|
63
|
+
else
|
64
|
+
color(name, CYAN, true)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def sql_color(sql)
|
69
|
+
case sql
|
74
70
|
when /\A\s*rollback/mi
|
75
71
|
RED
|
76
72
|
when /select .*for update/mi, /\A\s*lock/mi
|
@@ -87,12 +83,16 @@ module ActiveRecord
|
|
87
83
|
CYAN
|
88
84
|
else
|
89
85
|
MAGENTA
|
86
|
+
end
|
90
87
|
end
|
91
|
-
end
|
92
88
|
|
93
|
-
|
94
|
-
|
95
|
-
|
89
|
+
def logger
|
90
|
+
ActiveRecord::Base.logger
|
91
|
+
end
|
92
|
+
|
93
|
+
def type_cast(value)
|
94
|
+
ActiveRecord::Base.connection.type_cast(value)
|
95
|
+
end
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
@@ -277,8 +277,10 @@ module ActiveRecord
|
|
277
277
|
#
|
278
278
|
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
|
279
279
|
# the column to a different type using the same parameters as add_column.
|
280
|
-
# * <tt>change_column_default(table_name, column_name,
|
281
|
-
# default value for +column_name+ defined by +
|
280
|
+
# * <tt>change_column_default(table_name, column_name, default_or_changes)</tt>:
|
281
|
+
# Sets a default value for +column_name+ defined by +default_or_changes+ on
|
282
|
+
# +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
|
283
|
+
# as +default_or_changes+ will make this change reversible in the migration.
|
282
284
|
# * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
|
283
285
|
# Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
|
284
286
|
# indicates whether the value can be +NULL+. See
|
@@ -510,8 +512,8 @@ module ActiveRecord
|
|
510
512
|
# Remember that you can still open your own transactions, even if you
|
511
513
|
# are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
|
512
514
|
class Migration
|
513
|
-
autoload :CommandRecorder,
|
514
|
-
autoload :Compatibility,
|
515
|
+
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
516
|
+
autoload :Compatibility, "active_record/migration/compatibility"
|
515
517
|
|
516
518
|
# This must be defined before the inherited hook, below
|
517
519
|
class Current < Migration # :nodoc:
|
@@ -520,7 +522,10 @@ module ActiveRecord
|
|
520
522
|
def self.inherited(subclass) # :nodoc:
|
521
523
|
super
|
522
524
|
if subclass.superclass == Migration
|
523
|
-
|
525
|
+
raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
|
526
|
+
"Please specify the Rails release the migration was written for:\n" \
|
527
|
+
"\n" \
|
528
|
+
" class #{subclass} < ActiveRecord::Migration[4.2]"
|
524
529
|
end
|
525
530
|
end
|
526
531
|
|
@@ -555,9 +560,9 @@ module ActiveRecord
|
|
555
560
|
|
556
561
|
private
|
557
562
|
|
558
|
-
|
559
|
-
|
560
|
-
|
563
|
+
def connection
|
564
|
+
ActiveRecord::Base.connection
|
565
|
+
end
|
561
566
|
end
|
562
567
|
|
563
568
|
class << self
|
@@ -687,7 +692,7 @@ module ActiveRecord
|
|
687
692
|
connection.respond_to?(:reverting) && connection.reverting
|
688
693
|
end
|
689
694
|
|
690
|
-
|
695
|
+
ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
|
691
696
|
def up
|
692
697
|
yield unless reverting
|
693
698
|
end
|
@@ -725,7 +730,7 @@ module ActiveRecord
|
|
725
730
|
# end
|
726
731
|
def reversible
|
727
732
|
helper = ReversibleBlockHelper.new(reverting?)
|
728
|
-
execute_block{ yield helper }
|
733
|
+
execute_block { yield helper }
|
729
734
|
end
|
730
735
|
|
731
736
|
# Runs the given migration classes.
|
@@ -767,7 +772,7 @@ module ActiveRecord
|
|
767
772
|
when :down then announce "reverting"
|
768
773
|
end
|
769
774
|
|
770
|
-
time
|
775
|
+
time = nil
|
771
776
|
ActiveRecord::Base.connection_pool.with_connection do |conn|
|
772
777
|
time = Benchmark.measure do
|
773
778
|
exec_migration(conn, direction)
|
@@ -795,7 +800,7 @@ module ActiveRecord
|
|
795
800
|
@connection = nil
|
796
801
|
end
|
797
802
|
|
798
|
-
def write(text="")
|
803
|
+
def write(text = "")
|
799
804
|
puts(text) if verbose
|
800
805
|
end
|
801
806
|
|
@@ -805,7 +810,7 @@ module ActiveRecord
|
|
805
810
|
write "== %s %s" % [text, "=" * length]
|
806
811
|
end
|
807
812
|
|
808
|
-
def say(message, subitem=false)
|
813
|
+
def say(message, subitem = false)
|
809
814
|
write "#{subitem ? " ->" : "--"} #{message}"
|
810
815
|
end
|
811
816
|
|
@@ -830,7 +835,7 @@ module ActiveRecord
|
|
830
835
|
end
|
831
836
|
|
832
837
|
def method_missing(method, *arguments, &block)
|
833
|
-
arg_list = arguments.map(&:inspect) *
|
838
|
+
arg_list = arguments.map(&:inspect) * ", "
|
834
839
|
|
835
840
|
say_with_time "#{method}(#{arg_list})" do
|
836
841
|
unless connection.respond_to? :revert
|
@@ -922,19 +927,18 @@ module ActiveRecord
|
|
922
927
|
end
|
923
928
|
|
924
929
|
private
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
+
def execute_block
|
931
|
+
if connection.respond_to? :execute_block
|
932
|
+
super # use normal delegation to record the block
|
933
|
+
else
|
934
|
+
yield
|
935
|
+
end
|
930
936
|
end
|
931
|
-
end
|
932
937
|
end
|
933
938
|
|
934
939
|
# MigrationProxy is used to defer loading of the actual migration classes
|
935
940
|
# until they are needed
|
936
|
-
|
937
|
-
|
941
|
+
MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
|
938
942
|
def initialize(name, version, filename, scope)
|
939
943
|
super
|
940
944
|
@migration = nil
|
@@ -960,7 +964,6 @@ module ActiveRecord
|
|
960
964
|
require(File.expand_path(filename))
|
961
965
|
name.constantize.new(name, version)
|
962
966
|
end
|
963
|
-
|
964
967
|
end
|
965
968
|
|
966
969
|
class NullMigration < MigrationProxy #:nodoc:
|
@@ -991,11 +994,11 @@ module ActiveRecord
|
|
991
994
|
end
|
992
995
|
end
|
993
996
|
|
994
|
-
def rollback(migrations_paths, steps=1)
|
997
|
+
def rollback(migrations_paths, steps = 1)
|
995
998
|
move(:down, migrations_paths, steps)
|
996
999
|
end
|
997
1000
|
|
998
|
-
def forward(migrations_paths, steps=1)
|
1001
|
+
def forward(migrations_paths, steps = 1)
|
999
1002
|
move(:up, migrations_paths, steps)
|
1000
1003
|
end
|
1001
1004
|
|
@@ -1026,12 +1029,10 @@ module ActiveRecord
|
|
1026
1029
|
end
|
1027
1030
|
|
1028
1031
|
def get_all_versions(connection = Base.connection)
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
[]
|
1034
|
-
end
|
1032
|
+
if connection.table_exists?(schema_migrations_table_name)
|
1033
|
+
SchemaMigration.all.map { |x| x.version.to_i }.sort
|
1034
|
+
else
|
1035
|
+
[]
|
1035
1036
|
end
|
1036
1037
|
end
|
1037
1038
|
|
@@ -1052,11 +1053,15 @@ module ActiveRecord
|
|
1052
1053
|
end
|
1053
1054
|
|
1054
1055
|
def migrations_paths
|
1055
|
-
@migrations_paths ||= [
|
1056
|
+
@migrations_paths ||= ["db/migrate"]
|
1056
1057
|
# just to not break things if someone uses: migrations_path = some_string
|
1057
1058
|
Array(@migrations_paths)
|
1058
1059
|
end
|
1059
1060
|
|
1061
|
+
def match_to_migration_filename?(filename) # :nodoc:
|
1062
|
+
Migration::MigrationFilenameRegexp.match?(File.basename(filename))
|
1063
|
+
end
|
1064
|
+
|
1060
1065
|
def parse_migration_filename(filename) # :nodoc:
|
1061
1066
|
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1062
1067
|
end
|
@@ -1064,7 +1069,9 @@ module ActiveRecord
|
|
1064
1069
|
def migrations(paths)
|
1065
1070
|
paths = Array(paths)
|
1066
1071
|
|
1067
|
-
|
1072
|
+
files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
|
1073
|
+
|
1074
|
+
migrations = files.map do |file|
|
1068
1075
|
version, name, scope = parse_migration_filename(file)
|
1069
1076
|
raise IllegalMigrationNameError.new(file) unless version
|
1070
1077
|
version = version.to_i
|
@@ -1076,30 +1083,6 @@ module ActiveRecord
|
|
1076
1083
|
migrations.sort_by(&:version)
|
1077
1084
|
end
|
1078
1085
|
|
1079
|
-
def migrations_status(paths)
|
1080
|
-
paths = Array(paths)
|
1081
|
-
|
1082
|
-
db_list = ActiveRecord::SchemaMigration.normalized_versions
|
1083
|
-
|
1084
|
-
file_list = migration_files(paths).map do |file|
|
1085
|
-
version, name, scope = parse_migration_filename(file)
|
1086
|
-
raise IllegalMigrationNameError.new(file) unless version
|
1087
|
-
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
|
1088
|
-
status = db_list.delete(version) ? "up" : "down"
|
1089
|
-
[status, version, (name + scope).humanize]
|
1090
|
-
end.compact
|
1091
|
-
|
1092
|
-
db_list.map! do |version|
|
1093
|
-
["up", version, "********** NO FILE **********"]
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
(db_list + file_list).sort_by { |_, version, _| version }
|
1097
|
-
end
|
1098
|
-
|
1099
|
-
def migration_files(paths)
|
1100
|
-
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1101
|
-
end
|
1102
|
-
|
1103
1086
|
private
|
1104
1087
|
|
1105
1088
|
def move(direction, migrations_paths, steps)
|
@@ -1124,8 +1107,8 @@ module ActiveRecord
|
|
1124
1107
|
|
1125
1108
|
validate(@migrations)
|
1126
1109
|
|
1127
|
-
|
1128
|
-
|
1110
|
+
ActiveRecord::SchemaMigration.create_table
|
1111
|
+
ActiveRecord::InternalMetadata.create_table
|
1129
1112
|
end
|
1130
1113
|
|
1131
1114
|
def current_version
|
@@ -1183,148 +1166,148 @@ module ActiveRecord
|
|
1183
1166
|
|
1184
1167
|
private
|
1185
1168
|
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1169
|
+
# Used for running a specific migration.
|
1170
|
+
def run_without_lock
|
1171
|
+
migration = migrations.detect { |m| m.version == @target_version }
|
1172
|
+
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1173
|
+
result = execute_migration_in_transaction(migration, @direction)
|
1191
1174
|
|
1192
|
-
|
1193
|
-
|
1194
|
-
end
|
1195
|
-
|
1196
|
-
# Used for running multiple migrations up to or down to a certain value.
|
1197
|
-
def migrate_without_lock
|
1198
|
-
if invalid_target?
|
1199
|
-
raise UnknownMigrationVersionError.new(@target_version)
|
1175
|
+
record_environment
|
1176
|
+
result
|
1200
1177
|
end
|
1201
1178
|
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1179
|
+
# Used for running multiple migrations up to or down to a certain value.
|
1180
|
+
def migrate_without_lock
|
1181
|
+
if invalid_target?
|
1182
|
+
raise UnknownMigrationVersionError.new(@target_version)
|
1183
|
+
end
|
1205
1184
|
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1185
|
+
result = runnable.each do |migration|
|
1186
|
+
execute_migration_in_transaction(migration, @direction)
|
1187
|
+
end
|
1209
1188
|
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
|
1214
|
-
end
|
1189
|
+
record_environment
|
1190
|
+
result
|
1191
|
+
end
|
1215
1192
|
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1193
|
+
# Stores the current environment in the database.
|
1194
|
+
def record_environment
|
1195
|
+
return if down?
|
1196
|
+
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
|
1197
|
+
end
|
1219
1198
|
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
end
|
1199
|
+
def ran?(migration)
|
1200
|
+
migrated.include?(migration.version.to_i)
|
1201
|
+
end
|
1224
1202
|
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1203
|
+
# Return true if a valid version is not provided.
|
1204
|
+
def invalid_target?
|
1205
|
+
!target && @target_version && @target_version > 0
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
def execute_migration_in_transaction(migration, direction)
|
1209
|
+
return if down? && !migrated.include?(migration.version.to_i)
|
1210
|
+
return if up? && migrated.include?(migration.version.to_i)
|
1228
1211
|
|
1229
|
-
|
1212
|
+
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
1230
1213
|
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1214
|
+
ddl_transaction(migration) do
|
1215
|
+
migration.migrate(direction)
|
1216
|
+
record_version_state_after_migrating(migration.version)
|
1217
|
+
end
|
1218
|
+
rescue => e
|
1219
|
+
msg = "An error has occurred, "
|
1220
|
+
msg << "this and " if use_transaction?(migration)
|
1221
|
+
msg << "all later migrations canceled:\n\n#{e}"
|
1222
|
+
raise StandardError, msg, e.backtrace
|
1234
1223
|
end
|
1235
|
-
rescue => e
|
1236
|
-
msg = "An error has occurred, "
|
1237
|
-
msg << "this and " if use_transaction?(migration)
|
1238
|
-
msg << "all later migrations canceled:\n\n#{e}"
|
1239
|
-
raise StandardError, msg, e.backtrace
|
1240
|
-
end
|
1241
1224
|
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1225
|
+
def target
|
1226
|
+
migrations.detect { |m| m.version == @target_version }
|
1227
|
+
end
|
1245
1228
|
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1229
|
+
def finish
|
1230
|
+
migrations.index(target) || migrations.size - 1
|
1231
|
+
end
|
1249
1232
|
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1233
|
+
def start
|
1234
|
+
up? ? 0 : (migrations.index(current) || 0)
|
1235
|
+
end
|
1253
1236
|
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1237
|
+
def validate(migrations)
|
1238
|
+
name , = migrations.group_by(&:name).find { |_, v| v.length > 1 }
|
1239
|
+
raise DuplicateMigrationNameError.new(name) if name
|
1257
1240
|
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1241
|
+
version , = migrations.group_by(&:version).find { |_, v| v.length > 1 }
|
1242
|
+
raise DuplicateMigrationVersionError.new(version) if version
|
1243
|
+
end
|
1261
1244
|
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1245
|
+
def record_version_state_after_migrating(version)
|
1246
|
+
if down?
|
1247
|
+
migrated.delete(version)
|
1248
|
+
ActiveRecord::SchemaMigration.where(version: version.to_s).delete_all
|
1249
|
+
else
|
1250
|
+
migrated << version
|
1251
|
+
ActiveRecord::SchemaMigration.create!(version: version.to_s)
|
1252
|
+
end
|
1269
1253
|
end
|
1270
|
-
end
|
1271
1254
|
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1255
|
+
def self.last_stored_environment
|
1256
|
+
return nil if current_version == 0
|
1257
|
+
raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
|
1275
1258
|
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1259
|
+
environment = ActiveRecord::InternalMetadata[:environment]
|
1260
|
+
raise NoEnvironmentInSchemaError unless environment
|
1261
|
+
environment
|
1262
|
+
end
|
1280
1263
|
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1264
|
+
def self.current_environment
|
1265
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1266
|
+
end
|
1284
1267
|
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1268
|
+
def self.protected_environment?
|
1269
|
+
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
|
1270
|
+
end
|
1288
1271
|
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1272
|
+
def up?
|
1273
|
+
@direction == :up
|
1274
|
+
end
|
1292
1275
|
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1276
|
+
def down?
|
1277
|
+
@direction == :down
|
1278
|
+
end
|
1296
1279
|
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1280
|
+
# Wrap the migration in a transaction only if supported by the adapter.
|
1281
|
+
def ddl_transaction(migration)
|
1282
|
+
if use_transaction?(migration)
|
1283
|
+
Base.transaction { yield }
|
1284
|
+
else
|
1285
|
+
yield
|
1286
|
+
end
|
1303
1287
|
end
|
1304
|
-
end
|
1305
1288
|
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1289
|
+
def use_transaction?(migration)
|
1290
|
+
!migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
|
1291
|
+
end
|
1309
1292
|
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1293
|
+
def use_advisory_lock?
|
1294
|
+
Base.connection.supports_advisory_locks?
|
1295
|
+
end
|
1313
1296
|
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1297
|
+
def with_advisory_lock
|
1298
|
+
lock_id = generate_migrator_advisory_lock_id
|
1299
|
+
got_lock = Base.connection.get_advisory_lock(lock_id)
|
1300
|
+
raise ConcurrentMigrationError unless got_lock
|
1301
|
+
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1302
|
+
yield
|
1303
|
+
ensure
|
1304
|
+
Base.connection.release_advisory_lock(lock_id) if got_lock
|
1305
|
+
end
|
1323
1306
|
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1307
|
+
MIGRATOR_SALT = 2053462845
|
1308
|
+
def generate_migrator_advisory_lock_id
|
1309
|
+
db_name_hash = Zlib.crc32(Base.connection.current_database)
|
1310
|
+
MIGRATOR_SALT * db_name_hash
|
1311
|
+
end
|
1329
1312
|
end
|
1330
1313
|
end
|