activerecord 5.2.4.4 → 6.0.3.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 (292) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +777 -552
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +10 -2
  7. data/lib/active_record/advisory_lock_base.rb +18 -0
  8. data/lib/active_record/aggregations.rb +4 -3
  9. data/lib/active_record/association_relation.rb +10 -8
  10. data/lib/active_record/associations.rb +21 -16
  11. data/lib/active_record/associations/alias_tracker.rb +0 -1
  12. data/lib/active_record/associations/association.rb +56 -19
  13. data/lib/active_record/associations/association_scope.rb +4 -6
  14. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  16. data/lib/active_record/associations/builder/association.rb +14 -18
  17. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  18. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +35 -1
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +12 -23
  24. data/lib/active_record/associations/collection_proxy.rb +13 -17
  25. data/lib/active_record/associations/foreign_association.rb +7 -0
  26. data/lib/active_record/associations/has_many_association.rb +2 -11
  27. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  28. data/lib/active_record/associations/has_one_association.rb +28 -30
  29. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  30. data/lib/active_record/associations/join_dependency.rb +37 -28
  31. data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
  32. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  33. data/lib/active_record/associations/preloader.rb +39 -32
  34. data/lib/active_record/associations/preloader/association.rb +38 -36
  35. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  36. data/lib/active_record/associations/singular_association.rb +2 -16
  37. data/lib/active_record/attribute_assignment.rb +7 -11
  38. data/lib/active_record/attribute_decorators.rb +0 -2
  39. data/lib/active_record/attribute_methods.rb +28 -100
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
  41. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  42. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  43. data/lib/active_record/attribute_methods/query.rb +2 -3
  44. data/lib/active_record/attribute_methods/read.rb +15 -54
  45. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  47. data/lib/active_record/attribute_methods/write.rb +17 -25
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +3 -5
  50. data/lib/active_record/base.rb +2 -3
  51. data/lib/active_record/callbacks.rb +6 -21
  52. data/lib/active_record/coders/yaml_column.rb +0 -1
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +103 -18
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +100 -72
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +191 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +142 -215
  65. data/lib/active_record/connection_adapters/column.rb +17 -13
  66. data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
  67. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  68. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
  70. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  71. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
  73. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  74. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  75. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +132 -16
  76. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  82. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
  98. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
  101. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  102. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +135 -146
  107. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  108. data/lib/active_record/connection_handling.rb +139 -26
  109. data/lib/active_record/core.rb +103 -61
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations.rb +233 -0
  112. data/lib/active_record/database_configurations/database_config.rb +37 -0
  113. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  114. data/lib/active_record/database_configurations/url_config.rb +78 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +37 -7
  117. data/lib/active_record/errors.rb +15 -7
  118. data/lib/active_record/explain.rb +1 -2
  119. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  120. data/lib/active_record/fixture_set/render_context.rb +17 -0
  121. data/lib/active_record/fixture_set/table_row.rb +152 -0
  122. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  123. data/lib/active_record/fixtures.rb +144 -474
  124. data/lib/active_record/gem_version.rb +3 -3
  125. data/lib/active_record/inheritance.rb +13 -6
  126. data/lib/active_record/insert_all.rb +179 -0
  127. data/lib/active_record/integration.rb +68 -16
  128. data/lib/active_record/internal_metadata.rb +11 -3
  129. data/lib/active_record/locking/optimistic.rb +5 -7
  130. data/lib/active_record/locking/pessimistic.rb +3 -3
  131. data/lib/active_record/log_subscriber.rb +8 -27
  132. data/lib/active_record/middleware/database_selector.rb +74 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  135. data/lib/active_record/migration.rb +104 -85
  136. data/lib/active_record/migration/command_recorder.rb +54 -22
  137. data/lib/active_record/migration/compatibility.rb +79 -52
  138. data/lib/active_record/migration/join_table.rb +0 -1
  139. data/lib/active_record/model_schema.rb +33 -11
  140. data/lib/active_record/nested_attributes.rb +2 -4
  141. data/lib/active_record/no_touching.rb +9 -2
  142. data/lib/active_record/null_relation.rb +0 -1
  143. data/lib/active_record/persistence.rb +232 -29
  144. data/lib/active_record/query_cache.rb +11 -4
  145. data/lib/active_record/querying.rb +33 -21
  146. data/lib/active_record/railtie.rb +80 -43
  147. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  148. data/lib/active_record/railties/controller_runtime.rb +30 -35
  149. data/lib/active_record/railties/databases.rake +199 -46
  150. data/lib/active_record/reflection.rb +40 -38
  151. data/lib/active_record/relation.rb +322 -80
  152. data/lib/active_record/relation/batches.rb +13 -11
  153. data/lib/active_record/relation/calculations.rb +54 -48
  154. data/lib/active_record/relation/delegation.rb +33 -49
  155. data/lib/active_record/relation/finder_methods.rb +23 -28
  156. data/lib/active_record/relation/from_clause.rb +4 -0
  157. data/lib/active_record/relation/merger.rb +11 -21
  158. data/lib/active_record/relation/predicate_builder.rb +5 -11
  159. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  160. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  161. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  162. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  163. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  164. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  165. data/lib/active_record/relation/query_attribute.rb +13 -8
  166. data/lib/active_record/relation/query_methods.rb +221 -70
  167. data/lib/active_record/relation/spawn_methods.rb +1 -2
  168. data/lib/active_record/relation/where_clause.rb +14 -11
  169. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  170. data/lib/active_record/result.rb +30 -12
  171. data/lib/active_record/sanitization.rb +32 -40
  172. data/lib/active_record/schema.rb +2 -11
  173. data/lib/active_record/schema_dumper.rb +22 -7
  174. data/lib/active_record/schema_migration.rb +6 -2
  175. data/lib/active_record/scoping.rb +8 -9
  176. data/lib/active_record/scoping/default.rb +4 -6
  177. data/lib/active_record/scoping/named.rb +21 -17
  178. data/lib/active_record/statement_cache.rb +30 -3
  179. data/lib/active_record/store.rb +87 -8
  180. data/lib/active_record/suppressor.rb +2 -2
  181. data/lib/active_record/table_metadata.rb +23 -15
  182. data/lib/active_record/tasks/database_tasks.rb +194 -25
  183. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
  184. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
  185. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
  186. data/lib/active_record/test_databases.rb +23 -0
  187. data/lib/active_record/test_fixtures.rb +225 -0
  188. data/lib/active_record/timestamp.rb +39 -26
  189. data/lib/active_record/touch_later.rb +5 -4
  190. data/lib/active_record/transactions.rb +64 -73
  191. data/lib/active_record/translation.rb +1 -1
  192. data/lib/active_record/type.rb +3 -5
  193. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  194. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  195. data/lib/active_record/type/serialized.rb +0 -1
  196. data/lib/active_record/type/type_map.rb +0 -1
  197. data/lib/active_record/type/unsigned_integer.rb +0 -1
  198. data/lib/active_record/type_caster/connection.rb +15 -14
  199. data/lib/active_record/type_caster/map.rb +1 -4
  200. data/lib/active_record/validations.rb +3 -3
  201. data/lib/active_record/validations/associated.rb +1 -2
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/arel.rb +62 -0
  204. data/lib/arel/alias_predication.rb +9 -0
  205. data/lib/arel/attributes.rb +22 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/collectors/bind.rb +24 -0
  208. data/lib/arel/collectors/composite.rb +31 -0
  209. data/lib/arel/collectors/plain_string.rb +20 -0
  210. data/lib/arel/collectors/sql_string.rb +20 -0
  211. data/lib/arel/collectors/substitute_binds.rb +28 -0
  212. data/lib/arel/crud.rb +42 -0
  213. data/lib/arel/delete_manager.rb +18 -0
  214. data/lib/arel/errors.rb +9 -0
  215. data/lib/arel/expressions.rb +29 -0
  216. data/lib/arel/factory_methods.rb +49 -0
  217. data/lib/arel/insert_manager.rb +49 -0
  218. data/lib/arel/math.rb +45 -0
  219. data/lib/arel/nodes.rb +68 -0
  220. data/lib/arel/nodes/and.rb +32 -0
  221. data/lib/arel/nodes/ascending.rb +23 -0
  222. data/lib/arel/nodes/binary.rb +52 -0
  223. data/lib/arel/nodes/bind_param.rb +36 -0
  224. data/lib/arel/nodes/case.rb +55 -0
  225. data/lib/arel/nodes/casted.rb +50 -0
  226. data/lib/arel/nodes/comment.rb +29 -0
  227. data/lib/arel/nodes/count.rb +12 -0
  228. data/lib/arel/nodes/delete_statement.rb +45 -0
  229. data/lib/arel/nodes/descending.rb +23 -0
  230. data/lib/arel/nodes/equality.rb +18 -0
  231. data/lib/arel/nodes/extract.rb +24 -0
  232. data/lib/arel/nodes/false.rb +16 -0
  233. data/lib/arel/nodes/full_outer_join.rb +8 -0
  234. data/lib/arel/nodes/function.rb +44 -0
  235. data/lib/arel/nodes/grouping.rb +8 -0
  236. data/lib/arel/nodes/in.rb +8 -0
  237. data/lib/arel/nodes/infix_operation.rb +80 -0
  238. data/lib/arel/nodes/inner_join.rb +8 -0
  239. data/lib/arel/nodes/insert_statement.rb +37 -0
  240. data/lib/arel/nodes/join_source.rb +20 -0
  241. data/lib/arel/nodes/matches.rb +18 -0
  242. data/lib/arel/nodes/named_function.rb +23 -0
  243. data/lib/arel/nodes/node.rb +50 -0
  244. data/lib/arel/nodes/node_expression.rb +13 -0
  245. data/lib/arel/nodes/outer_join.rb +8 -0
  246. data/lib/arel/nodes/over.rb +15 -0
  247. data/lib/arel/nodes/regexp.rb +16 -0
  248. data/lib/arel/nodes/right_outer_join.rb +8 -0
  249. data/lib/arel/nodes/select_core.rb +67 -0
  250. data/lib/arel/nodes/select_statement.rb +41 -0
  251. data/lib/arel/nodes/sql_literal.rb +16 -0
  252. data/lib/arel/nodes/string_join.rb +11 -0
  253. data/lib/arel/nodes/table_alias.rb +27 -0
  254. data/lib/arel/nodes/terminal.rb +16 -0
  255. data/lib/arel/nodes/true.rb +16 -0
  256. data/lib/arel/nodes/unary.rb +45 -0
  257. data/lib/arel/nodes/unary_operation.rb +20 -0
  258. data/lib/arel/nodes/unqualified_column.rb +22 -0
  259. data/lib/arel/nodes/update_statement.rb +41 -0
  260. data/lib/arel/nodes/values_list.rb +9 -0
  261. data/lib/arel/nodes/window.rb +126 -0
  262. data/lib/arel/nodes/with.rb +11 -0
  263. data/lib/arel/order_predications.rb +13 -0
  264. data/lib/arel/predications.rb +256 -0
  265. data/lib/arel/select_manager.rb +271 -0
  266. data/lib/arel/table.rb +110 -0
  267. data/lib/arel/tree_manager.rb +72 -0
  268. data/lib/arel/update_manager.rb +34 -0
  269. data/lib/arel/visitors.rb +20 -0
  270. data/lib/arel/visitors/depth_first.rb +203 -0
  271. data/lib/arel/visitors/dot.rb +296 -0
  272. data/lib/arel/visitors/ibm_db.rb +34 -0
  273. data/lib/arel/visitors/informix.rb +62 -0
  274. data/lib/arel/visitors/mssql.rb +156 -0
  275. data/lib/arel/visitors/mysql.rb +83 -0
  276. data/lib/arel/visitors/oracle.rb +158 -0
  277. data/lib/arel/visitors/oracle12.rb +65 -0
  278. data/lib/arel/visitors/postgresql.rb +109 -0
  279. data/lib/arel/visitors/sqlite.rb +38 -0
  280. data/lib/arel/visitors/to_sql.rb +888 -0
  281. data/lib/arel/visitors/visitor.rb +45 -0
  282. data/lib/arel/visitors/where_sql.rb +22 -0
  283. data/lib/arel/window_predications.rb +9 -0
  284. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  285. data/lib/rails/generators/active_record/migration.rb +14 -2
  286. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  287. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  288. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  289. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  290. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  291. metadata +115 -29
  292. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -40,24 +40,6 @@ module ActiveRecord
40
40
  committed? || rolledback?
41
41
  end
42
42
 
43
- def set_state(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
57
- raise ArgumentError, "Invalid transaction state: #{state}"
58
- end
59
- end
60
-
61
43
  def rollback!
62
44
  @children.each { |c| c.rollback! }
63
45
  @state = :rolledback
@@ -91,13 +73,14 @@ module ActiveRecord
91
73
  end
92
74
 
93
75
  class Transaction #:nodoc:
94
- attr_reader :connection, :state, :records, :savepoint_name
95
- attr_writer :joinable
76
+ attr_reader :connection, :state, :records, :savepoint_name, :isolation_level
96
77
 
97
78
  def initialize(connection, options, run_commit_callbacks: false)
98
79
  @connection = connection
99
80
  @state = TransactionState.new
100
81
  @records = []
82
+ @isolation_level = options[:isolation]
83
+ @materialized = false
101
84
  @joinable = options.fetch(:joinable, true)
102
85
  @run_commit_callbacks = run_commit_callbacks
103
86
  end
@@ -106,10 +89,22 @@ module ActiveRecord
106
89
  records << record
107
90
  end
108
91
 
92
+ def materialize!
93
+ @materialized = true
94
+ end
95
+
96
+ def materialized?
97
+ @materialized
98
+ end
99
+
109
100
  def rollback_records
110
- ite = records.uniq
101
+ ite = records.uniq(&:__id__)
102
+ already_run_callbacks = {}
111
103
  while record = ite.shift
112
- record.rolledback!(force_restore_state: full_rollback?)
104
+ trigger_callbacks = record.trigger_transactional_callbacks?
105
+ should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
106
+ already_run_callbacks[record] ||= trigger_callbacks
107
+ record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
113
108
  end
114
109
  ensure
115
110
  ite.each do |i|
@@ -122,13 +117,17 @@ module ActiveRecord
122
117
  end
123
118
 
124
119
  def commit_records
125
- ite = records.uniq
120
+ ite = records.uniq(&:__id__)
121
+ already_run_callbacks = {}
126
122
  while record = ite.shift
127
123
  if @run_commit_callbacks
128
- record.committed!
124
+ trigger_callbacks = record.trigger_transactional_callbacks?
125
+ should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
126
+ already_run_callbacks[record] ||= trigger_callbacks
127
+ record.committed!(should_run_callbacks: should_run_callbacks)
129
128
  else
130
129
  # if not running callbacks, only adds the record to the parent transaction
131
- record.add_to_transaction
130
+ connection.add_transaction_record(record)
132
131
  end
133
132
  end
134
133
  ensure
@@ -142,24 +141,30 @@ module ActiveRecord
142
141
  end
143
142
 
144
143
  class SavepointTransaction < Transaction
145
- def initialize(connection, savepoint_name, parent_transaction, options, *args)
146
- super(connection, options, *args)
144
+ def initialize(connection, savepoint_name, parent_transaction, *args, **options)
145
+ super(connection, *args, **options)
147
146
 
148
147
  parent_transaction.state.add_child(@state)
149
148
 
150
- if options[:isolation]
149
+ if isolation_level
151
150
  raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
152
151
  end
153
- connection.create_savepoint(@savepoint_name = savepoint_name)
152
+
153
+ @savepoint_name = savepoint_name
154
+ end
155
+
156
+ def materialize!
157
+ connection.create_savepoint(savepoint_name)
158
+ super
154
159
  end
155
160
 
156
161
  def rollback
157
- connection.rollback_to_savepoint(savepoint_name)
162
+ connection.rollback_to_savepoint(savepoint_name) if materialized?
158
163
  @state.rollback!
159
164
  end
160
165
 
161
166
  def commit
162
- connection.release_savepoint(savepoint_name)
167
+ connection.release_savepoint(savepoint_name) if materialized?
163
168
  @state.commit!
164
169
  end
165
170
 
@@ -167,22 +172,23 @@ module ActiveRecord
167
172
  end
168
173
 
169
174
  class RealTransaction < Transaction
170
- def initialize(connection, options, *args)
171
- super
172
- if options[:isolation]
173
- connection.begin_isolated_db_transaction(options[:isolation])
175
+ def materialize!
176
+ if isolation_level
177
+ connection.begin_isolated_db_transaction(isolation_level)
174
178
  else
175
179
  connection.begin_db_transaction
176
180
  end
181
+
182
+ super
177
183
  end
178
184
 
179
185
  def rollback
180
- connection.rollback_db_transaction
186
+ connection.rollback_db_transaction if materialized?
181
187
  @state.full_rollback!
182
188
  end
183
189
 
184
190
  def commit
185
- connection.commit_db_transaction
191
+ connection.commit_db_transaction if materialized?
186
192
  @state.full_commit!
187
193
  end
188
194
  end
@@ -191,6 +197,9 @@ module ActiveRecord
191
197
  def initialize(connection)
192
198
  @stack = []
193
199
  @connection = connection
200
+ @has_unmaterialized_transactions = false
201
+ @materializing_transactions = false
202
+ @lazy_transactions_enabled = true
194
203
  end
195
204
 
196
205
  def begin_transaction(options = {})
@@ -204,11 +213,44 @@ module ActiveRecord
204
213
  run_commit_callbacks: run_commit_callbacks)
205
214
  end
206
215
 
216
+ if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && options[:_lazy] != false
217
+ @has_unmaterialized_transactions = true
218
+ else
219
+ transaction.materialize!
220
+ end
207
221
  @stack.push(transaction)
208
222
  transaction
209
223
  end
210
224
  end
211
225
 
226
+ def disable_lazy_transactions!
227
+ materialize_transactions
228
+ @lazy_transactions_enabled = false
229
+ end
230
+
231
+ def enable_lazy_transactions!
232
+ @lazy_transactions_enabled = true
233
+ end
234
+
235
+ def lazy_transactions_enabled?
236
+ @lazy_transactions_enabled
237
+ end
238
+
239
+ def materialize_transactions
240
+ return if @materializing_transactions
241
+ return unless @has_unmaterialized_transactions
242
+
243
+ @connection.lock.synchronize do
244
+ begin
245
+ @materializing_transactions = true
246
+ @stack.each { |t| t.materialize! unless t.materialized? }
247
+ ensure
248
+ @materializing_transactions = false
249
+ end
250
+ @has_unmaterialized_transactions = false
251
+ end
252
+ end
253
+
212
254
  def commit_transaction
213
255
  @connection.lock.synchronize do
214
256
  transaction = @stack.last
@@ -234,26 +276,24 @@ module ActiveRecord
234
276
 
235
277
  def within_new_transaction(options = {})
236
278
  @connection.lock.synchronize do
237
- begin
238
- transaction = begin_transaction options
239
- yield
240
- rescue Exception => error
241
- if transaction
279
+ transaction = begin_transaction options
280
+ yield
281
+ rescue Exception => error
282
+ if transaction
283
+ rollback_transaction
284
+ after_failure_actions(transaction, error)
285
+ end
286
+ raise
287
+ ensure
288
+ if !error && transaction
289
+ if Thread.current.status == "aborting"
242
290
  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
291
+ else
292
+ begin
293
+ commit_transaction
294
+ rescue Exception
295
+ rollback_transaction(transaction) unless transaction.state.completed?
296
+ raise
257
297
  end
258
298
  end
259
299
  end
@@ -269,7 +309,6 @@ module ActiveRecord
269
309
  end
270
310
 
271
311
  private
272
-
273
312
  NULL_TRANSACTION = NullTransaction.new
274
313
 
275
314
  # Deallocate invalidated prepared statements outside of the transaction
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "set"
3
4
  require "active_record/connection_adapters/determine_if_preparable_visitor"
4
5
  require "active_record/connection_adapters/schema_cache"
5
6
  require "active_record/connection_adapters/sql_type_metadata"
6
7
  require "active_record/connection_adapters/abstract/schema_dumper"
7
8
  require "active_record/connection_adapters/abstract/schema_creation"
8
9
  require "active_support/concurrency/load_interlock_aware_monitor"
10
+ require "active_support/deprecation"
9
11
  require "arel/collectors/bind"
10
12
  require "arel/collectors/composite"
11
13
  require "arel/collectors/sql_string"
@@ -65,7 +67,7 @@ module ActiveRecord
65
67
  # Most of the methods in the adapter are useful during migrations. Most
66
68
  # notably, the instance methods provided by SchemaStatements are very useful.
67
69
  class AbstractAdapter
68
- ADAPTER_NAME = "Abstract".freeze
70
+ ADAPTER_NAME = "Abstract"
69
71
  include ActiveSupport::Callbacks
70
72
  define_callbacks :checkout, :checkin
71
73
 
@@ -75,15 +77,18 @@ module ActiveRecord
75
77
  include Savepoints
76
78
 
77
79
  SIMPLE_INT = /\A\d+\z/
80
+ COMMENT_REGEX = %r{/\*(?:[^\*]|\*[^/])*\*/}m
78
81
 
79
- attr_accessor :visitor, :pool
80
- attr_reader :schema_cache, :owner, :logger, :prepared_statements, :lock
82
+ attr_accessor :pool
83
+ attr_reader :visitor, :owner, :logger, :lock
81
84
  alias :in_use? :owner
82
85
 
86
+ set_callback :checkin, :after, :enable_lazy_transactions!
87
+
83
88
  def self.type_cast_config_to_integer(config)
84
89
  if config.is_a?(Integer)
85
90
  config
86
- elsif config =~ SIMPLE_INT
91
+ elsif SIMPLE_INT.match?(config)
87
92
  config.to_i
88
93
  else
89
94
  config
@@ -98,6 +103,19 @@ module ActiveRecord
98
103
  end
99
104
  end
100
105
 
106
+ def self.build_read_query_regexp(*parts) # :nodoc:
107
+ parts = parts.map { |part| /#{part}/i }
108
+ /\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
109
+ end
110
+
111
+ def self.quoted_column_names # :nodoc:
112
+ @quoted_column_names ||= {}
113
+ end
114
+
115
+ def self.quoted_table_names # :nodoc:
116
+ @quoted_table_names ||= {}
117
+ end
118
+
101
119
  def initialize(connection, logger = nil, config = {}) # :nodoc:
102
120
  super()
103
121
 
@@ -106,11 +124,10 @@ module ActiveRecord
106
124
  @instrumenter = ActiveSupport::Notifications.instrumenter
107
125
  @logger = logger
108
126
  @config = config
109
- @pool = nil
127
+ @pool = ActiveRecord::ConnectionAdapters::NullPool.new
110
128
  @idle_since = Concurrent.monotonic_time
111
- @schema_cache = SchemaCache.new self
112
- @quoted_column_names, @quoted_table_names = {}, {}
113
129
  @visitor = arel_visitor
130
+ @statements = build_statement_pool
114
131
  @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
115
132
 
116
133
  if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
@@ -119,6 +136,22 @@ module ActiveRecord
119
136
  else
120
137
  @prepared_statements = false
121
138
  end
139
+
140
+ @advisory_locks_enabled = self.class.type_cast_config_to_boolean(
141
+ config.fetch(:advisory_locks, true)
142
+ )
143
+ end
144
+
145
+ def replica?
146
+ @config[:replica] || false
147
+ end
148
+
149
+ # Determines whether writes are currently being prevents.
150
+ #
151
+ # Returns true if the connection is a replica, or if +prevent_writes+
152
+ # is set to true.
153
+ def preventing_writes?
154
+ replica? || ActiveRecord::Base.connection_handler.prevent_writes
122
155
  end
123
156
 
124
157
  def migrations_paths # :nodoc:
@@ -126,19 +159,49 @@ module ActiveRecord
126
159
  end
127
160
 
128
161
  def migration_context # :nodoc:
129
- MigrationContext.new(migrations_paths)
162
+ MigrationContext.new(migrations_paths, schema_migration)
163
+ end
164
+
165
+ def schema_migration # :nodoc:
166
+ @schema_migration ||= begin
167
+ conn = self
168
+ spec_name = conn.pool.spec.name
169
+ name = "#{spec_name}::SchemaMigration"
170
+
171
+ Class.new(ActiveRecord::SchemaMigration) do
172
+ define_singleton_method(:name) { name }
173
+ define_singleton_method(:to_s) { name }
174
+
175
+ self.connection_specification_name = spec_name
176
+ end
177
+ end
178
+ end
179
+
180
+ def prepared_statements
181
+ @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
182
+ end
183
+
184
+ def prepared_statements_disabled_cache # :nodoc:
185
+ Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
130
186
  end
131
187
 
132
188
  class Version
133
189
  include Comparable
134
190
 
135
- def initialize(version_string)
191
+ attr_reader :full_version_string
192
+
193
+ def initialize(version_string, full_version_string = nil)
136
194
  @version = version_string.split(".").map(&:to_i)
195
+ @full_version_string = full_version_string
137
196
  end
138
197
 
139
198
  def <=>(version_string)
140
199
  @version <=> version_string.split(".").map(&:to_i)
141
200
  end
201
+
202
+ def to_s
203
+ @version.join(".")
204
+ end
142
205
  end
143
206
 
144
207
  def valid_type?(type) # :nodoc:
@@ -148,7 +211,7 @@ module ActiveRecord
148
211
  # this method must only be called while holding connection pool's mutex
149
212
  def lease
150
213
  if in_use?
151
- msg = "Cannot lease connection, ".dup
214
+ msg = +"Cannot lease connection, "
152
215
  if @owner == Thread.current
153
216
  msg << "it is already leased by the current thread."
154
217
  else
@@ -161,9 +224,13 @@ module ActiveRecord
161
224
  @owner = Thread.current
162
225
  end
163
226
 
227
+ def schema_cache
228
+ @pool.get_schema_cache(self)
229
+ end
230
+
164
231
  def schema_cache=(cache)
165
232
  cache.connection = self
166
- @schema_cache = cache
233
+ @pool.set_schema_cache(cache)
167
234
  end
168
235
 
169
236
  # this method must only be called while holding connection pool's mutex
@@ -202,10 +269,10 @@ module ActiveRecord
202
269
  end
203
270
 
204
271
  def unprepared_statement
205
- old_prepared_statements, @prepared_statements = @prepared_statements, false
272
+ cache = prepared_statements_disabled_cache.add(object_id) if @prepared_statements
206
273
  yield
207
274
  ensure
208
- @prepared_statements = old_prepared_statements
275
+ cache&.delete(object_id)
209
276
  end
210
277
 
211
278
  # Returns the human-readable name of the adapter. Use mixed case - one
@@ -214,6 +281,11 @@ module ActiveRecord
214
281
  self.class::ADAPTER_NAME
215
282
  end
216
283
 
284
+ # Does the database for this adapter exist?
285
+ def self.database_exists?(config)
286
+ raise NotImplementedError
287
+ end
288
+
217
289
  # Does this adapter support DDL rollbacks in transactions? That is, would
218
290
  # CREATE TABLE or ALTER TABLE get rolled back by a transaction?
219
291
  def supports_ddl_transactions?
@@ -241,6 +313,10 @@ module ActiveRecord
241
313
  false
242
314
  end
243
315
 
316
+ def supports_partitioned_indexes?
317
+ false
318
+ end
319
+
244
320
  # Does this adapter support index sort order?
245
321
  def supports_index_sort_order?
246
322
  false
@@ -292,12 +368,18 @@ module ActiveRecord
292
368
  def supports_foreign_keys_in_create?
293
369
  supports_foreign_keys?
294
370
  end
371
+ deprecate :supports_foreign_keys_in_create?
295
372
 
296
373
  # Does this adapter support views?
297
374
  def supports_views?
298
375
  false
299
376
  end
300
377
 
378
+ # Does this adapter support materialized views?
379
+ def supports_materialized_views?
380
+ false
381
+ end
382
+
301
383
  # Does this adapter support datetime with precision?
302
384
  def supports_datetime_with_precision?
303
385
  false
@@ -322,6 +404,7 @@ module ActiveRecord
322
404
  def supports_multi_insert?
323
405
  true
324
406
  end
407
+ deprecate :supports_multi_insert?
325
408
 
326
409
  # Does this adapter support virtual columns?
327
410
  def supports_virtual_columns?
@@ -333,6 +416,35 @@ module ActiveRecord
333
416
  false
334
417
  end
335
418
 
419
+ # Does this adapter support optimizer hints?
420
+ def supports_optimizer_hints?
421
+ false
422
+ end
423
+
424
+ def supports_common_table_expressions?
425
+ false
426
+ end
427
+
428
+ def supports_lazy_transactions?
429
+ false
430
+ end
431
+
432
+ def supports_insert_returning?
433
+ false
434
+ end
435
+
436
+ def supports_insert_on_duplicate_skip?
437
+ false
438
+ end
439
+
440
+ def supports_insert_on_duplicate_update?
441
+ false
442
+ end
443
+
444
+ def supports_insert_conflict_target?
445
+ false
446
+ end
447
+
336
448
  # This is meant to be implemented by the adapters that support extensions
337
449
  def disable_extension(name)
338
450
  end
@@ -341,6 +453,10 @@ module ActiveRecord
341
453
  def enable_extension(name)
342
454
  end
343
455
 
456
+ def advisory_locks_enabled? # :nodoc:
457
+ supports_advisory_locks? && @advisory_locks_enabled
458
+ end
459
+
344
460
  # This is meant to be implemented by the adapters that support advisory
345
461
  # locks
346
462
  #
@@ -406,6 +522,9 @@ module ActiveRecord
406
522
  #
407
523
  # Prevent @connection's finalizer from touching the socket, or
408
524
  # otherwise communicating with its server, when it is collected.
525
+ if schema_cache.connection == self
526
+ schema_cache.connection = nil
527
+ end
409
528
  end
410
529
 
411
530
  # Reset the state of this connection, directing the DBMS to clear
@@ -418,11 +537,9 @@ module ActiveRecord
418
537
  # this should be overridden by concrete adapters
419
538
  end
420
539
 
421
- ###
422
- # Clear any caching the database adapter may be doing, for example
423
- # clearing the prepared statement cache. This is database specific.
540
+ # Clear any caching the database adapter may be doing.
424
541
  def clear_cache!
425
- # this should be overridden by concrete adapters
542
+ @lock.synchronize { @statements.clear } if @statements
426
543
  end
427
544
 
428
545
  # Returns true if its required to reload the connection between requests for development mode.
@@ -444,18 +561,25 @@ module ActiveRecord
444
561
  # This is useful for when you need to call a proprietary method such as
445
562
  # PostgreSQL's lo_* methods.
446
563
  def raw_connection
564
+ disable_lazy_transactions!
447
565
  @connection
448
566
  end
449
567
 
450
- def case_sensitive_comparison(table, attribute, column, value) # :nodoc:
451
- table[attribute].eq(value)
568
+ def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
569
+ attribute.eq(value)
452
570
  end
453
571
 
454
- def case_insensitive_comparison(table, attribute, column, value) # :nodoc:
572
+ def case_sensitive_comparison(attribute, value) # :nodoc:
573
+ attribute.eq(value)
574
+ end
575
+
576
+ def case_insensitive_comparison(attribute, value) # :nodoc:
577
+ column = column_for_attribute(attribute)
578
+
455
579
  if can_perform_case_insensitive_comparison_for?(column)
456
- table[attribute].lower.eq(table.lower(value))
580
+ attribute.lower.eq(attribute.relation.lower(value))
457
581
  else
458
- table[attribute].eq(value)
582
+ attribute.eq(value)
459
583
  end
460
584
  end
461
585
 
@@ -470,17 +594,36 @@ module ActiveRecord
470
594
  end
471
595
 
472
596
  def column_name_for_operation(operation, node) # :nodoc:
473
- column_name_from_arel_node(node)
474
- end
475
-
476
- def column_name_from_arel_node(node) # :nodoc:
477
- visitor.accept(node, Arel::Collectors::SQLString.new).value
597
+ visitor.compile(node)
478
598
  end
479
599
 
480
600
  def default_index_type?(index) # :nodoc:
481
601
  index.using.nil?
482
602
  end
483
603
 
604
+ # Called by ActiveRecord::InsertAll,
605
+ # Passed an instance of ActiveRecord::InsertAll::Builder,
606
+ # This method implements standard bulk inserts for all databases, but
607
+ # should be overridden by adapters to implement common features with
608
+ # non-standard syntax like handling duplicates or returning values.
609
+ def build_insert_sql(insert) # :nodoc:
610
+ if insert.skip_duplicates? || insert.update_duplicates?
611
+ raise NotImplementedError, "#{self.class} should define `build_insert_sql` to implement adapter-specific logic for handling duplicates during INSERT"
612
+ end
613
+
614
+ "INSERT #{insert.into} #{insert.values_list}"
615
+ end
616
+
617
+ def get_database_version # :nodoc:
618
+ end
619
+
620
+ def database_version # :nodoc:
621
+ schema_cache.database_version
622
+ end
623
+
624
+ def check_version # :nodoc:
625
+ end
626
+
484
627
  private
485
628
  def type_map
486
629
  @type_map ||= Type::TypeMap.new.tap do |mapping|
@@ -555,14 +698,12 @@ module ActiveRecord
555
698
  $1.to_i if sql_type =~ /\((.*)\)/
556
699
  end
557
700
 
558
- def translate_exception_class(e, sql)
559
- begin
560
- message = "#{e.class.name}: #{e.message}: #{sql}"
561
- rescue Encoding::CompatibilityError
562
- message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
563
- end
701
+ def translate_exception_class(e, sql, binds)
702
+ message = "#{e.class.name}: #{e.message}"
564
703
 
565
- exception = translate_exception(e, message)
704
+ exception = translate_exception(
705
+ e, message: message, sql: sql, binds: binds
706
+ )
566
707
  exception.set_backtrace e.backtrace
567
708
  exception
568
709
  end
@@ -575,24 +716,23 @@ module ActiveRecord
575
716
  binds: binds,
576
717
  type_casted_binds: type_casted_binds,
577
718
  statement_name: statement_name,
578
- connection_id: object_id) do
579
- begin
580
- @lock.synchronize do
581
- yield
582
- end
583
- rescue => e
584
- raise translate_exception_class(e, sql)
719
+ connection_id: object_id,
720
+ connection: self) do
721
+ @lock.synchronize do
722
+ yield
585
723
  end
724
+ rescue => e
725
+ raise translate_exception_class(e, sql, binds)
586
726
  end
587
727
  end
588
728
 
589
- def translate_exception(exception, message)
729
+ def translate_exception(exception, message:, sql:, binds:)
590
730
  # override in derived class
591
731
  case exception
592
732
  when RuntimeError
593
733
  exception
594
734
  else
595
- ActiveRecord::StatementInvalid.new(message)
735
+ ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
596
736
  end
597
737
  end
598
738
 
@@ -606,6 +746,11 @@ module ActiveRecord
606
746
  raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
607
747
  end
608
748
 
749
+ def column_for_attribute(attribute)
750
+ table_name = attribute.relation.name
751
+ schema_cache.columns_hash(table_name)[attribute.name.to_s]
752
+ end
753
+
609
754
  def collector
610
755
  if prepared_statements
611
756
  Arel::Collectors::Composite.new(
@@ -623,6 +768,9 @@ module ActiveRecord
623
768
  def arel_visitor
624
769
  Arel::Visitors::ToSql.new(self)
625
770
  end
771
+
772
+ def build_statement_pool
773
+ end
626
774
  end
627
775
  end
628
776
  end