serrano-vk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (588) hide show
  1. checksums.yaml +7 -0
  2. data/EXAMPLES.md +271 -0
  3. data/README.md +170 -0
  4. data/bin/serrano +6 -0
  5. data/examples/demo_crud/Gemfile +9 -0
  6. data/examples/demo_crud/Gemfile.lock +31 -0
  7. data/examples/demo_crud/app/controllers/articles_controller.rb +92 -0
  8. data/examples/demo_crud/app/controllers/categories_controller.rb +92 -0
  9. data/examples/demo_crud/app/entities/article.rb +17 -0
  10. data/examples/demo_crud/app/entities/category.rb +17 -0
  11. data/examples/demo_crud/app/entities/concerns/validatable.rb +136 -0
  12. data/examples/demo_crud/app/repositories/article_repository.rb +42 -0
  13. data/examples/demo_crud/app/repositories/category_repository.rb +42 -0
  14. data/examples/demo_crud/app/services/articles/create.rb +29 -0
  15. data/examples/demo_crud/app/services/articles/destroy.rb +20 -0
  16. data/examples/demo_crud/app/services/articles/index.rb +17 -0
  17. data/examples/demo_crud/app/services/articles/show.rb +20 -0
  18. data/examples/demo_crud/app/services/articles/update.rb +26 -0
  19. data/examples/demo_crud/app/services/categories/create.rb +27 -0
  20. data/examples/demo_crud/app/services/categories/destroy.rb +20 -0
  21. data/examples/demo_crud/app/services/categories/index.rb +17 -0
  22. data/examples/demo_crud/app/services/categories/show.rb +20 -0
  23. data/examples/demo_crud/app/services/categories/update.rb +26 -0
  24. data/examples/demo_crud/config/db.rb +3 -0
  25. data/examples/demo_crud/config.ru +19 -0
  26. data/examples/demo_crud/db/development.sqlite3 +0 -0
  27. data/examples/demo_crud/db/migrations/20260307212844_create_articles.rb +14 -0
  28. data/examples/demo_crud/db/migrations/20260307212845_create_categories.rb +12 -0
  29. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/bin/rackup +29 -0
  30. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/bin/rackup.bat +2 -0
  31. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/bin/sequel +29 -0
  32. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/bin/sequel.bat +2 -0
  33. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/bin/serrano +29 -0
  34. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/bin/serrano.bat +2 -0
  35. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/cache/bigdecimal-4.0.1.gem +0 -0
  36. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/cache/rack-3.2.5.gem +0 -0
  37. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/cache/rackup-2.3.1.gem +0 -0
  38. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/cache/sequel-5.102.0.gem +0 -0
  39. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/cache/sqlite3-2.9.1-x64-mingw-ucrt.gem +0 -0
  40. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/cache/webrick-1.9.2.gem +0 -0
  41. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/extensions/x64-mingw-ucrt/3.4.0/bigdecimal-4.0.1/bigdecimal.so +0 -0
  42. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/extensions/x64-mingw-ucrt/3.4.0/bigdecimal-4.0.1/gem.build_complete +0 -0
  43. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/extensions/x64-mingw-ucrt/3.4.0/bigdecimal-4.0.1/gem_make.out +43 -0
  44. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/extensions/x64-mingw-ucrt/3.4.0/bigdecimal-4.0.1/mkmf.log +669 -0
  45. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/LICENSE +56 -0
  46. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/bigdecimal.gemspec +57 -0
  47. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/Makefile +278 -0
  48. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/bigdecimal.c +6206 -0
  49. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/bigdecimal.h +292 -0
  50. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/bits.h +144 -0
  51. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/extconf.rb +60 -0
  52. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/feature.h +68 -0
  53. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/missing/dtoa.c +3462 -0
  54. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/missing.c +28 -0
  55. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/missing.h +104 -0
  56. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/ext/bigdecimal/static_assert.h +54 -0
  57. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/lib/bigdecimal/jacobian.rb +92 -0
  58. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/lib/bigdecimal/ludcmp.rb +91 -0
  59. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/lib/bigdecimal/math.rb +948 -0
  60. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/lib/bigdecimal/newton.rb +82 -0
  61. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/lib/bigdecimal/util.rb +186 -0
  62. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/lib/bigdecimal.rb +360 -0
  63. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/lib/bigdecimal.so +0 -0
  64. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/sample/linear.rb +74 -0
  65. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/sample/nlsolve.rb +40 -0
  66. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/bigdecimal-4.0.1/sample/pi.rb +21 -0
  67. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/CHANGELOG.md +1314 -0
  68. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/CONTRIBUTING.md +144 -0
  69. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/MIT-LICENSE +20 -0
  70. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/README.md +384 -0
  71. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/SPEC.rdoc +258 -0
  72. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/auth/abstract/handler.rb +41 -0
  73. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/auth/abstract/request.rb +51 -0
  74. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/auth/basic.rb +58 -0
  75. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/bad_request.rb +8 -0
  76. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/body_proxy.rb +63 -0
  77. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/builder.rb +296 -0
  78. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/cascade.rb +67 -0
  79. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/common_logger.rb +89 -0
  80. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/conditional_get.rb +87 -0
  81. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/config.rb +22 -0
  82. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/constants.rb +68 -0
  83. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/content_length.rb +34 -0
  84. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/content_type.rb +33 -0
  85. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/deflater.rb +158 -0
  86. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/directory.rb +208 -0
  87. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/etag.rb +71 -0
  88. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/events.rb +172 -0
  89. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/files.rb +216 -0
  90. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/head.rb +25 -0
  91. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/headers.rb +238 -0
  92. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/lint.rb +964 -0
  93. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/lock.rb +29 -0
  94. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/media_type.rb +52 -0
  95. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/method_override.rb +56 -0
  96. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/mime.rb +694 -0
  97. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/mock.rb +3 -0
  98. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/mock_request.rb +161 -0
  99. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/mock_response.rb +156 -0
  100. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/multipart/generator.rb +99 -0
  101. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/multipart/parser.rb +580 -0
  102. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/multipart/uploaded_file.rb +82 -0
  103. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/multipart.rb +77 -0
  104. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/null_logger.rb +48 -0
  105. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/query_parser.rb +261 -0
  106. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/recursive.rb +66 -0
  107. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/reloader.rb +112 -0
  108. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/request.rb +790 -0
  109. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/response.rb +403 -0
  110. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/rewindable_input.rb +116 -0
  111. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/runtime.rb +35 -0
  112. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/sendfile.rb +197 -0
  113. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/show_exceptions.rb +409 -0
  114. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/show_status.rb +121 -0
  115. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/static.rb +188 -0
  116. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/tempfile_reaper.rb +33 -0
  117. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/urlmap.rb +99 -0
  118. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/utils.rb +622 -0
  119. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack/version.rb +17 -0
  120. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rack-3.2.5/lib/rack.rb +64 -0
  121. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/bin/rackup +5 -0
  122. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/lib/rackup/handler/cgi.rb +61 -0
  123. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/lib/rackup/handler/webrick.rb +196 -0
  124. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/lib/rackup/handler.rb +113 -0
  125. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/lib/rackup/lobster.rb +81 -0
  126. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/lib/rackup/server.rb +462 -0
  127. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/lib/rackup/stream.rb +199 -0
  128. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/lib/rackup/version.rb +8 -0
  129. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/lib/rackup.rb +21 -0
  130. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/license.md +80 -0
  131. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/readme.md +82 -0
  132. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/releases.md +28 -0
  133. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/rackup-2.3.1/security.md +3 -0
  134. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/MIT-LICENSE +19 -0
  135. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/bin/sequel +280 -0
  136. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/ado/access.rb +335 -0
  137. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/ado/mssql.rb +62 -0
  138. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/ado.rb +283 -0
  139. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/amalgalite.rb +184 -0
  140. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/ibmdb.rb +423 -0
  141. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/db2.rb +83 -0
  142. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/derby.rb +318 -0
  143. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/h2.rb +290 -0
  144. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/hsqldb.rb +228 -0
  145. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/jtds.rb +39 -0
  146. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/mssql.rb +30 -0
  147. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/mysql.rb +89 -0
  148. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/oracle.rb +146 -0
  149. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/postgresql.rb +239 -0
  150. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/sqlanywhere.rb +87 -0
  151. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/sqlite.rb +133 -0
  152. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/sqlserver.rb +92 -0
  153. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc/transactions.rb +95 -0
  154. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/jdbc.rb +850 -0
  155. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/mock.rb +381 -0
  156. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/mysql.rb +380 -0
  157. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/mysql2.rb +307 -0
  158. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/odbc/db2.rb +11 -0
  159. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/odbc/mssql.rb +57 -0
  160. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/odbc/oracle.rb +11 -0
  161. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/odbc.rb +150 -0
  162. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/oracle.rb +427 -0
  163. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/postgres.rb +863 -0
  164. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/postgresql.rb +3 -0
  165. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/shared/access.rb +301 -0
  166. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/shared/db2.rb +509 -0
  167. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/shared/mssql.rb +1238 -0
  168. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/shared/mysql.rb +1175 -0
  169. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/shared/oracle.rb +732 -0
  170. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/shared/postgres.rb +3022 -0
  171. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/shared/sqlanywhere.rb +470 -0
  172. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/shared/sqlite.rb +1073 -0
  173. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/sqlanywhere.rb +192 -0
  174. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/sqlite.rb +475 -0
  175. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/tinytds.rb +259 -0
  176. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/trilogy.rb +116 -0
  177. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  178. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +74 -0
  179. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +93 -0
  180. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
  181. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
  182. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/replace.rb +35 -0
  183. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/split_alter_table.rb +46 -0
  184. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/stored_procedures.rb +61 -0
  185. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
  186. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/ast_transformer.rb +132 -0
  187. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/connection_pool/sharded_single.rb +113 -0
  188. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/connection_pool/sharded_threaded.rb +392 -0
  189. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/connection_pool/sharded_timed_queue.rb +399 -0
  190. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/connection_pool/single.rb +57 -0
  191. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/connection_pool/threaded.rb +307 -0
  192. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/connection_pool/timed_queue.rb +288 -0
  193. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/connection_pool.rb +175 -0
  194. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/core.rb +476 -0
  195. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/connecting.rb +349 -0
  196. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/dataset.rb +89 -0
  197. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/dataset_defaults.rb +93 -0
  198. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/features.rb +150 -0
  199. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/logging.rb +91 -0
  200. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/misc.rb +663 -0
  201. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/query.rb +436 -0
  202. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/schema_generator.rb +720 -0
  203. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/schema_methods.rb +1157 -0
  204. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database/transactions.rb +552 -0
  205. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/database.rb +37 -0
  206. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/actions.rb +1412 -0
  207. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/dataset_module.rb +46 -0
  208. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
  209. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/features.rb +284 -0
  210. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/graph.rb +297 -0
  211. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/misc.rb +381 -0
  212. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/placeholder_literalizer.rb +230 -0
  213. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/prepared_statements.rb +474 -0
  214. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/query.rb +1571 -0
  215. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset/sql.rb +1863 -0
  216. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/dataset.rb +60 -0
  217. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/deprecated.rb +70 -0
  218. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/exceptions.rb +130 -0
  219. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
  220. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/_model_pg_row.rb +31 -0
  221. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/_pretty_table.rb +85 -0
  222. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/any_not_empty.rb +45 -0
  223. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/arbitrary_servers.rb +114 -0
  224. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/async_thread_pool.rb +446 -0
  225. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
  226. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  227. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/blank.rb +57 -0
  228. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/caller_logging.rb +80 -0
  229. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/columns_introspection.rb +88 -0
  230. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/connection_checkout_event_callback.rb +151 -0
  231. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/connection_expiration.rb +105 -0
  232. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/connection_validator.rb +133 -0
  233. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/constant_sql_override.rb +65 -0
  234. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/constraint_validations.rb +510 -0
  235. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/core_extensions.rb +222 -0
  236. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/core_refinements.rb +244 -0
  237. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/current_datetime_timestamp.rb +59 -0
  238. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/dataset_run.rb +41 -0
  239. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/dataset_source_alias.rb +95 -0
  240. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/date_arithmetic.rb +254 -0
  241. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  242. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/datetime_parse_to_time.rb +41 -0
  243. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/duplicate_columns_handler.rb +95 -0
  244. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/empty_array_consider_nulls.rb +46 -0
  245. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/error_sql.rb +76 -0
  246. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/escaped_like.rb +100 -0
  247. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/eval_inspect.rb +185 -0
  248. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/exclude_or_null.rb +68 -0
  249. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  250. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/freeze_datasets.rb +3 -0
  251. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/from_block.rb +3 -0
  252. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/graph_each.rb +88 -0
  253. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/identifier_mangling.rb +180 -0
  254. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/implicit_subquery.rb +48 -0
  255. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/index_caching.rb +113 -0
  256. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/inflector.rb +258 -0
  257. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/integer64.rb +32 -0
  258. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/is_distinct_from.rb +141 -0
  259. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/looser_typecasting.rb +50 -0
  260. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/migration.rb +867 -0
  261. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +84 -0
  262. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/named_timezones.rb +184 -0
  263. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/no_auto_literal_strings.rb +4 -0
  264. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/null_dataset.rb +109 -0
  265. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pagination.rb +140 -0
  266. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_array.rb +556 -0
  267. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_array_ops.rb +377 -0
  268. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_auto_parameterize.rb +516 -0
  269. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb +191 -0
  270. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +194 -0
  271. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_enum.rb +199 -0
  272. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_extended_date_support.rb +261 -0
  273. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  274. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_hstore.rb +353 -0
  275. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_hstore_ops.rb +418 -0
  276. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_inet.rb +136 -0
  277. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_inet_ops.rb +204 -0
  278. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_interval.rb +224 -0
  279. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_json.rb +644 -0
  280. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_json_ops.rb +1460 -0
  281. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_loose_count.rb +39 -0
  282. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_multirange.rb +367 -0
  283. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_range.rb +572 -0
  284. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_range_ops.rb +195 -0
  285. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_row.rb +585 -0
  286. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_row_ops.rb +217 -0
  287. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_schema_caching.rb +90 -0
  288. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_static_cache_updater.rb +144 -0
  289. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pg_timestamptz.rb +52 -0
  290. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/pretty_table.rb +40 -0
  291. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/provenance.rb +108 -0
  292. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/query.rb +85 -0
  293. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/query_blocker.rb +172 -0
  294. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/round_timestamps.rb +49 -0
  295. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  296. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/s.rb +60 -0
  297. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/schema_caching.rb +103 -0
  298. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/schema_dumper.rb +550 -0
  299. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/select_remove.rb +52 -0
  300. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
  301. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/server_block.rb +179 -0
  302. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/server_logging.rb +61 -0
  303. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/set_literalizer.rb +39 -0
  304. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/split_array_nil.rb +80 -0
  305. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/sql_comments.rb +203 -0
  306. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/sql_expr.rb +23 -0
  307. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  308. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/sqlite_json_ops.rb +313 -0
  309. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/stdio_logger.rb +48 -0
  310. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/string_agg.rb +194 -0
  311. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/string_date_time.rb +48 -0
  312. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/symbol_aref.rb +55 -0
  313. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
  314. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/symbol_as.rb +23 -0
  315. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
  316. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/synchronize_sql.rb +45 -0
  317. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/temporarily_release_connection.rb +178 -0
  318. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/thread_local_timezones.rb +59 -0
  319. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/to_dot.rb +169 -0
  320. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
  321. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/extensions/virtual_row_method_block.rb +45 -0
  322. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model/associations.rb +4066 -0
  323. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model/base.rb +2360 -0
  324. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model/dataset_module.rb +36 -0
  325. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model/default_inflections.rb +47 -0
  326. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model/errors.rb +67 -0
  327. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model/exceptions.rb +67 -0
  328. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model/inflections.rb +151 -0
  329. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model/plugins.rb +165 -0
  330. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/model.rb +85 -0
  331. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/accessed_columns.rb +63 -0
  332. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/active_model.rb +124 -0
  333. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/after_initialize.rb +39 -0
  334. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/association_dependencies.rb +106 -0
  335. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  336. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  337. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/association_pks.rb +316 -0
  338. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/association_proxies.rb +131 -0
  339. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/async_thread_pool.rb +39 -0
  340. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  341. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/auto_validations.rb +302 -0
  342. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  343. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/before_after_save.rb +8 -0
  344. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/blacklist_security.rb +104 -0
  345. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/boolean_readers.rb +59 -0
  346. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/boolean_subsets.rb +64 -0
  347. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/caching.rb +164 -0
  348. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/class_table_inheritance.rb +439 -0
  349. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/class_table_inheritance_constraint_validations.rb +82 -0
  350. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/column_conflicts.rb +108 -0
  351. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/column_encryption.rb +749 -0
  352. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/column_select.rb +61 -0
  353. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/columns_updated.rb +42 -0
  354. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/composition.rb +205 -0
  355. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  356. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/constraint_validations.rb +259 -0
  357. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/csv_serializer.rb +196 -0
  358. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/dataset_associations.rb +152 -0
  359. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/def_dataset_method.rb +90 -0
  360. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/defaults_setter.rb +158 -0
  361. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/delay_add_association.rb +53 -0
  362. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/deprecated_associations.rb +151 -0
  363. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/detect_unnecessary_association_options.rb +164 -0
  364. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/dirty.rb +276 -0
  365. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/eager_each.rb +88 -0
  366. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  367. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  368. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/enum.rb +124 -0
  369. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/error_splitter.rb +61 -0
  370. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/finder.rb +248 -0
  371. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/forbid_lazy_load.rb +229 -0
  372. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/force_encoding.rb +78 -0
  373. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/hook_class_methods.rb +110 -0
  374. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/input_transformer.rb +89 -0
  375. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/insert_conflict.rb +76 -0
  376. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/insert_returning_select.rb +81 -0
  377. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/inspect_pk.rb +44 -0
  378. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/instance_filters.rb +138 -0
  379. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/instance_hooks.rb +115 -0
  380. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/instance_specific_default.rb +113 -0
  381. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/inverted_subsets.rb +60 -0
  382. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/json_serializer.rb +445 -0
  383. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/lazy_attributes.rb +126 -0
  384. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/list.rb +208 -0
  385. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/many_through_many.rb +437 -0
  386. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/modification_detection.rb +102 -0
  387. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/mssql_optimistic_locking.rb +65 -0
  388. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/nested_attributes.rb +340 -0
  389. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/optimistic_locking.rb +54 -0
  390. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
  391. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/paged_operations.rb +184 -0
  392. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/pg_array_associations.rb +580 -0
  393. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/pg_auto_constraint_validations.rb +361 -0
  394. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/pg_auto_validate_enums.rb +88 -0
  395. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/pg_eager_any_typed_array.rb +95 -0
  396. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/pg_row.rb +79 -0
  397. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
  398. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/prepared_statements.rb +196 -0
  399. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  400. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  401. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/rcte_tree.rb +343 -0
  402. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/require_valid_schema.rb +67 -0
  403. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/serialization.rb +242 -0
  404. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/serialization_modification_detection.rb +87 -0
  405. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/sharding.rb +126 -0
  406. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/single_statement_dataset_destroy.rb +49 -0
  407. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/single_table_inheritance.rb +271 -0
  408. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/singular_table_names.rb +33 -0
  409. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/skip_create_refresh.rb +37 -0
  410. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  411. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/split_values.rb +81 -0
  412. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/sql_comments.rb +194 -0
  413. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/static_cache.rb +315 -0
  414. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/static_cache_cache.rb +94 -0
  415. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/string_stripper.rb +59 -0
  416. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/subclasses.rb +96 -0
  417. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/subset_conditions.rb +128 -0
  418. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/subset_static_cache.rb +278 -0
  419. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/table_select.rb +50 -0
  420. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/tactical_eager_loading.rb +216 -0
  421. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/throw_failures.rb +110 -0
  422. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/timestamps.rb +109 -0
  423. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/touch.rb +153 -0
  424. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/tree.rb +188 -0
  425. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/typecast_on_load.rb +90 -0
  426. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/unlimited_update.rb +27 -0
  427. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/unused_associations.rb +529 -0
  428. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/update_or_create.rb +64 -0
  429. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/update_primary_key.rb +72 -0
  430. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/update_refresh.rb +88 -0
  431. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/uuid.rb +70 -0
  432. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/validate_associated.rb +85 -0
  433. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/validation_class_methods.rb +460 -0
  434. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/validation_contexts.rb +49 -0
  435. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/validation_helpers.rb +351 -0
  436. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
  437. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/whitelist_security.rb +122 -0
  438. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/plugins/xml_serializer.rb +411 -0
  439. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/sql.rb +2061 -0
  440. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/timezones.rb +254 -0
  441. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel/version.rb +25 -0
  442. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sequel-5.102.0/lib/sequel.rb +3 -0
  443. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/CHANGELOG.md +1014 -0
  444. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/CONTRIBUTING.md +60 -0
  445. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/FAQ.md +399 -0
  446. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/INSTALLATION.md +267 -0
  447. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/LICENSE +23 -0
  448. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/README.md +198 -0
  449. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/dependencies.yml +13 -0
  450. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/aggregator.c +270 -0
  451. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/aggregator.h +10 -0
  452. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/backup.c +190 -0
  453. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/backup.h +15 -0
  454. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/database.c +1006 -0
  455. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/database.h +28 -0
  456. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/exception.c +122 -0
  457. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/exception.h +12 -0
  458. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/extconf.rb +297 -0
  459. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/sqlite3.c +225 -0
  460. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/sqlite3_ruby.h +48 -0
  461. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/statement.c +739 -0
  462. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/statement.h +17 -0
  463. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/ext/sqlite3/timespec.h +20 -0
  464. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/3.2/sqlite3_native.so +0 -0
  465. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/3.3/sqlite3_native.so +0 -0
  466. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/3.4/sqlite3_native.so +0 -0
  467. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/4.0/sqlite3_native.so +0 -0
  468. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/constants.rb +198 -0
  469. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/database.rb +798 -0
  470. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/errors.rb +88 -0
  471. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/fork_safety.rb +66 -0
  472. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/pragmas.rb +648 -0
  473. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/resultset.rb +96 -0
  474. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/statement.rb +190 -0
  475. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/value.rb +54 -0
  476. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/version.rb +4 -0
  477. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3/version_info.rb +17 -0
  478. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/sqlite3-2.9.1-x64-mingw-ucrt/lib/sqlite3.rb +19 -0
  479. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Gemfile +10 -0
  480. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/LICENSE.txt +22 -0
  481. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/README.md +63 -0
  482. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/Rakefile +10 -0
  483. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/accesslog.rb +157 -0
  484. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cgi.rb +313 -0
  485. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/compat.rb +36 -0
  486. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/config.rb +158 -0
  487. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/cookie.rb +172 -0
  488. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/htmlutils.rb +30 -0
  489. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/authenticator.rb +117 -0
  490. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/basicauth.rb +116 -0
  491. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/digestauth.rb +395 -0
  492. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htdigest.rb +132 -0
  493. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htgroup.rb +97 -0
  494. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/htpasswd.rb +158 -0
  495. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth/userdb.rb +53 -0
  496. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpauth.rb +96 -0
  497. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpproxy.rb +354 -0
  498. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httprequest.rb +668 -0
  499. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpresponse.rb +588 -0
  500. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/https.rb +152 -0
  501. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpserver.rb +294 -0
  502. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/abstract.rb +152 -0
  503. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  504. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/cgihandler.rb +126 -0
  505. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/erbhandler.rb +88 -0
  506. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/filehandler.rb +552 -0
  507. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet/prochandler.rb +48 -0
  508. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpservlet.rb +23 -0
  509. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpstatus.rb +194 -0
  510. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httputils.rb +543 -0
  511. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/httpversion.rb +76 -0
  512. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/log.rb +156 -0
  513. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/server.rb +380 -0
  514. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/ssl.rb +219 -0
  515. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/utils.rb +265 -0
  516. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick/version.rb +18 -0
  517. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/lib/webrick.rb +232 -0
  518. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/accesslog.rbs +24 -0
  519. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cgi.rbs +92 -0
  520. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/compat.rbs +18 -0
  521. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/config.rbs +17 -0
  522. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/cookie.rbs +37 -0
  523. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/htmlutils.rbs +5 -0
  524. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/authenticator.rbs +55 -0
  525. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/basicauth.rbs +29 -0
  526. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/digestauth.rbs +85 -0
  527. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htdigest.rbs +31 -0
  528. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htgroup.rbs +21 -0
  529. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/htpasswd.rbs +31 -0
  530. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth/userdb.rbs +13 -0
  531. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpauth.rbs +13 -0
  532. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpproxy.rbs +61 -0
  533. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httprequest.rbs +167 -0
  534. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpresponse.rbs +117 -0
  535. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/https.rbs +49 -0
  536. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpserver.rbs +71 -0
  537. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/abstract.rbs +36 -0
  538. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgi_runner.rbs +3 -0
  539. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/cgihandler.rbs +23 -0
  540. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/erbhandler.rbs +17 -0
  541. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/filehandler.rbs +76 -0
  542. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet/prochandler.rbs +21 -0
  543. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpservlet.rbs +4 -0
  544. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpstatus.rbs +255 -0
  545. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httputils.rbs +116 -0
  546. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/httpversion.rbs +17 -0
  547. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/log.rbs +93 -0
  548. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/manifest.yaml +8 -0
  549. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/server.rbs +57 -0
  550. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/ssl.rbs +19 -0
  551. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/utils.rbs +122 -0
  552. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/sig/version.rbs +3 -0
  553. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.2/webrick.gemspec +105 -0
  554. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/specifications/bigdecimal-4.0.1.gemspec +25 -0
  555. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/specifications/rack-3.2.5.gemspec +31 -0
  556. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/specifications/rackup-2.3.1.gemspec +26 -0
  557. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/specifications/sequel-5.102.0.gemspec +36 -0
  558. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/specifications/sqlite3-2.9.1-x64-mingw-ucrt.gemspec +25 -0
  559. data/examples/demo_crud/vendor/bundle/ruby/3.4.0/specifications/webrick-1.9.2.gemspec +22 -0
  560. data/lib/serrano/application.rb +36 -0
  561. data/lib/serrano/cli/base.rb +92 -0
  562. data/lib/serrano/cli/generate.rb +285 -0
  563. data/lib/serrano/cli/templates/controller.rb.tt +92 -0
  564. data/lib/serrano/cli/templates/entity.rb.tt +43 -0
  565. data/lib/serrano/cli/templates/entity_validatable.rb.tt +136 -0
  566. data/lib/serrano/cli/templates/migration.rb.tt +19 -0
  567. data/lib/serrano/cli/templates/new_default_config.ru.tt +6 -0
  568. data/lib/serrano/cli/templates/new_default_db.rb.tt +3 -0
  569. data/lib/serrano/cli/templates/new_default_gemfile.tt +6 -0
  570. data/lib/serrano/cli/templates/new_minimal_config.ru.tt +5 -0
  571. data/lib/serrano/cli/templates/new_minimal_gemfile.tt +4 -0
  572. data/lib/serrano/cli/templates/new_project_config.ru.tt +8 -0
  573. data/lib/serrano/cli/templates/new_project_db.rb.tt +3 -0
  574. data/lib/serrano/cli/templates/new_project_gemfile.tt +8 -0
  575. data/lib/serrano/cli/templates/repository.rb.tt +42 -0
  576. data/lib/serrano/cli/templates/service_create.rb.tt +40 -0
  577. data/lib/serrano/cli/templates/service_destroy.rb.tt +20 -0
  578. data/lib/serrano/cli/templates/service_generic.rb.tt +15 -0
  579. data/lib/serrano/cli/templates/service_index.rb.tt +17 -0
  580. data/lib/serrano/cli/templates/service_show.rb.tt +20 -0
  581. data/lib/serrano/cli/templates/service_update.rb.tt +41 -0
  582. data/lib/serrano/dispatcher.rb +53 -0
  583. data/lib/serrano/request.rb +78 -0
  584. data/lib/serrano/response.rb +33 -0
  585. data/lib/serrano/router.rb +80 -0
  586. data/lib/serrano/version.rb +5 -0
  587. data/lib/serrano.rb +11 -0
  588. metadata +768 -0
@@ -0,0 +1,3022 @@
1
+ # frozen-string-literal: true
2
+
3
+ require_relative '../utils/unmodified_identifiers'
4
+
5
+ module Sequel
6
+ # Top level module for holding all PostgreSQL-related modules and classes
7
+ # for Sequel. All adapters that connect to PostgreSQL support the following options:
8
+ #
9
+ # :client_min_messages :: Change the minimum level of messages that PostgreSQL will send to the
10
+ # the client. The PostgreSQL default is NOTICE, the Sequel default is
11
+ # WARNING. Set to nil to not change the server default. Overridable on
12
+ # a per instance basis via the :client_min_messages option.
13
+ # :force_standard_strings :: Set to false to not force the use of standard strings. Overridable
14
+ # on a per instance basis via the :force_standard_strings option.
15
+ # :search_path :: Set the schema search_path for this Database's connections.
16
+ # Allows to to set which schemas do not need explicit
17
+ # qualification, and in which order to check the schemas when
18
+ # an unqualified object is referenced.
19
+ module Postgres
20
+ Sequel::Database.set_shared_adapter_scheme(:postgres, self)
21
+
22
+ # Exception class ranged when literalizing integers outside the bigint/int8 range.
23
+ class IntegerOutsideBigintRange < InvalidValue; end
24
+
25
+ NAN = 0.0/0.0
26
+ PLUS_INFINITY = 1.0/0.0
27
+ MINUS_INFINITY = -1.0/0.0
28
+
29
+ boolean = Object.new
30
+ def boolean.call(s) s == 't' end
31
+ integer = Object.new
32
+ def integer.call(s) s.to_i end
33
+ float = Object.new
34
+ def float.call(s)
35
+ case s
36
+ when 'NaN'
37
+ NAN
38
+ when 'Infinity'
39
+ PLUS_INFINITY
40
+ when '-Infinity'
41
+ MINUS_INFINITY
42
+ else
43
+ s.to_f
44
+ end
45
+ end
46
+ date = Object.new
47
+ def date.call(s) ::Date.new(*s.split('-').map(&:to_i)) end
48
+ TYPE_TRANSLATOR_DATE = date.freeze
49
+ bytea = Object.new
50
+ def bytea.call(str)
51
+ str = if str.start_with?('\\x')
52
+ # PostgreSQL 9.0+ bytea hex format
53
+ str[2..-1].gsub(/(..)/){|s| s.to_i(16).chr}
54
+ else
55
+ # Historical PostgreSQL bytea escape format
56
+ str.gsub(/\\(\\|'|[0-3][0-7][0-7])/) {|s|
57
+ if s.size == 2 then s[1,1] else s[1,3].oct.chr end
58
+ }
59
+ end
60
+ ::Sequel::SQL::Blob.new(str)
61
+ end
62
+
63
+ CONVERSION_PROCS = {}
64
+
65
+ {
66
+ [16] => boolean,
67
+ [17] => bytea,
68
+ [20, 21, 23, 26] => integer,
69
+ [700, 701] => float,
70
+ [1700] => ::Kernel.method(:BigDecimal),
71
+ [1083, 1266] => ::Sequel.method(:string_to_time),
72
+ [1082] => ::Sequel.method(:string_to_date),
73
+ [1184, 1114] => ::Sequel.method(:database_to_application_timestamp),
74
+ }.each do |k,v|
75
+ k.each do |n|
76
+ CONVERSION_PROCS[n] = v
77
+ end
78
+ end
79
+ CONVERSION_PROCS.freeze
80
+
81
+ module MockAdapterDatabaseMethods
82
+ def bound_variable_arg(arg, conn)
83
+ arg
84
+ end
85
+
86
+ def primary_key(table)
87
+ :id
88
+ end
89
+
90
+ private
91
+
92
+ # Handle NoMethodErrors when parsing schema due to output_identifier
93
+ # being called with nil when the Database fetch results are not set
94
+ # to what schema parsing expects.
95
+ def schema_parse_table(table, opts=OPTS)
96
+ super
97
+ rescue NoMethodError
98
+ []
99
+ end
100
+ end
101
+
102
+ def self.mock_adapter_setup(db)
103
+ db.instance_exec do
104
+ @server_version = 170000
105
+ initialize_postgres_adapter
106
+ extend(MockAdapterDatabaseMethods)
107
+ end
108
+ end
109
+
110
+ class CreateTableGenerator < Sequel::Schema::CreateTableGenerator
111
+ # Add an exclusion constraint when creating the table. Elements should be
112
+ # an array of 2 element arrays, with the first element being the column or
113
+ # expression the exclusion constraint is applied to, and the second element
114
+ # being the operator to use for the column/expression to check for exclusion:
115
+ #
116
+ # exclude([[:col1, '&&'], [:col2, '=']])
117
+ # # EXCLUDE USING gist (col1 WITH &&, col2 WITH =)
118
+ #
119
+ # To use a custom operator class, you need to use Sequel.lit with the expression
120
+ # and operator class:
121
+ #
122
+ # exclude([[Sequel.lit('col1 inet_ops'), '&&'], [:col2, '=']])
123
+ # # EXCLUDE USING gist (col1 inet_ops WITH &&, col2 WITH =)
124
+ #
125
+ # Options supported:
126
+ #
127
+ # :include :: Include additional columns in the underlying index, to
128
+ # allow for index-only scans in more cases (PostgreSQL 11+).
129
+ # :name :: Name the constraint with the given name (useful if you may
130
+ # need to drop the constraint later)
131
+ # :using :: Override the index_method for the exclusion constraint (defaults to gist).
132
+ # :where :: Create a partial exclusion constraint, which only affects
133
+ # a subset of table rows, value should be a filter expression.
134
+ def exclude(elements, opts=OPTS)
135
+ constraints << {:type => :exclude, :elements => elements}.merge!(opts)
136
+ end
137
+ end
138
+
139
+ class AlterTableGenerator < Sequel::Schema::AlterTableGenerator
140
+ # Adds an exclusion constraint to an existing table, see
141
+ # CreateTableGenerator#exclude.
142
+ def add_exclusion_constraint(elements, opts=OPTS)
143
+ @operations << {:op => :add_constraint, :type => :exclude, :elements => elements}.merge!(opts)
144
+ end
145
+
146
+ # Alter an existing constraint. Options:
147
+ # :deferrable :: Modify deferrable setting for constraint (PostgreSQL 9.4+):
148
+ # true :: DEFERRABLE INITIALLY DEFERRED
149
+ # false :: NOT DEFERRABLE
150
+ # :immediate :: DEFERRABLE INITIALLY IMMEDIATE
151
+ # :enforced :: Set true to use ENFORCED, or false to use NOT ENFORCED (PostgreSQL 18+)
152
+ # :inherit :: Set true to use INHERIT, or false to use NO INHERIT (PostgreSQL 18+)
153
+ def alter_constraint(name, opts=OPTS)
154
+ @operations << {:op => :alter_constraint, :name => name}.merge!(opts)
155
+ end
156
+
157
+ # :inherit :: Set true to use INHERIT, or false to use NO INHERIT (PostgreSQL 18+)
158
+ def rename_constraint(name, new_name)
159
+ @operations << {:op => :rename_constraint, :name => name, :new_name => new_name}
160
+ end
161
+
162
+ # Validate the constraint with the given name, which should have
163
+ # been added previously with NOT VALID.
164
+ def validate_constraint(name)
165
+ @operations << {:op => :validate_constraint, :name => name}
166
+ end
167
+ end
168
+
169
+ # Generator used for creating tables that are partitions of other tables.
170
+ class CreatePartitionOfTableGenerator
171
+ MINVALUE = Sequel.lit('MINVALUE').freeze
172
+ MAXVALUE = Sequel.lit('MAXVALUE').freeze
173
+
174
+ def initialize(&block)
175
+ instance_exec(&block)
176
+ end
177
+
178
+ # The minimum value of the data type used in range partitions, useful
179
+ # as an argument to #from.
180
+ def minvalue
181
+ MINVALUE
182
+ end
183
+
184
+ # The minimum value of the data type used in range partitions, useful
185
+ # as an argument to #to.
186
+ def maxvalue
187
+ MAXVALUE
188
+ end
189
+
190
+ # Assumes range partitioning, sets the inclusive minimum value of the range for
191
+ # this partition.
192
+ def from(*v)
193
+ @from = v
194
+ end
195
+
196
+ # Assumes range partitioning, sets the exclusive maximum value of the range for
197
+ # this partition.
198
+ def to(*v)
199
+ @to = v
200
+ end
201
+
202
+ # Assumes list partitioning, sets the values to be included in this partition.
203
+ def values_in(*v)
204
+ @in = v
205
+ end
206
+
207
+ # Assumes hash partitioning, sets the modulus for this parition.
208
+ def modulus(v)
209
+ @modulus = v
210
+ end
211
+
212
+ # Assumes hash partitioning, sets the remainder for this parition.
213
+ def remainder(v)
214
+ @remainder = v
215
+ end
216
+
217
+ # Sets that this is a default partition, where values not in other partitions
218
+ # are stored.
219
+ def default
220
+ @default = true
221
+ end
222
+
223
+ # The from and to values of this partition for a range partition.
224
+ def range
225
+ [@from, @to]
226
+ end
227
+
228
+ # The values to include in this partition for a list partition.
229
+ def list
230
+ @in
231
+ end
232
+
233
+ # The modulus and remainder to use for this partition for a hash partition.
234
+ def hash_values
235
+ [@modulus, @remainder]
236
+ end
237
+
238
+ # Determine the appropriate partition type for this partition by which methods
239
+ # were called on it.
240
+ def partition_type
241
+ raise Error, "Unable to determine partition type, multiple different partitioning methods called" if [@from || @to, @list, @modulus || @remainder, @default].compact.length > 1
242
+
243
+ if @from || @to
244
+ raise Error, "must call both from and to when creating a partition of a table if calling either" unless @from && @to
245
+ :range
246
+ elsif @in
247
+ :list
248
+ elsif @modulus || @remainder
249
+ raise Error, "must call both modulus and remainder when creating a partition of a table if calling either" unless @modulus && @remainder
250
+ :hash
251
+ elsif @default
252
+ :default
253
+ else
254
+ raise Error, "unable to determine partition type, no partitioning methods called"
255
+ end
256
+ end
257
+ end
258
+
259
+ # Error raised when Sequel determines a PostgreSQL exclusion constraint has been violated.
260
+ class ExclusionConstraintViolation < Sequel::ConstraintViolation; end
261
+
262
+ module DatabaseMethods
263
+ include UnmodifiedIdentifiers::DatabaseMethods
264
+
265
+ FOREIGN_KEY_LIST_ON_DELETE_MAP = {'a'=>:no_action, 'r'=>:restrict, 'c'=>:cascade, 'n'=>:set_null, 'd'=>:set_default}.freeze
266
+ ON_COMMIT = {:drop => 'DROP', :delete_rows => 'DELETE ROWS', :preserve_rows => 'PRESERVE ROWS'}.freeze
267
+ ON_COMMIT.each_value(&:freeze)
268
+
269
+ # SQL fragment for custom sequences (ones not created by serial primary key),
270
+ # Returning the schema and literal form of the sequence name, by parsing
271
+ # the column defaults table.
272
+ SELECT_CUSTOM_SEQUENCE_SQL = (<<-end_sql
273
+ SELECT name.nspname AS "schema",
274
+ CASE
275
+ WHEN split_part(pg_get_expr(def.adbin, attr.attrelid), '''', 2) ~ '.' THEN
276
+ substr(split_part(pg_get_expr(def.adbin, attr.attrelid), '''', 2),
277
+ strpos(split_part(pg_get_expr(def.adbin, attr.attrelid), '''', 2), '.')+1)
278
+ ELSE split_part(pg_get_expr(def.adbin, attr.attrelid), '''', 2)
279
+ END AS "sequence"
280
+ FROM pg_class t
281
+ JOIN pg_namespace name ON (t.relnamespace = name.oid)
282
+ JOIN pg_attribute attr ON (t.oid = attrelid)
283
+ JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
284
+ JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
285
+ WHERE cons.contype = 'p'
286
+ AND pg_get_expr(def.adbin, attr.attrelid) ~* 'nextval'
287
+ end_sql
288
+ ).strip.gsub(/\s+/, ' ').freeze # SEQUEL6: Remove
289
+
290
+ # SQL fragment for determining primary key column for the given table. Only
291
+ # returns the first primary key if the table has a composite primary key.
292
+ SELECT_PK_SQL = (<<-end_sql
293
+ SELECT pg_attribute.attname AS pk
294
+ FROM pg_class, pg_attribute, pg_index, pg_namespace
295
+ WHERE pg_class.oid = pg_attribute.attrelid
296
+ AND pg_class.relnamespace = pg_namespace.oid
297
+ AND pg_class.oid = pg_index.indrelid
298
+ AND pg_index.indkey[0] = pg_attribute.attnum
299
+ AND pg_index.indisprimary = 't'
300
+ end_sql
301
+ ).strip.gsub(/\s+/, ' ').freeze # SEQUEL6: Remove
302
+
303
+ # SQL fragment for getting sequence associated with table's
304
+ # primary key, assuming it was a serial primary key column.
305
+ SELECT_SERIAL_SEQUENCE_SQL = (<<-end_sql
306
+ SELECT name.nspname AS "schema", seq.relname AS "sequence"
307
+ FROM pg_class seq, pg_attribute attr, pg_depend dep,
308
+ pg_namespace name, pg_constraint cons, pg_class t
309
+ WHERE seq.oid = dep.objid
310
+ AND seq.relnamespace = name.oid
311
+ AND seq.relkind = 'S'
312
+ AND attr.attrelid = dep.refobjid
313
+ AND attr.attnum = dep.refobjsubid
314
+ AND attr.attrelid = cons.conrelid
315
+ AND attr.attnum = cons.conkey[1]
316
+ AND attr.attrelid = t.oid
317
+ AND cons.contype = 'p'
318
+ end_sql
319
+ ).strip.gsub(/\s+/, ' ').freeze # SEQUEL6: Remove
320
+
321
+ # A hash of conversion procs, keyed by type integer (oid) and
322
+ # having callable values for the conversion proc for that type.
323
+ attr_reader :conversion_procs
324
+
325
+ # Set a conversion proc for the given oid. The callable can
326
+ # be passed either as a argument or a block.
327
+ def add_conversion_proc(oid, callable=nil, &block)
328
+ conversion_procs[oid] = callable || block
329
+ end
330
+
331
+ # Add a conversion proc for a named type, using the given block.
332
+ # This should be used for types without fixed OIDs, which includes all types that
333
+ # are not included in a default PostgreSQL installation.
334
+ def add_named_conversion_proc(name, &block)
335
+ unless oid = from(:pg_type).where(:typtype=>['b', 'e'], :typname=>name.to_s).get(:oid)
336
+ raise Error, "No matching type in pg_type for #{name.inspect}"
337
+ end
338
+ add_conversion_proc(oid, block)
339
+ end
340
+
341
+ def commit_prepared_transaction(transaction_id, opts=OPTS)
342
+ run("COMMIT PREPARED #{literal(transaction_id)}", opts)
343
+ end
344
+
345
+ # A hash of metadata for CHECK constraints on the table.
346
+ # Keys are CHECK constraint name symbols. Values are hashes with the following keys:
347
+ # :definition :: An SQL fragment for the definition of the constraint
348
+ # :columns :: An array of column symbols for the columns referenced in the constraint,
349
+ # can be an empty array if the database cannot deteremine the column symbols.
350
+ def check_constraints(table)
351
+ m = output_identifier_meth
352
+
353
+ hash = {}
354
+ _check_constraints_ds.where_each(:conrelid=>regclass_oid(table)) do |row|
355
+ constraint = m.call(row[:constraint])
356
+ entry = hash[constraint] ||= {:definition=>row[:definition], :columns=>[], :validated=>row[:validated], :enforced=>row[:enforced]}
357
+ entry[:columns] << m.call(row[:column]) if row[:column]
358
+ end
359
+
360
+ hash
361
+ end
362
+
363
+ # Convert the first primary key column in the +table+ from being a serial column to being an identity column.
364
+ # If the column is already an identity column, assume it was already converted and make no changes.
365
+ #
366
+ # Only supported on PostgreSQL 10.2+, since on those versions Sequel will use identity columns
367
+ # instead of serial columns for auto incrementing primary keys. Only supported when running as
368
+ # a superuser, since regular users cannot modify system tables, and there is no way to keep an
369
+ # existing sequence when changing an existing column to be an identity column.
370
+ #
371
+ # This method can raise an exception in at least the following cases where it may otherwise succeed
372
+ # (there may be additional cases not listed here):
373
+ #
374
+ # * The serial column was added after table creation using PostgreSQL <7.3
375
+ # * A regular index also exists on the column (such an index can probably be dropped as the
376
+ # primary key index should suffice)
377
+ #
378
+ # Options:
379
+ # :column :: Specify the column to convert instead of using the first primary key column
380
+ # :server :: Run the SQL on the given server
381
+ def convert_serial_to_identity(table, opts=OPTS)
382
+ raise Error, "convert_serial_to_identity is only supported on PostgreSQL 10.2+" unless server_version >= 100002
383
+
384
+ server = opts[:server]
385
+ server_hash = server ? {:server=>server} : OPTS
386
+ ds = dataset
387
+ ds = ds.server(server) if server
388
+
389
+ raise Error, "convert_serial_to_identity requires superuser permissions" unless ds.get{current_setting('is_superuser')} == 'on'
390
+
391
+ table_oid = regclass_oid(table)
392
+ im = input_identifier_meth
393
+ unless column = (opts[:column] || ((sch = schema(table).find{|_, sc| sc[:primary_key] && sc[:auto_increment]}) && sch[0]))
394
+ raise Error, "could not determine column to convert from serial to identity automatically"
395
+ end
396
+ column = im.call(column)
397
+
398
+ column_num = ds.from(:pg_attribute).
399
+ where(:attrelid=>table_oid, :attname=>column).
400
+ get(:attnum)
401
+
402
+ pg_class = Sequel.cast('pg_class', :regclass)
403
+ res = ds.from(:pg_depend).
404
+ where(:refclassid=>pg_class, :refobjid=>table_oid, :refobjsubid=>column_num, :classid=>pg_class, :objsubid=>0, :deptype=>%w'a i').
405
+ select_map([:objid, Sequel.as({:deptype=>'i'}, :v)])
406
+
407
+ case res.length
408
+ when 0
409
+ raise Error, "unable to find related sequence when converting serial to identity"
410
+ when 1
411
+ seq_oid, already_identity = res.first
412
+ else
413
+ raise Error, "more than one linked sequence found when converting serial to identity"
414
+ end
415
+
416
+ return if already_identity
417
+
418
+ transaction(server_hash) do
419
+ run("ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(column)} DROP DEFAULT", server_hash)
420
+
421
+ ds.from(:pg_depend).
422
+ where(:classid=>pg_class, :objid=>seq_oid, :objsubid=>0, :deptype=>'a').
423
+ update(:deptype=>'i')
424
+
425
+ ds.from(:pg_attribute).
426
+ where(:attrelid=>table_oid, :attname=>column).
427
+ update(:attidentity=>'d')
428
+ end
429
+
430
+ remove_cached_schema(table)
431
+ nil
432
+ end
433
+
434
+ # Creates the function in the database. Arguments:
435
+ # name :: name of the function to create
436
+ # definition :: string definition of the function, or object file for a dynamically loaded C function.
437
+ # opts :: options hash:
438
+ # :args :: function arguments, can be either a symbol or string specifying a type or an array of 1-3 elements:
439
+ # 1 :: argument data type
440
+ # 2 :: argument name
441
+ # 3 :: argument mode (e.g. in, out, inout)
442
+ # :behavior :: Should be IMMUTABLE, STABLE, or VOLATILE. PostgreSQL assumes VOLATILE by default.
443
+ # :parallel :: The thread safety attribute of the function. Should be SAFE, UNSAFE, RESTRICTED. PostgreSQL assumes UNSAFE by default.
444
+ # :cost :: The estimated cost of the function, used by the query planner.
445
+ # :language :: The language the function uses. SQL is the default.
446
+ # :link_symbol :: For a dynamically loaded see function, the function's link symbol if different from the definition argument.
447
+ # :returns :: The data type returned by the function. If you are using OUT or INOUT argument modes, this is ignored.
448
+ # Otherwise, if this is not specified, void is used by default to specify the function is not supposed to return a value.
449
+ # :rows :: The estimated number of rows the function will return. Only use if the function returns SETOF something.
450
+ # :security_definer :: Makes the privileges of the function the same as the privileges of the user who defined the function instead of
451
+ # the privileges of the user who runs the function. There are security implications when doing this, see the PostgreSQL documentation.
452
+ # :set :: Configuration variables to set while the function is being run, can be a hash or an array of two pairs. search_path is
453
+ # often used here if :security_definer is used.
454
+ # :strict :: Makes the function return NULL when any argument is NULL.
455
+ def create_function(name, definition, opts=OPTS)
456
+ self << create_function_sql(name, definition, opts)
457
+ end
458
+
459
+ # Create the procedural language in the database. Arguments:
460
+ # name :: Name of the procedural language (e.g. plpgsql)
461
+ # opts :: options hash:
462
+ # :handler :: The name of a previously registered function used as a call handler for this language.
463
+ # :replace :: Replace the installed language if it already exists (on PostgreSQL 9.0+).
464
+ # :trusted :: Marks the language being created as trusted, allowing unprivileged users to create functions using this language.
465
+ # :validator :: The name of previously registered function used as a validator of functions defined in this language.
466
+ def create_language(name, opts=OPTS)
467
+ self << create_language_sql(name, opts)
468
+ end
469
+
470
+ # Create a schema in the database. Arguments:
471
+ # name :: Name of the schema (e.g. admin)
472
+ # opts :: options hash:
473
+ # :if_not_exists :: Don't raise an error if the schema already exists (PostgreSQL 9.3+)
474
+ # :owner :: The owner to set for the schema (defaults to current user if not specified)
475
+ def create_schema(name, opts=OPTS)
476
+ self << create_schema_sql(name, opts)
477
+ end
478
+
479
+ # Support partitions of tables using the :partition_of option.
480
+ def create_table(name, options=OPTS, &block)
481
+ if options[:partition_of]
482
+ create_partition_of_table_from_generator(name, CreatePartitionOfTableGenerator.new(&block), options)
483
+ return
484
+ end
485
+
486
+ super
487
+ end
488
+
489
+ # Support partitions of tables using the :partition_of option.
490
+ def create_table?(name, options=OPTS, &block)
491
+ if options[:partition_of]
492
+ create_table(name, options.merge!(:if_not_exists=>true), &block)
493
+ return
494
+ end
495
+
496
+ super
497
+ end
498
+
499
+ # Create a trigger in the database. Arguments:
500
+ # table :: the table on which this trigger operates
501
+ # name :: the name of this trigger
502
+ # function :: the function to call for this trigger, which should return type trigger.
503
+ # opts :: options hash:
504
+ # :after :: Calls the trigger after execution instead of before.
505
+ # :args :: An argument or array of arguments to pass to the function.
506
+ # :each_row :: Calls the trigger for each row instead of for each statement.
507
+ # :events :: Can be :insert, :update, :delete, or an array of any of those. Calls the trigger whenever that type of statement is used. By default,
508
+ # the trigger is called for insert, update, or delete.
509
+ # :replace :: Replace the trigger with the same name if it already exists (PostgreSQL 14+).
510
+ # :when :: A filter to use for the trigger
511
+ def create_trigger(table, name, function, opts=OPTS)
512
+ self << create_trigger_sql(table, name, function, opts)
513
+ end
514
+
515
+ def database_type
516
+ :postgres
517
+ end
518
+
519
+ # For constraints that are deferrable, defer constraints until
520
+ # transaction commit. Options:
521
+ #
522
+ # :constraints :: An identifier of the constraint, or an array of
523
+ # identifiers for constraints, to apply this
524
+ # change to specific constraints.
525
+ # :server :: The server/shard on which to run the query.
526
+ #
527
+ # Examples:
528
+ #
529
+ # DB.defer_constraints
530
+ # # SET CONSTRAINTS ALL DEFERRED
531
+ #
532
+ # DB.defer_constraints(constraints: [:c1, Sequel[:sc][:c2]])
533
+ # # SET CONSTRAINTS "c1", "sc"."s2" DEFERRED
534
+ def defer_constraints(opts=OPTS)
535
+ _set_constraints(' DEFERRED', opts)
536
+ end
537
+
538
+ # Use PostgreSQL's DO syntax to execute an anonymous code block. The code should
539
+ # be the literal code string to use in the underlying procedural language. Options:
540
+ #
541
+ # :language :: The procedural language the code is written in. The PostgreSQL
542
+ # default is plpgsql. Can be specified as a string or a symbol.
543
+ def do(code, opts=OPTS)
544
+ language = opts[:language]
545
+ run "DO #{"LANGUAGE #{literal(language.to_s)} " if language}#{literal(code)}"
546
+ end
547
+
548
+ # Drops the function from the database. Arguments:
549
+ # name :: name of the function to drop
550
+ # opts :: options hash:
551
+ # :args :: The arguments for the function. See create_function_sql.
552
+ # :cascade :: Drop other objects depending on this function.
553
+ # :if_exists :: Don't raise an error if the function doesn't exist.
554
+ def drop_function(name, opts=OPTS)
555
+ self << drop_function_sql(name, opts)
556
+ end
557
+
558
+ # Drops a procedural language from the database. Arguments:
559
+ # name :: name of the procedural language to drop
560
+ # opts :: options hash:
561
+ # :cascade :: Drop other objects depending on this function.
562
+ # :if_exists :: Don't raise an error if the function doesn't exist.
563
+ def drop_language(name, opts=OPTS)
564
+ self << drop_language_sql(name, opts)
565
+ end
566
+
567
+ # Drops a schema from the database. Arguments:
568
+ # name :: name of the schema to drop
569
+ # opts :: options hash:
570
+ # :cascade :: Drop all objects in this schema.
571
+ # :if_exists :: Don't raise an error if the schema doesn't exist.
572
+ def drop_schema(name, opts=OPTS)
573
+ self << drop_schema_sql(name, opts)
574
+ remove_all_cached_schemas
575
+ end
576
+
577
+ # Drops a trigger from the database. Arguments:
578
+ # table :: table from which to drop the trigger
579
+ # name :: name of the trigger to drop
580
+ # opts :: options hash:
581
+ # :cascade :: Drop other objects depending on this function.
582
+ # :if_exists :: Don't raise an error if the function doesn't exist.
583
+ def drop_trigger(table, name, opts=OPTS)
584
+ self << drop_trigger_sql(table, name, opts)
585
+ end
586
+
587
+ # Return full foreign key information using the pg system tables, including
588
+ # :name, :on_delete, :on_update, and :deferrable entries in the hashes.
589
+ #
590
+ # Supports additional options:
591
+ # :reverse :: Instead of returning foreign keys in the current table, return
592
+ # foreign keys in other tables that reference the current table.
593
+ # :schema :: Set to true to have the :table value in the hashes be a qualified
594
+ # identifier. Set to false to use a separate :schema value with
595
+ # the related schema. Defaults to whether the given table argument
596
+ # is a qualified identifier.
597
+ def foreign_key_list(table, opts=OPTS)
598
+ m = output_identifier_meth
599
+ schema, _ = opts.fetch(:schema, schema_and_table(table))
600
+
601
+ h = {}
602
+ fklod_map = FOREIGN_KEY_LIST_ON_DELETE_MAP
603
+ reverse = opts[:reverse]
604
+
605
+ (reverse ? _reverse_foreign_key_list_ds : _foreign_key_list_ds).where_each(Sequel[:cl][:oid]=>regclass_oid(table)) do |row|
606
+ if reverse
607
+ key = [row[:schema], row[:table], row[:name]]
608
+ else
609
+ key = row[:name]
610
+ end
611
+
612
+ if r = h[key]
613
+ r[:columns] << m.call(row[:column])
614
+ r[:key] << m.call(row[:refcolumn])
615
+ else
616
+ entry = h[key] = {
617
+ :name=>m.call(row[:name]),
618
+ :columns=>[m.call(row[:column])],
619
+ :key=>[m.call(row[:refcolumn])],
620
+ :on_update=>fklod_map[row[:on_update]],
621
+ :on_delete=>fklod_map[row[:on_delete]],
622
+ :deferrable=>row[:deferrable],
623
+ :validated=>row[:validated],
624
+ :enforced=>row[:enforced],
625
+ :table=>schema ? SQL::QualifiedIdentifier.new(m.call(row[:schema]), m.call(row[:table])) : m.call(row[:table]),
626
+ }
627
+
628
+ unless schema
629
+ # If not combining schema information into the :table entry
630
+ # include it as a separate entry.
631
+ entry[:schema] = m.call(row[:schema])
632
+ end
633
+ end
634
+ end
635
+
636
+ h.values
637
+ end
638
+
639
+ def freeze
640
+ server_version
641
+ supports_prepared_transactions?
642
+ _schema_ds
643
+ _select_serial_sequence_ds
644
+ _select_custom_sequence_ds
645
+ _select_pk_ds
646
+ _indexes_ds
647
+ _check_constraints_ds
648
+ _foreign_key_list_ds
649
+ _reverse_foreign_key_list_ds
650
+ @conversion_procs.freeze
651
+ super
652
+ end
653
+
654
+ # Immediately apply deferrable constraints.
655
+ #
656
+ # :constraints :: An identifier of the constraint, or an array of
657
+ # identifiers for constraints, to apply this
658
+ # change to specific constraints.
659
+ # :server :: The server/shard on which to run the query.
660
+ #
661
+ # Examples:
662
+ #
663
+ # DB.immediate_constraints
664
+ # # SET CONSTRAINTS ALL IMMEDIATE
665
+ #
666
+ # DB.immediate_constraints(constraints: [:c1, Sequel[:sc][:c2]])
667
+ # # SET CONSTRAINTS "c1", "sc"."s2" IMMEDIATE
668
+ def immediate_constraints(opts=OPTS)
669
+ _set_constraints(' IMMEDIATE', opts)
670
+ end
671
+
672
+ # Use the pg_* system tables to determine indexes on a table. Options:
673
+ #
674
+ # :include_partial :: Set to true to include partial indexes
675
+ # :invalid :: Set to true or :only to only return invalid indexes.
676
+ # Set to :include to also return both valid and invalid indexes.
677
+ # When not set or other value given, does not return invalid indexes.
678
+ def indexes(table, opts=OPTS)
679
+ m = output_identifier_meth
680
+ cond = {Sequel[:tab][:oid]=>regclass_oid(table, opts)}
681
+ cond[:indpred] = nil unless opts[:include_partial]
682
+
683
+ case opts[:invalid]
684
+ when true, :only
685
+ cond[:indisvalid] = false
686
+ when :include
687
+ # nothing
688
+ else
689
+ cond[:indisvalid] = true
690
+ end
691
+
692
+ indexes = {}
693
+ _indexes_ds.where_each(cond) do |r|
694
+ i = indexes[m.call(r[:name])] ||= {:columns=>[], :unique=>r[:unique], :deferrable=>r[:deferrable]}
695
+ i[:columns] << m.call(r[:column])
696
+ end
697
+ indexes
698
+ end
699
+
700
+ # Dataset containing all current database locks
701
+ def locks
702
+ dataset.from(:pg_class).join(:pg_locks, :relation=>:relfilenode).select{[pg_class[:relname], Sequel::SQL::ColumnAll.new(:pg_locks)]}
703
+ end
704
+
705
+ # Notifies the given channel. See the PostgreSQL NOTIFY documentation. Options:
706
+ #
707
+ # :payload :: The payload string to use for the NOTIFY statement. Only supported
708
+ # in PostgreSQL 9.0+.
709
+ # :server :: The server to which to send the NOTIFY statement, if the sharding support
710
+ # is being used.
711
+ def notify(channel, opts=OPTS)
712
+ sql = String.new
713
+ sql << "NOTIFY "
714
+ dataset.send(:identifier_append, sql, channel)
715
+ if payload = opts[:payload]
716
+ sql << ", "
717
+ dataset.literal_append(sql, payload.to_s)
718
+ end
719
+ execute_ddl(sql, opts)
720
+ end
721
+
722
+ # Return primary key for the given table.
723
+ def primary_key(table, opts=OPTS)
724
+ quoted_table = quote_schema_table(table)
725
+ Sequel.synchronize{return @primary_keys[quoted_table] if @primary_keys.has_key?(quoted_table)}
726
+ value = _select_pk_ds.where_single_value(Sequel[:pg_class][:oid] => regclass_oid(table, opts))
727
+ Sequel.synchronize{@primary_keys[quoted_table] = value}
728
+ end
729
+
730
+ # Return the sequence providing the default for the primary key for the given table.
731
+ def primary_key_sequence(table, opts=OPTS)
732
+ quoted_table = quote_schema_table(table)
733
+ Sequel.synchronize{return @primary_key_sequences[quoted_table] if @primary_key_sequences.has_key?(quoted_table)}
734
+ cond = {Sequel[:t][:oid] => regclass_oid(table, opts)}
735
+ value = if pks = _select_serial_sequence_ds.first(cond)
736
+ literal(SQL::QualifiedIdentifier.new(pks[:schema], pks[:sequence]))
737
+ elsif pks = _select_custom_sequence_ds.first(cond)
738
+ literal(SQL::QualifiedIdentifier.new(pks[:schema], LiteralString.new(pks[:sequence])))
739
+ end
740
+
741
+ Sequel.synchronize{@primary_key_sequences[quoted_table] = value} if value
742
+ end
743
+
744
+ # Rename a schema in the database. Arguments:
745
+ # name :: Current name of the schema
746
+ # opts :: New name for the schema
747
+ def rename_schema(name, new_name)
748
+ self << rename_schema_sql(name, new_name)
749
+ remove_all_cached_schemas
750
+ end
751
+
752
+ # Refresh the materialized view with the given name.
753
+ #
754
+ # DB.refresh_view(:items_view)
755
+ # # REFRESH MATERIALIZED VIEW items_view
756
+ # DB.refresh_view(:items_view, concurrently: true)
757
+ # # REFRESH MATERIALIZED VIEW CONCURRENTLY items_view
758
+ def refresh_view(name, opts=OPTS)
759
+ run "REFRESH MATERIALIZED VIEW#{' CONCURRENTLY' if opts[:concurrently]} #{quote_schema_table(name)}"
760
+ end
761
+
762
+ # Reset the primary key sequence for the given table, basing it on the
763
+ # maximum current value of the table's primary key.
764
+ def reset_primary_key_sequence(table)
765
+ return unless seq = primary_key_sequence(table)
766
+ pk = SQL::Identifier.new(primary_key(table))
767
+ db = self
768
+ s, t = schema_and_table(table)
769
+ table = Sequel.qualify(s, t) if s
770
+
771
+ if server_version >= 100000
772
+ seq_ds = metadata_dataset.from(:pg_sequence).where(:seqrelid=>regclass_oid(LiteralString.new(seq)))
773
+ increment_by = :seqincrement
774
+ min_value = :seqmin
775
+ # :nocov:
776
+ else
777
+ seq_ds = metadata_dataset.from(LiteralString.new(seq))
778
+ increment_by = :increment_by
779
+ min_value = :min_value
780
+ # :nocov:
781
+ end
782
+
783
+ get{setval(seq, db[table].select(coalesce(max(pk)+seq_ds.select(increment_by), seq_ds.select(min_value))), false)}
784
+ end
785
+
786
+ def rollback_prepared_transaction(transaction_id, opts=OPTS)
787
+ run("ROLLBACK PREPARED #{literal(transaction_id)}", opts)
788
+ end
789
+
790
+ # PostgreSQL uses SERIAL psuedo-type instead of AUTOINCREMENT for
791
+ # managing incrementing primary keys.
792
+ def serial_primary_key_options
793
+ # :nocov:
794
+ auto_increment_key = server_version >= 100002 ? :identity : :serial
795
+ # :nocov:
796
+ {:primary_key => true, auto_increment_key => true, :type=>Integer}
797
+ end
798
+
799
+ # The version of the PostgreSQL server, used for determining capability.
800
+ def server_version(server=nil)
801
+ return @server_version if @server_version
802
+ ds = dataset
803
+ ds = ds.server(server) if server
804
+ @server_version = swallow_database_error{ds.with_sql("SELECT CAST(current_setting('server_version_num') AS integer) AS v").single_value} || 0
805
+ end
806
+
807
+ # PostgreSQL supports CREATE TABLE IF NOT EXISTS on 9.1+
808
+ def supports_create_table_if_not_exists?
809
+ server_version >= 90100
810
+ end
811
+
812
+ # PostgreSQL 9.0+ supports some types of deferrable constraints beyond foreign key constraints.
813
+ def supports_deferrable_constraints?
814
+ server_version >= 90000
815
+ end
816
+
817
+ # PostgreSQL supports deferrable foreign key constraints.
818
+ def supports_deferrable_foreign_key_constraints?
819
+ true
820
+ end
821
+
822
+ # PostgreSQL supports DROP TABLE IF EXISTS
823
+ def supports_drop_table_if_exists?
824
+ true
825
+ end
826
+
827
+ # PostgreSQL supports partial indexes.
828
+ def supports_partial_indexes?
829
+ true
830
+ end
831
+
832
+ # PostgreSQL 9.0+ supports trigger conditions.
833
+ def supports_trigger_conditions?
834
+ server_version >= 90000
835
+ end
836
+
837
+ # PostgreSQL supports prepared transactions (two-phase commit) if
838
+ # max_prepared_transactions is greater than 0.
839
+ def supports_prepared_transactions?
840
+ return @supports_prepared_transactions if defined?(@supports_prepared_transactions)
841
+ @supports_prepared_transactions = self['SHOW max_prepared_transactions'].get.to_i > 0
842
+ end
843
+
844
+ # PostgreSQL supports savepoints
845
+ def supports_savepoints?
846
+ true
847
+ end
848
+
849
+ # PostgreSQL supports transaction isolation levels
850
+ def supports_transaction_isolation_levels?
851
+ true
852
+ end
853
+
854
+ # PostgreSQL supports transaction DDL statements.
855
+ def supports_transactional_ddl?
856
+ true
857
+ end
858
+
859
+ # Array of symbols specifying table names in the current database.
860
+ # The dataset used is yielded to the block if one is provided,
861
+ # otherwise, an array of symbols of table names is returned.
862
+ #
863
+ # Options:
864
+ # :qualify :: Return the tables as Sequel::SQL::QualifiedIdentifier instances,
865
+ # using the schema the table is located in as the qualifier.
866
+ # :schema :: The schema to search
867
+ # :server :: The server to use
868
+ def tables(opts=OPTS, &block)
869
+ pg_class_relname(['r', 'p'], opts, &block)
870
+ end
871
+
872
+ # Check whether the given type name string/symbol (e.g. :hstore) is supported by
873
+ # the database.
874
+ def type_supported?(type)
875
+ Sequel.synchronize{return @supported_types[type] if @supported_types.has_key?(type)}
876
+ supported = from(:pg_type).where(:typtype=>'b', :typname=>type.to_s).count > 0
877
+ Sequel.synchronize{return @supported_types[type] = supported}
878
+ end
879
+
880
+ # Creates a dataset that uses the VALUES clause:
881
+ #
882
+ # DB.values([[1, 2], [3, 4]])
883
+ # # VALUES ((1, 2), (3, 4))
884
+ #
885
+ # DB.values([[1, 2], [3, 4]]).order(:column2).limit(1, 1)
886
+ # # VALUES ((1, 2), (3, 4)) ORDER BY column2 LIMIT 1 OFFSET 1
887
+ def values(v)
888
+ raise Error, "Cannot provide an empty array for values" if v.empty?
889
+ @default_dataset.clone(:values=>v)
890
+ end
891
+
892
+ # Array of symbols specifying view names in the current database.
893
+ #
894
+ # Options:
895
+ # :materialized :: Return materialized views
896
+ # :qualify :: Return the views as Sequel::SQL::QualifiedIdentifier instances,
897
+ # using the schema the view is located in as the qualifier.
898
+ # :schema :: The schema to search
899
+ # :server :: The server to use
900
+ def views(opts=OPTS)
901
+ relkind = opts[:materialized] ? 'm' : 'v'
902
+ pg_class_relname(relkind, opts)
903
+ end
904
+
905
+ # Attempt to acquire an exclusive advisory lock with the given lock_id (which should be
906
+ # a 64-bit integer). If successful, yield to the block, then release the advisory lock
907
+ # when the block exits. If unsuccessful, raise a Sequel::AdvisoryLockError.
908
+ #
909
+ # DB.with_advisory_lock(1347){DB.get(1)}
910
+ # # SELECT pg_try_advisory_lock(1357) LIMIT 1
911
+ # # SELECT 1 AS v LIMIT 1
912
+ # # SELECT pg_advisory_unlock(1357) LIMIT 1
913
+ #
914
+ # Options:
915
+ # :wait :: Do not raise an error, instead, wait until the advisory lock can be acquired.
916
+ def with_advisory_lock(lock_id, opts=OPTS)
917
+ ds = dataset
918
+ if server = opts[:server]
919
+ ds = ds.server(server)
920
+ end
921
+
922
+ synchronize(server) do |c|
923
+ begin
924
+ if opts[:wait]
925
+ ds.get{pg_advisory_lock(lock_id)}
926
+ locked = true
927
+ else
928
+ unless locked = ds.get{pg_try_advisory_lock(lock_id)}
929
+ raise AdvisoryLockError, "unable to acquire advisory lock #{lock_id.inspect}"
930
+ end
931
+ end
932
+
933
+ yield
934
+ ensure
935
+ ds.get{pg_advisory_unlock(lock_id)} if locked
936
+ end
937
+ end
938
+ end
939
+
940
+ private
941
+
942
+ # Dataset used to retrieve CHECK constraint information
943
+ def _check_constraints_ds
944
+ @_check_constraints_ds ||= begin
945
+ ds = metadata_dataset.
946
+ from{pg_constraint.as(:co)}.
947
+ left_join(Sequel[:pg_attribute].as(:att), :attrelid=>:conrelid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
948
+ where(:contype=>'c').
949
+ select{[co[:conname].as(:constraint), att[:attname].as(:column), pg_get_constraintdef(co[:oid]).as(:definition)]}
950
+
951
+ _add_validated_enforced_constraint_columns(ds)
952
+ end
953
+ end
954
+
955
+ # Dataset used to retrieve foreign keys referenced by a table
956
+ def _foreign_key_list_ds
957
+ @_foreign_key_list_ds ||= __foreign_key_list_ds(false)
958
+ end
959
+
960
+ # Dataset used to retrieve foreign keys referencing a table
961
+ def _reverse_foreign_key_list_ds
962
+ @_reverse_foreign_key_list_ds ||= __foreign_key_list_ds(true)
963
+ end
964
+
965
+ # Build dataset used for foreign key list methods.
966
+ def __foreign_key_list_ds(reverse)
967
+ if reverse
968
+ ctable = Sequel[:att2]
969
+ cclass = Sequel[:cl2]
970
+ rtable = Sequel[:att]
971
+ rclass = Sequel[:cl]
972
+ else
973
+ ctable = Sequel[:att]
974
+ cclass = Sequel[:cl]
975
+ rtable = Sequel[:att2]
976
+ rclass = Sequel[:cl2]
977
+ end
978
+
979
+ if server_version >= 90500
980
+ cpos = Sequel.expr{array_position(co[:conkey], ctable[:attnum])}
981
+ rpos = Sequel.expr{array_position(co[:confkey], rtable[:attnum])}
982
+ # :nocov:
983
+ else
984
+ range = 0...32
985
+ cpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:conkey], [x]), x]}, 32, ctable[:attnum])}
986
+ rpos = Sequel.expr{SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(co[:confkey], [x]), x]}, 32, rtable[:attnum])}
987
+ # :nocov:
988
+ end
989
+
990
+ ds = metadata_dataset.
991
+ from{pg_constraint.as(:co)}.
992
+ join(Sequel[:pg_class].as(cclass), :oid=>:conrelid).
993
+ join(Sequel[:pg_attribute].as(ctable), :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:conkey])).
994
+ join(Sequel[:pg_class].as(rclass), :oid=>Sequel[:co][:confrelid]).
995
+ join(Sequel[:pg_attribute].as(rtable), :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, Sequel[:co][:confkey])).
996
+ join(Sequel[:pg_namespace].as(:nsp), :oid=>Sequel[:cl2][:relnamespace]).
997
+ order{[co[:conname], cpos]}.
998
+ where{{
999
+ cl[:relkind]=>%w'r p',
1000
+ co[:contype]=>'f',
1001
+ cpos=>rpos
1002
+ }}.
1003
+ select{[
1004
+ co[:conname].as(:name),
1005
+ ctable[:attname].as(:column),
1006
+ co[:confupdtype].as(:on_update),
1007
+ co[:confdeltype].as(:on_delete),
1008
+ cl2[:relname].as(:table),
1009
+ rtable[:attname].as(:refcolumn),
1010
+ SQL::BooleanExpression.new(:AND, co[:condeferrable], co[:condeferred]).as(:deferrable),
1011
+ nsp[:nspname].as(:schema)
1012
+ ]}
1013
+
1014
+ if reverse
1015
+ ds = ds.order_append(Sequel[:nsp][:nspname], Sequel[:cl2][:relname])
1016
+ end
1017
+
1018
+ _add_validated_enforced_constraint_columns(ds)
1019
+ end
1020
+
1021
+ def _add_validated_enforced_constraint_columns(ds)
1022
+ validated_cond = if server_version >= 90100
1023
+ Sequel[:convalidated]
1024
+ # :nocov:
1025
+ else
1026
+ Sequel.cast(true, TrueClass)
1027
+ # :nocov:
1028
+ end
1029
+ ds = ds.select_append(validated_cond.as(:validated))
1030
+
1031
+ enforced_cond = if server_version >= 180000
1032
+ Sequel[:conenforced]
1033
+ # :nocov:
1034
+ else
1035
+ Sequel.cast(true, TrueClass)
1036
+ # :nocov:
1037
+ end
1038
+ ds = ds.select_append(enforced_cond.as(:enforced))
1039
+
1040
+ ds
1041
+ end
1042
+
1043
+ # Dataset used to retrieve index information
1044
+ def _indexes_ds
1045
+ @_indexes_ds ||= begin
1046
+ if server_version >= 90500
1047
+ order = [Sequel[:indc][:relname], Sequel.function(:array_position, Sequel[:ind][:indkey], Sequel[:att][:attnum])]
1048
+ # :nocov:
1049
+ else
1050
+ range = 0...32
1051
+ order = [Sequel[:indc][:relname], SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(Sequel[:ind][:indkey], [x]), x]}, 32, Sequel[:att][:attnum])]
1052
+ # :nocov:
1053
+ end
1054
+
1055
+ attnums = SQL::Function.new(:ANY, Sequel[:ind][:indkey])
1056
+
1057
+ ds = metadata_dataset.
1058
+ from{pg_class.as(:tab)}.
1059
+ join(Sequel[:pg_index].as(:ind), :indrelid=>:oid).
1060
+ join(Sequel[:pg_class].as(:indc), :oid=>:indexrelid).
1061
+ join(Sequel[:pg_attribute].as(:att), :attrelid=>Sequel[:tab][:oid], :attnum=>attnums).
1062
+ left_join(Sequel[:pg_constraint].as(:con), :conname=>Sequel[:indc][:relname]).
1063
+ where{{
1064
+ indc[:relkind]=>%w'i I',
1065
+ ind[:indisprimary]=>false,
1066
+ :indexprs=>nil}}.
1067
+ order(*order).
1068
+ select{[indc[:relname].as(:name), ind[:indisunique].as(:unique), att[:attname].as(:column), con[:condeferrable].as(:deferrable)]}
1069
+
1070
+ # :nocov:
1071
+ ds = ds.where(:indisready=>true) if server_version >= 80300
1072
+ ds = ds.where(:indislive=>true) if server_version >= 90300
1073
+ # :nocov:
1074
+
1075
+ ds
1076
+ end
1077
+ end
1078
+
1079
+ # Dataset used to determine custom serial sequences for tables
1080
+ def _select_custom_sequence_ds
1081
+ @_select_custom_sequence_ds ||= metadata_dataset.
1082
+ from{pg_class.as(:t)}.
1083
+ join(:pg_namespace, {:oid => :relnamespace}, :table_alias=>:name).
1084
+ join(:pg_attribute, {:attrelid => Sequel[:t][:oid]}, :table_alias=>:attr).
1085
+ join(:pg_attrdef, {:adrelid => :attrelid, :adnum => :attnum}, :table_alias=>:def).
1086
+ join(:pg_constraint, {:conrelid => :adrelid, Sequel[:cons][:conkey].sql_subscript(1) => :adnum}, :table_alias=>:cons).
1087
+ where{{cons[:contype] => 'p', pg_get_expr(self.def[:adbin], attr[:attrelid]) => /nextval/i}}.
1088
+ select{
1089
+ expr = split_part(pg_get_expr(self.def[:adbin], attr[:attrelid]), "'", 2)
1090
+ [
1091
+ name[:nspname].as(:schema),
1092
+ Sequel.case({{expr => /./} => substr(expr, strpos(expr, '.')+1)}, expr).as(:sequence)
1093
+ ]
1094
+ }
1095
+ end
1096
+
1097
+ # Dataset used to determine normal serial sequences for tables
1098
+ def _select_serial_sequence_ds
1099
+ @_serial_sequence_ds ||= metadata_dataset.
1100
+ from{[
1101
+ pg_class.as(:seq),
1102
+ pg_attribute.as(:attr),
1103
+ pg_depend.as(:dep),
1104
+ pg_namespace.as(:name),
1105
+ pg_constraint.as(:cons),
1106
+ pg_class.as(:t)
1107
+ ]}.
1108
+ where{[
1109
+ [seq[:oid], dep[:objid]],
1110
+ [seq[:relnamespace], name[:oid]],
1111
+ [seq[:relkind], 'S'],
1112
+ [attr[:attrelid], dep[:refobjid]],
1113
+ [attr[:attnum], dep[:refobjsubid]],
1114
+ [attr[:attrelid], cons[:conrelid]],
1115
+ [attr[:attnum], cons[:conkey].sql_subscript(1)],
1116
+ [attr[:attrelid], t[:oid]],
1117
+ [cons[:contype], 'p']
1118
+ ]}.
1119
+ select{[
1120
+ name[:nspname].as(:schema),
1121
+ seq[:relname].as(:sequence)
1122
+ ]}
1123
+ end
1124
+
1125
+ # Dataset used to determine primary keys for tables
1126
+ def _select_pk_ds
1127
+ @_select_pk_ds ||= metadata_dataset.
1128
+ from(:pg_class, :pg_attribute, :pg_index, :pg_namespace).
1129
+ where{[
1130
+ [pg_class[:oid], pg_attribute[:attrelid]],
1131
+ [pg_class[:relnamespace], pg_namespace[:oid]],
1132
+ [pg_class[:oid], pg_index[:indrelid]],
1133
+ [pg_index[:indkey].sql_subscript(0), pg_attribute[:attnum]],
1134
+ [pg_index[:indisprimary], 't']
1135
+ ]}.
1136
+ select{pg_attribute[:attname].as(:pk)}
1137
+ end
1138
+
1139
+ # Dataset used to get schema for tables
1140
+ def _schema_ds
1141
+ @_schema_ds ||= begin
1142
+ ds = metadata_dataset.select{[
1143
+ pg_attribute[:attname].as(:name),
1144
+ SQL::Cast.new(pg_attribute[:atttypid], :integer).as(:oid),
1145
+ SQL::Cast.new(basetype[:oid], :integer).as(:base_oid),
1146
+ SQL::Function.new(:col_description, pg_class[:oid], pg_attribute[:attnum]).as(:comment),
1147
+ SQL::Function.new(:format_type, basetype[:oid], pg_type[:typtypmod]).as(:db_base_type),
1148
+ SQL::Function.new(:format_type, pg_type[:oid], pg_attribute[:atttypmod]).as(:db_type),
1149
+ SQL::Function.new(:pg_get_expr, pg_attrdef[:adbin], pg_class[:oid]).as(:default),
1150
+ SQL::BooleanExpression.new(:NOT, pg_attribute[:attnotnull]).as(:allow_null),
1151
+ SQL::Function.new(:COALESCE, SQL::BooleanExpression.from_value_pairs(pg_attribute[:attnum] => SQL::Function.new(:ANY, pg_index[:indkey])), false).as(:primary_key),
1152
+ Sequel[:pg_type][:typtype],
1153
+ (~Sequel[Sequel[:elementtype][:oid]=>nil]).as(:is_array),
1154
+ ]}.
1155
+ from(:pg_class).
1156
+ join(:pg_attribute, :attrelid=>:oid).
1157
+ join(:pg_type, :oid=>:atttypid).
1158
+ left_outer_join(Sequel[:pg_type].as(:basetype), :oid=>:typbasetype).
1159
+ left_outer_join(Sequel[:pg_type].as(:elementtype), :typarray=>Sequel[:pg_type][:oid]).
1160
+ left_outer_join(:pg_attrdef, :adrelid=>Sequel[:pg_class][:oid], :adnum=>Sequel[:pg_attribute][:attnum]).
1161
+ left_outer_join(:pg_index, :indrelid=>Sequel[:pg_class][:oid], :indisprimary=>true).
1162
+ where{{pg_attribute[:attisdropped]=>false}}.
1163
+ where{pg_attribute[:attnum] > 0}.
1164
+ order{pg_attribute[:attnum]}
1165
+
1166
+ # :nocov:
1167
+ if server_version > 100000
1168
+ # :nocov:
1169
+ ds = ds.select_append{pg_attribute[:attidentity]}
1170
+
1171
+ # :nocov:
1172
+ if server_version > 120000
1173
+ # :nocov:
1174
+ ds = ds.select_append{Sequel.~(pg_attribute[:attgenerated]=>'').as(:generated)}
1175
+ end
1176
+ end
1177
+
1178
+ ds
1179
+ end
1180
+ end
1181
+
1182
+ # Internals of defer_constraints/immediate_constraints
1183
+ def _set_constraints(type, opts)
1184
+ execute_ddl(_set_constraints_sql(type, opts), opts)
1185
+ end
1186
+
1187
+ # SQL to use for SET CONSTRAINTS
1188
+ def _set_constraints_sql(type, opts)
1189
+ sql = String.new
1190
+ sql << "SET CONSTRAINTS "
1191
+ if constraints = opts[:constraints]
1192
+ dataset.send(:source_list_append, sql, Array(constraints))
1193
+ else
1194
+ sql << "ALL"
1195
+ end
1196
+ sql << type
1197
+ end
1198
+
1199
+ # Consider lock or statement timeout errors as evidence that the table exists
1200
+ # but is locked.
1201
+ def _table_exists?(ds)
1202
+ super
1203
+ rescue DatabaseError => e
1204
+ raise e unless /canceling statement due to (?:statement|lock) timeout/ =~ e.message
1205
+ end
1206
+
1207
+ def alter_table_add_column_sql(table, op)
1208
+ "ADD COLUMN#{' IF NOT EXISTS' if op[:if_not_exists]} #{column_definition_sql(op)}"
1209
+ end
1210
+
1211
+ def alter_table_alter_constraint_sql(table, op)
1212
+ sql = String.new
1213
+ sql << "ALTER CONSTRAINT #{quote_identifier(op[:name])}"
1214
+
1215
+ constraint_deferrable_sql_append(sql, op[:deferrable])
1216
+
1217
+ case op[:enforced]
1218
+ when nil
1219
+ when false
1220
+ sql << " NOT ENFORCED"
1221
+ else
1222
+ sql << " ENFORCED"
1223
+ end
1224
+
1225
+ case op[:inherit]
1226
+ when nil
1227
+ when false
1228
+ sql << " NO INHERIT"
1229
+ else
1230
+ sql << " INHERIT"
1231
+ end
1232
+
1233
+ sql
1234
+ end
1235
+
1236
+ def alter_table_generator_class
1237
+ Postgres::AlterTableGenerator
1238
+ end
1239
+
1240
+ def alter_table_rename_constraint_sql(table, op)
1241
+ "RENAME CONSTRAINT #{quote_identifier(op[:name])} TO #{quote_identifier(op[:new_name])}"
1242
+ end
1243
+
1244
+ def alter_table_set_column_type_sql(table, op)
1245
+ s = super
1246
+ if using = op[:using]
1247
+ using = Sequel::LiteralString.new(using) if using.is_a?(String)
1248
+ s += ' USING '
1249
+ s << literal(using)
1250
+ end
1251
+ s
1252
+ end
1253
+
1254
+ def alter_table_drop_column_sql(table, op)
1255
+ "DROP COLUMN #{'IF EXISTS ' if op[:if_exists]}#{quote_identifier(op[:name])}#{' CASCADE' if op[:cascade]}"
1256
+ end
1257
+
1258
+ def alter_table_validate_constraint_sql(table, op)
1259
+ "VALIDATE CONSTRAINT #{quote_identifier(op[:name])}"
1260
+ end
1261
+
1262
+ # If the :synchronous option is given and non-nil, set synchronous_commit
1263
+ # appropriately. Valid values for the :synchronous option are true,
1264
+ # :on, false, :off, :local, and :remote_write.
1265
+ def begin_new_transaction(conn, opts)
1266
+ super
1267
+ if opts.has_key?(:synchronous)
1268
+ case sync = opts[:synchronous]
1269
+ when true
1270
+ sync = :on
1271
+ when false
1272
+ sync = :off
1273
+ when nil
1274
+ return
1275
+ end
1276
+
1277
+ log_connection_execute(conn, "SET LOCAL synchronous_commit = #{sync}")
1278
+ end
1279
+ end
1280
+
1281
+ # Set the READ ONLY transaction setting per savepoint, as PostgreSQL supports that.
1282
+ def begin_savepoint(conn, opts)
1283
+ super
1284
+
1285
+ unless (read_only = opts[:read_only]).nil?
1286
+ log_connection_execute(conn, "SET TRANSACTION READ #{read_only ? 'ONLY' : 'WRITE'}")
1287
+ end
1288
+ end
1289
+
1290
+ def column_definition_append_include_sql(sql, constraint)
1291
+ if include_cols = constraint[:include]
1292
+ sql << " INCLUDE " << literal(Array(include_cols))
1293
+ end
1294
+ end
1295
+
1296
+ def column_definition_append_primary_key_sql(sql, constraint)
1297
+ super
1298
+ column_definition_append_include_sql(sql, constraint)
1299
+ end
1300
+
1301
+ def column_definition_append_unique_sql(sql, constraint)
1302
+ super
1303
+ column_definition_append_include_sql(sql, constraint)
1304
+ end
1305
+
1306
+ # Literalize non-String collate options. This is because unquoted collatations
1307
+ # are folded to lowercase, and PostgreSQL used mixed case or capitalized collations.
1308
+ def column_definition_collate_sql(sql, column)
1309
+ if collate = column[:collate]
1310
+ collate = literal(collate) unless collate.is_a?(String)
1311
+ sql << " COLLATE #{collate}"
1312
+ end
1313
+ end
1314
+
1315
+ # Support identity columns, but only use the identity SQL syntax if no
1316
+ # default value is given.
1317
+ def column_definition_default_sql(sql, column)
1318
+ super
1319
+ if !column[:serial] && !['smallserial', 'serial', 'bigserial'].include?(column[:type].to_s) && !column[:default]
1320
+ if (identity = column[:identity])
1321
+ sql << " GENERATED "
1322
+ sql << (identity == :always ? "ALWAYS" : "BY DEFAULT")
1323
+ sql << " AS IDENTITY"
1324
+ elsif (generated = column[:generated_always_as])
1325
+ sql << " GENERATED ALWAYS AS (#{literal(generated)}) #{column[:virtual] ? 'VIRTUAL' : 'STORED'}"
1326
+ end
1327
+ end
1328
+ end
1329
+
1330
+ # Handle PostgreSQL specific default format.
1331
+ def column_schema_normalize_default(default, type)
1332
+ if m = /\A(?:B?('.*')::[^']+|\((-?\d+(?:\.\d+)?)\))\z/.match(default)
1333
+ default = m[1] || m[2]
1334
+ end
1335
+ super(default, type)
1336
+ end
1337
+
1338
+ # If the :prepare option is given and we aren't in a savepoint,
1339
+ # prepare the transaction for a two-phase commit.
1340
+ def commit_transaction(conn, opts=OPTS)
1341
+ if (s = opts[:prepare]) && savepoint_level(conn) <= 1
1342
+ log_connection_execute(conn, "PREPARE TRANSACTION #{literal(s)}")
1343
+ else
1344
+ super
1345
+ end
1346
+ end
1347
+
1348
+ # PostgreSQL can't combine rename_column operations, and it can combine
1349
+ # validate_constraint and alter_constraint operations.
1350
+ def combinable_alter_table_op?(op)
1351
+ (super || op[:op] == :validate_constraint || op[:op] == :alter_constraint) && op[:op] != :rename_column
1352
+ end
1353
+
1354
+ VALID_CLIENT_MIN_MESSAGES = %w'DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 LOG NOTICE WARNING ERROR FATAL PANIC'.freeze.each(&:freeze)
1355
+ # The SQL queries to execute when starting a new connection.
1356
+ def connection_configuration_sqls(opts=@opts)
1357
+ sqls = []
1358
+
1359
+ sqls << "SET standard_conforming_strings = ON" if typecast_value_boolean(opts.fetch(:force_standard_strings, true))
1360
+
1361
+ cmm = opts.fetch(:client_min_messages, :warning)
1362
+ if cmm && !cmm.to_s.empty?
1363
+ cmm = cmm.to_s.upcase.strip
1364
+ unless VALID_CLIENT_MIN_MESSAGES.include?(cmm)
1365
+ raise Error, "Unsupported client_min_messages setting: #{cmm}"
1366
+ end
1367
+ sqls << "SET client_min_messages = '#{cmm.to_s.upcase}'"
1368
+ end
1369
+
1370
+ if search_path = opts[:search_path]
1371
+ case search_path
1372
+ when String
1373
+ search_path = search_path.split(",").map(&:strip)
1374
+ when Array
1375
+ # nil
1376
+ else
1377
+ raise Error, "unrecognized value for :search_path option: #{search_path.inspect}"
1378
+ end
1379
+ sqls << "SET search_path = #{search_path.map{|s| "\"#{s.gsub('"', '""')}\""}.join(',')}"
1380
+ end
1381
+
1382
+ sqls
1383
+ end
1384
+
1385
+ # Handle PostgreSQL-specific constraint features.
1386
+ def constraint_definition_sql(constraint)
1387
+ case type = constraint[:type]
1388
+ when :exclude
1389
+ elements = constraint[:elements].map{|c, op| "#{literal(c)} WITH #{op}"}.join(', ')
1390
+ sql = String.new
1391
+ sql << "CONSTRAINT #{quote_identifier(constraint[:name])} " if constraint[:name]
1392
+ sql << "EXCLUDE USING #{constraint[:using]||'gist'} (#{elements})"
1393
+ column_definition_append_include_sql(sql, constraint)
1394
+ sql << " WHERE #{filter_expr(constraint[:where])}" if constraint[:where]
1395
+ constraint_deferrable_sql_append(sql, constraint[:deferrable])
1396
+ sql
1397
+ when :primary_key, :unique
1398
+ sql = String.new
1399
+ sql << "CONSTRAINT #{quote_identifier(constraint[:name])} " if constraint[:name]
1400
+
1401
+ if type == :primary_key
1402
+ sql << primary_key_constraint_sql_fragment(constraint)
1403
+ else
1404
+ sql << unique_constraint_sql_fragment(constraint)
1405
+ end
1406
+
1407
+ if using_index = constraint[:using_index]
1408
+ sql << " USING INDEX " << quote_identifier(using_index)
1409
+ else
1410
+ cols = literal(constraint[:columns])
1411
+ cols.insert(-2, " WITHOUT OVERLAPS") if constraint[:without_overlaps]
1412
+ sql << " " << cols
1413
+
1414
+ if include_cols = constraint[:include]
1415
+ sql << " INCLUDE " << literal(Array(include_cols))
1416
+ end
1417
+ end
1418
+
1419
+ constraint_deferrable_sql_append(sql, constraint[:deferrable])
1420
+ sql
1421
+ else # when :foreign_key, :check
1422
+ sql = super
1423
+ if constraint[:no_inherit]
1424
+ sql << " NO INHERIT"
1425
+ end
1426
+ if constraint[:not_enforced]
1427
+ sql << " NOT ENFORCED"
1428
+ end
1429
+ if constraint[:not_valid]
1430
+ sql << " NOT VALID"
1431
+ end
1432
+ sql
1433
+ end
1434
+ end
1435
+
1436
+ def column_definition_add_references_sql(sql, column)
1437
+ super
1438
+ if column[:not_enforced]
1439
+ sql << " NOT ENFORCED"
1440
+ end
1441
+ end
1442
+
1443
+ def column_definition_null_sql(sql, column)
1444
+ constraint = column[:not_null]
1445
+ constraint = nil unless constraint.is_a?(Hash)
1446
+ if constraint && (name = constraint[:name])
1447
+ sql << " CONSTRAINT #{quote_identifier(name)}"
1448
+ end
1449
+ super
1450
+ if constraint && constraint[:no_inherit]
1451
+ sql << " NO INHERIT"
1452
+ end
1453
+ end
1454
+
1455
+ # Handle :period option
1456
+ def column_references_table_constraint_sql(constraint)
1457
+ sql = String.new
1458
+ sql << "FOREIGN KEY "
1459
+ cols = constraint[:columns]
1460
+ cols = column_references_add_period(cols) if constraint[:period]
1461
+ sql << literal(cols) << column_references_sql(constraint)
1462
+ end
1463
+
1464
+ def column_references_append_key_sql(sql, column)
1465
+ cols = Array(column[:key])
1466
+ cols = column_references_add_period(cols) if column[:period]
1467
+ sql << "(#{cols.map{|x| quote_identifier(x)}.join(', ')})"
1468
+ end
1469
+
1470
+ def column_references_add_period(cols)
1471
+ cols= cols.dup
1472
+ cols[-1] = Sequel.lit("PERIOD #{quote_identifier(cols[-1])}")
1473
+ cols
1474
+ end
1475
+
1476
+ def database_specific_error_class_from_sqlstate(sqlstate)
1477
+ if sqlstate == '23P01'
1478
+ ExclusionConstraintViolation
1479
+ elsif sqlstate == '40P01'
1480
+ SerializationFailure
1481
+ elsif sqlstate == '55P03'
1482
+ DatabaseLockTimeout
1483
+ else
1484
+ super
1485
+ end
1486
+ end
1487
+
1488
+ DATABASE_ERROR_REGEXPS = [
1489
+ # Add this check first, since otherwise it's possible for users to control
1490
+ # which exception class is generated.
1491
+ [/invalid input syntax/, DatabaseError],
1492
+ [/duplicate key value violates unique constraint/, UniqueConstraintViolation],
1493
+ [/violates foreign key constraint/, ForeignKeyConstraintViolation],
1494
+ [/violates check constraint/, CheckConstraintViolation],
1495
+ [/violates not-null constraint/, NotNullConstraintViolation],
1496
+ [/conflicting key value violates exclusion constraint/, ExclusionConstraintViolation],
1497
+ [/could not serialize access/, SerializationFailure],
1498
+ [/could not obtain lock on row in relation/, DatabaseLockTimeout],
1499
+ ].freeze
1500
+ def database_error_regexps
1501
+ DATABASE_ERROR_REGEXPS
1502
+ end
1503
+
1504
+ # SQL for doing fast table insert from stdin.
1505
+ def copy_into_sql(table, opts)
1506
+ sql = String.new
1507
+ sql << "COPY #{literal(table)}"
1508
+ if cols = opts[:columns]
1509
+ sql << literal(Array(cols))
1510
+ end
1511
+ sql << " FROM STDIN"
1512
+ if opts[:options] || opts[:format]
1513
+ sql << " ("
1514
+ sql << "FORMAT #{opts[:format]}" if opts[:format]
1515
+ sql << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
1516
+ sql << ')'
1517
+ end
1518
+ sql
1519
+ end
1520
+
1521
+ # SQL for doing fast table output to stdout.
1522
+ def copy_table_sql(table, opts)
1523
+ if table.is_a?(String)
1524
+ table
1525
+ else
1526
+ if opts[:options] || opts[:format]
1527
+ options = String.new
1528
+ options << " ("
1529
+ options << "FORMAT #{opts[:format]}" if opts[:format]
1530
+ options << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
1531
+ options << ')'
1532
+ end
1533
+ table = if table.is_a?(::Sequel::Dataset)
1534
+ "(#{table.sql})"
1535
+ else
1536
+ literal(table)
1537
+ end
1538
+ "COPY #{table} TO STDOUT#{options}"
1539
+ end
1540
+ end
1541
+
1542
+ # SQL statement to create database function.
1543
+ def create_function_sql(name, definition, opts=OPTS)
1544
+ args = opts[:args]
1545
+ in_out = %w'OUT INOUT'
1546
+ if (!opts[:args].is_a?(Array) || !opts[:args].any?{|a| Array(a).length == 3 && in_out.include?(a[2].to_s)})
1547
+ returns = opts[:returns] || 'void'
1548
+ end
1549
+ language = opts[:language] || 'SQL'
1550
+ <<-END
1551
+ CREATE#{' OR REPLACE' if opts[:replace]} FUNCTION #{name}#{sql_function_args(args)}
1552
+ #{"RETURNS #{returns}" if returns}
1553
+ LANGUAGE #{language}
1554
+ #{opts[:behavior].to_s.upcase if opts[:behavior]}
1555
+ #{'STRICT' if opts[:strict]}
1556
+ #{'SECURITY DEFINER' if opts[:security_definer]}
1557
+ #{"PARALLEL #{opts[:parallel].to_s.upcase}" if opts[:parallel]}
1558
+ #{"COST #{opts[:cost]}" if opts[:cost]}
1559
+ #{"ROWS #{opts[:rows]}" if opts[:rows]}
1560
+ #{opts[:set].map{|k,v| " SET #{k} = #{v}"}.join("\n") if opts[:set]}
1561
+ AS #{literal(definition.to_s)}#{", #{literal(opts[:link_symbol].to_s)}" if opts[:link_symbol]}
1562
+ END
1563
+ end
1564
+
1565
+ # SQL for creating a procedural language.
1566
+ def create_language_sql(name, opts=OPTS)
1567
+ "CREATE#{' OR REPLACE' if opts[:replace] && server_version >= 90000}#{' TRUSTED' if opts[:trusted]} LANGUAGE #{name}#{" HANDLER #{opts[:handler]}" if opts[:handler]}#{" VALIDATOR #{opts[:validator]}" if opts[:validator]}"
1568
+ end
1569
+
1570
+ # Create a partition of another table, used when the create_table with
1571
+ # the :partition_of option is given.
1572
+ def create_partition_of_table_from_generator(name, generator, options)
1573
+ execute_ddl(create_partition_of_table_sql(name, generator, options))
1574
+ end
1575
+
1576
+ # SQL for creating a partition of another table.
1577
+ def create_partition_of_table_sql(name, generator, options)
1578
+ sql = create_table_prefix_sql(name, options).dup
1579
+
1580
+ sql << " PARTITION OF #{quote_schema_table(options[:partition_of])}"
1581
+
1582
+ case generator.partition_type
1583
+ when :range
1584
+ from, to = generator.range
1585
+ sql << " FOR VALUES FROM #{literal(from)} TO #{literal(to)}"
1586
+ when :list
1587
+ sql << " FOR VALUES IN #{literal(generator.list)}"
1588
+ when :hash
1589
+ mod, remainder = generator.hash_values
1590
+ sql << " FOR VALUES WITH (MODULUS #{literal(mod)}, REMAINDER #{literal(remainder)})"
1591
+ else # when :default
1592
+ sql << " DEFAULT"
1593
+ end
1594
+
1595
+ sql << create_table_suffix_sql(name, options)
1596
+
1597
+ sql
1598
+ end
1599
+
1600
+ # SQL for creating a schema.
1601
+ def create_schema_sql(name, opts=OPTS)
1602
+ "CREATE SCHEMA #{'IF NOT EXISTS ' if opts[:if_not_exists]}#{quote_identifier(name)}#{" AUTHORIZATION #{literal(opts[:owner])}" if opts[:owner]}"
1603
+ end
1604
+
1605
+ # DDL statement for creating a table with the given name, columns, and options
1606
+ def create_table_prefix_sql(name, options)
1607
+ prefix_sql = if options[:temp]
1608
+ raise(Error, "can't provide both :temp and :unlogged to create_table") if options[:unlogged]
1609
+ raise(Error, "can't provide both :temp and :foreign to create_table") if options[:foreign]
1610
+ temporary_table_sql
1611
+ elsif options[:foreign]
1612
+ raise(Error, "can't provide both :foreign and :unlogged to create_table") if options[:unlogged]
1613
+ 'FOREIGN '
1614
+ elsif options.fetch(:unlogged){typecast_value_boolean(@opts[:unlogged_tables_default])}
1615
+ 'UNLOGGED '
1616
+ end
1617
+
1618
+ "CREATE #{prefix_sql}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)}"
1619
+ end
1620
+
1621
+ # SQL for creating a table with PostgreSQL specific options
1622
+ def create_table_sql(name, generator, options)
1623
+ "#{super}#{create_table_suffix_sql(name, options)}"
1624
+ end
1625
+
1626
+ # Handle various PostgreSQl specific table extensions such as inheritance,
1627
+ # partitioning, tablespaces, and foreign tables.
1628
+ def create_table_suffix_sql(name, options)
1629
+ sql = String.new
1630
+
1631
+ if inherits = options[:inherits]
1632
+ sql << " INHERITS (#{Array(inherits).map{|t| quote_schema_table(t)}.join(', ')})"
1633
+ end
1634
+
1635
+ if partition_by = options[:partition_by]
1636
+ sql << " PARTITION BY #{options[:partition_type]||'RANGE'} #{literal(Array(partition_by))}"
1637
+ end
1638
+
1639
+ if on_commit = options[:on_commit]
1640
+ raise(Error, "can't provide :on_commit without :temp to create_table") unless options[:temp]
1641
+ raise(Error, "unsupported on_commit option: #{on_commit.inspect}") unless ON_COMMIT.has_key?(on_commit)
1642
+ sql << " ON COMMIT #{ON_COMMIT[on_commit]}"
1643
+ end
1644
+
1645
+ if tablespace = options[:tablespace]
1646
+ sql << " TABLESPACE #{quote_identifier(tablespace)}"
1647
+ end
1648
+
1649
+ if server = options[:foreign]
1650
+ sql << " SERVER #{quote_identifier(server)}"
1651
+ if foreign_opts = options[:options]
1652
+ sql << " OPTIONS (#{foreign_opts.map{|k, v| "#{k} #{literal(v.to_s)}"}.join(', ')})"
1653
+ end
1654
+ end
1655
+
1656
+ sql
1657
+ end
1658
+
1659
+ def create_table_as_sql(name, sql, options)
1660
+ result = create_table_prefix_sql name, options
1661
+ if on_commit = options[:on_commit]
1662
+ result += " ON COMMIT #{ON_COMMIT[on_commit]}"
1663
+ end
1664
+ result += " AS #{sql}"
1665
+ end
1666
+
1667
+ def create_table_generator_class
1668
+ Postgres::CreateTableGenerator
1669
+ end
1670
+
1671
+ # SQL for creating a database trigger.
1672
+ def create_trigger_sql(table, name, function, opts=OPTS)
1673
+ events = opts[:events] ? Array(opts[:events]) : [:insert, :update, :delete]
1674
+ whence = opts[:after] ? 'AFTER' : 'BEFORE'
1675
+ if filter = opts[:when]
1676
+ raise Error, "Trigger conditions are not supported for this database" unless supports_trigger_conditions?
1677
+ filter = " WHEN #{filter_expr(filter)}"
1678
+ end
1679
+ "CREATE #{'OR REPLACE ' if opts[:replace]}TRIGGER #{name} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} ON #{quote_schema_table(table)}#{' FOR EACH ROW' if opts[:each_row]}#{filter} EXECUTE PROCEDURE #{function}(#{Array(opts[:args]).map{|a| literal(a)}.join(', ')})"
1680
+ end
1681
+
1682
+ # DDL fragment for initial part of CREATE VIEW statement
1683
+ def create_view_prefix_sql(name, options)
1684
+ sql = create_view_sql_append_columns("CREATE #{'OR REPLACE 'if options[:replace]}#{'TEMPORARY 'if options[:temp]}#{'RECURSIVE ' if options[:recursive]}#{'MATERIALIZED ' if options[:materialized]}VIEW #{quote_schema_table(name)}", options[:columns] || options[:recursive])
1685
+
1686
+ if options[:security_invoker]
1687
+ sql += " WITH (security_invoker)"
1688
+ end
1689
+
1690
+ if tablespace = options[:tablespace]
1691
+ sql += " TABLESPACE #{quote_identifier(tablespace)}"
1692
+ end
1693
+
1694
+ sql
1695
+ end
1696
+
1697
+ # SQL for dropping a function from the database.
1698
+ def drop_function_sql(name, opts=OPTS)
1699
+ "DROP FUNCTION#{' IF EXISTS' if opts[:if_exists]} #{name}#{sql_function_args(opts[:args])}#{' CASCADE' if opts[:cascade]}"
1700
+ end
1701
+
1702
+ # Support :if_exists, :cascade, and :concurrently options.
1703
+ def drop_index_sql(table, op)
1704
+ sch, _ = schema_and_table(table)
1705
+ "DROP INDEX#{' CONCURRENTLY' if op[:concurrently]}#{' IF EXISTS' if op[:if_exists]} #{"#{quote_identifier(sch)}." if sch}#{quote_identifier(op[:name] || default_index_name(table, op[:columns]))}#{' CASCADE' if op[:cascade]}"
1706
+ end
1707
+
1708
+ # SQL for dropping a procedural language from the database.
1709
+ def drop_language_sql(name, opts=OPTS)
1710
+ "DROP LANGUAGE#{' IF EXISTS' if opts[:if_exists]} #{name}#{' CASCADE' if opts[:cascade]}"
1711
+ end
1712
+
1713
+ # SQL for dropping a schema from the database.
1714
+ def drop_schema_sql(name, opts=OPTS)
1715
+ "DROP SCHEMA#{' IF EXISTS' if opts[:if_exists]} #{quote_identifier(name)}#{' CASCADE' if opts[:cascade]}"
1716
+ end
1717
+
1718
+ # SQL for dropping a trigger from the database.
1719
+ def drop_trigger_sql(table, name, opts=OPTS)
1720
+ "DROP TRIGGER#{' IF EXISTS' if opts[:if_exists]} #{name} ON #{quote_schema_table(table)}#{' CASCADE' if opts[:cascade]}"
1721
+ end
1722
+
1723
+ # Support :foreign tables
1724
+ def drop_table_sql(name, options)
1725
+ "DROP#{' FOREIGN' if options[:foreign]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_schema_table(name)}#{' CASCADE' if options[:cascade]}"
1726
+ end
1727
+
1728
+ # SQL for dropping a view from the database.
1729
+ def drop_view_sql(name, opts=OPTS)
1730
+ "DROP #{'MATERIALIZED ' if opts[:materialized]}VIEW#{' IF EXISTS' if opts[:if_exists]} #{quote_schema_table(name)}#{' CASCADE' if opts[:cascade]}"
1731
+ end
1732
+
1733
+ # If opts includes a :schema option, use it, otherwise restrict the filter to only the
1734
+ # currently visible schemas.
1735
+ def filter_schema(ds, opts)
1736
+ expr = if schema = opts[:schema]
1737
+ if schema.is_a?(SQL::Identifier)
1738
+ schema.value.to_s
1739
+ else
1740
+ schema.to_s
1741
+ end
1742
+ else
1743
+ Sequel.function(:any, Sequel.function(:current_schemas, false))
1744
+ end
1745
+ ds.where{{pg_namespace[:nspname]=>expr}}
1746
+ end
1747
+
1748
+ def index_definition_sql(table_name, index)
1749
+ cols = index[:columns]
1750
+ index_name = index[:name] || default_index_name(table_name, cols)
1751
+
1752
+ expr = if o = index[:opclass]
1753
+ "(#{Array(cols).map{|c| "#{literal(c)} #{o}"}.join(', ')})"
1754
+ else
1755
+ literal(Array(cols))
1756
+ end
1757
+
1758
+ if_not_exists = " IF NOT EXISTS" if index[:if_not_exists]
1759
+ unique = "UNIQUE " if index[:unique]
1760
+ index_type = index[:type]
1761
+ filter = index[:where] || index[:filter]
1762
+ filter = " WHERE #{filter_expr(filter)}" if filter
1763
+ nulls_distinct = " NULLS#{' NOT' if index[:nulls_distinct] == false} DISTINCT" unless index[:nulls_distinct].nil?
1764
+
1765
+ case index_type
1766
+ when :full_text
1767
+ expr = "(to_tsvector(#{literal(index[:language] || 'simple')}::regconfig, #{literal(dataset.send(:full_text_string_join, cols))}))"
1768
+ index_type = index[:index_type] || :gin
1769
+ when :spatial
1770
+ index_type = :gist
1771
+ end
1772
+
1773
+ "CREATE #{unique}INDEX#{' CONCURRENTLY' if index[:concurrently]}#{if_not_exists} #{quote_identifier(index_name)} ON#{' ONLY' if index[:only]} #{quote_schema_table(table_name)} #{"USING #{index_type} " if index_type}#{expr}#{" INCLUDE #{literal(Array(index[:include]))}" if index[:include]}#{nulls_distinct}#{" TABLESPACE #{quote_identifier(index[:tablespace])}" if index[:tablespace]}#{filter}"
1774
+ end
1775
+
1776
+ # Setup datastructures shared by all postgres adapters.
1777
+ def initialize_postgres_adapter
1778
+ @primary_keys = {}
1779
+ @primary_key_sequences = {}
1780
+ @supported_types = {}
1781
+ procs = @conversion_procs = CONVERSION_PROCS.dup
1782
+ procs[1184] = procs[1114] = method(:to_application_timestamp)
1783
+ end
1784
+
1785
+ # Backbone of the tables and views support.
1786
+ def pg_class_relname(type, opts)
1787
+ ds = metadata_dataset.from(:pg_class).where(:relkind=>type).select(:relname).server(opts[:server]).join(:pg_namespace, :oid=>:relnamespace)
1788
+ ds = filter_schema(ds, opts)
1789
+ m = output_identifier_meth
1790
+ if defined?(yield)
1791
+ yield(ds)
1792
+ elsif opts[:qualify]
1793
+ ds.select_append{pg_namespace[:nspname]}.map{|r| Sequel.qualify(m.call(r[:nspname]).to_s, m.call(r[:relname]).to_s)}
1794
+ else
1795
+ ds.map{|r| m.call(r[:relname])}
1796
+ end
1797
+ end
1798
+
1799
+ # Return an expression the oid for the table expr. Used by the metadata parsing
1800
+ # code to disambiguate unqualified tables.
1801
+ def regclass_oid(expr, opts=OPTS)
1802
+ if expr.is_a?(String) && !expr.is_a?(LiteralString)
1803
+ expr = Sequel.identifier(expr)
1804
+ end
1805
+
1806
+ sch, table = schema_and_table(expr)
1807
+ sch ||= opts[:schema]
1808
+ if sch
1809
+ expr = Sequel.qualify(sch, table)
1810
+ end
1811
+
1812
+ expr = if ds = opts[:dataset]
1813
+ ds.literal(expr)
1814
+ else
1815
+ literal(expr)
1816
+ end
1817
+
1818
+ Sequel.cast(expr.to_s,:regclass).cast(:oid)
1819
+ end
1820
+
1821
+ # Remove the cached entries for primary keys and sequences when a table is changed.
1822
+ def remove_cached_schema(table)
1823
+ tab = quote_schema_table(table)
1824
+ Sequel.synchronize do
1825
+ @primary_keys.delete(tab)
1826
+ @primary_key_sequences.delete(tab)
1827
+ end
1828
+ super
1829
+ end
1830
+
1831
+ # Clear all cached schema information
1832
+ def remove_all_cached_schemas
1833
+ @primary_keys.clear
1834
+ @primary_key_sequences.clear
1835
+ @schemas.clear
1836
+ end
1837
+
1838
+ # SQL for renaming a schema.
1839
+ def rename_schema_sql(name, new_name)
1840
+ "ALTER SCHEMA #{quote_identifier(name)} RENAME TO #{quote_identifier(new_name)}"
1841
+ end
1842
+
1843
+ # SQL DDL statement for renaming a table. PostgreSQL doesn't allow you to change a table's schema in
1844
+ # a rename table operation, so specifying a new schema in new_name will not have an effect.
1845
+ def rename_table_sql(name, new_name)
1846
+ "ALTER TABLE #{quote_schema_table(name)} RENAME TO #{quote_identifier(schema_and_table(new_name).last)}"
1847
+ end
1848
+
1849
+ # Handle interval and citext types.
1850
+ def schema_column_type(db_type)
1851
+ case db_type
1852
+ when /\Ainterval\z/i
1853
+ :interval
1854
+ when /\Acitext\z/i
1855
+ :string
1856
+ else
1857
+ super
1858
+ end
1859
+ end
1860
+
1861
+ # The schema :type entry to use for array types.
1862
+ def schema_array_type(db_type)
1863
+ :array
1864
+ end
1865
+
1866
+ # The schema :type entry to use for row/composite types.
1867
+ def schema_composite_type(db_type)
1868
+ :composite
1869
+ end
1870
+
1871
+ # The schema :type entry to use for enum types.
1872
+ def schema_enum_type(db_type)
1873
+ :enum
1874
+ end
1875
+
1876
+ # The schema :type entry to use for range types.
1877
+ def schema_range_type(db_type)
1878
+ :range
1879
+ end
1880
+
1881
+ # The schema :type entry to use for multirange types.
1882
+ def schema_multirange_type(db_type)
1883
+ :multirange
1884
+ end
1885
+
1886
+ MIN_DATE = Date.new(-4713, 11, 24)
1887
+ MAX_DATE = Date.new(5874897, 12, 31)
1888
+ MIN_TIMESTAMP = Time.utc(-4713, 11, 24).freeze
1889
+ MAX_TIMESTAMP = (Time.utc(294277) - Rational(1, 1000000)).freeze
1890
+ TYPTYPE_METHOD_MAP = {
1891
+ 'c' => :schema_composite_type,
1892
+ 'e' => :schema_enum_type,
1893
+ 'r' => :schema_range_type,
1894
+ 'm' => :schema_multirange_type,
1895
+ }
1896
+ TYPTYPE_METHOD_MAP.default = :schema_column_type
1897
+ TYPTYPE_METHOD_MAP.freeze
1898
+ # The dataset used for parsing table schemas, using the pg_* system catalogs.
1899
+ def schema_parse_table(table_name, opts)
1900
+ m = output_identifier_meth(opts[:dataset])
1901
+
1902
+ _schema_ds.where_all(Sequel[:pg_class][:oid]=>regclass_oid(table_name, opts)).map do |row|
1903
+ row[:default] = nil if blank_object?(row[:default])
1904
+ if row[:base_oid]
1905
+ row[:domain_oid] = row[:oid]
1906
+ row[:oid] = row.delete(:base_oid)
1907
+ row[:db_domain_type] = row[:db_type]
1908
+ row[:db_type] = row.delete(:db_base_type)
1909
+ else
1910
+ row.delete(:base_oid)
1911
+ row.delete(:db_base_type)
1912
+ end
1913
+
1914
+ db_type = row[:db_type]
1915
+ row[:type] = if row.delete(:is_array)
1916
+ schema_array_type(db_type)
1917
+ else
1918
+ send(TYPTYPE_METHOD_MAP[row.delete(:typtype)], db_type)
1919
+ end
1920
+ identity = row.delete(:attidentity)
1921
+ if row[:primary_key]
1922
+ row[:auto_increment] = !!(row[:default] =~ /\A(?:nextval)/i) || identity == 'a' || identity == 'd'
1923
+ end
1924
+
1925
+ # :nocov:
1926
+ if server_version >= 90600
1927
+ # :nocov:
1928
+ case row[:oid]
1929
+ when 1082
1930
+ row[:min_value] = MIN_DATE
1931
+ row[:max_value] = MAX_DATE
1932
+ when 1184, 1114
1933
+ if Sequel.datetime_class == Time
1934
+ row[:min_value] = MIN_TIMESTAMP
1935
+ row[:max_value] = MAX_TIMESTAMP
1936
+ end
1937
+ end
1938
+ end
1939
+
1940
+ [m.call(row.delete(:name)), row]
1941
+ end
1942
+ end
1943
+
1944
+ # Set the transaction isolation level on the given connection
1945
+ def set_transaction_isolation(conn, opts)
1946
+ level = opts.fetch(:isolation, transaction_isolation_level)
1947
+ read_only = opts[:read_only]
1948
+ deferrable = opts[:deferrable]
1949
+ if level || !read_only.nil? || !deferrable.nil?
1950
+ sql = String.new
1951
+ sql << "SET TRANSACTION"
1952
+ sql << " ISOLATION LEVEL #{Sequel::Database::TRANSACTION_ISOLATION_LEVELS[level]}" if level
1953
+ sql << " READ #{read_only ? 'ONLY' : 'WRITE'}" unless read_only.nil?
1954
+ sql << " #{'NOT ' unless deferrable}DEFERRABLE" unless deferrable.nil?
1955
+ log_connection_execute(conn, sql)
1956
+ end
1957
+ end
1958
+
1959
+ # Turns an array of argument specifiers into an SQL fragment used for function arguments. See create_function_sql.
1960
+ def sql_function_args(args)
1961
+ "(#{Array(args).map{|a| Array(a).reverse.join(' ')}.join(', ')})"
1962
+ end
1963
+
1964
+ # PostgreSQL can combine multiple alter table ops into a single query.
1965
+ def supports_combining_alter_table_ops?
1966
+ true
1967
+ end
1968
+
1969
+ # PostgreSQL supports CREATE OR REPLACE VIEW.
1970
+ def supports_create_or_replace_view?
1971
+ true
1972
+ end
1973
+
1974
+ # Handle bigserial type if :serial option is present
1975
+ def type_literal_generic_bignum_symbol(column)
1976
+ column[:serial] ? :bigserial : super
1977
+ end
1978
+
1979
+ # PostgreSQL uses the bytea data type for blobs
1980
+ def type_literal_generic_file(column)
1981
+ :bytea
1982
+ end
1983
+
1984
+ # Handle serial type if :serial option is present
1985
+ def type_literal_generic_integer(column)
1986
+ column[:serial] ? :serial : super
1987
+ end
1988
+
1989
+ # PostgreSQL prefers the text datatype. If a fixed size is requested,
1990
+ # the char type is used. If the text type is specifically
1991
+ # disallowed or there is a size specified, use the varchar type.
1992
+ # Otherwise use the text type.
1993
+ def type_literal_generic_string(column)
1994
+ if column[:text]
1995
+ :text
1996
+ elsif column[:fixed]
1997
+ "char(#{column[:size]||default_string_column_size})"
1998
+ elsif column[:text] == false || column[:size]
1999
+ "varchar(#{column[:size]||default_string_column_size})"
2000
+ else
2001
+ :text
2002
+ end
2003
+ end
2004
+
2005
+ # Support :nulls_not_distinct option.
2006
+ def unique_constraint_sql_fragment(constraint)
2007
+ if constraint[:nulls_not_distinct]
2008
+ 'UNIQUE NULLS NOT DISTINCT'
2009
+ else
2010
+ 'UNIQUE'
2011
+ end
2012
+ end
2013
+
2014
+ # PostgreSQL 9.4+ supports views with check option.
2015
+ def view_with_check_option_support
2016
+ # :nocov:
2017
+ :local if server_version >= 90400
2018
+ # :nocov:
2019
+ end
2020
+ end
2021
+
2022
+ module DatasetMethods
2023
+ include UnmodifiedIdentifiers::DatasetMethods
2024
+
2025
+ NULL = LiteralString.new('NULL').freeze
2026
+ LOCK_MODES = ['ACCESS SHARE', 'ROW SHARE', 'ROW EXCLUSIVE', 'SHARE UPDATE EXCLUSIVE', 'SHARE', 'SHARE ROW EXCLUSIVE', 'EXCLUSIVE', 'ACCESS EXCLUSIVE'].each(&:freeze).freeze
2027
+
2028
+ Dataset.def_sql_method(self, :delete, [['if server_version >= 90100', %w'with delete from using where returning'], ['else', %w'delete from using where returning']])
2029
+ Dataset.def_sql_method(self, :insert, [['if server_version >= 90500', %w'with insert into columns override values conflict returning'], ['elsif server_version >= 90100', %w'with insert into columns values returning'], ['else', %w'insert into columns values returning']])
2030
+ Dataset.def_sql_method(self, :select, [['if opts[:values]', %w'values compounds order limit'], ['elsif server_version >= 80400', %w'with select distinct columns from join where group having window compounds order limit lock'], ['else', %w'select distinct columns from join where group having compounds order limit lock']])
2031
+ Dataset.def_sql_method(self, :update, [['if server_version >= 90100', %w'with update table set from where returning'], ['else', %w'update table set from where returning']])
2032
+
2033
+ # Return the results of an EXPLAIN ANALYZE query as a string
2034
+ def analyze
2035
+ explain(:analyze=>true)
2036
+ end
2037
+
2038
+ # Handle converting the ruby xor operator (^) into the
2039
+ # PostgreSQL xor operator (#), and use the ILIKE and NOT ILIKE
2040
+ # operators.
2041
+ def complex_expression_sql_append(sql, op, args)
2042
+ case op
2043
+ when :^
2044
+ j = ' # '
2045
+ c = false
2046
+ args.each do |a|
2047
+ sql << j if c
2048
+ literal_append(sql, a)
2049
+ c ||= true
2050
+ end
2051
+ when :ILIKE, :'NOT ILIKE'
2052
+ sql << '('
2053
+ literal_append(sql, args[0])
2054
+ sql << ' ' << op.to_s << ' '
2055
+ literal_append(sql, args[1])
2056
+ sql << ')'
2057
+ else
2058
+ super
2059
+ end
2060
+ end
2061
+
2062
+ # Disables automatic use of INSERT ... RETURNING. You can still use
2063
+ # returning manually to force the use of RETURNING when inserting.
2064
+ #
2065
+ # This is designed for cases where INSERT RETURNING cannot be used,
2066
+ # such as when you are using partitioning with trigger functions
2067
+ # or conditional rules, or when you are using a PostgreSQL version
2068
+ # less than 8.2, or a PostgreSQL derivative that does not support
2069
+ # returning.
2070
+ #
2071
+ # Note that when this method is used, insert will not return the
2072
+ # primary key of the inserted row, you will have to get the primary
2073
+ # key of the inserted row before inserting via nextval, or after
2074
+ # inserting via currval or lastval (making sure to use the same
2075
+ # database connection for currval or lastval).
2076
+ def disable_insert_returning
2077
+ clone(:disable_insert_returning=>true)
2078
+ end
2079
+
2080
+ # Always return false when using VALUES
2081
+ def empty?
2082
+ return false if @opts[:values]
2083
+ super
2084
+ end
2085
+
2086
+ # Return the results of an EXPLAIN query. Boolean options:
2087
+ #
2088
+ # :analyze :: Use the ANALYZE option.
2089
+ # :buffers :: Use the BUFFERS option.
2090
+ # :costs :: Use the COSTS option.
2091
+ # :generic_plan :: Use the GENERIC_PLAN option.
2092
+ # :memory :: Use the MEMORY option.
2093
+ # :settings :: Use the SETTINGS option.
2094
+ # :summary :: Use the SUMMARY option.
2095
+ # :timing :: Use the TIMING option.
2096
+ # :verbose :: Use the VERBOSE option.
2097
+ # :wal :: Use the WAL option.
2098
+ #
2099
+ # Non boolean options:
2100
+ #
2101
+ # :format :: Use the FORMAT option to change the format of the
2102
+ # returned value. Values can be :text, :xml, :json,
2103
+ # or :yaml.
2104
+ # :serialize :: Use the SERIALIZE option to get timing on
2105
+ # serialization. Values can be :none, :text, or
2106
+ # :binary.
2107
+ #
2108
+ # See the PostgreSQL EXPLAIN documentation for an explanation of
2109
+ # what each option does.
2110
+ #
2111
+ # In most cases, the return value is a single string. However,
2112
+ # using the <tt>format: :json</tt> option can result in the return
2113
+ # value being an array containing a hash.
2114
+ def explain(opts=OPTS)
2115
+ rows = clone(:append_sql=>explain_sql_string_origin(opts)).map(:'QUERY PLAN')
2116
+
2117
+ if rows.length == 1
2118
+ rows[0]
2119
+ elsif rows.all?{|row| String === row}
2120
+ rows.join("\r\n")
2121
+ # :nocov:
2122
+ else
2123
+ # This branch is unreachable in tests, but it seems better to just return
2124
+ # all rows than throw in error if this case actually happens.
2125
+ rows
2126
+ # :nocov:
2127
+ end
2128
+ end
2129
+
2130
+ # Return a cloned dataset which will use FOR KEY SHARE to lock returned rows.
2131
+ # Supported on PostgreSQL 9.3+.
2132
+ def for_key_share
2133
+ cached_lock_style_dataset(:_for_key_share_ds, :key_share)
2134
+ end
2135
+
2136
+ # Return a cloned dataset which will use FOR NO KEY UPDATE to lock returned rows.
2137
+ # This is generally a better choice than using for_update on PostgreSQL, unless
2138
+ # you will be deleting the row or modifying a key column. Supported on PostgreSQL 9.3+.
2139
+ def for_no_key_update
2140
+ cached_lock_style_dataset(:_for_no_key_update_ds, :no_key_update)
2141
+ end
2142
+
2143
+ # Return a cloned dataset which will use FOR SHARE to lock returned rows.
2144
+ def for_share
2145
+ cached_lock_style_dataset(:_for_share_ds, :share)
2146
+ end
2147
+
2148
+ # Run a full text search on PostgreSQL. By default, searching for the inclusion
2149
+ # of any of the terms in any of the cols.
2150
+ #
2151
+ # Options:
2152
+ # :headline :: Append a expression to the selected columns aliased to headline that
2153
+ # contains an extract of the matched text.
2154
+ # :language :: The language to use for the search (default: 'simple')
2155
+ # :plain :: Whether a plain search should be used (default: false). In this case,
2156
+ # terms should be a single string, and it will do a search where cols
2157
+ # contains all of the words in terms. This ignores search operators in terms.
2158
+ # :phrase :: Similar to :plain, but also adding an ILIKE filter to ensure that
2159
+ # returned rows also include the exact phrase used.
2160
+ # :rank :: Set to true to order by the rank, so that closer matches are returned first.
2161
+ # :to_tsquery :: Can be set to :plain, :phrase, or :websearch to specify the function to use to
2162
+ # convert the terms to a ts_query.
2163
+ # :tsquery :: Specifies the terms argument is already a valid SQL expression returning a
2164
+ # tsquery, and can be used directly in the query.
2165
+ # :tsvector :: Specifies the cols argument is already a valid SQL expression returning a
2166
+ # tsvector, and can be used directly in the query.
2167
+ def full_text_search(cols, terms, opts = OPTS)
2168
+ lang = Sequel.cast(opts[:language] || 'simple', :regconfig)
2169
+
2170
+ unless opts[:tsvector]
2171
+ phrase_cols = full_text_string_join(cols)
2172
+ cols = Sequel.function(:to_tsvector, lang, phrase_cols)
2173
+ end
2174
+
2175
+ unless opts[:tsquery]
2176
+ phrase_terms = terms.is_a?(Array) || terms.is_a?(Set) ? Sequel.array_or_set_join(terms, ' | ') : terms
2177
+
2178
+ query_func = case to_tsquery = opts[:to_tsquery]
2179
+ when :phrase, :plain
2180
+ :"#{to_tsquery}to_tsquery"
2181
+ when :websearch
2182
+ :"websearch_to_tsquery"
2183
+ else
2184
+ (opts[:phrase] || opts[:plain]) ? :plainto_tsquery : :to_tsquery
2185
+ end
2186
+
2187
+ terms = Sequel.function(query_func, lang, phrase_terms)
2188
+ end
2189
+
2190
+ ds = where(Sequel.lit(["", " @@ ", ""], cols, terms))
2191
+
2192
+ if opts[:phrase]
2193
+ raise Error, "can't use :phrase with either :tsvector or :tsquery arguments to full_text_search together" if opts[:tsvector] || opts[:tsquery]
2194
+ ds = ds.grep(phrase_cols, "%#{escape_like(phrase_terms)}%", :case_insensitive=>true)
2195
+ end
2196
+
2197
+ if opts[:rank]
2198
+ ds = ds.reverse{ts_rank_cd(cols, terms)}
2199
+ end
2200
+
2201
+ if opts[:headline]
2202
+ ds = ds.select_append{ts_headline(lang, phrase_cols, terms).as(:headline)}
2203
+ end
2204
+
2205
+ ds
2206
+ end
2207
+
2208
+ # Insert given values into the database.
2209
+ def insert(*values)
2210
+ if @opts[:returning]
2211
+ # Already know which columns to return, let the standard code handle it
2212
+ super
2213
+ elsif @opts[:sql] || @opts[:disable_insert_returning]
2214
+ # Raw SQL used or RETURNING disabled, just use the default behavior
2215
+ # and return nil since sequence is not known.
2216
+ super
2217
+ nil
2218
+ else
2219
+ # Force the use of RETURNING with the primary key value,
2220
+ # unless it has been disabled.
2221
+ returning(insert_pk).insert(*values){|r| return r.values.first}
2222
+ end
2223
+ end
2224
+
2225
+ # Handle uniqueness violations when inserting, by updating the conflicting row, using
2226
+ # ON CONFLICT. With no options, uses ON CONFLICT DO NOTHING. Options:
2227
+ # :conflict_where :: The index filter, when using a partial index to determine uniqueness.
2228
+ # :constraint :: An explicit constraint name, has precendence over :target.
2229
+ # :target :: The column name or expression to handle uniqueness violations on.
2230
+ # :update :: A hash of columns and values to set. Uses ON CONFLICT DO UPDATE.
2231
+ # :update_where :: A WHERE condition to use for the update.
2232
+ #
2233
+ # Examples:
2234
+ #
2235
+ # DB[:table].insert_conflict.insert(a: 1, b: 2)
2236
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2237
+ # # ON CONFLICT DO NOTHING
2238
+ #
2239
+ # DB[:table].insert_conflict(constraint: :table_a_uidx).insert(a: 1, b: 2)
2240
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2241
+ # # ON CONFLICT ON CONSTRAINT table_a_uidx DO NOTHING
2242
+ #
2243
+ # DB[:table].insert_conflict(target: :a).insert(a: 1, b: 2)
2244
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2245
+ # # ON CONFLICT (a) DO NOTHING
2246
+ #
2247
+ # DB[:table].insert_conflict(target: :a, conflict_where: {c: true}).insert(a: 1, b: 2)
2248
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2249
+ # # ON CONFLICT (a) WHERE (c IS TRUE) DO NOTHING
2250
+ #
2251
+ # DB[:table].insert_conflict(target: :a, update: {b: Sequel[:excluded][:b]}).insert(a: 1, b: 2)
2252
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2253
+ # # ON CONFLICT (a) DO UPDATE SET b = excluded.b
2254
+ #
2255
+ # DB[:table].insert_conflict(constraint: :table_a_uidx,
2256
+ # update: {b: Sequel[:excluded][:b]}, update_where: {Sequel[:table][:status_id] => 1}).insert(a: 1, b: 2)
2257
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2258
+ # # ON CONFLICT ON CONSTRAINT table_a_uidx
2259
+ # # DO UPDATE SET b = excluded.b WHERE (table.status_id = 1)
2260
+ def insert_conflict(opts=OPTS)
2261
+ clone(:insert_conflict => opts)
2262
+ end
2263
+
2264
+ # Ignore uniqueness/exclusion violations when inserting, using ON CONFLICT DO NOTHING.
2265
+ # Exists mostly for compatibility to MySQL's insert_ignore. Example:
2266
+ #
2267
+ # DB[:table].insert_ignore.insert(a: 1, b: 2)
2268
+ # # INSERT INTO TABLE (a, b) VALUES (1, 2)
2269
+ # # ON CONFLICT DO NOTHING
2270
+ def insert_ignore
2271
+ insert_conflict
2272
+ end
2273
+
2274
+ # Insert a record, returning the record inserted, using RETURNING. Always returns nil without
2275
+ # running an INSERT statement if disable_insert_returning is used. If the query runs
2276
+ # but returns no values, returns false.
2277
+ def insert_select(*values)
2278
+ return unless supports_insert_select?
2279
+ # Handle case where query does not return a row
2280
+ server?(:default).with_sql_first(insert_select_sql(*values)) || false
2281
+ end
2282
+
2283
+ # The SQL to use for an insert_select, adds a RETURNING clause to the insert
2284
+ # unless the RETURNING clause is already present.
2285
+ def insert_select_sql(*values)
2286
+ ds = opts[:returning] ? self : returning
2287
+ ds.insert_sql(*values)
2288
+ end
2289
+
2290
+ # Support SQL::AliasedExpression as expr to setup a USING join with a table alias for the
2291
+ # USING columns.
2292
+ def join_table(type, table, expr=nil, options=OPTS, &block)
2293
+ if expr.is_a?(SQL::AliasedExpression) && expr.expression.is_a?(Array) && !expr.expression.empty? && expr.expression.all?
2294
+ options = options.merge(:join_using=>true)
2295
+ end
2296
+ super
2297
+ end
2298
+
2299
+ # Locks all tables in the dataset's FROM clause (but not in JOINs) with
2300
+ # the specified mode (e.g. 'EXCLUSIVE'). If a block is given, starts
2301
+ # a new transaction, locks the table, and yields. If a block is not given,
2302
+ # just locks the tables. Note that PostgreSQL will probably raise an error
2303
+ # if you lock the table outside of an existing transaction. Returns nil.
2304
+ def lock(mode, opts=OPTS)
2305
+ if defined?(yield) # perform locking inside a transaction and yield to block
2306
+ @db.transaction(opts){lock(mode, opts); yield}
2307
+ else
2308
+ sql = 'LOCK TABLE '.dup
2309
+ source_list_append(sql, @opts[:from])
2310
+ mode = mode.to_s.upcase.strip
2311
+ unless LOCK_MODES.include?(mode)
2312
+ raise Error, "Unsupported lock mode: #{mode}"
2313
+ end
2314
+ sql << " IN #{mode} MODE"
2315
+ @db.execute(sql, opts)
2316
+ end
2317
+ nil
2318
+ end
2319
+
2320
+ # Support MERGE RETURNING on PostgreSQL 17+.
2321
+ def merge(&block)
2322
+ sql = merge_sql
2323
+ if uses_returning?(:merge)
2324
+ returning_fetch_rows(sql, &block)
2325
+ else
2326
+ execute_ddl(sql)
2327
+ end
2328
+ end
2329
+
2330
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN DELETE clause added to the
2331
+ # MERGE statement. If a block is passed, treat it as a virtual row and
2332
+ # use it as additional conditions for the match.
2333
+ #
2334
+ # merge_delete_not_matched_by_source
2335
+ # # WHEN NOT MATCHED BY SOURCE THEN DELETE
2336
+ #
2337
+ # merge_delete_not_matched_by_source{a > 30}
2338
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN DELETE
2339
+ def merge_delete_when_not_matched_by_source(&block)
2340
+ _merge_when(:type=>:delete_not_matched_by_source, &block)
2341
+ end
2342
+
2343
+ # Return a dataset with a WHEN MATCHED THEN DO NOTHING clause added to the
2344
+ # MERGE statement. If a block is passed, treat it as a virtual row and
2345
+ # use it as additional conditions for the match.
2346
+ #
2347
+ # merge_do_nothing_when_matched
2348
+ # # WHEN MATCHED THEN DO NOTHING
2349
+ #
2350
+ # merge_do_nothing_when_matched{a > 30}
2351
+ # # WHEN MATCHED AND (a > 30) THEN DO NOTHING
2352
+ def merge_do_nothing_when_matched(&block)
2353
+ _merge_when(:type=>:matched, &block)
2354
+ end
2355
+
2356
+ # Return a dataset with a WHEN NOT MATCHED THEN DO NOTHING clause added to the
2357
+ # MERGE statement. If a block is passed, treat it as a virtual row and
2358
+ # use it as additional conditions for the match.
2359
+ #
2360
+ # merge_do_nothing_when_not_matched
2361
+ # # WHEN NOT MATCHED THEN DO NOTHING
2362
+ #
2363
+ # merge_do_nothing_when_not_matched{a > 30}
2364
+ # # WHEN NOT MATCHED AND (a > 30) THEN DO NOTHING
2365
+ def merge_do_nothing_when_not_matched(&block)
2366
+ _merge_when(:type=>:not_matched, &block)
2367
+ end
2368
+
2369
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN DO NOTHING clause added to the
2370
+ # MERGE BY SOURCE statement. If a block is passed, treat it as a virtual row and
2371
+ # use it as additional conditions for the match.
2372
+ #
2373
+ # merge_do_nothing_when_not_matched_by_source
2374
+ # # WHEN NOT MATCHED BY SOURCE THEN DO NOTHING
2375
+ #
2376
+ # merge_do_nothing_when_not_matched_by_source{a > 30}
2377
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN DO NOTHING
2378
+ def merge_do_nothing_when_not_matched_by_source(&block)
2379
+ _merge_when(:type=>:not_matched_by_source, &block)
2380
+ end
2381
+
2382
+ # Support OVERRIDING USER|SYSTEM VALUE for MERGE INSERT.
2383
+ def merge_insert(*values, &block)
2384
+ h = {:type=>:insert, :values=>values}
2385
+ if @opts[:override]
2386
+ h[:override] = insert_override_sql(String.new)
2387
+ end
2388
+ _merge_when(h, &block)
2389
+ end
2390
+
2391
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN UPDATE clause added to the
2392
+ # MERGE statement. If a block is passed, treat it as a virtual row and
2393
+ # use it as additional conditions for the match.
2394
+ #
2395
+ # merge_update_not_matched_by_source(i1: Sequel[:i1]+:i2+10, a: Sequel[:a]+:b+20)
2396
+ # # WHEN NOT MATCHED BY SOURCE THEN UPDATE SET i1 = (i1 + i2 + 10), a = (a + b + 20)
2397
+ #
2398
+ # merge_update_not_matched_by_source(i1: :i2){a > 30}
2399
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN UPDATE SET i1 = i2
2400
+ def merge_update_when_not_matched_by_source(values, &block)
2401
+ _merge_when(:type=>:update_not_matched_by_source, :values=>values, &block)
2402
+ end
2403
+
2404
+ # Use OVERRIDING USER VALUE for INSERT statements, so that identity columns
2405
+ # always use the user supplied value, and an error is not raised for identity
2406
+ # columns that are GENERATED ALWAYS.
2407
+ def overriding_system_value
2408
+ clone(:override=>:system)
2409
+ end
2410
+
2411
+ # Use OVERRIDING USER VALUE for INSERT statements, so that identity columns
2412
+ # always use the sequence value instead of the user supplied value.
2413
+ def overriding_user_value
2414
+ clone(:override=>:user)
2415
+ end
2416
+
2417
+ def supports_cte?(type=:select)
2418
+ if type == :select
2419
+ server_version >= 80400
2420
+ else
2421
+ server_version >= 90100
2422
+ end
2423
+ end
2424
+
2425
+ # PostgreSQL supports using the WITH clause in subqueries if it
2426
+ # supports using WITH at all (i.e. on PostgreSQL 8.4+).
2427
+ def supports_cte_in_subqueries?
2428
+ supports_cte?
2429
+ end
2430
+
2431
+ # DISTINCT ON is a PostgreSQL extension
2432
+ def supports_distinct_on?
2433
+ true
2434
+ end
2435
+
2436
+ # PostgreSQL 9.5+ supports GROUP CUBE
2437
+ def supports_group_cube?
2438
+ server_version >= 90500
2439
+ end
2440
+
2441
+ # PostgreSQL 9.5+ supports GROUP ROLLUP
2442
+ def supports_group_rollup?
2443
+ server_version >= 90500
2444
+ end
2445
+
2446
+ # PostgreSQL 9.5+ supports GROUPING SETS
2447
+ def supports_grouping_sets?
2448
+ server_version >= 90500
2449
+ end
2450
+
2451
+ # True unless insert returning has been disabled for this dataset.
2452
+ def supports_insert_select?
2453
+ !@opts[:disable_insert_returning]
2454
+ end
2455
+
2456
+ # PostgreSQL 9.5+ supports the ON CONFLICT clause to INSERT.
2457
+ def supports_insert_conflict?
2458
+ server_version >= 90500
2459
+ end
2460
+
2461
+ # PostgreSQL 9.3+ supports lateral subqueries
2462
+ def supports_lateral_subqueries?
2463
+ server_version >= 90300
2464
+ end
2465
+
2466
+ # PostgreSQL supports modifying joined datasets
2467
+ def supports_modifying_joins?
2468
+ true
2469
+ end
2470
+
2471
+ # PostgreSQL 15+ supports MERGE.
2472
+ def supports_merge?
2473
+ server_version >= 150000
2474
+ end
2475
+
2476
+ # PostgreSQL supports NOWAIT.
2477
+ def supports_nowait?
2478
+ true
2479
+ end
2480
+
2481
+ # MERGE RETURNING is supported on PostgreSQL 17+. Other RETURNING is supported
2482
+ # on all supported PostgreSQL versions.
2483
+ def supports_returning?(type)
2484
+ if type == :merge
2485
+ server_version >= 170000
2486
+ else
2487
+ true
2488
+ end
2489
+ end
2490
+
2491
+ # PostgreSQL supports pattern matching via regular expressions
2492
+ def supports_regexp?
2493
+ true
2494
+ end
2495
+
2496
+ # PostgreSQL 9.5+ supports SKIP LOCKED.
2497
+ def supports_skip_locked?
2498
+ server_version >= 90500
2499
+ end
2500
+
2501
+ # :nocov:
2502
+
2503
+ # PostgreSQL supports timezones in literal timestamps
2504
+ def supports_timestamp_timezones?
2505
+ # SEQUEL6: Remove
2506
+ true
2507
+ end
2508
+ # :nocov:
2509
+
2510
+ # PostgreSQL 8.4+ supports WINDOW clause.
2511
+ def supports_window_clause?
2512
+ server_version >= 80400
2513
+ end
2514
+
2515
+ # PostgreSQL 8.4+ supports window functions
2516
+ def supports_window_functions?
2517
+ server_version >= 80400
2518
+ end
2519
+
2520
+ # Base support added in 8.4, offset supported added in 9.0,
2521
+ # GROUPS and EXCLUDE support added in 11.0.
2522
+ def supports_window_function_frame_option?(option)
2523
+ case option
2524
+ when :rows, :range
2525
+ true
2526
+ when :offset
2527
+ server_version >= 90000
2528
+ when :groups, :exclude
2529
+ server_version >= 110000
2530
+ else
2531
+ false
2532
+ end
2533
+ end
2534
+
2535
+ # Truncates the dataset. Returns nil.
2536
+ #
2537
+ # Options:
2538
+ # :cascade :: whether to use the CASCADE option, useful when truncating
2539
+ # tables with foreign keys.
2540
+ # :only :: truncate using ONLY, so child tables are unaffected
2541
+ # :restart :: use RESTART IDENTITY to restart any related sequences
2542
+ #
2543
+ # :only and :restart only work correctly on PostgreSQL 8.4+.
2544
+ #
2545
+ # Usage:
2546
+ # DB[:table].truncate
2547
+ # # TRUNCATE TABLE "table"
2548
+ #
2549
+ # DB[:table].truncate(cascade: true, only: true, restart: true)
2550
+ # # TRUNCATE TABLE ONLY "table" RESTART IDENTITY CASCADE
2551
+ def truncate(opts = OPTS)
2552
+ if opts.empty?
2553
+ super()
2554
+ else
2555
+ clone(:truncate_opts=>opts).truncate
2556
+ end
2557
+ end
2558
+
2559
+ # Use WITH TIES when limiting the result set to also include additional
2560
+ # rules that have the same results for the order column as the final row.
2561
+ # Requires PostgreSQL 13.
2562
+ def with_ties
2563
+ clone(:limit_with_ties=>true)
2564
+ end
2565
+
2566
+ protected
2567
+
2568
+ # If returned primary keys are requested, use RETURNING unless already set on the
2569
+ # dataset. If RETURNING is already set, use existing returning values. If RETURNING
2570
+ # is only set to return a single columns, return an array of just that column.
2571
+ # Otherwise, return an array of hashes.
2572
+ def _import(columns, values, opts=OPTS)
2573
+ if @opts[:returning]
2574
+ # no transaction: our multi_insert_sql_strategy should guarantee
2575
+ # that there's only ever a single statement.
2576
+ sql = multi_insert_sql(columns, values)[0]
2577
+ returning_fetch_rows(sql).map{|v| v.length == 1 ? v.values.first : v}
2578
+ elsif opts[:return] == :primary_key
2579
+ returning(insert_pk)._import(columns, values, opts)
2580
+ else
2581
+ super
2582
+ end
2583
+ end
2584
+
2585
+ def to_prepared_statement(type, *a)
2586
+ if type == :insert && !@opts.has_key?(:returning)
2587
+ returning(insert_pk).send(:to_prepared_statement, :insert_pk, *a)
2588
+ else
2589
+ super
2590
+ end
2591
+ end
2592
+
2593
+ private
2594
+
2595
+ # Append the INSERT sql used in a MERGE
2596
+ def _merge_insert_sql(sql, data)
2597
+ sql << " THEN INSERT"
2598
+ columns, values = _parse_insert_sql_args(data[:values])
2599
+ _insert_columns_sql(sql, columns)
2600
+ if override = data[:override]
2601
+ sql << override
2602
+ end
2603
+ _insert_values_sql(sql, values)
2604
+ end
2605
+
2606
+ def _merge_do_nothing_sql(sql, data)
2607
+ sql << " THEN DO NOTHING"
2608
+ end
2609
+
2610
+ # Support MERGE RETURNING on PostgreSQL 17+.
2611
+ def _merge_when_sql(sql)
2612
+ super
2613
+ insert_returning_sql(sql) if uses_returning?(:merge)
2614
+ end
2615
+
2616
+ # Format TRUNCATE statement with PostgreSQL specific options.
2617
+ def _truncate_sql(table)
2618
+ to = @opts[:truncate_opts] || OPTS
2619
+ "TRUNCATE TABLE#{' ONLY' if to[:only]} #{table}#{' RESTART IDENTITY' if to[:restart]}#{' CASCADE' if to[:cascade]}"
2620
+ end
2621
+
2622
+ # Use from_self for aggregate dataset using VALUES.
2623
+ def aggreate_dataset_use_from_self?
2624
+ super || @opts[:values]
2625
+ end
2626
+
2627
+ # Allow truncation of multiple source tables.
2628
+ def check_truncation_allowed!
2629
+ raise(InvalidOperation, "Grouped datasets cannot be truncated") if opts[:group]
2630
+ raise(InvalidOperation, "Joined datasets cannot be truncated") if opts[:join]
2631
+ end
2632
+
2633
+ # The strftime format to use when literalizing the time.
2634
+ def default_timestamp_format
2635
+ "'%Y-%m-%d %H:%M:%S.%6N%z'"
2636
+ end
2637
+
2638
+ # Only include the primary table in the main delete clause
2639
+ def delete_from_sql(sql)
2640
+ sql << ' FROM '
2641
+ source_list_append(sql, @opts[:from][0..0])
2642
+ end
2643
+
2644
+ # Use USING to specify additional tables in a delete query
2645
+ def delete_using_sql(sql)
2646
+ join_from_sql(:USING, sql)
2647
+ end
2648
+
2649
+ # Handle column aliases containing data types, useful for selecting from functions
2650
+ # that return the record data type.
2651
+ def derived_column_list_sql_append(sql, column_aliases)
2652
+ c = false
2653
+ comma = ', '
2654
+ column_aliases.each do |a|
2655
+ sql << comma if c
2656
+ if a.is_a?(Array)
2657
+ raise Error, "column aliases specified as arrays must have only 2 elements, the first is alias name and the second is data type" unless a.length == 2
2658
+ a, type = a
2659
+ identifier_append(sql, a)
2660
+ sql << " " << db.cast_type_literal(type).to_s
2661
+ else
2662
+ identifier_append(sql, a)
2663
+ end
2664
+ c ||= true
2665
+ end
2666
+ end
2667
+
2668
+ EXPLAIN_BOOLEAN_OPTIONS = {}
2669
+ %w[analyze verbose costs settings generic_plan buffers wal timing summary memory].each do |str|
2670
+ EXPLAIN_BOOLEAN_OPTIONS[str.to_sym] = str.upcase.freeze
2671
+ end
2672
+ EXPLAIN_BOOLEAN_OPTIONS.freeze
2673
+
2674
+ EXPLAIN_NONBOOLEAN_OPTIONS = {
2675
+ :serialize => {:none=>"SERIALIZE NONE", :text=>"SERIALIZE TEXT", :binary=>"SERIALIZE BINARY"}.freeze,
2676
+ :format => {:text=>"FORMAT TEXT", :xml=>"FORMAT XML", :json=>"FORMAT JSON", :yaml=>"FORMAT YAML"}.freeze
2677
+ }.freeze
2678
+
2679
+ # A mutable string used as the prefix when explaining a query.
2680
+ def explain_sql_string_origin(opts)
2681
+ origin = String.new
2682
+ origin << 'EXPLAIN '
2683
+
2684
+ # :nocov:
2685
+ if server_version < 90000
2686
+ if opts[:analyze]
2687
+ origin << 'ANALYZE '
2688
+ end
2689
+
2690
+ return origin
2691
+ end
2692
+ # :nocov:
2693
+
2694
+ comma = nil
2695
+ paren = "("
2696
+
2697
+ add_opt = lambda do |str, value|
2698
+ origin << paren if paren
2699
+ origin << comma if comma
2700
+ origin << str
2701
+ origin << " FALSE" unless value
2702
+ comma ||= ', '
2703
+ paren &&= nil
2704
+ end
2705
+
2706
+ EXPLAIN_BOOLEAN_OPTIONS.each do |key, str|
2707
+ unless (value = opts[key]).nil?
2708
+ add_opt.call(str, value)
2709
+ end
2710
+ end
2711
+
2712
+ EXPLAIN_NONBOOLEAN_OPTIONS.each do |key, e_opts|
2713
+ if value = opts[key]
2714
+ if str = e_opts[value]
2715
+ add_opt.call(str, true)
2716
+ else
2717
+ raise Sequel::Error, "unrecognized value for Dataset#explain #{key.inspect} option: #{value.inspect}"
2718
+ end
2719
+ end
2720
+ end
2721
+
2722
+ origin << ') ' unless paren
2723
+ origin
2724
+ end
2725
+
2726
+ # Add ON CONFLICT clause if it should be used
2727
+ def insert_conflict_sql(sql)
2728
+ if opts = @opts[:insert_conflict]
2729
+ sql << " ON CONFLICT"
2730
+
2731
+ if target = opts[:constraint]
2732
+ sql << " ON CONSTRAINT "
2733
+ identifier_append(sql, target)
2734
+ elsif target = opts[:target]
2735
+ sql << ' '
2736
+ identifier_append(sql, Array(target))
2737
+ if conflict_where = opts[:conflict_where]
2738
+ sql << " WHERE "
2739
+ literal_append(sql, conflict_where)
2740
+ end
2741
+ end
2742
+
2743
+ if values = opts[:update]
2744
+ sql << " DO UPDATE SET "
2745
+ update_sql_values_hash(sql, values)
2746
+ if update_where = opts[:update_where]
2747
+ sql << " WHERE "
2748
+ literal_append(sql, update_where)
2749
+ end
2750
+ else
2751
+ sql << " DO NOTHING"
2752
+ end
2753
+ end
2754
+ end
2755
+
2756
+ # Include aliases when inserting into a single table on PostgreSQL 9.5+.
2757
+ def insert_into_sql(sql)
2758
+ sql << " INTO "
2759
+ if (f = @opts[:from]) && f.length == 1
2760
+ identifier_append(sql, server_version >= 90500 ? f.first : unaliased_identifier(f.first))
2761
+ else
2762
+ source_list_append(sql, f)
2763
+ end
2764
+ end
2765
+
2766
+ # Return the primary key to use for RETURNING in an INSERT statement
2767
+ def insert_pk
2768
+ (f = opts[:from]) && !f.empty? && (t = f.first)
2769
+
2770
+ t = t.call(self) if t.is_a? Sequel::SQL::DelayedEvaluation
2771
+
2772
+ case t
2773
+ when Symbol, String, SQL::Identifier, SQL::QualifiedIdentifier
2774
+ if pk = db.primary_key(t)
2775
+ Sequel::SQL::Identifier.new(pk)
2776
+ end
2777
+ end
2778
+ end
2779
+
2780
+ # Support OVERRIDING SYSTEM|USER VALUE in insert statements
2781
+ def insert_override_sql(sql)
2782
+ case opts[:override]
2783
+ when :system
2784
+ sql << " OVERRIDING SYSTEM VALUE"
2785
+ when :user
2786
+ sql << " OVERRIDING USER VALUE"
2787
+ end
2788
+ end
2789
+
2790
+ # For multiple table support, PostgreSQL requires at least
2791
+ # two from tables, with joins allowed.
2792
+ def join_from_sql(type, sql)
2793
+ if(from = @opts[:from][1..-1]).empty?
2794
+ raise(Error, 'Need multiple FROM tables if updating/deleting a dataset with JOINs') if @opts[:join]
2795
+ else
2796
+ sql << ' ' << type.to_s << ' '
2797
+ source_list_append(sql, from)
2798
+ select_join_sql(sql)
2799
+ end
2800
+ end
2801
+
2802
+ # Support table aliases for USING columns
2803
+ def join_using_clause_using_sql_append(sql, using_columns)
2804
+ if using_columns.is_a?(SQL::AliasedExpression)
2805
+ super(sql, using_columns.expression)
2806
+ sql << ' AS '
2807
+ identifier_append(sql, using_columns.alias)
2808
+ else
2809
+ super
2810
+ end
2811
+ end
2812
+
2813
+ # Use a generic blob quoting method, hopefully overridden in one of the subadapter methods
2814
+ def literal_blob_append(sql, v)
2815
+ sql << "'" << v.gsub(/[\000-\037\047\134\177-\377]/n){|b| "\\#{("%o" % b[0..1].unpack("C")[0]).rjust(3, '0')}"} << "'"
2816
+ end
2817
+
2818
+ # PostgreSQL uses FALSE for false values
2819
+ def literal_false
2820
+ 'false'
2821
+ end
2822
+
2823
+ # PostgreSQL quotes NaN and Infinity.
2824
+ def literal_float(value)
2825
+ if value.finite?
2826
+ super
2827
+ elsif value.nan?
2828
+ "'NaN'"
2829
+ elsif value.infinite? == 1
2830
+ "'Infinity'"
2831
+ else
2832
+ "'-Infinity'"
2833
+ end
2834
+ end
2835
+
2836
+ # Handle Ruby integers outside PostgreSQL bigint range specially.
2837
+ def literal_integer(v)
2838
+ if v > 9223372036854775807 || v < -9223372036854775808
2839
+ literal_integer_outside_bigint_range(v)
2840
+ else
2841
+ v.to_s
2842
+ end
2843
+ end
2844
+
2845
+ # Raise IntegerOutsideBigintRange when attempting to literalize Ruby integer
2846
+ # outside PostgreSQL bigint range, so PostgreSQL doesn't treat
2847
+ # the value as numeric.
2848
+ def literal_integer_outside_bigint_range(v)
2849
+ raise IntegerOutsideBigintRange, "attempt to literalize Ruby integer outside PostgreSQL bigint range: #{v}"
2850
+ end
2851
+
2852
+ # Assume that SQL standard quoting is on, per Sequel's defaults
2853
+ def literal_string_append(sql, v)
2854
+ sql << "'" << v.gsub("'", "''") << "'"
2855
+ end
2856
+
2857
+ # PostgreSQL uses true for true values
2858
+ def literal_true
2859
+ 'true'
2860
+ end
2861
+
2862
+ # PostgreSQL supports multiple rows in INSERT.
2863
+ def multi_insert_sql_strategy
2864
+ :values
2865
+ end
2866
+
2867
+ # Dataset options that do not affect the generated SQL.
2868
+ def non_sql_option?(key)
2869
+ super || key == :cursor || key == :insert_conflict
2870
+ end
2871
+
2872
+ # PostgreSQL requires parentheses around compound datasets if they use
2873
+ # CTEs, and using them in other places doesn't hurt.
2874
+ def compound_dataset_sql_append(sql, ds)
2875
+ sql << '('
2876
+ super
2877
+ sql << ')'
2878
+ end
2879
+
2880
+ # Backslash is supported by default as the escape character on PostgreSQL,
2881
+ # and using ESCAPE can break LIKE ANY() usage.
2882
+ def requires_like_escape?
2883
+ false
2884
+ end
2885
+
2886
+ # Support FETCH FIRST WITH TIES on PostgreSQL 13+.
2887
+ def select_limit_sql(sql)
2888
+ l = @opts[:limit]
2889
+ o = @opts[:offset]
2890
+
2891
+ return unless l || o
2892
+
2893
+ if @opts[:limit_with_ties]
2894
+ if o
2895
+ sql << " OFFSET "
2896
+ literal_append(sql, o)
2897
+ end
2898
+
2899
+ if l
2900
+ sql << " FETCH FIRST "
2901
+ literal_append(sql, l)
2902
+ sql << " ROWS WITH TIES"
2903
+ end
2904
+ else
2905
+ if l
2906
+ sql << " LIMIT "
2907
+ literal_append(sql, l)
2908
+ end
2909
+
2910
+ if o
2911
+ sql << " OFFSET "
2912
+ literal_append(sql, o)
2913
+ end
2914
+ end
2915
+ end
2916
+
2917
+ # Support FOR SHARE locking when using the :share lock style.
2918
+ # Use SKIP LOCKED if skipping locked rows.
2919
+ def select_lock_sql(sql)
2920
+ lock = @opts[:lock]
2921
+ case lock
2922
+ when :share
2923
+ sql << ' FOR SHARE'
2924
+ when :no_key_update
2925
+ sql << ' FOR NO KEY UPDATE'
2926
+ when :key_share
2927
+ sql << ' FOR KEY SHARE'
2928
+ else
2929
+ super
2930
+ end
2931
+
2932
+ if lock
2933
+ if @opts[:skip_locked]
2934
+ sql << " SKIP LOCKED"
2935
+ elsif @opts[:nowait]
2936
+ sql << " NOWAIT"
2937
+ end
2938
+ end
2939
+ end
2940
+
2941
+ # Support VALUES clause instead of the SELECT clause to return rows.
2942
+ def select_values_sql(sql)
2943
+ sql << "VALUES "
2944
+ expression_list_append(sql, opts[:values])
2945
+ end
2946
+
2947
+ # Use WITH RECURSIVE instead of WITH if any of the CTEs is recursive
2948
+ def select_with_sql_base
2949
+ opts[:with].any?{|w| w[:recursive]} ? "WITH RECURSIVE " : super
2950
+ end
2951
+
2952
+ # Support PostgreSQL 14+ CTE SEARCH/CYCLE clauses
2953
+ def select_with_sql_cte(sql, cte)
2954
+ super
2955
+ select_with_sql_cte_search_cycle(sql, cte)
2956
+ end
2957
+
2958
+ def select_with_sql_cte_search_cycle(sql, cte)
2959
+ if search_opts = cte[:search]
2960
+ sql << if search_opts[:type] == :breadth
2961
+ " SEARCH BREADTH FIRST BY "
2962
+ else
2963
+ " SEARCH DEPTH FIRST BY "
2964
+ end
2965
+
2966
+ identifier_list_append(sql, Array(search_opts[:by]))
2967
+ sql << " SET "
2968
+ identifier_append(sql, search_opts[:set] || :ordercol)
2969
+ end
2970
+
2971
+ if cycle_opts = cte[:cycle]
2972
+ sql << " CYCLE "
2973
+ identifier_list_append(sql, Array(cycle_opts[:columns]))
2974
+ sql << " SET "
2975
+ identifier_append(sql, cycle_opts[:cycle_column] || :is_cycle)
2976
+ if cycle_opts.has_key?(:cycle_value)
2977
+ sql << " TO "
2978
+ literal_append(sql, cycle_opts[:cycle_value])
2979
+ sql << " DEFAULT "
2980
+ literal_append(sql, cycle_opts.fetch(:noncycle_value, false))
2981
+ end
2982
+ sql << " USING "
2983
+ identifier_append(sql, cycle_opts[:path_column] || :path)
2984
+ end
2985
+ end
2986
+
2987
+ # The version of the database server
2988
+ def server_version
2989
+ db.server_version(@opts[:server])
2990
+ end
2991
+
2992
+ # PostgreSQL 9.4+ supports the FILTER clause for aggregate functions.
2993
+ def supports_filtered_aggregates?
2994
+ server_version >= 90400
2995
+ end
2996
+
2997
+ # PostgreSQL supports quoted function names.
2998
+ def supports_quoted_function_names?
2999
+ true
3000
+ end
3001
+
3002
+ # Concatenate the expressions with a space in between
3003
+ def full_text_string_join(cols)
3004
+ cols = Array(cols).map{|x| SQL::Function.new(:COALESCE, x, '')}
3005
+ cols = cols.zip([' '] * cols.length).flatten
3006
+ cols.pop
3007
+ SQL::StringExpression.new(:'||', *cols)
3008
+ end
3009
+
3010
+ # Use FROM to specify additional tables in an update query
3011
+ def update_from_sql(sql)
3012
+ join_from_sql(:FROM, sql)
3013
+ end
3014
+
3015
+ # Only include the primary table in the main update clause
3016
+ def update_table_sql(sql)
3017
+ sql << ' '
3018
+ source_list_append(sql, @opts[:from][0..0])
3019
+ end
3020
+ end
3021
+ end
3022
+ end