activerecord 5.2.8.1 → 6.1.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1347 -624
  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 +16 -7
  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 +107 -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 +73 -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 +225 -121
  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 +341 -99
  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 +4 -4
  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 +113 -74
  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 +478 -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 +94 -10
  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 +291 -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 +118 -32
  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
@@ -214,21 +247,14 @@ module ActiveRecord
214
247
  def initialize(connection, logger, connection_parameters, config)
215
248
  super(connection, logger, config)
216
249
 
217
- @connection_parameters = connection_parameters
250
+ @connection_parameters = connection_parameters || {}
218
251
 
219
252
  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
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)