activerecord 4.2.0 → 5.2.8.1

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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +640 -928
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -11
  5. data/examples/performance.rb +32 -31
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +264 -247
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +87 -41
  11. data/lib/active_record/associations/association_scope.rb +106 -132
  12. data/lib/active_record/associations/belongs_to_association.rb +55 -36
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +29 -38
  15. data/lib/active_record/associations/builder/belongs_to.rb +77 -30
  16. data/lib/active_record/associations/builder/collection_association.rb +14 -23
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
  18. data/lib/active_record/associations/builder/has_many.rb +6 -4
  19. data/lib/active_record/associations/builder/has_one.rb +13 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +15 -11
  21. data/lib/active_record/associations/collection_association.rb +145 -266
  22. data/lib/active_record/associations/collection_proxy.rb +242 -138
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -75
  25. data/lib/active_record/associations/has_many_through_association.rb +51 -69
  26. data/lib/active_record/associations/has_one_association.rb +39 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -154
  32. data/lib/active_record/associations/preloader/association.rb +85 -116
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +83 -93
  35. data/lib/active_record/associations/singular_association.rb +27 -40
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1732 -1596
  38. data/lib/active_record/attribute_assignment.rb +58 -182
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -125
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -71
  43. data/lib/active_record/attribute_methods/query.rb +4 -2
  44. data/lib/active_record/attribute_methods/read.rb +45 -63
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +31 -46
  48. data/lib/active_record/attribute_methods.rb +170 -117
  49. data/lib/active_record/attributes.rb +201 -74
  50. data/lib/active_record/autosave_association.rb +118 -45
  51. data/lib/active_record/base.rb +60 -48
  52. data/lib/active_record/callbacks.rb +97 -57
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +37 -13
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
  69. data/lib/active_record/connection_adapters/column.rb +50 -41
  70. data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
  117. data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +40 -27
  128. data/lib/active_record/core.rb +205 -202
  129. data/lib/active_record/counter_cache.rb +80 -37
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +87 -105
  132. data/lib/active_record/enum.rb +136 -90
  133. data/lib/active_record/errors.rb +180 -52
  134. data/lib/active_record/explain.rb +23 -11
  135. data/lib/active_record/explain_registry.rb +4 -2
  136. data/lib/active_record/explain_subscriber.rb +11 -6
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +193 -135
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +148 -112
  141. data/lib/active_record/integration.rb +70 -28
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +92 -98
  146. data/lib/active_record/locking/pessimistic.rb +15 -3
  147. data/lib/active_record/log_subscriber.rb +95 -33
  148. data/lib/active_record/migration/command_recorder.rb +133 -90
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +8 -6
  151. data/lib/active_record/migration.rb +594 -267
  152. data/lib/active_record/model_schema.rb +292 -111
  153. data/lib/active_record/nested_attributes.rb +266 -214
  154. data/lib/active_record/no_touching.rb +8 -2
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +350 -119
  157. data/lib/active_record/query_cache.rb +13 -24
  158. data/lib/active_record/querying.rb +19 -17
  159. data/lib/active_record/railtie.rb +117 -35
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +9 -3
  162. data/lib/active_record/railties/databases.rake +160 -174
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +447 -288
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +204 -55
  167. data/lib/active_record/relation/calculations.rb +259 -244
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +290 -253
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +91 -68
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  179. data/lib/active_record/relation/predicate_builder.rb +118 -92
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +446 -389
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +18 -16
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +287 -339
  187. data/lib/active_record/result.rb +54 -36
  188. data/lib/active_record/runtime_registry.rb +6 -4
  189. data/lib/active_record/sanitization.rb +155 -124
  190. data/lib/active_record/schema.rb +30 -24
  191. data/lib/active_record/schema_dumper.rb +91 -87
  192. data/lib/active_record/schema_migration.rb +19 -19
  193. data/lib/active_record/scoping/default.rb +102 -84
  194. data/lib/active_record/scoping/named.rb +81 -32
  195. data/lib/active_record/scoping.rb +45 -26
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +5 -5
  198. data/lib/active_record/statement_cache.rb +45 -35
  199. data/lib/active_record/store.rb +42 -36
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +136 -95
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
  206. data/lib/active_record/timestamp.rb +70 -38
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +208 -123
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +4 -41
  212. data/lib/active_record/type/date_time.rb +4 -38
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +30 -15
  218. data/lib/active_record/type/text.rb +2 -2
  219. data/lib/active_record/type/time.rb +11 -16
  220. data/lib/active_record/type/type_map.rb +15 -17
  221. data/lib/active_record/type/unsigned_integer.rb +9 -7
  222. data/lib/active_record/type.rb +79 -23
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +13 -4
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +14 -13
  230. data/lib/active_record/validations/uniqueness.rb +41 -32
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +36 -21
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
  237. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
  239. data/lib/rails/generators/active_record/migration.rb +18 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
  242. data/lib/rails/generators/active_record.rb +7 -5
  243. metadata +77 -53
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  251. data/lib/active_record/attribute.rb +0 -149
  252. data/lib/active_record/attribute_set/builder.rb +0 -86
  253. data/lib/active_record/attribute_set.rb +0 -77
  254. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  255. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  256. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  257. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  258. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  259. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  260. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  261. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  262. data/lib/active_record/type/big_integer.rb +0 -13
  263. data/lib/active_record/type/binary.rb +0 -50
  264. data/lib/active_record/type/boolean.rb +0 -30
  265. data/lib/active_record/type/decimal.rb +0 -40
  266. data/lib/active_record/type/decorator.rb +0 -14
  267. data/lib/active_record/type/float.rb +0 -19
  268. data/lib/active_record/type/integer.rb +0 -55
  269. data/lib/active_record/type/mutable.rb +0 -16
  270. data/lib/active_record/type/numeric.rb +0 -36
  271. data/lib/active_record/type/string.rb +0 -36
  272. data/lib/active_record/type/time_value.rb +0 -38
  273. data/lib/active_record/type/value.rb +0 -101
  274. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  class TransactionState
4
- attr_reader :parent
5
-
6
- VALID_STATES = Set.new([:committed, :rolledback, nil])
7
-
8
6
  def initialize(state = nil)
9
7
  @state = state
10
- @parent = nil
8
+ @children = []
9
+ end
10
+
11
+ def add_child(state)
12
+ @children << state
11
13
  end
12
14
 
13
15
  def finalized?
@@ -15,11 +17,23 @@ module ActiveRecord
15
17
  end
16
18
 
17
19
  def committed?
18
- @state == :committed
20
+ @state == :committed || @state == :fully_committed
21
+ end
22
+
23
+ def fully_committed?
24
+ @state == :fully_committed
19
25
  end
20
26
 
21
27
  def rolledback?
22
- @state == :rolledback
28
+ @state == :rolledback || @state == :fully_rolledback
29
+ end
30
+
31
+ def fully_rolledback?
32
+ @state == :fully_rolledback
33
+ end
34
+
35
+ def fully_completed?
36
+ completed?
23
37
  end
24
38
 
25
39
  def completed?
@@ -27,15 +41,49 @@ module ActiveRecord
27
41
  end
28
42
 
29
43
  def set_state(state)
30
- if !VALID_STATES.include?(state)
44
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
45
+ The set_state method is deprecated and will be removed in
46
+ Rails 6.0. Please use rollback! or commit! to set transaction
47
+ state directly.
48
+ MSG
49
+ case state
50
+ when :rolledback
51
+ rollback!
52
+ when :committed
53
+ commit!
54
+ when nil
55
+ nullify!
56
+ else
31
57
  raise ArgumentError, "Invalid transaction state: #{state}"
32
58
  end
33
- @state = state
59
+ end
60
+
61
+ def rollback!
62
+ @children.each { |c| c.rollback! }
63
+ @state = :rolledback
64
+ end
65
+
66
+ def full_rollback!
67
+ @children.each { |c| c.rollback! }
68
+ @state = :fully_rolledback
69
+ end
70
+
71
+ def commit!
72
+ @state = :committed
73
+ end
74
+
75
+ def full_commit!
76
+ @state = :fully_committed
77
+ end
78
+
79
+ def nullify!
80
+ @state = nil
34
81
  end
35
82
  end
36
83
 
37
84
  class NullTransaction #:nodoc:
38
85
  def initialize; end
86
+ def state; end
39
87
  def closed?; true; end
40
88
  def open?; false; end
41
89
  def joinable?; false; end
@@ -43,63 +91,48 @@ module ActiveRecord
43
91
  end
44
92
 
45
93
  class Transaction #:nodoc:
46
-
47
94
  attr_reader :connection, :state, :records, :savepoint_name
48
95
  attr_writer :joinable
49
96
 
50
- def initialize(connection, options)
97
+ def initialize(connection, options, run_commit_callbacks: false)
51
98
  @connection = connection
52
99
  @state = TransactionState.new
53
100
  @records = []
54
101
  @joinable = options.fetch(:joinable, true)
102
+ @run_commit_callbacks = run_commit_callbacks
55
103
  end
56
104
 
57
105
  def add_record(record)
58
- if record.has_transactional_callbacks?
59
- records << record
60
- else
61
- record.set_transaction_state(@state)
62
- end
63
- end
64
-
65
- def rollback
66
- @state.set_state(:rolledback)
106
+ records << record
67
107
  end
68
108
 
69
109
  def rollback_records
70
110
  ite = records.uniq
71
111
  while record = ite.shift
72
- begin
73
- record.rolledback! full_rollback?
74
- rescue => e
75
- raise if ActiveRecord::Base.raise_in_transactional_callbacks
76
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
77
- end
112
+ record.rolledback!(force_restore_state: full_rollback?)
78
113
  end
79
114
  ensure
80
115
  ite.each do |i|
81
- i.rolledback!(full_rollback?, false)
116
+ i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
82
117
  end
83
118
  end
84
119
 
85
- def commit
86
- @state.set_state(:committed)
120
+ def before_commit_records
121
+ records.uniq.each(&:before_committed!) if @run_commit_callbacks
87
122
  end
88
123
 
89
124
  def commit_records
90
125
  ite = records.uniq
91
126
  while record = ite.shift
92
- begin
127
+ if @run_commit_callbacks
93
128
  record.committed!
94
- rescue => e
95
- raise if ActiveRecord::Base.raise_in_transactional_callbacks
96
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
129
+ else
130
+ # if not running callbacks, only adds the record to the parent transaction
131
+ record.add_to_transaction
97
132
  end
98
133
  end
99
134
  ensure
100
- ite.each do |i|
101
- i.committed!(false)
102
- end
135
+ ite.each { |i| i.committed!(should_run_callbacks: false) }
103
136
  end
104
137
 
105
138
  def full_rollback?; true; end
@@ -109,9 +142,11 @@ module ActiveRecord
109
142
  end
110
143
 
111
144
  class SavepointTransaction < Transaction
145
+ def initialize(connection, savepoint_name, parent_transaction, options, *args)
146
+ super(connection, options, *args)
147
+
148
+ parent_transaction.state.add_child(@state)
112
149
 
113
- def initialize(connection, savepoint_name, options)
114
- super(connection, options)
115
150
  if options[:isolation]
116
151
  raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
117
152
  end
@@ -120,23 +155,19 @@ module ActiveRecord
120
155
 
121
156
  def rollback
122
157
  connection.rollback_to_savepoint(savepoint_name)
123
- super
124
- rollback_records
158
+ @state.rollback!
125
159
  end
126
160
 
127
161
  def commit
128
162
  connection.release_savepoint(savepoint_name)
129
- super
130
- parent = connection.transaction_manager.current_transaction
131
- records.each { |r| parent.add_record(r) }
163
+ @state.commit!
132
164
  end
133
165
 
134
166
  def full_rollback?; false; end
135
167
  end
136
168
 
137
169
  class RealTransaction < Transaction
138
-
139
- def initialize(connection, options)
170
+ def initialize(connection, options, *args)
140
171
  super
141
172
  if options[:isolation]
142
173
  connection.begin_isolated_db_transaction(options[:isolation])
@@ -147,14 +178,12 @@ module ActiveRecord
147
178
 
148
179
  def rollback
149
180
  connection.rollback_db_transaction
150
- super
151
- rollback_records
181
+ @state.full_rollback!
152
182
  end
153
183
 
154
184
  def commit
155
185
  connection.commit_db_transaction
156
- super
157
- commit_records
186
+ @state.full_commit!
158
187
  end
159
188
  end
160
189
 
@@ -165,40 +194,67 @@ module ActiveRecord
165
194
  end
166
195
 
167
196
  def begin_transaction(options = {})
168
- transaction =
169
- if @stack.empty?
170
- RealTransaction.new(@connection, options)
171
- else
172
- SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options)
173
- end
174
- @stack.push(transaction)
175
- transaction
197
+ @connection.lock.synchronize do
198
+ run_commit_callbacks = !current_transaction.joinable?
199
+ transaction =
200
+ if @stack.empty?
201
+ RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
202
+ else
203
+ SavepointTransaction.new(@connection, "active_record_#{@stack.size}", @stack.last, options,
204
+ run_commit_callbacks: run_commit_callbacks)
205
+ end
206
+
207
+ @stack.push(transaction)
208
+ transaction
209
+ end
176
210
  end
177
211
 
178
212
  def commit_transaction
179
- @stack.pop.commit
213
+ @connection.lock.synchronize do
214
+ transaction = @stack.last
215
+
216
+ begin
217
+ transaction.before_commit_records
218
+ ensure
219
+ @stack.pop
220
+ end
221
+
222
+ transaction.commit
223
+ transaction.commit_records
224
+ end
180
225
  end
181
226
 
182
- def rollback_transaction
183
- @stack.pop.rollback
227
+ def rollback_transaction(transaction = nil)
228
+ @connection.lock.synchronize do
229
+ transaction ||= @stack.pop
230
+ transaction.rollback
231
+ transaction.rollback_records
232
+ end
184
233
  end
185
234
 
186
235
  def within_new_transaction(options = {})
187
- transaction = begin_transaction options
188
- yield
189
- rescue Exception => error
190
- rollback_transaction if transaction
191
- raise
192
- ensure
193
- unless error
194
- if Thread.current.status == 'aborting'
195
- rollback_transaction
196
- else
197
- begin
198
- commit_transaction
199
- rescue Exception
200
- transaction.rollback unless transaction.state.completed?
201
- raise
236
+ @connection.lock.synchronize do
237
+ begin
238
+ transaction = begin_transaction options
239
+ yield
240
+ rescue Exception => error
241
+ if transaction
242
+ rollback_transaction
243
+ after_failure_actions(transaction, error)
244
+ end
245
+ raise
246
+ ensure
247
+ unless error
248
+ if Thread.current.status == "aborting"
249
+ rollback_transaction if transaction
250
+ else
251
+ begin
252
+ commit_transaction if transaction
253
+ rescue Exception
254
+ rollback_transaction(transaction) unless transaction.state.completed?
255
+ raise
256
+ end
257
+ end
202
258
  end
203
259
  end
204
260
  end
@@ -213,7 +269,15 @@ module ActiveRecord
213
269
  end
214
270
 
215
271
  private
272
+
216
273
  NULL_TRANSACTION = NullTransaction.new
274
+
275
+ # Deallocate invalidated prepared statements outside of the transaction
276
+ def after_failure_actions(transaction, error)
277
+ return unless transaction.is_a?(RealTransaction)
278
+ return unless error.is_a?(ActiveRecord::PreparedStatementCacheExpired)
279
+ @connection.clear_cache!
280
+ end
217
281
  end
218
282
  end
219
283
  end