sequel 3.21.0 → 3.36.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 (311) hide show
  1. data/CHANGELOG +855 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +23 -7
  4. data/Rakefile +42 -24
  5. data/bin/sequel +26 -8
  6. data/doc/active_record.rdoc +1 -0
  7. data/doc/advanced_associations.rdoc +171 -11
  8. data/doc/association_basics.rdoc +293 -43
  9. data/doc/dataset_basics.rdoc +5 -5
  10. data/doc/dataset_filtering.rdoc +8 -0
  11. data/doc/mass_assignment.rdoc +56 -0
  12. data/doc/migration.rdoc +85 -552
  13. data/doc/model_hooks.rdoc +78 -27
  14. data/doc/object_model.rdoc +541 -0
  15. data/doc/opening_databases.rdoc +97 -50
  16. data/doc/prepared_statements.rdoc +40 -14
  17. data/doc/querying.rdoc +28 -4
  18. data/doc/reflection.rdoc +30 -4
  19. data/doc/release_notes/3.22.0.txt +39 -0
  20. data/doc/release_notes/3.23.0.txt +172 -0
  21. data/doc/release_notes/3.24.0.txt +420 -0
  22. data/doc/release_notes/3.25.0.txt +88 -0
  23. data/doc/release_notes/3.26.0.txt +88 -0
  24. data/doc/release_notes/3.27.0.txt +82 -0
  25. data/doc/release_notes/3.28.0.txt +304 -0
  26. data/doc/release_notes/3.29.0.txt +459 -0
  27. data/doc/release_notes/3.30.0.txt +135 -0
  28. data/doc/release_notes/3.31.0.txt +146 -0
  29. data/doc/release_notes/3.32.0.txt +202 -0
  30. data/doc/release_notes/3.33.0.txt +157 -0
  31. data/doc/release_notes/3.34.0.txt +671 -0
  32. data/doc/release_notes/3.35.0.txt +144 -0
  33. data/doc/release_notes/3.36.0.txt +245 -0
  34. data/doc/schema_modification.rdoc +572 -0
  35. data/doc/sharding.rdoc +95 -3
  36. data/doc/testing.rdoc +129 -0
  37. data/doc/thread_safety.rdoc +17 -0
  38. data/doc/transactions.rdoc +137 -0
  39. data/doc/virtual_rows.rdoc +51 -2
  40. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  41. data/lib/sequel/adapters/ado.rb +40 -18
  42. data/lib/sequel/adapters/amalgalite.rb +17 -9
  43. data/lib/sequel/adapters/db2.rb +175 -86
  44. data/lib/sequel/adapters/dbi.rb +15 -15
  45. data/lib/sequel/adapters/do/mysql.rb +17 -11
  46. data/lib/sequel/adapters/do/postgres.rb +1 -57
  47. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  48. data/lib/sequel/adapters/do.rb +18 -36
  49. data/lib/sequel/adapters/firebird.rb +27 -208
  50. data/lib/sequel/adapters/ibmdb.rb +453 -0
  51. data/lib/sequel/adapters/informix.rb +6 -23
  52. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  53. data/lib/sequel/adapters/jdbc/db2.rb +47 -0
  54. data/lib/sequel/adapters/jdbc/derby.rb +287 -0
  55. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  56. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  57. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  58. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  59. data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  61. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  62. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
  64. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  65. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  66. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  67. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  68. data/lib/sequel/adapters/jdbc.rb +265 -94
  69. data/lib/sequel/adapters/mock.rb +361 -0
  70. data/lib/sequel/adapters/mysql.rb +118 -222
  71. data/lib/sequel/adapters/mysql2.rb +58 -57
  72. data/lib/sequel/adapters/odbc/mssql.rb +15 -7
  73. data/lib/sequel/adapters/odbc.rb +28 -9
  74. data/lib/sequel/adapters/openbase.rb +3 -5
  75. data/lib/sequel/adapters/oracle.rb +349 -53
  76. data/lib/sequel/adapters/postgres.rb +356 -107
  77. data/lib/sequel/adapters/shared/access.rb +32 -9
  78. data/lib/sequel/adapters/shared/db2.rb +342 -0
  79. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  80. data/lib/sequel/adapters/shared/informix.rb +53 -0
  81. data/lib/sequel/adapters/shared/mssql.rb +335 -118
  82. data/lib/sequel/adapters/shared/mysql.rb +340 -76
  83. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  84. data/lib/sequel/adapters/shared/oracle.rb +243 -45
  85. data/lib/sequel/adapters/shared/postgres.rb +524 -279
  86. data/lib/sequel/adapters/shared/progress.rb +5 -8
  87. data/lib/sequel/adapters/shared/sqlite.rb +265 -89
  88. data/lib/sequel/adapters/sqlite.rb +101 -39
  89. data/lib/sequel/adapters/swift/mysql.rb +9 -12
  90. data/lib/sequel/adapters/swift/postgres.rb +9 -74
  91. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  92. data/lib/sequel/adapters/swift.rb +8 -7
  93. data/lib/sequel/adapters/tinytds.rb +161 -21
  94. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  95. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  96. data/lib/sequel/ast_transformer.rb +194 -0
  97. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  98. data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
  99. data/lib/sequel/connection_pool/single.rb +5 -0
  100. data/lib/sequel/connection_pool/threaded.rb +38 -14
  101. data/lib/sequel/connection_pool.rb +10 -2
  102. data/lib/sequel/core.rb +118 -11
  103. data/lib/sequel/database/connecting.rb +38 -28
  104. data/lib/sequel/database/dataset.rb +4 -4
  105. data/lib/sequel/database/dataset_defaults.rb +63 -2
  106. data/lib/sequel/database/logging.rb +7 -2
  107. data/lib/sequel/database/misc.rb +150 -46
  108. data/lib/sequel/database/query.rb +215 -65
  109. data/lib/sequel/database/schema_generator.rb +64 -20
  110. data/lib/sequel/database/schema_methods.rb +212 -54
  111. data/lib/sequel/dataset/actions.rb +322 -85
  112. data/lib/sequel/dataset/features.rb +96 -8
  113. data/lib/sequel/dataset/graph.rb +38 -11
  114. data/lib/sequel/dataset/misc.rb +50 -23
  115. data/lib/sequel/dataset/mutation.rb +12 -7
  116. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  117. data/lib/sequel/dataset/query.rb +237 -44
  118. data/lib/sequel/dataset/sql.rb +698 -278
  119. data/lib/sequel/dataset.rb +8 -0
  120. data/lib/sequel/exceptions.rb +4 -0
  121. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  122. data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
  123. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  124. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
  125. data/lib/sequel/extensions/migration.rb +97 -11
  126. data/lib/sequel/extensions/named_timezones.rb +5 -0
  127. data/lib/sequel/extensions/null_dataset.rb +90 -0
  128. data/lib/sequel/extensions/pg_array.rb +460 -0
  129. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  130. data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
  131. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  132. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  133. data/lib/sequel/extensions/pg_inet.rb +89 -0
  134. data/lib/sequel/extensions/pg_json.rb +178 -0
  135. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  136. data/lib/sequel/extensions/pretty_table.rb +5 -71
  137. data/lib/sequel/extensions/query.rb +1 -1
  138. data/lib/sequel/extensions/query_literals.rb +79 -0
  139. data/lib/sequel/extensions/schema_caching.rb +76 -0
  140. data/lib/sequel/extensions/schema_dumper.rb +251 -37
  141. data/lib/sequel/extensions/select_remove.rb +35 -0
  142. data/lib/sequel/extensions/server_block.rb +139 -0
  143. data/lib/sequel/extensions/sql_expr.rb +4 -110
  144. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  145. data/lib/sequel/extensions/to_dot.rb +95 -83
  146. data/lib/sequel/model/associations.rb +1187 -393
  147. data/lib/sequel/model/base.rb +578 -170
  148. data/lib/sequel/model/errors.rb +1 -1
  149. data/lib/sequel/model/exceptions.rb +5 -1
  150. data/lib/sequel/model/inflections.rb +1 -1
  151. data/lib/sequel/model.rb +30 -11
  152. data/lib/sequel/no_core_ext.rb +2 -0
  153. data/lib/sequel/plugins/active_model.rb +13 -1
  154. data/lib/sequel/plugins/association_pks.rb +22 -4
  155. data/lib/sequel/plugins/caching.rb +25 -18
  156. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  157. data/lib/sequel/plugins/composition.rb +44 -12
  158. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  159. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  160. data/lib/sequel/plugins/dirty.rb +214 -0
  161. data/lib/sequel/plugins/eager_each.rb +59 -0
  162. data/lib/sequel/plugins/force_encoding.rb +6 -6
  163. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  164. data/lib/sequel/plugins/identity_map.rb +123 -8
  165. data/lib/sequel/plugins/instance_filters.rb +10 -0
  166. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  167. data/lib/sequel/plugins/json_serializer.rb +58 -6
  168. data/lib/sequel/plugins/list.rb +12 -2
  169. data/lib/sequel/plugins/many_through_many.rb +79 -28
  170. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  171. data/lib/sequel/plugins/nested_attributes.rb +139 -63
  172. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  173. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  174. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  175. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  176. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  177. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  178. data/lib/sequel/plugins/schema.rb +7 -2
  179. data/lib/sequel/plugins/serialization.rb +98 -49
  180. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  181. data/lib/sequel/plugins/sharding.rb +21 -54
  182. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  183. data/lib/sequel/plugins/static_cache.rb +99 -0
  184. data/lib/sequel/plugins/subclasses.rb +10 -2
  185. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  186. data/lib/sequel/plugins/timestamps.rb +1 -1
  187. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  188. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  189. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  190. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  191. data/lib/sequel/sql.rb +526 -59
  192. data/lib/sequel/timezones.rb +57 -38
  193. data/lib/sequel/version.rb +1 -1
  194. data/spec/adapters/db2_spec.rb +146 -0
  195. data/spec/adapters/firebird_spec.rb +1 -1
  196. data/spec/adapters/mssql_spec.rb +142 -40
  197. data/spec/adapters/mysql_spec.rb +380 -234
  198. data/spec/adapters/oracle_spec.rb +67 -77
  199. data/spec/adapters/postgres_spec.rb +1050 -212
  200. data/spec/adapters/spec_helper.rb +8 -5
  201. data/spec/adapters/sqlite_spec.rb +139 -27
  202. data/spec/core/connection_pool_spec.rb +196 -93
  203. data/spec/core/database_spec.rb +879 -510
  204. data/spec/core/dataset_spec.rb +1415 -1086
  205. data/spec/core/expression_filters_spec.rb +554 -109
  206. data/spec/core/mock_adapter_spec.rb +449 -0
  207. data/spec/core/object_graph_spec.rb +86 -114
  208. data/spec/core/schema_generator_spec.rb +4 -4
  209. data/spec/core/schema_spec.rb +482 -38
  210. data/spec/core/spec_helper.rb +6 -48
  211. data/spec/extensions/active_model_spec.rb +13 -0
  212. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  213. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  214. data/spec/extensions/association_dependencies_spec.rb +15 -25
  215. data/spec/extensions/association_pks_spec.rb +66 -32
  216. data/spec/extensions/association_proxies_spec.rb +4 -4
  217. data/spec/extensions/caching_spec.rb +47 -51
  218. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  219. data/spec/extensions/columns_introspection_spec.rb +91 -0
  220. data/spec/extensions/composition_spec.rb +18 -13
  221. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
  222. data/spec/extensions/dataset_associations_spec.rb +199 -0
  223. data/spec/extensions/defaults_setter_spec.rb +64 -0
  224. data/spec/extensions/dirty_spec.rb +155 -0
  225. data/spec/extensions/eager_each_spec.rb +34 -0
  226. data/spec/extensions/force_encoding_spec.rb +4 -2
  227. data/spec/extensions/hook_class_methods_spec.rb +69 -92
  228. data/spec/extensions/identity_map_spec.rb +131 -22
  229. data/spec/extensions/inflector_spec.rb +0 -4
  230. data/spec/extensions/instance_filters_spec.rb +11 -21
  231. data/spec/extensions/instance_hooks_spec.rb +72 -0
  232. data/spec/extensions/json_serializer_spec.rb +49 -6
  233. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  234. data/spec/extensions/list_spec.rb +48 -39
  235. data/spec/extensions/many_through_many_spec.rb +283 -250
  236. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  237. data/spec/extensions/migration_spec.rb +140 -35
  238. data/spec/extensions/named_timezones_spec.rb +29 -11
  239. data/spec/extensions/nested_attributes_spec.rb +251 -89
  240. data/spec/extensions/null_dataset_spec.rb +85 -0
  241. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  242. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  243. data/spec/extensions/pg_array_spec.rb +196 -0
  244. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  245. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  246. data/spec/extensions/pg_hstore_spec.rb +195 -0
  247. data/spec/extensions/pg_inet_spec.rb +44 -0
  248. data/spec/extensions/pg_json_spec.rb +101 -0
  249. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  250. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  251. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  252. data/spec/extensions/prepared_statements_spec.rb +87 -0
  253. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  254. data/spec/extensions/pretty_table_spec.rb +7 -6
  255. data/spec/extensions/query_literals_spec.rb +168 -0
  256. data/spec/extensions/query_spec.rb +6 -0
  257. data/spec/extensions/rcte_tree_spec.rb +50 -43
  258. data/spec/extensions/schema_caching_spec.rb +41 -0
  259. data/spec/extensions/schema_dumper_spec.rb +429 -22
  260. data/spec/extensions/schema_spec.rb +25 -21
  261. data/spec/extensions/select_remove_spec.rb +38 -0
  262. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  263. data/spec/extensions/serialization_spec.rb +85 -43
  264. data/spec/extensions/server_block_spec.rb +90 -0
  265. data/spec/extensions/sharding_spec.rb +69 -143
  266. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  267. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  268. data/spec/extensions/spec_helper.rb +22 -61
  269. data/spec/extensions/sql_expr_spec.rb +29 -60
  270. data/spec/extensions/static_cache_spec.rb +145 -0
  271. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  272. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  273. data/spec/extensions/timestamps_spec.rb +6 -6
  274. data/spec/extensions/to_dot_spec.rb +4 -7
  275. data/spec/extensions/touch_spec.rb +13 -14
  276. data/spec/extensions/tree_spec.rb +11 -26
  277. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  278. data/spec/extensions/update_primary_key_spec.rb +30 -24
  279. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  280. data/spec/extensions/validation_helpers_spec.rb +16 -35
  281. data/spec/extensions/xml_serializer_spec.rb +29 -4
  282. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  283. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  284. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  285. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  286. data/spec/integration/associations_test.rb +659 -21
  287. data/spec/integration/database_test.rb +9 -3
  288. data/spec/integration/dataset_test.rb +605 -91
  289. data/spec/integration/eager_loader_test.rb +19 -21
  290. data/spec/integration/migrator_test.rb +2 -3
  291. data/spec/integration/model_test.rb +81 -2
  292. data/spec/integration/plugin_test.rb +454 -143
  293. data/spec/integration/prepared_statement_test.rb +263 -128
  294. data/spec/integration/schema_test.rb +309 -43
  295. data/spec/integration/spec_helper.rb +40 -30
  296. data/spec/integration/timezone_test.rb +38 -12
  297. data/spec/integration/transaction_test.rb +183 -8
  298. data/spec/integration/type_test.rb +18 -4
  299. data/spec/model/association_reflection_spec.rb +201 -7
  300. data/spec/model/associations_spec.rb +1067 -661
  301. data/spec/model/base_spec.rb +329 -95
  302. data/spec/model/dataset_methods_spec.rb +7 -27
  303. data/spec/model/eager_loading_spec.rb +677 -676
  304. data/spec/model/hooks_spec.rb +349 -67
  305. data/spec/model/model_spec.rb +240 -168
  306. data/spec/model/plugins_spec.rb +24 -13
  307. data/spec/model/record_spec.rb +490 -232
  308. data/spec/model/spec_helper.rb +14 -71
  309. data/spec/model/validations_spec.rb +11 -0
  310. data/spec/rcov.opts +2 -0
  311. metadata +178 -80
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Database
3
3
  # ---------------------
4
- # :section: Methods that execute queries and/or return results
4
+ # :section: 1 - Methods that execute queries and/or return results
5
5
  # This methods generally execute SQL code on the database server.
6
6
  # ---------------------
7
7
 
@@ -35,11 +35,19 @@ module Sequel
35
35
  # Database#transaction, as on MSSQL if affects all future transactions
36
36
  # on the same connection.
37
37
  attr_accessor :transaction_isolation_level
38
+
39
+ # Whether the schema should be cached for this database. True by default
40
+ # for performance, can be set to false to always issue a database query to
41
+ # get the schema.
42
+ attr_accessor :cache_schema
38
43
 
39
44
  # Runs the supplied SQL statement string on the database server.
40
- # Alias for run.
45
+ # Returns self so it can be safely chained:
46
+ #
47
+ # DB << "UPDATE albums SET artist_id = NULL" << "DROP TABLE artists"
41
48
  def <<(sql)
42
49
  run(sql)
50
+ self
43
51
  end
44
52
 
45
53
  # Call the prepared statement with the given name with the given hash
@@ -47,8 +55,8 @@ module Sequel
47
55
  #
48
56
  # DB[:items].filter(:id=>1).prepare(:first, :sa)
49
57
  # DB.call(:sa) # SELECT * FROM items WHERE id = 1
50
- def call(ps_name, hash={})
51
- prepared_statements[ps_name].call(hash)
58
+ def call(ps_name, hash={}, &block)
59
+ prepared_statement(ps_name).call(hash, &block)
52
60
  end
53
61
 
54
62
  # Executes the given SQL on the database. This method should be overridden in descendants.
@@ -78,16 +86,34 @@ module Sequel
78
86
  execute_dui(sql, opts, &block)
79
87
  end
80
88
 
89
+ # Returns an array of hashes containing foreign key information from the
90
+ # table. Each hash will contain at least the following fields:
91
+ #
92
+ # :columns :: An array of columns in the given table
93
+ # :table :: The table referenced by the columns
94
+ # :key :: An array of columns referenced (in the table specified by :table),
95
+ # but can be nil on certain adapters if the primary key is referenced.
96
+ #
97
+ # The hash may also contain entries for:
98
+ #
99
+ # :deferrable :: Whether the constraint is deferrable
100
+ # :name :: The name of the constraint
101
+ # :on_delete :: The action to take ON DELETE
102
+ # :on_update :: The action to take ON UPDATE
103
+ def foreign_key_list(table, opts={})
104
+ raise NotImplemented, "#foreign_key_list should be overridden by adapters"
105
+ end
106
+
81
107
  # Returns a single value from the database, e.g.:
82
108
  #
83
109
  # DB.get(1) # SELECT 1
84
110
  # # => 1
85
- # DB.get{version{}} # SELECT server_version()
111
+ # DB.get{server_version{}} # SELECT server_version()
86
112
  def get(*args, &block)
87
113
  dataset.get(*args, &block)
88
114
  end
89
115
 
90
- # Return a hash containing index information. Hash keys are index name symbols.
116
+ # Return a hash containing index information for the table. Hash keys are index name symbols.
91
117
  # Values are subhashes with two keys, :columns and :unique. The value of :columns
92
118
  # is an array of symbols of column names. The value of :unique is true or false
93
119
  # depending on if the index is unique.
@@ -110,17 +136,17 @@ module Sequel
110
136
  nil
111
137
  end
112
138
 
113
- # Parse the schema from the database.
114
139
  # Returns the schema for the given table as an array with all members being arrays of length 2,
115
140
  # the first member being the column name, and the second member being a hash of column information.
141
+ # The table argument can also be a dataset, as long as it only has one table.
116
142
  # Available options are:
117
143
  #
118
144
  # :reload :: Ignore any cached results, and get fresh information from the database.
119
145
  # :schema :: An explicit schema to use. It may also be implicitly provided
120
146
  # via the table name.
121
147
  #
122
- # If schema parsing is supported by the database, the column information should at least contain the
123
- # following columns:
148
+ # If schema parsing is supported by the database, the column information should hash at least contain the
149
+ # following entries:
124
150
  #
125
151
  # :allow_null :: Whether NULL is an allowed value for the column.
126
152
  # :db_type :: The database type for the column, as a database specific string.
@@ -129,7 +155,8 @@ module Sequel
129
155
  # it means that primary key information is unavailable, not that the column
130
156
  # is not a primary key.
131
157
  # :ruby_default :: The database default for the column, as a ruby object. In many cases, complex
132
- # database defaults cannot be parsed into ruby objects.
158
+ # database defaults cannot be parsed into ruby objects, in which case nil will be
159
+ # used as the value.
133
160
  # :type :: A symbol specifying the type, such as :integer or :string.
134
161
  #
135
162
  # Example:
@@ -152,32 +179,48 @@ module Sequel
152
179
  def schema(table, opts={})
153
180
  raise(Error, 'schema parsing is not implemented on this database') unless respond_to?(:schema_parse_table, true)
154
181
 
155
- sch, table_name = schema_and_table(table)
156
- quoted_name = quote_schema_table(table)
157
- opts = opts.merge(:schema=>sch) if sch && !opts.include?(:schema)
182
+ opts = opts.dup
183
+ if table.is_a?(Dataset)
184
+ o = table.opts
185
+ from = o[:from]
186
+ raise(Error, "can only parse the schema for a dataset with a single from table") unless from && from.length == 1 && !o.include?(:join) && !o.include?(:sql)
187
+ tab = table.first_source_table
188
+ sch, table_name = schema_and_table(tab)
189
+ quoted_name = table.literal(tab)
190
+ opts[:dataset] = table
191
+ else
192
+ sch, table_name = schema_and_table(table)
193
+ quoted_name = quote_schema_table(table)
194
+ end
195
+ opts[:schema] = sch if sch && !opts.include?(:schema)
158
196
 
159
- @schemas.delete(quoted_name) if opts[:reload]
160
- return @schemas[quoted_name] if @schemas[quoted_name]
197
+ Sequel.synchronize{@schemas.delete(quoted_name)} if opts[:reload]
198
+ return Sequel.synchronize{@schemas[quoted_name]} if @schemas[quoted_name]
161
199
 
162
200
  cols = schema_parse_table(table_name, opts)
163
201
  raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.nil? || cols.empty?
164
202
  cols.each{|_,c| c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type])}
165
- @schemas[quoted_name] = cols
203
+ Sequel.synchronize{@schemas[quoted_name] = cols} if cache_schema
204
+ cols
166
205
  end
167
206
 
168
207
  # Returns true if a table with the given name exists. This requires a query
169
208
  # to the database.
170
209
  #
171
210
  # DB.table_exists?(:foo) # => false
211
+ # # SELECT NULL FROM foo LIMIT 1
212
+ #
213
+ # Note that since this does a SELECT from the table, it can give false negatives
214
+ # if you don't have permission to SELECT from the table.
172
215
  def table_exists?(name)
173
- begin
174
- from(name).first
175
- true
176
- rescue
177
- false
178
- end
216
+ sch, table_name = schema_and_table(name)
217
+ name = SQL::QualifiedIdentifier.new(sch, table_name) if sch
218
+ _table_exists?(from(name))
219
+ true
220
+ rescue DatabaseError
221
+ false
179
222
  end
180
-
223
+
181
224
  # Return all tables in the database as an array of symbols.
182
225
  #
183
226
  # DB.tables # => [:albums, :artists]
@@ -189,7 +232,7 @@ module Sequel
189
232
  # either all statements are successful or none of the statements are
190
233
  # successful. Note that MySQL MyISAM tabels do not support transactions.
191
234
  #
192
- # The following options are respected:
235
+ # The following general options are respected:
193
236
  #
194
237
  # :isolation :: The transaction isolation level to use for this transaction,
195
238
  # should be :uncommitted, :committed, :repeatable, or :serializable,
@@ -198,11 +241,22 @@ module Sequel
198
241
  # :prepare :: A string to use as the transaction identifier for a
199
242
  # prepared transaction (two-phase commit), if the database/adapter
200
243
  # supports prepared transactions.
244
+ # :rollback :: Can the set to :reraise to reraise any Sequel::Rollback exceptions
245
+ # raised, or :always to always rollback even if no exceptions occur
246
+ # (useful for testing).
201
247
  # :server :: The server to use for the transaction.
202
248
  # :savepoint :: Whether to create a new savepoint for this transaction,
203
249
  # only respected if the database/adapter supports savepoints. By
204
250
  # default Sequel will reuse an existing transaction, so if you want to
205
251
  # use a savepoint you must use this option.
252
+ #
253
+ # PostgreSQL specific options:
254
+ #
255
+ # :deferrable :: (9.1+) If present, set to DEFERRABLE if true or NOT DEFERRABLE if false.
256
+ # :read_only :: If present, set to READ ONLY if true or READ WRITE if false.
257
+ # :synchronous :: if non-nil, set synchronous_commit
258
+ # appropriately. Valid values true, :on, false, :off, :local (9.1+),
259
+ # and :remote_write (9.2+).
206
260
  def transaction(opts={}, &block)
207
261
  synchronize(opts[:server]) do |conn|
208
262
  return yield(conn) if already_in_transaction?(conn, opts)
@@ -210,47 +264,99 @@ module Sequel
210
264
  end
211
265
  end
212
266
 
267
+ # Return all views in the database as an array of symbols.
268
+ #
269
+ # DB.views # => [:gold_albums, :artists_with_many_albums]
270
+ def views(opts={})
271
+ raise NotImplemented, "#views should be overridden by adapters"
272
+ end
273
+
213
274
  private
214
275
 
276
+ # Should raise an error if the table doesn't not exist,
277
+ # and not raise an error if the table does exist.
278
+ def _table_exists?(ds)
279
+ ds.get(Sequel::NULL)
280
+ end
281
+
215
282
  # Internal generic transaction method. Any exception raised by the given
216
283
  # block will cause the transaction to be rolled back. If the exception is
217
284
  # not a Sequel::Rollback, the error will be reraised. If no exception occurs
218
285
  # inside the block, the transaction is commited.
219
286
  def _transaction(conn, opts={})
287
+ rollback = opts[:rollback]
220
288
  begin
221
- add_transaction
222
- t = begin_transaction(conn, opts)
223
- yield(conn)
289
+ add_transaction(conn, opts)
290
+ begin_transaction(conn, opts)
291
+ if rollback == :always
292
+ begin
293
+ yield(conn)
294
+ rescue Exception => e1
295
+ raise e1
296
+ ensure
297
+ raise ::Sequel::Rollback unless e1
298
+ end
299
+ else
300
+ yield(conn)
301
+ end
224
302
  rescue Exception => e
225
- rollback_transaction(t, opts) if t
226
- transaction_error(e)
303
+ begin
304
+ rollback_transaction(conn, opts)
305
+ rescue Exception => e3
306
+ raise_error(e3, :classes=>database_error_classes, :conn=>conn)
307
+ end
308
+ transaction_error(e, :conn=>conn, :rollback=>rollback)
227
309
  ensure
228
310
  begin
229
- commit_transaction(t, opts) unless e
230
- rescue Exception => e
231
- raise_error(e, :classes=>database_error_classes)
311
+ committed = commit_or_rollback_transaction(e, conn, opts)
312
+ rescue Exception => e2
313
+ raise_error(e2, :classes=>database_error_classes, :conn=>conn)
232
314
  ensure
233
- remove_transaction(t)
315
+ remove_transaction(conn, committed)
234
316
  end
235
317
  end
236
318
  end
237
-
319
+
320
+ # Synchronize access to the current transactions, returning the hash
321
+ # of options for the current transaction (if any)
322
+ def _trans(conn)
323
+ Sequel.synchronize{@transactions[conn]}
324
+ end
325
+
238
326
  # Add the current thread to the list of active transactions
239
- def add_transaction
240
- th = Thread.current
327
+ def add_transaction(conn, opts)
241
328
  if supports_savepoints?
242
- unless @transactions.include?(th)
243
- th[:sequel_transaction_depth] = 0
244
- @transactions << th
329
+ unless _trans(conn)
330
+ if (prep = opts[:prepare]) && supports_prepared_transactions?
331
+ Sequel.synchronize{@transactions[conn] = {:savepoint_level=>0, :prepare=>prep}}
332
+ else
333
+ Sequel.synchronize{@transactions[conn] = {:savepoint_level=>0}}
334
+ end
245
335
  end
336
+ elsif (prep = opts[:prepare]) && supports_prepared_transactions?
337
+ Sequel.synchronize{@transactions[conn] = {:prepare => prep}}
246
338
  else
247
- @transactions << th
339
+ Sequel.synchronize{@transactions[conn] = {}}
248
340
  end
249
341
  end
250
342
 
343
+ # Call all stored after_commit blocks for the given transaction
344
+ def after_transaction_commit(conn)
345
+ if ary = _trans(conn)[:after_commit]
346
+ ary.each{|b| b.call}
347
+ end
348
+ end
349
+
350
+ # Call all stored after_rollback blocks for the given transaction
351
+ def after_transaction_rollback(conn)
352
+ if ary = _trans(conn)[:after_rollback]
353
+ ary.each{|b| b.call}
354
+ end
355
+ end
356
+
251
357
  # Whether the current thread/connection is already inside a transaction
252
358
  def already_in_transaction?(conn, opts)
253
- @transactions.include?(Thread.current) && (!supports_savepoints? || !opts[:savepoint])
359
+ _trans(conn) && (!supports_savepoints? || !opts[:savepoint])
254
360
  end
255
361
 
256
362
  # SQL to start a new savepoint
@@ -267,17 +373,16 @@ module Sequel
267
373
  # Start a new database transaction or a new savepoint on the given connection.
268
374
  def begin_transaction(conn, opts={})
269
375
  if supports_savepoints?
270
- th = Thread.current
271
- if (depth = th[:sequel_transaction_depth]) > 0
376
+ th = _trans(conn)
377
+ if (depth = th[:savepoint_level]) > 0
272
378
  log_connection_execute(conn, begin_savepoint_sql(depth))
273
379
  else
274
380
  begin_new_transaction(conn, opts)
275
381
  end
276
- th[:sequel_transaction_depth] += 1
382
+ th[:savepoint_level] += 1
277
383
  else
278
384
  begin_new_transaction(conn, opts)
279
385
  end
280
- conn
281
386
  end
282
387
 
283
388
  # SQL to BEGIN a transaction.
@@ -335,6 +440,38 @@ module Sequel
335
440
  end
336
441
  end
337
442
 
443
+ if (! defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby' or RUBY_ENGINE == 'rbx') and RUBY_VERSION < '1.9'
444
+ # Whether to commit the current transaction. On ruby 1.8 and rubinius,
445
+ # Thread.current.status is checked because Thread#kill skips rescue
446
+ # blocks (so exception would be nil), but the transaction should
447
+ # still be rolled back.
448
+ def commit_or_rollback_transaction(exception, conn, opts)
449
+ if exception
450
+ false
451
+ else
452
+ if Thread.current.status == 'aborting'
453
+ rollback_transaction(conn, opts)
454
+ false
455
+ else
456
+ commit_transaction(conn, opts)
457
+ true
458
+ end
459
+ end
460
+ end
461
+ else
462
+ # Whether to commit the current transaction. On ruby 1.9 and JRuby,
463
+ # transactions will be committed if Thread#kill is used on an thread
464
+ # that has a transaction open, and there isn't a work around.
465
+ def commit_or_rollback_transaction(exception, conn, opts)
466
+ if exception
467
+ false
468
+ else
469
+ commit_transaction(conn, opts)
470
+ true
471
+ end
472
+ end
473
+ end
474
+
338
475
  # SQL to commit a savepoint
339
476
  def commit_savepoint_sql(depth)
340
477
  SQL_RELEASE_SAVEPOINT % depth
@@ -343,7 +480,7 @@ module Sequel
343
480
  # Commit the active transaction on the connection
344
481
  def commit_transaction(conn, opts={})
345
482
  if supports_savepoints?
346
- depth = Thread.current[:sequel_transaction_depth]
483
+ depth = _trans(conn)[:savepoint_level]
347
484
  log_connection_execute(conn, depth > 1 ? commit_savepoint_sql(depth-1) : commit_transaction_sql)
348
485
  else
349
486
  log_connection_execute(conn, commit_transaction_sql)
@@ -364,8 +501,8 @@ module Sequel
364
501
  # Return a Method object for the dataset's output_identifier_method.
365
502
  # Used in metadata parsing to make sure the returned information is in the
366
503
  # correct format.
367
- def input_identifier_meth
368
- dataset.method(:input_identifier)
504
+ def input_identifier_meth(ds=nil)
505
+ (ds || dataset).method(:input_identifier)
369
506
  end
370
507
 
371
508
  # Return a dataset that uses the default identifier input and output methods
@@ -382,24 +519,28 @@ module Sequel
382
519
  # Return a Method object for the dataset's output_identifier_method.
383
520
  # Used in metadata parsing to make sure the returned information is in the
384
521
  # correct format.
385
- def output_identifier_meth
386
- dataset.method(:output_identifier)
522
+ def output_identifier_meth(ds=nil)
523
+ (ds || dataset).method(:output_identifier)
387
524
  end
388
525
 
389
- # SQL to ROLLBACK a transaction.
390
- def rollback_transaction_sql
391
- SQL_ROLLBACK
392
- end
393
-
394
526
  # Remove the cached schema for the given schema name
395
527
  def remove_cached_schema(table)
396
528
  @schemas.delete(quote_schema_table(table)) if @schemas
397
529
  end
398
530
 
399
531
  # Remove the current thread from the list of active transactions
400
- def remove_transaction(conn)
401
- th = Thread.current
402
- @transactions.delete(th) if !supports_savepoints? || ((th[:sequel_transaction_depth] -= 1) <= 0)
532
+ def remove_transaction(conn, committed)
533
+ if !supports_savepoints? || ((_trans(conn)[:savepoint_level] -= 1) <= 0)
534
+ begin
535
+ if committed
536
+ after_transaction_commit(conn)
537
+ else
538
+ after_transaction_rollback(conn)
539
+ end
540
+ ensure
541
+ Sequel.synchronize{@transactions.delete(conn)}
542
+ end
543
+ end
403
544
  end
404
545
 
405
546
  # SQL to rollback to a savepoint
@@ -410,13 +551,18 @@ module Sequel
410
551
  # Rollback the active transaction on the connection
411
552
  def rollback_transaction(conn, opts={})
412
553
  if supports_savepoints?
413
- depth = Thread.current[:sequel_transaction_depth]
554
+ depth = _trans(conn)[:savepoint_level]
414
555
  log_connection_execute(conn, depth > 1 ? rollback_savepoint_sql(depth-1) : rollback_transaction_sql)
415
556
  else
416
557
  log_connection_execute(conn, rollback_transaction_sql)
417
558
  end
418
559
  end
419
560
 
561
+ # SQL to ROLLBACK a transaction.
562
+ def rollback_transaction_sql
563
+ SQL_ROLLBACK
564
+ end
565
+
420
566
  # Match the database's column type to a ruby type via a
421
567
  # regular expression, and return the ruby type as a symbol
422
568
  # such as :integer or :string.
@@ -434,13 +580,13 @@ module Sequel
434
580
  :datetime
435
581
  when /\Atime( with(out)? time zone)?\z/io
436
582
  :time
437
- when /\A(boolean|bit)\z/io
583
+ when /\A(bool(ean)?)\z/io
438
584
  :boolean
439
585
  when /\A(real|float|double( precision)?)\z/io
440
586
  :float
441
- when /\A(?:(?:(?:num(?:ber|eric)?|decimal)(?:\(\d+,\s*(\d+)\))?)|(?:small)?money)\z/io
442
- $1 && $1 == '0' ? :integer : :decimal
443
- when /bytea|blob|image|(var)?binary/io
587
+ when /\A(?:(?:(?:num(?:ber|eric)?|decimal)(?:\(\d+,\s*(\d+|false|true)\))?)|(?:small)?money)\z/io
588
+ $1 && ['0', 'false'].include?($1) ? :integer : :decimal
589
+ when /bytea|[bc]lob|image|(var)?binary/io
444
590
  :blob
445
591
  when /\Aenum/io
446
592
  :enum
@@ -460,8 +606,12 @@ module Sequel
460
606
  end
461
607
 
462
608
  # Raise a database error unless the exception is an Rollback.
463
- def transaction_error(e)
464
- raise_error(e, :classes=>database_error_classes) unless e.is_a?(Rollback)
609
+ def transaction_error(e, opts={})
610
+ if e.is_a?(Rollback)
611
+ raise e if opts[:rollback] == :reraise
612
+ else
613
+ raise_error(e, opts.merge(:classes=>database_error_classes))
614
+ end
465
615
  end
466
616
  end
467
617
  end
@@ -83,30 +83,28 @@ module Sequel
83
83
  # reference table will use for its foreign key a value that does not
84
84
  # exists(yet) on referenced table. Basically it adds
85
85
  # DEFERRABLE INITIALLY DEFERRED on key creation.
86
- # :index :: Create an index on this column.
86
+ # :index :: Create an index on this column. If given a hash, use the hash as the
87
+ # options for the index.
87
88
  # :key :: For foreign key columns, the column in the associated table
88
89
  # that this column references. Unnecessary if this column
89
- # references the primary key of the associated table.
90
+ # references the primary key of the associated table, except if you are
91
+ # using MySQL.
90
92
  # :null :: Mark the column as allowing NULL values (if true),
91
93
  # or not allowing NULL values (if false). If unspecified, will default
92
94
  # to whatever the database default is.
93
95
  # :on_delete :: Specify the behavior of this column when being deleted
94
- # (:restrict, cascade, :set_null, :set_default, :no_action).
96
+ # (:restrict, :cascade, :set_null, :set_default, :no_action).
95
97
  # :on_update :: Specify the behavior of this column when being updated
96
- # (:restrict, cascade, :set_null, :set_default, :no_action).
98
+ # (:restrict, :cascade, :set_null, :set_default, :no_action).
97
99
  # :primary_key :: Make the column as a single primary key column. This should only
98
100
  # be used if you have a single, nonautoincrementing primary key column.
99
- # :size :: The size of the column, generally used with string
100
- # columns to specify the maximum number of characters the column will hold.
101
- # An array of two integers can be provided to set the size and the
102
- # precision, respectively, of decimal columns.
103
101
  # :unique :: Mark the column as unique, generally has the same effect as
104
102
  # creating a unique index on the column.
105
- # :unsigned :: Make the column type unsigned, only useful for integer
106
- # columns.
107
103
  def column(name, type, opts = {})
108
104
  columns << {:name => name, :type => type}.merge(opts)
109
- index(name) if opts[:index]
105
+ if index_opts = opts[:index]
106
+ index(name, index_opts.is_a?(Hash) ? index_opts : {})
107
+ end
110
108
  end
111
109
 
112
110
  # Adds a named constraint (or unnamed if name is nil) to the DDL,
@@ -124,6 +122,13 @@ module Sequel
124
122
  # foreign_key(:artist_id) # artist_id INTEGER
125
123
  # foreign_key(:artist_id, :artists) # artist_id INTEGER REFERENCES artists
126
124
  # foreign_key(:artist_id, :artists, :key=>:id) # artist_id INTEGER REFERENCES artists(id)
125
+ #
126
+ # If you want a foreign key constraint without adding a column (usually because it is a
127
+ # composite foreign key), you can provide an array of columns as the first argument, and
128
+ # you can provide the :name option to name the constraint:
129
+ #
130
+ # foreign_key([:artist_name, :artist_location], :artists, :name=>:artist_fk)
131
+ # # ADD CONSTRAINT artist_fk FOREIGN KEY (artist_name, artist_location) REFERENCES artists
127
132
  def foreign_key(name, table=nil, opts = {})
128
133
  opts = case table
129
134
  when Hash
@@ -140,6 +145,12 @@ module Sequel
140
145
  end
141
146
 
142
147
  # Add a full text index on the given columns to the DDL.
148
+ #
149
+ # PostgreSQL specific options:
150
+ # :language :: Set a language to use for the index (default: simple).
151
+ #
152
+ # Microsoft SQL Server specific options:
153
+ # :key_index :: The KEY INDEX to use for the full text index.
143
154
  def full_text_index(columns, opts = {})
144
155
  index(columns, opts.merge(:type => :full_text))
145
156
  end
@@ -150,12 +161,26 @@ module Sequel
150
161
  end
151
162
 
152
163
  # Add an index on the given column(s) with the given options to the DDL.
153
- # The available options are:
164
+ # General options:
154
165
  #
166
+ # :name :: The name to use for the index. If not given, a default name
167
+ # based on the table and columns is used.
155
168
  # :type :: The type of index to use (only supported by some databases)
156
169
  # :unique :: Make the index unique, so duplicate values are not allowed.
157
170
  # :where :: Create a partial index (only supported by some databases)
158
171
  #
172
+ # PostgreSQL specific options:
173
+ #
174
+ # :concurrently :: Create the index concurrently, so it doesn't block
175
+ # operations on the table while the index is being
176
+ # built.
177
+ # :op_class :: Use a specific operator class in the index.
178
+ #
179
+ # Microsoft SQL Server specific options:
180
+ #
181
+ # :include :: Include additional column values in the index, without
182
+ # actually indexing on those values.
183
+ #
159
184
  # index :name
160
185
  # # CREATE INDEX table_name_index ON table (name)
161
186
  #
@@ -281,8 +306,8 @@ module Sequel
281
306
  # to the DDL for the table. See Generator#column for the available options.
282
307
  #
283
308
  # You can also pass an array of column names for creating composite foreign
284
- # keys. In this case, it will assume the columns exists and will only add
285
- # the constraint.
309
+ # keys. In this case, it will assume the columns exist and will only add
310
+ # the constraint. You can provide a :name option to name the constraint.
286
311
  #
287
312
  # NOTE: If you need to add a foreign key constraint to a single existing column
288
313
  # use the composite key syntax even if it is only one column.
@@ -329,18 +354,33 @@ module Sequel
329
354
  # Remove a column from the DDL for the table.
330
355
  #
331
356
  # drop_column(:artist_id) # DROP COLUMN artist_id
332
- def drop_column(name)
333
- @operations << {:op => :drop_column, :name => name}
357
+ # drop_column(:artist_id, :cascade=>true) # DROP COLUMN artist_id CASCADE
358
+ def drop_column(name, opts={})
359
+ @operations << {:op => :drop_column, :name => name}.merge(opts)
334
360
  end
335
361
 
336
- # Remove a constraint from the DDL for the table.
362
+ # Remove a constraint from the DDL for the table. MySQL/SQLite specific options:
363
+ #
364
+ # :type :: Set the type of constraint to drop, either :primary_key, :foreign_key,
365
+ # or :unique.
337
366
  #
338
367
  # drop_constraint(:unique_name) # DROP CONSTRAINT unique_name
339
- def drop_constraint(name)
340
- @operations << {:op => :drop_constraint, :name => name}
368
+ # drop_constraint(:unique_name, :cascade=>true) # DROP CONSTRAINT unique_name CASCADE
369
+ def drop_constraint(name, opts={})
370
+ @operations << {:op => :drop_constraint, :name => name}.merge(opts)
341
371
  end
342
372
 
343
- # Remove an index from the DDL for the table.
373
+ # Remove an index from the DDL for the table. General options:
374
+ #
375
+ # :name :: The name of the index to drop. If not given, uses the same name
376
+ # that would be used by add_index with the same columns.
377
+ #
378
+ # PostgreSQL specific options:
379
+ #
380
+ # :cascade :: Cascade the index drop to dependent objects.
381
+ # :concurrently :: Drop the index using CONCURRENTLY, which doesn't block
382
+ # operations on the table. Supported in PostgreSQL 9.2+.
383
+ # :if_exists :: Only drop the index if it already exists.
344
384
  #
345
385
  # drop_index(:artist_id) # DROP INDEX table_artist_id_index
346
386
  # drop_index([:a, :b]) # DROP INDEX table_a_b_index
@@ -366,6 +406,10 @@ module Sequel
366
406
  # Modify a column's type in the DDL for the table.
367
407
  #
368
408
  # set_column_type(:artist_name, 'char(10)') # ALTER COLUMN artist_name TYPE char(10)
409
+ #
410
+ # PostgreSQL specific options:
411
+ #
412
+ # :using :: Add a USING clause that specifies how to convert existing values to new values.
369
413
  def set_column_type(name, type, opts={})
370
414
  @operations << {:op => :set_column_type, :name => name, :type => type}.merge(opts)
371
415
  end