activerecord 4.2.8 → 6.0.0

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