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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1162 -1792
- data/README.rdoc +15 -10
- data/lib/active_record.rb +4 -0
- data/lib/active_record/aggregations.rb +15 -8
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/associations/alias_tracker.rb +3 -12
- data/lib/active_record/associations/association.rb +16 -4
- data/lib/active_record/associations/association_scope.rb +83 -38
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +63 -27
- data/lib/active_record/associations/collection_proxy.rb +29 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +83 -22
- data/lib/active_record/associations/has_many_through_association.rb +49 -26
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +26 -13
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/preloader.rb +36 -26
- data/lib/active_record/associations/preloader/association.rb +14 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +5 -12
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +56 -94
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +107 -43
- data/lib/active_record/attribute_methods/primary_key.rb +7 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +16 -150
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +19 -12
- data/lib/active_record/base.rb +13 -24
- data/lib/active_record/callbacks.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
- data/lib/active_record/connection_adapters/column.rb +29 -240
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +163 -39
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -11
- data/lib/active_record/errors.rb +53 -30
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +55 -69
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +46 -26
- data/lib/active_record/migration.rb +71 -46
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/model_schema.rb +52 -58
- data/lib/active_record/nested_attributes.rb +5 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +46 -26
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +18 -11
- data/lib/active_record/railties/databases.rake +50 -51
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +273 -114
- data/lib/active_record/relation.rb +57 -25
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/finder_methods.rb +70 -47
- data/lib/active_record/relation/merger.rb +39 -29
- data/lib/active_record/relation/predicate_builder.rb +16 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
- data/lib/active_record/relation/query_methods.rb +114 -65
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +59 -28
- data/lib/active_record/schema_migration.rb +5 -4
- data/lib/active_record/scoping/default.rb +6 -4
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +61 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
- data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +53 -27
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +62 -0
- data/lib/active_record/type/string.rb +40 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +5 -3
- data/lib/active_record/validations/uniqueness.rb +25 -29
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +66 -11
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
data/lib/active_record/base.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
128
|
+
# super(minutes.to_i * 60)
|
127
129
|
# end
|
128
130
|
#
|
129
131
|
# def length
|
130
|
-
#
|
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
|
-
#
|
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
|
221
|
-
#
|
222
|
-
#
|
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.
|
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
|
-
|
292
|
+
_run_destroy_callbacks { super }
|
293
293
|
end
|
294
294
|
|
295
295
|
def touch(*) #:nodoc:
|
296
|
-
|
296
|
+
_run_touch_callbacks { super }
|
297
297
|
end
|
298
298
|
|
299
299
|
private
|
300
300
|
|
301
301
|
def create_or_update #:nodoc:
|
302
|
-
|
302
|
+
_run_save_callbacks { super }
|
303
303
|
end
|
304
304
|
|
305
305
|
def _create_record #:nodoc:
|
306
|
-
|
306
|
+
_run_create_callbacks { super }
|
307
307
|
end
|
308
308
|
|
309
309
|
def _update_record(*) #:nodoc:
|
310
|
-
|
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
|
62
|
-
# occur if a programmer forgets to close a
|
63
|
-
# thread or a thread dies unexpectedly.
|
64
|
-
#
|
65
|
-
#
|
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
|
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.
|
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
|
-
|
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
|
-
#
|
390
|
-
#
|
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
|
-
|
395
|
-
|
396
|
-
|
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 =
|
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
|
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.
|
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
|
-
#
|
467
|
-
#
|
468
|
-
#
|
469
|
-
#
|
470
|
-
#
|
471
|
-
#
|
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
|
-
#
|
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
|
-
#
|
480
|
-
#
|
481
|
-
#
|
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
|
-
|
502
|
-
|
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
|
-
|
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
|
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
|
-
|
13
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
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
|
-
|
295
|
-
|
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
|
330
|
-
# an UPDATE statement, so in the
|
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
|
-
|
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.
|
386
|
+
if relation.is_a?(Relation) && binds.empty?
|
385
387
|
relation, binds = relation.arel, relation.bind_values
|
386
388
|
end
|
387
389
|
[relation, binds]
|