activerecord 3.2.22.5 → 4.0.0.beta1
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 +1024 -543
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -29
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +55 -44
- data/lib/active_record/aggregations.rb +40 -34
- data/lib/active_record/associations.rb +204 -276
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +30 -35
- data/lib/active_record/associations/association_scope.rb +40 -40
- data/lib/active_record/associations/belongs_to_association.rb +15 -2
- data/lib/active_record/associations/builder/association.rb +81 -28
- data/lib/active_record/associations/builder/belongs_to.rb +35 -57
- data/lib/active_record/associations/builder/collection_association.rb +54 -40
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +13 -50
- data/lib/active_record/associations/builder/singular_association.rb +13 -13
- data/lib/active_record/associations/collection_association.rb +92 -88
- data/lib/active_record/associations/collection_proxy.rb +913 -63
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -10
- data/lib/active_record/associations/has_many_association.rb +35 -9
- data/lib/active_record/associations/has_many_through_association.rb +24 -14
- data/lib/active_record/associations/has_one_association.rb +33 -13
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_helper.rb +1 -11
- data/lib/active_record/associations/preloader.rb +14 -17
- data/lib/active_record/associations/preloader/association.rb +29 -33
- data/lib/active_record/associations/preloader/collection_association.rb +1 -1
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/through_association.rb +13 -17
- data/lib/active_record/associations/singular_association.rb +11 -11
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +133 -153
- data/lib/active_record/attribute_methods.rb +196 -93
- data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
- data/lib/active_record/attribute_methods/dirty.rb +31 -28
- data/lib/active_record/attribute_methods/primary_key.rb +38 -30
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +62 -91
- data/lib/active_record/attribute_methods/serialization.rb +97 -66
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -45
- data/lib/active_record/attribute_methods/write.rb +32 -39
- data/lib/active_record/autosave_association.rb +56 -70
- data/lib/active_record/base.rb +53 -450
- data/lib/active_record/callbacks.rb +53 -18
- data/lib/active_record/coders/yaml_column.rb +11 -9
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +353 -197
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -131
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -3
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +101 -91
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +225 -96
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +99 -46
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +114 -36
- data/lib/active_record/connection_adapters/column.rb +46 -24
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +181 -64
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +132 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +347 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +158 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +448 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +454 -885
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +574 -13
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +428 -0
- data/lib/active_record/counter_cache.rb +106 -108
- data/lib/active_record/dynamic_matchers.rb +110 -63
- data/lib/active_record/errors.rb +25 -8
- data/lib/active_record/explain.rb +8 -58
- data/lib/active_record/explain_subscriber.rb +6 -3
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +146 -148
- data/lib/active_record/inheritance.rb +77 -59
- data/lib/active_record/integration.rb +5 -5
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +38 -42
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +19 -9
- data/lib/active_record/migration.rb +318 -153
- data/lib/active_record/migration/command_recorder.rb +90 -31
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/model_schema.rb +69 -92
- data/lib/active_record/nested_attributes.rb +113 -148
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +188 -97
- data/lib/active_record/query_cache.rb +18 -36
- data/lib/active_record/querying.rb +19 -15
- data/lib/active_record/railtie.rb +91 -36
- data/lib/active_record/railties/console_sandbox.rb +0 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -2
- data/lib/active_record/railties/databases.rake +90 -309
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +7 -3
- data/lib/active_record/reflection.rb +72 -56
- data/lib/active_record/relation.rb +241 -157
- data/lib/active_record/relation/batches.rb +25 -22
- data/lib/active_record/relation/calculations.rb +143 -121
- data/lib/active_record/relation/delegation.rb +96 -18
- data/lib/active_record/relation/finder_methods.rb +117 -183
- data/lib/active_record/relation/merger.rb +133 -0
- data/lib/active_record/relation/predicate_builder.rb +90 -42
- data/lib/active_record/relation/query_methods.rb +666 -136
- data/lib/active_record/relation/spawn_methods.rb +43 -150
- data/lib/active_record/result.rb +33 -6
- data/lib/active_record/sanitization.rb +24 -50
- data/lib/active_record/schema.rb +19 -12
- data/lib/active_record/schema_dumper.rb +31 -39
- data/lib/active_record/schema_migration.rb +36 -0
- data/lib/active_record/scoping.rb +0 -124
- data/lib/active_record/scoping/default.rb +48 -45
- data/lib/active_record/scoping/named.rb +74 -103
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +9 -15
- data/lib/active_record/store.rb +119 -15
- data/lib/active_record/tasks/database_tasks.rb +158 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +138 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/test_case.rb +61 -38
- data/lib/active_record/timestamp.rb +8 -9
- data/lib/active_record/transactions.rb +65 -51
- data/lib/active_record/validations.rb +17 -15
- data/lib/active_record/validations/associated.rb +20 -14
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +93 -52
- data/lib/active_record/version.rb +4 -4
- data/lib/rails/generators/active_record.rb +3 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -7
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -3
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- metadata +53 -46
- 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/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/session_store.rb +0 -360
- data/lib/rails/generators/active_record/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
|
+
# <tt>index_name_length</tt>. The gap between
|
23
|
+
# <tt>index_name_length</tt> is to allow internal rails
|
24
|
+
# opreations to use prefixes in temporary opreations.
|
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,9 +1,15 @@
|
|
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)
|
12
|
+
binds = binds.dup
|
7
13
|
visitor.accept(arel.ast) do
|
8
14
|
quote(*binds.shift.reverse)
|
9
15
|
end
|
@@ -20,14 +26,14 @@ module ActiveRecord
|
|
20
26
|
|
21
27
|
# Returns a record hash with the column names as keys and column values
|
22
28
|
# as values.
|
23
|
-
def select_one(arel, name = nil)
|
24
|
-
result = select_all(arel, name)
|
29
|
+
def select_one(arel, name = nil, binds = [])
|
30
|
+
result = select_all(arel, name, binds)
|
25
31
|
result.first if result
|
26
32
|
end
|
27
33
|
|
28
34
|
# Returns a single value from a record
|
29
|
-
def select_value(arel, name = nil)
|
30
|
-
if result = select_one(arel, name)
|
35
|
+
def select_value(arel, name = nil, binds = [])
|
36
|
+
if result = select_one(arel, name, binds)
|
31
37
|
result.values.first
|
32
38
|
end
|
33
39
|
end
|
@@ -57,21 +63,21 @@ module ActiveRecord
|
|
57
63
|
end
|
58
64
|
|
59
65
|
# Executes insert +sql+ statement in the context of this connection using
|
60
|
-
# +binds+ as the bind substitutes. +name+ is
|
66
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
61
67
|
# the executed +sql+ statement.
|
62
|
-
def exec_insert(sql, name, binds)
|
68
|
+
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
63
69
|
exec_query(sql, name, binds)
|
64
70
|
end
|
65
71
|
|
66
72
|
# Executes delete +sql+ statement in the context of this connection using
|
67
|
-
# +binds+ as the bind substitutes. +name+ is
|
73
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
68
74
|
# the executed +sql+ statement.
|
69
75
|
def exec_delete(sql, name, binds)
|
70
76
|
exec_query(sql, name, binds)
|
71
77
|
end
|
72
78
|
|
73
79
|
# Executes update +sql+ statement in the context of this connection using
|
74
|
-
# +binds+ as the bind substitutes. +name+ is
|
80
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
75
81
|
# the executed +sql+ statement.
|
76
82
|
def exec_update(sql, name, binds)
|
77
83
|
exec_query(sql, name, binds)
|
@@ -87,7 +93,7 @@ module ActiveRecord
|
|
87
93
|
# passed in as +id_value+.
|
88
94
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
89
95
|
sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
|
90
|
-
value = exec_insert(sql, name, binds)
|
96
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
91
97
|
id_value || last_inserted_id(value)
|
92
98
|
end
|
93
99
|
|
@@ -101,20 +107,6 @@ module ActiveRecord
|
|
101
107
|
exec_delete(to_sql(arel, binds), name, binds)
|
102
108
|
end
|
103
109
|
|
104
|
-
# Checks whether there is currently no transaction active. This is done
|
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
|
117
|
-
|
118
110
|
# Returns +true+ when the connection adapter supports prepared statement
|
119
111
|
# caching, otherwise returns +false+
|
120
112
|
def supports_statement_cache?
|
@@ -158,95 +150,124 @@ module ActiveRecord
|
|
158
150
|
# already-automatically-released savepoints:
|
159
151
|
#
|
160
152
|
# Model.connection.transaction do # BEGIN
|
161
|
-
# Model.connection.transaction(:
|
153
|
+
# Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
|
162
154
|
# Model.connection.create_table(...)
|
163
155
|
# # active_record_1 now automatically released
|
164
156
|
# end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
|
165
157
|
# end
|
158
|
+
#
|
159
|
+
# == Transaction isolation
|
160
|
+
#
|
161
|
+
# If your database supports setting the isolation level for a transaction, you can set
|
162
|
+
# it like so:
|
163
|
+
#
|
164
|
+
# Post.transaction(isolation: :serializable) do
|
165
|
+
# # ...
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# Valid isolation levels are:
|
169
|
+
#
|
170
|
+
# * <tt>:read_uncommitted</tt>
|
171
|
+
# * <tt>:read_committed</tt>
|
172
|
+
# * <tt>:repeatable_read</tt>
|
173
|
+
# * <tt>:serializable</tt>
|
174
|
+
#
|
175
|
+
# You should consult the documentation for your database to understand the
|
176
|
+
# semantics of these different levels:
|
177
|
+
#
|
178
|
+
# * http://www.postgresql.org/docs/9.1/static/transaction-iso.html
|
179
|
+
# * https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
|
180
|
+
#
|
181
|
+
# An <tt>ActiveRecord::TransactionIsolationError</tt> will be raised if:
|
182
|
+
#
|
183
|
+
# * The adapter does not support setting the isolation level
|
184
|
+
# * You are joining an existing open transaction
|
185
|
+
# * You are creating a nested (savepoint) transaction
|
186
|
+
#
|
187
|
+
# The mysql, mysql2 and postgresql adapters support setting the transaction
|
188
|
+
# isolation level. However, support is disabled for mysql versions below 5,
|
189
|
+
# because they are affected by a bug[http://bugs.mysql.com/bug.php?id=39170]
|
190
|
+
# which means the isolation level gets persisted outside the transaction.
|
166
191
|
def transaction(options = {})
|
167
|
-
options.assert_valid_keys :requires_new, :joinable
|
192
|
+
options.assert_valid_keys :requires_new, :joinable, :isolation
|
193
|
+
|
194
|
+
if !options[:requires_new] && current_transaction.joinable?
|
195
|
+
if options[:isolation]
|
196
|
+
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
197
|
+
end
|
168
198
|
|
169
|
-
|
170
|
-
if options.has_key?(:joinable)
|
171
|
-
@transaction_joinable = options[:joinable]
|
199
|
+
yield
|
172
200
|
else
|
173
|
-
|
201
|
+
within_new_transaction(options) { yield }
|
174
202
|
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
@_current_transaction_records ||= []
|
203
|
+
rescue ActiveRecord::Rollback
|
204
|
+
# rollbacks are silently swallowed
|
205
|
+
end
|
179
206
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
create_savepoint
|
187
|
-
end
|
188
|
-
increment_open_transactions
|
189
|
-
transaction_open = true
|
190
|
-
@_current_transaction_records.push([])
|
191
|
-
end
|
192
|
-
yield
|
193
|
-
end
|
194
|
-
rescue Exception => database_transaction_rollback
|
195
|
-
if transaction_open && !outside_transaction?
|
196
|
-
transaction_open = false
|
197
|
-
decrement_open_transactions
|
198
|
-
if open_transactions == 0
|
199
|
-
rollback_db_transaction
|
200
|
-
rollback_transaction_records(true)
|
201
|
-
else
|
202
|
-
rollback_to_savepoint
|
203
|
-
rollback_transaction_records(false)
|
204
|
-
end
|
205
|
-
end
|
206
|
-
raise unless database_transaction_rollback.is_a?(ActiveRecord::Rollback)
|
207
|
-
end
|
207
|
+
def within_new_transaction(options = {}) #:nodoc:
|
208
|
+
transaction = begin_transaction(options)
|
209
|
+
yield
|
210
|
+
rescue Exception => error
|
211
|
+
rollback_transaction if transaction
|
212
|
+
raise
|
208
213
|
ensure
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
decrement_open_transactions
|
215
|
-
begin
|
216
|
-
if open_transactions == 0
|
217
|
-
commit_db_transaction
|
218
|
-
commit_transaction_records
|
219
|
-
else
|
220
|
-
release_savepoint
|
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
|
214
|
+
begin
|
215
|
+
commit_transaction unless error
|
216
|
+
rescue Exception
|
217
|
+
rollback_transaction
|
218
|
+
raise
|
237
219
|
end
|
238
220
|
end
|
239
221
|
|
222
|
+
def current_transaction #:nodoc:
|
223
|
+
@transaction
|
224
|
+
end
|
225
|
+
|
226
|
+
def transaction_open?
|
227
|
+
@transaction.open?
|
228
|
+
end
|
229
|
+
|
230
|
+
def begin_transaction(options = {}) #:nodoc:
|
231
|
+
@transaction = @transaction.begin(options)
|
232
|
+
end
|
233
|
+
|
234
|
+
def commit_transaction #:nodoc:
|
235
|
+
@transaction = @transaction.commit
|
236
|
+
end
|
237
|
+
|
238
|
+
def rollback_transaction #:nodoc:
|
239
|
+
@transaction = @transaction.rollback
|
240
|
+
end
|
241
|
+
|
242
|
+
def reset_transaction #:nodoc:
|
243
|
+
@transaction = ClosedTransaction.new(self)
|
244
|
+
end
|
245
|
+
|
240
246
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
241
247
|
# can be called.
|
242
248
|
def add_transaction_record(record)
|
243
|
-
|
244
|
-
last_batch << record if last_batch
|
249
|
+
@transaction.add_record(record)
|
245
250
|
end
|
246
251
|
|
247
252
|
# Begins the transaction (and turns off auto-committing).
|
248
253
|
def begin_db_transaction() end
|
249
254
|
|
255
|
+
def transaction_isolation_levels
|
256
|
+
{
|
257
|
+
read_uncommitted: "READ UNCOMMITTED",
|
258
|
+
read_committed: "READ COMMITTED",
|
259
|
+
repeatable_read: "REPEATABLE READ",
|
260
|
+
serializable: "SERIALIZABLE"
|
261
|
+
}
|
262
|
+
end
|
263
|
+
|
264
|
+
# Begins the transaction with the isolation level set. Raises an error by
|
265
|
+
# default; adapters that support setting the isolation level should implement
|
266
|
+
# this method.
|
267
|
+
def begin_isolated_db_transaction(isolation)
|
268
|
+
raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
|
269
|
+
end
|
270
|
+
|
250
271
|
# Commits the transaction (and turns on auto-committing).
|
251
272
|
def commit_db_transaction() end
|
252
273
|
|
@@ -278,7 +299,7 @@ module ActiveRecord
|
|
278
299
|
end
|
279
300
|
|
280
301
|
def empty_insert_statement_value
|
281
|
-
"VALUES
|
302
|
+
"DEFAULT VALUES"
|
282
303
|
end
|
283
304
|
|
284
305
|
def case_sensitive_equality_operator
|
@@ -312,13 +333,27 @@ module ActiveRecord
|
|
312
333
|
# on mysql (even when aliasing the tables), but mysql allows using JOIN directly in
|
313
334
|
# an UPDATE statement, so in the mysql adapters we redefine this to do that.
|
314
335
|
def join_to_update(update, select) #:nodoc:
|
315
|
-
|
316
|
-
subselect
|
336
|
+
key = update.key
|
337
|
+
subselect = subquery_for(key, select)
|
338
|
+
|
339
|
+
update.where key.in(subselect)
|
340
|
+
end
|
341
|
+
|
342
|
+
def join_to_delete(delete, select, key) #:nodoc:
|
343
|
+
subselect = subquery_for(key, select)
|
317
344
|
|
318
|
-
|
345
|
+
delete.where key.in(subselect)
|
319
346
|
end
|
320
347
|
|
321
348
|
protected
|
349
|
+
|
350
|
+
# Return a subquery for the given key using the join information.
|
351
|
+
def subquery_for(key, select)
|
352
|
+
subselect = select.clone
|
353
|
+
subselect.projections = [key]
|
354
|
+
subselect
|
355
|
+
end
|
356
|
+
|
322
357
|
# Returns an array of record hashes with the column names as keys and
|
323
358
|
# column values as values.
|
324
359
|
def select(sql, name = nil, binds = [])
|
@@ -341,42 +376,6 @@ module ActiveRecord
|
|
341
376
|
update_sql(sql, name)
|
342
377
|
end
|
343
378
|
|
344
|
-
# Send a rollback message to all records after they have been rolled back. If rollback
|
345
|
-
# is false, only rollback records since the last save point.
|
346
|
-
def rollback_transaction_records(rollback)
|
347
|
-
if rollback
|
348
|
-
records = @_current_transaction_records.flatten
|
349
|
-
@_current_transaction_records.clear
|
350
|
-
else
|
351
|
-
records = @_current_transaction_records.pop
|
352
|
-
end
|
353
|
-
|
354
|
-
unless records.blank?
|
355
|
-
records.uniq.each do |record|
|
356
|
-
begin
|
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
|
363
|
-
end
|
364
|
-
|
365
|
-
# Send a commit message to all records after they have been committed.
|
366
|
-
def commit_transaction_records
|
367
|
-
records = @_current_transaction_records.flatten
|
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
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
379
|
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
381
380
|
[sql, binds]
|
382
381
|
end
|
@@ -2,16 +2,16 @@ module ActiveRecord
|
|
2
2
|
module ConnectionAdapters # :nodoc:
|
3
3
|
module QueryCache
|
4
4
|
class << self
|
5
|
-
def included(base)
|
5
|
+
def included(base) #:nodoc:
|
6
6
|
dirties_query_cache base, :insert, :update, :delete
|
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}(*) # def update_with_query_dirty(*
|
12
|
+
def #{method_name}(*) # def update_with_query_dirty(*)
|
13
13
|
clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled
|
14
|
-
super #
|
14
|
+
super # super
|
15
15
|
end # end
|
16
16
|
end_code
|
17
17
|
end
|
@@ -65,26 +65,31 @@ module ActiveRecord
|
|
65
65
|
end
|
66
66
|
|
67
67
|
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
68
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
69
|
+
def cache_sql(sql, binds)
|
70
|
+
result =
|
71
|
+
if @query_cache[sql].key?(binds)
|
72
|
+
ActiveSupport::Notifications.instrument("sql.active_record",
|
73
|
+
:sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id)
|
74
|
+
@query_cache[sql][binds]
|
84
75
|
else
|
85
|
-
|
76
|
+
@query_cache[sql][binds] = yield
|
86
77
|
end
|
78
|
+
|
79
|
+
# FIXME: we should guarantee that all cached items are Result
|
80
|
+
# objects. Then we can avoid this conditional
|
81
|
+
if ActiveRecord::Result === result
|
82
|
+
result.dup
|
83
|
+
else
|
84
|
+
result.collect { |row| row.dup }
|
87
85
|
end
|
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
|
@@ -25,15 +25,22 @@ module ActiveRecord
|
|
25
25
|
when true, false
|
26
26
|
if column && column.type == :integer
|
27
27
|
value ? '1' : '0'
|
28
|
+
elsif column && [:text, :string, :binary].include?(column.type)
|
29
|
+
value ? "'1'" : "'0'"
|
28
30
|
else
|
29
31
|
value ? quoted_true : quoted_false
|
30
32
|
end
|
31
33
|
# BigDecimals need to be put in a non-normalized form and quoted.
|
32
34
|
when nil then "NULL"
|
33
|
-
when
|
34
|
-
|
35
|
+
when Numeric, ActiveSupport::Duration
|
36
|
+
value = BigDecimal === value ? value.to_s('F') : value.to_s
|
37
|
+
if column && ![:integer, :float, :decimal].include?(column.type)
|
38
|
+
value = "'#{value}'"
|
39
|
+
end
|
40
|
+
value
|
35
41
|
when Date, Time then "'#{quoted_date(value)}'"
|
36
42
|
when Symbol then "'#{quote_string(value.to_s)}'"
|
43
|
+
when Class then "'#{value.to_s}'"
|
37
44
|
else
|
38
45
|
"'#{quote_string(YAML.dump(value))}'"
|
39
46
|
end
|
@@ -71,7 +78,8 @@ module ActiveRecord
|
|
71
78
|
when Date, Time then quoted_date(value)
|
72
79
|
when Symbol then value.to_s
|
73
80
|
else
|
74
|
-
|
81
|
+
to_type = column ? " to #{column.type}" : ""
|
82
|
+
raise TypeError, "can't cast #{value.class}#{to_type}"
|
75
83
|
end
|
76
84
|
end
|
77
85
|
|
@@ -91,6 +99,18 @@ module ActiveRecord
|
|
91
99
|
quote_column_name(table_name)
|
92
100
|
end
|
93
101
|
|
102
|
+
# Override to return the quoted table name for assignment. Defaults to
|
103
|
+
# table quoting.
|
104
|
+
#
|
105
|
+
# This works for mysql and mysql2 where table.column can be used to
|
106
|
+
# resolve ambiguity.
|
107
|
+
#
|
108
|
+
# We override this in the sqlite and postgresql adapters to use only
|
109
|
+
# the column name (as per syntax requirements).
|
110
|
+
def quote_table_name_for_assignment(table, attr)
|
111
|
+
quote_table_name("#{table}.#{attr}")
|
112
|
+
end
|
113
|
+
|
94
114
|
def quoted_true
|
95
115
|
"'t'"
|
96
116
|
end
|