activerecord 5.1.5 → 5.2.1
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 +450 -699
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +4 -2
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +33 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +14 -5
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +52 -41
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +3 -1
- data/lib/active_record/associations/has_many_through_association.rb +8 -19
- data/lib/active_record/associations/has_one_association.rb +12 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +22 -67
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/join_dependency.rb +48 -93
- data/lib/active_record/associations/preloader/association.rb +45 -61
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +40 -63
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +25 -214
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +21 -9
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +16 -14
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +12 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +149 -78
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
- data/lib/active_record/connection_adapters/column.rb +3 -1
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -112
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +20 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +79 -92
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +39 -60
- data/lib/active_record/counter_cache.rb +20 -15
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +17 -13
- data/lib/active_record/errors.rb +42 -3
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +30 -42
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +43 -0
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +40 -2
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/model_schema.rb +19 -24
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +196 -48
- data/lib/active_record/query_cache.rb +12 -14
- data/lib/active_record/querying.rb +3 -1
- data/lib/active_record/railtie.rb +61 -3
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +46 -36
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +110 -192
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/calculations.rb +31 -9
- data/lib/active_record/relation/delegation.rb +15 -27
- data/lib/active_record/relation/finder_methods.rb +71 -76
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +47 -20
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +55 -79
- data/lib/active_record/relation/query_attribute.rb +26 -2
- data/lib/active_record/relation/query_methods.rb +95 -91
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -1
- data/lib/active_record/relation/where_clause.rb +65 -68
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +106 -219
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +21 -7
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +22 -12
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +25 -14
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +32 -27
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +6 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +36 -6
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +23 -36
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -114
- data/lib/active_record/attribute_set/builder.rb +0 -124
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
5
|
module DatabaseStatements
|
@@ -7,30 +9,43 @@ module ActiveRecord
|
|
7
9
|
end
|
8
10
|
|
9
11
|
# Converts an arel AST to SQL
|
10
|
-
def to_sql(
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
def to_sql(arel_or_sql_string, binds = [])
|
13
|
+
sql, _ = to_sql_and_binds(arel_or_sql_string, binds)
|
14
|
+
sql
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_sql_and_binds(arel_or_sql_string, binds = []) # :nodoc:
|
18
|
+
if arel_or_sql_string.respond_to?(:ast)
|
19
|
+
unless binds.empty?
|
20
|
+
raise "Passing bind parameters with an arel AST is forbidden. " \
|
21
|
+
"The values must be stored on the AST directly"
|
22
|
+
end
|
23
|
+
sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
|
24
|
+
[sql.freeze, binds || []]
|
14
25
|
else
|
15
|
-
|
26
|
+
[arel_or_sql_string.dup.freeze, binds]
|
16
27
|
end
|
17
28
|
end
|
29
|
+
private :to_sql_and_binds
|
18
30
|
|
19
31
|
# This is used in the StatementCache object. It returns an object that
|
20
32
|
# can be used to query the database repeatedly.
|
21
33
|
def cacheable_query(klass, arel) # :nodoc:
|
22
|
-
collected = visitor.accept(arel.ast, collector)
|
23
34
|
if prepared_statements
|
24
|
-
|
35
|
+
sql, binds = visitor.accept(arel.ast, collector).value
|
36
|
+
query = klass.query(sql)
|
25
37
|
else
|
26
|
-
|
38
|
+
collector = PartialQueryCollector.new
|
39
|
+
parts, binds = visitor.accept(arel.ast, collector).value
|
40
|
+
query = klass.partial_query(parts)
|
27
41
|
end
|
42
|
+
[query, binds]
|
28
43
|
end
|
29
44
|
|
30
45
|
# Returns an ActiveRecord::Result instance.
|
31
46
|
def select_all(arel, name = nil, binds = [], preparable: nil)
|
32
|
-
arel
|
33
|
-
sql =
|
47
|
+
arel = arel_from_relation(arel)
|
48
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
34
49
|
if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
|
35
50
|
preparable = false
|
36
51
|
else
|
@@ -130,26 +145,30 @@ module ActiveRecord
|
|
130
145
|
# If the next id was calculated in advance (as in Oracle), it should be
|
131
146
|
# passed in as +id_value+.
|
132
147
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
133
|
-
|
148
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
149
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
134
150
|
id_value || last_inserted_id(value)
|
135
151
|
end
|
136
152
|
alias create insert
|
137
153
|
|
138
154
|
# Executes the update statement and returns the number of rows affected.
|
139
155
|
def update(arel, name = nil, binds = [])
|
140
|
-
|
156
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
157
|
+
exec_update(sql, name, binds)
|
141
158
|
end
|
142
159
|
|
143
160
|
# Executes the delete statement and returns the number of rows affected.
|
144
161
|
def delete(arel, name = nil, binds = [])
|
145
|
-
|
162
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
163
|
+
exec_delete(sql, name, binds)
|
146
164
|
end
|
147
165
|
|
148
166
|
# Returns +true+ when the connection adapter supports prepared statement
|
149
167
|
# caching, otherwise returns +false+
|
150
|
-
def supports_statement_cache?
|
151
|
-
|
168
|
+
def supports_statement_cache? # :nodoc:
|
169
|
+
true
|
152
170
|
end
|
171
|
+
deprecate :supports_statement_cache?
|
153
172
|
|
154
173
|
# Runs the given block in a database transaction, and returns the result
|
155
174
|
# of the block.
|
@@ -162,7 +181,7 @@ module ActiveRecord
|
|
162
181
|
#
|
163
182
|
# In order to get around this problem, #transaction will emulate the effect
|
164
183
|
# of nested transactions, by using savepoints:
|
165
|
-
#
|
184
|
+
# https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
|
166
185
|
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
167
186
|
# supports savepoints.
|
168
187
|
#
|
@@ -214,7 +233,7 @@ module ActiveRecord
|
|
214
233
|
# You should consult the documentation for your database to understand the
|
215
234
|
# semantics of these different levels:
|
216
235
|
#
|
217
|
-
# *
|
236
|
+
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
|
218
237
|
# * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
|
219
238
|
#
|
220
239
|
# An ActiveRecord::TransactionIsolationError will be raised if:
|
@@ -305,6 +324,9 @@ module ActiveRecord
|
|
305
324
|
|
306
325
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
307
326
|
# something beyond a simple insert (eg. Oracle).
|
327
|
+
# Most of adapters should implement `insert_fixtures` that leverages bulk SQL insert.
|
328
|
+
# We keep this method to provide fallback
|
329
|
+
# for databases like sqlite that do not support bulk inserts.
|
308
330
|
def insert_fixture(fixture, table_name)
|
309
331
|
fixture = fixture.stringify_keys
|
310
332
|
|
@@ -317,16 +339,50 @@ module ActiveRecord
|
|
317
339
|
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
318
340
|
end
|
319
341
|
end
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
end
|
342
|
+
|
343
|
+
table = Arel::Table.new(table_name)
|
344
|
+
|
345
|
+
values = binds.map do |bind|
|
346
|
+
value = with_yaml_fallback(bind.value_for_database)
|
347
|
+
[table[bind.name], value]
|
327
348
|
end
|
328
349
|
|
329
|
-
|
350
|
+
manager = Arel::InsertManager.new
|
351
|
+
manager.into(table)
|
352
|
+
manager.insert(values)
|
353
|
+
execute manager.to_sql, "Fixture Insert"
|
354
|
+
end
|
355
|
+
|
356
|
+
# Inserts a set of fixtures into the table. Overridden in adapters that require
|
357
|
+
# something beyond a simple insert (eg. Oracle).
|
358
|
+
def insert_fixtures(fixtures, table_name)
|
359
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
360
|
+
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
361
|
+
Consider using `insert_fixtures_set` for performance improvement.
|
362
|
+
MSG
|
363
|
+
return if fixtures.empty?
|
364
|
+
|
365
|
+
execute(build_fixture_sql(fixtures, table_name), "Fixtures Insert")
|
366
|
+
end
|
367
|
+
|
368
|
+
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
369
|
+
fixture_inserts = fixture_set.map do |table_name, fixtures|
|
370
|
+
next if fixtures.empty?
|
371
|
+
|
372
|
+
build_fixture_sql(fixtures, table_name)
|
373
|
+
end.compact
|
374
|
+
|
375
|
+
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name table}".dup }
|
376
|
+
total_sql = Array.wrap(combine_multi_statements(table_deletes + fixture_inserts))
|
377
|
+
|
378
|
+
disable_referential_integrity do
|
379
|
+
transaction(requires_new: true) do
|
380
|
+
total_sql.each do |sql|
|
381
|
+
execute sql, "Fixtures Load"
|
382
|
+
yield if block_given?
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
330
386
|
end
|
331
387
|
|
332
388
|
def empty_insert_statement_value
|
@@ -358,6 +414,44 @@ module ActiveRecord
|
|
358
414
|
alias join_to_delete join_to_update
|
359
415
|
|
360
416
|
private
|
417
|
+
def default_insert_value(column)
|
418
|
+
Arel.sql("DEFAULT")
|
419
|
+
end
|
420
|
+
|
421
|
+
def build_fixture_sql(fixtures, table_name)
|
422
|
+
columns = schema_cache.columns_hash(table_name)
|
423
|
+
|
424
|
+
values = fixtures.map do |fixture|
|
425
|
+
fixture = fixture.stringify_keys
|
426
|
+
|
427
|
+
unknown_columns = fixture.keys - columns.keys
|
428
|
+
if unknown_columns.any?
|
429
|
+
raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
|
430
|
+
end
|
431
|
+
|
432
|
+
columns.map do |name, column|
|
433
|
+
if fixture.key?(name)
|
434
|
+
type = lookup_cast_type_from_column(column)
|
435
|
+
bind = Relation::QueryAttribute.new(name, fixture[name], type)
|
436
|
+
with_yaml_fallback(bind.value_for_database)
|
437
|
+
else
|
438
|
+
default_insert_value(column)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
table = Arel::Table.new(table_name)
|
444
|
+
manager = Arel::InsertManager.new
|
445
|
+
manager.into(table)
|
446
|
+
columns.each_key { |column| manager.columns << table[column] }
|
447
|
+
manager.values = manager.create_values_list(values)
|
448
|
+
|
449
|
+
manager.to_sql
|
450
|
+
end
|
451
|
+
|
452
|
+
def combine_multi_statements(total_sql)
|
453
|
+
total_sql.join(";\n")
|
454
|
+
end
|
361
455
|
|
362
456
|
# Returns a subquery for the given key using the join information.
|
363
457
|
def subquery_for(key, select)
|
@@ -388,11 +482,45 @@ module ActiveRecord
|
|
388
482
|
row && row.first
|
389
483
|
end
|
390
484
|
|
391
|
-
def
|
392
|
-
if relation.is_a?(Relation)
|
393
|
-
relation
|
485
|
+
def arel_from_relation(relation)
|
486
|
+
if relation.is_a?(Relation)
|
487
|
+
relation.arel
|
488
|
+
else
|
489
|
+
relation
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
# Fixture value is quoted by Arel, however scalar values
|
494
|
+
# are not quotable. In this case we want to convert
|
495
|
+
# the column value to YAML.
|
496
|
+
def with_yaml_fallback(value)
|
497
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
498
|
+
YAML.dump(value)
|
499
|
+
else
|
500
|
+
value
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
class PartialQueryCollector
|
505
|
+
def initialize
|
506
|
+
@parts = []
|
507
|
+
@binds = []
|
508
|
+
end
|
509
|
+
|
510
|
+
def <<(str)
|
511
|
+
@parts << str
|
512
|
+
self
|
513
|
+
end
|
514
|
+
|
515
|
+
def add_bind(obj)
|
516
|
+
@binds << obj
|
517
|
+
@parts << Arel::Nodes::BindParam.new(1)
|
518
|
+
self
|
519
|
+
end
|
520
|
+
|
521
|
+
def value
|
522
|
+
[@parts, @binds]
|
394
523
|
end
|
395
|
-
[relation, binds]
|
396
524
|
end
|
397
525
|
end
|
398
526
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent/map"
|
4
|
+
|
1
5
|
module ActiveRecord
|
2
6
|
module ConnectionAdapters # :nodoc:
|
3
7
|
module QueryCache
|
@@ -90,8 +94,8 @@ module ActiveRecord
|
|
90
94
|
|
91
95
|
def select_all(arel, name = nil, binds = [], preparable: nil)
|
92
96
|
if @query_cache_enabled && !locked?(arel)
|
93
|
-
arel
|
94
|
-
sql =
|
97
|
+
arel = arel_from_relation(arel)
|
98
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
95
99
|
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
|
96
100
|
else
|
97
101
|
super
|
@@ -124,6 +128,7 @@ module ActiveRecord
|
|
124
128
|
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
|
125
129
|
# queries should not be cached.
|
126
130
|
def locked?(arel)
|
131
|
+
arel = arel.arel if arel.is_a?(Relation)
|
127
132
|
arel.respond_to?(:locked) && arel.locked
|
128
133
|
end
|
129
134
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/big_decimal/conversions"
|
2
4
|
require "active_support/multibyte/chars"
|
3
5
|
|
@@ -5,21 +7,12 @@ module ActiveRecord
|
|
5
7
|
module ConnectionAdapters # :nodoc:
|
6
8
|
module Quoting
|
7
9
|
# Quotes the column value to help prevent
|
8
|
-
# {SQL injection attacks}[
|
10
|
+
# {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
|
9
11
|
def quote(value)
|
10
12
|
value = id_value_for_database(value) if value.is_a?(Base)
|
11
13
|
|
12
|
-
if value.respond_to?(:
|
13
|
-
|
14
|
-
at &&= " at %s:%d" % at
|
15
|
-
|
16
|
-
owner = value.method(:quoted_id).owner.to_s
|
17
|
-
klass = value.class.to_s
|
18
|
-
klass += "(#{owner})" unless owner == klass
|
19
|
-
|
20
|
-
ActiveSupport::Deprecation.warn \
|
21
|
-
"Defining #quoted_id is deprecated and will be ignored in Rails 5.2. (defined on #{klass}#{at})"
|
22
|
-
return value.quoted_id
|
14
|
+
if value.respond_to?(:value_for_database)
|
15
|
+
value = value.value_for_database
|
23
16
|
end
|
24
17
|
|
25
18
|
_quote(value)
|
@@ -31,10 +24,6 @@ module ActiveRecord
|
|
31
24
|
def type_cast(value, column = nil)
|
32
25
|
value = id_value_for_database(value) if value.is_a?(Base)
|
33
26
|
|
34
|
-
if value.respond_to?(:quoted_id) && value.respond_to?(:id)
|
35
|
-
return value.id
|
36
|
-
end
|
37
|
-
|
38
27
|
if column
|
39
28
|
value = type_cast_from_column(column, value)
|
40
29
|
end
|
@@ -68,17 +57,6 @@ module ActiveRecord
|
|
68
57
|
lookup_cast_type(column.sql_type)
|
69
58
|
end
|
70
59
|
|
71
|
-
def fetch_type_metadata(sql_type)
|
72
|
-
cast_type = lookup_cast_type(sql_type)
|
73
|
-
SqlTypeMetadata.new(
|
74
|
-
sql_type: sql_type,
|
75
|
-
type: cast_type.type,
|
76
|
-
limit: cast_type.limit,
|
77
|
-
precision: cast_type.precision,
|
78
|
-
scale: cast_type.scale,
|
79
|
-
)
|
80
|
-
end
|
81
|
-
|
82
60
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
83
61
|
# characters.
|
84
62
|
def quote_string(s)
|
@@ -117,19 +95,19 @@ module ActiveRecord
|
|
117
95
|
end
|
118
96
|
|
119
97
|
def quoted_true
|
120
|
-
"
|
98
|
+
"TRUE".freeze
|
121
99
|
end
|
122
100
|
|
123
101
|
def unquoted_true
|
124
|
-
|
102
|
+
true
|
125
103
|
end
|
126
104
|
|
127
105
|
def quoted_false
|
128
|
-
"
|
106
|
+
"FALSE".freeze
|
129
107
|
end
|
130
108
|
|
131
109
|
def unquoted_false
|
132
|
-
|
110
|
+
false
|
133
111
|
end
|
134
112
|
|
135
113
|
# Quote date/time values for use in SQL input. Includes microseconds
|
@@ -152,7 +130,8 @@ module ActiveRecord
|
|
152
130
|
end
|
153
131
|
|
154
132
|
def quoted_time(value) # :nodoc:
|
155
|
-
|
133
|
+
value = value.change(year: 2000, month: 1, day: 1)
|
134
|
+
quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "")
|
156
135
|
end
|
157
136
|
|
158
137
|
def quoted_binary(value) # :nodoc:
|
@@ -168,6 +147,10 @@ module ActiveRecord
|
|
168
147
|
end
|
169
148
|
|
170
149
|
private
|
150
|
+
def lookup_cast_type(sql_type)
|
151
|
+
type_map.lookup(sql_type)
|
152
|
+
end
|
153
|
+
|
171
154
|
def id_value_for_database(value)
|
172
155
|
if primary_key = value.class.primary_key
|
173
156
|
value.instance_variable_get(:@attributes)[primary_key].value_for_database
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/string/strip"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -22,7 +24,7 @@ module ActiveRecord
|
|
22
24
|
private
|
23
25
|
|
24
26
|
def visit_AlterTable(o)
|
25
|
-
sql = "ALTER TABLE #{quote_table_name(o.name)} "
|
27
|
+
sql = "ALTER TABLE #{quote_table_name(o.name)} ".dup
|
26
28
|
sql << o.adds.map { |col| accept col }.join(" ")
|
27
29
|
sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
|
28
30
|
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
|
@@ -30,17 +32,17 @@ module ActiveRecord
|
|
30
32
|
|
31
33
|
def visit_ColumnDefinition(o)
|
32
34
|
o.sql_type = type_to_sql(o.type, o.options)
|
33
|
-
column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
|
35
|
+
column_sql = "#{quote_column_name(o.name)} #{o.sql_type}".dup
|
34
36
|
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
|
35
37
|
column_sql
|
36
38
|
end
|
37
39
|
|
38
40
|
def visit_AddColumnDefinition(o)
|
39
|
-
"ADD #{accept(o.column)}"
|
41
|
+
"ADD #{accept(o.column)}".dup
|
40
42
|
end
|
41
43
|
|
42
44
|
def visit_TableDefinition(o)
|
43
|
-
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
|
45
|
+
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} ".dup
|
44
46
|
|
45
47
|
statements = o.columns.map { |c| accept c }
|
46
48
|
statements << accept(o.primary_keys) if o.primary_keys
|
@@ -55,7 +57,7 @@ module ActiveRecord
|
|
55
57
|
|
56
58
|
create_sql << "(#{statements.join(', ')})" if statements.present?
|
57
59
|
add_table_options!(create_sql, table_options(o))
|
58
|
-
create_sql << " AS #{
|
60
|
+
create_sql << " AS #{to_sql(o.as)}" if o.as
|
59
61
|
create_sql
|
60
62
|
end
|
61
63
|
|
@@ -93,6 +95,7 @@ module ActiveRecord
|
|
93
95
|
if options_sql = options[:options]
|
94
96
|
create_sql << " #{options_sql}"
|
95
97
|
end
|
98
|
+
create_sql
|
96
99
|
end
|
97
100
|
|
98
101
|
def column_options(o)
|
@@ -114,6 +117,11 @@ module ActiveRecord
|
|
114
117
|
sql
|
115
118
|
end
|
116
119
|
|
120
|
+
def to_sql(sql)
|
121
|
+
sql = sql.to_sql if sql.respond_to?(:to_sql)
|
122
|
+
sql
|
123
|
+
end
|
124
|
+
|
117
125
|
def foreign_key_in_create(from_table, to_table, options)
|
118
126
|
options = foreign_key_options(from_table, to_table, options)
|
119
127
|
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
@@ -133,5 +141,6 @@ module ActiveRecord
|
|
133
141
|
end
|
134
142
|
end
|
135
143
|
end
|
144
|
+
SchemaCreation = AbstractAdapter::SchemaCreation # :nodoc:
|
136
145
|
end
|
137
146
|
end
|
@@ -1,9 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters #:nodoc:
|
3
5
|
# Abstract representation of an index definition on a table. Instances of
|
4
6
|
# this type are typically created and returned by methods in database
|
5
|
-
# adapters. e.g. ActiveRecord::ConnectionAdapters::
|
6
|
-
IndexDefinition
|
7
|
+
# adapters. e.g. ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#indexes
|
8
|
+
class IndexDefinition # :nodoc:
|
9
|
+
attr_reader :table, :name, :unique, :columns, :lengths, :orders, :opclasses, :where, :type, :using, :comment
|
10
|
+
|
11
|
+
def initialize(
|
12
|
+
table, name,
|
13
|
+
unique = false,
|
14
|
+
columns = [],
|
15
|
+
lengths: {},
|
16
|
+
orders: {},
|
17
|
+
opclasses: {},
|
18
|
+
where: nil,
|
19
|
+
type: nil,
|
20
|
+
using: nil,
|
21
|
+
comment: nil
|
22
|
+
)
|
23
|
+
@table = table
|
24
|
+
@name = name
|
25
|
+
@unique = unique
|
26
|
+
@columns = columns
|
27
|
+
@lengths = concise_options(lengths)
|
28
|
+
@orders = concise_options(orders)
|
29
|
+
@opclasses = concise_options(opclasses)
|
30
|
+
@where = where
|
31
|
+
@type = type
|
32
|
+
@using = using
|
33
|
+
@comment = comment
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def concise_options(options)
|
38
|
+
if columns.size == options.size && options.values.uniq.size == 1
|
39
|
+
options.values.first
|
40
|
+
else
|
41
|
+
options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
7
45
|
|
8
46
|
# Abstract representation of a column definition. Instances of this type
|
9
47
|
# are typically created by methods in TableDefinition, and added to the
|
@@ -58,6 +96,11 @@ module ActiveRecord
|
|
58
96
|
options[:primary_key] != default_primary_key
|
59
97
|
end
|
60
98
|
|
99
|
+
def validate?
|
100
|
+
options.fetch(:validate, true)
|
101
|
+
end
|
102
|
+
alias validated? validate?
|
103
|
+
|
61
104
|
def defined_for?(to_table_ord = nil, to_table: nil, **options)
|
62
105
|
if to_table_ord
|
63
106
|
self.to_table == to_table_ord.to_s
|
@@ -177,6 +220,7 @@ module ActiveRecord
|
|
177
220
|
:decimal,
|
178
221
|
:float,
|
179
222
|
:integer,
|
223
|
+
:json,
|
180
224
|
:string,
|
181
225
|
:text,
|
182
226
|
:time,
|
@@ -369,6 +413,9 @@ module ActiveRecord
|
|
369
413
|
alias :belongs_to :references
|
370
414
|
|
371
415
|
def new_column_definition(name, type, **options) # :nodoc:
|
416
|
+
if integer_like_primary_key?(type, options)
|
417
|
+
type = integer_like_primary_key_type(type, options)
|
418
|
+
end
|
372
419
|
type = aliased_types(type.to_s, type)
|
373
420
|
options[:primary_key] ||= type == :primary_key
|
374
421
|
options[:null] = false if options[:primary_key]
|
@@ -383,6 +430,14 @@ module ActiveRecord
|
|
383
430
|
def aliased_types(name, fallback)
|
384
431
|
"timestamp" == name ? :datetime : fallback
|
385
432
|
end
|
433
|
+
|
434
|
+
def integer_like_primary_key?(type, options)
|
435
|
+
options[:primary_key] && [:integer, :bigint].include?(type) && !options.key?(:default)
|
436
|
+
end
|
437
|
+
|
438
|
+
def integer_like_primary_key_type(type, options)
|
439
|
+
type
|
440
|
+
end
|
386
441
|
end
|
387
442
|
|
388
443
|
class AlterTable # :nodoc:
|
@@ -443,6 +498,9 @@ module ActiveRecord
|
|
443
498
|
# t.date
|
444
499
|
# t.binary
|
445
500
|
# t.boolean
|
501
|
+
# t.foreign_key
|
502
|
+
# t.json
|
503
|
+
# t.virtual
|
446
504
|
# t.remove
|
447
505
|
# t.remove_references
|
448
506
|
# t.remove_belongs_to
|
@@ -607,19 +665,19 @@ module ActiveRecord
|
|
607
665
|
|
608
666
|
# Adds a foreign key.
|
609
667
|
#
|
610
|
-
#
|
668
|
+
# t.foreign_key(:authors)
|
611
669
|
#
|
612
670
|
# See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
|
613
|
-
def foreign_key(*args)
|
671
|
+
def foreign_key(*args)
|
614
672
|
@base.add_foreign_key(name, *args)
|
615
673
|
end
|
616
674
|
|
617
675
|
# Checks to see if a foreign key exists.
|
618
676
|
#
|
619
|
-
#
|
677
|
+
# t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
|
620
678
|
#
|
621
679
|
# See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
|
622
|
-
def foreign_key_exists?(*args)
|
680
|
+
def foreign_key_exists?(*args)
|
623
681
|
@base.foreign_key_exists?(name, *args)
|
624
682
|
end
|
625
683
|
end
|