activerecord 6.0.0 → 6.1.4

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1178 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_record/aggregations.rb +5 -6
  6. data/lib/active_record/association_relation.rb +30 -10
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -29
  9. data/lib/active_record/associations/association_scope.rb +19 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +25 -8
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +77 -42
  28. data/lib/active_record/associations/preloader/association.rb +51 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +13 -8
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +120 -13
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +33 -9
  45. data/lib/active_record/autosave_association.rb +63 -44
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +12 -3
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +141 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +76 -79
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  102. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -65
  104. data/lib/active_record/connection_adapters/schema_cache.rb +106 -15
  105. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  106. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
  107. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  108. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  109. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  110. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
  111. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  112. data/lib/active_record/connection_adapters.rb +52 -0
  113. data/lib/active_record/connection_handling.rb +219 -81
  114. data/lib/active_record/core.rb +268 -71
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  117. data/lib/active_record/database_configurations/database_config.rb +52 -9
  118. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  119. data/lib/active_record/database_configurations/url_config.rb +15 -41
  120. data/lib/active_record/database_configurations.rb +124 -85
  121. data/lib/active_record/delegated_type.rb +209 -0
  122. data/lib/active_record/destroy_association_async_job.rb +36 -0
  123. data/lib/active_record/dynamic_matchers.rb +2 -3
  124. data/lib/active_record/enum.rb +80 -38
  125. data/lib/active_record/errors.rb +47 -12
  126. data/lib/active_record/explain.rb +9 -5
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +10 -17
  129. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  130. data/lib/active_record/fixture_set/render_context.rb +1 -1
  131. data/lib/active_record/fixture_set/table_row.rb +2 -3
  132. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  133. data/lib/active_record/fixtures.rb +58 -12
  134. data/lib/active_record/gem_version.rb +2 -2
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +43 -10
  137. data/lib/active_record/integration.rb +3 -5
  138. data/lib/active_record/internal_metadata.rb +16 -7
  139. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  140. data/lib/active_record/locking/optimistic.rb +33 -18
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +28 -9
  143. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  144. data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
  145. data/lib/active_record/middleware/database_selector.rb +4 -2
  146. data/lib/active_record/migration/command_recorder.rb +53 -45
  147. data/lib/active_record/migration/compatibility.rb +71 -20
  148. data/lib/active_record/migration/join_table.rb +0 -1
  149. data/lib/active_record/migration.rb +115 -85
  150. data/lib/active_record/model_schema.rb +120 -15
  151. data/lib/active_record/nested_attributes.rb +2 -5
  152. data/lib/active_record/no_touching.rb +1 -1
  153. data/lib/active_record/null_relation.rb +0 -1
  154. data/lib/active_record/persistence.rb +50 -46
  155. data/lib/active_record/query_cache.rb +15 -5
  156. data/lib/active_record/querying.rb +12 -7
  157. data/lib/active_record/railtie.rb +65 -45
  158. data/lib/active_record/railties/console_sandbox.rb +2 -4
  159. data/lib/active_record/railties/databases.rake +280 -99
  160. data/lib/active_record/readonly_attributes.rb +4 -0
  161. data/lib/active_record/reflection.rb +77 -63
  162. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  163. data/lib/active_record/relation/batches.rb +38 -32
  164. data/lib/active_record/relation/calculations.rb +106 -45
  165. data/lib/active_record/relation/delegation.rb +9 -7
  166. data/lib/active_record/relation/finder_methods.rb +55 -17
  167. data/lib/active_record/relation/from_clause.rb +5 -1
  168. data/lib/active_record/relation/merger.rb +27 -26
  169. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  170. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  171. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  172. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  173. data/lib/active_record/relation/predicate_builder.rb +59 -40
  174. data/lib/active_record/relation/query_methods.rb +344 -181
  175. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  176. data/lib/active_record/relation/spawn_methods.rb +8 -8
  177. data/lib/active_record/relation/where_clause.rb +111 -62
  178. data/lib/active_record/relation.rb +116 -82
  179. data/lib/active_record/result.rb +41 -34
  180. data/lib/active_record/runtime_registry.rb +2 -2
  181. data/lib/active_record/sanitization.rb +6 -17
  182. data/lib/active_record/schema_dumper.rb +34 -4
  183. data/lib/active_record/schema_migration.rb +2 -8
  184. data/lib/active_record/scoping/default.rb +1 -4
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/scoping.rb +0 -1
  187. data/lib/active_record/secure_token.rb +16 -8
  188. data/lib/active_record/serialization.rb +5 -3
  189. data/lib/active_record/signed_id.rb +116 -0
  190. data/lib/active_record/statement_cache.rb +20 -4
  191. data/lib/active_record/store.rb +3 -3
  192. data/lib/active_record/suppressor.rb +2 -2
  193. data/lib/active_record/table_metadata.rb +42 -36
  194. data/lib/active_record/tasks/database_tasks.rb +140 -113
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  197. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  198. data/lib/active_record/test_databases.rb +5 -4
  199. data/lib/active_record/test_fixtures.rb +79 -16
  200. data/lib/active_record/timestamp.rb +4 -7
  201. data/lib/active_record/touch_later.rb +20 -21
  202. data/lib/active_record/transactions.rb +26 -73
  203. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  204. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  205. data/lib/active_record/type/serialized.rb +6 -3
  206. data/lib/active_record/type/time.rb +10 -0
  207. data/lib/active_record/type/type_map.rb +0 -1
  208. data/lib/active_record/type/unsigned_integer.rb +0 -1
  209. data/lib/active_record/type.rb +8 -2
  210. data/lib/active_record/type_caster/connection.rb +0 -1
  211. data/lib/active_record/type_caster/map.rb +8 -5
  212. data/lib/active_record/validations/associated.rb +1 -2
  213. data/lib/active_record/validations/numericality.rb +35 -0
  214. data/lib/active_record/validations/uniqueness.rb +24 -4
  215. data/lib/active_record/validations.rb +3 -3
  216. data/lib/active_record.rb +7 -13
  217. data/lib/arel/attributes/attribute.rb +4 -0
  218. data/lib/arel/collectors/bind.rb +5 -0
  219. data/lib/arel/collectors/composite.rb +8 -0
  220. data/lib/arel/collectors/sql_string.rb +7 -0
  221. data/lib/arel/collectors/substitute_binds.rb +7 -0
  222. data/lib/arel/nodes/binary.rb +82 -8
  223. data/lib/arel/nodes/bind_param.rb +8 -0
  224. data/lib/arel/nodes/casted.rb +21 -9
  225. data/lib/arel/nodes/equality.rb +6 -9
  226. data/lib/arel/nodes/grouping.rb +3 -0
  227. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  228. data/lib/arel/nodes/in.rb +8 -1
  229. data/lib/arel/nodes/infix_operation.rb +13 -1
  230. data/lib/arel/nodes/join_source.rb +1 -1
  231. data/lib/arel/nodes/node.rb +7 -6
  232. data/lib/arel/nodes/ordering.rb +27 -0
  233. data/lib/arel/nodes/sql_literal.rb +3 -0
  234. data/lib/arel/nodes/table_alias.rb +7 -3
  235. data/lib/arel/nodes/unary.rb +0 -1
  236. data/lib/arel/nodes.rb +3 -1
  237. data/lib/arel/predications.rb +17 -24
  238. data/lib/arel/select_manager.rb +1 -2
  239. data/lib/arel/table.rb +13 -5
  240. data/lib/arel/visitors/dot.rb +14 -3
  241. data/lib/arel/visitors/mysql.rb +11 -1
  242. data/lib/arel/visitors/postgresql.rb +15 -5
  243. data/lib/arel/visitors/sqlite.rb +0 -1
  244. data/lib/arel/visitors/to_sql.rb +89 -79
  245. data/lib/arel/visitors/visitor.rb +0 -1
  246. data/lib/arel/visitors.rb +0 -7
  247. data/lib/arel.rb +15 -12
  248. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  249. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  250. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  251. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  252. data/lib/rails/generators/active_record/migration.rb +6 -2
  253. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  254. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  255. metadata +27 -24
  256. data/lib/active_record/attribute_decorators.rb +0 -90
  257. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  258. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  259. data/lib/active_record/define_callbacks.rb +0 -22
  260. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  261. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  262. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  263. data/lib/arel/attributes.rb +0 -22
  264. data/lib/arel/visitors/depth_first.rb +0 -204
  265. data/lib/arel/visitors/ibm_db.rb +0 -34
  266. data/lib/arel/visitors/informix.rb +0 -62
  267. data/lib/arel/visitors/mssql.rb +0 -157
  268. data/lib/arel/visitors/oracle.rb +0 -159
  269. data/lib/arel/visitors/oracle12.rb +0 -66
  270. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -5,10 +5,11 @@ module ActiveRecord
5
5
  class TransactionState
6
6
  def initialize(state = nil)
7
7
  @state = state
8
- @children = []
8
+ @children = nil
9
9
  end
10
10
 
11
11
  def add_child(state)
12
+ @children ||= []
12
13
  @children << state
13
14
  end
14
15
 
@@ -32,6 +33,10 @@ module ActiveRecord
32
33
  @state == :fully_rolledback
33
34
  end
34
35
 
36
+ def invalidated?
37
+ @state == :invalidated
38
+ end
39
+
35
40
  def fully_completed?
36
41
  completed?
37
42
  end
@@ -41,15 +46,20 @@ module ActiveRecord
41
46
  end
42
47
 
43
48
  def rollback!
44
- @children.each { |c| c.rollback! }
49
+ @children&.each { |c| c.rollback! }
45
50
  @state = :rolledback
46
51
  end
47
52
 
48
53
  def full_rollback!
49
- @children.each { |c| c.rollback! }
54
+ @children&.each { |c| c.rollback! }
50
55
  @state = :fully_rolledback
51
56
  end
52
57
 
58
+ def invalidate!
59
+ @children&.each { |c| c.invalidate! }
60
+ @state = :invalidated
61
+ end
62
+
53
63
  def commit!
54
64
  @state = :committed
55
65
  end
@@ -69,24 +79,40 @@ module ActiveRecord
69
79
  def closed?; true; end
70
80
  def open?; false; end
71
81
  def joinable?; false; end
72
- def add_record(record); end
82
+ def add_record(record, _ = true); end
73
83
  end
74
84
 
75
85
  class Transaction #:nodoc:
76
- attr_reader :connection, :state, :records, :savepoint_name, :isolation_level
86
+ attr_reader :connection, :state, :savepoint_name, :isolation_level
87
+ attr_accessor :written
77
88
 
78
- def initialize(connection, options, run_commit_callbacks: false)
89
+ def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
79
90
  @connection = connection
80
91
  @state = TransactionState.new
81
- @records = []
82
- @isolation_level = options[:isolation]
92
+ @records = nil
93
+ @isolation_level = isolation
83
94
  @materialized = false
84
- @joinable = options.fetch(:joinable, true)
95
+ @joinable = joinable
85
96
  @run_commit_callbacks = run_commit_callbacks
97
+ @lazy_enrollment_records = nil
98
+ end
99
+
100
+ def add_record(record, ensure_finalize = true)
101
+ @records ||= []
102
+ if ensure_finalize
103
+ @records << record
104
+ else
105
+ @lazy_enrollment_records ||= ObjectSpace::WeakMap.new
106
+ @lazy_enrollment_records[record] = record
107
+ end
86
108
  end
87
109
 
88
- def add_record(record)
89
- records << record
110
+ def records
111
+ if @lazy_enrollment_records
112
+ @records.concat @lazy_enrollment_records.values
113
+ @lazy_enrollment_records = nil
114
+ end
115
+ @records
90
116
  end
91
117
 
92
118
  def materialize!
@@ -98,7 +124,8 @@ module ActiveRecord
98
124
  end
99
125
 
100
126
  def rollback_records
101
- ite = records.uniq(&:object_id)
127
+ return unless records
128
+ ite = records.uniq(&:__id__)
102
129
  already_run_callbacks = {}
103
130
  while record = ite.shift
104
131
  trigger_callbacks = record.trigger_transactional_callbacks?
@@ -107,17 +134,18 @@ module ActiveRecord
107
134
  record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
108
135
  end
109
136
  ensure
110
- ite.each do |i|
137
+ ite&.each do |i|
111
138
  i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
112
139
  end
113
140
  end
114
141
 
115
142
  def before_commit_records
116
- records.uniq.each(&:before_committed!) if @run_commit_callbacks
143
+ records.uniq.each(&:before_committed!) if records && @run_commit_callbacks
117
144
  end
118
145
 
119
146
  def commit_records
120
- ite = records.uniq(&:object_id)
147
+ return unless records
148
+ ite = records.uniq(&:__id__)
121
149
  already_run_callbacks = {}
122
150
  while record = ite.shift
123
151
  if @run_commit_callbacks
@@ -131,7 +159,7 @@ module ActiveRecord
131
159
  end
132
160
  end
133
161
  ensure
134
- ite.each { |i| i.committed!(should_run_callbacks: false) }
162
+ ite&.each { |i| i.committed!(should_run_callbacks: false) }
135
163
  end
136
164
 
137
165
  def full_rollback?; true; end
@@ -141,8 +169,8 @@ module ActiveRecord
141
169
  end
142
170
 
143
171
  class SavepointTransaction < Transaction
144
- def initialize(connection, savepoint_name, parent_transaction, *args)
145
- super(connection, *args)
172
+ def initialize(connection, savepoint_name, parent_transaction, **options)
173
+ super(connection, **options)
146
174
 
147
175
  parent_transaction.state.add_child(@state)
148
176
 
@@ -202,18 +230,29 @@ module ActiveRecord
202
230
  @lazy_transactions_enabled = true
203
231
  end
204
232
 
205
- def begin_transaction(options = {})
233
+ def begin_transaction(isolation: nil, joinable: true, _lazy: true)
206
234
  @connection.lock.synchronize do
207
235
  run_commit_callbacks = !current_transaction.joinable?
208
236
  transaction =
209
237
  if @stack.empty?
210
- RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
238
+ RealTransaction.new(
239
+ @connection,
240
+ isolation: isolation,
241
+ joinable: joinable,
242
+ run_commit_callbacks: run_commit_callbacks
243
+ )
211
244
  else
212
- SavepointTransaction.new(@connection, "active_record_#{@stack.size}", @stack.last, options,
213
- run_commit_callbacks: run_commit_callbacks)
245
+ SavepointTransaction.new(
246
+ @connection,
247
+ "active_record_#{@stack.size}",
248
+ @stack.last,
249
+ isolation: isolation,
250
+ joinable: joinable,
251
+ run_commit_callbacks: run_commit_callbacks
252
+ )
214
253
  end
215
254
 
216
- if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && options[:_lazy] != false
255
+ if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && _lazy
217
256
  @has_unmaterialized_transactions = true
218
257
  else
219
258
  transaction.materialize!
@@ -269,31 +308,51 @@ module ActiveRecord
269
308
  def rollback_transaction(transaction = nil)
270
309
  @connection.lock.synchronize do
271
310
  transaction ||= @stack.pop
272
- transaction.rollback
311
+ transaction.rollback unless transaction.state.invalidated?
273
312
  transaction.rollback_records
274
313
  end
275
314
  end
276
315
 
277
- def within_new_transaction(options = {})
316
+ def within_new_transaction(isolation: nil, joinable: true)
278
317
  @connection.lock.synchronize do
279
- transaction = begin_transaction options
280
- yield
318
+ transaction = begin_transaction(isolation: isolation, joinable: joinable)
319
+ ret = yield
320
+ completed = true
321
+ ret
281
322
  rescue Exception => error
282
323
  if transaction
324
+ transaction.state.invalidate! if error.is_a? ActiveRecord::TransactionRollbackError
283
325
  rollback_transaction
284
326
  after_failure_actions(transaction, error)
285
327
  end
328
+
286
329
  raise
287
330
  ensure
288
- if !error && transaction
289
- if Thread.current.status == "aborting"
290
- rollback_transaction
331
+ if transaction
332
+ if error
333
+ # @connection still holds an open or invalid transaction, so we must not
334
+ # put it back in the pool for reuse.
335
+ @connection.throw_away! unless transaction.state.rolledback?
291
336
  else
292
- begin
293
- commit_transaction
294
- rescue Exception
295
- rollback_transaction(transaction) unless transaction.state.completed?
296
- raise
337
+ if Thread.current.status == "aborting"
338
+ rollback_transaction
339
+ else
340
+ if !completed && transaction.written
341
+ ActiveSupport::Deprecation.warn(<<~EOW)
342
+ Using `return`, `break` or `throw` to exit a transaction block is
343
+ deprecated without replacement. If the `throw` came from
344
+ `Timeout.timeout(duration)`, pass an exception class as a second
345
+ argument so it doesn't use `throw` to abort its block. This results
346
+ in the transaction being committed, but in the next release of Rails
347
+ it will rollback.
348
+ EOW
349
+ end
350
+ begin
351
+ commit_transaction
352
+ rescue Exception
353
+ rollback_transaction(transaction) unless transaction.state.completed?
354
+ raise
355
+ end
297
356
  end
298
357
  end
299
358
  end
@@ -309,7 +368,6 @@ module ActiveRecord
309
368
  end
310
369
 
311
370
  private
312
-
313
371
  NULL_TRANSACTION = NullTransaction.new
314
372
 
315
373
  # Deallocate invalidated prepared statements outside of the transaction
@@ -1,58 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_record/connection_adapters/determine_if_preparable_visitor"
4
- require "active_record/connection_adapters/schema_cache"
3
+ require "set"
5
4
  require "active_record/connection_adapters/sql_type_metadata"
6
5
  require "active_record/connection_adapters/abstract/schema_dumper"
7
6
  require "active_record/connection_adapters/abstract/schema_creation"
8
7
  require "active_support/concurrency/load_interlock_aware_monitor"
9
- require "active_support/deprecation"
10
8
  require "arel/collectors/bind"
11
9
  require "arel/collectors/composite"
12
10
  require "arel/collectors/sql_string"
13
11
  require "arel/collectors/substitute_binds"
14
- require "concurrent/atomic/thread_local_var"
15
12
 
16
13
  module ActiveRecord
17
14
  module ConnectionAdapters # :nodoc:
18
- extend ActiveSupport::Autoload
19
-
20
- autoload :Column
21
- autoload :ConnectionSpecification
22
-
23
- autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
24
- autoload :IndexDefinition
25
- autoload :ColumnDefinition
26
- autoload :ChangeColumnDefinition
27
- autoload :ForeignKeyDefinition
28
- autoload :TableDefinition
29
- autoload :Table
30
- autoload :AlterTable
31
- autoload :ReferenceDefinition
32
- end
33
-
34
- autoload_at "active_record/connection_adapters/abstract/connection_pool" do
35
- autoload :ConnectionHandler
36
- end
37
-
38
- autoload_under "abstract" do
39
- autoload :SchemaStatements
40
- autoload :DatabaseStatements
41
- autoload :DatabaseLimits
42
- autoload :Quoting
43
- autoload :ConnectionPool
44
- autoload :QueryCache
45
- autoload :Savepoints
46
- end
47
-
48
- autoload_at "active_record/connection_adapters/abstract/transaction" do
49
- autoload :TransactionManager
50
- autoload :NullTransaction
51
- autoload :RealTransaction
52
- autoload :SavepointTransaction
53
- autoload :TransactionState
54
- end
55
-
56
15
  # Active Record supports multiple database systems. AbstractAdapter and
57
16
  # related classes form the abstraction layer which makes this possible.
58
17
  # An AbstractAdapter represents a connection to a database, and provides an
@@ -77,6 +36,7 @@ module ActiveRecord
77
36
  include Savepoints
78
37
 
79
38
  SIMPLE_INT = /\A\d+\z/
39
+ COMMENT_REGEX = %r{(?:\-\-.*\n)*|/\*(?:[^\*]|\*[^/])*\*/}m
80
40
 
81
41
  attr_accessor :pool
82
42
  attr_reader :visitor, :owner, :logger, :lock
@@ -102,9 +62,13 @@ module ActiveRecord
102
62
  end
103
63
  end
104
64
 
65
+ DEFAULT_READ_QUERY = [:begin, :commit, :explain, :release, :rollback, :savepoint, :select, :with] # :nodoc:
66
+ private_constant :DEFAULT_READ_QUERY
67
+
105
68
  def self.build_read_query_regexp(*parts) # :nodoc:
106
- parts = parts.map { |part| /\A[\(\s]*#{part}/i }
107
- Regexp.union(*parts)
69
+ parts += DEFAULT_READ_QUERY
70
+ parts = parts.map { |part| /#{part}/i }
71
+ /\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
108
72
  end
109
73
 
110
74
  def self.quoted_column_names # :nodoc:
@@ -129,12 +93,9 @@ module ActiveRecord
129
93
  @statements = build_statement_pool
130
94
  @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
131
95
 
132
- if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
133
- @prepared_statement_status = Concurrent::ThreadLocalVar.new(true)
134
- @visitor.extend(DetermineIfPreparableVisitor)
135
- else
136
- @prepared_statement_status = Concurrent::ThreadLocalVar.new(false)
137
- end
96
+ @prepared_statements = self.class.type_cast_config_to_boolean(
97
+ config.fetch(:prepared_statements, true)
98
+ )
138
99
 
139
100
  @advisory_locks_enabled = self.class.type_cast_config_to_boolean(
140
101
  config.fetch(:advisory_locks, true)
@@ -145,12 +106,25 @@ module ActiveRecord
145
106
  @config[:replica] || false
146
107
  end
147
108
 
148
- # Determines whether writes are currently being prevents.
109
+ def use_metadata_table?
110
+ @config.fetch(:use_metadata_table, true)
111
+ end
112
+
113
+ # Determines whether writes are currently being prevented.
114
+ #
115
+ # Returns true if the connection is a replica.
116
+ #
117
+ # If the application is using legacy handling, returns
118
+ # true if +connection_handler.prevent_writes+ is set.
149
119
  #
150
- # Returns true if the connection is a replica, or if +prevent_writes+
151
- # is set to true.
120
+ # If the application is using the new connection handling
121
+ # will return true based on +current_preventing_writes+.
152
122
  def preventing_writes?
153
- replica? || ActiveRecord::Base.connection_handler.prevent_writes
123
+ return true if replica?
124
+ return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord::Base.legacy_connection_handling
125
+ return false if connection_klass.nil?
126
+
127
+ connection_klass.current_preventing_writes
154
128
  end
155
129
 
156
130
  def migrations_paths # :nodoc:
@@ -164,20 +138,28 @@ module ActiveRecord
164
138
  def schema_migration # :nodoc:
165
139
  @schema_migration ||= begin
166
140
  conn = self
167
- spec_name = conn.pool.spec.name
168
- name = "#{spec_name}::SchemaMigration"
141
+ spec_name = conn.pool.pool_config.connection_specification_name
142
+
143
+ return ActiveRecord::SchemaMigration if spec_name == "ActiveRecord::Base"
144
+
145
+ schema_migration_name = "#{spec_name}::SchemaMigration"
169
146
 
170
147
  Class.new(ActiveRecord::SchemaMigration) do
171
- define_singleton_method(:name) { name }
172
- define_singleton_method(:to_s) { name }
148
+ define_singleton_method(:name) { schema_migration_name }
149
+ define_singleton_method(:to_s) { schema_migration_name }
173
150
 
174
151
  self.connection_specification_name = spec_name
175
152
  end
176
153
  end
177
154
  end
178
155
 
179
- def prepared_statements
180
- @prepared_statement_status.value
156
+ def prepared_statements?
157
+ @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
158
+ end
159
+ alias :prepared_statements :prepared_statements?
160
+
161
+ def prepared_statements_disabled_cache # :nodoc:
162
+ Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
181
163
  end
182
164
 
183
165
  class Version
@@ -219,6 +201,10 @@ module ActiveRecord
219
201
  @owner = Thread.current
220
202
  end
221
203
 
204
+ def connection_klass # :nodoc:
205
+ @pool.connection_klass
206
+ end
207
+
222
208
  def schema_cache
223
209
  @pool.get_schema_cache(self)
224
210
  end
@@ -264,7 +250,10 @@ module ActiveRecord
264
250
  end
265
251
 
266
252
  def unprepared_statement
267
- @prepared_statement_status.bind(false) { yield }
253
+ cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
254
+ yield
255
+ ensure
256
+ cache&.delete(object_id)
268
257
  end
269
258
 
270
259
  # Returns the human-readable name of the adapter. Use mixed case - one
@@ -305,6 +294,10 @@ module ActiveRecord
305
294
  false
306
295
  end
307
296
 
297
+ def supports_partitioned_indexes?
298
+ false
299
+ end
300
+
308
301
  # Does this adapter support index sort order?
309
302
  def supports_index_sort_order?
310
303
  false
@@ -351,12 +344,10 @@ module ActiveRecord
351
344
  false
352
345
  end
353
346
 
354
- # Does this adapter support creating foreign key constraints
355
- # in the same statement as creating the table?
356
- def supports_foreign_keys_in_create?
357
- supports_foreign_keys?
347
+ # Does this adapter support creating check constraints?
348
+ def supports_check_constraints?
349
+ false
358
350
  end
359
- deprecate :supports_foreign_keys_in_create?
360
351
 
361
352
  # Does this adapter support views?
362
353
  def supports_views?
@@ -388,12 +379,6 @@ module ActiveRecord
388
379
  false
389
380
  end
390
381
 
391
- # Does this adapter support multi-value insert?
392
- def supports_multi_insert?
393
- true
394
- end
395
- deprecate :supports_multi_insert?
396
-
397
382
  # Does this adapter support virtual columns?
398
383
  def supports_virtual_columns?
399
384
  false
@@ -409,6 +394,10 @@ module ActiveRecord
409
394
  false
410
395
  end
411
396
 
397
+ def supports_common_table_expressions?
398
+ false
399
+ end
400
+
412
401
  def supports_lazy_transactions?
413
402
  false
414
403
  end
@@ -521,6 +510,12 @@ module ActiveRecord
521
510
  # this should be overridden by concrete adapters
522
511
  end
523
512
 
513
+ # Removes the connection from the pool and disconnect it.
514
+ def throw_away!
515
+ pool.remove self
516
+ disconnect!
517
+ end
518
+
524
519
  # Clear any caching the database adapter may be doing.
525
520
  def clear_cache!
526
521
  @lock.synchronize { @statements.clear } if @statements
@@ -549,7 +544,7 @@ module ActiveRecord
549
544
  @connection
550
545
  end
551
546
 
552
- def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
547
+ def default_uniqueness_comparison(attribute, value) # :nodoc:
553
548
  attribute.eq(value)
554
549
  end
555
550
 
@@ -577,10 +572,6 @@ module ActiveRecord
577
572
  pool.checkin self
578
573
  end
579
574
 
580
- def column_name_for_operation(operation, node) # :nodoc:
581
- visitor.compile(node)
582
- end
583
-
584
575
  def default_index_type?(index) # :nodoc:
585
576
  index.using.nil?
586
577
  end
@@ -609,7 +600,6 @@ module ActiveRecord
609
600
  end
610
601
 
611
602
  private
612
-
613
603
  def type_map
614
604
  @type_map ||= Type::TypeMap.new.tap do |mapping|
615
605
  initialize_type_map(mapping)
@@ -701,7 +691,6 @@ module ActiveRecord
701
691
  binds: binds,
702
692
  type_casted_binds: type_casted_binds,
703
693
  statement_name: statement_name,
704
- connection_id: object_id,
705
694
  connection: self) do
706
695
  @lock.synchronize do
707
696
  yield
@@ -756,6 +745,14 @@ module ActiveRecord
756
745
 
757
746
  def build_statement_pool
758
747
  end
748
+
749
+ # Builds the result object.
750
+ #
751
+ # This is an internal hook to make possible connection adapters to build
752
+ # custom result objects with connection-specific data.
753
+ def build_result(columns:, rows:, column_types: {})
754
+ ActiveRecord::Result.new(columns, rows, column_types)
755
+ end
759
756
  end
760
757
  end
761
758
  end