activerecord 5.0.7.2 → 6.1.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 (363) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +829 -2015
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +11 -9
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -29
  8. data/lib/active_record/aggregations.rb +249 -247
  9. data/lib/active_record/association_relation.rb +30 -18
  10. data/lib/active_record/associations.rb +1714 -1596
  11. data/lib/active_record/associations/alias_tracker.rb +36 -42
  12. data/lib/active_record/associations/association.rb +143 -68
  13. data/lib/active_record/associations/association_scope.rb +98 -94
  14. data/lib/active_record/associations/belongs_to_association.rb +76 -46
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -28
  17. data/lib/active_record/associations/builder/belongs_to.rb +52 -60
  18. data/lib/active_record/associations/builder/collection_association.rb +12 -22
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
  20. data/lib/active_record/associations/builder/has_many.rb +10 -2
  21. data/lib/active_record/associations/builder/has_one.rb +35 -2
  22. data/lib/active_record/associations/builder/singular_association.rb +5 -1
  23. data/lib/active_record/associations/collection_association.rb +104 -259
  24. data/lib/active_record/associations/collection_proxy.rb +169 -125
  25. data/lib/active_record/associations/foreign_association.rb +22 -0
  26. data/lib/active_record/associations/has_many_association.rb +46 -31
  27. data/lib/active_record/associations/has_many_through_association.rb +66 -46
  28. data/lib/active_record/associations/has_one_association.rb +71 -52
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +169 -180
  31. data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +97 -104
  35. data/lib/active_record/associations/preloader/association.rb +109 -97
  36. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  37. data/lib/active_record/associations/singular_association.rb +12 -45
  38. data/lib/active_record/associations/through_association.rb +27 -15
  39. data/lib/active_record/attribute_assignment.rb +55 -60
  40. data/lib/active_record/attribute_methods.rb +111 -141
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
  42. data/lib/active_record/attribute_methods/dirty.rb +172 -112
  43. data/lib/active_record/attribute_methods/primary_key.rb +88 -91
  44. data/lib/active_record/attribute_methods/query.rb +6 -8
  45. data/lib/active_record/attribute_methods/read.rb +18 -50
  46. data/lib/active_record/attribute_methods/serialization.rb +38 -10
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
  48. data/lib/active_record/attribute_methods/write.rb +25 -32
  49. data/lib/active_record/attributes.rb +69 -31
  50. data/lib/active_record/autosave_association.rb +102 -66
  51. data/lib/active_record/base.rb +16 -25
  52. data/lib/active_record/callbacks.rb +202 -43
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -12
  55. data/lib/active_record/connection_adapters.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
  69. data/lib/active_record/connection_adapters/column.rb +55 -13
  70. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  71. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +79 -49
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -56
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +20 -12
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
  82. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  83. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
  85. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
  86. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  90. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -6
  93. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
  95. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  98. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  106. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
  107. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  109. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  110. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +98 -38
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +426 -324
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
  121. data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
  123. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  124. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -6
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +282 -290
  131. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  132. data/lib/active_record/connection_handling.rb +287 -45
  133. data/lib/active_record/core.rb +385 -181
  134. data/lib/active_record/counter_cache.rb +60 -28
  135. data/lib/active_record/database_configurations.rb +272 -0
  136. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  137. data/lib/active_record/database_configurations/database_config.rb +80 -0
  138. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  139. data/lib/active_record/database_configurations/url_config.rb +53 -0
  140. data/lib/active_record/delegated_type.rb +209 -0
  141. data/lib/active_record/destroy_association_async_job.rb +36 -0
  142. data/lib/active_record/dynamic_matchers.rb +87 -87
  143. data/lib/active_record/enum.rb +122 -47
  144. data/lib/active_record/errors.rb +153 -22
  145. data/lib/active_record/explain.rb +13 -8
  146. data/lib/active_record/explain_registry.rb +3 -1
  147. data/lib/active_record/explain_subscriber.rb +9 -4
  148. data/lib/active_record/fixture_set/file.rb +20 -22
  149. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  150. data/lib/active_record/fixture_set/render_context.rb +17 -0
  151. data/lib/active_record/fixture_set/table_row.rb +152 -0
  152. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  153. data/lib/active_record/fixtures.rb +246 -507
  154. data/lib/active_record/gem_version.rb +6 -4
  155. data/lib/active_record/inheritance.rb +168 -95
  156. data/lib/active_record/insert_all.rb +208 -0
  157. data/lib/active_record/integration.rb +114 -25
  158. data/lib/active_record/internal_metadata.rb +30 -24
  159. data/lib/active_record/legacy_yaml_adapter.rb +11 -5
  160. data/lib/active_record/locking/optimistic.rb +81 -85
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +68 -31
  163. data/lib/active_record/middleware/database_selector.rb +77 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  166. data/lib/active_record/migration.rb +439 -342
  167. data/lib/active_record/migration/command_recorder.rb +152 -98
  168. data/lib/active_record/migration/compatibility.rb +229 -60
  169. data/lib/active_record/migration/join_table.rb +8 -7
  170. data/lib/active_record/model_schema.rb +230 -122
  171. data/lib/active_record/nested_attributes.rb +213 -203
  172. data/lib/active_record/no_touching.rb +11 -2
  173. data/lib/active_record/null_relation.rb +12 -34
  174. data/lib/active_record/persistence.rb +471 -97
  175. data/lib/active_record/query_cache.rb +23 -12
  176. data/lib/active_record/querying.rb +43 -25
  177. data/lib/active_record/railtie.rb +155 -43
  178. data/lib/active_record/railties/console_sandbox.rb +2 -0
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +507 -195
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +245 -269
  183. data/lib/active_record/relation.rb +475 -324
  184. data/lib/active_record/relation/batches.rb +125 -72
  185. data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
  186. data/lib/active_record/relation/calculations.rb +267 -171
  187. data/lib/active_record/relation/delegation.rb +73 -69
  188. data/lib/active_record/relation/finder_methods.rb +238 -248
  189. data/lib/active_record/relation/from_clause.rb +7 -9
  190. data/lib/active_record/relation/merger.rb +95 -77
  191. data/lib/active_record/relation/predicate_builder.rb +109 -110
  192. data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
  193. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  194. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  195. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
  196. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  197. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  198. data/lib/active_record/relation/query_attribute.rb +33 -2
  199. data/lib/active_record/relation/query_methods.rb +654 -374
  200. data/lib/active_record/relation/record_fetch_warning.rb +8 -6
  201. data/lib/active_record/relation/spawn_methods.rb +15 -14
  202. data/lib/active_record/relation/where_clause.rb +171 -109
  203. data/lib/active_record/result.rb +88 -51
  204. data/lib/active_record/runtime_registry.rb +5 -3
  205. data/lib/active_record/sanitization.rb +73 -100
  206. data/lib/active_record/schema.rb +7 -14
  207. data/lib/active_record/schema_dumper.rb +101 -69
  208. data/lib/active_record/schema_migration.rb +16 -12
  209. data/lib/active_record/scoping.rb +20 -20
  210. data/lib/active_record/scoping/default.rb +92 -95
  211. data/lib/active_record/scoping/named.rb +39 -30
  212. data/lib/active_record/secure_token.rb +19 -9
  213. data/lib/active_record/serialization.rb +7 -3
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +80 -29
  216. data/lib/active_record/store.rb +122 -42
  217. data/lib/active_record/suppressor.rb +6 -3
  218. data/lib/active_record/table_metadata.rb +51 -39
  219. data/lib/active_record/tasks/database_tasks.rb +332 -115
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +246 -0
  225. data/lib/active_record/timestamp.rb +70 -38
  226. data/lib/active_record/touch_later.rb +26 -24
  227. data/lib/active_record/transactions.rb +121 -184
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type.rb +29 -17
  230. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  231. data/lib/active_record/type/date.rb +2 -0
  232. data/lib/active_record/type/date_time.rb +2 -0
  233. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  234. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  235. data/lib/active_record/type/internal/timezone.rb +2 -0
  236. data/lib/active_record/type/json.rb +30 -0
  237. data/lib/active_record/type/serialized.rb +20 -9
  238. data/lib/active_record/type/text.rb +11 -0
  239. data/lib/active_record/type/time.rb +12 -1
  240. data/lib/active_record/type/type_map.rb +14 -17
  241. data/lib/active_record/type/unsigned_integer.rb +16 -0
  242. data/lib/active_record/type_caster.rb +4 -2
  243. data/lib/active_record/type_caster/connection.rb +17 -13
  244. data/lib/active_record/type_caster/map.rb +10 -6
  245. data/lib/active_record/validations.rb +8 -5
  246. data/lib/active_record/validations/absence.rb +2 -0
  247. data/lib/active_record/validations/associated.rb +4 -3
  248. data/lib/active_record/validations/length.rb +2 -0
  249. data/lib/active_record/validations/numericality.rb +35 -0
  250. data/lib/active_record/validations/presence.rb +4 -2
  251. data/lib/active_record/validations/uniqueness.rb +52 -45
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/arel.rb +54 -0
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes.rb +70 -0
  269. data/lib/arel/nodes/and.rb +32 -0
  270. data/lib/arel/nodes/ascending.rb +23 -0
  271. data/lib/arel/nodes/binary.rb +126 -0
  272. data/lib/arel/nodes/bind_param.rb +44 -0
  273. data/lib/arel/nodes/case.rb +55 -0
  274. data/lib/arel/nodes/casted.rb +62 -0
  275. data/lib/arel/nodes/comment.rb +29 -0
  276. data/lib/arel/nodes/count.rb +12 -0
  277. data/lib/arel/nodes/delete_statement.rb +45 -0
  278. data/lib/arel/nodes/descending.rb +23 -0
  279. data/lib/arel/nodes/equality.rb +15 -0
  280. data/lib/arel/nodes/extract.rb +24 -0
  281. data/lib/arel/nodes/false.rb +16 -0
  282. data/lib/arel/nodes/full_outer_join.rb +8 -0
  283. data/lib/arel/nodes/function.rb +44 -0
  284. data/lib/arel/nodes/grouping.rb +11 -0
  285. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  286. data/lib/arel/nodes/in.rb +15 -0
  287. data/lib/arel/nodes/infix_operation.rb +92 -0
  288. data/lib/arel/nodes/inner_join.rb +8 -0
  289. data/lib/arel/nodes/insert_statement.rb +37 -0
  290. data/lib/arel/nodes/join_source.rb +20 -0
  291. data/lib/arel/nodes/matches.rb +18 -0
  292. data/lib/arel/nodes/named_function.rb +23 -0
  293. data/lib/arel/nodes/node.rb +51 -0
  294. data/lib/arel/nodes/node_expression.rb +13 -0
  295. data/lib/arel/nodes/ordering.rb +27 -0
  296. data/lib/arel/nodes/outer_join.rb +8 -0
  297. data/lib/arel/nodes/over.rb +15 -0
  298. data/lib/arel/nodes/regexp.rb +16 -0
  299. data/lib/arel/nodes/right_outer_join.rb +8 -0
  300. data/lib/arel/nodes/select_core.rb +67 -0
  301. data/lib/arel/nodes/select_statement.rb +41 -0
  302. data/lib/arel/nodes/sql_literal.rb +19 -0
  303. data/lib/arel/nodes/string_join.rb +11 -0
  304. data/lib/arel/nodes/table_alias.rb +31 -0
  305. data/lib/arel/nodes/terminal.rb +16 -0
  306. data/lib/arel/nodes/true.rb +16 -0
  307. data/lib/arel/nodes/unary.rb +44 -0
  308. data/lib/arel/nodes/unary_operation.rb +20 -0
  309. data/lib/arel/nodes/unqualified_column.rb +22 -0
  310. data/lib/arel/nodes/update_statement.rb +41 -0
  311. data/lib/arel/nodes/values_list.rb +9 -0
  312. data/lib/arel/nodes/window.rb +126 -0
  313. data/lib/arel/nodes/with.rb +11 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors.rb +13 -0
  321. data/lib/arel/visitors/dot.rb +308 -0
  322. data/lib/arel/visitors/mysql.rb +93 -0
  323. data/lib/arel/visitors/postgresql.rb +120 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +899 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/rails/generators/active_record.rb +7 -5
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration.rb +22 -3
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
  333. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
  334. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
  335. data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. metadata +141 -57
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute.rb +0 -213
  348. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  349. data/lib/active_record/attribute_decorators.rb +0 -67
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
  355. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
  356. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  359. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -17
  360. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  361. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  362. data/lib/active_record/relation/where_clause_factory.rb +0 -38
  363. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,10 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  class TransactionState
4
- VALID_STATES = Set.new([:committed, :rolledback, nil])
5
-
6
6
  def initialize(state = nil)
7
7
  @state = state
8
+ @children = nil
9
+ end
10
+
11
+ def add_child(state)
12
+ @children ||= []
13
+ @children << state
8
14
  end
9
15
 
10
16
  def finalized?
@@ -12,22 +18,49 @@ module ActiveRecord
12
18
  end
13
19
 
14
20
  def committed?
15
- @state == :committed
21
+ @state == :committed || @state == :fully_committed
22
+ end
23
+
24
+ def fully_committed?
25
+ @state == :fully_committed
16
26
  end
17
27
 
18
28
  def rolledback?
19
- @state == :rolledback
29
+ @state == :rolledback || @state == :fully_rolledback
30
+ end
31
+
32
+ def fully_rolledback?
33
+ @state == :fully_rolledback
34
+ end
35
+
36
+ def fully_completed?
37
+ completed?
20
38
  end
21
39
 
22
40
  def completed?
23
41
  committed? || rolledback?
24
42
  end
25
43
 
26
- def set_state(state)
27
- unless VALID_STATES.include?(state)
28
- raise ArgumentError, "Invalid transaction state: #{state}"
29
- end
30
- @state = state
44
+ def rollback!
45
+ @children&.each { |c| c.rollback! }
46
+ @state = :rolledback
47
+ end
48
+
49
+ def full_rollback!
50
+ @children&.each { |c| c.rollback! }
51
+ @state = :fully_rolledback
52
+ end
53
+
54
+ def commit!
55
+ @state = :committed
56
+ end
57
+
58
+ def full_commit!
59
+ @state = :fully_committed
60
+ end
61
+
62
+ def nullify!
63
+ @state = nil
31
64
  end
32
65
  end
33
66
 
@@ -37,61 +70,87 @@ module ActiveRecord
37
70
  def closed?; true; end
38
71
  def open?; false; end
39
72
  def joinable?; false; end
40
- def add_record(record); end
73
+ def add_record(record, _ = true); end
41
74
  end
42
75
 
43
76
  class Transaction #:nodoc:
77
+ attr_reader :connection, :state, :savepoint_name, :isolation_level
78
+ attr_accessor :written
44
79
 
45
- attr_reader :connection, :state, :records, :savepoint_name
46
- attr_writer :joinable
47
-
48
- def initialize(connection, options, run_commit_callbacks: false)
80
+ def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
49
81
  @connection = connection
50
82
  @state = TransactionState.new
51
- @records = []
52
- @joinable = options.fetch(:joinable, true)
83
+ @records = nil
84
+ @isolation_level = isolation
85
+ @materialized = false
86
+ @joinable = joinable
53
87
  @run_commit_callbacks = run_commit_callbacks
88
+ @lazy_enrollment_records = nil
54
89
  end
55
90
 
56
- def add_record(record)
57
- records << record
91
+ def add_record(record, ensure_finalize = true)
92
+ @records ||= []
93
+ if ensure_finalize
94
+ @records << record
95
+ else
96
+ @lazy_enrollment_records ||= ObjectSpace::WeakMap.new
97
+ @lazy_enrollment_records[record] = record
98
+ end
58
99
  end
59
100
 
60
- def rollback
61
- @state.set_state(:rolledback)
101
+ def records
102
+ if @lazy_enrollment_records
103
+ @records.concat @lazy_enrollment_records.values
104
+ @lazy_enrollment_records = nil
105
+ end
106
+ @records
107
+ end
108
+
109
+ def materialize!
110
+ @materialized = true
111
+ end
112
+
113
+ def materialized?
114
+ @materialized
62
115
  end
63
116
 
64
117
  def rollback_records
65
- ite = records.uniq
118
+ return unless records
119
+ ite = records.uniq(&:__id__)
120
+ already_run_callbacks = {}
66
121
  while record = ite.shift
67
- record.rolledback!(force_restore_state: full_rollback?)
122
+ trigger_callbacks = record.trigger_transactional_callbacks?
123
+ should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
124
+ already_run_callbacks[record] ||= trigger_callbacks
125
+ record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
68
126
  end
69
127
  ensure
70
- ite.each do |i|
128
+ ite&.each do |i|
71
129
  i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
72
130
  end
73
131
  end
74
132
 
75
- def commit
76
- @state.set_state(:committed)
77
- end
78
-
79
133
  def before_commit_records
80
- records.uniq.each(&:before_committed!) if @run_commit_callbacks
134
+ records.uniq.each(&:before_committed!) if records && @run_commit_callbacks
81
135
  end
82
136
 
83
137
  def commit_records
84
- ite = records.uniq
138
+ return unless records
139
+ ite = records.uniq(&:__id__)
140
+ already_run_callbacks = {}
85
141
  while record = ite.shift
86
142
  if @run_commit_callbacks
87
- record.committed!
143
+ trigger_callbacks = record.trigger_transactional_callbacks?
144
+ should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
145
+ already_run_callbacks[record] ||= trigger_callbacks
146
+ record.committed!(should_run_callbacks: should_run_callbacks)
88
147
  else
89
148
  # if not running callbacks, only adds the record to the parent transaction
90
- record.add_to_transaction
149
+ connection.add_transaction_record(record)
91
150
  end
92
151
  end
93
152
  ensure
94
- ite.each { |i| i.committed!(should_run_callbacks: false) }
153
+ ite&.each { |i| i.committed!(should_run_callbacks: false) }
95
154
  end
96
155
 
97
156
  def full_rollback?; true; end
@@ -101,47 +160,55 @@ module ActiveRecord
101
160
  end
102
161
 
103
162
  class SavepointTransaction < Transaction
163
+ def initialize(connection, savepoint_name, parent_transaction, **options)
164
+ super(connection, **options)
165
+
166
+ parent_transaction.state.add_child(@state)
104
167
 
105
- def initialize(connection, savepoint_name, options, *args)
106
- super(connection, options, *args)
107
- if options[:isolation]
168
+ if isolation_level
108
169
  raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
109
170
  end
110
- connection.create_savepoint(@savepoint_name = savepoint_name)
171
+
172
+ @savepoint_name = savepoint_name
111
173
  end
112
174
 
113
- def rollback
114
- connection.rollback_to_savepoint(savepoint_name)
175
+ def materialize!
176
+ connection.create_savepoint(savepoint_name)
115
177
  super
116
178
  end
117
179
 
180
+ def rollback
181
+ connection.rollback_to_savepoint(savepoint_name) if materialized?
182
+ @state.rollback!
183
+ end
184
+
118
185
  def commit
119
- connection.release_savepoint(savepoint_name)
120
- super
186
+ connection.release_savepoint(savepoint_name) if materialized?
187
+ @state.commit!
121
188
  end
122
189
 
123
190
  def full_rollback?; false; end
124
191
  end
125
192
 
126
193
  class RealTransaction < Transaction
127
-
128
- def initialize(connection, options, *args)
129
- super
130
- if options[:isolation]
131
- connection.begin_isolated_db_transaction(options[:isolation])
194
+ def materialize!
195
+ if isolation_level
196
+ connection.begin_isolated_db_transaction(isolation_level)
132
197
  else
133
198
  connection.begin_db_transaction
134
199
  end
200
+
201
+ super
135
202
  end
136
203
 
137
204
  def rollback
138
- connection.rollback_db_transaction
139
- super
205
+ connection.rollback_db_transaction if materialized?
206
+ @state.full_rollback!
140
207
  end
141
208
 
142
209
  def commit
143
- connection.commit_db_transaction
144
- super
210
+ connection.commit_db_transaction if materialized?
211
+ @state.full_commit!
145
212
  end
146
213
  end
147
214
 
@@ -149,60 +216,133 @@ module ActiveRecord
149
216
  def initialize(connection)
150
217
  @stack = []
151
218
  @connection = connection
219
+ @has_unmaterialized_transactions = false
220
+ @materializing_transactions = false
221
+ @lazy_transactions_enabled = true
152
222
  end
153
223
 
154
- def begin_transaction(options = {})
155
- run_commit_callbacks = !current_transaction.joinable?
156
- transaction =
157
- if @stack.empty?
158
- RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
224
+ def begin_transaction(isolation: nil, joinable: true, _lazy: true)
225
+ @connection.lock.synchronize do
226
+ run_commit_callbacks = !current_transaction.joinable?
227
+ transaction =
228
+ if @stack.empty?
229
+ RealTransaction.new(
230
+ @connection,
231
+ isolation: isolation,
232
+ joinable: joinable,
233
+ run_commit_callbacks: run_commit_callbacks
234
+ )
235
+ else
236
+ SavepointTransaction.new(
237
+ @connection,
238
+ "active_record_#{@stack.size}",
239
+ @stack.last,
240
+ isolation: isolation,
241
+ joinable: joinable,
242
+ run_commit_callbacks: run_commit_callbacks
243
+ )
244
+ end
245
+
246
+ if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && _lazy
247
+ @has_unmaterialized_transactions = true
159
248
  else
160
- SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options,
161
- run_commit_callbacks: run_commit_callbacks)
249
+ transaction.materialize!
162
250
  end
251
+ @stack.push(transaction)
252
+ transaction
253
+ end
254
+ end
163
255
 
164
- @stack.push(transaction)
165
- transaction
256
+ def disable_lazy_transactions!
257
+ materialize_transactions
258
+ @lazy_transactions_enabled = false
166
259
  end
167
260
 
168
- def commit_transaction
169
- transaction = @stack.last
261
+ def enable_lazy_transactions!
262
+ @lazy_transactions_enabled = true
263
+ end
170
264
 
171
- begin
172
- transaction.before_commit_records
173
- ensure
174
- @stack.pop
265
+ def lazy_transactions_enabled?
266
+ @lazy_transactions_enabled
267
+ end
268
+
269
+ def materialize_transactions
270
+ return if @materializing_transactions
271
+ return unless @has_unmaterialized_transactions
272
+
273
+ @connection.lock.synchronize do
274
+ begin
275
+ @materializing_transactions = true
276
+ @stack.each { |t| t.materialize! unless t.materialized? }
277
+ ensure
278
+ @materializing_transactions = false
279
+ end
280
+ @has_unmaterialized_transactions = false
175
281
  end
282
+ end
176
283
 
177
- transaction.commit
178
- transaction.commit_records
284
+ def commit_transaction
285
+ @connection.lock.synchronize do
286
+ transaction = @stack.last
287
+
288
+ begin
289
+ transaction.before_commit_records
290
+ ensure
291
+ @stack.pop
292
+ end
293
+
294
+ transaction.commit
295
+ transaction.commit_records
296
+ end
179
297
  end
180
298
 
181
299
  def rollback_transaction(transaction = nil)
182
- transaction ||= @stack.pop
183
- transaction.rollback
184
- transaction.rollback_records
185
- end
186
-
187
- def within_new_transaction(options = {})
188
- transaction = begin_transaction options
189
- yield
190
- rescue Exception => error
191
- if transaction
192
- rollback_transaction
193
- after_failure_actions(transaction, error)
300
+ @connection.lock.synchronize do
301
+ transaction ||= @stack.pop
302
+ transaction.rollback
303
+ transaction.rollback_records
194
304
  end
195
- raise
196
- ensure
197
- unless error
198
- if Thread.current.status == 'aborting'
199
- rollback_transaction if transaction
200
- else
201
- begin
202
- commit_transaction
203
- rescue Exception
204
- rollback_transaction(transaction) unless transaction.state.completed?
205
- raise
305
+ end
306
+
307
+ def within_new_transaction(isolation: nil, joinable: true)
308
+ @connection.lock.synchronize do
309
+ transaction = begin_transaction(isolation: isolation, joinable: joinable)
310
+ ret = yield
311
+ completed = true
312
+ ret
313
+ rescue Exception => error
314
+ if transaction
315
+ rollback_transaction
316
+ after_failure_actions(transaction, error)
317
+ end
318
+ raise
319
+ ensure
320
+ if transaction
321
+ if error
322
+ # @connection still holds an open transaction, so we must not
323
+ # put it back in the pool for reuse
324
+ @connection.throw_away! unless transaction.state.rolledback?
325
+ else
326
+ if Thread.current.status == "aborting"
327
+ rollback_transaction
328
+ else
329
+ if !completed && transaction.written
330
+ ActiveSupport::Deprecation.warn(<<~EOW)
331
+ Using `return`, `break` or `throw` to exit a transaction block is
332
+ deprecated without replacement. If the `throw` came from
333
+ `Timeout.timeout(duration)`, pass an exception class as a second
334
+ argument so it doesn't use `throw` to abort its block. This results
335
+ in the transaction being committed, but in the next release of Rails
336
+ it will rollback.
337
+ EOW
338
+ end
339
+ begin
340
+ commit_transaction
341
+ rescue Exception
342
+ rollback_transaction(transaction) unless transaction.state.completed?
343
+ raise
344
+ end
345
+ end
206
346
  end
207
347
  end
208
348
  end
@@ -217,7 +357,6 @@ module ActiveRecord
217
357
  end
218
358
 
219
359
  private
220
-
221
360
  NULL_TRANSACTION = NullTransaction.new
222
361
 
223
362
  # Deallocate invalidated prepared statements outside of the transaction
@@ -226,7 +365,6 @@ module ActiveRecord
226
365
  return unless error.is_a?(ActiveRecord::PreparedStatementCacheExpired)
227
366
  @connection.clear_cache!
228
367
  end
229
-
230
368
  end
231
369
  end
232
370
  end
@@ -1,52 +1,18 @@
1
- require 'active_record/type'
2
- require 'active_record/connection_adapters/determine_if_preparable_visitor'
3
- require 'active_record/connection_adapters/schema_cache'
4
- require 'active_record/connection_adapters/sql_type_metadata'
5
- require 'active_record/connection_adapters/abstract/schema_dumper'
6
- require 'active_record/connection_adapters/abstract/schema_creation'
7
- require 'arel/collectors/bind'
8
- require 'arel/collectors/sql_string'
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "active_record/connection_adapters/schema_cache"
5
+ require "active_record/connection_adapters/sql_type_metadata"
6
+ require "active_record/connection_adapters/abstract/schema_dumper"
7
+ require "active_record/connection_adapters/abstract/schema_creation"
8
+ require "active_support/concurrency/load_interlock_aware_monitor"
9
+ require "arel/collectors/bind"
10
+ require "arel/collectors/composite"
11
+ require "arel/collectors/sql_string"
12
+ require "arel/collectors/substitute_binds"
9
13
 
10
14
  module ActiveRecord
11
15
  module ConnectionAdapters # :nodoc:
12
- extend ActiveSupport::Autoload
13
-
14
- autoload :Column
15
- autoload :ConnectionSpecification
16
-
17
- autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do
18
- autoload :IndexDefinition
19
- autoload :ColumnDefinition
20
- autoload :ChangeColumnDefinition
21
- autoload :ForeignKeyDefinition
22
- autoload :TableDefinition
23
- autoload :Table
24
- autoload :AlterTable
25
- autoload :ReferenceDefinition
26
- end
27
-
28
- autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
29
- autoload :ConnectionHandler
30
- end
31
-
32
- autoload_under 'abstract' do
33
- autoload :SchemaStatements
34
- autoload :DatabaseStatements
35
- autoload :DatabaseLimits
36
- autoload :Quoting
37
- autoload :ConnectionPool
38
- autoload :QueryCache
39
- autoload :Savepoints
40
- end
41
-
42
- autoload_at 'active_record/connection_adapters/abstract/transaction' do
43
- autoload :TransactionManager
44
- autoload :NullTransaction
45
- autoload :RealTransaction
46
- autoload :SavepointTransaction
47
- autoload :TransactionState
48
- end
49
-
50
16
  # Active Record supports multiple database systems. AbstractAdapter and
51
17
  # related classes form the abstraction layer which makes this possible.
52
18
  # An AbstractAdapter represents a connection to a database, and provides an
@@ -61,24 +27,28 @@ module ActiveRecord
61
27
  # Most of the methods in the adapter are useful during migrations. Most
62
28
  # notably, the instance methods provided by SchemaStatements are very useful.
63
29
  class AbstractAdapter
64
- ADAPTER_NAME = "Abstract".freeze
30
+ ADAPTER_NAME = "Abstract"
65
31
  include ActiveSupport::Callbacks
66
32
  define_callbacks :checkout, :checkin
67
33
 
68
34
  include Quoting, DatabaseStatements, SchemaStatements
69
35
  include DatabaseLimits
70
36
  include QueryCache
71
- include ColumnDumper
72
37
  include Savepoints
73
38
 
74
39
  SIMPLE_INT = /\A\d+\z/
40
+ COMMENT_REGEX = %r{(?:\-\-.*\n)*|/\*(?:[^\*]|\*[^/])*\*/}m
75
41
 
76
- attr_accessor :visitor, :pool
77
- attr_reader :schema_cache, :owner, :logger
42
+ attr_accessor :pool
43
+ attr_reader :visitor, :owner, :logger, :lock
78
44
  alias :in_use? :owner
79
45
 
46
+ set_callback :checkin, :after, :enable_lazy_transactions!
47
+
80
48
  def self.type_cast_config_to_integer(config)
81
- if config =~ SIMPLE_INT
49
+ if config.is_a?(Integer)
50
+ config
51
+ elsif SIMPLE_INT.match?(config)
82
52
  config.to_i
83
53
  else
84
54
  config
@@ -93,7 +63,22 @@ module ActiveRecord
93
63
  end
94
64
  end
95
65
 
96
- attr_reader :prepared_statements
66
+ DEFAULT_READ_QUERY = [:begin, :commit, :explain, :release, :rollback, :savepoint, :select, :with] # :nodoc:
67
+ private_constant :DEFAULT_READ_QUERY
68
+
69
+ def self.build_read_query_regexp(*parts) # :nodoc:
70
+ parts += DEFAULT_READ_QUERY
71
+ parts = parts.map { |part| /#{part}/i }
72
+ /\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
73
+ end
74
+
75
+ def self.quoted_column_names # :nodoc:
76
+ @quoted_column_names ||= {}
77
+ end
78
+
79
+ def self.quoted_table_names # :nodoc:
80
+ @quoted_table_names ||= {}
81
+ end
97
82
 
98
83
  def initialize(connection, logger = nil, config = {}) # :nodoc:
99
84
  super()
@@ -103,72 +88,112 @@ module ActiveRecord
103
88
  @instrumenter = ActiveSupport::Notifications.instrumenter
104
89
  @logger = logger
105
90
  @config = config
106
- @pool = nil
107
- @schema_cache = SchemaCache.new self
108
- @quoted_column_names, @quoted_table_names = {}, {}
109
- @visitor = arel_visitor
110
-
111
- if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
112
- @prepared_statements = true
113
- @visitor.extend(DetermineIfPreparableVisitor)
114
- else
115
- @prepared_statements = false
116
- end
91
+ @pool = ActiveRecord::ConnectionAdapters::NullPool.new
92
+ @idle_since = Concurrent.monotonic_time
93
+ @visitor = arel_visitor
94
+ @statements = build_statement_pool
95
+ @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
96
+
97
+ @prepared_statements = self.class.type_cast_config_to_boolean(
98
+ config.fetch(:prepared_statements, true)
99
+ )
100
+
101
+ @advisory_locks_enabled = self.class.type_cast_config_to_boolean(
102
+ config.fetch(:advisory_locks, true)
103
+ )
117
104
  end
118
105
 
119
- class Version
120
- include Comparable
106
+ def replica?
107
+ @config[:replica] || false
108
+ end
121
109
 
122
- def initialize(version_string)
123
- @version = version_string.split('.').map(&:to_i)
124
- end
110
+ def use_metadata_table?
111
+ @config.fetch(:use_metadata_table, true)
112
+ end
125
113
 
126
- def <=>(version_string)
127
- @version <=> version_string.split('.').map(&:to_i)
128
- end
114
+ # Determines whether writes are currently being prevents.
115
+ #
116
+ # Returns true if the connection is a replica.
117
+ #
118
+ # If the application is using legacy handling, returns
119
+ # true if `connection_handler.prevent_writes` is set.
120
+ #
121
+ # If the application is using the new connection handling
122
+ # will return true based on `current_preventing_writes`.
123
+ def preventing_writes?
124
+ return true if replica?
125
+ return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord::Base.legacy_connection_handling
126
+ return false if owner_name.nil?
127
+
128
+ klass = self.owner_name.safe_constantize
129
+ klass&.current_preventing_writes
129
130
  end
130
131
 
131
- class BindCollector < Arel::Collectors::Bind
132
- def compile(bvs, conn)
133
- casted_binds = conn.prepare_binds_for_database(bvs)
134
- super(casted_binds.map { |value| conn.quote(value) })
135
- end
132
+ def migrations_paths # :nodoc:
133
+ @config[:migrations_paths] || Migrator.migrations_paths
136
134
  end
137
135
 
138
- class SQLString < Arel::Collectors::SQLString
139
- def compile(bvs, conn)
140
- super(bvs)
141
- end
136
+ def migration_context # :nodoc:
137
+ MigrationContext.new(migrations_paths, schema_migration)
142
138
  end
143
139
 
144
- def collector
145
- if prepared_statements
146
- SQLString.new
147
- else
148
- BindCollector.new
149
- end
140
+ def schema_migration # :nodoc:
141
+ @schema_migration ||= begin
142
+ conn = self
143
+ spec_name = conn.pool.pool_config.connection_specification_name
144
+
145
+ return ActiveRecord::SchemaMigration if spec_name == "ActiveRecord::Base"
146
+
147
+ schema_migration_name = "#{spec_name}::SchemaMigration"
148
+
149
+ Class.new(ActiveRecord::SchemaMigration) do
150
+ define_singleton_method(:name) { schema_migration_name }
151
+ define_singleton_method(:to_s) { schema_migration_name }
152
+
153
+ self.connection_specification_name = spec_name
154
+ end
155
+ end
150
156
  end
151
157
 
152
- def arel_visitor # :nodoc:
153
- Arel::Visitors::ToSql.new(self)
158
+ def prepared_statements
159
+ @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
154
160
  end
155
161
 
156
- def valid_type?(type)
157
- false
162
+ def prepared_statements_disabled_cache # :nodoc:
163
+ Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
158
164
  end
159
165
 
160
- def schema_creation
161
- SchemaCreation.new self
166
+ class Version
167
+ include Comparable
168
+
169
+ attr_reader :full_version_string
170
+
171
+ def initialize(version_string, full_version_string = nil)
172
+ @version = version_string.split(".").map(&:to_i)
173
+ @full_version_string = full_version_string
174
+ end
175
+
176
+ def <=>(version_string)
177
+ @version <=> version_string.split(".").map(&:to_i)
178
+ end
179
+
180
+ def to_s
181
+ @version.join(".")
182
+ end
183
+ end
184
+
185
+ def valid_type?(type) # :nodoc:
186
+ !native_database_types[type].nil?
162
187
  end
163
188
 
164
189
  # this method must only be called while holding connection pool's mutex
165
190
  def lease
166
191
  if in_use?
167
- msg = 'Cannot lease connection, '
192
+ msg = +"Cannot lease connection, "
168
193
  if @owner == Thread.current
169
- msg << 'it is already leased by the current thread.'
194
+ msg << "it is already leased by the current thread."
170
195
  else
171
- msg << "it is already in use by a different thread: #{@owner}. " <<
196
+ msg << "it is already in use by a different thread: #{@owner}. " \
172
197
  "Current thread: #{Thread.current}."
173
198
  end
174
199
  raise ActiveRecordError, msg
@@ -177,23 +202,32 @@ module ActiveRecord
177
202
  @owner = Thread.current
178
203
  end
179
204
 
205
+ def owner_name # :nodoc:
206
+ @pool.owner_name
207
+ end
208
+
209
+ def schema_cache
210
+ @pool.get_schema_cache(self)
211
+ end
212
+
180
213
  def schema_cache=(cache)
181
214
  cache.connection = self
182
- @schema_cache = cache
215
+ @pool.set_schema_cache(cache)
183
216
  end
184
217
 
185
218
  # this method must only be called while holding connection pool's mutex
186
219
  def expire
187
220
  if in_use?
188
221
  if @owner != Thread.current
189
- raise ActiveRecordError, "Cannot expire connection, " <<
190
- "it is owned by a different thread: #{@owner}. " <<
222
+ raise ActiveRecordError, "Cannot expire connection, " \
223
+ "it is owned by a different thread: #{@owner}. " \
191
224
  "Current thread: #{Thread.current}."
192
225
  end
193
226
 
227
+ @idle_since = Concurrent.monotonic_time
194
228
  @owner = nil
195
229
  else
196
- raise ActiveRecordError, 'Cannot expire connection, it is not currently leased.'
230
+ raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
197
231
  end
198
232
  end
199
233
 
@@ -206,15 +240,21 @@ module ActiveRecord
206
240
  @owner = Thread.current
207
241
  end
208
242
  else
209
- raise ActiveRecordError, 'Cannot steal connection, it is not currently leased.'
243
+ raise ActiveRecordError, "Cannot steal connection, it is not currently leased."
210
244
  end
211
245
  end
212
246
 
247
+ # Seconds since this connection was returned to the pool
248
+ def seconds_idle # :nodoc:
249
+ return 0 if in_use?
250
+ Concurrent.monotonic_time - @idle_since
251
+ end
252
+
213
253
  def unprepared_statement
214
- old_prepared_statements, @prepared_statements = @prepared_statements, false
254
+ cache = prepared_statements_disabled_cache.add(object_id) if @prepared_statements
215
255
  yield
216
256
  ensure
217
- @prepared_statements = old_prepared_statements
257
+ cache&.delete(object_id)
218
258
  end
219
259
 
220
260
  # Returns the human-readable name of the adapter. Use mixed case - one
@@ -223,15 +263,9 @@ module ActiveRecord
223
263
  self.class::ADAPTER_NAME
224
264
  end
225
265
 
226
- # Does this adapter support migrations?
227
- def supports_migrations?
228
- false
229
- end
230
-
231
- # Can this adapter determine the primary key for tables not attached
232
- # to an Active Record class, such as join tables?
233
- def supports_primary_key?
234
- false
266
+ # Does the database for this adapter exist?
267
+ def self.database_exists?(config)
268
+ raise NotImplementedError
235
269
  end
236
270
 
237
271
  # Does this adapter support DDL rollbacks in transactions? That is, would
@@ -261,6 +295,10 @@ module ActiveRecord
261
295
  false
262
296
  end
263
297
 
298
+ def supports_partitioned_indexes?
299
+ false
300
+ end
301
+
264
302
  # Does this adapter support index sort order?
265
303
  def supports_index_sort_order?
266
304
  false
@@ -302,11 +340,26 @@ module ActiveRecord
302
340
  false
303
341
  end
304
342
 
343
+ # Does this adapter support creating invalid constraints?
344
+ def supports_validate_constraints?
345
+ false
346
+ end
347
+
348
+ # Does this adapter support creating check constraints?
349
+ def supports_check_constraints?
350
+ false
351
+ end
352
+
305
353
  # Does this adapter support views?
306
354
  def supports_views?
307
355
  false
308
356
  end
309
357
 
358
+ # Does this adapter support materialized views?
359
+ def supports_materialized_views?
360
+ false
361
+ end
362
+
310
363
  # Does this adapter support datetime with precision?
311
364
  def supports_datetime_with_precision?
312
365
  false
@@ -327,9 +380,43 @@ module ActiveRecord
327
380
  false
328
381
  end
329
382
 
330
- # Does this adapter support multi-value insert?
331
- def supports_multi_insert?
332
- true
383
+ # Does this adapter support virtual columns?
384
+ def supports_virtual_columns?
385
+ false
386
+ end
387
+
388
+ # Does this adapter support foreign/external tables?
389
+ def supports_foreign_tables?
390
+ false
391
+ end
392
+
393
+ # Does this adapter support optimizer hints?
394
+ def supports_optimizer_hints?
395
+ false
396
+ end
397
+
398
+ def supports_common_table_expressions?
399
+ false
400
+ end
401
+
402
+ def supports_lazy_transactions?
403
+ false
404
+ end
405
+
406
+ def supports_insert_returning?
407
+ false
408
+ end
409
+
410
+ def supports_insert_on_duplicate_skip?
411
+ false
412
+ end
413
+
414
+ def supports_insert_on_duplicate_update?
415
+ false
416
+ end
417
+
418
+ def supports_insert_conflict_target?
419
+ false
333
420
  end
334
421
 
335
422
  # This is meant to be implemented by the adapters that support extensions
@@ -340,6 +427,10 @@ module ActiveRecord
340
427
  def enable_extension(name)
341
428
  end
342
429
 
430
+ def advisory_locks_enabled? # :nodoc:
431
+ supports_advisory_locks? && @advisory_locks_enabled
432
+ end
433
+
343
434
  # This is meant to be implemented by the adapters that support advisory
344
435
  # locks
345
436
  #
@@ -394,6 +485,22 @@ module ActiveRecord
394
485
  reset_transaction
395
486
  end
396
487
 
488
+ # Immediately forget this connection ever existed. Unlike disconnect!,
489
+ # this will not communicate with the server.
490
+ #
491
+ # After calling this method, the behavior of all other methods becomes
492
+ # undefined. This is called internally just before a forked process gets
493
+ # rid of a connection that belonged to its parent.
494
+ def discard!
495
+ # This should be overridden by concrete adapters.
496
+ #
497
+ # Prevent @connection's finalizer from touching the socket, or
498
+ # otherwise communicating with its server, when it is collected.
499
+ if schema_cache.connection == self
500
+ schema_cache.connection = nil
501
+ end
502
+ end
503
+
397
504
  # Reset the state of this connection, directing the DBMS to clear
398
505
  # transactions and other connection-related server-side state. Usually a
399
506
  # database-dependent operation.
@@ -404,11 +511,15 @@ module ActiveRecord
404
511
  # this should be overridden by concrete adapters
405
512
  end
406
513
 
407
- ###
408
- # Clear any caching the database adapter may be doing, for example
409
- # clearing the prepared statement cache. This is database specific.
514
+ # Removes the connection from the pool and disconnect it.
515
+ def throw_away!
516
+ pool.remove self
517
+ disconnect!
518
+ end
519
+
520
+ # Clear any caching the database adapter may be doing.
410
521
  def clear_cache!
411
- # this should be overridden by concrete adapters
522
+ @lock.synchronize { @statements.clear } if @statements
412
523
  end
413
524
 
414
525
  # Returns true if its required to reload the connection between requests for development mode.
@@ -419,7 +530,7 @@ module ActiveRecord
419
530
  # Checks whether the connection to the database is still active (i.e. not stale).
420
531
  # This is done under the hood by calling #active?. If the connection
421
532
  # is no longer active, then this method will reconnect to the database.
422
- def verify!(*ignored)
533
+ def verify!
423
534
  reconnect! unless active?
424
535
  end
425
536
 
@@ -430,22 +541,25 @@ module ActiveRecord
430
541
  # This is useful for when you need to call a proprietary method such as
431
542
  # PostgreSQL's lo_* methods.
432
543
  def raw_connection
544
+ disable_lazy_transactions!
433
545
  @connection
434
546
  end
435
547
 
436
- def case_sensitive_comparison(table, attribute, column, value)
437
- if value.nil?
438
- table[attribute].eq(value)
439
- else
440
- table[attribute].eq(Arel::Nodes::BindParam.new)
441
- end
548
+ def default_uniqueness_comparison(attribute, value) # :nodoc:
549
+ attribute.eq(value)
442
550
  end
443
551
 
444
- def case_insensitive_comparison(table, attribute, column, value)
552
+ def case_sensitive_comparison(attribute, value) # :nodoc:
553
+ attribute.eq(value)
554
+ end
555
+
556
+ def case_insensitive_comparison(attribute, value) # :nodoc:
557
+ column = column_for_attribute(attribute)
558
+
445
559
  if can_perform_case_insensitive_comparison_for?(column)
446
- table[attribute].lower.eq(table.lower(Arel::Nodes::BindParam.new))
560
+ attribute.lower.eq(attribute.relation.lower(value))
447
561
  else
448
- table[attribute].eq(Arel::Nodes::BindParam.new)
562
+ attribute.eq(value)
449
563
  end
450
564
  end
451
565
 
@@ -459,153 +573,187 @@ module ActiveRecord
459
573
  pool.checkin self
460
574
  end
461
575
 
462
- def type_map # :nodoc:
463
- @type_map ||= Type::TypeMap.new.tap do |mapping|
464
- initialize_type_map(mapping)
576
+ def default_index_type?(index) # :nodoc:
577
+ index.using.nil?
578
+ end
579
+
580
+ # Called by ActiveRecord::InsertAll,
581
+ # Passed an instance of ActiveRecord::InsertAll::Builder,
582
+ # This method implements standard bulk inserts for all databases, but
583
+ # should be overridden by adapters to implement common features with
584
+ # non-standard syntax like handling duplicates or returning values.
585
+ def build_insert_sql(insert) # :nodoc:
586
+ if insert.skip_duplicates? || insert.update_duplicates?
587
+ raise NotImplementedError, "#{self.class} should define `build_insert_sql` to implement adapter-specific logic for handling duplicates during INSERT"
465
588
  end
589
+
590
+ "INSERT #{insert.into} #{insert.values_list}"
466
591
  end
467
592
 
468
- def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
469
- Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation)
593
+ def get_database_version # :nodoc:
470
594
  end
471
595
 
472
- def lookup_cast_type(sql_type) # :nodoc:
473
- type_map.lookup(sql_type)
596
+ def database_version # :nodoc:
597
+ schema_cache.database_version
474
598
  end
475
599
 
476
- def column_name_for_operation(operation, node) # :nodoc:
477
- visitor.accept(node, collector).value
600
+ def check_version # :nodoc:
478
601
  end
479
602
 
480
- def combine_bind_parameters(
481
- from_clause: [],
482
- join_clause: [],
483
- where_clause: [],
484
- having_clause: [],
485
- limit: nil,
486
- offset: nil
487
- ) # :nodoc:
488
- result = from_clause + join_clause + where_clause + having_clause
489
- if limit
490
- result << limit
491
- end
492
- if offset
493
- result << offset
603
+ private
604
+ def type_map
605
+ @type_map ||= Type::TypeMap.new.tap do |mapping|
606
+ initialize_type_map(mapping)
607
+ end
494
608
  end
495
- result
496
- end
497
-
498
- protected
499
-
500
- def initialize_type_map(m) # :nodoc:
501
- register_class_with_limit m, %r(boolean)i, Type::Boolean
502
- register_class_with_limit m, %r(char)i, Type::String
503
- register_class_with_limit m, %r(binary)i, Type::Binary
504
- register_class_with_limit m, %r(text)i, Type::Text
505
- register_class_with_precision m, %r(date)i, Type::Date
506
- register_class_with_precision m, %r(time)i, Type::Time
507
- register_class_with_precision m, %r(datetime)i, Type::DateTime
508
- register_class_with_limit m, %r(float)i, Type::Float
509
- register_class_with_limit m, %r(int)i, Type::Integer
510
-
511
- m.alias_type %r(blob)i, 'binary'
512
- m.alias_type %r(clob)i, 'text'
513
- m.alias_type %r(timestamp)i, 'datetime'
514
- m.alias_type %r(numeric)i, 'decimal'
515
- m.alias_type %r(number)i, 'decimal'
516
- m.alias_type %r(double)i, 'float'
517
-
518
- m.register_type(%r(decimal)i) do |sql_type|
519
- scale = extract_scale(sql_type)
520
- precision = extract_precision(sql_type)
521
-
522
- if scale == 0
523
- # FIXME: Remove this class as well
524
- Type::DecimalWithoutScale.new(precision: precision)
525
- else
526
- Type::Decimal.new(precision: precision, scale: scale)
609
+
610
+ def initialize_type_map(m = type_map)
611
+ register_class_with_limit m, %r(boolean)i, Type::Boolean
612
+ register_class_with_limit m, %r(char)i, Type::String
613
+ register_class_with_limit m, %r(binary)i, Type::Binary
614
+ register_class_with_limit m, %r(text)i, Type::Text
615
+ register_class_with_precision m, %r(date)i, Type::Date
616
+ register_class_with_precision m, %r(time)i, Type::Time
617
+ register_class_with_precision m, %r(datetime)i, Type::DateTime
618
+ register_class_with_limit m, %r(float)i, Type::Float
619
+ register_class_with_limit m, %r(int)i, Type::Integer
620
+
621
+ m.alias_type %r(blob)i, "binary"
622
+ m.alias_type %r(clob)i, "text"
623
+ m.alias_type %r(timestamp)i, "datetime"
624
+ m.alias_type %r(numeric)i, "decimal"
625
+ m.alias_type %r(number)i, "decimal"
626
+ m.alias_type %r(double)i, "float"
627
+
628
+ m.register_type %r(^json)i, Type::Json.new
629
+
630
+ m.register_type(%r(decimal)i) do |sql_type|
631
+ scale = extract_scale(sql_type)
632
+ precision = extract_precision(sql_type)
633
+
634
+ if scale == 0
635
+ # FIXME: Remove this class as well
636
+ Type::DecimalWithoutScale.new(precision: precision)
637
+ else
638
+ Type::Decimal.new(precision: precision, scale: scale)
639
+ end
527
640
  end
528
641
  end
529
- end
530
642
 
531
- def reload_type_map # :nodoc:
532
- type_map.clear
533
- initialize_type_map(type_map)
534
- end
643
+ def reload_type_map
644
+ type_map.clear
645
+ initialize_type_map
646
+ end
535
647
 
536
- def register_class_with_limit(mapping, key, klass) # :nodoc:
537
- mapping.register_type(key) do |*args|
538
- limit = extract_limit(args.last)
539
- klass.new(limit: limit)
648
+ def register_class_with_limit(mapping, key, klass)
649
+ mapping.register_type(key) do |*args|
650
+ limit = extract_limit(args.last)
651
+ klass.new(limit: limit)
652
+ end
540
653
  end
541
- end
542
654
 
543
- def register_class_with_precision(mapping, key, klass) # :nodoc:
544
- mapping.register_type(key) do |*args|
545
- precision = extract_precision(args.last)
546
- klass.new(precision: precision)
655
+ def register_class_with_precision(mapping, key, klass)
656
+ mapping.register_type(key) do |*args|
657
+ precision = extract_precision(args.last)
658
+ klass.new(precision: precision)
659
+ end
547
660
  end
548
- end
549
661
 
550
- def extract_scale(sql_type) # :nodoc:
551
- case sql_type
662
+ def extract_scale(sql_type)
663
+ case sql_type
552
664
  when /\((\d+)\)/ then 0
553
665
  when /\((\d+)(,(\d+))\)/ then $3.to_i
666
+ end
554
667
  end
555
- end
556
668
 
557
- def extract_precision(sql_type) # :nodoc:
558
- $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
559
- end
669
+ def extract_precision(sql_type)
670
+ $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
671
+ end
560
672
 
561
- def extract_limit(sql_type) # :nodoc:
562
- case sql_type
563
- when /^bigint/i
564
- 8
565
- when /\((.*)\)/
566
- $1.to_i
673
+ def extract_limit(sql_type)
674
+ $1.to_i if sql_type =~ /\((.*)\)/
567
675
  end
568
- end
569
676
 
570
- def translate_exception_class(e, sql)
571
- begin
572
- message = "#{e.class.name}: #{e.message}: #{sql}"
573
- rescue Encoding::CompatibilityError
574
- message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
677
+ def translate_exception_class(e, sql, binds)
678
+ message = "#{e.class.name}: #{e.message}"
679
+
680
+ exception = translate_exception(
681
+ e, message: message, sql: sql, binds: binds
682
+ )
683
+ exception.set_backtrace e.backtrace
684
+ exception
575
685
  end
576
686
 
577
- exception = translate_exception(e, message)
578
- exception.set_backtrace e.backtrace
579
- exception
580
- end
687
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
688
+ @instrumenter.instrument(
689
+ "sql.active_record",
690
+ sql: sql,
691
+ name: name,
692
+ binds: binds,
693
+ type_casted_binds: type_casted_binds,
694
+ statement_name: statement_name,
695
+ connection: self) do
696
+ @lock.synchronize do
697
+ yield
698
+ end
699
+ rescue => e
700
+ raise translate_exception_class(e, sql, binds)
701
+ end
702
+ end
581
703
 
582
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
583
- @instrumenter.instrument(
584
- "sql.active_record",
585
- sql: sql,
586
- name: name,
587
- binds: binds,
588
- type_casted_binds: type_casted_binds,
589
- statement_name: statement_name,
590
- connection_id: object_id) { yield }
591
- rescue => e
592
- raise translate_exception_class(e, sql)
593
- end
704
+ def translate_exception(exception, message:, sql:, binds:)
705
+ # override in derived class
706
+ case exception
707
+ when RuntimeError
708
+ exception
709
+ else
710
+ ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
711
+ end
712
+ end
594
713
 
595
- def translate_exception(exception, message)
596
- # override in derived class
597
- ActiveRecord::StatementInvalid.new(message)
598
- end
714
+ def without_prepared_statement?(binds)
715
+ !prepared_statements || binds.empty?
716
+ end
599
717
 
600
- def without_prepared_statement?(binds)
601
- !prepared_statements || binds.empty?
602
- end
718
+ def column_for(table_name, column_name)
719
+ column_name = column_name.to_s
720
+ columns(table_name).detect { |c| c.name == column_name } ||
721
+ raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
722
+ end
603
723
 
604
- def column_for(table_name, column_name) # :nodoc:
605
- column_name = column_name.to_s
606
- columns(table_name).detect { |c| c.name == column_name } ||
607
- raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
608
- end
724
+ def column_for_attribute(attribute)
725
+ table_name = attribute.relation.name
726
+ schema_cache.columns_hash(table_name)[attribute.name.to_s]
727
+ end
728
+
729
+ def collector
730
+ if prepared_statements
731
+ Arel::Collectors::Composite.new(
732
+ Arel::Collectors::SQLString.new,
733
+ Arel::Collectors::Bind.new,
734
+ )
735
+ else
736
+ Arel::Collectors::SubstituteBinds.new(
737
+ self,
738
+ Arel::Collectors::SQLString.new,
739
+ )
740
+ end
741
+ end
742
+
743
+ def arel_visitor
744
+ Arel::Visitors::ToSql.new(self)
745
+ end
746
+
747
+ def build_statement_pool
748
+ end
749
+
750
+ # Builds the result object.
751
+ #
752
+ # This is an internal hook to make possible connection adapters to build
753
+ # custom result objects with connection-specific data.
754
+ def build_result(columns:, rows:, column_types: {})
755
+ ActiveRecord::Result.new(columns, rows, column_types)
756
+ end
609
757
  end
610
758
  end
611
759
  end