activerecord 5.2.8.1 → 6.1.6.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1255 -596
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +9 -8
  7. data/lib/active_record/association_relation.rb +30 -10
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +100 -41
  10. data/lib/active_record/associations/association_scope.rb +23 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +55 -48
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  13. data/lib/active_record/associations/builder/association.rb +45 -22
  14. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  15. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -2
  18. data/lib/active_record/associations/builder/has_one.rb +33 -2
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  20. data/lib/active_record/associations/collection_association.rb +44 -34
  21. data/lib/active_record/associations/collection_proxy.rb +25 -21
  22. data/lib/active_record/associations/foreign_association.rb +20 -0
  23. data/lib/active_record/associations/has_many_association.rb +26 -13
  24. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  25. data/lib/active_record/associations/has_one_association.rb +43 -31
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  28. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/preloader/association.rb +69 -43
  31. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/singular_association.rb +3 -17
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/associations.rb +137 -25
  36. data/lib/active_record/attribute_assignment.rb +17 -19
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  38. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  40. data/lib/active_record/attribute_methods/query.rb +4 -8
  41. data/lib/active_record/attribute_methods/read.rb +14 -56
  42. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +18 -34
  45. data/lib/active_record/attribute_methods.rb +81 -143
  46. data/lib/active_record/attributes.rb +46 -9
  47. data/lib/active_record/autosave_association.rb +57 -42
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +1 -2
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  64. data/lib/active_record/connection_adapters/column.rb +30 -12
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  77. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
  81. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  94. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  96. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  99. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  101. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  102. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  104. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  105. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  106. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
  107. data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
  108. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  109. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  110. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  111. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  112. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  113. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  114. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  115. data/lib/active_record/connection_adapters.rb +52 -0
  116. data/lib/active_record/connection_handling.rb +293 -33
  117. data/lib/active_record/core.rb +333 -98
  118. data/lib/active_record/counter_cache.rb +8 -30
  119. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  120. data/lib/active_record/database_configurations/database_config.rb +80 -0
  121. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  122. data/lib/active_record/database_configurations/url_config.rb +53 -0
  123. data/lib/active_record/database_configurations.rb +273 -0
  124. data/lib/active_record/delegated_type.rb +209 -0
  125. data/lib/active_record/destroy_association_async_job.rb +36 -0
  126. data/lib/active_record/dynamic_matchers.rb +3 -4
  127. data/lib/active_record/enum.rb +108 -36
  128. data/lib/active_record/errors.rb +62 -19
  129. data/lib/active_record/explain.rb +10 -6
  130. data/lib/active_record/explain_subscriber.rb +1 -1
  131. data/lib/active_record/fixture_set/file.rb +10 -17
  132. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  133. data/lib/active_record/fixture_set/render_context.rb +17 -0
  134. data/lib/active_record/fixture_set/table_row.rb +152 -0
  135. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  136. data/lib/active_record/fixtures.rb +200 -481
  137. data/lib/active_record/gem_version.rb +3 -3
  138. data/lib/active_record/inheritance.rb +53 -24
  139. data/lib/active_record/insert_all.rb +212 -0
  140. data/lib/active_record/integration.rb +67 -17
  141. data/lib/active_record/internal_metadata.rb +28 -9
  142. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  143. data/lib/active_record/locking/optimistic.rb +37 -23
  144. data/lib/active_record/locking/pessimistic.rb +9 -5
  145. data/lib/active_record/log_subscriber.rb +35 -35
  146. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  147. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  148. data/lib/active_record/middleware/database_selector.rb +77 -0
  149. data/lib/active_record/migration/command_recorder.rb +96 -44
  150. data/lib/active_record/migration/compatibility.rb +145 -64
  151. data/lib/active_record/migration/join_table.rb +0 -1
  152. data/lib/active_record/migration.rb +206 -157
  153. data/lib/active_record/model_schema.rb +148 -22
  154. data/lib/active_record/nested_attributes.rb +4 -7
  155. data/lib/active_record/no_touching.rb +8 -1
  156. data/lib/active_record/null_relation.rb +0 -1
  157. data/lib/active_record/persistence.rb +267 -59
  158. data/lib/active_record/query_cache.rb +21 -4
  159. data/lib/active_record/querying.rb +40 -23
  160. data/lib/active_record/railtie.rb +116 -59
  161. data/lib/active_record/railties/console_sandbox.rb +2 -4
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +411 -80
  164. data/lib/active_record/readonly_attributes.rb +4 -0
  165. data/lib/active_record/reflection.rb +109 -93
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  167. data/lib/active_record/relation/batches.rb +44 -35
  168. data/lib/active_record/relation/calculations.rb +157 -90
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +64 -39
  171. data/lib/active_record/relation/from_clause.rb +5 -1
  172. data/lib/active_record/relation/merger.rb +32 -40
  173. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  174. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  179. data/lib/active_record/relation/predicate_builder.rb +62 -45
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +476 -187
  182. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  183. data/lib/active_record/relation/spawn_methods.rb +9 -9
  184. data/lib/active_record/relation/where_clause.rb +115 -62
  185. data/lib/active_record/relation.rb +379 -115
  186. data/lib/active_record/result.rb +64 -38
  187. data/lib/active_record/runtime_registry.rb +2 -2
  188. data/lib/active_record/sanitization.rb +22 -41
  189. data/lib/active_record/schema.rb +2 -11
  190. data/lib/active_record/schema_dumper.rb +54 -9
  191. data/lib/active_record/schema_migration.rb +7 -9
  192. data/lib/active_record/scoping/default.rb +4 -8
  193. data/lib/active_record/scoping/named.rb +17 -24
  194. data/lib/active_record/scoping.rb +8 -9
  195. data/lib/active_record/secure_token.rb +16 -8
  196. data/lib/active_record/serialization.rb +5 -3
  197. data/lib/active_record/signed_id.rb +116 -0
  198. data/lib/active_record/statement_cache.rb +49 -6
  199. data/lib/active_record/store.rb +88 -9
  200. data/lib/active_record/suppressor.rb +2 -2
  201. data/lib/active_record/table_metadata.rb +42 -43
  202. data/lib/active_record/tasks/database_tasks.rb +277 -81
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  206. data/lib/active_record/test_databases.rb +24 -0
  207. data/lib/active_record/test_fixtures.rb +287 -0
  208. data/lib/active_record/timestamp.rb +43 -32
  209. data/lib/active_record/touch_later.rb +23 -22
  210. data/lib/active_record/transactions.rb +62 -118
  211. data/lib/active_record/translation.rb +1 -1
  212. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  213. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  214. data/lib/active_record/type/serialized.rb +6 -3
  215. data/lib/active_record/type/time.rb +10 -0
  216. data/lib/active_record/type/type_map.rb +0 -1
  217. data/lib/active_record/type/unsigned_integer.rb +0 -1
  218. data/lib/active_record/type.rb +10 -5
  219. data/lib/active_record/type_caster/connection.rb +15 -15
  220. data/lib/active_record/type_caster/map.rb +8 -8
  221. data/lib/active_record/validations/associated.rb +1 -2
  222. data/lib/active_record/validations/numericality.rb +35 -0
  223. data/lib/active_record/validations/uniqueness.rb +38 -30
  224. data/lib/active_record/validations.rb +4 -3
  225. data/lib/active_record.rb +13 -12
  226. data/lib/arel/alias_predication.rb +9 -0
  227. data/lib/arel/attributes/attribute.rb +41 -0
  228. data/lib/arel/collectors/bind.rb +29 -0
  229. data/lib/arel/collectors/composite.rb +39 -0
  230. data/lib/arel/collectors/plain_string.rb +20 -0
  231. data/lib/arel/collectors/sql_string.rb +27 -0
  232. data/lib/arel/collectors/substitute_binds.rb +35 -0
  233. data/lib/arel/crud.rb +42 -0
  234. data/lib/arel/delete_manager.rb +18 -0
  235. data/lib/arel/errors.rb +9 -0
  236. data/lib/arel/expressions.rb +29 -0
  237. data/lib/arel/factory_methods.rb +49 -0
  238. data/lib/arel/insert_manager.rb +49 -0
  239. data/lib/arel/math.rb +45 -0
  240. data/lib/arel/nodes/and.rb +32 -0
  241. data/lib/arel/nodes/ascending.rb +23 -0
  242. data/lib/arel/nodes/binary.rb +126 -0
  243. data/lib/arel/nodes/bind_param.rb +44 -0
  244. data/lib/arel/nodes/case.rb +55 -0
  245. data/lib/arel/nodes/casted.rb +62 -0
  246. data/lib/arel/nodes/comment.rb +29 -0
  247. data/lib/arel/nodes/count.rb +12 -0
  248. data/lib/arel/nodes/delete_statement.rb +45 -0
  249. data/lib/arel/nodes/descending.rb +23 -0
  250. data/lib/arel/nodes/equality.rb +15 -0
  251. data/lib/arel/nodes/extract.rb +24 -0
  252. data/lib/arel/nodes/false.rb +16 -0
  253. data/lib/arel/nodes/full_outer_join.rb +8 -0
  254. data/lib/arel/nodes/function.rb +44 -0
  255. data/lib/arel/nodes/grouping.rb +11 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  257. data/lib/arel/nodes/in.rb +15 -0
  258. data/lib/arel/nodes/infix_operation.rb +92 -0
  259. data/lib/arel/nodes/inner_join.rb +8 -0
  260. data/lib/arel/nodes/insert_statement.rb +37 -0
  261. data/lib/arel/nodes/join_source.rb +20 -0
  262. data/lib/arel/nodes/matches.rb +18 -0
  263. data/lib/arel/nodes/named_function.rb +23 -0
  264. data/lib/arel/nodes/node.rb +51 -0
  265. data/lib/arel/nodes/node_expression.rb +13 -0
  266. data/lib/arel/nodes/ordering.rb +27 -0
  267. data/lib/arel/nodes/outer_join.rb +8 -0
  268. data/lib/arel/nodes/over.rb +15 -0
  269. data/lib/arel/nodes/regexp.rb +16 -0
  270. data/lib/arel/nodes/right_outer_join.rb +8 -0
  271. data/lib/arel/nodes/select_core.rb +67 -0
  272. data/lib/arel/nodes/select_statement.rb +41 -0
  273. data/lib/arel/nodes/sql_literal.rb +19 -0
  274. data/lib/arel/nodes/string_join.rb +11 -0
  275. data/lib/arel/nodes/table_alias.rb +31 -0
  276. data/lib/arel/nodes/terminal.rb +16 -0
  277. data/lib/arel/nodes/true.rb +16 -0
  278. data/lib/arel/nodes/unary.rb +44 -0
  279. data/lib/arel/nodes/unary_operation.rb +20 -0
  280. data/lib/arel/nodes/unqualified_column.rb +22 -0
  281. data/lib/arel/nodes/update_statement.rb +41 -0
  282. data/lib/arel/nodes/values_list.rb +9 -0
  283. data/lib/arel/nodes/window.rb +126 -0
  284. data/lib/arel/nodes/with.rb +11 -0
  285. data/lib/arel/nodes.rb +70 -0
  286. data/lib/arel/order_predications.rb +13 -0
  287. data/lib/arel/predications.rb +250 -0
  288. data/lib/arel/select_manager.rb +270 -0
  289. data/lib/arel/table.rb +118 -0
  290. data/lib/arel/tree_manager.rb +72 -0
  291. data/lib/arel/update_manager.rb +34 -0
  292. data/lib/arel/visitors/dot.rb +308 -0
  293. data/lib/arel/visitors/mysql.rb +93 -0
  294. data/lib/arel/visitors/postgresql.rb +120 -0
  295. data/lib/arel/visitors/sqlite.rb +38 -0
  296. data/lib/arel/visitors/to_sql.rb +899 -0
  297. data/lib/arel/visitors/visitor.rb +45 -0
  298. data/lib/arel/visitors.rb +13 -0
  299. data/lib/arel/window_predications.rb +9 -0
  300. data/lib/arel.rb +54 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  303. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  304. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  305. data/lib/rails/generators/active_record/migration.rb +19 -2
  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 +116 -30
  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
@@ -1,17 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
4
- gem "pg", ">= 0.18", "< 2.0"
3
+ gem "pg", "~> 1.1"
5
4
  require "pg"
6
5
 
7
- # Use async_exec instead of exec_params on pg versions before 1.1
8
- class ::PG::Connection
9
- unless self.public_method_defined?(:async_exec_params)
10
- remove_method :exec_params
11
- alias exec_params async_exec
12
- end
13
- end
14
-
6
+ require "active_support/core_ext/object/try"
15
7
  require "active_record/connection_adapters/abstract_adapter"
16
8
  require "active_record/connection_adapters/statement_pool"
17
9
  require "active_record/connection_adapters/postgresql/column"
@@ -31,9 +23,7 @@ module ActiveRecord
31
23
  module ConnectionHandling # :nodoc:
32
24
  # Establishes a connection to the database that's used by all Active Record objects
33
25
  def postgresql_connection(config)
34
- conn_params = config.symbolize_keys
35
-
36
- conn_params.delete_if { |_, v| v.nil? }
26
+ conn_params = config.symbolize_keys.compact
37
27
 
38
28
  # Map ActiveRecords param names to PGs.
39
29
  conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
@@ -43,14 +33,17 @@ module ActiveRecord
43
33
  valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
44
34
  conn_params.slice!(*valid_conn_param_keys)
45
35
 
46
- # The postgres drivers don't allow the creation of an unconnected PG::Connection object,
47
- # so just pass a nil connection object for the time being.
48
- ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)
36
+ ConnectionAdapters::PostgreSQLAdapter.new(
37
+ ConnectionAdapters::PostgreSQLAdapter.new_client(conn_params),
38
+ logger,
39
+ conn_params,
40
+ config,
41
+ )
49
42
  end
50
43
  end
51
44
 
52
45
  module ConnectionAdapters
53
- # The PostgreSQL adapter works with the native C (https://bitbucket.org/ged/ruby-pg) driver.
46
+ # The PostgreSQL adapter works with the native C (https://github.com/ged/ruby-pg) driver.
54
47
  #
55
48
  # Options:
56
49
  #
@@ -78,7 +71,32 @@ module ActiveRecord
78
71
  # In addition, default connection parameters of libpq can be set per environment variables.
79
72
  # See https://www.postgresql.org/docs/current/static/libpq-envars.html .
80
73
  class PostgreSQLAdapter < AbstractAdapter
81
- ADAPTER_NAME = "PostgreSQL".freeze
74
+ ADAPTER_NAME = "PostgreSQL"
75
+
76
+ class << self
77
+ def new_client(conn_params)
78
+ PG.connect(conn_params)
79
+ rescue ::PG::Error => error
80
+ if conn_params && conn_params[:dbname] && error.message.include?(conn_params[:dbname])
81
+ raise ActiveRecord::NoDatabaseError
82
+ else
83
+ raise ActiveRecord::ConnectionNotEstablished, error.message
84
+ end
85
+ end
86
+ end
87
+
88
+ ##
89
+ # :singleton-method:
90
+ # PostgreSQL allows the creation of "unlogged" tables, which do not record
91
+ # data in the PostgreSQL Write-Ahead Log. This can make the tables faster,
92
+ # but significantly increases the risk of data loss if the database
93
+ # crashes. As a result, this should not be used in production
94
+ # environments. If you would like all created tables to be unlogged in
95
+ # the test environment you can add the following line to your test.rb
96
+ # file:
97
+ #
98
+ # ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
99
+ class_attribute :create_unlogged_tables, default: false
82
100
 
83
101
  NATIVE_DATABASE_TYPES = {
84
102
  primary_key: "bigserial primary key",
@@ -138,6 +156,10 @@ module ActiveRecord
138
156
  true
139
157
  end
140
158
 
159
+ def supports_partitioned_indexes?
160
+ database_version >= 110_000
161
+ end
162
+
141
163
  def supports_partial_index?
142
164
  true
143
165
  end
@@ -154,6 +176,10 @@ module ActiveRecord
154
176
  true
155
177
  end
156
178
 
179
+ def supports_check_constraints?
180
+ true
181
+ end
182
+
157
183
  def supports_validate_constraints?
158
184
  true
159
185
  end
@@ -167,7 +193,7 @@ module ActiveRecord
167
193
  end
168
194
 
169
195
  def supports_json?
170
- postgresql_version >= 90200
196
+ true
171
197
  end
172
198
 
173
199
  def supports_comments?
@@ -178,6 +204,17 @@ module ActiveRecord
178
204
  true
179
205
  end
180
206
 
207
+ def supports_insert_returning?
208
+ true
209
+ end
210
+
211
+ def supports_insert_on_conflict?
212
+ database_version >= 90500
213
+ end
214
+ alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
215
+ alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
216
+ alias supports_insert_conflict_target? supports_insert_on_conflict?
217
+
181
218
  def index_algorithms
182
219
  { concurrently: "CONCURRENTLY" }
183
220
  end
@@ -190,11 +227,7 @@ module ActiveRecord
190
227
  end
191
228
 
192
229
  def next_key
193
- "a#{@counter + 1}"
194
- end
195
-
196
- def []=(sql, key)
197
- super.tap { @counter += 1 }
230
+ "a#{@counter += 1}"
198
231
  end
199
232
 
200
233
  private
@@ -220,15 +253,8 @@ module ActiveRecord
220
253
  @local_tz = nil
221
254
  @max_identifier_length = nil
222
255
 
223
- connect
256
+ configure_connection
224
257
  add_pg_encoders
225
- @statements = StatementPool.new @connection,
226
- self.class.type_cast_config_to_integer(config[:statement_limit])
227
-
228
- if postgresql_version < 90100
229
- raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
230
- end
231
-
232
258
  add_pg_decoders
233
259
 
234
260
  @type_map = Type::HashLookupTypeMap.new
@@ -237,15 +263,10 @@ module ActiveRecord
237
263
  @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
238
264
  end
239
265
 
240
- # Clears the prepared statements cache.
241
- def clear_cache!
242
- @lock.synchronize do
243
- @statements.clear
244
- end
245
- end
246
-
247
- def truncate(table_name, name = nil)
248
- exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, []
266
+ def self.database_exists?(config)
267
+ !!ActiveRecord::Base.postgresql_connection(config)
268
+ rescue ActiveRecord::NoDatabaseError
269
+ false
249
270
  end
250
271
 
251
272
  # Is this connection alive and ready for queries?
@@ -264,6 +285,8 @@ module ActiveRecord
264
285
  super
265
286
  @connection.reset
266
287
  configure_connection
288
+ rescue PG::ConnectionBad
289
+ connect
267
290
  end
268
291
  end
269
292
 
@@ -289,6 +312,7 @@ module ActiveRecord
289
312
  end
290
313
 
291
314
  def discard! # :nodoc:
315
+ super
292
316
  @connection.socket_io.reopen(IO::NULL) rescue nil
293
317
  @connection = nil
294
318
  end
@@ -317,21 +341,31 @@ module ActiveRecord
317
341
  true
318
342
  end
319
343
 
320
- def supports_ranges?
321
- # Range datatypes weren't introduced until PostgreSQL 9.2
322
- postgresql_version >= 90200
323
- end
324
-
325
344
  def supports_materialized_views?
326
- postgresql_version >= 90300
345
+ true
327
346
  end
328
347
 
329
348
  def supports_foreign_tables?
330
- postgresql_version >= 90300
349
+ true
331
350
  end
332
351
 
333
352
  def supports_pgcrypto_uuid?
334
- postgresql_version >= 90400
353
+ database_version >= 90400
354
+ end
355
+
356
+ def supports_optimizer_hints?
357
+ unless defined?(@has_pg_hint_plan)
358
+ @has_pg_hint_plan = extension_available?("pg_hint_plan")
359
+ end
360
+ @has_pg_hint_plan
361
+ end
362
+
363
+ def supports_common_table_expressions?
364
+ true
365
+ end
366
+
367
+ def supports_lazy_transactions?
368
+ true
335
369
  end
336
370
 
337
371
  def get_advisory_lock(lock_id) # :nodoc:
@@ -360,9 +394,12 @@ module ActiveRecord
360
394
  }
361
395
  end
362
396
 
397
+ def extension_available?(name)
398
+ query_value("SELECT true FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
399
+ end
400
+
363
401
  def extension_enabled?(name)
364
- res = exec_query("SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled", "SCHEMA")
365
- res.cast_values.first
402
+ query_value("SELECT installed_version IS NOT NULL FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
366
403
  end
367
404
 
368
405
  def extensions
@@ -373,8 +410,6 @@ module ActiveRecord
373
410
  def max_identifier_length
374
411
  @max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
375
412
  end
376
- alias table_alias_length max_identifier_length
377
- alias index_name_length max_identifier_length
378
413
 
379
414
  # Set the authorized user for this session
380
415
  def session_auth=(user)
@@ -386,25 +421,37 @@ module ActiveRecord
386
421
  @use_insert_returning
387
422
  end
388
423
 
389
- def column_name_for_operation(operation, node) # :nodoc:
390
- OPERATION_ALIASES.fetch(operation) { operation.downcase }
391
- end
392
-
393
- OPERATION_ALIASES = { # :nodoc:
394
- "maximum" => "max",
395
- "minimum" => "min",
396
- "average" => "avg",
397
- }
398
-
399
424
  # Returns the version of the connected PostgreSQL server.
400
- def postgresql_version
425
+ def get_database_version # :nodoc:
401
426
  @connection.server_version
402
427
  end
428
+ alias :postgresql_version :database_version
403
429
 
404
430
  def default_index_type?(index) # :nodoc:
405
431
  index.using == :btree || super
406
432
  end
407
433
 
434
+ def build_insert_sql(insert) # :nodoc:
435
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
436
+
437
+ if insert.skip_duplicates?
438
+ sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
439
+ elsif insert.update_duplicates?
440
+ sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
441
+ sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
442
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
443
+ end
444
+
445
+ sql << " RETURNING #{insert.returning}" if insert.returning
446
+ sql
447
+ end
448
+
449
+ def check_version # :nodoc:
450
+ if database_version < 90300
451
+ raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
452
+ end
453
+ end
454
+
408
455
  private
409
456
  # See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
410
457
  VALUE_LIMIT_VIOLATION = "22001"
@@ -414,37 +461,46 @@ module ActiveRecord
414
461
  UNIQUE_VIOLATION = "23505"
415
462
  SERIALIZATION_FAILURE = "40001"
416
463
  DEADLOCK_DETECTED = "40P01"
464
+ DUPLICATE_DATABASE = "42P04"
417
465
  LOCK_NOT_AVAILABLE = "55P03"
418
466
  QUERY_CANCELED = "57014"
419
467
 
420
- def translate_exception(exception, message)
468
+ def translate_exception(exception, message:, sql:, binds:)
421
469
  return exception unless exception.respond_to?(:result)
422
470
 
423
471
  case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
472
+ when nil
473
+ if exception.message.match?(/connection is closed/i)
474
+ ConnectionNotEstablished.new(exception)
475
+ else
476
+ super
477
+ end
424
478
  when UNIQUE_VIOLATION
425
- RecordNotUnique.new(message)
479
+ RecordNotUnique.new(message, sql: sql, binds: binds)
426
480
  when FOREIGN_KEY_VIOLATION
427
- InvalidForeignKey.new(message)
481
+ InvalidForeignKey.new(message, sql: sql, binds: binds)
428
482
  when VALUE_LIMIT_VIOLATION
429
- ValueTooLong.new(message)
483
+ ValueTooLong.new(message, sql: sql, binds: binds)
430
484
  when NUMERIC_VALUE_OUT_OF_RANGE
431
- RangeError.new(message)
485
+ RangeError.new(message, sql: sql, binds: binds)
432
486
  when NOT_NULL_VIOLATION
433
- NotNullViolation.new(message)
487
+ NotNullViolation.new(message, sql: sql, binds: binds)
434
488
  when SERIALIZATION_FAILURE
435
- SerializationFailure.new(message)
489
+ SerializationFailure.new(message, sql: sql, binds: binds)
436
490
  when DEADLOCK_DETECTED
437
- Deadlocked.new(message)
491
+ Deadlocked.new(message, sql: sql, binds: binds)
492
+ when DUPLICATE_DATABASE
493
+ DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
438
494
  when LOCK_NOT_AVAILABLE
439
- LockWaitTimeout.new(message)
495
+ LockWaitTimeout.new(message, sql: sql, binds: binds)
440
496
  when QUERY_CANCELED
441
- QueryCanceled.new(message)
497
+ QueryCanceled.new(message, sql: sql, binds: binds)
442
498
  else
443
499
  super
444
500
  end
445
501
  end
446
502
 
447
- def get_oid_type(oid, fmod, column_name, sql_type = "".freeze)
503
+ def get_oid_type(oid, fmod, column_name, sql_type = "")
448
504
  if !type_map.key?(oid)
449
505
  load_additional_types([oid])
450
506
  end
@@ -486,7 +542,7 @@ module ActiveRecord
486
542
  m.register_type "uuid", OID::Uuid.new
487
543
  m.register_type "xml", OID::Xml.new
488
544
  m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
489
- m.register_type "macaddr", OID::SpecializedString.new(:macaddr)
545
+ m.register_type "macaddr", OID::Macaddr.new
490
546
  m.register_type "citext", OID::SpecializedString.new(:citext)
491
547
  m.register_type "ltree", OID::SpecializedString.new(:ltree)
492
548
  m.register_type "line", OID::SpecializedString.new(:line)
@@ -496,11 +552,6 @@ module ActiveRecord
496
552
  m.register_type "polygon", OID::SpecializedString.new(:polygon)
497
553
  m.register_type "circle", OID::SpecializedString.new(:circle)
498
554
 
499
- m.register_type "interval" do |_, _, sql_type|
500
- precision = extract_precision(sql_type)
501
- OID::SpecializedString.new(:interval, precision: precision)
502
- end
503
-
504
555
  register_class_with_precision m, "time", Type::Time
505
556
  register_class_with_precision m, "timestamp", OID::DateTime
506
557
 
@@ -524,6 +575,11 @@ module ActiveRecord
524
575
  end
525
576
  end
526
577
 
578
+ m.register_type "interval" do |*args, sql_type|
579
+ precision = extract_precision(sql_type)
580
+ OID::Interval.new(precision: precision)
581
+ end
582
+
527
583
  load_additional_types
528
584
  end
529
585
 
@@ -533,13 +589,13 @@ module ActiveRecord
533
589
  # Quoted types
534
590
  when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
535
591
  # The default 'now'::date is CURRENT_DATE
536
- if $1 == "now".freeze && $2 == "date".freeze
592
+ if $1 == "now" && $2 == "date"
537
593
  nil
538
594
  else
539
- $1.gsub("''".freeze, "'".freeze)
595
+ $1.gsub("''", "'")
540
596
  end
541
597
  # Boolean types
542
- when "true".freeze, "false".freeze
598
+ when "true", "false"
543
599
  default
544
600
  # Numeric types
545
601
  when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
@@ -565,21 +621,14 @@ module ActiveRecord
565
621
  def load_additional_types(oids = nil)
566
622
  initializer = OID::TypeMapInitializer.new(type_map)
567
623
 
568
- if supports_ranges?
569
- query = <<-SQL
570
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
571
- FROM pg_type as t
572
- LEFT JOIN pg_range as r ON oid = rngtypid
573
- SQL
574
- else
575
- query = <<-SQL
576
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
577
- FROM pg_type as t
578
- SQL
579
- end
624
+ query = <<~SQL
625
+ SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
626
+ FROM pg_type as t
627
+ LEFT JOIN pg_range as r ON oid = rngtypid
628
+ SQL
580
629
 
581
630
  if oids
582
- query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
631
+ query += "WHERE t.oid IN (%s)" % oids.join(", ")
583
632
  else
584
633
  query += initializer.query_conditions_for_initial_load
585
634
  end
@@ -592,19 +641,31 @@ module ActiveRecord
592
641
  FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
593
642
 
594
643
  def execute_and_clear(sql, name, binds, prepare: false)
595
- if without_prepared_statement?(binds)
596
- result = exec_no_cache(sql, name, [])
597
- elsif !prepare
644
+ if preventing_writes? && write_query?(sql)
645
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
646
+ end
647
+
648
+ if !prepare || without_prepared_statement?(binds)
598
649
  result = exec_no_cache(sql, name, binds)
599
650
  else
600
651
  result = exec_cache(sql, name, binds)
601
652
  end
602
- ret = yield result
603
- result.clear
653
+ begin
654
+ ret = yield result
655
+ ensure
656
+ result.clear
657
+ end
604
658
  ret
605
659
  end
606
660
 
607
661
  def exec_no_cache(sql, name, binds)
662
+ materialize_transactions
663
+ mark_transaction_written_if_write(sql)
664
+
665
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
666
+ # made since we established the connection
667
+ update_typemap_for_default_timezone
668
+
608
669
  type_casted_binds = type_casted_binds(binds)
609
670
  log(sql, name, binds, type_casted_binds) do
610
671
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
@@ -614,7 +675,11 @@ module ActiveRecord
614
675
  end
615
676
 
616
677
  def exec_cache(sql, name, binds)
617
- stmt_key = prepare_statement(sql)
678
+ materialize_transactions
679
+ mark_transaction_written_if_write(sql)
680
+ update_typemap_for_default_timezone
681
+
682
+ stmt_key = prepare_statement(sql, binds)
618
683
  type_casted_binds = type_casted_binds(binds)
619
684
 
620
685
  log(sql, name, binds, type_casted_binds, stmt_key) do
@@ -647,11 +712,10 @@ module ActiveRecord
647
712
  #
648
713
  # Check here for more details:
649
714
  # https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
650
- CACHED_PLAN_HEURISTIC = "cached plan must not change result type".freeze
651
715
  def is_cached_plan_failure?(e)
652
716
  pgerror = e.cause
653
- code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
654
- code == FEATURE_NOT_SUPPORTED && pgerror.message.include?(CACHED_PLAN_HEURISTIC)
717
+ pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
718
+ pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "RevalidateCachedQuery"
655
719
  rescue
656
720
  false
657
721
  end
@@ -668,7 +732,7 @@ module ActiveRecord
668
732
 
669
733
  # Prepare the statement if it hasn't been prepared, return
670
734
  # the statement key.
671
- def prepare_statement(sql)
735
+ def prepare_statement(sql, binds)
672
736
  @lock.synchronize do
673
737
  sql_key = sql_key(sql)
674
738
  unless @statements.key? sql_key
@@ -676,7 +740,7 @@ module ActiveRecord
676
740
  begin
677
741
  @connection.prepare nextkey, sql
678
742
  rescue => e
679
- raise translate_exception_class(e, sql)
743
+ raise translate_exception_class(e, sql, binds)
680
744
  end
681
745
  # Clear the queue
682
746
  @connection.get_last_result
@@ -689,14 +753,10 @@ module ActiveRecord
689
753
  # Connects to a PostgreSQL server and sets up the adapter depending on the
690
754
  # connected server's characteristics.
691
755
  def connect
692
- @connection = PG.connect(@connection_parameters)
756
+ @connection = self.class.new_client(@connection_parameters)
693
757
  configure_connection
694
- rescue ::PG::Error => error
695
- if error.message.include?("does not exist")
696
- raise ActiveRecord::NoDatabaseError
697
- else
698
- raise
699
- end
758
+ add_pg_encoders
759
+ add_pg_decoders
700
760
  end
701
761
 
702
762
  # Configures the encoding, verbosity, schema search path, and time zone of the connection.
@@ -723,6 +783,9 @@ module ActiveRecord
723
783
  end
724
784
  end
725
785
 
786
+ # Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
787
+ execute("SET intervalstyle = iso_8601", "SCHEMA")
788
+
726
789
  # SET statements from :variables config hash
727
790
  # https://www.postgresql.org/docs/current/static/sql-set.html
728
791
  variables.map do |k, v|
@@ -754,7 +817,7 @@ module ActiveRecord
754
817
  # - format_type includes the column size constraint, e.g. varchar(50)
755
818
  # - ::regclass is a function that gives the id for a table name
756
819
  def column_definitions(table_name)
757
- query(<<-end_sql, "SCHEMA")
820
+ query(<<~SQL, "SCHEMA")
758
821
  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
759
822
  pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
760
823
  c.collname, col_description(a.attrelid, a.attnum) AS comment
@@ -765,7 +828,7 @@ module ActiveRecord
765
828
  WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
766
829
  AND a.attnum > 0 AND NOT a.attisdropped
767
830
  ORDER BY a.attnum
768
- end_sql
831
+ SQL
769
832
  end
770
833
 
771
834
  def extract_table_ref_from_insert_sql(sql)
@@ -777,10 +840,14 @@ module ActiveRecord
777
840
  Arel::Visitors::PostgreSQL.new(self)
778
841
  end
779
842
 
843
+ def build_statement_pool
844
+ StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
845
+ end
846
+
780
847
  def can_perform_case_insensitive_comparison_for?(column)
781
848
  @case_insensitive_cache ||= {}
782
849
  @case_insensitive_cache[column.sql_type] ||= begin
783
- sql = <<-end_sql
850
+ sql = <<~SQL
784
851
  SELECT exists(
785
852
  SELECT * FROM pg_proc
786
853
  WHERE proname = 'lower'
@@ -792,7 +859,7 @@ module ActiveRecord
792
859
  WHERE proname = 'lower'
793
860
  AND castsource = #{quote column.sql_type}::regtype
794
861
  )
795
- end_sql
862
+ SQL
796
863
  execute_and_clear(sql, "SCHEMA", []) do |result|
797
864
  result.getvalue(0, 0)
798
865
  end
@@ -807,7 +874,22 @@ module ActiveRecord
807
874
  @connection.type_map_for_queries = map
808
875
  end
809
876
 
877
+ def update_typemap_for_default_timezone
878
+ if @default_timezone != ActiveRecord::Base.default_timezone && @timestamp_decoder
879
+ decoder_class = ActiveRecord::Base.default_timezone == :utc ?
880
+ PG::TextDecoder::TimestampUtc :
881
+ PG::TextDecoder::TimestampWithoutTimeZone
882
+
883
+ @timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
884
+ @connection.type_map_for_results.add_coder(@timestamp_decoder)
885
+ @default_timezone = ActiveRecord::Base.default_timezone
886
+ end
887
+ end
888
+
810
889
  def add_pg_decoders
890
+ @default_timezone = nil
891
+ @timestamp_decoder = nil
892
+
811
893
  coders_by_name = {
812
894
  "int2" => PG::TextDecoder::Integer,
813
895
  "int4" => PG::TextDecoder::Integer,
@@ -815,10 +897,14 @@ module ActiveRecord
815
897
  "oid" => PG::TextDecoder::Integer,
816
898
  "float4" => PG::TextDecoder::Float,
817
899
  "float8" => PG::TextDecoder::Float,
900
+ "numeric" => PG::TextDecoder::Numeric,
818
901
  "bool" => PG::TextDecoder::Boolean,
902
+ "timestamp" => PG::TextDecoder::TimestampUtc,
903
+ "timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
819
904
  }
905
+
820
906
  known_coder_types = coders_by_name.keys.map { |n| quote(n) }
821
- query = <<-SQL % known_coder_types.join(", ")
907
+ query = <<~SQL % known_coder_types.join(", ")
822
908
  SELECT t.oid, t.typname
823
909
  FROM pg_type as t
824
910
  WHERE t.typname IN (%s)
@@ -832,6 +918,15 @@ module ActiveRecord
832
918
  map = PG::TypeMapByOid.new
833
919
  coders.each { |coder| map.add_coder(coder) }
834
920
  @connection.type_map_for_results = map
921
+
922
+ @type_map_for_results = PG::TypeMapByOid.new
923
+ @type_map_for_results.default_type_map = map
924
+ @type_map_for_results.add_coder(PG::TextDecoder::Bytea.new(oid: 17, name: "bytea"))
925
+ @type_map_for_results.add_coder(MoneyDecoder.new(oid: 790, name: "money"))
926
+
927
+ # extract timestamp decoder for use in update_typemap_for_default_timezone
928
+ @timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
929
+ update_typemap_for_default_timezone
835
930
  end
836
931
 
837
932
  def construct_coder(row, coder_class)
@@ -839,6 +934,14 @@ module ActiveRecord
839
934
  coder_class.new(oid: row["oid"].to_i, name: row["typname"])
840
935
  end
841
936
 
937
+ class MoneyDecoder < PG::SimpleDecoder # :nodoc:
938
+ TYPE = OID::Money.new
939
+
940
+ def decode(value, tuple = nil, field = nil)
941
+ TYPE.deserialize(value)
942
+ end
943
+ end
944
+
842
945
  ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
843
946
  ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
844
947
  ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
@@ -851,6 +954,7 @@ module ActiveRecord
851
954
  ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
852
955
  ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
853
956
  ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
957
+ ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
854
958
  ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
855
959
  ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
856
960
  ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)