activerecord 4.2.0 → 6.0.5.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 (373) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +852 -801
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +14 -13
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/advisory_lock_base.rb +18 -0
  8. data/lib/active_record/aggregations.rb +267 -249
  9. data/lib/active_record/association_relation.rb +26 -6
  10. data/lib/active_record/associations/alias_tracker.rb +29 -36
  11. data/lib/active_record/associations/association.rb +137 -55
  12. data/lib/active_record/associations/association_scope.rb +110 -132
  13. data/lib/active_record/associations/belongs_to_association.rb +67 -54
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  15. data/lib/active_record/associations/builder/association.rb +27 -40
  16. data/lib/active_record/associations/builder/belongs_to.rb +69 -55
  17. data/lib/active_record/associations/builder/collection_association.rb +10 -29
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +58 -70
  19. data/lib/active_record/associations/builder/has_many.rb +8 -4
  20. data/lib/active_record/associations/builder/has_one.rb +46 -5
  21. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  22. data/lib/active_record/associations/collection_association.rb +150 -275
  23. data/lib/active_record/associations/collection_proxy.rb +253 -152
  24. data/lib/active_record/associations/foreign_association.rb +20 -0
  25. data/lib/active_record/associations/has_many_association.rb +35 -84
  26. data/lib/active_record/associations/has_many_through_association.rb +62 -80
  27. data/lib/active_record/associations/has_one_association.rb +62 -49
  28. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  29. data/lib/active_record/associations/join_dependency/join_association.rb +43 -78
  30. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  31. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  32. data/lib/active_record/associations/join_dependency.rb +159 -162
  33. data/lib/active_record/associations/preloader/association.rb +102 -113
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  35. data/lib/active_record/associations/preloader.rb +96 -95
  36. data/lib/active_record/associations/singular_association.rb +18 -45
  37. data/lib/active_record/associations/through_association.rb +49 -24
  38. data/lib/active_record/associations.rb +1737 -1596
  39. data/lib/active_record/attribute_assignment.rb +57 -185
  40. data/lib/active_record/attribute_decorators.rb +39 -17
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +14 -5
  42. data/lib/active_record/attribute_methods/dirty.rb +174 -134
  43. data/lib/active_record/attribute_methods/primary_key.rb +90 -84
  44. data/lib/active_record/attribute_methods/query.rb +6 -5
  45. data/lib/active_record/attribute_methods/read.rb +20 -77
  46. data/lib/active_record/attribute_methods/serialization.rb +40 -21
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -37
  48. data/lib/active_record/attribute_methods/write.rb +33 -56
  49. data/lib/active_record/attribute_methods.rb +124 -143
  50. data/lib/active_record/attributes.rb +213 -74
  51. data/lib/active_record/autosave_association.rb +125 -54
  52. data/lib/active_record/base.rb +60 -49
  53. data/lib/active_record/callbacks.rb +101 -76
  54. data/lib/active_record/coders/json.rb +3 -1
  55. data/lib/active_record/coders/yaml_column.rb +36 -13
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +810 -291
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +253 -108
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -24
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +171 -53
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -47
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +383 -239
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +736 -235
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +190 -87
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -192
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +536 -600
  69. data/lib/active_record/connection_adapters/column.rb +56 -43
  70. data/lib/active_record/connection_adapters/connection_specification.rb +174 -153
  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 +196 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +71 -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 +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -196
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +71 -115
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -5
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  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 +49 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +465 -291
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +565 -363
  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 +119 -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 +102 -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 +299 -364
  127. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  128. data/lib/active_record/connection_handling.rb +167 -41
  129. data/lib/active_record/core.rb +277 -233
  130. data/lib/active_record/counter_cache.rb +71 -50
  131. data/lib/active_record/database_configurations/database_config.rb +37 -0
  132. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  133. data/lib/active_record/database_configurations/url_config.rb +78 -0
  134. data/lib/active_record/database_configurations.rb +233 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +87 -106
  137. data/lib/active_record/enum.rb +172 -89
  138. data/lib/active_record/errors.rb +189 -53
  139. data/lib/active_record/explain.rb +22 -11
  140. data/lib/active_record/explain_registry.rb +4 -2
  141. data/lib/active_record/explain_subscriber.rb +11 -6
  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 +152 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  147. data/lib/active_record/fixtures.rb +225 -497
  148. data/lib/active_record/gem_version.rb +6 -4
  149. data/lib/active_record/inheritance.rb +158 -115
  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 +48 -0
  154. data/lib/active_record/locale/en.yml +3 -2
  155. data/lib/active_record/locking/optimistic.rb +99 -98
  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/resolver/session.rb +45 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  160. data/lib/active_record/middleware/database_selector.rb +74 -0
  161. data/lib/active_record/migration/command_recorder.rb +166 -91
  162. data/lib/active_record/migration/compatibility.rb +244 -0
  163. data/lib/active_record/migration/join_table.rb +8 -7
  164. data/lib/active_record/migration.rb +636 -290
  165. data/lib/active_record/model_schema.rb +344 -112
  166. data/lib/active_record/nested_attributes.rb +265 -215
  167. data/lib/active_record/no_touching.rb +15 -2
  168. data/lib/active_record/null_relation.rb +24 -38
  169. data/lib/active_record/persistence.rb +559 -125
  170. data/lib/active_record/query_cache.rb +19 -23
  171. data/lib/active_record/querying.rb +44 -30
  172. data/lib/active_record/railtie.rb +166 -47
  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 +341 -202
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +461 -302
  179. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  180. data/lib/active_record/relation/batches.rb +206 -55
  181. data/lib/active_record/relation/calculations.rb +270 -249
  182. data/lib/active_record/relation/delegation.rb +76 -84
  183. data/lib/active_record/relation/finder_methods.rb +287 -255
  184. data/lib/active_record/relation/from_clause.rb +30 -0
  185. data/lib/active_record/relation/merger.rb +86 -68
  186. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -25
  187. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  188. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  189. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  190. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  191. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  192. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  193. data/lib/active_record/relation/predicate_builder.rb +112 -92
  194. data/lib/active_record/relation/query_attribute.rb +50 -0
  195. data/lib/active_record/relation/query_methods.rb +612 -392
  196. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  197. data/lib/active_record/relation/spawn_methods.rb +18 -17
  198. data/lib/active_record/relation/where_clause.rb +189 -0
  199. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  200. data/lib/active_record/relation.rb +533 -340
  201. data/lib/active_record/result.rb +79 -43
  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 -20
  207. data/lib/active_record/scoping/default.rb +98 -82
  208. data/lib/active_record/scoping/named.rb +91 -33
  209. data/lib/active_record/scoping.rb +45 -27
  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 +90 -0
  216. data/lib/active_record/tasks/database_tasks.rb +309 -99
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +58 -89
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -31
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +37 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +243 -0
  222. data/lib/active_record/timestamp.rb +86 -41
  223. data/lib/active_record/touch_later.rb +65 -0
  224. data/lib/active_record/transactions.rb +222 -146
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  227. data/lib/active_record/type/date.rb +4 -41
  228. data/lib/active_record/type/date_time.rb +4 -38
  229. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  230. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  231. data/lib/active_record/type/internal/timezone.rb +17 -0
  232. data/lib/active_record/type/json.rb +30 -0
  233. data/lib/active_record/type/serialized.rb +29 -15
  234. data/lib/active_record/type/text.rb +2 -2
  235. data/lib/active_record/type/time.rb +21 -16
  236. data/lib/active_record/type/type_map.rb +16 -19
  237. data/lib/active_record/type/unsigned_integer.rb +9 -8
  238. data/lib/active_record/type.rb +77 -23
  239. data/lib/active_record/type_caster/connection.rb +34 -0
  240. data/lib/active_record/type_caster/map.rb +20 -0
  241. data/lib/active_record/type_caster.rb +9 -0
  242. data/lib/active_record/validations/absence.rb +25 -0
  243. data/lib/active_record/validations/associated.rb +12 -4
  244. data/lib/active_record/validations/length.rb +26 -0
  245. data/lib/active_record/validations/presence.rb +14 -13
  246. data/lib/active_record/validations/uniqueness.rb +43 -46
  247. data/lib/active_record/validations.rb +38 -35
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/active_record.rb +44 -21
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes/attribute.rb +37 -0
  252. data/lib/arel/attributes.rb +22 -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/and.rb +32 -0
  266. data/lib/arel/nodes/ascending.rb +23 -0
  267. data/lib/arel/nodes/binary.rb +52 -0
  268. data/lib/arel/nodes/bind_param.rb +36 -0
  269. data/lib/arel/nodes/case.rb +55 -0
  270. data/lib/arel/nodes/casted.rb +50 -0
  271. data/lib/arel/nodes/comment.rb +29 -0
  272. data/lib/arel/nodes/count.rb +12 -0
  273. data/lib/arel/nodes/delete_statement.rb +45 -0
  274. data/lib/arel/nodes/descending.rb +23 -0
  275. data/lib/arel/nodes/equality.rb +18 -0
  276. data/lib/arel/nodes/extract.rb +24 -0
  277. data/lib/arel/nodes/false.rb +16 -0
  278. data/lib/arel/nodes/full_outer_join.rb +8 -0
  279. data/lib/arel/nodes/function.rb +44 -0
  280. data/lib/arel/nodes/grouping.rb +8 -0
  281. data/lib/arel/nodes/in.rb +8 -0
  282. data/lib/arel/nodes/infix_operation.rb +80 -0
  283. data/lib/arel/nodes/inner_join.rb +8 -0
  284. data/lib/arel/nodes/insert_statement.rb +37 -0
  285. data/lib/arel/nodes/join_source.rb +20 -0
  286. data/lib/arel/nodes/matches.rb +18 -0
  287. data/lib/arel/nodes/named_function.rb +23 -0
  288. data/lib/arel/nodes/node.rb +50 -0
  289. data/lib/arel/nodes/node_expression.rb +13 -0
  290. data/lib/arel/nodes/outer_join.rb +8 -0
  291. data/lib/arel/nodes/over.rb +15 -0
  292. data/lib/arel/nodes/regexp.rb +16 -0
  293. data/lib/arel/nodes/right_outer_join.rb +8 -0
  294. data/lib/arel/nodes/select_core.rb +67 -0
  295. data/lib/arel/nodes/select_statement.rb +41 -0
  296. data/lib/arel/nodes/sql_literal.rb +16 -0
  297. data/lib/arel/nodes/string_join.rb +11 -0
  298. data/lib/arel/nodes/table_alias.rb +27 -0
  299. data/lib/arel/nodes/terminal.rb +16 -0
  300. data/lib/arel/nodes/true.rb +16 -0
  301. data/lib/arel/nodes/unary.rb +45 -0
  302. data/lib/arel/nodes/unary_operation.rb +20 -0
  303. data/lib/arel/nodes/unqualified_column.rb +22 -0
  304. data/lib/arel/nodes/update_statement.rb +41 -0
  305. data/lib/arel/nodes/values_list.rb +9 -0
  306. data/lib/arel/nodes/window.rb +126 -0
  307. data/lib/arel/nodes/with.rb +11 -0
  308. data/lib/arel/nodes.rb +68 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +256 -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/depth_first.rb +203 -0
  316. data/lib/arel/visitors/dot.rb +296 -0
  317. data/lib/arel/visitors/ibm_db.rb +34 -0
  318. data/lib/arel/visitors/informix.rb +62 -0
  319. data/lib/arel/visitors/mssql.rb +156 -0
  320. data/lib/arel/visitors/mysql.rb +83 -0
  321. data/lib/arel/visitors/oracle.rb +158 -0
  322. data/lib/arel/visitors/oracle12.rb +65 -0
  323. data/lib/arel/visitors/postgresql.rb +109 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +888 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/visitors/where_sql.rb +22 -0
  328. data/lib/arel/visitors.rb +20 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/arel.rb +62 -0
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -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/migration_generator.rb +42 -37
  334. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  335. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -8
  336. data/lib/rails/generators/active_record/migration.rb +30 -1
  337. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record.rb +7 -5
  340. metadata +174 -63
  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 -149
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  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/integer.rb +0 -11
  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 -30
  362. data/lib/active_record/type/decimal.rb +0 -40
  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 -55
  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 -36
  369. data/lib/active_record/type/time_value.rb +0 -38
  370. data/lib/active_record/type/value.rb +0 -101
  371. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  372. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  373. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,40 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
- class SchemaCreation < AbstractAdapter::SchemaCreation
5
- private
6
-
7
- def visit_ColumnDefinition(o)
8
- sql = super
9
- if o.primary_key? && o.type != :primary_key
10
- sql << " PRIMARY KEY "
11
- add_column_options!(sql, column_options(o))
12
- end
13
- sql
14
- end
15
-
16
- def add_column_options!(sql, options)
17
- if options[:array] || options[:column].try(:array)
18
- sql << '[]'
19
- end
20
-
21
- column = options.fetch(:column) { return super }
22
- if column.type == :uuid && options[:default] =~ /\(\)/
23
- sql << " DEFAULT #{options[:default]}"
24
- else
25
- super
26
- end
27
- end
28
-
29
- def type_for_column(column)
30
- if column.array
31
- @conn.lookup_cast_type("#{column.sql_type}[]")
32
- else
33
- super
34
- end
35
- end
36
- end
37
-
38
6
  module SchemaStatements
39
7
  # Drops the database specified on the +name+ attribute
40
8
  # and creates it again using the provided +options+.
@@ -52,26 +20,26 @@ module ActiveRecord
52
20
  # create_database config[:database], config
53
21
  # create_database 'foo_development', encoding: 'unicode'
54
22
  def create_database(name, options = {})
55
- options = { encoding: 'utf8' }.merge!(options.symbolize_keys)
56
-
57
- option_string = options.inject("") do |memo, (key, value)|
58
- memo += case key
59
- when :owner
60
- " OWNER = \"#{value}\""
61
- when :template
62
- " TEMPLATE = \"#{value}\""
63
- when :encoding
64
- " ENCODING = '#{value}'"
65
- when :collation
66
- " LC_COLLATE = '#{value}'"
67
- when :ctype
68
- " LC_CTYPE = '#{value}'"
69
- when :tablespace
70
- " TABLESPACE = \"#{value}\""
71
- when :connection_limit
72
- " CONNECTION LIMIT = #{value}"
73
- else
74
- ""
23
+ options = { encoding: "utf8" }.merge!(options.symbolize_keys)
24
+
25
+ option_string = options.each_with_object(+"") do |(key, value), memo|
26
+ memo << case key
27
+ when :owner
28
+ " OWNER = \"#{value}\""
29
+ when :template
30
+ " TEMPLATE = \"#{value}\""
31
+ when :encoding
32
+ " ENCODING = '#{value}'"
33
+ when :collation
34
+ " LC_COLLATE = '#{value}'"
35
+ when :ctype
36
+ " LC_CTYPE = '#{value}'"
37
+ when :tablespace
38
+ " TABLESPACE = \"#{value}\""
39
+ when :connection_limit
40
+ " CONNECTION LIMIT = #{value}"
41
+ else
42
+ ""
75
43
  end
76
44
  end
77
45
 
@@ -86,150 +54,149 @@ module ActiveRecord
86
54
  execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
87
55
  end
88
56
 
89
- # Returns the list of all tables in the schema search path or a specified schema.
90
- def tables(name = nil)
91
- query(<<-SQL, 'SCHEMA').map { |row| row[0] }
92
- SELECT tablename
93
- FROM pg_tables
94
- WHERE schemaname = ANY (current_schemas(false))
95
- SQL
96
- end
97
-
98
- # Returns true if table exists.
99
- # If the schema is not specified as part of +name+ then it will only find tables within
100
- # the current schema search path (regardless of permissions to access tables in other schemas)
101
- def table_exists?(name)
102
- name = Utils.extract_schema_qualified_name(name.to_s)
103
- return false unless name.identifier
104
-
105
- exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
106
- SELECT COUNT(*)
107
- FROM pg_class c
108
- LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
109
- WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
110
- AND c.relname = '#{name.identifier}'
111
- AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
112
- SQL
113
- end
114
-
115
- def drop_table(table_name, options = {})
116
- execute "DROP TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
57
+ def drop_table(table_name, options = {}) # :nodoc:
58
+ execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
117
59
  end
118
60
 
119
61
  # Returns true if schema exists.
120
62
  def schema_exists?(name)
121
- exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
122
- SELECT COUNT(*)
123
- FROM pg_namespace
124
- WHERE nspname = '#{name}'
125
- SQL
63
+ query_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = #{quote(name)}", "SCHEMA").to_i > 0
126
64
  end
127
65
 
128
- def index_name_exists?(table_name, index_name, default)
129
- exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
66
+ # Verifies existence of an index with a given name.
67
+ def index_name_exists?(table_name, index_name)
68
+ table = quoted_scope(table_name)
69
+ index = quoted_scope(index_name)
70
+
71
+ query_value(<<~SQL, "SCHEMA").to_i > 0
130
72
  SELECT COUNT(*)
131
73
  FROM pg_class t
132
74
  INNER JOIN pg_index d ON t.oid = d.indrelid
133
75
  INNER JOIN pg_class i ON d.indexrelid = i.oid
134
- WHERE i.relkind = 'i'
135
- AND i.relname = '#{index_name}'
136
- AND t.relname = '#{table_name}'
137
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
76
+ LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
77
+ WHERE i.relkind IN ('i', 'I')
78
+ AND i.relname = #{index[:name]}
79
+ AND t.relname = #{table[:name]}
80
+ AND n.nspname = #{index[:schema]}
138
81
  SQL
139
82
  end
140
83
 
141
84
  # Returns an array of indexes for the given table.
142
- def indexes(table_name, name = nil)
143
- result = query(<<-SQL, 'SCHEMA')
144
- SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
145
- FROM pg_class t
146
- INNER JOIN pg_index d ON t.oid = d.indrelid
147
- INNER JOIN pg_class i ON d.indexrelid = i.oid
148
- WHERE i.relkind = 'i'
149
- AND d.indisprimary = 'f'
150
- AND t.relname = '#{table_name}'
151
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
85
+ def indexes(table_name) # :nodoc:
86
+ scope = quoted_scope(table_name)
87
+
88
+ result = query(<<~SQL, "SCHEMA")
89
+ SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
90
+ pg_catalog.obj_description(i.oid, 'pg_class') AS comment
91
+ FROM pg_class t
92
+ INNER JOIN pg_index d ON t.oid = d.indrelid
93
+ INNER JOIN pg_class i ON d.indexrelid = i.oid
94
+ LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
95
+ WHERE i.relkind IN ('i', 'I')
96
+ AND d.indisprimary = 'f'
97
+ AND t.relname = #{scope[:name]}
98
+ AND n.nspname = #{scope[:schema]}
152
99
  ORDER BY i.relname
153
100
  SQL
154
101
 
155
102
  result.map do |row|
156
103
  index_name = row[0]
157
- unique = row[1] == 't'
158
- indkey = row[2].split(" ")
104
+ unique = row[1]
105
+ indkey = row[2].split(" ").map(&:to_i)
159
106
  inddef = row[3]
160
107
  oid = row[4]
108
+ comment = row[5]
161
109
 
162
- columns = Hash[query(<<-SQL, "SCHEMA")]
163
- SELECT a.attnum, a.attname
164
- FROM pg_attribute a
165
- WHERE a.attrelid = #{oid}
166
- AND a.attnum IN (#{indkey.join(",")})
167
- SQL
168
-
169
- column_names = columns.values_at(*indkey).compact
110
+ using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/m).flatten
170
111
 
171
- unless column_names.empty?
172
- # add info on sort order for columns (only desc order is explicitly specified, asc is the default)
173
- desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
174
- orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {}
175
- where = inddef.scan(/WHERE (.+)$/).flatten[0]
176
- using = inddef.scan(/USING (.+?) /).flatten[0].to_sym
112
+ orders = {}
113
+ opclasses = {}
177
114
 
178
- IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where, nil, using)
115
+ if indkey.include?(0)
116
+ columns = expressions
117
+ else
118
+ columns = Hash[query(<<~SQL, "SCHEMA")].values_at(*indkey).compact
119
+ SELECT a.attnum, a.attname
120
+ FROM pg_attribute a
121
+ WHERE a.attrelid = #{oid}
122
+ AND a.attnum IN (#{indkey.join(",")})
123
+ SQL
124
+
125
+ # add info on sort order (only desc order is explicitly specified, asc is the default)
126
+ # and non-default opclasses
127
+ expressions.scan(/(?<column>\w+)"?\s?(?<opclass>\w+_ops)?\s?(?<desc>DESC)?\s?(?<nulls>NULLS (?:FIRST|LAST))?/).each do |column, opclass, desc, nulls|
128
+ opclasses[column] = opclass.to_sym if opclass
129
+ if nulls
130
+ orders[column] = [desc, nulls].compact.join(" ")
131
+ else
132
+ orders[column] = :desc if desc
133
+ end
134
+ end
179
135
  end
180
- end.compact
136
+
137
+ IndexDefinition.new(
138
+ table_name,
139
+ index_name,
140
+ unique,
141
+ columns,
142
+ orders: orders,
143
+ opclasses: opclasses,
144
+ where: where,
145
+ using: using.to_sym,
146
+ comment: comment.presence
147
+ )
148
+ end
181
149
  end
182
150
 
183
- # Returns the list of all column definitions for a table.
184
- def columns(table_name)
185
- # Limit, precision, and scale are all handled by the superclass.
186
- column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
187
- oid = get_oid_type(oid.to_i, fmod.to_i, column_name, type)
188
- default_value = extract_value_from_default(oid, default)
189
- default_function = extract_default_function(default_value, default)
190
- new_column(column_name, default_value, oid, type, notnull == 'f', default_function)
151
+ def table_options(table_name) # :nodoc:
152
+ if comment = table_comment(table_name)
153
+ { comment: comment }
191
154
  end
192
155
  end
193
156
 
194
- def new_column(name, default, cast_type, sql_type = nil, null = true, default_function = nil) # :nodoc:
195
- PostgreSQLColumn.new(name, default, cast_type, sql_type, null, default_function)
157
+ # Returns a comment stored in database for given table
158
+ def table_comment(table_name) # :nodoc:
159
+ scope = quoted_scope(table_name, type: "BASE TABLE")
160
+ if scope[:name]
161
+ query_value(<<~SQL, "SCHEMA")
162
+ SELECT pg_catalog.obj_description(c.oid, 'pg_class')
163
+ FROM pg_catalog.pg_class c
164
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
165
+ WHERE c.relname = #{scope[:name]}
166
+ AND c.relkind IN (#{scope[:type]})
167
+ AND n.nspname = #{scope[:schema]}
168
+ SQL
169
+ end
196
170
  end
197
171
 
198
172
  # Returns the current database name.
199
173
  def current_database
200
- query('select current_database()', 'SCHEMA')[0][0]
174
+ query_value("SELECT current_database()", "SCHEMA")
201
175
  end
202
176
 
203
177
  # Returns the current schema name.
204
178
  def current_schema
205
- query('SELECT current_schema', 'SCHEMA')[0][0]
179
+ query_value("SELECT current_schema", "SCHEMA")
206
180
  end
207
181
 
208
182
  # Returns the current database encoding format.
209
183
  def encoding
210
- query(<<-end_sql, 'SCHEMA')[0][0]
211
- SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database
212
- WHERE pg_database.datname LIKE '#{current_database}'
213
- end_sql
184
+ query_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = current_database()", "SCHEMA")
214
185
  end
215
186
 
216
187
  # Returns the current database collation.
217
188
  def collation
218
- query(<<-end_sql, 'SCHEMA')[0][0]
219
- SELECT pg_database.datcollate FROM pg_database WHERE pg_database.datname LIKE '#{current_database}'
220
- end_sql
189
+ query_value("SELECT datcollate FROM pg_database WHERE datname = current_database()", "SCHEMA")
221
190
  end
222
191
 
223
192
  # Returns the current database ctype.
224
193
  def ctype
225
- query(<<-end_sql, 'SCHEMA')[0][0]
226
- SELECT pg_database.datctype FROM pg_database WHERE pg_database.datname LIKE '#{current_database}'
227
- end_sql
194
+ query_value("SELECT datctype FROM pg_database WHERE datname = current_database()", "SCHEMA")
228
195
  end
229
196
 
230
197
  # Returns an array of schema names.
231
198
  def schema_names
232
- query(<<-SQL, 'SCHEMA').flatten
199
+ query_values(<<~SQL, "SCHEMA")
233
200
  SELECT nspname
234
201
  FROM pg_namespace
235
202
  WHERE nspname !~ '^pg_.*'
@@ -239,56 +206,53 @@ module ActiveRecord
239
206
  end
240
207
 
241
208
  # Creates a schema for the given schema name.
242
- def create_schema schema_name
243
- execute "CREATE SCHEMA #{schema_name}"
209
+ def create_schema(schema_name)
210
+ execute "CREATE SCHEMA #{quote_schema_name(schema_name)}"
244
211
  end
245
212
 
246
213
  # Drops the schema for the given schema name.
247
- def drop_schema schema_name
248
- execute "DROP SCHEMA #{schema_name} CASCADE"
214
+ def drop_schema(schema_name, options = {})
215
+ execute "DROP SCHEMA#{' IF EXISTS' if options[:if_exists]} #{quote_schema_name(schema_name)} CASCADE"
249
216
  end
250
217
 
251
218
  # Sets the schema search path to a string of comma-separated schema names.
252
219
  # Names beginning with $ have to be quoted (e.g. $user => '$user').
253
- # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
220
+ # See: https://www.postgresql.org/docs/current/static/ddl-schemas.html
254
221
  #
255
222
  # This should be not be called manually but set in database.yml.
256
223
  def schema_search_path=(schema_csv)
257
224
  if schema_csv
258
- execute("SET search_path TO #{schema_csv}", 'SCHEMA')
225
+ execute("SET search_path TO #{schema_csv}", "SCHEMA")
259
226
  @schema_search_path = schema_csv
260
227
  end
261
228
  end
262
229
 
263
230
  # Returns the active schema search path.
264
231
  def schema_search_path
265
- @schema_search_path ||= query('SHOW search_path', 'SCHEMA')[0][0]
232
+ @schema_search_path ||= query_value("SHOW search_path", "SCHEMA")
266
233
  end
267
234
 
268
235
  # Returns the current client message level.
269
236
  def client_min_messages
270
- query('SHOW client_min_messages', 'SCHEMA')[0][0]
237
+ query_value("SHOW client_min_messages", "SCHEMA")
271
238
  end
272
239
 
273
240
  # Set the client message level.
274
241
  def client_min_messages=(level)
275
- execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
242
+ execute("SET client_min_messages TO '#{level}'", "SCHEMA")
276
243
  end
277
244
 
278
245
  # Returns the sequence name for a table's primary key or some other specified key.
279
- def default_sequence_name(table_name, pk = nil) #:nodoc:
280
- result = serial_sequence(table_name, pk || 'id')
246
+ def default_sequence_name(table_name, pk = "id") #:nodoc:
247
+ result = serial_sequence(table_name, pk)
281
248
  return nil unless result
282
249
  Utils.extract_schema_qualified_name(result).to_s
283
250
  rescue ActiveRecord::StatementInvalid
284
- PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq").to_s
251
+ PostgreSQL::Name.new(nil, "#{table_name}_#{pk}_seq").to_s
285
252
  end
286
253
 
287
254
  def serial_sequence(table, column)
288
- result = exec_query(<<-eosql, 'SCHEMA')
289
- SELECT pg_get_serial_sequence('#{table}', '#{column}')
290
- eosql
291
- result.rows.first.first
255
+ query_value("SELECT pg_get_serial_sequence(#{quote(table)}, #{quote(column)})", "SCHEMA")
292
256
  end
293
257
 
294
258
  # Sets the sequence of a table's primary key to the specified value.
@@ -299,18 +263,16 @@ module ActiveRecord
299
263
  if sequence
300
264
  quoted_sequence = quote_table_name(sequence)
301
265
 
302
- select_value <<-end_sql, 'SCHEMA'
303
- SELECT setval('#{quoted_sequence}', #{value})
304
- end_sql
266
+ query_value("SELECT setval(#{quote(quoted_sequence)}, #{value})", "SCHEMA")
305
267
  else
306
- @logger.warn "#{table} has primary key #{pk} with no default sequence" if @logger
268
+ @logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger
307
269
  end
308
270
  end
309
271
  end
310
272
 
311
273
  # Resets the sequence of a table's primary key to the maximum value.
312
274
  def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
313
- unless pk and sequence
275
+ unless pk && sequence
314
276
  default_pk, default_sequence = pk_and_sequence_for(table)
315
277
 
316
278
  pk ||= default_pk
@@ -318,15 +280,21 @@ module ActiveRecord
318
280
  end
319
281
 
320
282
  if @logger && pk && !sequence
321
- @logger.warn "#{table} has primary key #{pk} with no default sequence"
283
+ @logger.warn "#{table} has primary key #{pk} with no default sequence."
322
284
  end
323
285
 
324
286
  if pk && sequence
325
287
  quoted_sequence = quote_table_name(sequence)
288
+ max_pk = query_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}", "SCHEMA")
289
+ if max_pk.nil?
290
+ if database_version >= 100000
291
+ minvalue = query_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass", "SCHEMA")
292
+ else
293
+ minvalue = query_value("SELECT min_value FROM #{quoted_sequence}", "SCHEMA")
294
+ end
295
+ end
326
296
 
327
- select_value <<-end_sql, 'SCHEMA'
328
- SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false)
329
- end_sql
297
+ query_value("SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})", "SCHEMA")
330
298
  end
331
299
  end
332
300
 
@@ -334,7 +302,7 @@ module ActiveRecord
334
302
  def pk_and_sequence_for(table) #:nodoc:
335
303
  # First try looking for a sequence with a dependency on the
336
304
  # given table's primary key.
337
- result = query(<<-end_sql, 'SCHEMA')[0]
305
+ result = query(<<~SQL, "SCHEMA")[0]
338
306
  SELECT attr.attname, nsp.nspname, seq.relname
339
307
  FROM pg_class seq,
340
308
  pg_attribute attr,
@@ -350,11 +318,11 @@ module ActiveRecord
350
318
  AND seq.relnamespace = nsp.oid
351
319
  AND cons.contype = 'p'
352
320
  AND dep.classid = 'pg_class'::regclass
353
- AND dep.refobjid = '#{quote_table_name(table)}'::regclass
354
- end_sql
321
+ AND dep.refobjid = #{quote(quote_table_name(table))}::regclass
322
+ SQL
355
323
 
356
- if result.nil? or result.empty?
357
- result = query(<<-end_sql, 'SCHEMA')[0]
324
+ if result.nil? || result.empty?
325
+ result = query(<<~SQL, "SCHEMA")[0]
358
326
  SELECT attr.attname, nsp.nspname,
359
327
  CASE
360
328
  WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
@@ -368,10 +336,10 @@ module ActiveRecord
368
336
  JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
369
337
  JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
370
338
  JOIN pg_namespace nsp ON (t.relnamespace = nsp.oid)
371
- WHERE t.oid = '#{quote_table_name(table)}'::regclass
339
+ WHERE t.oid = #{quote(quote_table_name(table))}::regclass
372
340
  AND cons.contype = 'p'
373
341
  AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
374
- end_sql
342
+ SQL
375
343
  end
376
344
 
377
345
  pk = result.shift
@@ -384,17 +352,20 @@ module ActiveRecord
384
352
  nil
385
353
  end
386
354
 
387
- # Returns just a table's primary key
388
- def primary_key(table)
389
- row = exec_query(<<-end_sql, 'SCHEMA').rows.first
390
- SELECT attr.attname
391
- FROM pg_attribute attr
392
- INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
393
- WHERE cons.contype = 'p'
394
- AND cons.conrelid = '#{quote_table_name(table)}'::regclass
395
- end_sql
396
-
397
- row && row.first
355
+ def primary_keys(table_name) # :nodoc:
356
+ query_values(<<~SQL, "SCHEMA")
357
+ SELECT a.attname
358
+ FROM (
359
+ SELECT indrelid, indkey, generate_subscripts(indkey, 1) idx
360
+ FROM pg_index
361
+ WHERE indrelid = #{quote(quote_table_name(table_name))}::regclass
362
+ AND indisprimary
363
+ ) i
364
+ JOIN pg_attribute a
365
+ ON a.attrelid = i.indrelid
366
+ AND a.attnum = i.indkey[i.idx]
367
+ ORDER BY i.idx
368
+ SQL
398
369
  end
399
370
 
400
371
  # Renames a table.
@@ -407,92 +378,109 @@ module ActiveRecord
407
378
  clear_cache!
408
379
  execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
409
380
  pk, seq = pk_and_sequence_for(new_name)
410
- if seq && seq.identifier == "#{table_name}_#{pk}_seq"
411
- new_seq = "#{new_name}_#{pk}_seq"
381
+ if pk
412
382
  idx = "#{table_name}_pkey"
413
383
  new_idx = "#{new_name}_pkey"
414
- execute "ALTER TABLE #{quote_table_name(seq)} RENAME TO #{quote_table_name(new_seq)}"
415
384
  execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_table_name(new_idx)}"
385
+ if seq && seq.identifier == "#{table_name}_#{pk}_seq"
386
+ new_seq = "#{new_name}_#{pk}_seq"
387
+ execute "ALTER TABLE #{seq.quoted} RENAME TO #{quote_table_name(new_seq)}"
388
+ end
416
389
  end
417
-
418
390
  rename_table_indexes(table_name, new_name)
419
391
  end
420
392
 
421
- # Adds a new column to the named table.
422
- # See TableDefinition#column for details of the options you can use.
423
- def add_column(table_name, column_name, type, options = {})
393
+ def add_column(table_name, column_name, type, **options) #:nodoc:
424
394
  clear_cache!
425
395
  super
396
+ change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
426
397
  end
427
398
 
428
- # Changes the column of a table.
429
- def change_column(table_name, column_name, type, options = {})
399
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
430
400
  clear_cache!
431
- quoted_table_name = quote_table_name(table_name)
432
- sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
433
- sql_type << "[]" if options[:array]
434
- sql = "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{sql_type}"
435
- sql << " USING #{options[:using]}" if options[:using]
436
- if options[:cast_as]
437
- sql << " USING CAST(#{quote_column_name(column_name)} AS #{type_to_sql(options[:cast_as], options[:limit], options[:precision], options[:scale])})"
438
- end
439
- execute sql
440
-
441
- change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
442
- change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
401
+ sqls, procs = Array(change_column_for_alter(table_name, column_name, type, options)).partition { |v| v.is_a?(String) }
402
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{sqls.join(", ")}"
403
+ procs.each(&:call)
443
404
  end
444
405
 
445
406
  # Changes the default value of a table column.
446
- def change_column_default(table_name, column_name, default)
447
- clear_cache!
448
- column = column_for(table_name, column_name)
449
- return unless column
450
-
451
- alter_column_query = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} %s"
452
- if default.nil?
453
- # <tt>DEFAULT NULL</tt> results in the same behavior as <tt>DROP DEFAULT</tt>. However, PostgreSQL will
454
- # cast the default to the columns type, which leaves us with a default like "default NULL::character varying".
455
- execute alter_column_query % "DROP DEFAULT"
456
- else
457
- execute alter_column_query % "SET DEFAULT #{quote_default_value(default, column)}"
458
- end
407
+ def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
408
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}"
459
409
  end
460
410
 
461
- def change_column_null(table_name, column_name, null, default = nil)
411
+ def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
462
412
  clear_cache!
463
413
  unless null || default.nil?
464
414
  column = column_for(table_name, column_name)
465
- execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_value(default, column)} WHERE #{quote_column_name(column_name)} IS NULL") if column
415
+ execute "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(default, column)} WHERE #{quote_column_name(column_name)} IS NULL" if column
466
416
  end
467
- execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
417
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_null_for_alter(table_name, column_name, null, default)}"
418
+ end
419
+
420
+ # Adds comment for given table column or drops it if +comment+ is a +nil+
421
+ def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
422
+ clear_cache!
423
+ comment = extract_new_comment_value(comment_or_changes)
424
+ execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS #{quote(comment)}"
425
+ end
426
+
427
+ # Adds comment for given table or drops it if +comment+ is a +nil+
428
+ def change_table_comment(table_name, comment_or_changes) # :nodoc:
429
+ clear_cache!
430
+ comment = extract_new_comment_value(comment_or_changes)
431
+ execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
468
432
  end
469
433
 
470
434
  # Renames a column in a table.
471
- def rename_column(table_name, column_name, new_column_name)
435
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
472
436
  clear_cache!
473
437
  execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
474
438
  rename_column_indexes(table_name, column_name, new_column_name)
475
439
  end
476
440
 
477
441
  def add_index(table_name, column_name, options = {}) #:nodoc:
478
- index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options)
479
- execute "CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}"
442
+ index_name, index_type, index_columns_and_opclasses, index_options, index_algorithm, index_using, comment = add_index_options(table_name, column_name, **options)
443
+ execute("CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns_and_opclasses})#{index_options}").tap do
444
+ execute "COMMENT ON INDEX #{quote_column_name(index_name)} IS #{quote(comment)}" if comment
445
+ end
480
446
  end
481
447
 
482
- def remove_index!(table_name, index_name) #:nodoc:
483
- execute "DROP INDEX #{quote_table_name(index_name)}"
448
+ def remove_index(table_name, options = {}) #:nodoc:
449
+ table = Utils.extract_schema_qualified_name(table_name.to_s)
450
+
451
+ if options.is_a?(Hash) && options.key?(:name)
452
+ provided_index = Utils.extract_schema_qualified_name(options[:name].to_s)
453
+
454
+ options[:name] = provided_index.identifier
455
+ table = PostgreSQL::Name.new(provided_index.schema, table.identifier) unless table.schema.present?
456
+
457
+ if provided_index.schema.present? && table.schema != provided_index.schema
458
+ raise ArgumentError.new("Index schema '#{provided_index.schema}' does not match table schema '#{table.schema}'")
459
+ end
460
+ end
461
+
462
+ index_to_remove = PostgreSQL::Name.new(table.schema, index_name_for_remove(table.to_s, options))
463
+ algorithm =
464
+ if options.is_a?(Hash) && options.key?(:algorithm)
465
+ index_algorithms.fetch(options[:algorithm]) do
466
+ raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
467
+ end
468
+ end
469
+ execute "DROP INDEX #{algorithm} #{quote_table_name(index_to_remove)}"
484
470
  end
485
471
 
472
+ # Renames an index of a table. Raises error if length of new
473
+ # index name is greater than allowed limit.
486
474
  def rename_index(table_name, old_name, new_name)
487
- if new_name.length > allowed_index_name_length
488
- raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters"
489
- end
475
+ validate_index_length!(table_name, new_name)
476
+
490
477
  execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
491
478
  end
492
479
 
493
480
  def foreign_keys(table_name)
494
- fk_info = select_all <<-SQL.strip_heredoc
495
- SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
481
+ scope = quoted_scope(table_name)
482
+ fk_info = exec_query(<<~SQL, "SCHEMA")
483
+ SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid
496
484
  FROM pg_constraint c
497
485
  JOIN pg_class t1 ON c.conrelid = t1.oid
498
486
  JOIN pg_class t2 ON c.confrelid = t2.oid
@@ -500,88 +488,274 @@ module ActiveRecord
500
488
  JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
501
489
  JOIN pg_namespace t3 ON c.connamespace = t3.oid
502
490
  WHERE c.contype = 'f'
503
- AND t1.relname = #{quote(table_name)}
504
- AND t3.nspname = ANY (current_schemas(false))
491
+ AND t1.relname = #{scope[:name]}
492
+ AND t3.nspname = #{scope[:schema]}
505
493
  ORDER BY c.conname
506
494
  SQL
507
495
 
508
496
  fk_info.map do |row|
509
497
  options = {
510
- column: row['column'],
511
- name: row['name'],
512
- primary_key: row['primary_key']
498
+ column: row["column"],
499
+ name: row["name"],
500
+ primary_key: row["primary_key"]
513
501
  }
514
502
 
515
- options[:on_delete] = extract_foreign_key_action(row['on_delete'])
516
- options[:on_update] = extract_foreign_key_action(row['on_update'])
503
+ options[:on_delete] = extract_foreign_key_action(row["on_delete"])
504
+ options[:on_update] = extract_foreign_key_action(row["on_update"])
505
+ options[:validate] = row["valid"]
517
506
 
518
- ForeignKeyDefinition.new(table_name, row['to_table'], options)
507
+ ForeignKeyDefinition.new(table_name, row["to_table"], options)
519
508
  end
520
509
  end
521
510
 
522
- def extract_foreign_key_action(specifier) # :nodoc:
523
- case specifier
524
- when 'c'; :cascade
525
- when 'n'; :nullify
526
- when 'r'; :restrict
527
- end
511
+ def foreign_tables
512
+ query_values(data_source_sql(type: "FOREIGN TABLE"), "SCHEMA")
528
513
  end
529
514
 
530
- def index_name_length
531
- 63
515
+ def foreign_table_exists?(table_name)
516
+ query_values(data_source_sql(table_name, type: "FOREIGN TABLE"), "SCHEMA").any? if table_name.present?
532
517
  end
533
518
 
534
519
  # Maps logical Rails types to PostgreSQL-specific data types.
535
- def type_to_sql(type, limit = nil, precision = nil, scale = nil)
536
- case type.to_s
537
- when 'binary'
538
- # PostgreSQL doesn't support limits on binary (bytea) columns.
539
- # The hard limit is 1Gb, because of a 32-bit size field, and TOAST.
540
- case limit
541
- when nil, 0..0x3fffffff; super(type)
542
- else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
543
- end
544
- when 'text'
545
- # PostgreSQL doesn't support limits on text columns.
546
- # The hard limit is 1Gb, according to section 8.3 in the manual.
547
- case limit
548
- when nil, 0..0x3fffffff; super(type)
549
- else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
550
- end
551
- when 'integer'
552
- return 'integer' unless limit
553
-
554
- case limit
555
- when 1, 2; 'smallint'
556
- when 3, 4; 'integer'
557
- when 5..8; 'bigint'
558
- else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
520
+ def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
521
+ sql = \
522
+ case type.to_s
523
+ when "binary"
524
+ # PostgreSQL doesn't support limits on binary (bytea) columns.
525
+ # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
526
+ case limit
527
+ when nil, 0..0x3fffffff; super(type)
528
+ else raise ArgumentError, "No binary type has byte size #{limit}. The limit on binary can be at most 1GB - 1byte."
529
+ end
530
+ when "text"
531
+ # PostgreSQL doesn't support limits on text columns.
532
+ # The hard limit is 1GB, according to section 8.3 in the manual.
533
+ case limit
534
+ when nil, 0..0x3fffffff; super(type)
535
+ else raise ArgumentError, "No text type has byte size #{limit}. The limit on text can be at most 1GB - 1byte."
536
+ end
537
+ when "integer"
538
+ case limit
539
+ when 1, 2; "smallint"
540
+ when nil, 3, 4; "integer"
541
+ when 5..8; "bigint"
542
+ else raise ArgumentError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead."
543
+ end
544
+ else
545
+ super
559
546
  end
560
- when 'datetime'
561
- return super unless precision
562
547
 
563
- case precision
564
- when 0..6; "timestamp(#{precision})"
565
- else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
566
- end
567
- else
568
- super
569
- end
548
+ sql = "#{sql}[]" if array && type != :primary_key
549
+ sql
570
550
  end
571
551
 
572
552
  # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
573
553
  # requires that the ORDER BY include the distinct column.
574
554
  def columns_for_distinct(columns, orders) #:nodoc:
575
- order_columns = orders.reject(&:blank?).map{ |s|
576
- # Convert Arel node to string
577
- s = s.to_sql unless s.is_a?(String)
578
- # Remove any ASC/DESC modifiers
579
- s.gsub(/\s+(?:ASC|DESC)\b/i, '')
580
- .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
581
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
555
+ order_columns = orders.reject(&:blank?).map { |s|
556
+ # Convert Arel node to string
557
+ s = visitor.compile(s) unless s.is_a?(String)
558
+ # Remove any ASC/DESC modifiers
559
+ s.gsub(/\s+(?:ASC|DESC)\b/i, "")
560
+ .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
561
+ }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
562
+
563
+ (order_columns << super).join(", ")
564
+ end
565
+
566
+ def update_table_definition(table_name, base) # :nodoc:
567
+ PostgreSQL::Table.new(table_name, base)
568
+ end
569
+
570
+ def create_schema_dumper(options) # :nodoc:
571
+ PostgreSQL::SchemaDumper.create(self, options)
572
+ end
573
+
574
+ # Validates the given constraint.
575
+ #
576
+ # Validates the constraint named +constraint_name+ on +accounts+.
577
+ #
578
+ # validate_constraint :accounts, :constraint_name
579
+ def validate_constraint(table_name, constraint_name)
580
+ return unless supports_validate_constraints?
581
+
582
+ at = create_alter_table table_name
583
+ at.validate_constraint constraint_name
584
+
585
+ execute schema_creation.accept(at)
586
+ end
587
+
588
+ # Validates the given foreign key.
589
+ #
590
+ # Validates the foreign key on +accounts.branch_id+.
591
+ #
592
+ # validate_foreign_key :accounts, :branches
593
+ #
594
+ # Validates the foreign key on +accounts.owner_id+.
595
+ #
596
+ # validate_foreign_key :accounts, column: :owner_id
597
+ #
598
+ # Validates the foreign key named +special_fk_name+ on the +accounts+ table.
599
+ #
600
+ # validate_foreign_key :accounts, name: :special_fk_name
601
+ #
602
+ # The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key.
603
+ def validate_foreign_key(from_table, to_table = nil, **options)
604
+ return unless supports_validate_constraints?
605
+
606
+ fk_name_to_validate = foreign_key_for!(from_table, to_table: to_table, **options).name
582
607
 
583
- [super, *order_columns].join(', ')
608
+ validate_constraint from_table, fk_name_to_validate
584
609
  end
610
+
611
+ private
612
+ def schema_creation
613
+ PostgreSQL::SchemaCreation.new(self)
614
+ end
615
+
616
+ def create_table_definition(*args, **options)
617
+ PostgreSQL::TableDefinition.new(self, *args, **options)
618
+ end
619
+
620
+ def create_alter_table(name)
621
+ PostgreSQL::AlterTable.new create_table_definition(name)
622
+ end
623
+
624
+ def new_column_from_field(table_name, field)
625
+ column_name, type, default, notnull, oid, fmod, collation, comment = field
626
+ type_metadata = fetch_type_metadata(column_name, type, oid.to_i, fmod.to_i)
627
+ default_value = extract_value_from_default(default)
628
+ default_function = extract_default_function(default_value, default)
629
+
630
+ if match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/)
631
+ serial = sequence_name_from_parts(table_name, column_name, match[:suffix]) == match[:sequence_name]
632
+ end
633
+
634
+ PostgreSQL::Column.new(
635
+ column_name,
636
+ default_value,
637
+ type_metadata,
638
+ !notnull,
639
+ default_function,
640
+ collation: collation,
641
+ comment: comment.presence,
642
+ serial: serial
643
+ )
644
+ end
645
+
646
+ def fetch_type_metadata(column_name, sql_type, oid, fmod)
647
+ cast_type = get_oid_type(oid, fmod, column_name, sql_type)
648
+ simple_type = SqlTypeMetadata.new(
649
+ sql_type: sql_type,
650
+ type: cast_type.type,
651
+ limit: cast_type.limit,
652
+ precision: cast_type.precision,
653
+ scale: cast_type.scale,
654
+ )
655
+ PostgreSQL::TypeMetadata.new(simple_type, oid: oid, fmod: fmod)
656
+ end
657
+
658
+ def sequence_name_from_parts(table_name, column_name, suffix)
659
+ over_length = [table_name, column_name, suffix].sum(&:length) + 2 - max_identifier_length
660
+
661
+ if over_length > 0
662
+ column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
663
+ over_length -= column_name.length - column_name_length
664
+ column_name = column_name[0, column_name_length - [over_length, 0].min]
665
+ end
666
+
667
+ if over_length > 0
668
+ table_name = table_name[0, table_name.length - over_length]
669
+ end
670
+
671
+ "#{table_name}_#{column_name}_#{suffix}"
672
+ end
673
+
674
+ def extract_foreign_key_action(specifier)
675
+ case specifier
676
+ when "c"; :cascade
677
+ when "n"; :nullify
678
+ when "r"; :restrict
679
+ end
680
+ end
681
+
682
+ def add_column_for_alter(table_name, column_name, type, **options)
683
+ return super unless options.key?(:comment)
684
+ [super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
685
+ end
686
+
687
+ def change_column_for_alter(table_name, column_name, type, options = {})
688
+ td = create_table_definition(table_name)
689
+ cd = td.new_column_definition(column_name, type, **options)
690
+ sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
691
+ sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
692
+ sqls
693
+ end
694
+
695
+ def change_column_default_for_alter(table_name, column_name, default_or_changes)
696
+ column = column_for(table_name, column_name)
697
+ return unless column
698
+
699
+ default = extract_new_default_value(default_or_changes)
700
+ alter_column_query = "ALTER COLUMN #{quote_column_name(column_name)} %s"
701
+ if default.nil?
702
+ # <tt>DEFAULT NULL</tt> results in the same behavior as <tt>DROP DEFAULT</tt>. However, PostgreSQL will
703
+ # cast the default to the columns type, which leaves us with a default like "default NULL::character varying".
704
+ alter_column_query % "DROP DEFAULT"
705
+ else
706
+ alter_column_query % "SET DEFAULT #{quote_default_expression(default, column)}"
707
+ end
708
+ end
709
+
710
+ def change_column_null_for_alter(table_name, column_name, null, default = nil)
711
+ "ALTER COLUMN #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
712
+ end
713
+
714
+ def add_index_opclass(quoted_columns, **options)
715
+ opclasses = options_for_index_columns(options[:opclass])
716
+ quoted_columns.each do |name, column|
717
+ column << " #{opclasses[name]}" if opclasses[name].present?
718
+ end
719
+ end
720
+
721
+ def add_options_for_index_columns(quoted_columns, **options)
722
+ quoted_columns = add_index_opclass(quoted_columns, **options)
723
+ super
724
+ end
725
+
726
+ def data_source_sql(name = nil, type: nil)
727
+ scope = quoted_scope(name, type: type)
728
+ scope[:type] ||= "'r','v','m','p','f'" # (r)elation/table, (v)iew, (m)aterialized view, (p)artitioned table, (f)oreign table
729
+
730
+ sql = +"SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace"
731
+ sql << " WHERE n.nspname = #{scope[:schema]}"
732
+ sql << " AND c.relname = #{scope[:name]}" if scope[:name]
733
+ sql << " AND c.relkind IN (#{scope[:type]})"
734
+ sql
735
+ end
736
+
737
+ def quoted_scope(name = nil, type: nil)
738
+ schema, name = extract_schema_qualified_name(name)
739
+ type = \
740
+ case type
741
+ when "BASE TABLE"
742
+ "'r','p'"
743
+ when "VIEW"
744
+ "'v','m'"
745
+ when "FOREIGN TABLE"
746
+ "'f'"
747
+ end
748
+ scope = {}
749
+ scope[:schema] = schema ? quote(schema) : "ANY (current_schemas(false))"
750
+ scope[:name] = quote(name) if name
751
+ scope[:type] = type if type
752
+ scope
753
+ end
754
+
755
+ def extract_schema_qualified_name(string)
756
+ name = Utils.extract_schema_qualified_name(string.to_s)
757
+ [name.schema, name.identifier]
758
+ end
585
759
  end
586
760
  end
587
761
  end