activerecord 4.2.11.3 → 6.0.0

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