activerecord 7.0.8.6 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +631 -1939
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +29 -29
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +16 -13
  7. data/lib/active_record/association_relation.rb +2 -2
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +35 -12
  10. data/lib/active_record/associations/association_scope.rb +16 -9
  11. data/lib/active_record/associations/belongs_to_association.rb +23 -8
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  13. data/lib/active_record/associations/builder/association.rb +3 -3
  14. data/lib/active_record/associations/builder/belongs_to.rb +22 -8
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  16. data/lib/active_record/associations/builder/has_many.rb +3 -4
  17. data/lib/active_record/associations/builder/has_one.rb +3 -4
  18. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  19. data/lib/active_record/associations/collection_association.rb +26 -14
  20. data/lib/active_record/associations/collection_proxy.rb +29 -11
  21. data/lib/active_record/associations/errors.rb +265 -0
  22. data/lib/active_record/associations/foreign_association.rb +10 -3
  23. data/lib/active_record/associations/has_many_association.rb +21 -14
  24. data/lib/active_record/associations/has_many_through_association.rb +17 -7
  25. data/lib/active_record/associations/has_one_association.rb +10 -3
  26. data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
  27. data/lib/active_record/associations/join_dependency.rb +10 -10
  28. data/lib/active_record/associations/nested_error.rb +47 -0
  29. data/lib/active_record/associations/preloader/association.rb +33 -8
  30. data/lib/active_record/associations/preloader/branch.rb +7 -1
  31. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  32. data/lib/active_record/associations/preloader.rb +13 -10
  33. data/lib/active_record/associations/singular_association.rb +7 -1
  34. data/lib/active_record/associations/through_association.rb +22 -11
  35. data/lib/active_record/associations.rb +354 -485
  36. data/lib/active_record/attribute_assignment.rb +0 -4
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  38. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  39. data/lib/active_record/attribute_methods/dirty.rb +53 -35
  40. data/lib/active_record/attribute_methods/primary_key.rb +45 -25
  41. data/lib/active_record/attribute_methods/query.rb +28 -16
  42. data/lib/active_record/attribute_methods/read.rb +8 -7
  43. data/lib/active_record/attribute_methods/serialization.rb +131 -32
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
  45. data/lib/active_record/attribute_methods/write.rb +6 -6
  46. data/lib/active_record/attribute_methods.rb +148 -33
  47. data/lib/active_record/attributes.rb +64 -50
  48. data/lib/active_record/autosave_association.rb +69 -37
  49. data/lib/active_record/base.rb +9 -5
  50. data/lib/active_record/callbacks.rb +11 -25
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -42
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +323 -88
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +217 -63
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +307 -129
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +278 -125
  69. data/lib/active_record/connection_adapters/column.rb +9 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -10
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  87. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  89. data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
  90. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
  91. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  92. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
  93. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
  94. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +370 -63
  95. data/lib/active_record/connection_adapters/postgresql_adapter.rb +367 -201
  96. data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
  97. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  98. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
  99. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
  100. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  101. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
  102. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  103. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
  104. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
  105. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  106. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  107. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  108. data/lib/active_record/connection_adapters.rb +124 -1
  109. data/lib/active_record/connection_handling.rb +96 -104
  110. data/lib/active_record/core.rb +251 -176
  111. data/lib/active_record/counter_cache.rb +68 -34
  112. data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
  113. data/lib/active_record/database_configurations/database_config.rb +26 -5
  114. data/lib/active_record/database_configurations/hash_config.rb +52 -34
  115. data/lib/active_record/database_configurations/url_config.rb +37 -12
  116. data/lib/active_record/database_configurations.rb +87 -34
  117. data/lib/active_record/delegated_type.rb +39 -10
  118. data/lib/active_record/deprecator.rb +7 -0
  119. data/lib/active_record/destroy_association_async_job.rb +3 -1
  120. data/lib/active_record/dynamic_matchers.rb +2 -2
  121. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  122. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  123. data/lib/active_record/encryption/config.rb +25 -1
  124. data/lib/active_record/encryption/configurable.rb +12 -19
  125. data/lib/active_record/encryption/context.rb +10 -3
  126. data/lib/active_record/encryption/contexts.rb +5 -1
  127. data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
  128. data/lib/active_record/encryption/encryptable_record.rb +45 -21
  129. data/lib/active_record/encryption/encrypted_attribute_type.rb +47 -12
  130. data/lib/active_record/encryption/encryptor.rb +18 -3
  131. data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
  132. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
  133. data/lib/active_record/encryption/key_generator.rb +12 -1
  134. data/lib/active_record/encryption/key_provider.rb +1 -1
  135. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  136. data/lib/active_record/encryption/message_serializer.rb +6 -0
  137. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  138. data/lib/active_record/encryption/properties.rb +3 -3
  139. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  140. data/lib/active_record/encryption/scheme.rb +22 -21
  141. data/lib/active_record/encryption.rb +3 -0
  142. data/lib/active_record/enum.rb +129 -28
  143. data/lib/active_record/errors.rb +151 -31
  144. data/lib/active_record/explain.rb +21 -12
  145. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  146. data/lib/active_record/fixture_set/render_context.rb +2 -0
  147. data/lib/active_record/fixture_set/table_row.rb +29 -8
  148. data/lib/active_record/fixtures.rb +167 -97
  149. data/lib/active_record/future_result.rb +47 -8
  150. data/lib/active_record/gem_version.rb +4 -4
  151. data/lib/active_record/inheritance.rb +34 -18
  152. data/lib/active_record/insert_all.rb +72 -22
  153. data/lib/active_record/integration.rb +11 -8
  154. data/lib/active_record/internal_metadata.rb +124 -20
  155. data/lib/active_record/locking/optimistic.rb +8 -7
  156. data/lib/active_record/locking/pessimistic.rb +5 -2
  157. data/lib/active_record/log_subscriber.rb +18 -22
  158. data/lib/active_record/marshalling.rb +59 -0
  159. data/lib/active_record/message_pack.rb +124 -0
  160. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  161. data/lib/active_record/middleware/database_selector.rb +6 -8
  162. data/lib/active_record/middleware/shard_selector.rb +3 -1
  163. data/lib/active_record/migration/command_recorder.rb +106 -8
  164. data/lib/active_record/migration/compatibility.rb +147 -5
  165. data/lib/active_record/migration/default_strategy.rb +22 -0
  166. data/lib/active_record/migration/execution_strategy.rb +19 -0
  167. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  168. data/lib/active_record/migration.rb +234 -117
  169. data/lib/active_record/model_schema.rb +90 -102
  170. data/lib/active_record/nested_attributes.rb +48 -11
  171. data/lib/active_record/normalization.rb +163 -0
  172. data/lib/active_record/persistence.rb +168 -339
  173. data/lib/active_record/promise.rb +84 -0
  174. data/lib/active_record/query_cache.rb +18 -25
  175. data/lib/active_record/query_logs.rb +92 -52
  176. data/lib/active_record/query_logs_formatter.rb +41 -0
  177. data/lib/active_record/querying.rb +33 -8
  178. data/lib/active_record/railtie.rb +129 -85
  179. data/lib/active_record/railties/controller_runtime.rb +22 -7
  180. data/lib/active_record/railties/databases.rake +145 -154
  181. data/lib/active_record/railties/job_runtime.rb +23 -0
  182. data/lib/active_record/readonly_attributes.rb +32 -5
  183. data/lib/active_record/reflection.rb +267 -69
  184. data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
  185. data/lib/active_record/relation/batches.rb +198 -63
  186. data/lib/active_record/relation/calculations.rb +250 -93
  187. data/lib/active_record/relation/delegation.rb +30 -19
  188. data/lib/active_record/relation/finder_methods.rb +93 -18
  189. data/lib/active_record/relation/merger.rb +6 -6
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  193. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  194. data/lib/active_record/relation/predicate_builder.rb +28 -16
  195. data/lib/active_record/relation/query_attribute.rb +2 -1
  196. data/lib/active_record/relation/query_methods.rb +576 -107
  197. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  198. data/lib/active_record/relation/spawn_methods.rb +5 -4
  199. data/lib/active_record/relation/where_clause.rb +7 -19
  200. data/lib/active_record/relation.rb +580 -90
  201. data/lib/active_record/result.rb +49 -48
  202. data/lib/active_record/runtime_registry.rb +63 -1
  203. data/lib/active_record/sanitization.rb +70 -25
  204. data/lib/active_record/schema.rb +8 -7
  205. data/lib/active_record/schema_dumper.rb +63 -14
  206. data/lib/active_record/schema_migration.rb +75 -24
  207. data/lib/active_record/scoping/default.rb +15 -5
  208. data/lib/active_record/scoping/named.rb +3 -2
  209. data/lib/active_record/scoping.rb +2 -1
  210. data/lib/active_record/secure_password.rb +60 -0
  211. data/lib/active_record/secure_token.rb +21 -3
  212. data/lib/active_record/signed_id.rb +27 -6
  213. data/lib/active_record/statement_cache.rb +7 -7
  214. data/lib/active_record/store.rb +8 -8
  215. data/lib/active_record/suppressor.rb +3 -1
  216. data/lib/active_record/table_metadata.rb +1 -1
  217. data/lib/active_record/tasks/database_tasks.rb +190 -118
  218. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  219. data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
  220. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  221. data/lib/active_record/test_fixtures.rb +170 -155
  222. data/lib/active_record/testing/query_assertions.rb +121 -0
  223. data/lib/active_record/timestamp.rb +31 -17
  224. data/lib/active_record/token_for.rb +123 -0
  225. data/lib/active_record/touch_later.rb +12 -7
  226. data/lib/active_record/transaction.rb +132 -0
  227. data/lib/active_record/transactions.rb +106 -24
  228. data/lib/active_record/translation.rb +0 -2
  229. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  230. data/lib/active_record/type/internal/timezone.rb +7 -2
  231. data/lib/active_record/type/serialized.rb +1 -3
  232. data/lib/active_record/type/time.rb +4 -0
  233. data/lib/active_record/type_caster/connection.rb +4 -4
  234. data/lib/active_record/validations/absence.rb +1 -1
  235. data/lib/active_record/validations/associated.rb +9 -3
  236. data/lib/active_record/validations/numericality.rb +5 -4
  237. data/lib/active_record/validations/presence.rb +5 -28
  238. data/lib/active_record/validations/uniqueness.rb +61 -11
  239. data/lib/active_record/validations.rb +12 -5
  240. data/lib/active_record/version.rb +1 -1
  241. data/lib/active_record.rb +247 -33
  242. data/lib/arel/alias_predication.rb +1 -1
  243. data/lib/arel/collectors/bind.rb +2 -0
  244. data/lib/arel/collectors/composite.rb +7 -0
  245. data/lib/arel/collectors/sql_string.rb +1 -1
  246. data/lib/arel/collectors/substitute_binds.rb +1 -1
  247. data/lib/arel/errors.rb +10 -0
  248. data/lib/arel/factory_methods.rb +4 -0
  249. data/lib/arel/nodes/binary.rb +6 -7
  250. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  251. data/lib/arel/nodes/cte.rb +36 -0
  252. data/lib/arel/nodes/fragments.rb +35 -0
  253. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  254. data/lib/arel/nodes/leading_join.rb +8 -0
  255. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  256. data/lib/arel/nodes/node.rb +115 -5
  257. data/lib/arel/nodes/sql_literal.rb +13 -0
  258. data/lib/arel/nodes/table_alias.rb +4 -0
  259. data/lib/arel/nodes.rb +6 -2
  260. data/lib/arel/predications.rb +3 -1
  261. data/lib/arel/select_manager.rb +1 -1
  262. data/lib/arel/table.rb +9 -5
  263. data/lib/arel/tree_manager.rb +8 -3
  264. data/lib/arel/update_manager.rb +2 -1
  265. data/lib/arel/visitors/dot.rb +1 -0
  266. data/lib/arel/visitors/mysql.rb +17 -5
  267. data/lib/arel/visitors/postgresql.rb +1 -12
  268. data/lib/arel/visitors/sqlite.rb +25 -0
  269. data/lib/arel/visitors/to_sql.rb +112 -34
  270. data/lib/arel/visitors/visitor.rb +2 -2
  271. data/lib/arel.rb +21 -3
  272. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  273. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  274. data/lib/rails/generators/active_record/migration.rb +3 -1
  275. data/lib/rails/generators/active_record/model/USAGE +113 -0
  276. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  277. metadata +56 -14
  278. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  279. data/lib/active_record/null_relation.rb +0 -63
@@ -4,6 +4,7 @@ require "set"
4
4
  require "active_record/connection_adapters/sql_type_metadata"
5
5
  require "active_record/connection_adapters/abstract/schema_dumper"
6
6
  require "active_record/connection_adapters/abstract/schema_creation"
7
+ require "active_support/concurrency/null_lock"
7
8
  require "active_support/concurrency/load_interlock_aware_monitor"
8
9
  require "arel/collectors/bind"
9
10
  require "arel/collectors/composite"
@@ -12,6 +13,8 @@ require "arel/collectors/substitute_binds"
12
13
 
13
14
  module ActiveRecord
14
15
  module ConnectionAdapters # :nodoc:
16
+ # = Active Record Abstract Adapter
17
+ #
15
18
  # Active Record supports multiple database systems. AbstractAdapter and
16
19
  # related classes form the abstraction layer which makes this possible.
17
20
  # An AbstractAdapter represents a connection to a database, and provides an
@@ -20,7 +23,7 @@ module ActiveRecord
20
23
  # and +:limit+ options, etc.
21
24
  #
22
25
  # All the concrete database adapters follow the interface laid down in this class.
23
- # {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling#connection] returns an AbstractAdapter object, which
26
+ # {ActiveRecord::Base.lease_connection}[rdoc-ref:ConnectionHandling#lease_connection] returns an AbstractAdapter object, which
24
27
  # you can use.
25
28
  #
26
29
  # Most of the methods in the adapter are useful during migrations. Most
@@ -36,12 +39,18 @@ module ActiveRecord
36
39
  include Savepoints
37
40
 
38
41
  SIMPLE_INT = /\A\d+\z/
39
- COMMENT_REGEX = %r{(?:--.*\n)|/\*(?:[^*]|\*[^/])*\*/}m
42
+ COMMENT_REGEX = %r{(?:--.*\n)|/\*(?:[^*]|\*[^/])*\*/}
40
43
 
41
- attr_accessor :pool
44
+ attr_reader :pool
42
45
  attr_reader :visitor, :owner, :logger, :lock
43
46
  alias :in_use? :owner
44
47
 
48
+ def pool=(value)
49
+ return if value.eql?(@pool)
50
+ @schema_cache = nil
51
+ @pool = value
52
+ end
53
+
45
54
  set_callback :checkin, :after, :enable_lazy_transactions!
46
55
 
47
56
  def self.type_cast_config_to_integer(config)
@@ -62,6 +71,16 @@ module ActiveRecord
62
71
  end
63
72
  end
64
73
 
74
+ def self.validate_default_timezone(config)
75
+ case config
76
+ when nil
77
+ when "utc", "local"
78
+ config.to_sym
79
+ else
80
+ raise ArgumentError, "default_timezone must be either 'utc' or 'local'"
81
+ end
82
+ end
83
+
65
84
  DEFAULT_READ_QUERY = [:begin, :commit, :explain, :release, :rollback, :savepoint, :select, :with] # :nodoc:
66
85
  private_constant :DEFAULT_READ_QUERY
67
86
 
@@ -71,27 +90,105 @@ module ActiveRecord
71
90
  /\A(?:[(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
72
91
  end
73
92
 
74
- def initialize(connection, logger = nil, config = {}) # :nodoc:
93
+ def self.find_cmd_and_exec(commands, *args) # :doc:
94
+ commands = Array(commands)
95
+
96
+ dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR)
97
+ unless (ext = RbConfig::CONFIG["EXEEXT"]).empty?
98
+ commands = commands.map { |cmd| "#{cmd}#{ext}" }
99
+ end
100
+
101
+ full_path_command = nil
102
+ found = commands.detect do |cmd|
103
+ dirs_on_path.detect do |path|
104
+ full_path_command = File.join(path, cmd)
105
+ begin
106
+ stat = File.stat(full_path_command)
107
+ rescue SystemCallError
108
+ else
109
+ stat.file? && stat.executable?
110
+ end
111
+ end
112
+ end
113
+
114
+ if found
115
+ exec full_path_command, *args
116
+ else
117
+ abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
118
+ end
119
+ end
120
+
121
+ # Opens a database console session.
122
+ def self.dbconsole(config, options = {})
123
+ raise NotImplementedError
124
+ end
125
+
126
+ def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
75
127
  super()
76
128
 
77
- @connection = connection
78
- @owner = nil
79
- @instrumenter = ActiveSupport::Notifications.instrumenter
80
- @logger = logger
81
- @config = config
82
- @pool = ActiveRecord::ConnectionAdapters::NullPool.new
83
- @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
129
+ @raw_connection = nil
130
+ @unconfigured_connection = nil
131
+
132
+ if config_or_deprecated_connection.is_a?(Hash)
133
+ @config = config_or_deprecated_connection.symbolize_keys
134
+ @logger = ActiveRecord::Base.logger
135
+
136
+ if deprecated_logger || deprecated_connection_options || deprecated_config
137
+ raise ArgumentError, "when initializing an Active Record adapter with a config hash, that should be the only argument"
138
+ end
139
+ else
140
+ # Soft-deprecated for now; we'll probably warn in future.
141
+
142
+ @unconfigured_connection = config_or_deprecated_connection
143
+ @logger = deprecated_logger || ActiveRecord::Base.logger
144
+ if deprecated_config
145
+ @config = (deprecated_config || {}).symbolize_keys
146
+ @connection_parameters = deprecated_connection_options
147
+ else
148
+ @config = (deprecated_connection_options || {}).symbolize_keys
149
+ @connection_parameters = nil
150
+ end
151
+ end
152
+
153
+ @owner = nil
154
+ @instrumenter = ActiveSupport::Notifications.instrumenter
155
+ @pool = ActiveRecord::ConnectionAdapters::NullPool.new
156
+ @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
84
157
  @visitor = arel_visitor
85
158
  @statements = build_statement_pool
86
- @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
159
+ self.lock_thread = nil
87
160
 
88
- @prepared_statements = self.class.type_cast_config_to_boolean(
89
- config.fetch(:prepared_statements, true)
161
+ @prepared_statements = !ActiveRecord.disable_prepared_statements && self.class.type_cast_config_to_boolean(
162
+ @config.fetch(:prepared_statements) { default_prepared_statements }
90
163
  )
91
164
 
92
165
  @advisory_locks_enabled = self.class.type_cast_config_to_boolean(
93
- config.fetch(:advisory_locks, true)
166
+ @config.fetch(:advisory_locks, true)
94
167
  )
168
+
169
+ @default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
170
+
171
+ @raw_connection_dirty = false
172
+ @verified = false
173
+ end
174
+
175
+ def inspect # :nodoc:
176
+ name_field = " name=#{pool.db_config.name.inspect}" unless pool.db_config.name == "primary"
177
+ shard_field = " shard=#{shard.inspect}" unless shard == :default
178
+
179
+ "#<#{self.class.name}:#{'%#016x' % (object_id << 1)} env_name=#{pool.db_config.env_name.inspect}#{name_field} role=#{role.inspect}#{shard_field}>"
180
+ end
181
+
182
+ def lock_thread=(lock_thread) # :nodoc:
183
+ @lock =
184
+ case lock_thread
185
+ when Thread
186
+ ActiveSupport::Concurrency::ThreadLoadInterlockAwareMonitor.new
187
+ when Fiber
188
+ ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
189
+ else
190
+ ActiveSupport::Concurrency::NullLock
191
+ end
95
192
  end
96
193
 
97
194
  EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
@@ -117,53 +214,33 @@ module ActiveRecord
117
214
  @config[:replica] || false
118
215
  end
119
216
 
120
- def use_metadata_table?
121
- @config.fetch(:use_metadata_table, true)
217
+ def connection_retries
218
+ (@config[:connection_retries] || 1).to_i
219
+ end
220
+
221
+ def retry_deadline
222
+ if @config[:retry_deadline]
223
+ @config[:retry_deadline].to_f
224
+ else
225
+ nil
226
+ end
227
+ end
228
+
229
+ def default_timezone
230
+ @default_timezone || ActiveRecord.default_timezone
122
231
  end
123
232
 
124
233
  # Determines whether writes are currently being prevented.
125
234
  #
126
- # Returns true if the connection is a replica.
127
- #
128
- # If the application is using legacy handling, returns
129
- # true if +connection_handler.prevent_writes+ is set.
130
- #
131
- # If the application is using the new connection handling
132
- # will return true based on +current_preventing_writes+.
235
+ # Returns true if the connection is a replica or returns
236
+ # the value of +current_preventing_writes+.
133
237
  def preventing_writes?
134
238
  return true if replica?
135
- return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
136
239
  return false if connection_class.nil?
137
240
 
138
241
  connection_class.current_preventing_writes
139
242
  end
140
243
 
141
- def migrations_paths # :nodoc:
142
- @config[:migrations_paths] || Migrator.migrations_paths
143
- end
144
-
145
- def migration_context # :nodoc:
146
- MigrationContext.new(migrations_paths, schema_migration)
147
- end
148
-
149
- def schema_migration # :nodoc:
150
- @schema_migration ||= begin
151
- conn = self
152
- spec_name = conn.pool.pool_config.connection_specification_name
153
-
154
- return ActiveRecord::SchemaMigration if spec_name == "ActiveRecord::Base"
155
-
156
- schema_migration_name = "#{spec_name}::SchemaMigration"
157
-
158
- Class.new(ActiveRecord::SchemaMigration) do
159
- define_singleton_method(:name) { schema_migration_name }
160
- define_singleton_method(:to_s) { schema_migration_name }
161
-
162
- self.connection_specification_name = spec_name
163
- end
164
- end
165
- end
166
-
167
244
  def prepared_statements?
168
245
  @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
169
246
  end
@@ -200,16 +277,16 @@ module ActiveRecord
200
277
  def lease
201
278
  if in_use?
202
279
  msg = +"Cannot lease connection, "
203
- if @owner == Thread.current
280
+ if @owner == ActiveSupport::IsolatedExecutionState.context
204
281
  msg << "it is already leased by the current thread."
205
282
  else
206
283
  msg << "it is already in use by a different thread: #{@owner}. " \
207
- "Current thread: #{Thread.current}."
284
+ "Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
208
285
  end
209
286
  raise ActiveRecordError, msg
210
287
  end
211
288
 
212
- @owner = Thread.current
289
+ @owner = ActiveSupport::IsolatedExecutionState.context
213
290
  end
214
291
 
215
292
  def connection_class # :nodoc:
@@ -229,21 +306,16 @@ module ActiveRecord
229
306
  end
230
307
 
231
308
  def schema_cache
232
- @pool.get_schema_cache(self)
233
- end
234
-
235
- def schema_cache=(cache)
236
- cache.connection = self
237
- @pool.set_schema_cache(cache)
309
+ @pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
238
310
  end
239
311
 
240
312
  # this method must only be called while holding connection pool's mutex
241
313
  def expire
242
314
  if in_use?
243
- if @owner != Thread.current
315
+ if @owner != ActiveSupport::IsolatedExecutionState.context
244
316
  raise ActiveRecordError, "Cannot expire connection, " \
245
317
  "it is owned by a different thread: #{@owner}. " \
246
- "Current thread: #{Thread.current}."
318
+ "Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
247
319
  end
248
320
 
249
321
  @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@@ -256,10 +328,10 @@ module ActiveRecord
256
328
  # this method must only be called while holding connection pool's mutex (and a desire for segfaults)
257
329
  def steal! # :nodoc:
258
330
  if in_use?
259
- if @owner != Thread.current
331
+ if @owner != ActiveSupport::IsolatedExecutionState.context
260
332
  pool.send :remove_connection_from_thread_cache, self, @owner
261
333
 
262
- @owner = Thread.current
334
+ @owner = ActiveSupport::IsolatedExecutionState.context
263
335
  end
264
336
  else
265
337
  raise ActiveRecordError, "Cannot steal connection, it is not currently leased."
@@ -287,7 +359,14 @@ module ActiveRecord
287
359
 
288
360
  # Does the database for this adapter exist?
289
361
  def self.database_exists?(config)
290
- raise NotImplementedError
362
+ new(config).database_exists?
363
+ end
364
+
365
+ def database_exists?
366
+ connect!
367
+ true
368
+ rescue ActiveRecord::NoDatabaseError
369
+ false
291
370
  end
292
371
 
293
372
  # Does this adapter support DDL rollbacks in transactions? That is, would
@@ -305,6 +384,16 @@ module ActiveRecord
305
384
  false
306
385
  end
307
386
 
387
+ # Do TransactionRollbackErrors on savepoints affect the parent
388
+ # transaction?
389
+ def savepoint_errors_invalidate_transactions?
390
+ false
391
+ end
392
+
393
+ def supports_restart_db_transaction?
394
+ false
395
+ end
396
+
308
397
  # Does this adapter support application-enforced advisory locking?
309
398
  def supports_advisory_locks?
310
399
  false
@@ -331,6 +420,11 @@ module ActiveRecord
331
420
  false
332
421
  end
333
422
 
423
+ # Does this adapter support including non-key columns?
424
+ def supports_index_include?
425
+ false
426
+ end
427
+
334
428
  # Does this adapter support expression indices?
335
429
  def supports_expression_index?
336
430
  false
@@ -377,6 +471,16 @@ module ActiveRecord
377
471
  false
378
472
  end
379
473
 
474
+ # Does this adapter support creating exclusion constraints?
475
+ def supports_exclusion_constraints?
476
+ false
477
+ end
478
+
479
+ # Does this adapter support creating unique constraints?
480
+ def supports_unique_constraints?
481
+ false
482
+ end
483
+
380
484
  # Does this adapter support views?
381
485
  def supports_views?
382
486
  false
@@ -392,7 +496,7 @@ module ActiveRecord
392
496
  false
393
497
  end
394
498
 
395
- # Does this adapter support json data type?
499
+ # Does this adapter support JSON data type?
396
500
  def supports_json?
397
501
  false
398
502
  end
@@ -450,23 +554,47 @@ module ActiveRecord
450
554
  true
451
555
  end
452
556
 
557
+ def supports_nulls_not_distinct?
558
+ false
559
+ end
560
+
561
+ def return_value_after_insert?(column) # :nodoc:
562
+ column.auto_populated?
563
+ end
564
+
453
565
  def async_enabled? # :nodoc:
454
566
  supports_concurrent_connections? &&
455
567
  !ActiveRecord.async_query_executor.nil? && !pool.async_executor.nil?
456
568
  end
457
569
 
458
570
  # This is meant to be implemented by the adapters that support extensions
459
- def disable_extension(name)
571
+ def disable_extension(name, **)
460
572
  end
461
573
 
462
574
  # This is meant to be implemented by the adapters that support extensions
463
- def enable_extension(name)
575
+ def enable_extension(name, **)
464
576
  end
465
577
 
466
578
  # This is meant to be implemented by the adapters that support custom enum types
467
579
  def create_enum(*) # :nodoc:
468
580
  end
469
581
 
582
+ # This is meant to be implemented by the adapters that support custom enum types
583
+ def drop_enum(*) # :nodoc:
584
+ end
585
+
586
+ # This is meant to be implemented by the adapters that support custom enum types
587
+ def rename_enum(*) # :nodoc:
588
+ end
589
+
590
+ # This is meant to be implemented by the adapters that support custom enum types
591
+ def add_enum_value(*) # :nodoc:
592
+ end
593
+
594
+ # This is meant to be implemented by the adapters that support custom enum types
595
+ def rename_enum_value(*) # :nodoc:
596
+ end
597
+
470
598
  def advisory_locks_enabled? # :nodoc:
471
599
  supports_advisory_locks? && @advisory_locks_enabled
472
600
  end
@@ -503,31 +631,71 @@ module ActiveRecord
503
631
  end
504
632
 
505
633
  # Override to check all foreign key constraints in a database.
506
- def all_foreign_keys_valid?
507
- true
634
+ # The adapter should raise a +ActiveRecord::StatementInvalid+ if foreign key
635
+ # constraints are not met.
636
+ def check_all_foreign_keys_valid!
508
637
  end
509
638
 
510
639
  # CONNECTION MANAGEMENT ====================================
511
640
 
641
+ # Checks whether the connection to the database was established. This doesn't
642
+ # include checking whether the database is actually capable of responding, i.e.
643
+ # whether the connection is stale.
644
+ def connected?
645
+ !@raw_connection.nil?
646
+ end
647
+
512
648
  # Checks whether the connection to the database is still active. This includes
513
649
  # checking whether the database is actually capable of responding, i.e. whether
514
650
  # the connection isn't stale.
515
651
  def active?
516
652
  end
517
653
 
518
- # Disconnects from the database if already connected, and establishes a
519
- # new connection with the database. Implementors should call super if they
520
- # override the default implementation.
521
- def reconnect!
522
- clear_cache!
523
- reset_transaction
654
+ # Disconnects from the database if already connected, and establishes a new
655
+ # connection with the database. Implementors should define private #reconnect
656
+ # instead.
657
+ def reconnect!(restore_transactions: false)
658
+ retries_available = connection_retries
659
+ deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
660
+
661
+ @lock.synchronize do
662
+ reconnect
663
+
664
+ enable_lazy_transactions!
665
+ @raw_connection_dirty = false
666
+ @verified = true
667
+
668
+ reset_transaction(restore: restore_transactions) do
669
+ clear_cache!(new_connection: true)
670
+ configure_connection
671
+ end
672
+ rescue => original_exception
673
+ translated_exception = translate_exception_class(original_exception, nil, nil)
674
+ retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
675
+
676
+ if !retry_deadline_exceeded && retries_available > 0
677
+ retries_available -= 1
678
+
679
+ if retryable_connection_error?(translated_exception)
680
+ backoff(connection_retries - retries_available)
681
+ retry
682
+ end
683
+ end
684
+
685
+ @verified = false
686
+
687
+ raise translated_exception
688
+ end
524
689
  end
525
690
 
526
691
  # Disconnects from the database if already connected. Otherwise, this
527
692
  # method does nothing.
528
693
  def disconnect!
529
- clear_cache!
530
- reset_transaction
694
+ @lock.synchronize do
695
+ clear_cache!(new_connection: true)
696
+ reset_transaction
697
+ @raw_connection_dirty = false
698
+ end
531
699
  end
532
700
 
533
701
  # Immediately forget this connection ever existed. Unlike disconnect!,
@@ -538,22 +706,20 @@ module ActiveRecord
538
706
  # rid of a connection that belonged to its parent.
539
707
  def discard!
540
708
  # This should be overridden by concrete adapters.
541
- #
542
- # Prevent @connection's finalizer from touching the socket, or
543
- # otherwise communicating with its server, when it is collected.
544
- if schema_cache.connection == self
545
- schema_cache.connection = nil
546
- end
547
709
  end
548
710
 
549
711
  # Reset the state of this connection, directing the DBMS to clear
550
712
  # transactions and other connection-related server-side state. Usually a
551
713
  # database-dependent operation.
552
714
  #
553
- # The default implementation does nothing; the implementation should be
554
- # overridden by concrete adapters.
715
+ # If a database driver or protocol does not support such a feature,
716
+ # implementors may alias this to #reconnect!. Otherwise, implementors
717
+ # should call super immediately after resetting the connection (and while
718
+ # still holding @lock).
555
719
  def reset!
556
- # this should be overridden by concrete adapters
720
+ clear_cache!(new_connection: true)
721
+ reset_transaction
722
+ configure_connection
557
723
  end
558
724
 
559
725
  # Removes the connection from the pool and disconnect it.
@@ -563,8 +729,16 @@ module ActiveRecord
563
729
  end
564
730
 
565
731
  # Clear any caching the database adapter may be doing.
566
- def clear_cache!
567
- @lock.synchronize { @statements.clear } if @statements
732
+ def clear_cache!(new_connection: false)
733
+ if @statements
734
+ @lock.synchronize do
735
+ if new_connection
736
+ @statements.reset
737
+ else
738
+ @statements.clear
739
+ end
740
+ end
741
+ end
568
742
  end
569
743
 
570
744
  # Returns true if its required to reload the connection between requests for development mode.
@@ -576,7 +750,31 @@ module ActiveRecord
576
750
  # This is done under the hood by calling #active?. If the connection
577
751
  # is no longer active, then this method will reconnect to the database.
578
752
  def verify!
579
- reconnect! unless active?
753
+ unless active?
754
+ @lock.synchronize do
755
+ if @unconfigured_connection
756
+ @raw_connection = @unconfigured_connection
757
+ @unconfigured_connection = nil
758
+ configure_connection
759
+ @verified = true
760
+ return
761
+ end
762
+
763
+ reconnect!(restore_transactions: true)
764
+ end
765
+ end
766
+
767
+ @verified = true
768
+ end
769
+
770
+ def connect!
771
+ verify!
772
+ self
773
+ end
774
+
775
+ def clean! # :nodoc:
776
+ @raw_connection_dirty = false
777
+ @verified = nil
580
778
  end
581
779
 
582
780
  # Provides access to the underlying database driver for this adapter. For
@@ -590,8 +788,11 @@ module ActiveRecord
590
788
  # this client. If that is the case, generally you'll want to invalidate
591
789
  # the query cache using +ActiveRecord::Base.clear_query_cache+.
592
790
  def raw_connection
593
- disable_lazy_transactions!
594
- @connection
791
+ with_raw_connection do |conn|
792
+ disable_lazy_transactions!
793
+ @raw_connection_dirty = true
794
+ conn
795
+ end
595
796
  end
596
797
 
597
798
  def default_uniqueness_comparison(attribute, value) # :nodoc:
@@ -643,7 +844,7 @@ module ActiveRecord
643
844
  end
644
845
 
645
846
  def database_version # :nodoc:
646
- schema_cache.database_version
847
+ pool.server_version(self)
647
848
  end
648
849
 
649
850
  def check_version # :nodoc:
@@ -654,10 +855,25 @@ module ActiveRecord
654
855
  # numbered migration that has been executed, or 0 if no schema
655
856
  # information is present / the database is empty.
656
857
  def schema_version
657
- migration_context.current_version
858
+ pool.migration_context.current_version
658
859
  end
659
860
 
660
861
  class << self
862
+ def register_class_with_precision(mapping, key, klass, **kwargs) # :nodoc:
863
+ mapping.register_type(key) do |*args|
864
+ precision = extract_precision(args.last)
865
+ klass.new(precision: precision, **kwargs)
866
+ end
867
+ end
868
+
869
+ def extended_type_map(default_timezone:) # :nodoc:
870
+ Type::TypeMap.new(self::TYPE_MAP).tap do |m|
871
+ register_class_with_precision m, %r(\A[^\(]*time)i, Type::Time, timezone: default_timezone
872
+ register_class_with_precision m, %r(\A[^\(]*datetime)i, Type::DateTime, timezone: default_timezone
873
+ m.alias_type %r(\A[^\(]*timestamp)i, "datetime"
874
+ end
875
+ end
876
+
661
877
  private
662
878
  def initialize_type_map(m)
663
879
  register_class_with_limit m, %r(boolean)i, Type::Boolean
@@ -699,13 +915,6 @@ module ActiveRecord
699
915
  end
700
916
  end
701
917
 
702
- def register_class_with_precision(mapping, key, klass)
703
- mapping.register_type(key) do |*args|
704
- precision = extract_precision(args.last)
705
- klass.new(precision: precision)
706
- end
707
- end
708
-
709
918
  def extract_scale(sql_type)
710
919
  case sql_type
711
920
  when /\((\d+)\)/ then 0
@@ -723,10 +932,177 @@ module ActiveRecord
723
932
  end
724
933
 
725
934
  TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
935
+ EXTENDED_TYPE_MAPS = Concurrent::Map.new
726
936
 
727
937
  private
938
+ def reconnect_can_restore_state?
939
+ transaction_manager.restorable? && !@raw_connection_dirty
940
+ end
941
+
942
+ # Lock the monitor, ensure we're properly connected and
943
+ # transactions are materialized, and then yield the underlying
944
+ # raw connection object.
945
+ #
946
+ # If +allow_retry+ is true, a connection-related exception will
947
+ # cause an automatic reconnect and re-run of the block, up to
948
+ # the connection's configured +connection_retries+ setting
949
+ # and the configured +retry_deadline+ limit. (Note that when
950
+ # +allow_retry+ is true, it's possible to return without having marked
951
+ # the connection as verified. If the block is guaranteed to exercise the
952
+ # connection, consider calling `verified!` to avoid needless
953
+ # verification queries in subsequent calls.)
954
+ #
955
+ # If +materialize_transactions+ is false, the block will be run without
956
+ # ensuring virtual transactions have been materialized in the DB
957
+ # server's state. The active transaction will also remain clean
958
+ # (if it is not already dirty), meaning it's able to be restored
959
+ # by reconnecting and opening an equivalent-depth set of new
960
+ # transactions. This should only be used by transaction control
961
+ # methods, and internal transaction-agnostic queries.
962
+ #
963
+ ###
964
+ #
965
+ # It's not the primary use case, so not something to optimize
966
+ # for, but note that this method does need to be re-entrant:
967
+ # +materialize_transactions+ will re-enter if it has work to do,
968
+ # and the yield block can also do so under some circumstances.
969
+ #
970
+ # In the latter case, we really ought to guarantee the inner
971
+ # call will not reconnect (which would interfere with the
972
+ # still-yielded connection in the outer block), but we currently
973
+ # provide no special enforcement there.
974
+ #
975
+ def with_raw_connection(allow_retry: false, materialize_transactions: true)
976
+ @lock.synchronize do
977
+ connect! if @raw_connection.nil? && reconnect_can_restore_state?
978
+
979
+ self.materialize_transactions if materialize_transactions
980
+
981
+ retries_available = allow_retry ? connection_retries : 0
982
+ deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
983
+ reconnectable = reconnect_can_restore_state?
984
+
985
+ if @verified
986
+ # Cool, we're confident the connection's ready to use. (Note this might have
987
+ # become true during the above #materialize_transactions.)
988
+ elsif reconnectable
989
+ if allow_retry
990
+ # Not sure about the connection yet, but if anything goes wrong we can
991
+ # just reconnect and re-run our query
992
+ else
993
+ # We can reconnect if needed, but we don't trust the upcoming query to be
994
+ # safely re-runnable: let's verify the connection to be sure
995
+ verify!
996
+ end
997
+ else
998
+ # We don't know whether the connection is okay, but it also doesn't matter:
999
+ # we wouldn't be able to reconnect anyway. We're just going to run our query
1000
+ # and hope for the best.
1001
+ end
1002
+
1003
+ begin
1004
+ yield @raw_connection
1005
+ rescue => original_exception
1006
+ translated_exception = translate_exception_class(original_exception, nil, nil)
1007
+ invalidate_transaction(translated_exception)
1008
+ retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
1009
+
1010
+ if !retry_deadline_exceeded && retries_available > 0
1011
+ retries_available -= 1
1012
+
1013
+ if retryable_query_error?(translated_exception)
1014
+ backoff(connection_retries - retries_available)
1015
+ retry
1016
+ elsif reconnectable && retryable_connection_error?(translated_exception)
1017
+ reconnect!(restore_transactions: true)
1018
+ # Only allowed to reconnect once, because reconnect! has its own retry
1019
+ # loop
1020
+ reconnectable = false
1021
+ retry
1022
+ end
1023
+ end
1024
+
1025
+ unless retryable_query_error?(translated_exception)
1026
+ # Barring a known-retryable error inside the query (regardless of
1027
+ # whether we were in a _position_ to retry it), we should infer that
1028
+ # there's likely a real problem with the connection.
1029
+ @verified = false
1030
+ end
1031
+
1032
+ raise translated_exception
1033
+ ensure
1034
+ dirty_current_transaction if materialize_transactions
1035
+ end
1036
+ end
1037
+ end
1038
+
1039
+ # Mark the connection as verified. Call this inside a
1040
+ # `with_raw_connection` block only when the block is guaranteed to
1041
+ # exercise the raw connection.
1042
+ def verified!
1043
+ @verified = true
1044
+ end
1045
+
1046
+ def retryable_connection_error?(exception)
1047
+ exception.is_a?(ConnectionNotEstablished) || exception.is_a?(ConnectionFailed)
1048
+ end
1049
+
1050
+ def invalidate_transaction(exception)
1051
+ return unless exception.is_a?(TransactionRollbackError)
1052
+ return unless savepoint_errors_invalidate_transactions?
1053
+
1054
+ current_transaction.invalidate!
1055
+ end
1056
+
1057
+ def retryable_query_error?(exception)
1058
+ # We definitely can't retry if we were inside an invalidated transaction.
1059
+ return false if current_transaction.invalidated?
1060
+
1061
+ exception.is_a?(Deadlocked) || exception.is_a?(LockWaitTimeout)
1062
+ end
1063
+
1064
+ def backoff(counter)
1065
+ sleep 0.1 * counter
1066
+ end
1067
+
1068
+ def reconnect
1069
+ raise NotImplementedError
1070
+ end
1071
+
1072
+ # Returns a raw connection for internal use with methods that are known
1073
+ # to both be thread-safe and not rely upon actual server communication.
1074
+ # This is useful for e.g. string escaping methods.
1075
+ def any_raw_connection
1076
+ @raw_connection || valid_raw_connection
1077
+ end
1078
+
1079
+ # Similar to any_raw_connection, but ensures it is validated and
1080
+ # connected. Any method called on this result still needs to be
1081
+ # independently thread-safe, so it probably shouldn't talk to the
1082
+ # server... but some drivers fail if they know the connection has gone
1083
+ # away.
1084
+ def valid_raw_connection
1085
+ (@verified && @raw_connection) ||
1086
+ # `allow_retry: false`, to force verification: the block won't
1087
+ # raise, so a retry wouldn't help us get the valid connection we
1088
+ # need.
1089
+ with_raw_connection(allow_retry: false, materialize_transactions: false) { |conn| conn }
1090
+ end
1091
+
1092
+ def extended_type_map_key
1093
+ if @default_timezone
1094
+ { default_timezone: @default_timezone }
1095
+ end
1096
+ end
1097
+
728
1098
  def type_map
729
- TYPE_MAP
1099
+ if key = extended_type_map_key
1100
+ self.class::EXTENDED_TYPE_MAPS.compute_if_absent(key) do
1101
+ self.class.extended_type_map(**key)
1102
+ end
1103
+ else
1104
+ self.class::TYPE_MAP
1105
+ end
730
1106
  end
731
1107
 
732
1108
  def translate_exception_class(e, sql, binds)
@@ -748,16 +1124,18 @@ module ActiveRecord
748
1124
  type_casted_binds: type_casted_binds,
749
1125
  statement_name: statement_name,
750
1126
  async: async,
751
- connection: self) do
752
- @lock.synchronize(&block)
753
- rescue => e
754
- raise translate_exception_class(e, sql, binds)
755
- end
1127
+ connection: self,
1128
+ transaction: current_transaction.user_transaction.presence,
1129
+ row_count: 0,
1130
+ &block
1131
+ )
1132
+ rescue ActiveRecord::StatementInvalid => ex
1133
+ raise ex.set_query(sql, binds)
756
1134
  end
757
1135
 
758
1136
  def transform_query(sql)
759
1137
  ActiveRecord.query_transformers.each do |transformer|
760
- sql = transformer.call(sql)
1138
+ sql = transformer.call(sql, self)
761
1139
  end
762
1140
  sql
763
1141
  end
@@ -765,10 +1143,10 @@ module ActiveRecord
765
1143
  def translate_exception(exception, message:, sql:, binds:)
766
1144
  # override in derived class
767
1145
  case exception
768
- when RuntimeError
1146
+ when RuntimeError, ActiveRecord::ActiveRecordError
769
1147
  exception
770
1148
  else
771
- ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
1149
+ ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
772
1150
  end
773
1151
  end
774
1152
 
@@ -812,9 +1190,30 @@ module ActiveRecord
812
1190
  #
813
1191
  # This is an internal hook to make possible connection adapters to build
814
1192
  # custom result objects with connection-specific data.
815
- def build_result(columns:, rows:, column_types: {})
1193
+ def build_result(columns:, rows:, column_types: nil)
816
1194
  ActiveRecord::Result.new(columns, rows, column_types)
817
1195
  end
1196
+
1197
+ # Perform any necessary initialization upon the newly-established
1198
+ # @raw_connection -- this is the place to modify the adapter's
1199
+ # connection settings, run queries to configure any application-global
1200
+ # "session" variables, etc.
1201
+ #
1202
+ # Implementations may assume this method will only be called while
1203
+ # holding @lock (or from #initialize).
1204
+ def configure_connection
1205
+ check_version
1206
+ end
1207
+
1208
+ def default_prepared_statements
1209
+ true
1210
+ end
1211
+
1212
+ def warning_ignored?(warning)
1213
+ ActiveRecord.db_warnings_ignore.any? do |warning_matcher|
1214
+ warning.message.match?(warning_matcher) || warning.code.to_s.match?(warning_matcher)
1215
+ end
1216
+ end
818
1217
  end
819
1218
  end
820
1219
  end