activerecord 3.2.22.4 → 4.0.13

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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2799 -617
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +23 -32
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +40 -34
  7. data/lib/active_record/association_relation.rb +22 -0
  8. data/lib/active_record/associations/alias_tracker.rb +4 -2
  9. data/lib/active_record/associations/association.rb +60 -46
  10. data/lib/active_record/associations/association_scope.rb +46 -40
  11. data/lib/active_record/associations/belongs_to_association.rb +17 -4
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  13. data/lib/active_record/associations/builder/association.rb +81 -28
  14. data/lib/active_record/associations/builder/belongs_to.rb +73 -56
  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 +130 -96
  21. data/lib/active_record/associations/collection_proxy.rb +916 -63
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +15 -13
  23. data/lib/active_record/associations/has_many_association.rb +35 -8
  24. data/lib/active_record/associations/has_many_through_association.rb +37 -17
  25. data/lib/active_record/associations/has_one_association.rb +42 -19
  26. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_association.rb +39 -22
  28. data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
  29. data/lib/active_record/associations/join_dependency/join_part.rb +21 -8
  30. data/lib/active_record/associations/join_dependency.rb +30 -9
  31. data/lib/active_record/associations/join_helper.rb +1 -11
  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 +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
  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/preloader.rb +20 -43
  39. data/lib/active_record/associations/singular_association.rb +11 -11
  40. data/lib/active_record/associations/through_association.rb +3 -3
  41. data/lib/active_record/associations.rb +223 -282
  42. data/lib/active_record/attribute_assignment.rb +134 -154
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
  44. data/lib/active_record/attribute_methods/dirty.rb +36 -29
  45. data/lib/active_record/attribute_methods/primary_key.rb +45 -31
  46. data/lib/active_record/attribute_methods/query.rb +5 -4
  47. data/lib/active_record/attribute_methods/read.rb +67 -90
  48. data/lib/active_record/attribute_methods/serialization.rb +133 -70
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +51 -45
  50. data/lib/active_record/attribute_methods/write.rb +34 -39
  51. data/lib/active_record/attribute_methods.rb +268 -108
  52. data/lib/active_record/autosave_association.rb +80 -73
  53. data/lib/active_record/base.rb +54 -451
  54. data/lib/active_record/callbacks.rb +60 -22
  55. data/lib/active_record/coders/yaml_column.rb +18 -21
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +347 -197
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +146 -138
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -19
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +19 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +151 -142
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +499 -217
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +208 -0
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +209 -44
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +169 -61
  67. data/lib/active_record/connection_adapters/column.rb +67 -36
  68. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +28 -29
  70. data/lib/active_record/connection_adapters/mysql_adapter.rb +200 -73
  71. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +98 -0
  72. data/lib/active_record/connection_adapters/postgresql/cast.rb +160 -0
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +240 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +374 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +183 -0
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +508 -0
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +544 -899
  79. data/lib/active_record/connection_adapters/schema_cache.rb +76 -16
  80. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +595 -16
  81. data/lib/active_record/connection_handling.rb +98 -0
  82. data/lib/active_record/core.rb +472 -0
  83. data/lib/active_record/counter_cache.rb +107 -108
  84. data/lib/active_record/dynamic_matchers.rb +115 -63
  85. data/lib/active_record/errors.rb +36 -18
  86. data/lib/active_record/explain.rb +15 -63
  87. data/lib/active_record/explain_registry.rb +30 -0
  88. data/lib/active_record/explain_subscriber.rb +8 -4
  89. data/lib/active_record/fixture_set/file.rb +55 -0
  90. data/lib/active_record/fixtures.rb +159 -155
  91. data/lib/active_record/inheritance.rb +93 -59
  92. data/lib/active_record/integration.rb +8 -8
  93. data/lib/active_record/locale/en.yml +8 -1
  94. data/lib/active_record/locking/optimistic.rb +39 -43
  95. data/lib/active_record/locking/pessimistic.rb +4 -4
  96. data/lib/active_record/log_subscriber.rb +19 -9
  97. data/lib/active_record/migration/command_recorder.rb +102 -33
  98. data/lib/active_record/migration/join_table.rb +15 -0
  99. data/lib/active_record/migration.rb +411 -173
  100. data/lib/active_record/model_schema.rb +81 -94
  101. data/lib/active_record/nested_attributes.rb +173 -131
  102. data/lib/active_record/null_relation.rb +67 -0
  103. data/lib/active_record/persistence.rb +254 -106
  104. data/lib/active_record/query_cache.rb +18 -36
  105. data/lib/active_record/querying.rb +19 -15
  106. data/lib/active_record/railtie.rb +113 -38
  107. data/lib/active_record/railties/console_sandbox.rb +3 -4
  108. data/lib/active_record/railties/controller_runtime.rb +4 -3
  109. data/lib/active_record/railties/databases.rake +115 -368
  110. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  111. data/lib/active_record/readonly_attributes.rb +7 -3
  112. data/lib/active_record/reflection.rb +110 -61
  113. data/lib/active_record/relation/batches.rb +29 -29
  114. data/lib/active_record/relation/calculations.rb +155 -125
  115. data/lib/active_record/relation/delegation.rb +94 -18
  116. data/lib/active_record/relation/finder_methods.rb +151 -203
  117. data/lib/active_record/relation/merger.rb +188 -0
  118. data/lib/active_record/relation/predicate_builder.rb +85 -42
  119. data/lib/active_record/relation/query_methods.rb +793 -146
  120. data/lib/active_record/relation/spawn_methods.rb +43 -150
  121. data/lib/active_record/relation.rb +293 -173
  122. data/lib/active_record/result.rb +48 -7
  123. data/lib/active_record/runtime_registry.rb +17 -0
  124. data/lib/active_record/sanitization.rb +41 -54
  125. data/lib/active_record/schema.rb +19 -12
  126. data/lib/active_record/schema_dumper.rb +41 -41
  127. data/lib/active_record/schema_migration.rb +46 -0
  128. data/lib/active_record/scoping/default.rb +56 -52
  129. data/lib/active_record/scoping/named.rb +78 -103
  130. data/lib/active_record/scoping.rb +54 -124
  131. data/lib/active_record/serialization.rb +6 -2
  132. data/lib/active_record/serializers/xml_serializer.rb +9 -15
  133. data/lib/active_record/statement_cache.rb +26 -0
  134. data/lib/active_record/store.rb +131 -15
  135. data/lib/active_record/tasks/database_tasks.rb +204 -0
  136. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  137. data/lib/active_record/tasks/mysql_database_tasks.rb +144 -0
  138. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  139. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  140. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  141. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  142. data/lib/active_record/test_case.rb +67 -38
  143. data/lib/active_record/timestamp.rb +16 -11
  144. data/lib/active_record/transactions.rb +73 -51
  145. data/lib/active_record/validations/associated.rb +19 -13
  146. data/lib/active_record/validations/presence.rb +65 -0
  147. data/lib/active_record/validations/uniqueness.rb +110 -57
  148. data/lib/active_record/validations.rb +18 -17
  149. data/lib/active_record/version.rb +7 -6
  150. data/lib/active_record.rb +63 -45
  151. data/lib/rails/generators/active_record/migration/migration_generator.rb +45 -8
  152. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
  153. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  154. data/lib/rails/generators/active_record/model/model_generator.rb +5 -4
  155. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  156. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  157. data/lib/rails/generators/active_record.rb +3 -5
  158. metadata +43 -29
  159. data/examples/associations.png +0 -0
  160. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  161. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  162. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  163. data/lib/active_record/dynamic_finder_match.rb +0 -68
  164. data/lib/active_record/dynamic_scope_match.rb +0 -23
  165. data/lib/active_record/fixtures/file.rb +0 -65
  166. data/lib/active_record/identity_map.rb +0 -162
  167. data/lib/active_record/observer.rb +0 -121
  168. data/lib/active_record/session_store.rb +0 -360
  169. data/lib/rails/generators/active_record/migration.rb +0 -15
  170. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  171. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  172. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  173. 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
+ # operations to use prefixes in temporary operations.
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
@@ -15,19 +21,20 @@ module ActiveRecord
15
21
  # Returns an array of record hashes with the column names as keys and
16
22
  # column values as values.
17
23
  def select_all(arel, name = nil, binds = [])
24
+ arel, binds = binds_from_relation arel, binds
18
25
  select(to_sql(arel, binds), name, binds)
19
26
  end
20
27
 
21
28
  # Returns a record hash with the column names as keys and column values
22
29
  # as values.
23
- def select_one(arel, name = nil)
24
- result = select_all(arel, name)
30
+ def select_one(arel, name = nil, binds = [])
31
+ result = select_all(arel, name, binds)
25
32
  result.first if result
26
33
  end
27
34
 
28
35
  # Returns a single value from a record
29
- def select_value(arel, name = nil)
30
- if result = select_one(arel, name)
36
+ def select_value(arel, name = nil, binds = [])
37
+ if result = select_one(arel, name, binds)
31
38
  result.values.first
32
39
  end
33
40
  end
@@ -35,13 +42,13 @@ module ActiveRecord
35
42
  # Returns an array of the values of the first column in a select:
36
43
  # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
37
44
  def select_values(arel, name = nil)
38
- result = select_rows(to_sql(arel, []), name)
39
- result.map { |v| v[0] }
45
+ arel, binds = binds_from_relation arel, []
46
+ select_rows(to_sql(arel, binds), name, binds).map(&:first)
40
47
  end
41
48
 
42
49
  # Returns an array of arrays containing the field values.
43
50
  # Order is the same as that returned by +columns+.
44
- def select_rows(sql, name = nil)
51
+ def select_rows(sql, name = nil, binds = [])
45
52
  end
46
53
  undef_method :select_rows
47
54
 
@@ -57,21 +64,21 @@ module ActiveRecord
57
64
  end
58
65
 
59
66
  # Executes insert +sql+ statement in the context of this connection using
60
- # +binds+ as the bind substitutes. +name+ is the logged along with
67
+ # +binds+ as the bind substitutes. +name+ is logged along with
61
68
  # the executed +sql+ statement.
62
- def exec_insert(sql, name, binds)
69
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
63
70
  exec_query(sql, name, binds)
64
71
  end
65
72
 
66
73
  # Executes delete +sql+ statement in the context of this connection using
67
- # +binds+ as the bind substitutes. +name+ is the logged along with
74
+ # +binds+ as the bind substitutes. +name+ is logged along with
68
75
  # the executed +sql+ statement.
69
76
  def exec_delete(sql, name, binds)
70
77
  exec_query(sql, name, binds)
71
78
  end
72
79
 
73
80
  # Executes update +sql+ statement in the context of this connection using
74
- # +binds+ as the bind substitutes. +name+ is the logged along with
81
+ # +binds+ as the bind substitutes. +name+ is logged along with
75
82
  # the executed +sql+ statement.
76
83
  def exec_update(sql, name, binds)
77
84
  exec_query(sql, name, binds)
@@ -87,7 +94,7 @@ module ActiveRecord
87
94
  # passed in as +id_value+.
88
95
  def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
89
96
  sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
90
- value = exec_insert(sql, name, binds)
97
+ value = exec_insert(sql, name, binds, pk, sequence_name)
91
98
  id_value || last_inserted_id(value)
92
99
  end
93
100
 
@@ -101,20 +108,6 @@ module ActiveRecord
101
108
  exec_delete(to_sql(arel, binds), name, binds)
102
109
  end
103
110
 
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
111
  # Returns +true+ when the connection adapter supports prepared statement
119
112
  # caching, otherwise returns +false+
120
113
  def supports_statement_cache?
@@ -133,7 +126,8 @@ module ActiveRecord
133
126
  # In order to get around this problem, #transaction will emulate the effect
134
127
  # of nested transactions, by using savepoints:
135
128
  # http://dev.mysql.com/doc/refman/5.0/en/savepoint.html
136
- # Savepoints are supported by MySQL and PostgreSQL, but not SQLite3.
129
+ # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
130
+ # supports savepoints.
137
131
  #
138
132
  # It is safe to call this method if a database transaction is already open,
139
133
  # i.e. if #transaction is called within another #transaction block. In case
@@ -158,95 +152,124 @@ module ActiveRecord
158
152
  # already-automatically-released savepoints:
159
153
  #
160
154
  # Model.connection.transaction do # BEGIN
161
- # Model.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1
155
+ # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
162
156
  # Model.connection.create_table(...)
163
157
  # # active_record_1 now automatically released
164
158
  # end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
165
159
  # end
160
+ #
161
+ # == Transaction isolation
162
+ #
163
+ # If your database supports setting the isolation level for a transaction, you can set
164
+ # it like so:
165
+ #
166
+ # Post.transaction(isolation: :serializable) do
167
+ # # ...
168
+ # end
169
+ #
170
+ # Valid isolation levels are:
171
+ #
172
+ # * <tt>:read_uncommitted</tt>
173
+ # * <tt>:read_committed</tt>
174
+ # * <tt>:repeatable_read</tt>
175
+ # * <tt>:serializable</tt>
176
+ #
177
+ # You should consult the documentation for your database to understand the
178
+ # semantics of these different levels:
179
+ #
180
+ # * http://www.postgresql.org/docs/9.1/static/transaction-iso.html
181
+ # * https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
182
+ #
183
+ # An <tt>ActiveRecord::TransactionIsolationError</tt> will be raised if:
184
+ #
185
+ # * The adapter does not support setting the isolation level
186
+ # * You are joining an existing open transaction
187
+ # * You are creating a nested (savepoint) transaction
188
+ #
189
+ # The mysql, mysql2 and postgresql adapters support setting the transaction
190
+ # isolation level. However, support is disabled for mysql versions below 5,
191
+ # because they are affected by a bug[http://bugs.mysql.com/bug.php?id=39170]
192
+ # which means the isolation level gets persisted outside the transaction.
166
193
  def transaction(options = {})
167
- options.assert_valid_keys :requires_new, :joinable
194
+ options.assert_valid_keys :requires_new, :joinable, :isolation
195
+
196
+ if !options[:requires_new] && current_transaction.joinable?
197
+ if options[:isolation]
198
+ raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
199
+ end
168
200
 
169
- last_transaction_joinable = defined?(@transaction_joinable) ? @transaction_joinable : nil
170
- if options.has_key?(:joinable)
171
- @transaction_joinable = options[:joinable]
201
+ yield
172
202
  else
173
- @transaction_joinable = true
203
+ within_new_transaction(options) { yield }
174
204
  end
175
- requires_new = options[:requires_new] || !last_transaction_joinable
176
-
177
- transaction_open = false
178
- @_current_transaction_records ||= []
205
+ rescue ActiveRecord::Rollback
206
+ # rollbacks are silently swallowed
207
+ end
179
208
 
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
209
+ def within_new_transaction(options = {}) #:nodoc:
210
+ transaction = begin_transaction(options)
211
+ yield
212
+ rescue Exception => error
213
+ rollback_transaction if transaction
214
+ raise
208
215
  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
216
+ begin
217
+ commit_transaction unless error
218
+ rescue Exception
219
+ rollback_transaction
220
+ raise
237
221
  end
238
222
  end
239
223
 
224
+ def current_transaction #:nodoc:
225
+ @transaction
226
+ end
227
+
228
+ def transaction_open?
229
+ @transaction.open?
230
+ end
231
+
232
+ def begin_transaction(options = {}) #:nodoc:
233
+ @transaction = @transaction.begin(options)
234
+ end
235
+
236
+ def commit_transaction #:nodoc:
237
+ @transaction = @transaction.commit
238
+ end
239
+
240
+ def rollback_transaction #:nodoc:
241
+ @transaction = @transaction.rollback
242
+ end
243
+
244
+ def reset_transaction #:nodoc:
245
+ @transaction = ClosedTransaction.new(self)
246
+ end
247
+
240
248
  # Register a record with the current transaction so that its after_commit and after_rollback callbacks
241
249
  # can be called.
242
250
  def add_transaction_record(record)
243
- last_batch = @_current_transaction_records.last
244
- last_batch << record if last_batch
251
+ @transaction.add_record(record)
245
252
  end
246
253
 
247
254
  # Begins the transaction (and turns off auto-committing).
248
255
  def begin_db_transaction() end
249
256
 
257
+ def transaction_isolation_levels
258
+ {
259
+ read_uncommitted: "READ UNCOMMITTED",
260
+ read_committed: "READ COMMITTED",
261
+ repeatable_read: "REPEATABLE READ",
262
+ serializable: "SERIALIZABLE"
263
+ }
264
+ end
265
+
266
+ # Begins the transaction with the isolation level set. Raises an error by
267
+ # default; adapters that support setting the isolation level should implement
268
+ # this method.
269
+ def begin_isolated_db_transaction(isolation)
270
+ raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
271
+ end
272
+
250
273
  # Commits the transaction (and turns on auto-committing).
251
274
  def commit_db_transaction() end
252
275
 
@@ -278,7 +301,7 @@ module ActiveRecord
278
301
  end
279
302
 
280
303
  def empty_insert_statement_value
281
- "VALUES(DEFAULT)"
304
+ "DEFAULT VALUES"
282
305
  end
283
306
 
284
307
  def case_sensitive_equality_operator
@@ -312,13 +335,27 @@ module ActiveRecord
312
335
  # on mysql (even when aliasing the tables), but mysql allows using JOIN directly in
313
336
  # an UPDATE statement, so in the mysql adapters we redefine this to do that.
314
337
  def join_to_update(update, select) #:nodoc:
315
- subselect = select.clone
316
- subselect.projections = [update.key]
338
+ key = update.key
339
+ subselect = subquery_for(key, select)
340
+
341
+ update.where key.in(subselect)
342
+ end
317
343
 
318
- update.where update.key.in(subselect)
344
+ def join_to_delete(delete, select, key) #:nodoc:
345
+ subselect = subquery_for(key, select)
346
+
347
+ delete.where key.in(subselect)
319
348
  end
320
349
 
321
350
  protected
351
+
352
+ # Return a subquery for the given key using the join information.
353
+ def subquery_for(key, select)
354
+ subselect = select.clone
355
+ subselect.projections = [key]
356
+ subselect
357
+ end
358
+
322
359
  # Returns an array of record hashes with the column names as keys and
323
360
  # column values as values.
324
361
  def select(sql, name = nil, binds = [])
@@ -341,50 +378,21 @@ module ActiveRecord
341
378
  update_sql(sql, name)
342
379
  end
343
380
 
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
381
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
382
+ [sql, binds]
383
+ end
353
384
 
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
385
+ def last_inserted_id(result)
386
+ row = result.rows.first
387
+ row && row.first
363
388
  end
364
389
 
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
390
+ def binds_from_relation(relation, binds)
391
+ if relation.is_a?(Relation) && binds.blank?
392
+ relation, binds = relation.arel, relation.bind_values
377
393
  end
394
+ [relation, binds]
378
395
  end
379
-
380
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
381
- [sql, binds]
382
- end
383
-
384
- def last_inserted_id(result)
385
- row = result.rows.first
386
- row && row.first
387
- end
388
396
  end
389
397
  end
390
398
  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
@@ -57,6 +57,7 @@ module ActiveRecord
57
57
 
58
58
  def select_all(arel, name = nil, binds = [])
59
59
  if @query_cache_enabled && !locked?(arel)
60
+ arel, binds = binds_from_relation arel, binds
60
61
  sql = to_sql(arel, binds)
61
62
  cache_sql(sql, binds) { super(sql, name, binds) }
62
63
  else
@@ -65,26 +66,31 @@ module ActiveRecord
65
66
  end
66
67
 
67
68
  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
69
 
78
- result.collect { |row| row.dup }
79
- end
80
-
81
- def locked?(arel)
82
- if arel.respond_to?(:locked)
83
- arel.locked
70
+ def cache_sql(sql, binds)
71
+ result =
72
+ if @query_cache[sql].key?(binds)
73
+ ActiveSupport::Notifications.instrument("sql.active_record",
74
+ :sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id)
75
+ @query_cache[sql][binds]
84
76
  else
85
- false
77
+ @query_cache[sql][binds] = yield
86
78
  end
79
+
80
+ # FIXME: we should guarantee that all cached items are Result
81
+ # objects. Then we can avoid this conditional
82
+ if ActiveRecord::Result === result
83
+ result.dup
84
+ else
85
+ result.collect { |row| row.dup }
87
86
  end
87
+ end
88
+
89
+ # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
90
+ # queries should not be cached.
91
+ def locked?(arel)
92
+ arel.respond_to?(:locked) && arel.locked
93
+ end
88
94
  end
89
95
  end
90
96
  end
@@ -31,9 +31,10 @@ module ActiveRecord
31
31
  # BigDecimals need to be put in a non-normalized form and quoted.
32
32
  when nil then "NULL"
33
33
  when BigDecimal then value.to_s('F')
34
- when Numeric then value.to_s
34
+ when Numeric, ActiveSupport::Duration then value.to_s
35
35
  when Date, Time then "'#{quoted_date(value)}'"
36
36
  when Symbol then "'#{quote_string(value.to_s)}'"
37
+ when Class then "'#{value.to_s}'"
37
38
  else
38
39
  "'#{quote_string(YAML.dump(value))}'"
39
40
  end
@@ -43,7 +44,9 @@ module ActiveRecord
43
44
  # SQLite does not understand dates, so this method will convert a Date
44
45
  # to a String.
45
46
  def type_cast(value, column)
46
- return value.id if value.respond_to?(:quoted_id)
47
+ if value.respond_to?(:quoted_id) && value.respond_to?(:id)
48
+ return value.id
49
+ end
47
50
 
48
51
  case value
49
52
  when String, ActiveSupport::Multibyte::Chars
@@ -71,7 +74,8 @@ module ActiveRecord
71
74
  when Date, Time then quoted_date(value)
72
75
  when Symbol then value.to_s
73
76
  else
74
- YAML.dump(value)
77
+ to_type = column ? " to #{column.type}" : ""
78
+ raise TypeError, "can't cast #{value.class}#{to_type}"
75
79
  end
76
80
  end
77
81
 
@@ -91,6 +95,18 @@ module ActiveRecord
91
95
  quote_column_name(table_name)
92
96
  end
93
97
 
98
+ # Override to return the quoted table name for assignment. Defaults to
99
+ # table quoting.
100
+ #
101
+ # This works for mysql and mysql2 where table.column can be used to
102
+ # resolve ambiguity.
103
+ #
104
+ # We override this in the sqlite and postgresql adapters to use only
105
+ # the column name (as per syntax requirements).
106
+ def quote_table_name_for_assignment(table, attr)
107
+ quote_table_name("#{table}.#{attr}")
108
+ end
109
+
94
110
  def quoted_true
95
111
  "'t'"
96
112
  end