activerecord 5.1.0 → 5.2.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 +5 -5
- data/CHANGELOG.md +410 -530
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- 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 +23 -32
- data/lib/active_record/associations/association.rb +20 -21
- data/lib/active_record/associations/association_scope.rb +49 -49
- data/lib/active_record/associations/belongs_to_association.rb +12 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +10 -6
- 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 +50 -41
- data/lib/active_record/associations/collection_proxy.rb +22 -39
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +4 -2
- data/lib/active_record/associations/has_many_through_association.rb +12 -18
- data/lib/active_record/associations/has_one_association.rb +5 -1
- data/lib/active_record/associations/has_one_through_association.rb +8 -7
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -64
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
- data/lib/active_record/associations/join_dependency.rb +27 -44
- data/lib/active_record/associations/preloader/association.rb +53 -92
- data/lib/active_record/associations/preloader/through_association.rb +72 -73
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/singular_association.rb +14 -10
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +68 -76
- data/lib/active_record/attribute_assignment.rb +2 -0
- 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 +24 -214
- data/lib/active_record/attribute_methods/primary_key.rb +10 -13
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +8 -2
- 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 +22 -19
- data/lib/active_record/attribute_methods.rb +48 -12
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +8 -11
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +8 -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 +14 -10
- 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 +175 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -24
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +58 -3
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +165 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +118 -180
- data/lib/active_record/connection_adapters/column.rb +4 -2
- 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 +11 -17
- 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 -23
- 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 +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -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_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 -11
- 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 +4 -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 +2 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
- 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 +269 -126
- 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 +64 -85
- 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 +18 -0
- 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 +71 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +92 -95
- 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 +3 -2
- 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 +9 -9
- 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 +8 -6
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +74 -22
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +181 -137
- data/lib/active_record/model_schema.rb +73 -58
- 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 +153 -18
- data/lib/active_record/query_cache.rb +17 -12
- data/lib/active_record/querying.rb +4 -2
- 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 +47 -37
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +131 -204
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/calculations.rb +58 -20
- data/lib/active_record/relation/delegation.rb +10 -29
- data/lib/active_record/relation/finder_methods.rb +74 -85
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +51 -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 +54 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +53 -78
- data/lib/active_record/relation/query_attribute.rb +9 -2
- data/lib/active_record/relation/query_methods.rb +101 -95
- 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 -67
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +99 -202
- 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 +10 -7
- data/lib/active_record/scoping/named.rb +38 -12
- data/lib/active_record/scoping.rb +12 -10
- 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 +37 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +5 -5
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +9 -7
- 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 +2 -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 +35 -5
- 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 +25 -37
- 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 -113
- 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 -33
@@ -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
|
@@ -51,9 +66,7 @@ module ActiveRecord
|
|
51
66
|
|
52
67
|
# Returns a single value from a record
|
53
68
|
def select_value(arel, name = nil, binds = [])
|
54
|
-
|
55
|
-
result.first
|
56
|
-
end
|
69
|
+
single_value_from_rows(select_rows(arel, name, binds))
|
57
70
|
end
|
58
71
|
|
59
72
|
# Returns an array of the values of the first column in a select:
|
@@ -68,6 +81,18 @@ module ActiveRecord
|
|
68
81
|
select_all(arel, name, binds).rows
|
69
82
|
end
|
70
83
|
|
84
|
+
def query_value(sql, name = nil) # :nodoc:
|
85
|
+
single_value_from_rows(query(sql, name))
|
86
|
+
end
|
87
|
+
|
88
|
+
def query_values(sql, name = nil) # :nodoc:
|
89
|
+
query(sql, name).map(&:first)
|
90
|
+
end
|
91
|
+
|
92
|
+
def query(sql, name = nil) # :nodoc:
|
93
|
+
exec_query(sql, name).rows
|
94
|
+
end
|
95
|
+
|
71
96
|
# Executes the SQL statement in the context of this connection and returns
|
72
97
|
# the raw result from the connection adapter.
|
73
98
|
# Note: depending on your database connector, the result returned by this
|
@@ -120,26 +145,30 @@ module ActiveRecord
|
|
120
145
|
# If the next id was calculated in advance (as in Oracle), it should be
|
121
146
|
# passed in as +id_value+.
|
122
147
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
123
|
-
|
148
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
149
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
124
150
|
id_value || last_inserted_id(value)
|
125
151
|
end
|
126
152
|
alias create insert
|
127
153
|
|
128
154
|
# Executes the update statement and returns the number of rows affected.
|
129
155
|
def update(arel, name = nil, binds = [])
|
130
|
-
|
156
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
157
|
+
exec_update(sql, name, binds)
|
131
158
|
end
|
132
159
|
|
133
160
|
# Executes the delete statement and returns the number of rows affected.
|
134
161
|
def delete(arel, name = nil, binds = [])
|
135
|
-
|
162
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
163
|
+
exec_delete(sql, name, binds)
|
136
164
|
end
|
137
165
|
|
138
166
|
# Returns +true+ when the connection adapter supports prepared statement
|
139
167
|
# caching, otherwise returns +false+
|
140
|
-
def supports_statement_cache?
|
141
|
-
|
168
|
+
def supports_statement_cache? # :nodoc:
|
169
|
+
true
|
142
170
|
end
|
171
|
+
deprecate :supports_statement_cache?
|
143
172
|
|
144
173
|
# Runs the given block in a database transaction, and returns the result
|
145
174
|
# of the block.
|
@@ -152,7 +181,7 @@ module ActiveRecord
|
|
152
181
|
#
|
153
182
|
# In order to get around this problem, #transaction will emulate the effect
|
154
183
|
# of nested transactions, by using savepoints:
|
155
|
-
#
|
184
|
+
# https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
|
156
185
|
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
157
186
|
# supports savepoints.
|
158
187
|
#
|
@@ -204,7 +233,7 @@ module ActiveRecord
|
|
204
233
|
# You should consult the documentation for your database to understand the
|
205
234
|
# semantics of these different levels:
|
206
235
|
#
|
207
|
-
# *
|
236
|
+
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
|
208
237
|
# * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
|
209
238
|
#
|
210
239
|
# An ActiveRecord::TransactionIsolationError will be raised if:
|
@@ -295,6 +324,9 @@ module ActiveRecord
|
|
295
324
|
|
296
325
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
297
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.
|
298
330
|
def insert_fixture(fixture, table_name)
|
299
331
|
fixture = fixture.stringify_keys
|
300
332
|
|
@@ -307,16 +339,50 @@ module ActiveRecord
|
|
307
339
|
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
308
340
|
end
|
309
341
|
end
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
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]
|
317
348
|
end
|
318
349
|
|
319
|
-
|
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
|
320
386
|
end
|
321
387
|
|
322
388
|
def empty_insert_statement_value
|
@@ -348,6 +414,44 @@ module ActiveRecord
|
|
348
414
|
alias join_to_delete join_to_update
|
349
415
|
|
350
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
|
351
455
|
|
352
456
|
# Returns a subquery for the given key using the join information.
|
353
457
|
def subquery_for(key, select)
|
@@ -370,15 +474,53 @@ module ActiveRecord
|
|
370
474
|
end
|
371
475
|
|
372
476
|
def last_inserted_id(result)
|
373
|
-
|
477
|
+
single_value_from_rows(result.rows)
|
478
|
+
end
|
479
|
+
|
480
|
+
def single_value_from_rows(rows)
|
481
|
+
row = rows.first
|
374
482
|
row && row.first
|
375
483
|
end
|
376
484
|
|
377
|
-
def
|
378
|
-
if relation.is_a?(Relation)
|
379
|
-
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]
|
380
523
|
end
|
381
|
-
[relation, binds]
|
382
524
|
end
|
383
525
|
end
|
384
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
|
@@ -108,6 +112,7 @@ module ActiveRecord
|
|
108
112
|
"sql.active_record",
|
109
113
|
sql: sql,
|
110
114
|
binds: binds,
|
115
|
+
type_casted_binds: -> { type_casted_binds(binds) },
|
111
116
|
name: name,
|
112
117
|
connection_id: object_id,
|
113
118
|
cached: true,
|
@@ -123,6 +128,7 @@ module ActiveRecord
|
|
123
128
|
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
|
124
129
|
# queries should not be cached.
|
125
130
|
def locked?(arel)
|
131
|
+
arel = arel.arel if arel.is_a?(Relation)
|
126
132
|
arel.respond_to?(:locked) && arel.locked
|
127
133
|
end
|
128
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,14 +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
|
-
"Using #quoted_id is deprecated and will be removed in Rails 5.2."
|
15
|
-
return value.quoted_id
|
14
|
+
if value.respond_to?(:value_for_database)
|
15
|
+
value = value.value_for_database
|
16
16
|
end
|
17
17
|
|
18
18
|
_quote(value)
|
@@ -24,10 +24,6 @@ module ActiveRecord
|
|
24
24
|
def type_cast(value, column = nil)
|
25
25
|
value = id_value_for_database(value) if value.is_a?(Base)
|
26
26
|
|
27
|
-
if value.respond_to?(:quoted_id) && value.respond_to?(:id)
|
28
|
-
return value.id
|
29
|
-
end
|
30
|
-
|
31
27
|
if column
|
32
28
|
value = type_cast_from_column(column, value)
|
33
29
|
end
|
@@ -61,17 +57,6 @@ module ActiveRecord
|
|
61
57
|
lookup_cast_type(column.sql_type)
|
62
58
|
end
|
63
59
|
|
64
|
-
def fetch_type_metadata(sql_type)
|
65
|
-
cast_type = lookup_cast_type(sql_type)
|
66
|
-
SqlTypeMetadata.new(
|
67
|
-
sql_type: sql_type,
|
68
|
-
type: cast_type.type,
|
69
|
-
limit: cast_type.limit,
|
70
|
-
precision: cast_type.precision,
|
71
|
-
scale: cast_type.scale,
|
72
|
-
)
|
73
|
-
end
|
74
|
-
|
75
60
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
76
61
|
# characters.
|
77
62
|
def quote_string(s)
|
@@ -110,19 +95,19 @@ module ActiveRecord
|
|
110
95
|
end
|
111
96
|
|
112
97
|
def quoted_true
|
113
|
-
"
|
98
|
+
"TRUE".freeze
|
114
99
|
end
|
115
100
|
|
116
101
|
def unquoted_true
|
117
|
-
|
102
|
+
true
|
118
103
|
end
|
119
104
|
|
120
105
|
def quoted_false
|
121
|
-
"
|
106
|
+
"FALSE".freeze
|
122
107
|
end
|
123
108
|
|
124
109
|
def unquoted_false
|
125
|
-
|
110
|
+
false
|
126
111
|
end
|
127
112
|
|
128
113
|
# Quote date/time values for use in SQL input. Includes microseconds
|
@@ -161,6 +146,10 @@ module ActiveRecord
|
|
161
146
|
end
|
162
147
|
|
163
148
|
private
|
149
|
+
def lookup_cast_type(sql_type)
|
150
|
+
type_map.lookup(sql_type)
|
151
|
+
end
|
152
|
+
|
164
153
|
def id_value_for_database(value)
|
165
154
|
if primary_key = value.class.primary_key
|
166
155
|
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,12 +57,12 @@ 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
|
|
62
64
|
def visit_PrimaryKeyDefinition(o)
|
63
|
-
"PRIMARY KEY (#{o.name.join(', ')})"
|
65
|
+
"PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})"
|
64
66
|
end
|
65
67
|
|
66
68
|
def visit_ForeignKeyDefinition(o)
|
@@ -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
|
@@ -121,7 +164,7 @@ module ActiveRecord
|
|
121
164
|
end
|
122
165
|
|
123
166
|
def polymorphic_options
|
124
|
-
as_options(polymorphic)
|
167
|
+
as_options(polymorphic).merge(options.slice(:null, :first, :after))
|
125
168
|
end
|
126
169
|
|
127
170
|
def index_options
|
@@ -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:
|