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.

Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1024 -543
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +20 -29
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +55 -44
  7. data/lib/active_record/aggregations.rb +40 -34
  8. data/lib/active_record/associations.rb +204 -276
  9. data/lib/active_record/associations/alias_tracker.rb +1 -1
  10. data/lib/active_record/associations/association.rb +30 -35
  11. data/lib/active_record/associations/association_scope.rb +40 -40
  12. data/lib/active_record/associations/belongs_to_association.rb +15 -2
  13. data/lib/active_record/associations/builder/association.rb +81 -28
  14. data/lib/active_record/associations/builder/belongs_to.rb +35 -57
  15. data/lib/active_record/associations/builder/collection_association.rb +54 -40
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -64
  18. data/lib/active_record/associations/builder/has_one.rb +13 -50
  19. data/lib/active_record/associations/builder/singular_association.rb +13 -13
  20. data/lib/active_record/associations/collection_association.rb +92 -88
  21. data/lib/active_record/associations/collection_proxy.rb +913 -63
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -10
  23. data/lib/active_record/associations/has_many_association.rb +35 -9
  24. data/lib/active_record/associations/has_many_through_association.rb +24 -14
  25. data/lib/active_record/associations/has_one_association.rb +33 -13
  26. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +2 -2
  28. data/lib/active_record/associations/join_dependency/join_association.rb +17 -22
  29. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  30. data/lib/active_record/associations/join_helper.rb +1 -11
  31. data/lib/active_record/associations/preloader.rb +14 -17
  32. data/lib/active_record/associations/preloader/association.rb +29 -33
  33. data/lib/active_record/associations/preloader/collection_association.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  36. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +13 -17
  38. data/lib/active_record/associations/singular_association.rb +11 -11
  39. data/lib/active_record/associations/through_association.rb +2 -2
  40. data/lib/active_record/attribute_assignment.rb +133 -153
  41. data/lib/active_record/attribute_methods.rb +196 -93
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
  43. data/lib/active_record/attribute_methods/dirty.rb +31 -28
  44. data/lib/active_record/attribute_methods/primary_key.rb +38 -30
  45. data/lib/active_record/attribute_methods/query.rb +5 -4
  46. data/lib/active_record/attribute_methods/read.rb +62 -91
  47. data/lib/active_record/attribute_methods/serialization.rb +97 -66
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -45
  49. data/lib/active_record/attribute_methods/write.rb +32 -39
  50. data/lib/active_record/autosave_association.rb +56 -70
  51. data/lib/active_record/base.rb +53 -450
  52. data/lib/active_record/callbacks.rb +53 -18
  53. data/lib/active_record/coders/yaml_column.rb +11 -9
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +353 -197
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -131
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -19
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -3
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +101 -91
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +59 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +225 -96
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +99 -46
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +114 -36
  65. data/lib/active_record/connection_adapters/column.rb +46 -24
  66. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  67. data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
  68. data/lib/active_record/connection_adapters/mysql_adapter.rb +181 -64
  69. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
  70. data/lib/active_record/connection_adapters/postgresql/cast.rb +132 -0
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid.rb +347 -0
  73. data/lib/active_record/connection_adapters/postgresql/quoting.rb +158 -0
  74. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  75. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +448 -0
  76. data/lib/active_record/connection_adapters/postgresql_adapter.rb +454 -885
  77. data/lib/active_record/connection_adapters/schema_cache.rb +48 -16
  78. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +574 -13
  79. data/lib/active_record/connection_handling.rb +98 -0
  80. data/lib/active_record/core.rb +428 -0
  81. data/lib/active_record/counter_cache.rb +106 -108
  82. data/lib/active_record/dynamic_matchers.rb +110 -63
  83. data/lib/active_record/errors.rb +25 -8
  84. data/lib/active_record/explain.rb +8 -58
  85. data/lib/active_record/explain_subscriber.rb +6 -3
  86. data/lib/active_record/fixture_set/file.rb +56 -0
  87. data/lib/active_record/fixtures.rb +146 -148
  88. data/lib/active_record/inheritance.rb +77 -59
  89. data/lib/active_record/integration.rb +5 -5
  90. data/lib/active_record/locale/en.yml +8 -1
  91. data/lib/active_record/locking/optimistic.rb +38 -42
  92. data/lib/active_record/locking/pessimistic.rb +4 -4
  93. data/lib/active_record/log_subscriber.rb +19 -9
  94. data/lib/active_record/migration.rb +318 -153
  95. data/lib/active_record/migration/command_recorder.rb +90 -31
  96. data/lib/active_record/migration/join_table.rb +15 -0
  97. data/lib/active_record/model_schema.rb +69 -92
  98. data/lib/active_record/nested_attributes.rb +113 -148
  99. data/lib/active_record/null_relation.rb +65 -0
  100. data/lib/active_record/persistence.rb +188 -97
  101. data/lib/active_record/query_cache.rb +18 -36
  102. data/lib/active_record/querying.rb +19 -15
  103. data/lib/active_record/railtie.rb +91 -36
  104. data/lib/active_record/railties/console_sandbox.rb +0 -2
  105. data/lib/active_record/railties/controller_runtime.rb +2 -2
  106. data/lib/active_record/railties/databases.rake +90 -309
  107. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  108. data/lib/active_record/readonly_attributes.rb +7 -3
  109. data/lib/active_record/reflection.rb +72 -56
  110. data/lib/active_record/relation.rb +241 -157
  111. data/lib/active_record/relation/batches.rb +25 -22
  112. data/lib/active_record/relation/calculations.rb +143 -121
  113. data/lib/active_record/relation/delegation.rb +96 -18
  114. data/lib/active_record/relation/finder_methods.rb +117 -183
  115. data/lib/active_record/relation/merger.rb +133 -0
  116. data/lib/active_record/relation/predicate_builder.rb +90 -42
  117. data/lib/active_record/relation/query_methods.rb +666 -136
  118. data/lib/active_record/relation/spawn_methods.rb +43 -150
  119. data/lib/active_record/result.rb +33 -6
  120. data/lib/active_record/sanitization.rb +24 -50
  121. data/lib/active_record/schema.rb +19 -12
  122. data/lib/active_record/schema_dumper.rb +31 -39
  123. data/lib/active_record/schema_migration.rb +36 -0
  124. data/lib/active_record/scoping.rb +0 -124
  125. data/lib/active_record/scoping/default.rb +48 -45
  126. data/lib/active_record/scoping/named.rb +74 -103
  127. data/lib/active_record/serialization.rb +6 -2
  128. data/lib/active_record/serializers/xml_serializer.rb +9 -15
  129. data/lib/active_record/store.rb +119 -15
  130. data/lib/active_record/tasks/database_tasks.rb +158 -0
  131. data/lib/active_record/tasks/mysql_database_tasks.rb +138 -0
  132. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  133. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  134. data/lib/active_record/test_case.rb +61 -38
  135. data/lib/active_record/timestamp.rb +8 -9
  136. data/lib/active_record/transactions.rb +65 -51
  137. data/lib/active_record/validations.rb +17 -15
  138. data/lib/active_record/validations/associated.rb +20 -14
  139. data/lib/active_record/validations/presence.rb +65 -0
  140. data/lib/active_record/validations/uniqueness.rb +93 -52
  141. data/lib/active_record/version.rb +4 -4
  142. data/lib/rails/generators/active_record.rb +3 -5
  143. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -7
  144. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  145. data/lib/rails/generators/active_record/model/model_generator.rb +4 -3
  146. data/lib/rails/generators/active_record/model/templates/model.rb +1 -6
  147. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  148. metadata +53 -46
  149. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  150. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  151. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  152. data/lib/active_record/dynamic_finder_match.rb +0 -68
  153. data/lib/active_record/dynamic_scope_match.rb +0 -23
  154. data/lib/active_record/fixtures/file.rb +0 -65
  155. data/lib/active_record/identity_map.rb +0 -162
  156. data/lib/active_record/observer.rb +0 -121
  157. data/lib/active_record/session_store.rb +0 -360
  158. data/lib/rails/generators/active_record/migration.rb +0 -15
  159. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  160. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  161. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  162. 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 the logged along with
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 the logged along with
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 the logged along with
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(:requires_new => true) do # CREATE SAVEPOINT active_record_1
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
- last_transaction_joinable = defined?(@transaction_joinable) ? @transaction_joinable : nil
170
- if options.has_key?(:joinable)
171
- @transaction_joinable = options[:joinable]
199
+ yield
172
200
  else
173
- @transaction_joinable = true
201
+ within_new_transaction(options) { yield }
174
202
  end
175
- requires_new = options[:requires_new] || !last_transaction_joinable
176
-
177
- transaction_open = false
178
- @_current_transaction_records ||= []
203
+ rescue ActiveRecord::Rollback
204
+ # rollbacks are silently swallowed
205
+ end
179
206
 
180
- begin
181
- if block_given?
182
- if requires_new || open_transactions == 0
183
- if open_transactions == 0
184
- begin_db_transaction
185
- elsif requires_new
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
- @transaction_joinable = last_transaction_joinable
210
-
211
- if outside_transaction?
212
- @open_transactions = 0
213
- elsif transaction_open
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
- last_batch = @_current_transaction_records.last
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(DEFAULT)"
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
- subselect = select.clone
316
- subselect.projections = [update.key]
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
- update.where update.key.in(subselect)
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(*args)
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 # update_without_query_dirty(*args)
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
- result.collect { |row| row.dup }
79
- end
80
-
81
- def locked?(arel)
82
- if arel.respond_to?(:locked)
83
- arel.locked
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
- false
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 BigDecimal then value.to_s('F')
34
- when Numeric then value.to_s
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
- YAML.dump(value)
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