activerecord 4.1.15 → 4.2.11.3

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 (185) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1162 -1792
  3. data/README.rdoc +15 -10
  4. data/lib/active_record.rb +4 -0
  5. data/lib/active_record/aggregations.rb +15 -8
  6. data/lib/active_record/association_relation.rb +13 -0
  7. data/lib/active_record/associations.rb +158 -49
  8. data/lib/active_record/associations/alias_tracker.rb +3 -12
  9. data/lib/active_record/associations/association.rb +16 -4
  10. data/lib/active_record/associations/association_scope.rb +83 -38
  11. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  12. data/lib/active_record/associations/builder/association.rb +15 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
  16. data/lib/active_record/associations/builder/has_many.rb +1 -1
  17. data/lib/active_record/associations/builder/has_one.rb +2 -2
  18. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  19. data/lib/active_record/associations/collection_association.rb +63 -27
  20. data/lib/active_record/associations/collection_proxy.rb +29 -35
  21. data/lib/active_record/associations/foreign_association.rb +11 -0
  22. data/lib/active_record/associations/has_many_association.rb +83 -22
  23. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  24. data/lib/active_record/associations/has_one_association.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -13
  26. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  27. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  28. data/lib/active_record/associations/preloader.rb +36 -26
  29. data/lib/active_record/associations/preloader/association.rb +14 -11
  30. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  31. data/lib/active_record/associations/singular_association.rb +17 -2
  32. data/lib/active_record/associations/through_association.rb +5 -12
  33. data/lib/active_record/attribute.rb +163 -0
  34. data/lib/active_record/attribute_assignment.rb +19 -11
  35. data/lib/active_record/attribute_decorators.rb +66 -0
  36. data/lib/active_record/attribute_methods.rb +56 -94
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  39. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  40. data/lib/active_record/attribute_methods/query.rb +1 -1
  41. data/lib/active_record/attribute_methods/read.rb +22 -59
  42. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
  44. data/lib/active_record/attribute_methods/write.rb +9 -24
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attribute_set/builder.rb +106 -0
  47. data/lib/active_record/attributes.rb +147 -0
  48. data/lib/active_record/autosave_association.rb +19 -12
  49. data/lib/active_record/base.rb +13 -24
  50. data/lib/active_record/callbacks.rb +6 -6
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  55. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
  63. data/lib/active_record/connection_adapters/column.rb +29 -240
  64. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  68. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  71. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  99. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
  100. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  101. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  102. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  103. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  104. data/lib/active_record/connection_handling.rb +1 -1
  105. data/lib/active_record/core.rb +163 -39
  106. data/lib/active_record/counter_cache.rb +60 -6
  107. data/lib/active_record/enum.rb +9 -11
  108. data/lib/active_record/errors.rb +53 -30
  109. data/lib/active_record/explain.rb +1 -1
  110. data/lib/active_record/explain_subscriber.rb +1 -1
  111. data/lib/active_record/fixtures.rb +55 -69
  112. data/lib/active_record/gem_version.rb +4 -4
  113. data/lib/active_record/inheritance.rb +35 -10
  114. data/lib/active_record/integration.rb +4 -4
  115. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  116. data/lib/active_record/locking/optimistic.rb +46 -26
  117. data/lib/active_record/migration.rb +71 -46
  118. data/lib/active_record/migration/command_recorder.rb +19 -2
  119. data/lib/active_record/migration/join_table.rb +1 -1
  120. data/lib/active_record/model_schema.rb +52 -58
  121. data/lib/active_record/nested_attributes.rb +5 -5
  122. data/lib/active_record/no_touching.rb +1 -1
  123. data/lib/active_record/persistence.rb +46 -26
  124. data/lib/active_record/query_cache.rb +3 -3
  125. data/lib/active_record/querying.rb +10 -7
  126. data/lib/active_record/railtie.rb +18 -11
  127. data/lib/active_record/railties/databases.rake +50 -51
  128. data/lib/active_record/readonly_attributes.rb +0 -1
  129. data/lib/active_record/reflection.rb +273 -114
  130. data/lib/active_record/relation.rb +57 -25
  131. data/lib/active_record/relation/batches.rb +0 -2
  132. data/lib/active_record/relation/calculations.rb +41 -37
  133. data/lib/active_record/relation/finder_methods.rb +70 -47
  134. data/lib/active_record/relation/merger.rb +39 -29
  135. data/lib/active_record/relation/predicate_builder.rb +16 -8
  136. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  137. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
  138. data/lib/active_record/relation/query_methods.rb +114 -65
  139. data/lib/active_record/relation/spawn_methods.rb +3 -0
  140. data/lib/active_record/result.rb +18 -7
  141. data/lib/active_record/sanitization.rb +12 -2
  142. data/lib/active_record/schema.rb +0 -1
  143. data/lib/active_record/schema_dumper.rb +59 -28
  144. data/lib/active_record/schema_migration.rb +5 -4
  145. data/lib/active_record/scoping/default.rb +6 -4
  146. data/lib/active_record/scoping/named.rb +4 -0
  147. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  148. data/lib/active_record/statement_cache.rb +95 -10
  149. data/lib/active_record/store.rb +5 -5
  150. data/lib/active_record/tasks/database_tasks.rb +61 -6
  151. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
  152. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  153. data/lib/active_record/timestamp.rb +9 -7
  154. data/lib/active_record/transactions.rb +53 -27
  155. data/lib/active_record/type.rb +23 -0
  156. data/lib/active_record/type/big_integer.rb +13 -0
  157. data/lib/active_record/type/binary.rb +50 -0
  158. data/lib/active_record/type/boolean.rb +31 -0
  159. data/lib/active_record/type/date.rb +50 -0
  160. data/lib/active_record/type/date_time.rb +54 -0
  161. data/lib/active_record/type/decimal.rb +64 -0
  162. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  163. data/lib/active_record/type/decorator.rb +14 -0
  164. data/lib/active_record/type/float.rb +19 -0
  165. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  166. data/lib/active_record/type/integer.rb +59 -0
  167. data/lib/active_record/type/mutable.rb +16 -0
  168. data/lib/active_record/type/numeric.rb +36 -0
  169. data/lib/active_record/type/serialized.rb +62 -0
  170. data/lib/active_record/type/string.rb +40 -0
  171. data/lib/active_record/type/text.rb +11 -0
  172. data/lib/active_record/type/time.rb +26 -0
  173. data/lib/active_record/type/time_value.rb +38 -0
  174. data/lib/active_record/type/type_map.rb +64 -0
  175. data/lib/active_record/type/unsigned_integer.rb +15 -0
  176. data/lib/active_record/type/value.rb +110 -0
  177. data/lib/active_record/validations.rb +25 -19
  178. data/lib/active_record/validations/associated.rb +5 -3
  179. data/lib/active_record/validations/presence.rb +5 -3
  180. data/lib/active_record/validations/uniqueness.rb +25 -29
  181. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  182. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  183. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  184. metadata +66 -11
  185. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -9,16 +9,19 @@ require 'active_support/core_ext/class/delegating_attributes'
9
9
  require 'active_support/core_ext/array/extract_options'
10
10
  require 'active_support/core_ext/hash/deep_merge'
11
11
  require 'active_support/core_ext/hash/slice'
12
+ require 'active_support/core_ext/hash/transform_values'
12
13
  require 'active_support/core_ext/string/behavior'
13
14
  require 'active_support/core_ext/kernel/singleton_class'
14
15
  require 'active_support/core_ext/module/introspection'
15
16
  require 'active_support/core_ext/object/duplicable'
16
17
  require 'active_support/core_ext/class/subclasses'
17
18
  require 'arel'
19
+ require 'active_record/attribute_decorators'
18
20
  require 'active_record/errors'
19
21
  require 'active_record/log_subscriber'
20
22
  require 'active_record/explain_subscriber'
21
23
  require 'active_record/relation/delegation'
24
+ require 'active_record/attributes'
22
25
 
23
26
  module ActiveRecord #:nodoc:
24
27
  # = Active Record
@@ -116,28 +119,28 @@ module ActiveRecord #:nodoc:
116
119
  # All column values are automatically available through basic accessors on the Active Record
117
120
  # object, but sometimes you want to specialize this behavior. This can be done by overwriting
118
121
  # the default accessors (using the same name as the attribute) and calling
119
- # <tt>read_attribute(attr_name)</tt> and <tt>write_attribute(attr_name, value)</tt> to actually
120
- # change things.
122
+ # +super+ to actually change things.
121
123
  #
122
124
  # class Song < ActiveRecord::Base
123
125
  # # Uses an integer of seconds to hold the length of the song
124
126
  #
125
127
  # def length=(minutes)
126
- # write_attribute(:length, minutes.to_i * 60)
128
+ # super(minutes.to_i * 60)
127
129
  # end
128
130
  #
129
131
  # def length
130
- # read_attribute(:length) / 60
132
+ # super / 60
131
133
  # end
132
134
  # end
133
135
  #
134
136
  # You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt>
135
- # instead of <tt>write_attribute(:attribute, value)</tt> and <tt>read_attribute(:attribute)</tt>.
137
+ # or <tt>write_attribute(:attribute, value)</tt> and <tt>read_attribute(:attribute)</tt>.
136
138
  #
137
139
  # == Attribute query methods
138
140
  #
139
141
  # In addition to the basic accessors, query methods are also automatically available on the Active Record object.
140
142
  # Query methods allow you to test whether an attribute value is present.
143
+ # For numeric values, present is defined as non-zero.
141
144
  #
142
145
  # For example, an Active Record User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
143
146
  # to determine whether the user has a name:
@@ -217,25 +220,9 @@ module ActiveRecord #:nodoc:
217
220
  #
218
221
  # == Single table inheritance
219
222
  #
220
- # Active Record allows inheritance by storing the name of the class in a column that by
221
- # default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
222
- # This means that an inheritance looking like this:
223
- #
224
- # class Company < ActiveRecord::Base; end
225
- # class Firm < Company; end
226
- # class Client < Company; end
227
- # class PriorityClient < Client; end
228
- #
229
- # When you do <tt>Firm.create(name: "37signals")</tt>, this record will be saved in
230
- # the companies table with type = "Firm". You can then fetch this row again using
231
- # <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object.
232
- #
233
- # If you don't have a type column defined in your table, single-table inheritance won't
234
- # be triggered. In that case, it'll work just like normal subclasses with no special magic
235
- # for differentiating between them or reloading the right type with find.
236
- #
237
- # Note, all the attributes for all the cases are kept in the same table. Read more:
238
- # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
223
+ # Active Record allows inheritance by storing the name of the class in a
224
+ # column that is named "type" by default. See ActiveRecord::Inheritance for
225
+ # more details.
239
226
  #
240
227
  # == Connection to multiple databases in different models
241
228
  #
@@ -306,6 +293,8 @@ module ActiveRecord #:nodoc:
306
293
  include Integration
307
294
  include Validations
308
295
  include CounterCache
296
+ include Attributes
297
+ include AttributeDecorators
309
298
  include Locking::Optimistic
310
299
  include Locking::Pessimistic
311
300
  include AttributeMethods
@@ -199,7 +199,7 @@ module ActiveRecord
199
199
  # == Canceling callbacks
200
200
  #
201
201
  # If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are
202
- # cancelled. If an <tt>after_*</tt> callback returns +false+, all the later callbacks are cancelled.
202
+ # cancelled.
203
203
  # Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
204
204
  # methods on the model, which are called last.
205
205
  #
@@ -289,25 +289,25 @@ module ActiveRecord
289
289
  end
290
290
 
291
291
  def destroy #:nodoc:
292
- run_callbacks(:destroy) { super }
292
+ _run_destroy_callbacks { super }
293
293
  end
294
294
 
295
295
  def touch(*) #:nodoc:
296
- run_callbacks(:touch) { super }
296
+ _run_touch_callbacks { super }
297
297
  end
298
298
 
299
299
  private
300
300
 
301
301
  def create_or_update #:nodoc:
302
- run_callbacks(:save) { super }
302
+ _run_save_callbacks { super }
303
303
  end
304
304
 
305
305
  def _create_record #:nodoc:
306
- run_callbacks(:create) { super }
306
+ _run_create_callbacks { super }
307
307
  end
308
308
 
309
309
  def _update_record(*) #:nodoc:
310
- run_callbacks(:update) { super }
310
+ _run_update_callbacks { super }
311
311
  end
312
312
  end
313
313
  end
@@ -2,6 +2,7 @@ require 'thread'
2
2
  require 'thread_safe'
3
3
  require 'monitor'
4
4
  require 'set'
5
+ require 'active_support/core_ext/string/filters'
5
6
 
6
7
  module ActiveRecord
7
8
  # Raised when a connection could not be obtained within the connection
@@ -58,13 +59,11 @@ module ActiveRecord
58
59
  # * +checkout_timeout+: number of seconds to block and wait for a connection
59
60
  # before giving up and raising a timeout error (default 5 seconds).
60
61
  # * +reaping_frequency+: frequency in seconds to periodically run the
61
- # Reaper, which attempts to find and close dead connections, which can
62
- # occur if a programmer forgets to close a connection at the end of a
63
- # thread or a thread dies unexpectedly. (Default nil, which means don't
64
- # run the Reaper).
65
- # * +dead_connection_timeout+: number of seconds from last checkout
66
- # after which the Reaper will consider a connection reapable. (default
67
- # 5 seconds).
62
+ # Reaper, which attempts to find and recover connections from dead
63
+ # threads, which can occur if a programmer forgets to close a
64
+ # connection at the end of a thread or a thread dies unexpectedly.
65
+ # Regardless of this setting, the Reaper will be invoked before every
66
+ # blocking wait. (Default nil, which means don't schedule the Reaper).
68
67
  class ConnectionPool
69
68
  # Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool
70
69
  # with which it shares a Monitor. But could be a generic Queue.
@@ -222,7 +221,7 @@ module ActiveRecord
222
221
 
223
222
  include MonitorMixin
224
223
 
225
- attr_accessor :automatic_reconnect, :checkout_timeout, :dead_connection_timeout
224
+ attr_accessor :automatic_reconnect, :checkout_timeout
226
225
  attr_reader :spec, :connections, :size, :reaper
227
226
 
228
227
  # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
@@ -237,7 +236,6 @@ module ActiveRecord
237
236
  @spec = spec
238
237
 
239
238
  @checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
240
- @dead_connection_timeout = (spec.config[:dead_connection_timeout] && spec.config[:dead_connection_timeout].to_f) || 5
241
239
  @reaper = Reaper.new(self, (spec.config[:reaping_frequency] && spec.config[:reaping_frequency].to_f))
242
240
  @reaper.run
243
241
 
@@ -361,11 +359,13 @@ module ActiveRecord
361
359
  # calling +checkout+ on this pool.
362
360
  def checkin(conn)
363
361
  synchronize do
364
- conn.run_callbacks :checkin do
362
+ owner = conn.owner
363
+
364
+ conn._run_checkin_callbacks do
365
365
  conn.expire
366
366
  end
367
367
 
368
- release conn
368
+ release conn, owner
369
369
 
370
370
  @available.add conn
371
371
  end
@@ -378,22 +378,28 @@ module ActiveRecord
378
378
  @connections.delete conn
379
379
  @available.delete conn
380
380
 
381
- # FIXME: we might want to store the key on the connection so that removing
382
- # from the reserved hash will be a little easier.
383
- release conn
381
+ release conn, conn.owner
384
382
 
385
383
  @available.add checkout_new_connection if @available.any_waiting?
386
384
  end
387
385
  end
388
386
 
389
- # Removes dead connections from the pool. A dead connection can occur
390
- # if a programmer forgets to close a connection at the end of a thread
387
+ # Recover lost connections for the pool. A lost connection can occur if
388
+ # a programmer forgets to checkin a connection at the end of a thread
391
389
  # or a thread dies unexpectedly.
392
390
  def reap
393
- synchronize do
394
- stale = Time.now - @dead_connection_timeout
395
- connections.dup.each do |conn|
396
- if conn.in_use? && stale > conn.last_use && !conn.active_threadsafe?
391
+ stale_connections = synchronize do
392
+ @connections.select do |conn|
393
+ conn.in_use? && !conn.owner.alive?
394
+ end
395
+ end
396
+
397
+ stale_connections.each do |conn|
398
+ synchronize do
399
+ if conn.active?
400
+ conn.reset!
401
+ checkin conn
402
+ else
397
403
  remove conn
398
404
  end
399
405
  end
@@ -415,20 +421,17 @@ module ActiveRecord
415
421
  elsif @connections.size < @size
416
422
  checkout_new_connection
417
423
  else
424
+ reap
418
425
  @available.poll(@checkout_timeout)
419
426
  end
420
427
  end
421
428
 
422
- def release(conn)
423
- thread_id = if @reserved_connections[current_connection_id] == conn
424
- current_connection_id
425
- else
426
- @reserved_connections.keys.find { |k|
427
- @reserved_connections[k] == conn
428
- }
429
- end
429
+ def release(conn, owner)
430
+ thread_id = owner.object_id
430
431
 
431
- @reserved_connections.delete thread_id if thread_id
432
+ if @reserved_connections[thread_id] == conn
433
+ @reserved_connections.delete thread_id
434
+ end
432
435
  end
433
436
 
434
437
  def new_connection
@@ -449,10 +452,14 @@ module ActiveRecord
449
452
  end
450
453
 
451
454
  def checkout_and_verify(c)
452
- c.run_callbacks :checkout do
455
+ c._run_checkout_callbacks do
453
456
  c.verify!
454
457
  end
455
458
  c
459
+ rescue
460
+ remove c
461
+ c.disconnect!
462
+ raise
456
463
  end
457
464
  end
458
465
 
@@ -462,23 +469,44 @@ module ActiveRecord
462
469
  #
463
470
  # For example, suppose that you have 5 models, with the following hierarchy:
464
471
  #
465
- # |
466
- # +-- Book
467
- # | |
468
- # | +-- ScaryBook
469
- # | +-- GoodBook
470
- # +-- Author
471
- # +-- BankAccount
472
+ # class Author < ActiveRecord::Base
473
+ # end
474
+ #
475
+ # class BankAccount < ActiveRecord::Base
476
+ # end
477
+ #
478
+ # class Book < ActiveRecord::Base
479
+ # establish_connection "library_db"
480
+ # end
481
+ #
482
+ # class ScaryBook < Book
483
+ # end
484
+ #
485
+ # class GoodBook < Book
486
+ # end
472
487
  #
473
- # Suppose that Book is to connect to a separate database (i.e. one other
474
- # than the default database). Then Book, ScaryBook and GoodBook will all use
475
- # the same connection pool. Likewise, Author and BankAccount will use the
476
- # same connection pool. However, the connection pool used by Author/BankAccount
477
- # is not the same as the one used by Book/ScaryBook/GoodBook.
488
+ # And a database.yml that looked like this:
478
489
  #
479
- # Normally there is only a single ConnectionHandler instance, accessible via
480
- # ActiveRecord::Base.connection_handler. Active Record models use this to
481
- # determine the connection pool that they should use.
490
+ # development:
491
+ # database: my_application
492
+ # host: localhost
493
+ #
494
+ # library_db:
495
+ # database: library
496
+ # host: some.library.org
497
+ #
498
+ # Your primary database in the development environment is "my_application"
499
+ # but the Book model connects to a separate database called "library_db"
500
+ # (this can even be a database on a different machine).
501
+ #
502
+ # Book, ScaryBook and GoodBook will all use the same connection pool to
503
+ # "library_db" while Author, BankAccount, and any other models you create
504
+ # will use the default connection pool to "my_application".
505
+ #
506
+ # The various connection pools are managed by a single instance of
507
+ # ConnectionHandler accessible via ActiveRecord::Base.connection_handler.
508
+ # All Active Record models use this handler to determine the connection pool that they
509
+ # should use.
482
510
  class ConnectionHandler
483
511
  def initialize
484
512
  # These caches are keyed by klass.name, NOT klass. Keying them by klass
@@ -497,10 +525,11 @@ module ActiveRecord
497
525
  end
498
526
 
499
527
  def connection_pools
500
- ActiveSupport::Deprecation.warn(
501
- "In the next release, this will return the same as #connection_pool_list. " \
502
- "(An array of pools, rather than a hash mapping specs to pools.)"
503
- )
528
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
529
+ In the next release, this will return the same as `#connection_pool_list`.
530
+ (An array of pools, rather than a hash mapping specs to pools.)
531
+ MSG
532
+
504
533
  Hash[connection_pool_list.map { |pool| [pool.spec, pool] }]
505
534
  end
506
535
 
@@ -538,7 +567,10 @@ module ActiveRecord
538
567
  # for (not necessarily the current class).
539
568
  def retrieve_connection(klass) #:nodoc:
540
569
  pool = retrieve_connection_pool(klass)
541
- (pool && pool.connection) or raise ConnectionNotEstablished
570
+ raise ConnectionNotEstablished, "No connection pool for #{klass}" unless pool
571
+ conn = pool.connection
572
+ raise ConnectionNotEstablished, "No connection for #{klass} in connection pool" unless conn
573
+ conn
542
574
  end
543
575
 
544
576
  # Returns true if a connection that's accessible to this class has
@@ -605,7 +637,7 @@ module ActiveRecord
605
637
  end
606
638
 
607
639
  def pool_from_any_process_for(owner)
608
- owner_to_pool = @owner_to_pool.values.find { |v| v[owner.name] }
640
+ owner_to_pool = @owner_to_pool.values.reverse.find { |v| v[owner.name] }
609
641
  owner_to_pool && owner_to_pool[owner.name]
610
642
  end
611
643
  end
@@ -616,7 +648,7 @@ module ActiveRecord
616
648
  end
617
649
 
618
650
  def call(env)
619
- testing = env.key?('rack.test')
651
+ testing = env['rack.test']
620
652
 
621
653
  response = @app.call(env)
622
654
  response[2] = ::Rack::BodyProxy.new(response[2]) do
@@ -9,15 +9,23 @@ module ActiveRecord
9
9
  # Converts an arel AST to SQL
10
10
  def to_sql(arel, binds = [])
11
11
  if arel.respond_to?(:ast)
12
- binds = binds.dup
13
- visitor.accept(arel.ast) do
14
- quote(*binds.shift.reverse)
15
- end
12
+ collected = visitor.accept(arel.ast, collector)
13
+ collected.compile(binds.dup, self)
16
14
  else
17
15
  arel
18
16
  end
19
17
  end
20
18
 
19
+ # This is used in the StatementCache object. It returns an object that
20
+ # can be used to query the database repeatedly.
21
+ def cacheable_query(arel) # :nodoc:
22
+ if prepared_statements
23
+ ActiveRecord::StatementCache.query visitor, arel.ast
24
+ else
25
+ ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector
26
+ end
27
+ end
28
+
21
29
  # Returns an ActiveRecord::Result instance.
22
30
  def select_all(arel, name = nil, binds = [])
23
31
  arel, binds = binds_from_relation arel, binds
@@ -75,6 +83,11 @@ module ActiveRecord
75
83
  exec_query(sql, name, binds)
76
84
  end
77
85
 
86
+ # Executes the truncate statement.
87
+ def truncate(table_name, name = nil)
88
+ raise NotImplementedError
89
+ end
90
+
78
91
  # Executes update +sql+ statement in the context of this connection using
79
92
  # +binds+ as the bind substitutes. +name+ is logged along with
80
93
  # the executed +sql+ statement.
@@ -185,7 +198,7 @@ module ActiveRecord
185
198
  # * You are creating a nested (savepoint) transaction
186
199
  #
187
200
  # The mysql, mysql2 and postgresql adapters support setting the transaction
188
- # isolation level. However, support is disabled for mysql versions below 5,
201
+ # isolation level. However, support is disabled for MySQL versions below 5,
189
202
  # because they are affected by a bug[http://bugs.mysql.com/bug.php?id=39170]
190
203
  # which means the isolation level gets persisted outside the transaction.
191
204
  def transaction(options = {})
@@ -195,58 +208,34 @@ module ActiveRecord
195
208
  if options[:isolation]
196
209
  raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
197
210
  end
198
-
199
211
  yield
200
212
  else
201
- within_new_transaction(options) { yield }
213
+ transaction_manager.within_new_transaction(options) { yield }
202
214
  end
203
215
  rescue ActiveRecord::Rollback
204
216
  # rollbacks are silently swallowed
205
217
  end
206
218
 
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
213
- ensure
214
- begin
215
- commit_transaction unless error
216
- rescue Exception
217
- rollback_transaction
218
- raise
219
- end
220
- end
219
+ attr_reader :transaction_manager #:nodoc:
221
220
 
222
- def current_transaction #:nodoc:
223
- @transaction
224
- end
221
+ delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction, :commit_transaction, :rollback_transaction, to: :transaction_manager
225
222
 
226
223
  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
224
+ current_transaction.open?
240
225
  end
241
226
 
242
227
  def reset_transaction #:nodoc:
243
- @transaction = ClosedTransaction.new(self)
228
+ @transaction_manager = TransactionManager.new(self)
244
229
  end
245
230
 
246
231
  # Register a record with the current transaction so that its after_commit and after_rollback callbacks
247
232
  # can be called.
248
233
  def add_transaction_record(record)
249
- @transaction.add_record(record)
234
+ current_transaction.add_record(record)
235
+ end
236
+
237
+ def transaction_state
238
+ current_transaction.state
250
239
  end
251
240
 
252
241
  # Begins the transaction (and turns off auto-committing).
@@ -273,7 +262,18 @@ module ActiveRecord
273
262
 
274
263
  # Rolls back the transaction (and turns on auto-committing). Must be
275
264
  # done if the transaction block raises an exception or returns false.
276
- def rollback_db_transaction() end
265
+ def rollback_db_transaction
266
+ exec_rollback_db_transaction
267
+ end
268
+
269
+ def exec_rollback_db_transaction() end #:nodoc:
270
+
271
+ def rollback_to_savepoint(name = nil)
272
+ exec_rollback_to_savepoint(name)
273
+ end
274
+
275
+ def exec_rollback_to_savepoint(name = nil) #:nodoc:
276
+ end
277
277
 
278
278
  def default_sequence_name(table, column)
279
279
  nil
@@ -287,12 +287,17 @@ module ActiveRecord
287
287
  # Inserts the given fixture into the table. Overridden in adapters that require
288
288
  # something beyond a simple insert (eg. Oracle).
289
289
  def insert_fixture(fixture, table_name)
290
+ fixture = fixture.stringify_keys
290
291
  columns = schema_cache.columns_hash(table_name)
291
292
 
292
293
  key_list = []
293
294
  value_list = fixture.map do |name, value|
294
- key_list << quote_column_name(name)
295
- quote(value, columns[name])
295
+ if column = columns[name]
296
+ key_list << quote_column_name(name)
297
+ quote(value, column)
298
+ else
299
+ raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
300
+ end
296
301
  end
297
302
 
298
303
  execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
@@ -302,10 +307,6 @@ module ActiveRecord
302
307
  "DEFAULT VALUES"
303
308
  end
304
309
 
305
- def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
306
- "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
307
- end
308
-
309
310
  # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
310
311
  #
311
312
  # The +limit+ may be anything that can evaluate to a string via #to_s. It
@@ -326,8 +327,8 @@ module ActiveRecord
326
327
  end
327
328
 
328
329
  # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
329
- # on mysql (even when aliasing the tables), but mysql allows using JOIN directly in
330
- # an UPDATE statement, so in the mysql adapters we redefine this to do that.
330
+ # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
331
+ # an UPDATE statement, so in the MySQL adapters we redefine this to do that.
331
332
  def join_to_update(update, select) #:nodoc:
332
333
  key = update.key
333
334
  subselect = subquery_for(key, select)
@@ -352,8 +353,9 @@ module ActiveRecord
352
353
 
353
354
  # Returns an ActiveRecord::Result instance.
354
355
  def select(sql, name = nil, binds = [])
356
+ exec_query(sql, name, binds)
355
357
  end
356
- undef_method :select
358
+
357
359
 
358
360
  # Returns the last auto-generated ID from the affected table.
359
361
  def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
@@ -381,7 +383,7 @@ module ActiveRecord
381
383
  end
382
384
 
383
385
  def binds_from_relation(relation, binds)
384
- if relation.is_a?(Relation) && binds.blank?
386
+ if relation.is_a?(Relation) && binds.empty?
385
387
  relation, binds = relation.arel, relation.bind_values
386
388
  end
387
389
  [relation, binds]