activerecord 4.2.6 → 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 +1307 -1105
- 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 +3 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +11 -9
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- 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 +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
- 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 +50 -31
- data/lib/active_record/associations/collection_proxy.rb +69 -29
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
- data/lib/active_record/associations/join_dependency.rb +29 -19
- data/lib/active_record/associations/preloader/association.rb +46 -52
- 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 +14 -4
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/associations.rb +317 -209
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +68 -18
- 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 +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- 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 +61 -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 +6 -4
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attributes.rb +199 -80
- data/lib/active_record/autosave_association.rb +49 -16
- data/lib/active_record/base.rb +32 -23
- 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 +452 -182
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -140
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +153 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -362
- 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 +25 -176
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
- 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 +1 -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 -22
- 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/specialized_string.rb +0 -4
- 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 +234 -148
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
- 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 +148 -203
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +89 -107
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +113 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +3 -3
- 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 +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- 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 +364 -109
- data/lib/active_record/model_schema.rb +128 -38
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +121 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +27 -18
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +58 -45
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +282 -115
- 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 +163 -81
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -15
- 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 +120 -107
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- 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 -116
- 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 +23 -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 +58 -41
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -20
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- 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 +138 -56
- 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 -49
- 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 +15 -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 +30 -29
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +7 -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 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- 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 +58 -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 -31
- data/lib/active_record/type/decimal.rb +0 -50
- 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 -59
- 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 -40
- 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 -105
@@ -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
|
@@ -272,9 +291,6 @@ module ActiveRecord
|
|
272
291
|
exec_rollback_to_savepoint(name)
|
273
292
|
end
|
274
293
|
|
275
|
-
def exec_rollback_to_savepoint(name = nil) #:nodoc:
|
276
|
-
end
|
277
|
-
|
278
294
|
def default_sequence_name(table, column)
|
279
295
|
nil
|
280
296
|
end
|
@@ -288,17 +304,24 @@ module ActiveRecord
|
|
288
304
|
# something beyond a simple insert (eg. Oracle).
|
289
305
|
def insert_fixture(fixture, table_name)
|
290
306
|
fixture = fixture.stringify_keys
|
291
|
-
columns = schema_cache.columns_hash(table_name)
|
292
307
|
|
293
|
-
|
294
|
-
|
308
|
+
columns = schema_cache.columns_hash(table_name)
|
309
|
+
binds = fixture.map do |name, value|
|
295
310
|
if column = columns[name]
|
296
|
-
|
297
|
-
|
311
|
+
type = lookup_cast_type_from_column(column)
|
312
|
+
Relation::QueryAttribute.new(name, value, type)
|
298
313
|
else
|
299
314
|
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
300
315
|
end
|
301
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
|
324
|
+
end
|
302
325
|
|
303
326
|
execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
|
304
327
|
end
|
@@ -329,18 +352,12 @@ module ActiveRecord
|
|
329
352
|
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
|
330
353
|
# on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
|
331
354
|
# an UPDATE statement, so in the MySQL adapters we redefine this to do that.
|
332
|
-
def join_to_update(update, select)
|
333
|
-
key = update.key
|
355
|
+
def join_to_update(update, select, key) # :nodoc:
|
334
356
|
subselect = subquery_for(key, select)
|
335
357
|
|
336
358
|
update.where key.in(subselect)
|
337
359
|
end
|
338
|
-
|
339
|
-
def join_to_delete(delete, select, key) #:nodoc:
|
340
|
-
subselect = subquery_for(key, select)
|
341
|
-
|
342
|
-
delete.where key.in(subselect)
|
343
|
-
end
|
360
|
+
alias join_to_delete join_to_update
|
344
361
|
|
345
362
|
protected
|
346
363
|
|
@@ -353,28 +370,15 @@ module ActiveRecord
|
|
353
370
|
|
354
371
|
# Returns an ActiveRecord::Result instance.
|
355
372
|
def select(sql, name = nil, binds = [])
|
356
|
-
exec_query(sql, name, binds)
|
357
|
-
end
|
358
|
-
|
359
|
-
|
360
|
-
# Returns the last auto-generated ID from the affected table.
|
361
|
-
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
362
|
-
execute(sql, name)
|
363
|
-
id_value
|
364
|
-
end
|
365
|
-
|
366
|
-
# Executes the update statement and returns the number of rows affected.
|
367
|
-
def update_sql(sql, name = nil)
|
368
|
-
execute(sql, name)
|
373
|
+
exec_query(sql, name, binds, prepare: false)
|
369
374
|
end
|
370
375
|
|
371
|
-
|
372
|
-
|
373
|
-
update_sql(sql, name)
|
376
|
+
def select_prepared(sql, name = nil, binds = [])
|
377
|
+
exec_query(sql, name, binds, prepare: true)
|
374
378
|
end
|
375
379
|
|
376
380
|
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
377
|
-
[sql, binds]
|
381
|
+
[sql, binds, pk, sequence_name]
|
378
382
|
end
|
379
383
|
|
380
384
|
def last_inserted_id(result)
|
@@ -384,7 +388,7 @@ module ActiveRecord
|
|
384
388
|
|
385
389
|
def binds_from_relation(relation, binds)
|
386
390
|
if relation.is_a?(Relation) && binds.empty?
|
387
|
-
relation, binds = relation.arel, relation.
|
391
|
+
relation, binds = relation.arel, relation.bound_attributes
|
388
392
|
end
|
389
393
|
[relation, binds]
|
390
394
|
end
|
@@ -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
|
@@ -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
|