activerecord 5.2.6 → 6.1.3.2

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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1038 -571
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +13 -12
  7. data/lib/active_record/aggregations.rb +9 -8
  8. data/lib/active_record/association_relation.rb +30 -10
  9. data/lib/active_record/associations.rb +137 -25
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +95 -42
  12. data/lib/active_record/associations/association_scope.rb +23 -21
  13. data/lib/active_record/associations/belongs_to_association.rb +54 -46
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  15. data/lib/active_record/associations/builder/association.rb +45 -22
  16. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  17. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  19. data/lib/active_record/associations/builder/has_many.rb +8 -2
  20. data/lib/active_record/associations/builder/has_one.rb +33 -2
  21. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  22. data/lib/active_record/associations/collection_association.rb +31 -29
  23. data/lib/active_record/associations/collection_proxy.rb +25 -21
  24. data/lib/active_record/associations/foreign_association.rb +20 -0
  25. data/lib/active_record/associations/has_many_association.rb +26 -13
  26. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  27. data/lib/active_record/associations/has_one_association.rb +43 -31
  28. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  31. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/preloader/association.rb +71 -43
  34. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  35. data/lib/active_record/associations/singular_association.rb +3 -17
  36. data/lib/active_record/associations/through_association.rb +1 -1
  37. data/lib/active_record/attribute_assignment.rb +17 -19
  38. data/lib/active_record/attribute_methods.rb +81 -143
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  42. data/lib/active_record/attribute_methods/query.rb +4 -8
  43. data/lib/active_record/attribute_methods/read.rb +14 -56
  44. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  46. data/lib/active_record/attribute_methods/write.rb +18 -34
  47. data/lib/active_record/attributes.rb +46 -9
  48. data/lib/active_record/autosave_association.rb +57 -42
  49. data/lib/active_record/base.rb +4 -17
  50. data/lib/active_record/callbacks.rb +158 -43
  51. data/lib/active_record/coders/yaml_column.rb +1 -2
  52. data/lib/active_record/connection_adapters.rb +50 -0
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  58. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  60. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -90
  61. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  63. data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
  64. data/lib/active_record/connection_adapters/abstract_adapter.rb +228 -98
  65. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  66. data/lib/active_record/connection_adapters/column.rb +30 -12
  67. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  68. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  69. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
  71. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  77. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  79. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  80. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
  83. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  99. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  101. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  102. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  103. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  104. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  105. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  106. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  107. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  108. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
  109. data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
  110. data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
  111. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  112. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  113. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  114. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  116. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  117. data/lib/active_record/connection_handling.rb +293 -33
  118. data/lib/active_record/core.rb +323 -97
  119. data/lib/active_record/counter_cache.rb +8 -30
  120. data/lib/active_record/database_configurations.rb +272 -0
  121. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  122. data/lib/active_record/database_configurations/database_config.rb +80 -0
  123. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  124. data/lib/active_record/database_configurations/url_config.rb +53 -0
  125. data/lib/active_record/delegated_type.rb +209 -0
  126. data/lib/active_record/destroy_association_async_job.rb +36 -0
  127. data/lib/active_record/dynamic_matchers.rb +3 -4
  128. data/lib/active_record/enum.rb +111 -37
  129. data/lib/active_record/errors.rb +62 -19
  130. data/lib/active_record/explain.rb +10 -6
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +10 -17
  133. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  134. data/lib/active_record/fixture_set/render_context.rb +17 -0
  135. data/lib/active_record/fixture_set/table_row.rb +152 -0
  136. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  137. data/lib/active_record/fixtures.rb +200 -481
  138. data/lib/active_record/gem_version.rb +4 -4
  139. data/lib/active_record/inheritance.rb +53 -24
  140. data/lib/active_record/insert_all.rb +208 -0
  141. data/lib/active_record/integration.rb +67 -17
  142. data/lib/active_record/internal_metadata.rb +26 -9
  143. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  144. data/lib/active_record/locking/optimistic.rb +37 -23
  145. data/lib/active_record/locking/pessimistic.rb +9 -5
  146. data/lib/active_record/log_subscriber.rb +35 -35
  147. data/lib/active_record/middleware/database_selector.rb +77 -0
  148. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  149. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  150. data/lib/active_record/migration.rb +206 -157
  151. data/lib/active_record/migration/command_recorder.rb +96 -44
  152. data/lib/active_record/migration/compatibility.rb +142 -64
  153. data/lib/active_record/migration/join_table.rb +0 -1
  154. data/lib/active_record/model_schema.rb +148 -22
  155. data/lib/active_record/nested_attributes.rb +4 -7
  156. data/lib/active_record/no_touching.rb +8 -1
  157. data/lib/active_record/null_relation.rb +0 -1
  158. data/lib/active_record/persistence.rb +267 -59
  159. data/lib/active_record/query_cache.rb +21 -4
  160. data/lib/active_record/querying.rb +40 -23
  161. data/lib/active_record/railtie.rb +115 -58
  162. data/lib/active_record/railties/console_sandbox.rb +2 -4
  163. data/lib/active_record/railties/controller_runtime.rb +30 -35
  164. data/lib/active_record/railties/databases.rake +408 -78
  165. data/lib/active_record/readonly_attributes.rb +4 -0
  166. data/lib/active_record/reflection.rb +109 -93
  167. data/lib/active_record/relation.rb +374 -104
  168. data/lib/active_record/relation/batches.rb +44 -35
  169. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  170. data/lib/active_record/relation/calculations.rb +153 -90
  171. data/lib/active_record/relation/delegation.rb +35 -50
  172. data/lib/active_record/relation/finder_methods.rb +64 -39
  173. data/lib/active_record/relation/from_clause.rb +5 -1
  174. data/lib/active_record/relation/merger.rb +32 -40
  175. data/lib/active_record/relation/predicate_builder.rb +62 -45
  176. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  177. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  179. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  180. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  181. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  182. data/lib/active_record/relation/query_attribute.rb +13 -8
  183. data/lib/active_record/relation/query_methods.rb +475 -186
  184. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  185. data/lib/active_record/relation/spawn_methods.rb +9 -9
  186. data/lib/active_record/relation/where_clause.rb +111 -61
  187. data/lib/active_record/result.rb +64 -38
  188. data/lib/active_record/runtime_registry.rb +2 -2
  189. data/lib/active_record/sanitization.rb +22 -41
  190. data/lib/active_record/schema.rb +2 -11
  191. data/lib/active_record/schema_dumper.rb +54 -9
  192. data/lib/active_record/schema_migration.rb +7 -9
  193. data/lib/active_record/scoping.rb +8 -9
  194. data/lib/active_record/scoping/default.rb +4 -6
  195. data/lib/active_record/scoping/named.rb +17 -24
  196. data/lib/active_record/secure_token.rb +16 -8
  197. data/lib/active_record/serialization.rb +5 -3
  198. data/lib/active_record/signed_id.rb +116 -0
  199. data/lib/active_record/statement_cache.rb +49 -6
  200. data/lib/active_record/store.rb +88 -9
  201. data/lib/active_record/suppressor.rb +2 -2
  202. data/lib/active_record/table_metadata.rb +42 -43
  203. data/lib/active_record/tasks/database_tasks.rb +277 -81
  204. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  205. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  206. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  207. data/lib/active_record/test_databases.rb +24 -0
  208. data/lib/active_record/test_fixtures.rb +246 -0
  209. data/lib/active_record/timestamp.rb +43 -32
  210. data/lib/active_record/touch_later.rb +23 -22
  211. data/lib/active_record/transactions.rb +62 -118
  212. data/lib/active_record/translation.rb +1 -1
  213. data/lib/active_record/type.rb +10 -5
  214. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  215. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  216. data/lib/active_record/type/serialized.rb +6 -3
  217. data/lib/active_record/type/time.rb +10 -0
  218. data/lib/active_record/type/type_map.rb +0 -1
  219. data/lib/active_record/type/unsigned_integer.rb +0 -1
  220. data/lib/active_record/type_caster/connection.rb +15 -15
  221. data/lib/active_record/type_caster/map.rb +8 -8
  222. data/lib/active_record/validations.rb +4 -3
  223. data/lib/active_record/validations/associated.rb +1 -2
  224. data/lib/active_record/validations/numericality.rb +35 -0
  225. data/lib/active_record/validations/uniqueness.rb +38 -30
  226. data/lib/arel.rb +54 -0
  227. data/lib/arel/alias_predication.rb +9 -0
  228. data/lib/arel/attributes/attribute.rb +41 -0
  229. data/lib/arel/collectors/bind.rb +29 -0
  230. data/lib/arel/collectors/composite.rb +39 -0
  231. data/lib/arel/collectors/plain_string.rb +20 -0
  232. data/lib/arel/collectors/sql_string.rb +27 -0
  233. data/lib/arel/collectors/substitute_binds.rb +35 -0
  234. data/lib/arel/crud.rb +42 -0
  235. data/lib/arel/delete_manager.rb +18 -0
  236. data/lib/arel/errors.rb +9 -0
  237. data/lib/arel/expressions.rb +29 -0
  238. data/lib/arel/factory_methods.rb +49 -0
  239. data/lib/arel/insert_manager.rb +49 -0
  240. data/lib/arel/math.rb +45 -0
  241. data/lib/arel/nodes.rb +70 -0
  242. data/lib/arel/nodes/and.rb +32 -0
  243. data/lib/arel/nodes/ascending.rb +23 -0
  244. data/lib/arel/nodes/binary.rb +126 -0
  245. data/lib/arel/nodes/bind_param.rb +44 -0
  246. data/lib/arel/nodes/case.rb +55 -0
  247. data/lib/arel/nodes/casted.rb +62 -0
  248. data/lib/arel/nodes/comment.rb +29 -0
  249. data/lib/arel/nodes/count.rb +12 -0
  250. data/lib/arel/nodes/delete_statement.rb +45 -0
  251. data/lib/arel/nodes/descending.rb +23 -0
  252. data/lib/arel/nodes/equality.rb +15 -0
  253. data/lib/arel/nodes/extract.rb +24 -0
  254. data/lib/arel/nodes/false.rb +16 -0
  255. data/lib/arel/nodes/full_outer_join.rb +8 -0
  256. data/lib/arel/nodes/function.rb +44 -0
  257. data/lib/arel/nodes/grouping.rb +11 -0
  258. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  259. data/lib/arel/nodes/in.rb +15 -0
  260. data/lib/arel/nodes/infix_operation.rb +92 -0
  261. data/lib/arel/nodes/inner_join.rb +8 -0
  262. data/lib/arel/nodes/insert_statement.rb +37 -0
  263. data/lib/arel/nodes/join_source.rb +20 -0
  264. data/lib/arel/nodes/matches.rb +18 -0
  265. data/lib/arel/nodes/named_function.rb +23 -0
  266. data/lib/arel/nodes/node.rb +51 -0
  267. data/lib/arel/nodes/node_expression.rb +13 -0
  268. data/lib/arel/nodes/ordering.rb +27 -0
  269. data/lib/arel/nodes/outer_join.rb +8 -0
  270. data/lib/arel/nodes/over.rb +15 -0
  271. data/lib/arel/nodes/regexp.rb +16 -0
  272. data/lib/arel/nodes/right_outer_join.rb +8 -0
  273. data/lib/arel/nodes/select_core.rb +67 -0
  274. data/lib/arel/nodes/select_statement.rb +41 -0
  275. data/lib/arel/nodes/sql_literal.rb +19 -0
  276. data/lib/arel/nodes/string_join.rb +11 -0
  277. data/lib/arel/nodes/table_alias.rb +31 -0
  278. data/lib/arel/nodes/terminal.rb +16 -0
  279. data/lib/arel/nodes/true.rb +16 -0
  280. data/lib/arel/nodes/unary.rb +44 -0
  281. data/lib/arel/nodes/unary_operation.rb +20 -0
  282. data/lib/arel/nodes/unqualified_column.rb +22 -0
  283. data/lib/arel/nodes/update_statement.rb +41 -0
  284. data/lib/arel/nodes/values_list.rb +9 -0
  285. data/lib/arel/nodes/window.rb +126 -0
  286. data/lib/arel/nodes/with.rb +11 -0
  287. data/lib/arel/order_predications.rb +13 -0
  288. data/lib/arel/predications.rb +250 -0
  289. data/lib/arel/select_manager.rb +270 -0
  290. data/lib/arel/table.rb +118 -0
  291. data/lib/arel/tree_manager.rb +72 -0
  292. data/lib/arel/update_manager.rb +34 -0
  293. data/lib/arel/visitors.rb +13 -0
  294. data/lib/arel/visitors/dot.rb +308 -0
  295. data/lib/arel/visitors/mysql.rb +93 -0
  296. data/lib/arel/visitors/postgresql.rb +120 -0
  297. data/lib/arel/visitors/sqlite.rb +38 -0
  298. data/lib/arel/visitors/to_sql.rb +899 -0
  299. data/lib/arel/visitors/visitor.rb +45 -0
  300. data/lib/arel/window_predications.rb +9 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration.rb +19 -2
  303. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  304. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  305. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +119 -34
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -6,28 +6,33 @@ module ActiveRecord
6
6
  class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
7
7
  undef to_yaml if method_defined?(:to_yaml)
8
8
 
9
+ include Deduplicable
10
+
9
11
  attr_reader :extra
10
12
 
11
- def initialize(type_metadata, extra: "")
13
+ def initialize(type_metadata, extra: nil)
12
14
  super(type_metadata)
13
- @type_metadata = type_metadata
14
15
  @extra = extra
15
16
  end
16
17
 
17
18
  def ==(other)
18
- other.is_a?(MySQL::TypeMetadata) &&
19
- attributes_for_hash == other.attributes_for_hash
19
+ other.is_a?(TypeMetadata) &&
20
+ __getobj__ == other.__getobj__ &&
21
+ extra == other.extra
20
22
  end
21
23
  alias eql? ==
22
24
 
23
25
  def hash
24
- attributes_for_hash.hash
26
+ TypeMetadata.hash ^
27
+ __getobj__.hash ^
28
+ extra.hash
25
29
  end
26
30
 
27
- protected
28
-
29
- def attributes_for_hash
30
- [self.class, @type_metadata, extra]
31
+ private
32
+ def deduplicated
33
+ __setobj__(__getobj__.deduplicate)
34
+ @extra = -extra if extra
35
+ super
31
36
  end
32
37
  end
33
38
  end
@@ -3,7 +3,7 @@
3
3
  require "active_record/connection_adapters/abstract_mysql_adapter"
4
4
  require "active_record/connection_adapters/mysql/database_statements"
5
5
 
6
- gem "mysql2", ">= 0.4.4", "< 0.6.0"
6
+ gem "mysql2", "~> 0.5"
7
7
  require "mysql2"
8
8
 
9
9
  module ActiveRecord
@@ -14,36 +14,53 @@ module ActiveRecord
14
14
  config[:flags] ||= 0
15
15
 
16
16
  if config[:flags].kind_of? Array
17
- config[:flags].push "FOUND_ROWS".freeze
17
+ config[:flags].push "FOUND_ROWS"
18
18
  else
19
19
  config[:flags] |= Mysql2::Client::FOUND_ROWS
20
20
  end
21
21
 
22
- client = Mysql2::Client.new(config)
23
- ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
24
- rescue Mysql2::Error => error
25
- if error.message.include?("Unknown database")
26
- raise ActiveRecord::NoDatabaseError
27
- else
28
- raise
29
- end
22
+ ConnectionAdapters::Mysql2Adapter.new(
23
+ ConnectionAdapters::Mysql2Adapter.new_client(config),
24
+ logger,
25
+ nil,
26
+ config,
27
+ )
30
28
  end
31
29
  end
32
30
 
33
31
  module ConnectionAdapters
34
32
  class Mysql2Adapter < AbstractMysqlAdapter
35
- ADAPTER_NAME = "Mysql2".freeze
33
+ ER_BAD_DB_ERROR = 1049
34
+ ADAPTER_NAME = "Mysql2"
36
35
 
37
36
  include MySQL::DatabaseStatements
38
37
 
38
+ class << self
39
+ def new_client(config)
40
+ Mysql2::Client.new(config)
41
+ rescue Mysql2::Error => error
42
+ if error.error_number == ConnectionAdapters::Mysql2Adapter::ER_BAD_DB_ERROR
43
+ raise ActiveRecord::NoDatabaseError
44
+ else
45
+ raise ActiveRecord::ConnectionNotEstablished, error.message
46
+ end
47
+ end
48
+ end
49
+
39
50
  def initialize(connection, logger, connection_options, config)
40
- super
41
- @prepared_statements = false unless config.key?(:prepared_statements)
51
+ superclass_config = config.reverse_merge(prepared_statements: false)
52
+ super(connection, logger, connection_options, superclass_config)
42
53
  configure_connection
43
54
  end
44
55
 
56
+ def self.database_exists?(config)
57
+ !!ActiveRecord::Base.mysql2_connection(config)
58
+ rescue ActiveRecord::NoDatabaseError
59
+ false
60
+ end
61
+
45
62
  def supports_json?
46
- !mariadb? && version >= "5.7.8"
63
+ !mariadb? && database_version >= "5.7.8"
47
64
  end
48
65
 
49
66
  def supports_comments?
@@ -58,6 +75,10 @@ module ActiveRecord
58
75
  true
59
76
  end
60
77
 
78
+ def supports_lazy_transactions?
79
+ true
80
+ end
81
+
61
82
  # HELPER METHODS ===========================================
62
83
 
63
84
  def each_hash(result) # :nodoc:
@@ -80,6 +101,8 @@ module ActiveRecord
80
101
 
81
102
  def quote_string(string)
82
103
  @connection.escape(string)
104
+ rescue Mysql2::Error => error
105
+ raise translate_exception(error, message: error.message, sql: "<escape>", binds: [])
83
106
  end
84
107
 
85
108
  #--
@@ -105,24 +128,36 @@ module ActiveRecord
105
128
  end
106
129
 
107
130
  def discard! # :nodoc:
131
+ super
108
132
  @connection.automatic_close = false
109
133
  @connection = nil
110
134
  end
111
135
 
112
136
  private
113
-
114
137
  def connect
115
- @connection = Mysql2::Client.new(@config)
138
+ @connection = self.class.new_client(@config)
116
139
  configure_connection
117
140
  end
118
141
 
119
142
  def configure_connection
120
- @connection.query_options.merge!(as: :array)
143
+ @connection.query_options[:as] = :array
121
144
  super
122
145
  end
123
146
 
124
147
  def full_version
125
- @full_version ||= @connection.server_info[:version]
148
+ schema_cache.database_version.full_version_string
149
+ end
150
+
151
+ def get_full_version
152
+ @connection.server_info[:version]
153
+ end
154
+
155
+ def translate_exception(exception, message:, sql:, binds:)
156
+ if exception.is_a?(Mysql2::Error::TimeoutError) && !exception.error_number
157
+ ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds)
158
+ else
159
+ super
160
+ end
126
161
  end
127
162
  end
128
163
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class PoolConfig # :nodoc:
6
+ include Mutex_m
7
+
8
+ attr_reader :db_config, :connection_klass
9
+ attr_accessor :schema_cache
10
+
11
+ INSTANCES = ObjectSpace::WeakMap.new
12
+ private_constant :INSTANCES
13
+
14
+ class << self
15
+ def discard_pools!
16
+ INSTANCES.each_key(&:discard_pool!)
17
+ end
18
+ end
19
+
20
+ def initialize(connection_klass, db_config)
21
+ super()
22
+ @connection_klass = connection_klass
23
+ @db_config = db_config
24
+ @pool = nil
25
+ INSTANCES[self] = self
26
+ end
27
+
28
+ def connection_specification_name
29
+ if connection_klass.is_a?(String)
30
+ connection_klass
31
+ elsif connection_klass.primary_class?
32
+ "ActiveRecord::Base"
33
+ else
34
+ connection_klass.name
35
+ end
36
+ end
37
+
38
+ def disconnect!
39
+ ActiveSupport::ForkTracker.check!
40
+
41
+ return unless @pool
42
+
43
+ synchronize do
44
+ return unless @pool
45
+
46
+ @pool.automatic_reconnect = false
47
+ @pool.disconnect!
48
+ end
49
+
50
+ nil
51
+ end
52
+
53
+ def pool
54
+ ActiveSupport::ForkTracker.check!
55
+
56
+ @pool || synchronize { @pool ||= ConnectionAdapters::ConnectionPool.new(self) }
57
+ end
58
+
59
+ def discard_pool!
60
+ return unless @pool
61
+
62
+ synchronize do
63
+ return unless @pool
64
+
65
+ @pool.discard!
66
+ @pool = nil
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ ActiveSupport::ForkTracker.after_fork { ActiveRecord::ConnectionAdapters::PoolConfig.discard_pools! }
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class PoolManager # :nodoc:
6
+ def initialize
7
+ @name_to_role_mapping = Hash.new { |h, k| h[k] = {} }
8
+ end
9
+
10
+ def shard_names
11
+ @name_to_role_mapping.values.flat_map { |shard_map| shard_map.keys }
12
+ end
13
+
14
+ def role_names
15
+ @name_to_role_mapping.keys
16
+ end
17
+
18
+ def pool_configs(role = nil)
19
+ if role
20
+ @name_to_role_mapping[role].values
21
+ else
22
+ @name_to_role_mapping.flat_map { |_, shard_map| shard_map.values }
23
+ end
24
+ end
25
+
26
+ def remove_role(role)
27
+ @name_to_role_mapping.delete(role)
28
+ end
29
+
30
+ def remove_pool_config(role, shard)
31
+ @name_to_role_mapping[role].delete(shard)
32
+ end
33
+
34
+ def get_pool_config(role, shard)
35
+ @name_to_role_mapping[role][shard]
36
+ end
37
+
38
+ def set_pool_config(role, shard, pool_config)
39
+ @name_to_role_mapping[role][shard] = pool_config
40
+ end
41
+ end
42
+ end
43
+ end
@@ -2,43 +2,52 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
- # PostgreSQL-specific extensions to column definitions in a table.
6
- class PostgreSQLColumn < Column #:nodoc:
7
- delegate :array, :oid, :fmod, to: :sql_type_metadata
8
- alias :array? :array
9
-
10
- def initialize(*, max_identifier_length: 63, **)
11
- super
12
- @max_identifier_length = max_identifier_length
13
- end
5
+ module PostgreSQL
6
+ class Column < ConnectionAdapters::Column # :nodoc:
7
+ delegate :oid, :fmod, to: :sql_type_metadata
14
8
 
15
- def serial?
16
- return unless default_function
9
+ def initialize(*, serial: nil, **)
10
+ super
11
+ @serial = serial
12
+ end
17
13
 
18
- if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
19
- sequence_name_from_parts(table_name, name, suffix) == sequence_name
14
+ def serial?
15
+ @serial
20
16
  end
21
- end
22
17
 
23
- protected
24
- attr_reader :max_identifier_length
18
+ def array
19
+ sql_type_metadata.sql_type.end_with?("[]")
20
+ end
21
+ alias :array? :array
22
+
23
+ def sql_type
24
+ super.delete_suffix("[]")
25
+ end
25
26
 
26
- private
27
- def sequence_name_from_parts(table_name, column_name, suffix)
28
- over_length = [table_name, column_name, suffix].map(&:length).sum + 2 - max_identifier_length
27
+ def init_with(coder)
28
+ @serial = coder["serial"]
29
+ super
30
+ end
29
31
 
30
- if over_length > 0
31
- column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
32
- over_length -= column_name.length - column_name_length
33
- column_name = column_name[0, column_name_length - [over_length, 0].min]
34
- end
32
+ def encode_with(coder)
33
+ coder["serial"] = @serial
34
+ super
35
+ end
35
36
 
36
- if over_length > 0
37
- table_name = table_name[0, table_name.length - over_length]
38
- end
37
+ def ==(other)
38
+ other.is_a?(Column) &&
39
+ super &&
40
+ serial? == other.serial?
41
+ end
42
+ alias :eql? :==
39
43
 
40
- "#{table_name}_#{column_name}_#{suffix}"
44
+ def hash
45
+ Column.hash ^
46
+ super.hash ^
47
+ serial?.hash
41
48
  end
49
+ end
42
50
  end
51
+ PostgreSQLColumn = PostgreSQL::Column # :nodoc:
43
52
  end
44
53
  end
@@ -9,67 +9,39 @@ module ActiveRecord
9
9
  PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", binds))
10
10
  end
11
11
 
12
- # The internal PostgreSQL identifier of the money data type.
13
- MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
14
- # The internal PostgreSQL identifier of the BYTEA data type.
15
- BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
16
-
17
- # create a 2D array representing the result set
18
- def result_as_array(res) #:nodoc:
19
- # check if we have any binary column and if they need escaping
20
- ftypes = Array.new(res.nfields) do |i|
21
- [i, res.ftype(i)]
22
- end
23
-
24
- rows = res.values
25
- return rows unless ftypes.any? { |_, x|
26
- x == BYTEA_COLUMN_TYPE_OID || x == MONEY_COLUMN_TYPE_OID
27
- }
28
-
29
- typehash = ftypes.group_by { |_, type| type }
30
- binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
31
- monies = typehash[MONEY_COLUMN_TYPE_OID] || []
32
-
33
- rows.each do |row|
34
- # unescape string passed BYTEA field (OID == 17)
35
- binaries.each do |index, _|
36
- row[index] = unescape_bytea(row[index])
37
- end
38
-
39
- # If this is a money type column and there are any currency symbols,
40
- # then strip them off. Indeed it would be prettier to do this in
41
- # PostgreSQLColumn.string_to_decimal but would break form input
42
- # fields that call value_before_type_cast.
43
- monies.each do |index, _|
44
- data = row[index]
45
- # Because money output is formatted according to the locale, there are two
46
- # cases to consider (note the decimal separators):
47
- # (1) $12,345,678.12
48
- # (2) $12.345.678,12
49
- case data
50
- when /^-?\D+[\d,]+\.\d{2}$/ # (1)
51
- data.gsub!(/[^-\d.]/, "")
52
- when /^-?\D+[\d.]+,\d{2}$/ # (2)
53
- data.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
54
- end
55
- end
56
- end
57
- end
58
-
59
12
  # Queries the database and returns the results in an Array-like object
60
13
  def query(sql, name = nil) #:nodoc:
14
+ materialize_transactions
15
+ mark_transaction_written_if_write(sql)
16
+
61
17
  log(sql, name) do
62
18
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
63
- result_as_array @connection.async_exec(sql)
19
+ @connection.async_exec(sql).map_types!(@type_map_for_results).values
64
20
  end
65
21
  end
66
22
  end
67
23
 
24
+ READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
25
+ :close, :declare, :fetch, :move, :set, :show
26
+ ) # :nodoc:
27
+ private_constant :READ_QUERY
28
+
29
+ def write_query?(sql) # :nodoc:
30
+ !READ_QUERY.match?(sql)
31
+ end
32
+
68
33
  # Executes an SQL statement, returning a PG::Result object on success
69
34
  # or raising a PG::Error exception otherwise.
70
35
  # Note: the PG::Result object is manually memory managed; if you don't
71
36
  # need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
72
37
  def execute(sql, name = nil)
38
+ if preventing_writes? && write_query?(sql)
39
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
40
+ end
41
+
42
+ materialize_transactions
43
+ mark_transaction_written_if_write(sql)
44
+
73
45
  log(sql, name) do
74
46
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
75
47
  @connection.async_exec(sql)
@@ -84,9 +56,13 @@ module ActiveRecord
84
56
  fields.each_with_index do |fname, i|
85
57
  ftype = result.ftype i
86
58
  fmod = result.fmod i
87
- types[fname] = get_oid_type(ftype, fmod, fname)
59
+ case type = get_oid_type(ftype, fmod, fname)
60
+ when Type::Integer, Type::Float, OID::Decimal, Type::String, Type::DateTime, Type::Boolean
61
+ # skip if a column has already been type casted by pg decoders
62
+ else types[fname] = type
63
+ end
88
64
  end
89
- ActiveRecord::Result.new(fields, result.values, types)
65
+ build_result(columns: fields, rows: result.values, column_types: types)
90
66
  end
91
67
  end
92
68
 
@@ -95,7 +71,7 @@ module ActiveRecord
95
71
  end
96
72
  alias :exec_update :exec_delete
97
73
 
98
- def sql_for_insert(sql, pk, id_value, sequence_name, binds) # :nodoc:
74
+ def sql_for_insert(sql, pk, binds) # :nodoc:
99
75
  if pk.nil?
100
76
  # Extract the table from the insert sql. Yuck.
101
77
  table_ref = extract_table_ref_from_insert_sql(sql)
@@ -130,7 +106,7 @@ module ActiveRecord
130
106
 
131
107
  # Begins a transaction.
132
108
  def begin_db_transaction
133
- execute "BEGIN"
109
+ execute("BEGIN", "TRANSACTION")
134
110
  end
135
111
 
136
112
  def begin_isolated_db_transaction(isolation)
@@ -140,15 +116,23 @@ module ActiveRecord
140
116
 
141
117
  # Commits a transaction.
142
118
  def commit_db_transaction
143
- execute "COMMIT"
119
+ execute("COMMIT", "TRANSACTION")
144
120
  end
145
121
 
146
122
  # Aborts a transaction.
147
123
  def exec_rollback_db_transaction
148
- execute "ROLLBACK"
124
+ execute("ROLLBACK", "TRANSACTION")
149
125
  end
150
126
 
151
127
  private
128
+ def execute_batch(statements, name = nil)
129
+ execute(combine_multi_statements(statements))
130
+ end
131
+
132
+ def build_truncate_statements(table_names)
133
+ ["TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"]
134
+ end
135
+
152
136
  # Returns the current ID of a table's sequence.
153
137
  def last_insert_id_result(sequence_name)
154
138
  exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")