activerecord 4.2.0 → 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 +4 -4
- data/CHANGELOG.md +1537 -789
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record/aggregations.rb +37 -23
- data/lib/active_record/association_relation.rb +16 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +23 -9
- data/lib/active_record/associations/association_scope.rb +74 -102
- data/lib/active_record/associations/belongs_to_association.rb +26 -29
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +12 -20
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +61 -33
- data/lib/active_record/associations/collection_proxy.rb +81 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +15 -45
- data/lib/active_record/associations/has_one_association.rb +13 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
- data/lib/active_record/associations/join_dependency.rb +37 -21
- data/lib/active_record/associations/preloader/association.rb +51 -53
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +18 -8
- data/lib/active_record/associations/singular_association.rb +8 -8
- data/lib/active_record/associations/through_association.rb +22 -9
- data/lib/active_record/associations.rb +321 -212
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +79 -15
- data/lib/active_record/attribute_assignment.rb +20 -141
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
- data/lib/active_record/attribute_methods/dirty.rb +51 -81
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
- data/lib/active_record/attribute_methods/write.rb +14 -38
- data/lib/active_record/attribute_methods.rb +70 -45
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +37 -15
- data/lib/active_record/attribute_set.rb +34 -3
- data/lib/active_record/attributes.rb +199 -73
- data/lib/active_record/autosave_association.rb +73 -25
- data/lib/active_record/base.rb +35 -27
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- 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 +26 -177
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- 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 +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- 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 +150 -209
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +38 -15
- data/lib/active_record/core.rb +109 -114
- data/lib/active_record/counter_cache.rb +14 -25
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +115 -79
- data/lib/active_record/errors.rb +88 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +84 -46
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- 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 +3 -2
- data/lib/active_record/locking/optimistic.rb +27 -25
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +372 -114
- data/lib/active_record/model_schema.rb +128 -38
- data/lib/active_record/nested_attributes.rb +71 -32
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +124 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +28 -19
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +67 -51
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +318 -139
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +80 -102
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +167 -97
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +38 -41
- data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
- 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 +1 -1
- data/lib/active_record/relation/predicate_builder.rb +124 -82
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +323 -257
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -10
- 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 +176 -115
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -17
- data/lib/active_record/scoping/default.rb +24 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- 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 +59 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
- data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +159 -67
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -41
- data/lib/active_record/type/date_time.rb +2 -38
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- 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 +21 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type.rb +66 -17
- 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 +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +29 -18
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +9 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +60 -34
- 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/date.rb +0 -11
- 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/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- 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/decimal_without_scale.rb +0 -11
- 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/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -101
@@ -18,9 +18,9 @@ module ActiveRecord
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# Returns the maximum allowed length for an index name. This
|
21
|
-
# limit is enforced by
|
22
|
-
#
|
23
|
-
#
|
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
24
|
# operations to use prefixes in temporary operations.
|
25
25
|
def allowed_index_name_length
|
26
26
|
index_name_length
|
@@ -27,9 +27,19 @@ module ActiveRecord
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# Returns an ActiveRecord::Result instance.
|
30
|
-
def select_all(arel, name = nil, binds = [])
|
30
|
+
def select_all(arel, name = nil, binds = [], preparable: nil)
|
31
31
|
arel, binds = binds_from_relation arel, binds
|
32
|
-
|
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
|
33
43
|
end
|
34
44
|
|
35
45
|
# Returns a record hash with the column names as keys and column values
|
@@ -40,33 +50,39 @@ module ActiveRecord
|
|
40
50
|
|
41
51
|
# Returns a single value from a record
|
42
52
|
def select_value(arel, name = nil, binds = [])
|
43
|
-
|
44
|
-
|
53
|
+
arel, binds = binds_from_relation arel, binds
|
54
|
+
if result = select_rows(to_sql(arel, binds), name, binds).first
|
55
|
+
result.first
|
45
56
|
end
|
46
57
|
end
|
47
58
|
|
48
59
|
# Returns an array of the values of the first column in a select:
|
49
60
|
# select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
|
50
|
-
def select_values(arel, name = nil)
|
51
|
-
arel, binds = binds_from_relation arel,
|
61
|
+
def select_values(arel, name = nil, binds = [])
|
62
|
+
arel, binds = binds_from_relation arel, binds
|
52
63
|
select_rows(to_sql(arel, binds), name, binds).map(&:first)
|
53
64
|
end
|
54
65
|
|
55
66
|
# Returns an array of arrays containing the field values.
|
56
67
|
# Order is the same as that returned by +columns+.
|
57
68
|
def select_rows(sql, name = nil, binds = [])
|
69
|
+
exec_query(sql, name, binds).rows
|
58
70
|
end
|
59
|
-
undef_method :select_rows
|
60
71
|
|
61
|
-
# 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.
|
62
77
|
def execute(sql, name = nil)
|
78
|
+
raise NotImplementedError
|
63
79
|
end
|
64
|
-
undef_method :execute
|
65
80
|
|
66
81
|
# Executes +sql+ statement in the context of this connection using
|
67
82
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
68
83
|
# the executed +sql+ statement.
|
69
|
-
def exec_query(sql, name = 'SQL', binds = [])
|
84
|
+
def exec_query(sql, name = 'SQL', binds = [], prepare: false)
|
85
|
+
raise NotImplementedError
|
70
86
|
end
|
71
87
|
|
72
88
|
# Executes insert +sql+ statement in the context of this connection using
|
@@ -95,7 +111,7 @@ module ActiveRecord
|
|
95
111
|
exec_query(sql, name, binds)
|
96
112
|
end
|
97
113
|
|
98
|
-
#
|
114
|
+
# Executes an INSERT query and returns the new record's ID
|
99
115
|
#
|
100
116
|
# +id_value+ will be returned unless the value is nil, in
|
101
117
|
# which case the database will attempt to calculate the last inserted
|
@@ -104,20 +120,27 @@ module ActiveRecord
|
|
104
120
|
# If the next id was calculated in advance (as in Oracle), it should be
|
105
121
|
# passed in as +id_value+.
|
106
122
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
107
|
-
sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
|
108
|
-
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)
|
109
125
|
id_value || last_inserted_id(value)
|
110
126
|
end
|
127
|
+
alias create insert
|
128
|
+
alias insert_sql insert
|
129
|
+
deprecate insert_sql: :insert
|
111
130
|
|
112
131
|
# Executes the update statement and returns the number of rows affected.
|
113
132
|
def update(arel, name = nil, binds = [])
|
114
133
|
exec_update(to_sql(arel, binds), name, binds)
|
115
134
|
end
|
135
|
+
alias update_sql update
|
136
|
+
deprecate update_sql: :update
|
116
137
|
|
117
138
|
# Executes the delete statement and returns the number of rows affected.
|
118
139
|
def delete(arel, name = nil, binds = [])
|
119
140
|
exec_delete(to_sql(arel, binds), name, binds)
|
120
141
|
end
|
142
|
+
alias delete_sql delete
|
143
|
+
deprecate delete_sql: :delete
|
121
144
|
|
122
145
|
# Returns +true+ when the connection adapter supports prepared statement
|
123
146
|
# caching, otherwise returns +false+
|
@@ -136,7 +159,7 @@ module ActiveRecord
|
|
136
159
|
#
|
137
160
|
# In order to get around this problem, #transaction will emulate the effect
|
138
161
|
# of nested transactions, by using savepoints:
|
139
|
-
# http://dev.mysql.com/doc/refman/5.
|
162
|
+
# http://dev.mysql.com/doc/refman/5.7/en/savepoint.html
|
140
163
|
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
141
164
|
# supports savepoints.
|
142
165
|
#
|
@@ -188,29 +211,25 @@ module ActiveRecord
|
|
188
211
|
# You should consult the documentation for your database to understand the
|
189
212
|
# semantics of these different levels:
|
190
213
|
#
|
191
|
-
# * http://www.postgresql.org/docs/
|
192
|
-
# * https://dev.mysql.com/doc/refman/5.
|
214
|
+
# * http://www.postgresql.org/docs/current/static/transaction-iso.html
|
215
|
+
# * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
|
193
216
|
#
|
194
|
-
# An
|
217
|
+
# An ActiveRecord::TransactionIsolationError will be raised if:
|
195
218
|
#
|
196
219
|
# * The adapter does not support setting the isolation level
|
197
220
|
# * You are joining an existing open transaction
|
198
221
|
# * You are creating a nested (savepoint) transaction
|
199
222
|
#
|
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]
|
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
|
209
228
|
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
210
229
|
end
|
211
230
|
yield
|
212
231
|
else
|
213
|
-
transaction_manager.within_new_transaction(
|
232
|
+
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
|
214
233
|
end
|
215
234
|
rescue ActiveRecord::Rollback
|
216
235
|
# rollbacks are silently swallowed
|
@@ -234,6 +253,10 @@ module ActiveRecord
|
|
234
253
|
current_transaction.add_record(record)
|
235
254
|
end
|
236
255
|
|
256
|
+
def transaction_state
|
257
|
+
current_transaction.state
|
258
|
+
end
|
259
|
+
|
237
260
|
# Begins the transaction (and turns off auto-committing).
|
238
261
|
def begin_db_transaction() end
|
239
262
|
|
@@ -258,7 +281,15 @@ module ActiveRecord
|
|
258
281
|
|
259
282
|
# Rolls back the transaction (and turns on auto-committing). Must be
|
260
283
|
# done if the transaction block raises an exception or returns false.
|
261
|
-
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
|
262
293
|
|
263
294
|
def default_sequence_name(table, column)
|
264
295
|
nil
|
@@ -272,12 +303,24 @@ module ActiveRecord
|
|
272
303
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
273
304
|
# something beyond a simple insert (eg. Oracle).
|
274
305
|
def insert_fixture(fixture, table_name)
|
275
|
-
|
306
|
+
fixture = fixture.stringify_keys
|
276
307
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
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
|
281
324
|
end
|
282
325
|
|
283
326
|
execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
|
@@ -309,18 +352,12 @@ module ActiveRecord
|
|
309
352
|
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
|
310
353
|
# on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
|
311
354
|
# 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
|
355
|
+
def join_to_update(update, select, key) # :nodoc:
|
314
356
|
subselect = subquery_for(key, select)
|
315
357
|
|
316
358
|
update.where key.in(subselect)
|
317
359
|
end
|
318
|
-
|
319
|
-
def join_to_delete(delete, select, key) #:nodoc:
|
320
|
-
subselect = subquery_for(key, select)
|
321
|
-
|
322
|
-
delete.where key.in(subselect)
|
323
|
-
end
|
360
|
+
alias join_to_delete join_to_update
|
324
361
|
|
325
362
|
protected
|
326
363
|
|
@@ -333,28 +370,15 @@ module ActiveRecord
|
|
333
370
|
|
334
371
|
# Returns an ActiveRecord::Result instance.
|
335
372
|
def select(sql, name = nil, binds = [])
|
336
|
-
exec_query(sql, name, binds)
|
337
|
-
end
|
338
|
-
|
339
|
-
|
340
|
-
# Returns the last auto-generated ID from the affected table.
|
341
|
-
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
342
|
-
execute(sql, name)
|
343
|
-
id_value
|
344
|
-
end
|
345
|
-
|
346
|
-
# Executes the update statement and returns the number of rows affected.
|
347
|
-
def update_sql(sql, name = nil)
|
348
|
-
execute(sql, name)
|
373
|
+
exec_query(sql, name, binds, prepare: false)
|
349
374
|
end
|
350
375
|
|
351
|
-
|
352
|
-
|
353
|
-
update_sql(sql, name)
|
376
|
+
def select_prepared(sql, name = nil, binds = [])
|
377
|
+
exec_query(sql, name, binds, prepare: true)
|
354
378
|
end
|
355
379
|
|
356
380
|
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
357
|
-
[sql, binds]
|
381
|
+
[sql, binds, pk, sequence_name]
|
358
382
|
end
|
359
383
|
|
360
384
|
def last_inserted_id(result)
|
@@ -364,7 +388,7 @@ module ActiveRecord
|
|
364
388
|
|
365
389
|
def binds_from_relation(relation, binds)
|
366
390
|
if relation.is_a?(Relation) && binds.empty?
|
367
|
-
relation, binds = relation.arel, relation.
|
391
|
+
relation, binds = relation.arel, relation.bound_attributes
|
368
392
|
end
|
369
393
|
[relation, binds]
|
370
394
|
end
|
@@ -3,7 +3,7 @@ module ActiveRecord
|
|
3
3
|
module QueryCache
|
4
4
|
class << self
|
5
5
|
def included(base) #:nodoc:
|
6
|
-
dirties_query_cache base, :insert, :update, :delete
|
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)
|
@@ -61,11 +61,11 @@ module ActiveRecord
|
|
61
61
|
@query_cache.clear
|
62
62
|
end
|
63
63
|
|
64
|
-
def select_all(arel, name = nil, binds = [])
|
64
|
+
def select_all(arel, name = nil, binds = [], preparable: nil)
|
65
65
|
if @query_cache_enabled && !locked?(arel)
|
66
66
|
arel, binds = binds_from_relation arel, binds
|
67
67
|
sql = to_sql(arel, binds)
|
68
|
-
cache_sql(sql, binds) { super(sql, name, binds) }
|
68
|
+
cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
|
69
69
|
else
|
70
70
|
super
|
71
71
|
end
|
@@ -10,7 +10,13 @@ module ActiveRecord
|
|
10
10
|
return value.quoted_id if value.respond_to?(:quoted_id)
|
11
11
|
|
12
12
|
if column
|
13
|
-
|
13
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
14
|
+
Passing a column to `quote` has been deprecated. It is only used
|
15
|
+
for type casting, which should be handled elsewhere. See
|
16
|
+
https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11
|
17
|
+
for more information.
|
18
|
+
MSG
|
19
|
+
value = type_cast_from_column(column, value)
|
14
20
|
end
|
15
21
|
|
16
22
|
_quote(value)
|
@@ -19,13 +25,13 @@ module ActiveRecord
|
|
19
25
|
# Cast a +value+ to a type that the database understands. For example,
|
20
26
|
# SQLite does not understand dates, so this method will convert a Date
|
21
27
|
# to a String.
|
22
|
-
def type_cast(value, column)
|
28
|
+
def type_cast(value, column = nil)
|
23
29
|
if value.respond_to?(:quoted_id) && value.respond_to?(:id)
|
24
30
|
return value.id
|
25
31
|
end
|
26
32
|
|
27
33
|
if column
|
28
|
-
value = column
|
34
|
+
value = type_cast_from_column(column, value)
|
29
35
|
end
|
30
36
|
|
31
37
|
_type_cast(value)
|
@@ -34,15 +40,49 @@ module ActiveRecord
|
|
34
40
|
raise TypeError, "can't cast #{value.class}#{to_type}"
|
35
41
|
end
|
36
42
|
|
43
|
+
# If you are having to call this function, you are likely doing something
|
44
|
+
# wrong. The column does not have sufficient type information if the user
|
45
|
+
# provided a custom type on the class level either explicitly (via
|
46
|
+
# Attributes::ClassMethods#attribute) or implicitly (via
|
47
|
+
# AttributeMethods::Serialization::ClassMethods#serialize, +time_zone_aware_attributes+).
|
48
|
+
# In almost all cases, the sql type should only be used to change quoting behavior, when the primitive to
|
49
|
+
# represent the type doesn't sufficiently reflect the differences
|
50
|
+
# (varchar vs binary) for example. The type used to get this primitive
|
51
|
+
# should have been provided before reaching the connection adapter.
|
52
|
+
def type_cast_from_column(column, value) # :nodoc:
|
53
|
+
if column
|
54
|
+
type = lookup_cast_type_from_column(column)
|
55
|
+
type.serialize(value)
|
56
|
+
else
|
57
|
+
value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# See docs for #type_cast_from_column
|
62
|
+
def lookup_cast_type_from_column(column) # :nodoc:
|
63
|
+
lookup_cast_type(column.sql_type)
|
64
|
+
end
|
65
|
+
|
66
|
+
def fetch_type_metadata(sql_type)
|
67
|
+
cast_type = lookup_cast_type(sql_type)
|
68
|
+
SqlTypeMetadata.new(
|
69
|
+
sql_type: sql_type,
|
70
|
+
type: cast_type.type,
|
71
|
+
limit: cast_type.limit,
|
72
|
+
precision: cast_type.precision,
|
73
|
+
scale: cast_type.scale,
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
37
77
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
38
78
|
# characters.
|
39
79
|
def quote_string(s)
|
40
|
-
s.gsub(
|
80
|
+
s.gsub('\\'.freeze, '\&\&'.freeze).gsub("'".freeze, "''".freeze) # ' (for ruby-mode)
|
41
81
|
end
|
42
82
|
|
43
83
|
# Quotes the column name. Defaults to no quoting.
|
44
84
|
def quote_column_name(column_name)
|
45
|
-
column_name
|
85
|
+
column_name.to_s
|
46
86
|
end
|
47
87
|
|
48
88
|
# Quotes the table name. Defaults to column name quoting.
|
@@ -53,7 +93,7 @@ module ActiveRecord
|
|
53
93
|
# Override to return the quoted table name for assignment. Defaults to
|
54
94
|
# table quoting.
|
55
95
|
#
|
56
|
-
# This works for
|
96
|
+
# This works for mysql2 where table.column can be used to
|
57
97
|
# resolve ambiguity.
|
58
98
|
#
|
59
99
|
# We override this in the sqlite3 and postgresql adapters to use only
|
@@ -62,6 +102,15 @@ module ActiveRecord
|
|
62
102
|
quote_table_name("#{table}.#{attr}")
|
63
103
|
end
|
64
104
|
|
105
|
+
def quote_default_expression(value, column) # :nodoc:
|
106
|
+
if value.is_a?(Proc)
|
107
|
+
value.call
|
108
|
+
else
|
109
|
+
value = lookup_cast_type(column.sql_type).serialize(value)
|
110
|
+
quote(value)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
65
114
|
def quoted_true
|
66
115
|
"'t'"
|
67
116
|
end
|
@@ -78,6 +127,8 @@ module ActiveRecord
|
|
78
127
|
'f'
|
79
128
|
end
|
80
129
|
|
130
|
+
# Quote date/time values for use in SQL input. Includes microseconds
|
131
|
+
# if the value is a Time responding to usec.
|
81
132
|
def quoted_date(value)
|
82
133
|
if value.acts_like?(:time)
|
83
134
|
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
@@ -87,7 +138,20 @@ module ActiveRecord
|
|
87
138
|
end
|
88
139
|
end
|
89
140
|
|
90
|
-
value.to_s(:db)
|
141
|
+
result = value.to_s(:db)
|
142
|
+
if value.respond_to?(:usec) && value.usec > 0
|
143
|
+
"#{result}.#{sprintf("%06d", value.usec)}"
|
144
|
+
else
|
145
|
+
result
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def quoted_time(value) # :nodoc:
|
150
|
+
quoted_date(value).sub(/\A2000-01-01 /, '')
|
151
|
+
end
|
152
|
+
|
153
|
+
def prepare_binds_for_database(binds) # :nodoc:
|
154
|
+
binds.map(&:value_for_database)
|
91
155
|
end
|
92
156
|
|
93
157
|
private
|
@@ -106,11 +170,11 @@ module ActiveRecord
|
|
106
170
|
# BigDecimals need to be put in a non-normalized form and quoted.
|
107
171
|
when BigDecimal then value.to_s('F')
|
108
172
|
when Numeric, ActiveSupport::Duration then value.to_s
|
173
|
+
when Type::Time::Value then "'#{quoted_time(value)}'"
|
109
174
|
when Date, Time then "'#{quoted_date(value)}'"
|
110
175
|
when Symbol then "'#{quote_string(value.to_s)}'"
|
111
176
|
when Class then "'#{value}'"
|
112
|
-
else
|
113
|
-
"'#{quote_string(YAML.dump(value))}'"
|
177
|
+
else raise TypeError, "can't quote #{value.class.name}"
|
114
178
|
end
|
115
179
|
end
|
116
180
|
|
@@ -122,6 +186,7 @@ module ActiveRecord
|
|
122
186
|
when false then unquoted_false
|
123
187
|
# BigDecimals need to be put in a non-normalized form and quoted.
|
124
188
|
when BigDecimal then value.to_s('F')
|
189
|
+
when Type::Time::Value then quoted_time(value)
|
125
190
|
when Date, Time then quoted_date(value)
|
126
191
|
when *types_which_need_no_typecasting
|
127
192
|
value
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionAdapters
|
3
|
-
module Savepoints
|
4
|
-
def
|
5
|
-
|
3
|
+
module Savepoints
|
4
|
+
def current_savepoint_name
|
5
|
+
current_transaction.savepoint_name
|
6
6
|
end
|
7
7
|
|
8
8
|
def create_savepoint(name = current_savepoint_name)
|
9
9
|
execute("SAVEPOINT #{name}")
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def exec_rollback_to_savepoint(name = current_savepoint_name)
|
13
13
|
execute("ROLLBACK TO SAVEPOINT #{name}")
|
14
14
|
end
|
15
15
|
|
@@ -14,38 +14,58 @@ module ActiveRecord
|
|
14
14
|
send m, o
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
18
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options, to: :@conn
|
19
|
+
private :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
20
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options
|
20
21
|
|
21
22
|
private
|
22
23
|
|
23
24
|
def visit_AlterTable(o)
|
24
25
|
sql = "ALTER TABLE #{quote_table_name(o.name)} "
|
25
|
-
sql << o.adds.map { |col|
|
26
|
+
sql << o.adds.map { |col| accept col }.join(' ')
|
26
27
|
sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ')
|
27
28
|
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ')
|
28
29
|
end
|
29
30
|
|
30
31
|
def visit_ColumnDefinition(o)
|
31
|
-
sql_type
|
32
|
-
column_sql = "#{quote_column_name(o.name)} #{sql_type}"
|
33
|
-
add_column_options!(column_sql, column_options(o)) unless o.primary_key
|
32
|
+
o.sql_type ||= type_to_sql(o.type, o.limit, o.precision, o.scale)
|
33
|
+
column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
|
34
|
+
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
|
34
35
|
column_sql
|
35
36
|
end
|
36
37
|
|
38
|
+
def visit_AddColumnDefinition(o)
|
39
|
+
"ADD #{accept(o.column)}"
|
40
|
+
end
|
41
|
+
|
37
42
|
def visit_TableDefinition(o)
|
38
|
-
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE "
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
|
44
|
+
|
45
|
+
statements = o.columns.map { |c| accept c }
|
46
|
+
statements << accept(o.primary_keys) if o.primary_keys
|
47
|
+
|
48
|
+
if supports_indexes_in_create?
|
49
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
50
|
+
end
|
51
|
+
|
52
|
+
if supports_foreign_keys?
|
53
|
+
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
54
|
+
end
|
55
|
+
|
56
|
+
create_sql << "(#{statements.join(', ')})" if statements.present?
|
57
|
+
add_table_options!(create_sql, table_options(o))
|
42
58
|
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
|
43
59
|
create_sql
|
44
60
|
end
|
45
61
|
|
46
|
-
def
|
62
|
+
def visit_PrimaryKeyDefinition(o)
|
63
|
+
"PRIMARY KEY (#{o.name.join(', ')})"
|
64
|
+
end
|
65
|
+
|
66
|
+
def visit_ForeignKeyDefinition(o)
|
47
67
|
sql = <<-SQL.strip_heredoc
|
48
|
-
|
68
|
+
CONSTRAINT #{quote_column_name(o.name)}
|
49
69
|
FOREIGN KEY (#{quote_column_name(o.column)})
|
50
70
|
REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
|
51
71
|
SQL
|
@@ -54,10 +74,27 @@ module ActiveRecord
|
|
54
74
|
sql
|
55
75
|
end
|
56
76
|
|
77
|
+
def visit_AddForeignKey(o)
|
78
|
+
"ADD #{accept(o)}"
|
79
|
+
end
|
80
|
+
|
57
81
|
def visit_DropForeignKey(name)
|
58
82
|
"DROP CONSTRAINT #{quote_column_name(name)}"
|
59
83
|
end
|
60
84
|
|
85
|
+
def table_options(o)
|
86
|
+
table_options = {}
|
87
|
+
table_options[:comment] = o.comment
|
88
|
+
table_options[:options] = o.options
|
89
|
+
table_options
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_table_options!(create_sql, options)
|
93
|
+
if options_sql = options[:options]
|
94
|
+
create_sql << " #{options_sql}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
61
98
|
def column_options(o)
|
62
99
|
column_options = {}
|
63
100
|
column_options[:null] = o.null unless o.null.nil?
|
@@ -65,23 +102,15 @@ module ActiveRecord
|
|
65
102
|
column_options[:column] = o
|
66
103
|
column_options[:first] = o.first
|
67
104
|
column_options[:after] = o.after
|
105
|
+
column_options[:auto_increment] = o.auto_increment
|
106
|
+
column_options[:primary_key] = o.primary_key
|
107
|
+
column_options[:collation] = o.collation
|
108
|
+
column_options[:comment] = o.comment
|
68
109
|
column_options
|
69
110
|
end
|
70
111
|
|
71
|
-
def quote_column_name(name)
|
72
|
-
@conn.quote_column_name name
|
73
|
-
end
|
74
|
-
|
75
|
-
def quote_table_name(name)
|
76
|
-
@conn.quote_table_name name
|
77
|
-
end
|
78
|
-
|
79
|
-
def type_to_sql(type, limit, precision, scale)
|
80
|
-
@conn.type_to_sql type.to_sym, limit, precision, scale
|
81
|
-
end
|
82
|
-
|
83
112
|
def add_column_options!(sql, options)
|
84
|
-
sql << " DEFAULT #{
|
113
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
85
114
|
# must explicitly check for :null to allow change_column to work on migrations
|
86
115
|
if options[:null] == false
|
87
116
|
sql << " NOT NULL"
|
@@ -89,18 +118,15 @@ module ActiveRecord
|
|
89
118
|
if options[:auto_increment] == true
|
90
119
|
sql << " AUTO_INCREMENT"
|
91
120
|
end
|
121
|
+
if options[:primary_key] == true
|
122
|
+
sql << " PRIMARY KEY"
|
123
|
+
end
|
92
124
|
sql
|
93
125
|
end
|
94
126
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
@conn.quote(value, column)
|
100
|
-
end
|
101
|
-
|
102
|
-
def options_include_default?(options)
|
103
|
-
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
127
|
+
def foreign_key_in_create(from_table, to_table, options)
|
128
|
+
options = foreign_key_options(from_table, to_table, options)
|
129
|
+
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
104
130
|
end
|
105
131
|
|
106
132
|
def action_sql(action, dependency)
|
@@ -115,10 +141,6 @@ module ActiveRecord
|
|
115
141
|
MSG
|
116
142
|
end
|
117
143
|
end
|
118
|
-
|
119
|
-
def type_for_column(column)
|
120
|
-
@conn.lookup_cast_type(column.sql_type)
|
121
|
-
end
|
122
144
|
end
|
123
145
|
end
|
124
146
|
end
|