activerecord 3.2.19 → 5.0.0
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 +7 -0
- data/CHANGELOG.md +1715 -604
- data/MIT-LICENSE +2 -2
- data/README.rdoc +40 -45
- data/examples/performance.rb +33 -22
- data/examples/simple.rb +3 -4
- data/lib/active_record/aggregations.rb +76 -51
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +54 -40
- data/lib/active_record/associations/association.rb +76 -56
- data/lib/active_record/associations/association_scope.rb +125 -93
- data/lib/active_record/associations/belongs_to_association.rb +57 -28
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +120 -32
- data/lib/active_record/associations/builder/belongs_to.rb +115 -62
- data/lib/active_record/associations/builder/collection_association.rb +61 -53
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
- data/lib/active_record/associations/builder/has_many.rb +9 -65
- data/lib/active_record/associations/builder/has_one.rb +18 -52
- data/lib/active_record/associations/builder/singular_association.rb +18 -19
- data/lib/active_record/associations/collection_association.rb +268 -186
- data/lib/active_record/associations/collection_proxy.rb +1003 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +81 -41
- data/lib/active_record/associations/has_many_through_association.rb +76 -55
- data/lib/active_record/associations/has_one_association.rb +51 -21
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +239 -155
- data/lib/active_record/associations/preloader/association.rb +97 -62
- data/lib/active_record/associations/preloader/collection_association.rb +2 -8
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +75 -33
- data/lib/active_record/associations/preloader.rb +111 -79
- data/lib/active_record/associations/singular_association.rb +35 -13
- data/lib/active_record/associations/through_association.rb +41 -19
- data/lib/active_record/associations.rb +727 -501
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +213 -0
- data/lib/active_record/attribute_assignment.rb +32 -162
- data/lib/active_record/attribute_decorators.rb +67 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -61
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +7 -6
- data/lib/active_record/attribute_methods/read.rb +56 -117
- data/lib/active_record/attribute_methods/serialization.rb +43 -96
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
- data/lib/active_record/attribute_methods/write.rb +34 -45
- data/lib/active_record/attribute_methods.rb +333 -144
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +108 -0
- data/lib/active_record/attribute_set.rb +108 -0
- data/lib/active_record/attributes.rb +265 -0
- data/lib/active_record/autosave_association.rb +285 -223
- data/lib/active_record/base.rb +95 -490
- data/lib/active_record/callbacks.rb +95 -61
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +28 -19
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
- data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
- data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
- data/lib/active_record/connection_adapters/column.rb +30 -259
- data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
- data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
- data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +155 -0
- data/lib/active_record/core.rb +561 -0
- data/lib/active_record/counter_cache.rb +146 -105
- data/lib/active_record/dynamic_matchers.rb +101 -64
- data/lib/active_record/enum.rb +234 -0
- data/lib/active_record/errors.rb +153 -56
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +10 -6
- data/lib/active_record/fixture_set/file.rb +77 -0
- data/lib/active_record/fixtures.rb +355 -232
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +144 -79
- data/lib/active_record/integration.rb +66 -13
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +77 -56
- data/lib/active_record/locking/pessimistic.rb +6 -6
- data/lib/active_record/log_subscriber.rb +53 -28
- data/lib/active_record/migration/command_recorder.rb +166 -33
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +792 -264
- data/lib/active_record/model_schema.rb +192 -130
- data/lib/active_record/nested_attributes.rb +238 -145
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +89 -0
- data/lib/active_record/persistence.rb +357 -157
- data/lib/active_record/query_cache.rb +22 -43
- data/lib/active_record/querying.rb +34 -23
- data/lib/active_record/railtie.rb +88 -48
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +5 -4
- data/lib/active_record/railties/databases.rake +170 -422
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -5
- data/lib/active_record/reflection.rb +715 -189
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +203 -50
- data/lib/active_record/relation/calculations.rb +203 -194
- data/lib/active_record/relation/delegation.rb +103 -25
- data/lib/active_record/relation/finder_methods.rb +457 -261
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +167 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +153 -48
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +1019 -194
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +46 -150
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +450 -245
- data/lib/active_record/result.rb +104 -12
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +120 -94
- data/lib/active_record/schema.rb +28 -18
- data/lib/active_record/schema_dumper.rb +141 -74
- data/lib/active_record/schema_migration.rb +50 -0
- data/lib/active_record/scoping/default.rb +64 -57
- data/lib/active_record/scoping/named.rb +93 -108
- data/lib/active_record/scoping.rb +73 -121
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +7 -5
- data/lib/active_record/statement_cache.rb +113 -0
- data/lib/active_record/store.rb +173 -15
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +313 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
- data/lib/active_record/timestamp.rb +42 -24
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +233 -105
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +7 -0
- data/lib/active_record/type/date_time.rb +7 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +63 -0
- data/lib/active_record/type/time.rb +20 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type.rb +72 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +33 -18
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +66 -0
- data/lib/active_record/validations/uniqueness.rb +128 -68
- data/lib/active_record/validations.rb +48 -40
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +71 -47
- data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
- data/lib/rails/generators/active_record/migration.rb +18 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +188 -134
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -17,6 +17,15 @@ module ActiveRecord
|
|
17
17
|
64
|
18
18
|
end
|
19
19
|
|
20
|
+
# Returns the maximum allowed length for an index name. This
|
21
|
+
# limit is enforced by \Rails and is less than or equal to
|
22
|
+
# #index_name_length. The gap between
|
23
|
+
# #index_name_length is to allow internal \Rails
|
24
|
+
# operations to use prefixes in temporary operations.
|
25
|
+
def allowed_index_name_length
|
26
|
+
index_name_length
|
27
|
+
end
|
28
|
+
|
20
29
|
# Returns the maximum length of an index name.
|
21
30
|
def index_name_length
|
22
31
|
64
|
@@ -1,83 +1,117 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionAdapters # :nodoc:
|
3
3
|
module DatabaseStatements
|
4
|
+
def initialize
|
5
|
+
super
|
6
|
+
reset_transaction
|
7
|
+
end
|
8
|
+
|
4
9
|
# Converts an arel AST to SQL
|
5
10
|
def to_sql(arel, binds = [])
|
6
11
|
if arel.respond_to?(:ast)
|
7
|
-
visitor.accept(arel.ast)
|
8
|
-
|
9
|
-
end
|
12
|
+
collected = visitor.accept(arel.ast, collector)
|
13
|
+
collected.compile(binds.dup, self)
|
10
14
|
else
|
11
15
|
arel
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
15
|
-
#
|
16
|
-
#
|
17
|
-
def
|
18
|
-
|
19
|
+
# This is used in the StatementCache object. It returns an object that
|
20
|
+
# can be used to query the database repeatedly.
|
21
|
+
def cacheable_query(arel) # :nodoc:
|
22
|
+
if prepared_statements
|
23
|
+
ActiveRecord::StatementCache.query visitor, arel.ast
|
24
|
+
else
|
25
|
+
ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns an ActiveRecord::Result instance.
|
30
|
+
def select_all(arel, name = nil, binds = [], preparable: nil)
|
31
|
+
arel, binds = binds_from_relation arel, binds
|
32
|
+
sql = to_sql(arel, binds)
|
33
|
+
if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
|
34
|
+
preparable = false
|
35
|
+
else
|
36
|
+
preparable = visitor.preparable
|
37
|
+
end
|
38
|
+
if prepared_statements && preparable
|
39
|
+
select_prepared(sql, name, binds)
|
40
|
+
else
|
41
|
+
select(sql, name, binds)
|
42
|
+
end
|
19
43
|
end
|
20
44
|
|
21
45
|
# Returns a record hash with the column names as keys and column values
|
22
46
|
# as values.
|
23
|
-
def select_one(arel, name = nil)
|
24
|
-
|
25
|
-
result.first if result
|
47
|
+
def select_one(arel, name = nil, binds = [])
|
48
|
+
select_all(arel, name, binds).first
|
26
49
|
end
|
27
50
|
|
28
51
|
# Returns a single value from a record
|
29
|
-
def select_value(arel, name = nil)
|
30
|
-
|
31
|
-
|
52
|
+
def select_value(arel, name = nil, binds = [])
|
53
|
+
arel, binds = binds_from_relation arel, binds
|
54
|
+
if result = select_rows(to_sql(arel, binds), name, binds).first
|
55
|
+
result.first
|
32
56
|
end
|
33
57
|
end
|
34
58
|
|
35
59
|
# Returns an array of the values of the first column in a select:
|
36
60
|
# select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
|
37
|
-
def select_values(arel, name = nil)
|
38
|
-
|
39
|
-
|
61
|
+
def select_values(arel, name = nil, binds = [])
|
62
|
+
arel, binds = binds_from_relation arel, binds
|
63
|
+
select_rows(to_sql(arel, binds), name, binds).map(&:first)
|
40
64
|
end
|
41
65
|
|
42
66
|
# Returns an array of arrays containing the field values.
|
43
67
|
# Order is the same as that returned by +columns+.
|
44
|
-
def select_rows(sql, name = nil)
|
68
|
+
def select_rows(sql, name = nil, binds = [])
|
69
|
+
exec_query(sql, name, binds).rows
|
45
70
|
end
|
46
|
-
undef_method :select_rows
|
47
71
|
|
48
|
-
# Executes the SQL statement in the context of this connection
|
72
|
+
# Executes the SQL statement in the context of this connection and returns
|
73
|
+
# the raw result from the connection adapter.
|
74
|
+
# Note: depending on your database connector, the result returned by this
|
75
|
+
# method may be manually memory managed. Consider using the exec_query
|
76
|
+
# wrapper instead.
|
49
77
|
def execute(sql, name = nil)
|
78
|
+
raise NotImplementedError
|
50
79
|
end
|
51
|
-
undef_method :execute
|
52
80
|
|
53
81
|
# Executes +sql+ statement in the context of this connection using
|
54
82
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
55
83
|
# the executed +sql+ statement.
|
56
|
-
def exec_query(sql, name = 'SQL', binds = [])
|
84
|
+
def exec_query(sql, name = 'SQL', binds = [], prepare: false)
|
85
|
+
raise NotImplementedError
|
57
86
|
end
|
58
87
|
|
59
88
|
# Executes insert +sql+ statement in the context of this connection using
|
60
|
-
# +binds+ as the bind substitutes. +name+ is
|
89
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
61
90
|
# the executed +sql+ statement.
|
62
|
-
def exec_insert(sql, name, binds)
|
91
|
+
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
63
92
|
exec_query(sql, name, binds)
|
64
93
|
end
|
65
94
|
|
66
95
|
# Executes delete +sql+ statement in the context of this connection using
|
67
|
-
# +binds+ as the bind substitutes. +name+ is
|
96
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
68
97
|
# the executed +sql+ statement.
|
69
98
|
def exec_delete(sql, name, binds)
|
70
99
|
exec_query(sql, name, binds)
|
71
100
|
end
|
72
101
|
|
102
|
+
# Executes the truncate statement.
|
103
|
+
def truncate(table_name, name = nil)
|
104
|
+
raise NotImplementedError
|
105
|
+
end
|
106
|
+
|
73
107
|
# Executes update +sql+ statement in the context of this connection using
|
74
|
-
# +binds+ as the bind substitutes. +name+ is
|
108
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
75
109
|
# the executed +sql+ statement.
|
76
110
|
def exec_update(sql, name, binds)
|
77
111
|
exec_query(sql, name, binds)
|
78
112
|
end
|
79
113
|
|
80
|
-
#
|
114
|
+
# Executes an INSERT query and returns the new record's ID
|
81
115
|
#
|
82
116
|
# +id_value+ will be returned unless the value is nil, in
|
83
117
|
# which case the database will attempt to calculate the last inserted
|
@@ -86,34 +120,27 @@ module ActiveRecord
|
|
86
120
|
# If the next id was calculated in advance (as in Oracle), it should be
|
87
121
|
# passed in as +id_value+.
|
88
122
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
89
|
-
sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
|
90
|
-
value
|
123
|
+
sql, binds, pk, sequence_name = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
|
124
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
91
125
|
id_value || last_inserted_id(value)
|
92
126
|
end
|
127
|
+
alias create insert
|
128
|
+
alias insert_sql insert
|
129
|
+
deprecate insert_sql: :insert
|
93
130
|
|
94
131
|
# Executes the update statement and returns the number of rows affected.
|
95
132
|
def update(arel, name = nil, binds = [])
|
96
133
|
exec_update(to_sql(arel, binds), name, binds)
|
97
134
|
end
|
135
|
+
alias update_sql update
|
136
|
+
deprecate update_sql: :update
|
98
137
|
|
99
138
|
# Executes the delete statement and returns the number of rows affected.
|
100
139
|
def delete(arel, name = nil, binds = [])
|
101
140
|
exec_delete(to_sql(arel, binds), name, binds)
|
102
141
|
end
|
103
|
-
|
104
|
-
|
105
|
-
# by querying the database driver, and does not use the transaction
|
106
|
-
# house-keeping information recorded by #increment_open_transactions and
|
107
|
-
# friends.
|
108
|
-
#
|
109
|
-
# Returns true if there is no transaction active, false if there is a
|
110
|
-
# transaction active, and nil if this information is unknown.
|
111
|
-
#
|
112
|
-
# Not all adapters supports transaction state introspection. Currently,
|
113
|
-
# only the PostgreSQL adapter supports this.
|
114
|
-
def outside_transaction?
|
115
|
-
nil
|
116
|
-
end
|
142
|
+
alias delete_sql delete
|
143
|
+
deprecate delete_sql: :delete
|
117
144
|
|
118
145
|
# Returns +true+ when the connection adapter supports prepared statement
|
119
146
|
# caching, otherwise returns +false+
|
@@ -132,8 +159,9 @@ module ActiveRecord
|
|
132
159
|
#
|
133
160
|
# In order to get around this problem, #transaction will emulate the effect
|
134
161
|
# of nested transactions, by using savepoints:
|
135
|
-
# http://dev.mysql.com/doc/refman/5.
|
136
|
-
# Savepoints are supported by MySQL and PostgreSQL
|
162
|
+
# http://dev.mysql.com/doc/refman/5.7/en/savepoint.html
|
163
|
+
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
164
|
+
# supports savepoints.
|
137
165
|
#
|
138
166
|
# It is safe to call this method if a database transaction is already open,
|
139
167
|
# i.e. if #transaction is called within another #transaction block. In case
|
@@ -158,101 +186,110 @@ module ActiveRecord
|
|
158
186
|
# already-automatically-released savepoints:
|
159
187
|
#
|
160
188
|
# Model.connection.transaction do # BEGIN
|
161
|
-
# Model.connection.transaction(:
|
189
|
+
# Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
|
162
190
|
# Model.connection.create_table(...)
|
163
191
|
# # active_record_1 now automatically released
|
164
192
|
# end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
|
165
193
|
# end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
else
|
202
|
-
rollback_to_savepoint
|
203
|
-
rollback_transaction_records(false)
|
204
|
-
end
|
194
|
+
#
|
195
|
+
# == Transaction isolation
|
196
|
+
#
|
197
|
+
# If your database supports setting the isolation level for a transaction, you can set
|
198
|
+
# it like so:
|
199
|
+
#
|
200
|
+
# Post.transaction(isolation: :serializable) do
|
201
|
+
# # ...
|
202
|
+
# end
|
203
|
+
#
|
204
|
+
# Valid isolation levels are:
|
205
|
+
#
|
206
|
+
# * <tt>:read_uncommitted</tt>
|
207
|
+
# * <tt>:read_committed</tt>
|
208
|
+
# * <tt>:repeatable_read</tt>
|
209
|
+
# * <tt>:serializable</tt>
|
210
|
+
#
|
211
|
+
# You should consult the documentation for your database to understand the
|
212
|
+
# semantics of these different levels:
|
213
|
+
#
|
214
|
+
# * http://www.postgresql.org/docs/current/static/transaction-iso.html
|
215
|
+
# * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
|
216
|
+
#
|
217
|
+
# An ActiveRecord::TransactionIsolationError will be raised if:
|
218
|
+
#
|
219
|
+
# * The adapter does not support setting the isolation level
|
220
|
+
# * You are joining an existing open transaction
|
221
|
+
# * You are creating a nested (savepoint) transaction
|
222
|
+
#
|
223
|
+
# The mysql2 and postgresql adapters support setting the transaction
|
224
|
+
# isolation level.
|
225
|
+
def transaction(requires_new: nil, isolation: nil, joinable: true)
|
226
|
+
if !requires_new && current_transaction.joinable?
|
227
|
+
if isolation
|
228
|
+
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
205
229
|
end
|
206
|
-
|
230
|
+
yield
|
231
|
+
else
|
232
|
+
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
|
207
233
|
end
|
208
|
-
|
209
|
-
|
234
|
+
rescue ActiveRecord::Rollback
|
235
|
+
# rollbacks are silently swallowed
|
236
|
+
end
|
210
237
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
save_point_records = @_current_transaction_records.pop
|
222
|
-
unless save_point_records.blank?
|
223
|
-
@_current_transaction_records.push([]) if @_current_transaction_records.empty?
|
224
|
-
@_current_transaction_records.last.concat(save_point_records)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
rescue Exception => database_transaction_rollback
|
228
|
-
if open_transactions == 0
|
229
|
-
rollback_db_transaction
|
230
|
-
rollback_transaction_records(true)
|
231
|
-
else
|
232
|
-
rollback_to_savepoint
|
233
|
-
rollback_transaction_records(false)
|
234
|
-
end
|
235
|
-
raise
|
236
|
-
end
|
237
|
-
end
|
238
|
+
attr_reader :transaction_manager #:nodoc:
|
239
|
+
|
240
|
+
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction, :commit_transaction, :rollback_transaction, to: :transaction_manager
|
241
|
+
|
242
|
+
def transaction_open?
|
243
|
+
current_transaction.open?
|
244
|
+
end
|
245
|
+
|
246
|
+
def reset_transaction #:nodoc:
|
247
|
+
@transaction_manager = TransactionManager.new(self)
|
238
248
|
end
|
239
249
|
|
240
250
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
241
251
|
# can be called.
|
242
252
|
def add_transaction_record(record)
|
243
|
-
|
244
|
-
|
253
|
+
current_transaction.add_record(record)
|
254
|
+
end
|
255
|
+
|
256
|
+
def transaction_state
|
257
|
+
current_transaction.state
|
245
258
|
end
|
246
259
|
|
247
260
|
# Begins the transaction (and turns off auto-committing).
|
248
261
|
def begin_db_transaction() end
|
249
262
|
|
263
|
+
def transaction_isolation_levels
|
264
|
+
{
|
265
|
+
read_uncommitted: "READ UNCOMMITTED",
|
266
|
+
read_committed: "READ COMMITTED",
|
267
|
+
repeatable_read: "REPEATABLE READ",
|
268
|
+
serializable: "SERIALIZABLE"
|
269
|
+
}
|
270
|
+
end
|
271
|
+
|
272
|
+
# Begins the transaction with the isolation level set. Raises an error by
|
273
|
+
# default; adapters that support setting the isolation level should implement
|
274
|
+
# this method.
|
275
|
+
def begin_isolated_db_transaction(isolation)
|
276
|
+
raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
|
277
|
+
end
|
278
|
+
|
250
279
|
# Commits the transaction (and turns on auto-committing).
|
251
280
|
def commit_db_transaction() end
|
252
281
|
|
253
282
|
# Rolls back the transaction (and turns on auto-committing). Must be
|
254
283
|
# done if the transaction block raises an exception or returns false.
|
255
|
-
def rollback_db_transaction
|
284
|
+
def rollback_db_transaction
|
285
|
+
exec_rollback_db_transaction
|
286
|
+
end
|
287
|
+
|
288
|
+
def exec_rollback_db_transaction() end #:nodoc:
|
289
|
+
|
290
|
+
def rollback_to_savepoint(name = nil)
|
291
|
+
exec_rollback_to_savepoint(name)
|
292
|
+
end
|
256
293
|
|
257
294
|
def default_sequence_name(table, column)
|
258
295
|
nil
|
@@ -266,27 +303,31 @@ module ActiveRecord
|
|
266
303
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
267
304
|
# something beyond a simple insert (eg. Oracle).
|
268
305
|
def insert_fixture(fixture, table_name)
|
269
|
-
|
306
|
+
fixture = fixture.stringify_keys
|
270
307
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
308
|
+
columns = schema_cache.columns_hash(table_name)
|
309
|
+
binds = fixture.map do |name, value|
|
310
|
+
if column = columns[name]
|
311
|
+
type = lookup_cast_type_from_column(column)
|
312
|
+
Relation::QueryAttribute.new(name, value, type)
|
313
|
+
else
|
314
|
+
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
key_list = fixture.keys.map { |name| quote_column_name(name) }
|
318
|
+
value_list = prepare_binds_for_database(binds).map do |value|
|
319
|
+
begin
|
320
|
+
quote(value)
|
321
|
+
rescue TypeError
|
322
|
+
quote(YAML.dump(value))
|
323
|
+
end
|
275
324
|
end
|
276
325
|
|
277
326
|
execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
|
278
327
|
end
|
279
328
|
|
280
329
|
def empty_insert_statement_value
|
281
|
-
"VALUES
|
282
|
-
end
|
283
|
-
|
284
|
-
def case_sensitive_equality_operator
|
285
|
-
"="
|
286
|
-
end
|
287
|
-
|
288
|
-
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
|
289
|
-
"WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
|
330
|
+
"DEFAULT VALUES"
|
290
331
|
end
|
291
332
|
|
292
333
|
# Sanitizes the given LIMIT parameter in order to prevent SQL injection.
|
@@ -301,7 +342,7 @@ module ActiveRecord
|
|
301
342
|
def sanitize_limit(limit)
|
302
343
|
if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
|
303
344
|
limit
|
304
|
-
elsif limit.to_s
|
345
|
+
elsif limit.to_s.include?(',')
|
305
346
|
Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
|
306
347
|
else
|
307
348
|
Integer(limit)
|
@@ -309,82 +350,48 @@ module ActiveRecord
|
|
309
350
|
end
|
310
351
|
|
311
352
|
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
|
312
|
-
# on
|
313
|
-
# an UPDATE statement, so in the
|
314
|
-
def join_to_update(update, select)
|
315
|
-
subselect = select
|
316
|
-
subselect.projections = [update.key]
|
353
|
+
# on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
|
354
|
+
# an UPDATE statement, so in the MySQL adapters we redefine this to do that.
|
355
|
+
def join_to_update(update, select, key) # :nodoc:
|
356
|
+
subselect = subquery_for(key, select)
|
317
357
|
|
318
|
-
update.where
|
358
|
+
update.where key.in(subselect)
|
319
359
|
end
|
360
|
+
alias join_to_delete join_to_update
|
320
361
|
|
321
362
|
protected
|
322
|
-
# Returns an array of record hashes with the column names as keys and
|
323
|
-
# column values as values.
|
324
|
-
def select(sql, name = nil, binds = [])
|
325
|
-
end
|
326
|
-
undef_method :select
|
327
363
|
|
328
|
-
# Returns the
|
329
|
-
def
|
330
|
-
|
331
|
-
|
364
|
+
# Returns a subquery for the given key using the join information.
|
365
|
+
def subquery_for(key, select)
|
366
|
+
subselect = select.clone
|
367
|
+
subselect.projections = [key]
|
368
|
+
subselect
|
332
369
|
end
|
333
370
|
|
334
|
-
#
|
335
|
-
def
|
336
|
-
|
371
|
+
# Returns an ActiveRecord::Result instance.
|
372
|
+
def select(sql, name = nil, binds = [])
|
373
|
+
exec_query(sql, name, binds, prepare: false)
|
337
374
|
end
|
338
375
|
|
339
|
-
|
340
|
-
|
341
|
-
update_sql(sql, name)
|
376
|
+
def select_prepared(sql, name = nil, binds = [])
|
377
|
+
exec_query(sql, name, binds, prepare: true)
|
342
378
|
end
|
343
379
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
if rollback
|
348
|
-
records = @_current_transaction_records.flatten
|
349
|
-
@_current_transaction_records.clear
|
350
|
-
else
|
351
|
-
records = @_current_transaction_records.pop
|
352
|
-
end
|
380
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
381
|
+
[sql, binds, pk, sequence_name]
|
382
|
+
end
|
353
383
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
record.rolledback!(rollback)
|
358
|
-
rescue Exception => e
|
359
|
-
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
360
|
-
end
|
361
|
-
end
|
362
|
-
end
|
384
|
+
def last_inserted_id(result)
|
385
|
+
row = result.rows.first
|
386
|
+
row && row.first
|
363
387
|
end
|
364
388
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
@_current_transaction_records.clear
|
369
|
-
unless records.blank?
|
370
|
-
records.uniq.each do |record|
|
371
|
-
begin
|
372
|
-
record.committed!
|
373
|
-
rescue Exception => e
|
374
|
-
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
375
|
-
end
|
376
|
-
end
|
389
|
+
def binds_from_relation(relation, binds)
|
390
|
+
if relation.is_a?(Relation) && binds.empty?
|
391
|
+
relation, binds = relation.arel, relation.bound_attributes
|
377
392
|
end
|
393
|
+
[relation, binds]
|
378
394
|
end
|
379
|
-
|
380
|
-
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
381
|
-
[sql, binds]
|
382
|
-
end
|
383
|
-
|
384
|
-
def last_inserted_id(result)
|
385
|
-
row = result.rows.first
|
386
|
-
row && row.first
|
387
|
-
end
|
388
395
|
end
|
389
396
|
end
|
390
397
|
end
|
@@ -2,17 +2,17 @@ module ActiveRecord
|
|
2
2
|
module ConnectionAdapters # :nodoc:
|
3
3
|
module QueryCache
|
4
4
|
class << self
|
5
|
-
def included(base)
|
6
|
-
dirties_query_cache base, :insert, :update, :delete
|
5
|
+
def included(base) #:nodoc:
|
6
|
+
dirties_query_cache base, :insert, :update, :delete, :rollback_to_savepoint, :rollback_db_transaction
|
7
7
|
end
|
8
8
|
|
9
9
|
def dirties_query_cache(base, *method_names)
|
10
10
|
method_names.each do |method_name|
|
11
11
|
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
12
|
-
def #{method_name}(*)
|
13
|
-
clear_query_cache if @query_cache_enabled
|
14
|
-
super
|
15
|
-
end
|
12
|
+
def #{method_name}(*)
|
13
|
+
clear_query_cache if @query_cache_enabled
|
14
|
+
super
|
15
|
+
end
|
16
16
|
end_code
|
17
17
|
end
|
18
18
|
end
|
@@ -20,13 +20,19 @@ module ActiveRecord
|
|
20
20
|
|
21
21
|
attr_reader :query_cache, :query_cache_enabled
|
22
22
|
|
23
|
+
def initialize(*)
|
24
|
+
super
|
25
|
+
@query_cache = Hash.new { |h,sql| h[sql] = {} }
|
26
|
+
@query_cache_enabled = false
|
27
|
+
end
|
28
|
+
|
23
29
|
# Enable the query cache within the block.
|
24
30
|
def cache
|
25
31
|
old, @query_cache_enabled = @query_cache_enabled, true
|
26
32
|
yield
|
27
33
|
ensure
|
28
|
-
clear_query_cache
|
29
34
|
@query_cache_enabled = old
|
35
|
+
clear_query_cache unless @query_cache_enabled
|
30
36
|
end
|
31
37
|
|
32
38
|
def enable_query_cache!
|
@@ -55,36 +61,35 @@ module ActiveRecord
|
|
55
61
|
@query_cache.clear
|
56
62
|
end
|
57
63
|
|
58
|
-
def select_all(arel, name = nil, binds = [])
|
64
|
+
def select_all(arel, name = nil, binds = [], preparable: nil)
|
59
65
|
if @query_cache_enabled && !locked?(arel)
|
66
|
+
arel, binds = binds_from_relation arel, binds
|
60
67
|
sql = to_sql(arel, binds)
|
61
|
-
cache_sql(sql, binds) { super(sql, name, binds) }
|
68
|
+
cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
|
62
69
|
else
|
63
70
|
super
|
64
71
|
end
|
65
72
|
end
|
66
73
|
|
67
74
|
private
|
68
|
-
def cache_sql(sql, binds)
|
69
|
-
result =
|
70
|
-
if @query_cache[sql].key?(binds)
|
71
|
-
ActiveSupport::Notifications.instrument("sql.active_record",
|
72
|
-
:sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id)
|
73
|
-
@query_cache[sql][binds]
|
74
|
-
else
|
75
|
-
@query_cache[sql][binds] = yield
|
76
|
-
end
|
77
|
-
|
78
|
-
result.collect { |row| row.dup }
|
79
|
-
end
|
80
75
|
|
81
|
-
|
82
|
-
|
83
|
-
|
76
|
+
def cache_sql(sql, binds)
|
77
|
+
result =
|
78
|
+
if @query_cache[sql].key?(binds)
|
79
|
+
ActiveSupport::Notifications.instrument("sql.active_record",
|
80
|
+
:sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id)
|
81
|
+
@query_cache[sql][binds]
|
84
82
|
else
|
85
|
-
|
83
|
+
@query_cache[sql][binds] = yield
|
86
84
|
end
|
87
|
-
|
85
|
+
result.dup
|
86
|
+
end
|
87
|
+
|
88
|
+
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
|
89
|
+
# queries should not be cached.
|
90
|
+
def locked?(arel)
|
91
|
+
arel.respond_to?(:locked) && arel.locked
|
92
|
+
end
|
88
93
|
end
|
89
94
|
end
|
90
95
|
end
|