activerecord 5.0.6 → 6.0.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 (358) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +638 -2023
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +8 -6
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record/aggregations.rb +249 -246
  8. data/lib/active_record/association_relation.rb +24 -13
  9. data/lib/active_record/associations/alias_tracker.rb +24 -33
  10. data/lib/active_record/associations/association.rb +119 -56
  11. data/lib/active_record/associations/association_scope.rb +94 -94
  12. data/lib/active_record/associations/belongs_to_association.rb +58 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  14. data/lib/active_record/associations/builder/association.rb +18 -25
  15. data/lib/active_record/associations/builder/belongs_to.rb +43 -54
  16. data/lib/active_record/associations/builder/collection_association.rb +7 -18
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -61
  18. data/lib/active_record/associations/builder/has_many.rb +4 -0
  19. data/lib/active_record/associations/builder/has_one.rb +37 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  21. data/lib/active_record/associations/collection_association.rb +80 -252
  22. data/lib/active_record/associations/collection_proxy.rb +158 -121
  23. data/lib/active_record/associations/foreign_association.rb +9 -0
  24. data/lib/active_record/associations/has_many_association.rb +23 -29
  25. data/lib/active_record/associations/has_many_through_association.rb +58 -44
  26. data/lib/active_record/associations/has_one_association.rb +59 -54
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +38 -90
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -176
  32. data/lib/active_record/associations/preloader/association.rb +84 -125
  33. data/lib/active_record/associations/preloader/through_association.rb +82 -75
  34. data/lib/active_record/associations/preloader.rb +90 -102
  35. data/lib/active_record/associations/singular_association.rb +12 -45
  36. data/lib/active_record/associations/through_association.rb +26 -14
  37. data/lib/active_record/associations.rb +1603 -1592
  38. data/lib/active_record/attribute_assignment.rb +54 -60
  39. data/lib/active_record/attribute_decorators.rb +38 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +179 -109
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -91
  43. data/lib/active_record/attribute_methods/query.rb +4 -3
  44. data/lib/active_record/attribute_methods/read.rb +21 -49
  45. data/lib/active_record/attribute_methods/serialization.rb +30 -7
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
  47. data/lib/active_record/attribute_methods/write.rb +35 -33
  48. data/lib/active_record/attribute_methods.rb +66 -106
  49. data/lib/active_record/attributes.rb +38 -24
  50. data/lib/active_record/autosave_association.rb +53 -32
  51. data/lib/active_record/base.rb +27 -24
  52. data/lib/active_record/callbacks.rb +63 -33
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -11
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
  68. data/lib/active_record/connection_adapters/column.rb +41 -13
  69. data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
  71. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +143 -49
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -45
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -54
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -10
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  98. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +31 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -30
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -4
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +35 -32
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -275
  116. data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +254 -262
  126. data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
  127. data/lib/active_record/connection_handling.rb +159 -40
  128. data/lib/active_record/core.rb +202 -162
  129. data/lib/active_record/counter_cache.rb +57 -28
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +87 -86
  136. data/lib/active_record/enum.rb +60 -23
  137. data/lib/active_record/errors.rb +114 -18
  138. data/lib/active_record/explain.rb +4 -3
  139. data/lib/active_record/explain_registry.rb +3 -1
  140. data/lib/active_record/explain_subscriber.rb +9 -4
  141. data/lib/active_record/fixture_set/file.rb +13 -8
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +195 -502
  147. data/lib/active_record/gem_version.rb +4 -2
  148. data/lib/active_record/inheritance.rb +151 -97
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +116 -25
  151. data/lib/active_record/internal_metadata.rb +15 -18
  152. data/lib/active_record/legacy_yaml_adapter.rb +4 -2
  153. data/lib/active_record/locking/optimistic.rb +78 -87
  154. data/lib/active_record/locking/pessimistic.rb +18 -6
  155. data/lib/active_record/log_subscriber.rb +48 -29
  156. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  157. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/migration/command_recorder.rb +143 -97
  160. data/lib/active_record/migration/compatibility.rb +174 -56
  161. data/lib/active_record/migration/join_table.rb +8 -6
  162. data/lib/active_record/migration.rb +367 -300
  163. data/lib/active_record/model_schema.rb +145 -139
  164. data/lib/active_record/nested_attributes.rb +214 -201
  165. data/lib/active_record/no_touching.rb +10 -1
  166. data/lib/active_record/null_relation.rb +13 -34
  167. data/lib/active_record/persistence.rb +442 -72
  168. data/lib/active_record/query_cache.rb +15 -14
  169. data/lib/active_record/querying.rb +36 -23
  170. data/lib/active_record/railtie.rb +128 -36
  171. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  172. data/lib/active_record/railties/console_sandbox.rb +2 -0
  173. data/lib/active_record/railties/controller_runtime.rb +34 -33
  174. data/lib/active_record/railties/databases.rake +309 -177
  175. data/lib/active_record/readonly_attributes.rb +5 -4
  176. data/lib/active_record/reflection.rb +211 -249
  177. data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
  178. data/lib/active_record/relation/batches.rb +99 -52
  179. data/lib/active_record/relation/calculations.rb +211 -172
  180. data/lib/active_record/relation/delegation.rb +67 -65
  181. data/lib/active_record/relation/finder_methods.rb +208 -247
  182. data/lib/active_record/relation/from_clause.rb +2 -8
  183. data/lib/active_record/relation/merger.rb +78 -61
  184. data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
  185. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  186. data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
  187. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  188. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  189. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  190. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  191. data/lib/active_record/relation/predicate_builder.rb +86 -104
  192. data/lib/active_record/relation/query_attribute.rb +33 -2
  193. data/lib/active_record/relation/query_methods.rb +458 -329
  194. data/lib/active_record/relation/record_fetch_warning.rb +5 -3
  195. data/lib/active_record/relation/spawn_methods.rb +8 -7
  196. data/lib/active_record/relation/where_clause.rb +111 -95
  197. data/lib/active_record/relation/where_clause_factory.rb +6 -11
  198. data/lib/active_record/relation.rb +429 -318
  199. data/lib/active_record/result.rb +69 -39
  200. data/lib/active_record/runtime_registry.rb +5 -3
  201. data/lib/active_record/sanitization.rb +83 -99
  202. data/lib/active_record/schema.rb +7 -14
  203. data/lib/active_record/schema_dumper.rb +71 -69
  204. data/lib/active_record/schema_migration.rb +15 -5
  205. data/lib/active_record/scoping/default.rb +93 -95
  206. data/lib/active_record/scoping/named.rb +45 -25
  207. data/lib/active_record/scoping.rb +20 -19
  208. data/lib/active_record/secure_token.rb +4 -2
  209. data/lib/active_record/serialization.rb +2 -0
  210. data/lib/active_record/statement_cache.rb +63 -28
  211. data/lib/active_record/store.rb +121 -41
  212. data/lib/active_record/suppressor.rb +4 -1
  213. data/lib/active_record/table_metadata.rb +26 -20
  214. data/lib/active_record/tasks/database_tasks.rb +276 -85
  215. data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
  216. data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
  217. data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
  218. data/lib/active_record/test_databases.rb +23 -0
  219. data/lib/active_record/test_fixtures.rb +224 -0
  220. data/lib/active_record/timestamp.rb +70 -35
  221. data/lib/active_record/touch_later.rb +7 -4
  222. data/lib/active_record/transactions.rb +133 -149
  223. data/lib/active_record/translation.rb +3 -1
  224. data/lib/active_record/type/adapter_specific_registry.rb +44 -45
  225. data/lib/active_record/type/date.rb +2 -0
  226. data/lib/active_record/type/date_time.rb +2 -0
  227. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  228. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  229. data/lib/active_record/type/internal/timezone.rb +2 -0
  230. data/lib/active_record/type/json.rb +30 -0
  231. data/lib/active_record/type/serialized.rb +16 -8
  232. data/lib/active_record/type/text.rb +11 -0
  233. data/lib/active_record/type/time.rb +2 -1
  234. data/lib/active_record/type/type_map.rb +13 -15
  235. data/lib/active_record/type/unsigned_integer.rb +17 -0
  236. data/lib/active_record/type.rb +23 -17
  237. data/lib/active_record/type_caster/connection.rb +17 -12
  238. data/lib/active_record/type_caster/map.rb +5 -4
  239. data/lib/active_record/type_caster.rb +4 -2
  240. data/lib/active_record/validations/absence.rb +2 -0
  241. data/lib/active_record/validations/associated.rb +3 -1
  242. data/lib/active_record/validations/length.rb +2 -0
  243. data/lib/active_record/validations/presence.rb +4 -2
  244. data/lib/active_record/validations/uniqueness.rb +29 -42
  245. data/lib/active_record/validations.rb +7 -4
  246. data/lib/active_record/version.rb +3 -1
  247. data/lib/active_record.rb +36 -22
  248. data/lib/arel/alias_predication.rb +9 -0
  249. data/lib/arel/attributes/attribute.rb +37 -0
  250. data/lib/arel/attributes.rb +22 -0
  251. data/lib/arel/collectors/bind.rb +24 -0
  252. data/lib/arel/collectors/composite.rb +31 -0
  253. data/lib/arel/collectors/plain_string.rb +20 -0
  254. data/lib/arel/collectors/sql_string.rb +20 -0
  255. data/lib/arel/collectors/substitute_binds.rb +28 -0
  256. data/lib/arel/crud.rb +42 -0
  257. data/lib/arel/delete_manager.rb +18 -0
  258. data/lib/arel/errors.rb +9 -0
  259. data/lib/arel/expressions.rb +29 -0
  260. data/lib/arel/factory_methods.rb +49 -0
  261. data/lib/arel/insert_manager.rb +49 -0
  262. data/lib/arel/math.rb +45 -0
  263. data/lib/arel/nodes/and.rb +32 -0
  264. data/lib/arel/nodes/ascending.rb +23 -0
  265. data/lib/arel/nodes/binary.rb +52 -0
  266. data/lib/arel/nodes/bind_param.rb +36 -0
  267. data/lib/arel/nodes/case.rb +55 -0
  268. data/lib/arel/nodes/casted.rb +50 -0
  269. data/lib/arel/nodes/comment.rb +29 -0
  270. data/lib/arel/nodes/count.rb +12 -0
  271. data/lib/arel/nodes/delete_statement.rb +45 -0
  272. data/lib/arel/nodes/descending.rb +23 -0
  273. data/lib/arel/nodes/equality.rb +18 -0
  274. data/lib/arel/nodes/extract.rb +24 -0
  275. data/lib/arel/nodes/false.rb +16 -0
  276. data/lib/arel/nodes/full_outer_join.rb +8 -0
  277. data/lib/arel/nodes/function.rb +44 -0
  278. data/lib/arel/nodes/grouping.rb +8 -0
  279. data/lib/arel/nodes/in.rb +8 -0
  280. data/lib/arel/nodes/infix_operation.rb +80 -0
  281. data/lib/arel/nodes/inner_join.rb +8 -0
  282. data/lib/arel/nodes/insert_statement.rb +37 -0
  283. data/lib/arel/nodes/join_source.rb +20 -0
  284. data/lib/arel/nodes/matches.rb +18 -0
  285. data/lib/arel/nodes/named_function.rb +23 -0
  286. data/lib/arel/nodes/node.rb +50 -0
  287. data/lib/arel/nodes/node_expression.rb +13 -0
  288. data/lib/arel/nodes/outer_join.rb +8 -0
  289. data/lib/arel/nodes/over.rb +15 -0
  290. data/lib/arel/nodes/regexp.rb +16 -0
  291. data/lib/arel/nodes/right_outer_join.rb +8 -0
  292. data/lib/arel/nodes/select_core.rb +67 -0
  293. data/lib/arel/nodes/select_statement.rb +41 -0
  294. data/lib/arel/nodes/sql_literal.rb +16 -0
  295. data/lib/arel/nodes/string_join.rb +11 -0
  296. data/lib/arel/nodes/table_alias.rb +27 -0
  297. data/lib/arel/nodes/terminal.rb +16 -0
  298. data/lib/arel/nodes/true.rb +16 -0
  299. data/lib/arel/nodes/unary.rb +45 -0
  300. data/lib/arel/nodes/unary_operation.rb +20 -0
  301. data/lib/arel/nodes/unqualified_column.rb +22 -0
  302. data/lib/arel/nodes/update_statement.rb +41 -0
  303. data/lib/arel/nodes/values_list.rb +9 -0
  304. data/lib/arel/nodes/window.rb +126 -0
  305. data/lib/arel/nodes/with.rb +11 -0
  306. data/lib/arel/nodes.rb +68 -0
  307. data/lib/arel/order_predications.rb +13 -0
  308. data/lib/arel/predications.rb +257 -0
  309. data/lib/arel/select_manager.rb +271 -0
  310. data/lib/arel/table.rb +110 -0
  311. data/lib/arel/tree_manager.rb +72 -0
  312. data/lib/arel/update_manager.rb +34 -0
  313. data/lib/arel/visitors/depth_first.rb +204 -0
  314. data/lib/arel/visitors/dot.rb +297 -0
  315. data/lib/arel/visitors/ibm_db.rb +34 -0
  316. data/lib/arel/visitors/informix.rb +62 -0
  317. data/lib/arel/visitors/mssql.rb +157 -0
  318. data/lib/arel/visitors/mysql.rb +83 -0
  319. data/lib/arel/visitors/oracle.rb +159 -0
  320. data/lib/arel/visitors/oracle12.rb +66 -0
  321. data/lib/arel/visitors/postgresql.rb +110 -0
  322. data/lib/arel/visitors/sqlite.rb +39 -0
  323. data/lib/arel/visitors/to_sql.rb +889 -0
  324. data/lib/arel/visitors/visitor.rb +46 -0
  325. data/lib/arel/visitors/where_sql.rb +23 -0
  326. data/lib/arel/visitors.rb +20 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +58 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
  332. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
  334. data/lib/rails/generators/active_record/migration.rb +17 -2
  335. data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
  336. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  337. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +133 -50
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  348. data/lib/active_record/attribute.rb +0 -213
  349. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  350. data/lib/active_record/attribute_set/builder.rb +0 -130
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/collection_cache_key.rb +0 -50
  353. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  354. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  355. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  356. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  357. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  358. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,20 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
2
- gem 'pg', '~> 0.18'
3
- require 'pg'
4
+ gem "pg", ">= 0.18", "< 2.0"
5
+ require "pg"
6
+
7
+ # Use async_exec instead of exec_params on pg versions before 1.1
8
+ class ::PG::Connection # :nodoc:
9
+ unless self.public_method_defined?(:async_exec_params)
10
+ remove_method :exec_params
11
+ alias exec_params async_exec
12
+ end
13
+ end
4
14
 
5
15
  require "active_record/connection_adapters/abstract_adapter"
16
+ require "active_record/connection_adapters/statement_pool"
6
17
  require "active_record/connection_adapters/postgresql/column"
7
18
  require "active_record/connection_adapters/postgresql/database_statements"
8
19
  require "active_record/connection_adapters/postgresql/explain_pretty_printer"
9
20
  require "active_record/connection_adapters/postgresql/oid"
10
21
  require "active_record/connection_adapters/postgresql/quoting"
11
22
  require "active_record/connection_adapters/postgresql/referential_integrity"
23
+ require "active_record/connection_adapters/postgresql/schema_creation"
12
24
  require "active_record/connection_adapters/postgresql/schema_definitions"
13
25
  require "active_record/connection_adapters/postgresql/schema_dumper"
14
26
  require "active_record/connection_adapters/postgresql/schema_statements"
15
27
  require "active_record/connection_adapters/postgresql/type_metadata"
16
28
  require "active_record/connection_adapters/postgresql/utils"
17
- require "active_record/connection_adapters/statement_pool"
18
29
 
19
30
  module ActiveRecord
20
31
  module ConnectionHandling # :nodoc:
@@ -32,9 +43,14 @@ module ActiveRecord
32
43
  valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
33
44
  conn_params.slice!(*valid_conn_param_keys)
34
45
 
35
- # The postgres drivers don't allow the creation of an unconnected PG::Connection object,
36
- # so just pass a nil connection object for the time being.
37
- ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)
46
+ conn = PG.connect(conn_params)
47
+ ConnectionAdapters::PostgreSQLAdapter.new(conn, logger, conn_params, config)
48
+ rescue ::PG::Error => error
49
+ if error.message.include?(conn_params[:dbname])
50
+ raise ActiveRecord::NoDatabaseError
51
+ else
52
+ raise
53
+ end
38
54
  end
39
55
  end
40
56
 
@@ -61,19 +77,32 @@ module ActiveRecord
61
77
  # defaults to true.
62
78
  #
63
79
  # Any further options are used as connection parameters to libpq. See
64
- # http://www.postgresql.org/docs/current/static/libpq-connect.html for the
80
+ # https://www.postgresql.org/docs/current/static/libpq-connect.html for the
65
81
  # list of parameters.
66
82
  #
67
83
  # In addition, default connection parameters of libpq can be set per environment variables.
68
- # See http://www.postgresql.org/docs/current/static/libpq-envars.html .
84
+ # See https://www.postgresql.org/docs/current/static/libpq-envars.html .
69
85
  class PostgreSQLAdapter < AbstractAdapter
70
- ADAPTER_NAME = 'PostgreSQL'.freeze
86
+ ADAPTER_NAME = "PostgreSQL"
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
71
100
 
72
101
  NATIVE_DATABASE_TYPES = {
73
- primary_key: "serial primary key",
102
+ primary_key: "bigserial primary key",
74
103
  string: { name: "character varying" },
75
104
  text: { name: "text" },
76
- integer: { name: "integer" },
105
+ integer: { name: "integer", limit: 4 },
77
106
  float: { name: "float" },
78
107
  decimal: { name: "decimal" },
79
108
  datetime: { name: "timestamp" },
@@ -108,6 +137,8 @@ module ActiveRecord
108
137
  bit: { name: "bit" },
109
138
  bit_varying: { name: "bit varying" },
110
139
  money: { name: "money" },
140
+ interval: { name: "interval" },
141
+ oid: { name: "oid" },
111
142
  }
112
143
 
113
144
  OID = PostgreSQL::OID #:nodoc:
@@ -116,19 +147,8 @@ module ActiveRecord
116
147
  include PostgreSQL::ReferentialIntegrity
117
148
  include PostgreSQL::SchemaStatements
118
149
  include PostgreSQL::DatabaseStatements
119
- include PostgreSQL::ColumnDumper
120
-
121
- def schema_creation # :nodoc:
122
- PostgreSQL::SchemaCreation.new self
123
- end
124
-
125
- def arel_visitor # :nodoc:
126
- Arel::Visitors::PostgreSQL.new(self)
127
- end
128
150
 
129
- # Returns true, since this connection adapter supports prepared statement
130
- # caching.
131
- def supports_statement_cache?
151
+ def supports_bulk_alter?
132
152
  true
133
153
  end
134
154
 
@@ -152,6 +172,10 @@ module ActiveRecord
152
172
  true
153
173
  end
154
174
 
175
+ def supports_validate_constraints?
176
+ true
177
+ end
178
+
155
179
  def supports_views?
156
180
  true
157
181
  end
@@ -161,7 +185,7 @@ module ActiveRecord
161
185
  end
162
186
 
163
187
  def supports_json?
164
- postgresql_version >= 90200
188
+ true
165
189
  end
166
190
 
167
191
  def supports_comments?
@@ -172,11 +196,22 @@ module ActiveRecord
172
196
  true
173
197
  end
174
198
 
199
+ def supports_insert_returning?
200
+ true
201
+ end
202
+
203
+ def supports_insert_on_conflict?
204
+ database_version >= 90500
205
+ end
206
+ alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
207
+ alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
208
+ alias supports_insert_conflict_target? supports_insert_on_conflict?
209
+
175
210
  def index_algorithms
176
- { concurrently: 'CONCURRENTLY' }
211
+ { concurrently: "CONCURRENTLY" }
177
212
  end
178
213
 
179
- class StatementPool < ConnectionAdapters::StatementPool
214
+ class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
180
215
  def initialize(connection, max)
181
216
  super(max)
182
217
  @connection = connection
@@ -192,9 +227,9 @@ module ActiveRecord
192
227
  end
193
228
 
194
229
  private
195
-
196
230
  def dealloc(key)
197
231
  @connection.query "DEALLOCATE #{key}" if connection_active?
232
+ rescue PG::Error
198
233
  end
199
234
 
200
235
  def connection_active?
@@ -212,37 +247,29 @@ module ActiveRecord
212
247
 
213
248
  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
214
249
  @local_tz = nil
215
- @table_alias_length = nil
250
+ @max_identifier_length = nil
216
251
 
217
- connect
252
+ configure_connection
218
253
  add_pg_encoders
219
- @statements = StatementPool.new @connection,
220
- self.class.type_cast_config_to_integer(config[:statement_limit])
221
-
222
- if postgresql_version < 90100
223
- raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
224
- end
225
-
226
254
  add_pg_decoders
227
255
 
228
256
  @type_map = Type::HashLookupTypeMap.new
229
- initialize_type_map(type_map)
230
- @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
257
+ initialize_type_map
258
+ @local_tz = execute("SHOW TIME ZONE", "SCHEMA").first["TimeZone"]
231
259
  @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
232
260
  end
233
261
 
234
- # Clears the prepared statements cache.
235
- def clear_cache!
236
- @statements.clear
237
- end
238
-
239
- def truncate(table_name, name = nil)
240
- exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, []
262
+ def self.database_exists?(config)
263
+ !!ActiveRecord::Base.postgresql_connection(config)
264
+ rescue ActiveRecord::NoDatabaseError
265
+ false
241
266
  end
242
267
 
243
268
  # Is this connection alive and ready for queries?
244
269
  def active?
245
- @connection.query 'SELECT 1'
270
+ @lock.synchronize do
271
+ @connection.query "SELECT 1"
272
+ end
246
273
  true
247
274
  rescue PG::Error
248
275
  false
@@ -250,44 +277,48 @@ module ActiveRecord
250
277
 
251
278
  # Close then reopen the connection.
252
279
  def reconnect!
253
- super
254
- @connection.reset
255
- configure_connection
280
+ @lock.synchronize do
281
+ super
282
+ @connection.reset
283
+ configure_connection
284
+ rescue PG::ConnectionBad
285
+ connect
286
+ end
256
287
  end
257
288
 
258
289
  def reset!
259
- clear_cache!
260
- reset_transaction
261
- unless @connection.transaction_status == ::PG::PQTRANS_IDLE
262
- @connection.query 'ROLLBACK'
290
+ @lock.synchronize do
291
+ clear_cache!
292
+ reset_transaction
293
+ unless @connection.transaction_status == ::PG::PQTRANS_IDLE
294
+ @connection.query "ROLLBACK"
295
+ end
296
+ @connection.query "DISCARD ALL"
297
+ configure_connection
263
298
  end
264
- @connection.query 'DISCARD ALL'
265
- configure_connection
266
299
  end
267
300
 
268
301
  # Disconnects from the database if already connected. Otherwise, this
269
302
  # method does nothing.
270
303
  def disconnect!
304
+ @lock.synchronize do
305
+ super
306
+ @connection.close rescue nil
307
+ end
308
+ end
309
+
310
+ def discard! # :nodoc:
271
311
  super
272
- @connection.close rescue nil
312
+ @connection.socket_io.reopen(IO::NULL) rescue nil
313
+ @connection = nil
273
314
  end
274
315
 
275
316
  def native_database_types #:nodoc:
276
317
  NATIVE_DATABASE_TYPES
277
318
  end
278
319
 
279
- # Returns true, since this connection adapter supports migrations.
280
- def supports_migrations?
281
- true
282
- end
283
-
284
- # Does PostgreSQL support finding primary key on non-Active Record tables?
285
- def supports_primary_key? #:nodoc:
286
- true
287
- end
288
-
289
320
  def set_standard_conforming_strings
290
- execute('SET standard_conforming_strings = on', 'SCHEMA')
321
+ execute("SET standard_conforming_strings = on", "SCHEMA")
291
322
  end
292
323
 
293
324
  def supports_ddl_transactions?
@@ -306,27 +337,50 @@ module ActiveRecord
306
337
  true
307
338
  end
308
339
 
309
- # Range datatypes weren't introduced until PostgreSQL 9.2
310
340
  def supports_ranges?
311
- postgresql_version >= 90200
341
+ true
312
342
  end
343
+ deprecate :supports_ranges?
313
344
 
314
345
  def supports_materialized_views?
315
- postgresql_version >= 90300
346
+ true
347
+ end
348
+
349
+ def supports_foreign_tables?
350
+ true
351
+ end
352
+
353
+ def supports_pgcrypto_uuid?
354
+ database_version >= 90400
355
+ end
356
+
357
+ def supports_optimizer_hints?
358
+ unless defined?(@has_pg_hint_plan)
359
+ @has_pg_hint_plan = extension_available?("pg_hint_plan")
360
+ end
361
+ @has_pg_hint_plan
362
+ end
363
+
364
+ def supports_common_table_expressions?
365
+ true
366
+ end
367
+
368
+ def supports_lazy_transactions?
369
+ true
316
370
  end
317
371
 
318
372
  def get_advisory_lock(lock_id) # :nodoc:
319
373
  unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
320
- raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
374
+ raise(ArgumentError, "PostgreSQL requires advisory lock ids to be a signed 64 bit integer")
321
375
  end
322
- select_value("SELECT pg_try_advisory_lock(#{lock_id});")
376
+ query_value("SELECT pg_try_advisory_lock(#{lock_id})")
323
377
  end
324
378
 
325
379
  def release_advisory_lock(lock_id) # :nodoc:
326
380
  unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
327
- raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
381
+ raise(ArgumentError, "PostgreSQL requires advisory lock ids to be a signed 64 bit integer")
328
382
  end
329
- select_value("SELECT pg_advisory_unlock(#{lock_id})")
383
+ query_value("SELECT pg_advisory_unlock(#{lock_id})")
330
384
  end
331
385
 
332
386
  def enable_extension(name)
@@ -341,50 +395,33 @@ module ActiveRecord
341
395
  }
342
396
  end
343
397
 
398
+ def extension_available?(name)
399
+ query_value("SELECT true FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
400
+ end
401
+
344
402
  def extension_enabled?(name)
345
- if supports_extensions?
346
- res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled",
347
- 'SCHEMA'
348
- res.cast_values.first
349
- end
403
+ query_value("SELECT installed_version IS NOT NULL FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
350
404
  end
351
405
 
352
406
  def extensions
353
- if supports_extensions?
354
- exec_query("SELECT extname from pg_extension", "SCHEMA").cast_values
355
- else
356
- super
357
- end
407
+ exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values
358
408
  end
359
409
 
360
410
  # Returns the configured supported identifier length supported by PostgreSQL
361
- def table_alias_length
362
- @table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i
411
+ def max_identifier_length
412
+ @max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
363
413
  end
364
414
 
365
415
  # Set the authorized user for this session
366
416
  def session_auth=(user)
367
417
  clear_cache!
368
- exec_query "SET SESSION AUTHORIZATION #{user}"
418
+ execute("SET SESSION AUTHORIZATION #{user}")
369
419
  end
370
420
 
371
421
  def use_insert_returning?
372
422
  @use_insert_returning
373
423
  end
374
424
 
375
- def valid_type?(type)
376
- !native_database_types[type].nil?
377
- end
378
-
379
- def update_table_definition(table_name, base) #:nodoc:
380
- PostgreSQL::Table.new(table_name, base)
381
- end
382
-
383
- def lookup_cast_type(sql_type) # :nodoc:
384
- oid = execute("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").first['oid'].to_i
385
- super(oid)
386
- end
387
-
388
425
  def column_name_for_operation(operation, node) # :nodoc:
389
426
  OPERATION_ALIASES.fetch(operation) { operation.downcase }
390
427
  end
@@ -396,93 +433,136 @@ module ActiveRecord
396
433
  }
397
434
 
398
435
  # Returns the version of the connected PostgreSQL server.
399
- def postgresql_version
436
+ def get_database_version # :nodoc:
400
437
  @connection.server_version
401
438
  end
439
+ alias :postgresql_version :database_version
440
+
441
+ def default_index_type?(index) # :nodoc:
442
+ index.using == :btree || super
443
+ end
444
+
445
+ def build_insert_sql(insert) # :nodoc:
446
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
447
+
448
+ if insert.skip_duplicates?
449
+ sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
450
+ elsif insert.update_duplicates?
451
+ sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
452
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
453
+ end
454
+
455
+ sql << " RETURNING #{insert.returning}" if insert.returning
456
+ sql
457
+ end
402
458
 
403
- protected
459
+ def check_version # :nodoc:
460
+ if database_version < 90300
461
+ raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
462
+ end
463
+ end
404
464
 
405
- # See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
465
+ private
466
+
467
+ # See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
406
468
  VALUE_LIMIT_VIOLATION = "22001"
469
+ NUMERIC_VALUE_OUT_OF_RANGE = "22003"
470
+ NOT_NULL_VIOLATION = "23502"
407
471
  FOREIGN_KEY_VIOLATION = "23503"
408
472
  UNIQUE_VIOLATION = "23505"
473
+ SERIALIZATION_FAILURE = "40001"
474
+ DEADLOCK_DETECTED = "40P01"
475
+ LOCK_NOT_AVAILABLE = "55P03"
476
+ QUERY_CANCELED = "57014"
409
477
 
410
- def translate_exception(exception, message)
478
+ def translate_exception(exception, message:, sql:, binds:)
411
479
  return exception unless exception.respond_to?(:result)
412
480
 
413
481
  case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
414
482
  when UNIQUE_VIOLATION
415
- RecordNotUnique.new(message)
483
+ RecordNotUnique.new(message, sql: sql, binds: binds)
416
484
  when FOREIGN_KEY_VIOLATION
417
- InvalidForeignKey.new(message)
485
+ InvalidForeignKey.new(message, sql: sql, binds: binds)
418
486
  when VALUE_LIMIT_VIOLATION
419
- ValueTooLong.new(message)
487
+ ValueTooLong.new(message, sql: sql, binds: binds)
488
+ when NUMERIC_VALUE_OUT_OF_RANGE
489
+ RangeError.new(message, sql: sql, binds: binds)
490
+ when NOT_NULL_VIOLATION
491
+ NotNullViolation.new(message, sql: sql, binds: binds)
492
+ when SERIALIZATION_FAILURE
493
+ SerializationFailure.new(message, sql: sql, binds: binds)
494
+ when DEADLOCK_DETECTED
495
+ Deadlocked.new(message, sql: sql, binds: binds)
496
+ when LOCK_NOT_AVAILABLE
497
+ LockWaitTimeout.new(message, sql: sql, binds: binds)
498
+ when QUERY_CANCELED
499
+ QueryCanceled.new(message, sql: sql, binds: binds)
420
500
  else
421
501
  super
422
502
  end
423
503
  end
424
504
 
425
- private
426
-
427
- def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
505
+ def get_oid_type(oid, fmod, column_name, sql_type = "")
428
506
  if !type_map.key?(oid)
429
- load_additional_types(type_map, [oid])
507
+ load_additional_types([oid])
430
508
  end
431
509
 
432
510
  type_map.fetch(oid, fmod, sql_type) {
433
511
  warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
434
- Type::Value.new.tap do |cast_type|
512
+ Type.default_value.tap do |cast_type|
435
513
  type_map.register_type(oid, cast_type)
436
514
  end
437
515
  }
438
516
  end
439
517
 
440
- def initialize_type_map(m) # :nodoc:
441
- register_class_with_limit m, 'int2', Type::Integer
442
- register_class_with_limit m, 'int4', Type::Integer
443
- register_class_with_limit m, 'int8', Type::Integer
444
- m.alias_type 'oid', 'int2'
445
- m.register_type 'float4', Type::Float.new
446
- m.alias_type 'float8', 'float4'
447
- m.register_type 'text', Type::Text.new
448
- register_class_with_limit m, 'varchar', Type::String
449
- m.alias_type 'char', 'varchar'
450
- m.alias_type 'name', 'varchar'
451
- m.alias_type 'bpchar', 'varchar'
452
- m.register_type 'bool', Type::Boolean.new
453
- register_class_with_limit m, 'bit', OID::Bit
454
- register_class_with_limit m, 'varbit', OID::BitVarying
455
- m.alias_type 'timestamptz', 'timestamp'
456
- m.register_type 'date', Type::Date.new
457
-
458
- m.register_type 'money', OID::Money.new
459
- m.register_type 'bytea', OID::Bytea.new
460
- m.register_type 'point', OID::Point.new
461
- m.register_type 'hstore', OID::Hstore.new
462
- m.register_type 'json', OID::Json.new
463
- m.register_type 'jsonb', OID::Jsonb.new
464
- m.register_type 'cidr', OID::Cidr.new
465
- m.register_type 'inet', OID::Inet.new
466
- m.register_type 'uuid', OID::Uuid.new
467
- m.register_type 'xml', OID::Xml.new
468
- m.register_type 'tsvector', OID::SpecializedString.new(:tsvector)
469
- m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
470
- m.register_type 'citext', OID::SpecializedString.new(:citext)
471
- m.register_type 'ltree', OID::SpecializedString.new(:ltree)
472
- m.register_type 'line', OID::SpecializedString.new(:line)
473
- m.register_type 'lseg', OID::SpecializedString.new(:lseg)
474
- m.register_type 'box', OID::SpecializedString.new(:box)
475
- m.register_type 'path', OID::SpecializedString.new(:path)
476
- m.register_type 'polygon', OID::SpecializedString.new(:polygon)
477
- m.register_type 'circle', OID::SpecializedString.new(:circle)
478
-
479
- # FIXME: why are we keeping these types as strings?
480
- m.alias_type 'interval', 'varchar'
481
-
482
- register_class_with_precision m, 'time', Type::Time
483
- register_class_with_precision m, 'timestamp', OID::DateTime
484
-
485
- m.register_type 'numeric' do |_, fmod, sql_type|
518
+ def initialize_type_map(m = type_map)
519
+ m.register_type "int2", Type::Integer.new(limit: 2)
520
+ m.register_type "int4", Type::Integer.new(limit: 4)
521
+ m.register_type "int8", Type::Integer.new(limit: 8)
522
+ m.register_type "oid", OID::Oid.new
523
+ m.register_type "float4", Type::Float.new
524
+ m.alias_type "float8", "float4"
525
+ m.register_type "text", Type::Text.new
526
+ register_class_with_limit m, "varchar", Type::String
527
+ m.alias_type "char", "varchar"
528
+ m.alias_type "name", "varchar"
529
+ m.alias_type "bpchar", "varchar"
530
+ m.register_type "bool", Type::Boolean.new
531
+ register_class_with_limit m, "bit", OID::Bit
532
+ register_class_with_limit m, "varbit", OID::BitVarying
533
+ m.alias_type "timestamptz", "timestamp"
534
+ m.register_type "date", OID::Date.new
535
+
536
+ m.register_type "money", OID::Money.new
537
+ m.register_type "bytea", OID::Bytea.new
538
+ m.register_type "point", OID::Point.new
539
+ m.register_type "hstore", OID::Hstore.new
540
+ m.register_type "json", Type::Json.new
541
+ m.register_type "jsonb", OID::Jsonb.new
542
+ m.register_type "cidr", OID::Cidr.new
543
+ m.register_type "inet", OID::Inet.new
544
+ m.register_type "uuid", OID::Uuid.new
545
+ m.register_type "xml", OID::Xml.new
546
+ m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
547
+ m.register_type "macaddr", OID::SpecializedString.new(:macaddr)
548
+ m.register_type "citext", OID::SpecializedString.new(:citext)
549
+ m.register_type "ltree", OID::SpecializedString.new(:ltree)
550
+ m.register_type "line", OID::SpecializedString.new(:line)
551
+ m.register_type "lseg", OID::SpecializedString.new(:lseg)
552
+ m.register_type "box", OID::SpecializedString.new(:box)
553
+ m.register_type "path", OID::SpecializedString.new(:path)
554
+ m.register_type "polygon", OID::SpecializedString.new(:polygon)
555
+ m.register_type "circle", OID::SpecializedString.new(:circle)
556
+
557
+ m.register_type "interval" do |_, _, sql_type|
558
+ precision = extract_precision(sql_type)
559
+ OID::SpecializedString.new(:interval, precision: precision)
560
+ end
561
+
562
+ register_class_with_precision m, "time", Type::Time
563
+ register_class_with_precision m, "timestamp", OID::DateTime
564
+
565
+ m.register_type "numeric" do |_, fmod, sql_type|
486
566
  precision = extract_precision(sql_type)
487
567
  scale = extract_scale(sql_type)
488
568
 
@@ -502,78 +582,60 @@ module ActiveRecord
502
582
  end
503
583
  end
504
584
 
505
- load_additional_types(m)
506
- end
507
-
508
- def extract_limit(sql_type) # :nodoc:
509
- case sql_type
510
- when /^bigint/i, /^int8/i
511
- 8
512
- when /^smallint/i
513
- 2
514
- else
515
- super
516
- end
585
+ load_additional_types
517
586
  end
518
587
 
519
588
  # Extracts the value from a PostgreSQL column default definition.
520
- def extract_value_from_default(default) # :nodoc:
589
+ def extract_value_from_default(default)
521
590
  case default
522
591
  # Quoted types
523
- when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
524
- # The default 'now'::date is CURRENT_DATE
525
- if $1 == "now".freeze && $2 == "date".freeze
526
- nil
527
- else
528
- $1.gsub("''".freeze, "'".freeze)
529
- end
592
+ when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
593
+ # The default 'now'::date is CURRENT_DATE
594
+ if $1 == "now" && $2 == "date"
595
+ nil
596
+ else
597
+ $1.gsub("''", "'")
598
+ end
530
599
  # Boolean types
531
- when 'true'.freeze, 'false'.freeze
532
- default
600
+ when "true", "false"
601
+ default
533
602
  # Numeric types
534
- when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
535
- $1
603
+ when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
604
+ $1
536
605
  # Object identifier types
537
- when /\A-?\d+\z/
538
- $1
539
- else
540
- # Anything else is blank, some user type, or some function
541
- # and we can't know the value of that, so return nil.
542
- nil
606
+ when /\A-?\d+\z/
607
+ $1
608
+ else
609
+ # Anything else is blank, some user type, or some function
610
+ # and we can't know the value of that, so return nil.
611
+ nil
543
612
  end
544
613
  end
545
614
 
546
- def extract_default_function(default_value, default) # :nodoc:
615
+ def extract_default_function(default_value, default)
547
616
  default if has_default_function?(default_value, default)
548
617
  end
549
618
 
550
- def has_default_function?(default_value, default) # :nodoc:
551
- !default_value && (%r{\w+\(.*\)|\(.*\)::\w+} === default)
619
+ def has_default_function?(default_value, default)
620
+ !default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
552
621
  end
553
622
 
554
- def load_additional_types(type_map, oids = nil) # :nodoc:
623
+ def load_additional_types(oids = nil)
555
624
  initializer = OID::TypeMapInitializer.new(type_map)
556
625
 
557
- if supports_ranges?
558
- query = <<-SQL
559
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
560
- FROM pg_type as t
561
- LEFT JOIN pg_range as r ON oid = rngtypid
562
- SQL
563
- else
564
- query = <<-SQL
565
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
566
- FROM pg_type as t
567
- SQL
568
- end
626
+ query = <<~SQL
627
+ SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
628
+ FROM pg_type as t
629
+ LEFT JOIN pg_range as r ON oid = rngtypid
630
+ SQL
569
631
 
570
632
  if oids
571
633
  query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
572
634
  else
573
- query += initializer.query_conditions_for_initial_load(type_map)
635
+ query += initializer.query_conditions_for_initial_load
574
636
  end
575
637
 
576
- execute_and_clear(query, 'SCHEMA', []) do |records|
638
+ execute_and_clear(query, "SCHEMA", []) do |records|
577
639
  initializer.run(records)
578
640
  end
579
641
  end
@@ -581,6 +643,10 @@ module ActiveRecord
581
643
  FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
582
644
 
583
645
  def execute_and_clear(sql, name, binds, prepare: false)
646
+ if preventing_writes? && write_query?(sql)
647
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
648
+ end
649
+
584
650
  if without_prepared_statement?(binds)
585
651
  result = exec_no_cache(sql, name, [])
586
652
  elsif !prepare
@@ -594,16 +660,31 @@ module ActiveRecord
594
660
  end
595
661
 
596
662
  def exec_no_cache(sql, name, binds)
663
+ materialize_transactions
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
+
597
669
  type_casted_binds = type_casted_binds(binds)
598
- log(sql, name, binds, type_casted_binds) { @connection.async_exec(sql, type_casted_binds) }
670
+ log(sql, name, binds, type_casted_binds) do
671
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
672
+ @connection.exec_params(sql, type_casted_binds)
673
+ end
674
+ end
599
675
  end
600
676
 
601
677
  def exec_cache(sql, name, binds)
602
- stmt_key = prepare_statement(sql)
678
+ materialize_transactions
679
+ update_typemap_for_default_timezone
680
+
681
+ stmt_key = prepare_statement(sql, binds)
603
682
  type_casted_binds = type_casted_binds(binds)
604
683
 
605
684
  log(sql, name, binds, type_casted_binds, stmt_key) do
606
- @connection.exec_prepared(stmt_key, type_casted_binds)
685
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
686
+ @connection.exec_prepared(stmt_key, type_casted_binds)
687
+ end
607
688
  end
608
689
  rescue ActiveRecord::StatementInvalid => e
609
690
  raise unless is_cached_plan_failure?(e)
@@ -613,8 +694,10 @@ module ActiveRecord
613
694
  if in_transaction?
614
695
  raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
615
696
  else
616
- # outside of transactions we can simply flush this query and retry
617
- @statements.delete sql_key(sql)
697
+ @lock.synchronize do
698
+ # outside of transactions we can simply flush this query and retry
699
+ @statements.delete sql_key(sql)
700
+ end
618
701
  retry
619
702
  end
620
703
  end
@@ -627,8 +710,8 @@ module ActiveRecord
627
710
  # ActiveRecord::PreparedStatementCacheExpired
628
711
  #
629
712
  # Check here for more details:
630
- # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
631
- CACHED_PLAN_HEURISTIC = 'cached plan must not change result type'.freeze
713
+ # https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
714
+ CACHED_PLAN_HEURISTIC = "cached plan must not change result type"
632
715
  def is_cached_plan_failure?(e)
633
716
  pgerror = e.cause
634
717
  code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
@@ -649,20 +732,22 @@ module ActiveRecord
649
732
 
650
733
  # Prepare the statement if it hasn't been prepared, return
651
734
  # the statement key.
652
- def prepare_statement(sql)
653
- sql_key = sql_key(sql)
654
- unless @statements.key? sql_key
655
- nextkey = @statements.next_key
656
- begin
657
- @connection.prepare nextkey, sql
658
- rescue => e
659
- raise translate_exception_class(e, sql)
735
+ def prepare_statement(sql, binds)
736
+ @lock.synchronize do
737
+ sql_key = sql_key(sql)
738
+ unless @statements.key? sql_key
739
+ nextkey = @statements.next_key
740
+ begin
741
+ @connection.prepare nextkey, sql
742
+ rescue => e
743
+ raise translate_exception_class(e, sql, binds)
744
+ end
745
+ # Clear the queue
746
+ @connection.get_last_result
747
+ @statements[sql_key] = nextkey
660
748
  end
661
- # Clear the queue
662
- @connection.get_last_result
663
- @statements[sql_key] = nextkey
749
+ @statements[sql_key]
664
750
  end
665
- @statements[sql_key]
666
751
  end
667
752
 
668
753
  # Connects to a PostgreSQL server and sets up the adapter depending on the
@@ -670,12 +755,8 @@ module ActiveRecord
670
755
  def connect
671
756
  @connection = PG.connect(@connection_parameters)
672
757
  configure_connection
673
- rescue ::PG::Error => error
674
- if error.message.include?("does not exist")
675
- raise ActiveRecord::NoDatabaseError
676
- else
677
- raise
678
- end
758
+ add_pg_encoders
759
+ add_pg_decoders
679
760
  end
680
761
 
681
762
  # Configures the encoding, verbosity, schema search path, and time zone of the connection.
@@ -684,39 +765,36 @@ module ActiveRecord
684
765
  if @config[:encoding]
685
766
  @connection.set_client_encoding(@config[:encoding])
686
767
  end
687
- self.client_min_messages = @config[:min_messages] || 'warning'
768
+ self.client_min_messages = @config[:min_messages] || "warning"
688
769
  self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
689
770
 
690
771
  # Use standard-conforming strings so we don't have to do the E'...' dance.
691
772
  set_standard_conforming_strings
692
773
 
774
+ variables = @config.fetch(:variables, {}).stringify_keys
775
+
693
776
  # If using Active Record's time zone support configure the connection to return
694
777
  # TIMESTAMP WITH ZONE types in UTC.
695
- # (SET TIME ZONE does not use an equals sign like other SET variables)
696
- if ActiveRecord::Base.default_timezone == :utc
697
- execute("SET time zone 'UTC'", 'SCHEMA')
698
- elsif @local_tz
699
- execute("SET time zone '#{@local_tz}'", 'SCHEMA')
778
+ unless variables["timezone"]
779
+ if ActiveRecord::Base.default_timezone == :utc
780
+ variables["timezone"] = "UTC"
781
+ elsif @local_tz
782
+ variables["timezone"] = @local_tz
783
+ end
700
784
  end
701
785
 
702
786
  # SET statements from :variables config hash
703
- # http://www.postgresql.org/docs/current/static/sql-set.html
704
- variables = @config[:variables] || {}
787
+ # https://www.postgresql.org/docs/current/static/sql-set.html
705
788
  variables.map do |k, v|
706
- if v == ':default' || v == :default
789
+ if v == ":default" || v == :default
707
790
  # Sets the value to the global or compile default
708
- execute("SET SESSION #{k} TO DEFAULT", 'SCHEMA')
791
+ execute("SET SESSION #{k} TO DEFAULT", "SCHEMA")
709
792
  elsif !v.nil?
710
- execute("SET SESSION #{k} TO #{quote(v)}", 'SCHEMA')
793
+ execute("SET SESSION #{k} TO #{quote(v)}", "SCHEMA")
711
794
  end
712
795
  end
713
796
  end
714
797
 
715
- # Returns the current ID of a table's sequence.
716
- def last_insert_id_result(sequence_name) # :nodoc:
717
- exec_query("SELECT currval('#{sequence_name}')", 'SQL')
718
- end
719
-
720
798
  # Returns the list of a table's column names, data types, and default values.
721
799
  #
722
800
  # The underlying query is roughly:
@@ -735,34 +813,38 @@ module ActiveRecord
735
813
  # Query implementation notes:
736
814
  # - format_type includes the column size constraint, e.g. varchar(50)
737
815
  # - ::regclass is a function that gives the id for a table name
738
- def column_definitions(table_name) # :nodoc:
739
- query(<<-end_sql, 'SCHEMA')
816
+ def column_definitions(table_name)
817
+ query(<<~SQL, "SCHEMA")
740
818
  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
741
819
  pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
742
- (SELECT c.collname FROM pg_collation c, pg_type t
743
- WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation),
744
- col_description(a.attrelid, a.attnum) AS comment
745
- FROM pg_attribute a LEFT JOIN pg_attrdef d
746
- ON a.attrelid = d.adrelid AND a.attnum = d.adnum
747
- WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
820
+ c.collname, col_description(a.attrelid, a.attnum) AS comment
821
+ FROM pg_attribute a
822
+ LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
823
+ LEFT JOIN pg_type t ON a.atttypid = t.oid
824
+ LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
825
+ WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
748
826
  AND a.attnum > 0 AND NOT a.attisdropped
749
827
  ORDER BY a.attnum
750
- end_sql
828
+ SQL
751
829
  end
752
830
 
753
- def extract_table_ref_from_insert_sql(sql) # :nodoc:
831
+ def extract_table_ref_from_insert_sql(sql)
754
832
  sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
755
833
  $1.strip if $1
756
834
  end
757
835
 
758
- def create_table_definition(*args) # :nodoc:
759
- PostgreSQL::TableDefinition.new(*args)
836
+ def arel_visitor
837
+ Arel::Visitors::PostgreSQL.new(self)
838
+ end
839
+
840
+ def build_statement_pool
841
+ StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
760
842
  end
761
843
 
762
844
  def can_perform_case_insensitive_comparison_for?(column)
763
845
  @case_insensitive_cache ||= {}
764
846
  @case_insensitive_cache[column.sql_type] ||= begin
765
- sql = <<-end_sql
847
+ sql = <<~SQL
766
848
  SELECT exists(
767
849
  SELECT * FROM pg_proc
768
850
  WHERE proname = 'lower'
@@ -774,7 +856,7 @@ module ActiveRecord
774
856
  WHERE proname = 'lower'
775
857
  AND castsource = #{quote column.sql_type}::regtype
776
858
  )
777
- end_sql
859
+ SQL
778
860
  execute_and_clear(sql, "SCHEMA", []) do |result|
779
861
  result.getvalue(0, 0)
780
862
  end
@@ -786,40 +868,65 @@ module ActiveRecord
786
868
  map[Integer] = PG::TextEncoder::Integer.new
787
869
  map[TrueClass] = PG::TextEncoder::Boolean.new
788
870
  map[FalseClass] = PG::TextEncoder::Boolean.new
789
- map[Float] = PG::TextEncoder::Float.new
790
871
  @connection.type_map_for_queries = map
791
872
  end
792
873
 
874
+ def update_typemap_for_default_timezone
875
+ if @default_timezone != ActiveRecord::Base.default_timezone && @timestamp_decoder
876
+ decoder_class = ActiveRecord::Base.default_timezone == :utc ?
877
+ PG::TextDecoder::TimestampUtc :
878
+ PG::TextDecoder::TimestampWithoutTimeZone
879
+
880
+ @timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
881
+ @connection.type_map_for_results.add_coder(@timestamp_decoder)
882
+ @default_timezone = ActiveRecord::Base.default_timezone
883
+ end
884
+ end
885
+
793
886
  def add_pg_decoders
887
+ @default_timezone = nil
888
+ @timestamp_decoder = nil
889
+
794
890
  coders_by_name = {
795
- 'int2' => PG::TextDecoder::Integer,
796
- 'int4' => PG::TextDecoder::Integer,
797
- 'int8' => PG::TextDecoder::Integer,
798
- 'oid' => PG::TextDecoder::Integer,
799
- 'float4' => PG::TextDecoder::Float,
800
- 'float8' => PG::TextDecoder::Float,
801
- 'bool' => PG::TextDecoder::Boolean,
891
+ "int2" => PG::TextDecoder::Integer,
892
+ "int4" => PG::TextDecoder::Integer,
893
+ "int8" => PG::TextDecoder::Integer,
894
+ "oid" => PG::TextDecoder::Integer,
895
+ "float4" => PG::TextDecoder::Float,
896
+ "float8" => PG::TextDecoder::Float,
897
+ "bool" => PG::TextDecoder::Boolean,
802
898
  }
899
+
900
+ if defined?(PG::TextDecoder::TimestampUtc)
901
+ # Use native PG encoders available since pg-1.1
902
+ coders_by_name["timestamp"] = PG::TextDecoder::TimestampUtc
903
+ coders_by_name["timestamptz"] = PG::TextDecoder::TimestampWithTimeZone
904
+ end
905
+
803
906
  known_coder_types = coders_by_name.keys.map { |n| quote(n) }
804
- query = <<-SQL % known_coder_types.join(", ")
907
+ query = <<~SQL % known_coder_types.join(", ")
805
908
  SELECT t.oid, t.typname
806
909
  FROM pg_type as t
807
910
  WHERE t.typname IN (%s)
808
911
  SQL
809
912
  coders = execute_and_clear(query, "SCHEMA", []) do |result|
810
913
  result
811
- .map { |row| construct_coder(row, coders_by_name[row['typname']]) }
914
+ .map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
812
915
  .compact
813
916
  end
814
917
 
815
918
  map = PG::TypeMapByOid.new
816
919
  coders.each { |coder| map.add_coder(coder) }
817
920
  @connection.type_map_for_results = map
921
+
922
+ # extract timestamp decoder for use in update_typemap_for_default_timezone
923
+ @timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
924
+ update_typemap_for_default_timezone
818
925
  end
819
926
 
820
927
  def construct_coder(row, coder_class)
821
928
  return unless coder_class
822
- coder_class.new(oid: row['oid'].to_i, name: row['typname'])
929
+ coder_class.new(oid: row["oid"].to_i, name: row["typname"])
823
930
  end
824
931
 
825
932
  ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
@@ -828,16 +935,16 @@ module ActiveRecord
828
935
  ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
829
936
  ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
830
937
  ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
938
+ ActiveRecord::Type.register(:date, OID::Date, adapter: :postgresql)
831
939
  ActiveRecord::Type.register(:datetime, OID::DateTime, adapter: :postgresql)
832
940
  ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
833
941
  ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
834
942
  ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
835
943
  ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
836
- ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
837
944
  ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
838
945
  ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
839
- ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql)
840
- ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql)
946
+ ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
947
+ ActiveRecord::Type.register(:legacy_point, OID::LegacyPoint, adapter: :postgresql)
841
948
  ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
842
949
  ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
843
950
  ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)