activerecord 6.0.0.beta3 → 6.0.0.rc1
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 +286 -6
- data/README.rdoc +3 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/associations.rb +3 -2
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_proxy.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/preloader.rb +11 -6
- data/lib/active_record/associations/preloader/association.rb +32 -30
- data/lib/active_record/associations/preloader/through_association.rb +48 -28
- data/lib/active_record/attribute_methods.rb +4 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +42 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +13 -3
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +84 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +10 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +70 -14
- data/lib/active_record/connection_adapters/abstract_adapter.rb +56 -11
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -69
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +6 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -27
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +50 -112
- data/lib/active_record/connection_handling.rb +17 -10
- data/lib/active_record/core.rb +15 -20
- data/lib/active_record/database_configurations.rb +14 -14
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +12 -12
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +6 -0
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +180 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration.rb +25 -18
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +10 -0
- data/lib/active_record/persistence.rb +206 -13
- data/lib/active_record/querying.rb +17 -12
- data/lib/active_record/railties/databases.rake +68 -6
- data/lib/active_record/reflection.rb +2 -2
- data/lib/active_record/relation.rb +98 -20
- data/lib/active_record/relation/calculations.rb +39 -39
- data/lib/active_record/relation/delegation.rb +22 -30
- data/lib/active_record/relation/finder_methods.rb +3 -9
- data/lib/active_record/relation/merger.rb +7 -16
- data/lib/active_record/relation/query_methods.rb +153 -38
- data/lib/active_record/relation/where_clause.rb +9 -5
- data/lib/active_record/sanitization.rb +3 -2
- data/lib/active_record/schema_dumper.rb +5 -0
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +3 -3
- data/lib/active_record/tasks/database_tasks.rb +36 -1
- data/lib/active_record/touch_later.rb +2 -2
- data/lib/active_record/transactions.rb +52 -41
- data/lib/active_record/validations/uniqueness.rb +3 -5
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +6 -1
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +87 -108
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +12 -11
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -29,9 +29,7 @@ module ActiveRecord
|
|
29
29
|
# <tt>reload</tt> the record and clears changed attributes.
|
30
30
|
def reload(*)
|
31
31
|
super.tap do
|
32
|
-
@previously_changed = ActiveSupport::HashWithIndifferentAccess.new
|
33
32
|
@mutations_before_last_save = nil
|
34
|
-
@attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
|
35
33
|
@mutations_from_database = nil
|
36
34
|
end
|
37
35
|
end
|
@@ -51,7 +49,7 @@ module ActiveRecord
|
|
51
49
|
# +to+ When passed, this method will return false unless the value was
|
52
50
|
# changed to the given value
|
53
51
|
def saved_change_to_attribute?(attr_name, **options)
|
54
|
-
mutations_before_last_save.changed?(attr_name,
|
52
|
+
mutations_before_last_save.changed?(attr_name.to_s, options)
|
55
53
|
end
|
56
54
|
|
57
55
|
# Returns the change to an attribute during the last save. If the
|
@@ -63,7 +61,7 @@ module ActiveRecord
|
|
63
61
|
# invoked as +saved_change_to_name+ instead of
|
64
62
|
# <tt>saved_change_to_attribute("name")</tt>.
|
65
63
|
def saved_change_to_attribute(attr_name)
|
66
|
-
mutations_before_last_save.change_to_attribute(attr_name)
|
64
|
+
mutations_before_last_save.change_to_attribute(attr_name.to_s)
|
67
65
|
end
|
68
66
|
|
69
67
|
# Returns the original value of an attribute before the last save.
|
@@ -73,7 +71,7 @@ module ActiveRecord
|
|
73
71
|
# invoked as +name_before_last_save+ instead of
|
74
72
|
# <tt>attribute_before_last_save("name")</tt>.
|
75
73
|
def attribute_before_last_save(attr_name)
|
76
|
-
mutations_before_last_save.original_value(attr_name)
|
74
|
+
mutations_before_last_save.original_value(attr_name.to_s)
|
77
75
|
end
|
78
76
|
|
79
77
|
# Did the last call to +save+ have any changes to change?
|
@@ -101,7 +99,7 @@ module ActiveRecord
|
|
101
99
|
# +to+ When passed, this method will return false unless the value will be
|
102
100
|
# changed to the given value
|
103
101
|
def will_save_change_to_attribute?(attr_name, **options)
|
104
|
-
mutations_from_database.changed?(attr_name,
|
102
|
+
mutations_from_database.changed?(attr_name.to_s, options)
|
105
103
|
end
|
106
104
|
|
107
105
|
# Returns the change to an attribute that will be persisted during the
|
@@ -115,7 +113,7 @@ module ActiveRecord
|
|
115
113
|
# If the attribute will change, the result will be an array containing the
|
116
114
|
# original value and the new value about to be saved.
|
117
115
|
def attribute_change_to_be_saved(attr_name)
|
118
|
-
mutations_from_database.change_to_attribute(attr_name)
|
116
|
+
mutations_from_database.change_to_attribute(attr_name.to_s)
|
119
117
|
end
|
120
118
|
|
121
119
|
# Returns the value of an attribute in the database, as opposed to the
|
@@ -127,7 +125,7 @@ module ActiveRecord
|
|
127
125
|
# saved. It can be invoked as +name_in_database+ instead of
|
128
126
|
# <tt>attribute_in_database("name")</tt>.
|
129
127
|
def attribute_in_database(attr_name)
|
130
|
-
mutations_from_database.original_value(attr_name)
|
128
|
+
mutations_from_database.original_value(attr_name.to_s)
|
131
129
|
end
|
132
130
|
|
133
131
|
# Will the next call to +save+ have any changes to persist?
|
@@ -158,16 +156,46 @@ module ActiveRecord
|
|
158
156
|
end
|
159
157
|
|
160
158
|
private
|
159
|
+
def mutations_from_database
|
160
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
161
|
+
super
|
162
|
+
end
|
163
|
+
|
164
|
+
def mutations_before_last_save
|
165
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
166
|
+
super
|
167
|
+
end
|
168
|
+
|
161
169
|
def write_attribute_without_type_cast(attr_name, value)
|
162
|
-
|
163
|
-
|
164
|
-
name = self.class.attribute_alias(name)
|
165
|
-
end
|
166
|
-
result = super(name, value)
|
167
|
-
clear_attribute_change(name)
|
170
|
+
result = super
|
171
|
+
clear_attribute_change(attr_name)
|
168
172
|
result
|
169
173
|
end
|
170
174
|
|
175
|
+
def _touch_row(attribute_names, time)
|
176
|
+
@_touch_attr_names = Set.new(attribute_names)
|
177
|
+
|
178
|
+
affected_rows = super
|
179
|
+
|
180
|
+
changes = {}
|
181
|
+
@attributes.keys.each do |attr_name|
|
182
|
+
next if @_touch_attr_names.include?(attr_name)
|
183
|
+
|
184
|
+
if attribute_changed?(attr_name)
|
185
|
+
changes[attr_name] = _read_attribute(attr_name)
|
186
|
+
_write_attribute(attr_name, attribute_was(attr_name))
|
187
|
+
clear_attribute_change(attr_name)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
changes_applied
|
192
|
+
changes.each { |attr_name, value| _write_attribute(attr_name, value) }
|
193
|
+
|
194
|
+
affected_rows
|
195
|
+
ensure
|
196
|
+
@_touch_attr_names = nil
|
197
|
+
end
|
198
|
+
|
171
199
|
def _update_record(attribute_names = attribute_names_for_partial_writes)
|
172
200
|
affected_rows = super
|
173
201
|
changes_applied
|
@@ -16,40 +16,32 @@ module ActiveRecord
|
|
16
16
|
|
17
17
|
# Returns the primary key column's value.
|
18
18
|
def id
|
19
|
-
|
20
|
-
primary_key = self.class.primary_key
|
21
|
-
_read_attribute(primary_key) if primary_key
|
19
|
+
_read_attribute(@primary_key)
|
22
20
|
end
|
23
21
|
|
24
22
|
# Sets the primary key column's value.
|
25
23
|
def id=(value)
|
26
|
-
|
27
|
-
primary_key = self.class.primary_key
|
28
|
-
_write_attribute(primary_key, value) if primary_key
|
24
|
+
_write_attribute(@primary_key, value)
|
29
25
|
end
|
30
26
|
|
31
27
|
# Queries the primary key column's value.
|
32
28
|
def id?
|
33
|
-
|
34
|
-
query_attribute(self.class.primary_key)
|
29
|
+
query_attribute(@primary_key)
|
35
30
|
end
|
36
31
|
|
37
32
|
# Returns the primary key column's value before type cast.
|
38
33
|
def id_before_type_cast
|
39
|
-
|
40
|
-
read_attribute_before_type_cast(self.class.primary_key)
|
34
|
+
read_attribute_before_type_cast(@primary_key)
|
41
35
|
end
|
42
36
|
|
43
37
|
# Returns the primary key column's previous value.
|
44
38
|
def id_was
|
45
|
-
|
46
|
-
attribute_was(self.class.primary_key)
|
39
|
+
attribute_was(@primary_key)
|
47
40
|
end
|
48
41
|
|
49
42
|
# Returns the primary key column's value from the database.
|
50
43
|
def id_in_database
|
51
|
-
|
52
|
-
attribute_in_database(self.class.primary_key)
|
44
|
+
attribute_in_database(@primary_key)
|
53
45
|
end
|
54
46
|
|
55
47
|
private
|
@@ -122,7 +114,7 @@ module ActiveRecord
|
|
122
114
|
#
|
123
115
|
# Project.primary_key # => "foo_id"
|
124
116
|
def primary_key=(value)
|
125
|
-
@primary_key = value && value.to_s
|
117
|
+
@primary_key = value && -value.to_s
|
126
118
|
@quoted_primary_key = nil
|
127
119
|
@attributes_builder = nil
|
128
120
|
end
|
@@ -16,8 +16,7 @@ module ActiveRecord
|
|
16
16
|
when true then true
|
17
17
|
when false, nil then false
|
18
18
|
else
|
19
|
-
|
20
|
-
if column.nil?
|
19
|
+
if !type_for_attribute(attr_name) { false }
|
21
20
|
if Numeric === value || value !~ /[^0-9]/
|
22
21
|
!value.to_i.zero?
|
23
22
|
else
|
@@ -33,7 +32,7 @@ module ActiveRecord
|
|
33
32
|
end
|
34
33
|
|
35
34
|
private
|
36
|
-
#
|
35
|
+
# Dispatch target for <tt>*?</tt> attribute methods.
|
37
36
|
def attribute?(attribute_name)
|
38
37
|
query_attribute(attribute_name)
|
39
38
|
end
|
@@ -9,14 +9,11 @@ module ActiveRecord
|
|
9
9
|
private
|
10
10
|
|
11
11
|
def define_method_attribute(name)
|
12
|
-
sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
|
13
|
-
|
14
12
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
15
13
|
generated_attribute_methods, name
|
16
14
|
) do |temp_method_name, attr_name_expr|
|
17
15
|
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
18
16
|
def #{temp_method_name}
|
19
|
-
#{sync_with_transaction_state}
|
20
17
|
name = #{attr_name_expr}
|
21
18
|
_read_attribute(name) { |n| missing_attribute(n, caller) }
|
22
19
|
end
|
@@ -30,19 +27,16 @@ module ActiveRecord
|
|
30
27
|
# to a date object, like Date.new(2004, 12, 12)).
|
31
28
|
def read_attribute(attr_name, &block)
|
32
29
|
name = attr_name.to_s
|
33
|
-
|
34
|
-
name = self.class.attribute_alias(name)
|
35
|
-
end
|
30
|
+
name = self.class.attribute_aliases[name] || name
|
36
31
|
|
37
|
-
|
38
|
-
name = primary_key if name == "id" && primary_key
|
39
|
-
sync_with_transaction_state if name == primary_key
|
32
|
+
name = @primary_key if name == "id" && @primary_key
|
40
33
|
_read_attribute(name, &block)
|
41
34
|
end
|
42
35
|
|
43
36
|
# This method exists to avoid the expensive primary_key check internally, without
|
44
37
|
# breaking compatibility with the read_attribute API
|
45
38
|
def _read_attribute(attr_name, &block) # :nodoc
|
39
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
46
40
|
@attributes.fetch_value(attr_name.to_s, &block)
|
47
41
|
end
|
48
42
|
|
@@ -13,15 +13,12 @@ module ActiveRecord
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def define_method_attribute=(name)
|
16
|
-
sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
|
17
|
-
|
18
16
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
19
17
|
generated_attribute_methods, name, writer: true,
|
20
18
|
) do |temp_method_name, attr_name_expr|
|
21
19
|
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
22
20
|
def #{temp_method_name}(value)
|
23
21
|
name = #{attr_name_expr}
|
24
|
-
#{sync_with_transaction_state}
|
25
22
|
_write_attribute(name, value)
|
26
23
|
end
|
27
24
|
RUBY
|
@@ -34,31 +31,28 @@ module ActiveRecord
|
|
34
31
|
# turned into +nil+.
|
35
32
|
def write_attribute(attr_name, value)
|
36
33
|
name = attr_name.to_s
|
37
|
-
|
38
|
-
name = self.class.attribute_alias(name)
|
39
|
-
end
|
34
|
+
name = self.class.attribute_aliases[name] || name
|
40
35
|
|
41
|
-
|
42
|
-
name = primary_key if name == "id" && primary_key
|
43
|
-
sync_with_transaction_state if name == primary_key
|
36
|
+
name = @primary_key if name == "id" && @primary_key
|
44
37
|
_write_attribute(name, value)
|
45
38
|
end
|
46
39
|
|
47
40
|
# This method exists to avoid the expensive primary_key check internally, without
|
48
41
|
# breaking compatibility with the write_attribute API
|
49
42
|
def _write_attribute(attr_name, value) # :nodoc:
|
43
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
50
44
|
@attributes.write_from_user(attr_name.to_s, value)
|
51
45
|
value
|
52
46
|
end
|
53
47
|
|
54
48
|
private
|
55
49
|
def write_attribute_without_type_cast(attr_name, value)
|
56
|
-
|
57
|
-
@attributes.write_cast_value(
|
50
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
51
|
+
@attributes.write_cast_value(attr_name.to_s, value)
|
58
52
|
value
|
59
53
|
end
|
60
54
|
|
61
|
-
#
|
55
|
+
# Dispatch target for <tt>*=</tt> attribute methods.
|
62
56
|
def attribute=(attribute_name, value)
|
63
57
|
_write_attribute(attribute_name, value)
|
64
58
|
end
|
@@ -41,6 +41,9 @@ module ActiveRecord
|
|
41
41
|
# +range+ (PostgreSQL only) specifies that the type should be a range (see the
|
42
42
|
# examples below).
|
43
43
|
#
|
44
|
+
# When using a symbol for +cast_type+, extra options are forwarded to the
|
45
|
+
# constructor of the type object.
|
46
|
+
#
|
44
47
|
# ==== Examples
|
45
48
|
#
|
46
49
|
# The type detected by Active Record can be overridden.
|
@@ -112,6 +115,16 @@ module ActiveRecord
|
|
112
115
|
# my_float_range: 1.0..3.5
|
113
116
|
# }
|
114
117
|
#
|
118
|
+
# Passing options to the type constructor
|
119
|
+
#
|
120
|
+
# # app/models/my_model.rb
|
121
|
+
# class MyModel < ActiveRecord::Base
|
122
|
+
# attribute :small_int, :integer, limit: 2
|
123
|
+
# end
|
124
|
+
#
|
125
|
+
# MyModel.create(small_int: 65537)
|
126
|
+
# # => Error: 65537 is out of range for the limit of two bytes
|
127
|
+
#
|
115
128
|
# ==== Creating Custom Types
|
116
129
|
#
|
117
130
|
# Users may also define their own custom types, as long as they respond
|
@@ -382,10 +382,14 @@ module ActiveRecord
|
|
382
382
|
if association = association_instance_get(reflection.name)
|
383
383
|
autosave = reflection.options[:autosave]
|
384
384
|
|
385
|
+
# By saving the instance variable in a local variable,
|
386
|
+
# we make the whole callback re-entrant.
|
387
|
+
new_record_before_save = @new_record_before_save
|
388
|
+
|
385
389
|
# reconstruct the scope now that we know the owner's id
|
386
390
|
association.reset_scope
|
387
391
|
|
388
|
-
if records = associated_records_to_validate_or_save(association,
|
392
|
+
if records = associated_records_to_validate_or_save(association, new_record_before_save, autosave)
|
389
393
|
if autosave
|
390
394
|
records_to_destroy = records.select(&:marked_for_destruction?)
|
391
395
|
records_to_destroy.each { |record| association.destroy(record) }
|
@@ -397,7 +401,7 @@ module ActiveRecord
|
|
397
401
|
|
398
402
|
saved = true
|
399
403
|
|
400
|
-
if autosave != false && (
|
404
|
+
if autosave != false && (new_record_before_save || record.new_record?)
|
401
405
|
if autosave
|
402
406
|
saved = association.insert_record(record, false)
|
403
407
|
elsif !reflection.nested?
|
@@ -457,10 +461,16 @@ module ActiveRecord
|
|
457
461
|
# If the record is new or it has changed, returns true.
|
458
462
|
def record_changed?(reflection, record, key)
|
459
463
|
record.new_record? ||
|
460
|
-
|
464
|
+
association_foreign_key_changed?(reflection, record, key) ||
|
461
465
|
record.will_save_change_to_attribute?(reflection.foreign_key)
|
462
466
|
end
|
463
467
|
|
468
|
+
def association_foreign_key_changed?(reflection, record, key)
|
469
|
+
return false if reflection.through_reflection?
|
470
|
+
|
471
|
+
record.has_attribute?(reflection.foreign_key) && record[reflection.foreign_key] != key
|
472
|
+
end
|
473
|
+
|
464
474
|
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
465
475
|
#
|
466
476
|
# In addition, it will destroy the association if it was marked for destruction.
|
data/lib/active_record/base.rb
CHANGED
@@ -5,20 +5,24 @@ require "active_support/deprecation"
|
|
5
5
|
module ActiveRecord
|
6
6
|
module ConnectionAdapters # :nodoc:
|
7
7
|
module DatabaseLimits
|
8
|
+
def max_identifier_length # :nodoc:
|
9
|
+
64
|
10
|
+
end
|
11
|
+
|
8
12
|
# Returns the maximum length of a table alias.
|
9
13
|
def table_alias_length
|
10
|
-
|
14
|
+
max_identifier_length
|
11
15
|
end
|
12
16
|
|
13
17
|
# Returns the maximum length of a column name.
|
14
18
|
def column_name_length
|
15
|
-
|
19
|
+
max_identifier_length
|
16
20
|
end
|
17
21
|
deprecate :column_name_length
|
18
22
|
|
19
23
|
# Returns the maximum length of a table name.
|
20
24
|
def table_name_length
|
21
|
-
|
25
|
+
max_identifier_length
|
22
26
|
end
|
23
27
|
deprecate :table_name_length
|
24
28
|
|
@@ -33,7 +37,7 @@ module ActiveRecord
|
|
33
37
|
|
34
38
|
# Returns the maximum length of an index name.
|
35
39
|
def index_name_length
|
36
|
-
|
40
|
+
max_identifier_length
|
37
41
|
end
|
38
42
|
|
39
43
|
# Returns the maximum number of columns per table.
|
@@ -131,7 +131,7 @@ module ActiveRecord
|
|
131
131
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
132
132
|
# the executed +sql+ statement.
|
133
133
|
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
134
|
-
sql, binds = sql_for_insert(sql, pk,
|
134
|
+
sql, binds = sql_for_insert(sql, pk, binds)
|
135
135
|
exec_query(sql, name, binds)
|
136
136
|
end
|
137
137
|
|
@@ -142,11 +142,6 @@ module ActiveRecord
|
|
142
142
|
exec_query(sql, name, binds)
|
143
143
|
end
|
144
144
|
|
145
|
-
# Executes the truncate statement.
|
146
|
-
def truncate(table_name, name = nil)
|
147
|
-
raise NotImplementedError
|
148
|
-
end
|
149
|
-
|
150
145
|
# Executes update +sql+ statement in the context of this connection using
|
151
146
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
152
147
|
# the executed +sql+ statement.
|
@@ -181,6 +176,23 @@ module ActiveRecord
|
|
181
176
|
exec_delete(sql, name, binds)
|
182
177
|
end
|
183
178
|
|
179
|
+
# Executes the truncate statement.
|
180
|
+
def truncate(table_name, name = nil)
|
181
|
+
execute(build_truncate_statements(table_name), name)
|
182
|
+
end
|
183
|
+
|
184
|
+
def truncate_tables(*table_names) # :nodoc:
|
185
|
+
return if table_names.empty?
|
186
|
+
|
187
|
+
with_multi_statements do
|
188
|
+
disable_referential_integrity do
|
189
|
+
Array(build_truncate_statements(*table_names)).each do |sql|
|
190
|
+
execute_batch(sql, "Truncate Tables")
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
184
196
|
# Runs the given block in a database transaction, and returns the result
|
185
197
|
# of the block.
|
186
198
|
#
|
@@ -341,46 +353,20 @@ module ActiveRecord
|
|
341
353
|
# We keep this method to provide fallback
|
342
354
|
# for databases like sqlite that do not support bulk inserts.
|
343
355
|
def insert_fixture(fixture, table_name)
|
344
|
-
fixture
|
345
|
-
|
346
|
-
columns = schema_cache.columns_hash(table_name)
|
347
|
-
binds = fixture.map do |name, value|
|
348
|
-
if column = columns[name]
|
349
|
-
type = lookup_cast_type_from_column(column)
|
350
|
-
Relation::QueryAttribute.new(name, value, type)
|
351
|
-
else
|
352
|
-
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
table = Arel::Table.new(table_name)
|
357
|
-
|
358
|
-
values = binds.map do |bind|
|
359
|
-
value = with_yaml_fallback(bind.value_for_database)
|
360
|
-
[table[bind.name], value]
|
361
|
-
end
|
362
|
-
|
363
|
-
manager = Arel::InsertManager.new
|
364
|
-
manager.into(table)
|
365
|
-
manager.insert(values)
|
366
|
-
execute manager.to_sql, "Fixture Insert"
|
356
|
+
execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
|
367
357
|
end
|
368
358
|
|
369
359
|
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
370
|
-
fixture_inserts = fixture_set
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
transaction(requires_new: true) do
|
381
|
-
total_sql.each do |sql|
|
382
|
-
execute sql, "Fixtures Load"
|
383
|
-
yield if block_given?
|
360
|
+
fixture_inserts = build_fixture_statements(fixture_set)
|
361
|
+
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
|
362
|
+
total_sql = Array(combine_multi_statements(table_deletes + fixture_inserts))
|
363
|
+
|
364
|
+
with_multi_statements do
|
365
|
+
disable_referential_integrity do
|
366
|
+
transaction(requires_new: true) do
|
367
|
+
total_sql.each do |sql|
|
368
|
+
execute_batch(sql, "Fixtures Load")
|
369
|
+
end
|
384
370
|
end
|
385
371
|
end
|
386
372
|
end
|
@@ -404,15 +390,33 @@ module ActiveRecord
|
|
404
390
|
end
|
405
391
|
end
|
406
392
|
|
393
|
+
# Fixture value is quoted by Arel, however scalar values
|
394
|
+
# are not quotable. In this case we want to convert
|
395
|
+
# the column value to YAML.
|
396
|
+
def with_yaml_fallback(value) # :nodoc:
|
397
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
398
|
+
YAML.dump(value)
|
399
|
+
else
|
400
|
+
value
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
407
404
|
private
|
405
|
+
def execute_batch(sql, name = nil)
|
406
|
+
execute(sql, name)
|
407
|
+
end
|
408
|
+
|
409
|
+
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
|
410
|
+
private_constant :DEFAULT_INSERT_VALUE
|
411
|
+
|
408
412
|
def default_insert_value(column)
|
409
|
-
|
413
|
+
DEFAULT_INSERT_VALUE
|
410
414
|
end
|
411
415
|
|
412
416
|
def build_fixture_sql(fixtures, table_name)
|
413
417
|
columns = schema_cache.columns_hash(table_name)
|
414
418
|
|
415
|
-
|
419
|
+
values_list = fixtures.map do |fixture|
|
416
420
|
fixture = fixture.stringify_keys
|
417
421
|
|
418
422
|
unknown_columns = fixture.keys - columns.keys
|
@@ -423,8 +427,7 @@ module ActiveRecord
|
|
423
427
|
columns.map do |name, column|
|
424
428
|
if fixture.key?(name)
|
425
429
|
type = lookup_cast_type_from_column(column)
|
426
|
-
|
427
|
-
with_yaml_fallback(bind.value_for_database)
|
430
|
+
with_yaml_fallback(type.serialize(fixture[name]))
|
428
431
|
else
|
429
432
|
default_insert_value(column)
|
430
433
|
end
|
@@ -434,12 +437,43 @@ module ActiveRecord
|
|
434
437
|
table = Arel::Table.new(table_name)
|
435
438
|
manager = Arel::InsertManager.new
|
436
439
|
manager.into(table)
|
437
|
-
columns.each_key { |column| manager.columns << table[column] }
|
438
|
-
manager.values = manager.create_values_list(values)
|
439
440
|
|
441
|
+
if values_list.size == 1
|
442
|
+
values = values_list.shift
|
443
|
+
new_values = []
|
444
|
+
columns.each_key.with_index { |column, i|
|
445
|
+
unless values[i].equal?(DEFAULT_INSERT_VALUE)
|
446
|
+
new_values << values[i]
|
447
|
+
manager.columns << table[column]
|
448
|
+
end
|
449
|
+
}
|
450
|
+
values_list << new_values
|
451
|
+
else
|
452
|
+
columns.each_key { |column| manager.columns << table[column] }
|
453
|
+
end
|
454
|
+
|
455
|
+
manager.values = manager.create_values_list(values_list)
|
440
456
|
manager.to_sql
|
441
457
|
end
|
442
458
|
|
459
|
+
def build_fixture_statements(fixture_set)
|
460
|
+
fixture_set.map do |table_name, fixtures|
|
461
|
+
next if fixtures.empty?
|
462
|
+
build_fixture_sql(fixtures, table_name)
|
463
|
+
end.compact
|
464
|
+
end
|
465
|
+
|
466
|
+
def build_truncate_statements(*table_names)
|
467
|
+
truncate_tables = table_names.map do |table_name|
|
468
|
+
"TRUNCATE TABLE #{quote_table_name(table_name)}"
|
469
|
+
end
|
470
|
+
combine_multi_statements(truncate_tables)
|
471
|
+
end
|
472
|
+
|
473
|
+
def with_multi_statements
|
474
|
+
yield
|
475
|
+
end
|
476
|
+
|
443
477
|
def combine_multi_statements(total_sql)
|
444
478
|
total_sql.join(";\n")
|
445
479
|
end
|
@@ -453,7 +487,7 @@ module ActiveRecord
|
|
453
487
|
exec_query(sql, name, binds, prepare: true)
|
454
488
|
end
|
455
489
|
|
456
|
-
def sql_for_insert(sql, pk,
|
490
|
+
def sql_for_insert(sql, pk, binds)
|
457
491
|
[sql, binds]
|
458
492
|
end
|
459
493
|
|
@@ -473,17 +507,6 @@ module ActiveRecord
|
|
473
507
|
relation
|
474
508
|
end
|
475
509
|
end
|
476
|
-
|
477
|
-
# Fixture value is quoted by Arel, however scalar values
|
478
|
-
# are not quotable. In this case we want to convert
|
479
|
-
# the column value to YAML.
|
480
|
-
def with_yaml_fallback(value)
|
481
|
-
if value.is_a?(Hash) || value.is_a?(Array)
|
482
|
-
YAML.dump(value)
|
483
|
-
else
|
484
|
-
value
|
485
|
-
end
|
486
|
-
end
|
487
510
|
end
|
488
511
|
end
|
489
512
|
end
|