activerecord 4.2.0 → 5.2.8.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 +5 -5
- data/CHANGELOG.md +640 -928
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -11
- data/examples/performance.rb +32 -31
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +264 -247
- data/lib/active_record/association_relation.rb +24 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +87 -41
- data/lib/active_record/associations/association_scope.rb +106 -132
- data/lib/active_record/associations/belongs_to_association.rb +55 -36
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +29 -38
- data/lib/active_record/associations/builder/belongs_to.rb +77 -30
- data/lib/active_record/associations/builder/collection_association.rb +14 -23
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
- data/lib/active_record/associations/builder/has_many.rb +6 -4
- data/lib/active_record/associations/builder/has_one.rb +13 -6
- data/lib/active_record/associations/builder/singular_association.rb +15 -11
- data/lib/active_record/associations/collection_association.rb +145 -266
- data/lib/active_record/associations/collection_proxy.rb +242 -138
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +35 -75
- data/lib/active_record/associations/has_many_through_association.rb +51 -69
- data/lib/active_record/associations/has_one_association.rb +39 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -154
- data/lib/active_record/associations/preloader/association.rb +85 -116
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +83 -93
- data/lib/active_record/associations/singular_association.rb +27 -40
- data/lib/active_record/associations/through_association.rb +48 -23
- data/lib/active_record/associations.rb +1732 -1596
- data/lib/active_record/attribute_assignment.rb +58 -182
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
- data/lib/active_record/attribute_methods/dirty.rb +94 -125
- data/lib/active_record/attribute_methods/primary_key.rb +86 -71
- data/lib/active_record/attribute_methods/query.rb +4 -2
- data/lib/active_record/attribute_methods/read.rb +45 -63
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
- data/lib/active_record/attribute_methods/write.rb +31 -46
- data/lib/active_record/attribute_methods.rb +170 -117
- data/lib/active_record/attributes.rb +201 -74
- data/lib/active_record/autosave_association.rb +118 -45
- data/lib/active_record/base.rb +60 -48
- data/lib/active_record/callbacks.rb +97 -57
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +37 -13
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
- data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
- data/lib/active_record/connection_adapters/column.rb +50 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- 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 +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +40 -27
- data/lib/active_record/core.rb +205 -202
- data/lib/active_record/counter_cache.rb +80 -37
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +136 -90
- data/lib/active_record/errors.rb +180 -52
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +193 -135
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +148 -112
- data/lib/active_record/integration.rb +70 -28
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +92 -98
- data/lib/active_record/locking/pessimistic.rb +15 -3
- data/lib/active_record/log_subscriber.rb +95 -33
- data/lib/active_record/migration/command_recorder.rb +133 -90
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +594 -267
- data/lib/active_record/model_schema.rb +292 -111
- data/lib/active_record/nested_attributes.rb +266 -214
- data/lib/active_record/no_touching.rb +8 -2
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +350 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +117 -35
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +9 -3
- data/lib/active_record/railties/databases.rake +160 -174
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +447 -288
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +204 -55
- data/lib/active_record/relation/calculations.rb +259 -244
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +290 -253
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +91 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +118 -92
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +446 -389
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -16
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +287 -339
- data/lib/active_record/result.rb +54 -36
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +155 -124
- data/lib/active_record/schema.rb +30 -24
- data/lib/active_record/schema_dumper.rb +91 -87
- data/lib/active_record/schema_migration.rb +19 -19
- data/lib/active_record/scoping/default.rb +102 -84
- data/lib/active_record/scoping/named.rb +81 -32
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +45 -35
- data/lib/active_record/store.rb +42 -36
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +136 -95
- data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +208 -123
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +4 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +30 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type.rb +79 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +41 -32
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -21
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
- data/lib/rails/generators/active_record/migration.rb +18 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +77 -53
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -149
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -30
- data/lib/active_record/type/decimal.rb +0 -40
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
5
|
module DatabaseLimits
|
4
|
-
|
5
6
|
# Returns the maximum length of a table alias.
|
6
7
|
def table_alias_length
|
7
8
|
255
|
@@ -18,9 +19,9 @@ module ActiveRecord
|
|
18
19
|
end
|
19
20
|
|
20
21
|
# Returns the maximum allowed length for an index name. This
|
21
|
-
# limit is enforced by
|
22
|
-
#
|
23
|
-
#
|
22
|
+
# limit is enforced by \Rails and is less than or equal to
|
23
|
+
# #index_name_length. The gap between
|
24
|
+
# #index_name_length is to allow internal \Rails
|
24
25
|
# operations to use prefixes in temporary operations.
|
25
26
|
def allowed_index_name_length
|
26
27
|
index_name_length
|
@@ -47,7 +48,7 @@ module ActiveRecord
|
|
47
48
|
end
|
48
49
|
|
49
50
|
# Returns the maximum number of elements in an IN (x,y,z) clause.
|
50
|
-
# nil means no limit.
|
51
|
+
# +nil+ means no limit.
|
51
52
|
def in_clause_length
|
52
53
|
nil
|
53
54
|
end
|
@@ -62,6 +63,10 @@ module ActiveRecord
|
|
62
63
|
256
|
63
64
|
end
|
64
65
|
|
66
|
+
private
|
67
|
+
def bind_params_length
|
68
|
+
65535
|
69
|
+
end
|
65
70
|
end
|
66
71
|
end
|
67
72
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
5
|
module DatabaseStatements
|
@@ -7,29 +9,66 @@ 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
|
+
|
24
|
+
if prepared_statements
|
25
|
+
sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
|
26
|
+
|
27
|
+
if binds.length > bind_params_length
|
28
|
+
unprepared_statement do
|
29
|
+
sql, binds = to_sql_and_binds(arel_or_sql_string)
|
30
|
+
visitor.preparable = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
sql = visitor.accept(arel_or_sql_string.ast, collector).value
|
35
|
+
end
|
36
|
+
[sql.freeze, binds]
|
14
37
|
else
|
15
|
-
|
38
|
+
visitor.preparable = false if prepared_statements
|
39
|
+
[arel_or_sql_string.dup.freeze, binds]
|
16
40
|
end
|
17
41
|
end
|
42
|
+
private :to_sql_and_binds
|
18
43
|
|
19
44
|
# This is used in the StatementCache object. It returns an object that
|
20
45
|
# can be used to query the database repeatedly.
|
21
|
-
def cacheable_query(arel) # :nodoc:
|
46
|
+
def cacheable_query(klass, arel) # :nodoc:
|
22
47
|
if prepared_statements
|
23
|
-
|
48
|
+
sql, binds = visitor.accept(arel.ast, collector).value
|
49
|
+
query = klass.query(sql)
|
24
50
|
else
|
25
|
-
|
51
|
+
collector = PartialQueryCollector.new
|
52
|
+
parts, binds = visitor.accept(arel.ast, collector).value
|
53
|
+
query = klass.partial_query(parts)
|
26
54
|
end
|
55
|
+
[query, binds]
|
27
56
|
end
|
28
57
|
|
29
58
|
# Returns an ActiveRecord::Result instance.
|
30
|
-
def select_all(arel, name = nil, binds = [])
|
31
|
-
arel
|
32
|
-
|
59
|
+
def select_all(arel, name = nil, binds = [], preparable: nil)
|
60
|
+
arel = arel_from_relation(arel)
|
61
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
62
|
+
|
63
|
+
if preparable.nil?
|
64
|
+
preparable = prepared_statements ? visitor.preparable : false
|
65
|
+
end
|
66
|
+
|
67
|
+
if prepared_statements && preparable
|
68
|
+
select_prepared(sql, name, binds)
|
69
|
+
else
|
70
|
+
select(sql, name, binds)
|
71
|
+
end
|
33
72
|
end
|
34
73
|
|
35
74
|
# Returns a record hash with the column names as keys and column values
|
@@ -40,46 +79,61 @@ module ActiveRecord
|
|
40
79
|
|
41
80
|
# Returns a single value from a record
|
42
81
|
def select_value(arel, name = nil, binds = [])
|
43
|
-
|
44
|
-
result.values.first
|
45
|
-
end
|
82
|
+
single_value_from_rows(select_rows(arel, name, binds))
|
46
83
|
end
|
47
84
|
|
48
85
|
# Returns an array of the values of the first column in a select:
|
49
86
|
# select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
|
50
|
-
def select_values(arel, name = nil)
|
51
|
-
arel,
|
52
|
-
select_rows(to_sql(arel, binds), name, binds).map(&:first)
|
87
|
+
def select_values(arel, name = nil, binds = [])
|
88
|
+
select_rows(arel, name, binds).map(&:first)
|
53
89
|
end
|
54
90
|
|
55
91
|
# Returns an array of arrays containing the field values.
|
56
92
|
# Order is the same as that returned by +columns+.
|
57
|
-
def select_rows(
|
93
|
+
def select_rows(arel, name = nil, binds = [])
|
94
|
+
select_all(arel, name, binds).rows
|
95
|
+
end
|
96
|
+
|
97
|
+
def query_value(sql, name = nil) # :nodoc:
|
98
|
+
single_value_from_rows(query(sql, name))
|
99
|
+
end
|
100
|
+
|
101
|
+
def query_values(sql, name = nil) # :nodoc:
|
102
|
+
query(sql, name).map(&:first)
|
58
103
|
end
|
59
|
-
undef_method :select_rows
|
60
104
|
|
61
|
-
|
105
|
+
def query(sql, name = nil) # :nodoc:
|
106
|
+
exec_query(sql, name).rows
|
107
|
+
end
|
108
|
+
|
109
|
+
# Executes the SQL statement in the context of this connection and returns
|
110
|
+
# the raw result from the connection adapter.
|
111
|
+
# Note: depending on your database connector, the result returned by this
|
112
|
+
# method may be manually memory managed. Consider using the exec_query
|
113
|
+
# wrapper instead.
|
62
114
|
def execute(sql, name = nil)
|
115
|
+
raise NotImplementedError
|
63
116
|
end
|
64
|
-
undef_method :execute
|
65
117
|
|
66
118
|
# Executes +sql+ statement in the context of this connection using
|
67
119
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
68
120
|
# the executed +sql+ statement.
|
69
|
-
def exec_query(sql, name =
|
121
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
122
|
+
raise NotImplementedError
|
70
123
|
end
|
71
124
|
|
72
125
|
# Executes insert +sql+ statement in the context of this connection using
|
73
126
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
74
127
|
# the executed +sql+ statement.
|
75
|
-
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
128
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
129
|
+
sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
|
76
130
|
exec_query(sql, name, binds)
|
77
131
|
end
|
78
132
|
|
79
133
|
# Executes delete +sql+ statement in the context of this connection using
|
80
134
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
81
135
|
# the executed +sql+ statement.
|
82
|
-
def exec_delete(sql, name, binds)
|
136
|
+
def exec_delete(sql, name = nil, binds = [])
|
83
137
|
exec_query(sql, name, binds)
|
84
138
|
end
|
85
139
|
|
@@ -91,39 +145,43 @@ module ActiveRecord
|
|
91
145
|
# Executes update +sql+ statement in the context of this connection using
|
92
146
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
93
147
|
# the executed +sql+ statement.
|
94
|
-
def exec_update(sql, name, binds)
|
148
|
+
def exec_update(sql, name = nil, binds = [])
|
95
149
|
exec_query(sql, name, binds)
|
96
150
|
end
|
97
151
|
|
98
|
-
#
|
152
|
+
# Executes an INSERT query and returns the new record's ID
|
99
153
|
#
|
100
|
-
# +id_value+ will be returned unless the value is nil
|
154
|
+
# +id_value+ will be returned unless the value is +nil+, in
|
101
155
|
# which case the database will attempt to calculate the last inserted
|
102
156
|
# id and return that value.
|
103
157
|
#
|
104
158
|
# If the next id was calculated in advance (as in Oracle), it should be
|
105
159
|
# passed in as +id_value+.
|
106
160
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
107
|
-
sql, binds =
|
108
|
-
value
|
161
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
162
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
109
163
|
id_value || last_inserted_id(value)
|
110
164
|
end
|
165
|
+
alias create insert
|
111
166
|
|
112
167
|
# Executes the update statement and returns the number of rows affected.
|
113
168
|
def update(arel, name = nil, binds = [])
|
114
|
-
|
169
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
170
|
+
exec_update(sql, name, binds)
|
115
171
|
end
|
116
172
|
|
117
173
|
# Executes the delete statement and returns the number of rows affected.
|
118
174
|
def delete(arel, name = nil, binds = [])
|
119
|
-
|
175
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
176
|
+
exec_delete(sql, name, binds)
|
120
177
|
end
|
121
178
|
|
122
179
|
# Returns +true+ when the connection adapter supports prepared statement
|
123
180
|
# caching, otherwise returns +false+
|
124
|
-
def supports_statement_cache?
|
125
|
-
|
181
|
+
def supports_statement_cache? # :nodoc:
|
182
|
+
true
|
126
183
|
end
|
184
|
+
deprecate :supports_statement_cache?
|
127
185
|
|
128
186
|
# Runs the given block in a database transaction, and returns the result
|
129
187
|
# of the block.
|
@@ -136,7 +194,7 @@ module ActiveRecord
|
|
136
194
|
#
|
137
195
|
# In order to get around this problem, #transaction will emulate the effect
|
138
196
|
# of nested transactions, by using savepoints:
|
139
|
-
#
|
197
|
+
# https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
|
140
198
|
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
141
199
|
# supports savepoints.
|
142
200
|
#
|
@@ -188,29 +246,25 @@ module ActiveRecord
|
|
188
246
|
# You should consult the documentation for your database to understand the
|
189
247
|
# semantics of these different levels:
|
190
248
|
#
|
191
|
-
# *
|
192
|
-
# * https://dev.mysql.com/doc/refman/5.
|
249
|
+
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
|
250
|
+
# * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
|
193
251
|
#
|
194
|
-
# An
|
252
|
+
# An ActiveRecord::TransactionIsolationError will be raised if:
|
195
253
|
#
|
196
254
|
# * The adapter does not support setting the isolation level
|
197
255
|
# * You are joining an existing open transaction
|
198
256
|
# * You are creating a nested (savepoint) transaction
|
199
257
|
#
|
200
|
-
# The
|
201
|
-
# isolation level.
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
options.assert_valid_keys :requires_new, :joinable, :isolation
|
206
|
-
|
207
|
-
if !options[:requires_new] && current_transaction.joinable?
|
208
|
-
if options[:isolation]
|
258
|
+
# The mysql2 and postgresql adapters support setting the transaction
|
259
|
+
# isolation level.
|
260
|
+
def transaction(requires_new: nil, isolation: nil, joinable: true)
|
261
|
+
if !requires_new && current_transaction.joinable?
|
262
|
+
if isolation
|
209
263
|
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
210
264
|
end
|
211
265
|
yield
|
212
266
|
else
|
213
|
-
transaction_manager.within_new_transaction(
|
267
|
+
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
|
214
268
|
end
|
215
269
|
rescue ActiveRecord::Rollback
|
216
270
|
# rollbacks are silently swallowed
|
@@ -225,7 +279,7 @@ module ActiveRecord
|
|
225
279
|
end
|
226
280
|
|
227
281
|
def reset_transaction #:nodoc:
|
228
|
-
@transaction_manager = TransactionManager.new(self)
|
282
|
+
@transaction_manager = ConnectionAdapters::TransactionManager.new(self)
|
229
283
|
end
|
230
284
|
|
231
285
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
@@ -234,6 +288,10 @@ module ActiveRecord
|
|
234
288
|
current_transaction.add_record(record)
|
235
289
|
end
|
236
290
|
|
291
|
+
def transaction_state
|
292
|
+
current_transaction.state
|
293
|
+
end
|
294
|
+
|
237
295
|
# Begins the transaction (and turns off auto-committing).
|
238
296
|
def begin_db_transaction() end
|
239
297
|
|
@@ -258,7 +316,15 @@ module ActiveRecord
|
|
258
316
|
|
259
317
|
# Rolls back the transaction (and turns on auto-committing). Must be
|
260
318
|
# done if the transaction block raises an exception or returns false.
|
261
|
-
def rollback_db_transaction
|
319
|
+
def rollback_db_transaction
|
320
|
+
exec_rollback_db_transaction
|
321
|
+
end
|
322
|
+
|
323
|
+
def exec_rollback_db_transaction() end #:nodoc:
|
324
|
+
|
325
|
+
def rollback_to_savepoint(name = nil)
|
326
|
+
exec_rollback_to_savepoint(name)
|
327
|
+
end
|
262
328
|
|
263
329
|
def default_sequence_name(table, column)
|
264
330
|
nil
|
@@ -271,16 +337,65 @@ module ActiveRecord
|
|
271
337
|
|
272
338
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
273
339
|
# something beyond a simple insert (eg. Oracle).
|
340
|
+
# Most of adapters should implement `insert_fixtures` that leverages bulk SQL insert.
|
341
|
+
# We keep this method to provide fallback
|
342
|
+
# for databases like sqlite that do not support bulk inserts.
|
274
343
|
def insert_fixture(fixture, table_name)
|
344
|
+
fixture = fixture.stringify_keys
|
345
|
+
|
275
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
|
276
355
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
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]
|
281
361
|
end
|
282
362
|
|
283
|
-
|
363
|
+
manager = Arel::InsertManager.new
|
364
|
+
manager.into(table)
|
365
|
+
manager.insert(values)
|
366
|
+
execute manager.to_sql, "Fixture Insert"
|
367
|
+
end
|
368
|
+
|
369
|
+
# Inserts a set of fixtures into the table. Overridden in adapters that require
|
370
|
+
# something beyond a simple insert (eg. Oracle).
|
371
|
+
def insert_fixtures(fixtures, table_name)
|
372
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
373
|
+
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
374
|
+
Consider using `insert_fixtures_set` for performance improvement.
|
375
|
+
MSG
|
376
|
+
return if fixtures.empty?
|
377
|
+
|
378
|
+
execute(build_fixture_sql(fixtures, table_name), "Fixtures Insert")
|
379
|
+
end
|
380
|
+
|
381
|
+
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
382
|
+
fixture_inserts = fixture_set.map do |table_name, fixtures|
|
383
|
+
next if fixtures.empty?
|
384
|
+
|
385
|
+
build_fixture_sql(fixtures, table_name)
|
386
|
+
end.compact
|
387
|
+
|
388
|
+
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name table}".dup }
|
389
|
+
total_sql = Array.wrap(combine_multi_statements(table_deletes + fixture_inserts))
|
390
|
+
|
391
|
+
disable_referential_integrity do
|
392
|
+
transaction(requires_new: true) do
|
393
|
+
total_sql.each do |sql|
|
394
|
+
execute sql, "Fixtures Load"
|
395
|
+
yield if block_given?
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
284
399
|
end
|
285
400
|
|
286
401
|
def empty_insert_statement_value
|
@@ -290,17 +405,12 @@ module ActiveRecord
|
|
290
405
|
# Sanitizes the given LIMIT parameter in order to prevent SQL injection.
|
291
406
|
#
|
292
407
|
# The +limit+ may be anything that can evaluate to a string via #to_s. It
|
293
|
-
# should look like an integer, or
|
294
|
-
# an Arel SQL literal.
|
408
|
+
# should look like an integer, or an Arel SQL literal.
|
295
409
|
#
|
296
410
|
# Returns Integer and Arel::Nodes::SqlLiteral limits as is.
|
297
|
-
# Returns the sanitized limit parameter, either as an integer, or as a
|
298
|
-
# string which contains a comma-delimited list of integers.
|
299
411
|
def sanitize_limit(limit)
|
300
412
|
if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
|
301
413
|
limit
|
302
|
-
elsif limit.to_s.include?(',')
|
303
|
-
Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
|
304
414
|
else
|
305
415
|
Integer(limit)
|
306
416
|
end
|
@@ -309,20 +419,52 @@ module ActiveRecord
|
|
309
419
|
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
|
310
420
|
# on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
|
311
421
|
# an UPDATE statement, so in the MySQL adapters we redefine this to do that.
|
312
|
-
def join_to_update(update, select)
|
313
|
-
key = update.key
|
422
|
+
def join_to_update(update, select, key) # :nodoc:
|
314
423
|
subselect = subquery_for(key, select)
|
315
424
|
|
316
425
|
update.where key.in(subselect)
|
317
426
|
end
|
427
|
+
alias join_to_delete join_to_update
|
318
428
|
|
319
|
-
|
320
|
-
|
429
|
+
private
|
430
|
+
def default_insert_value(column)
|
431
|
+
Arel.sql("DEFAULT")
|
432
|
+
end
|
321
433
|
|
322
|
-
|
323
|
-
|
434
|
+
def build_fixture_sql(fixtures, table_name)
|
435
|
+
columns = schema_cache.columns_hash(table_name)
|
436
|
+
|
437
|
+
values = fixtures.map do |fixture|
|
438
|
+
fixture = fixture.stringify_keys
|
439
|
+
|
440
|
+
unknown_columns = fixture.keys - columns.keys
|
441
|
+
if unknown_columns.any?
|
442
|
+
raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
|
443
|
+
end
|
444
|
+
|
445
|
+
columns.map do |name, column|
|
446
|
+
if fixture.key?(name)
|
447
|
+
type = lookup_cast_type_from_column(column)
|
448
|
+
bind = Relation::QueryAttribute.new(name, fixture[name], type)
|
449
|
+
with_yaml_fallback(bind.value_for_database)
|
450
|
+
else
|
451
|
+
default_insert_value(column)
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
table = Arel::Table.new(table_name)
|
457
|
+
manager = Arel::InsertManager.new
|
458
|
+
manager.into(table)
|
459
|
+
columns.each_key { |column| manager.columns << table[column] }
|
460
|
+
manager.values = manager.create_values_list(values)
|
324
461
|
|
325
|
-
|
462
|
+
manager.to_sql
|
463
|
+
end
|
464
|
+
|
465
|
+
def combine_multi_statements(total_sql)
|
466
|
+
total_sql.join(";\n")
|
467
|
+
end
|
326
468
|
|
327
469
|
# Returns a subquery for the given key using the join information.
|
328
470
|
def subquery_for(key, select)
|
@@ -333,40 +475,65 @@ module ActiveRecord
|
|
333
475
|
|
334
476
|
# Returns an ActiveRecord::Result instance.
|
335
477
|
def select(sql, name = nil, binds = [])
|
336
|
-
exec_query(sql, name, binds)
|
478
|
+
exec_query(sql, name, binds, prepare: false)
|
337
479
|
end
|
338
480
|
|
481
|
+
def select_prepared(sql, name = nil, binds = [])
|
482
|
+
exec_query(sql, name, binds, prepare: true)
|
483
|
+
end
|
339
484
|
|
340
|
-
|
341
|
-
|
342
|
-
execute(sql, name)
|
343
|
-
id_value
|
485
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
486
|
+
[sql, binds]
|
344
487
|
end
|
345
488
|
|
346
|
-
|
347
|
-
|
348
|
-
execute(sql, name)
|
489
|
+
def last_inserted_id(result)
|
490
|
+
single_value_from_rows(result.rows)
|
349
491
|
end
|
350
492
|
|
351
|
-
|
352
|
-
|
353
|
-
|
493
|
+
def single_value_from_rows(rows)
|
494
|
+
row = rows.first
|
495
|
+
row && row.first
|
354
496
|
end
|
355
497
|
|
356
|
-
def
|
357
|
-
|
498
|
+
def arel_from_relation(relation)
|
499
|
+
if relation.is_a?(Relation)
|
500
|
+
relation.arel
|
501
|
+
else
|
502
|
+
relation
|
503
|
+
end
|
358
504
|
end
|
359
505
|
|
360
|
-
|
361
|
-
|
362
|
-
|
506
|
+
# Fixture value is quoted by Arel, however scalar values
|
507
|
+
# are not quotable. In this case we want to convert
|
508
|
+
# the column value to YAML.
|
509
|
+
def with_yaml_fallback(value)
|
510
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
511
|
+
YAML.dump(value)
|
512
|
+
else
|
513
|
+
value
|
514
|
+
end
|
363
515
|
end
|
364
516
|
|
365
|
-
|
366
|
-
|
367
|
-
|
517
|
+
class PartialQueryCollector
|
518
|
+
def initialize
|
519
|
+
@parts = []
|
520
|
+
@binds = []
|
521
|
+
end
|
522
|
+
|
523
|
+
def <<(str)
|
524
|
+
@parts << str
|
525
|
+
self
|
526
|
+
end
|
527
|
+
|
528
|
+
def add_bind(obj)
|
529
|
+
@binds << obj
|
530
|
+
@parts << Arel::Nodes::BindParam.new(1)
|
531
|
+
self
|
532
|
+
end
|
533
|
+
|
534
|
+
def value
|
535
|
+
[@parts, @binds]
|
368
536
|
end
|
369
|
-
[relation, binds]
|
370
537
|
end
|
371
538
|
end
|
372
539
|
end
|