sequel 5.39.0 → 5.64.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +318 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +57 -25
  5. data/bin/sequel +11 -3
  6. data/doc/advanced_associations.rdoc +13 -13
  7. data/doc/association_basics.rdoc +119 -24
  8. data/doc/cheat_sheet.rdoc +11 -3
  9. data/doc/migration.rdoc +12 -6
  10. data/doc/model_hooks.rdoc +1 -1
  11. data/doc/object_model.rdoc +8 -8
  12. data/doc/opening_databases.rdoc +18 -11
  13. data/doc/postgresql.rdoc +16 -8
  14. data/doc/querying.rdoc +5 -3
  15. data/doc/release_notes/5.40.0.txt +40 -0
  16. data/doc/release_notes/5.41.0.txt +25 -0
  17. data/doc/release_notes/5.42.0.txt +136 -0
  18. data/doc/release_notes/5.43.0.txt +98 -0
  19. data/doc/release_notes/5.44.0.txt +32 -0
  20. data/doc/release_notes/5.45.0.txt +34 -0
  21. data/doc/release_notes/5.46.0.txt +87 -0
  22. data/doc/release_notes/5.47.0.txt +59 -0
  23. data/doc/release_notes/5.48.0.txt +14 -0
  24. data/doc/release_notes/5.49.0.txt +59 -0
  25. data/doc/release_notes/5.50.0.txt +78 -0
  26. data/doc/release_notes/5.51.0.txt +47 -0
  27. data/doc/release_notes/5.52.0.txt +87 -0
  28. data/doc/release_notes/5.53.0.txt +23 -0
  29. data/doc/release_notes/5.54.0.txt +27 -0
  30. data/doc/release_notes/5.55.0.txt +21 -0
  31. data/doc/release_notes/5.56.0.txt +51 -0
  32. data/doc/release_notes/5.57.0.txt +23 -0
  33. data/doc/release_notes/5.58.0.txt +31 -0
  34. data/doc/release_notes/5.59.0.txt +73 -0
  35. data/doc/release_notes/5.60.0.txt +22 -0
  36. data/doc/release_notes/5.61.0.txt +43 -0
  37. data/doc/release_notes/5.62.0.txt +132 -0
  38. data/doc/release_notes/5.63.0.txt +33 -0
  39. data/doc/release_notes/5.64.0.txt +50 -0
  40. data/doc/schema_modification.rdoc +1 -1
  41. data/doc/security.rdoc +9 -9
  42. data/doc/sql.rdoc +27 -15
  43. data/doc/testing.rdoc +22 -11
  44. data/doc/transactions.rdoc +6 -6
  45. data/doc/virtual_rows.rdoc +2 -2
  46. data/lib/sequel/adapters/ado/access.rb +1 -1
  47. data/lib/sequel/adapters/ado.rb +17 -17
  48. data/lib/sequel/adapters/amalgalite.rb +3 -5
  49. data/lib/sequel/adapters/ibmdb.rb +2 -2
  50. data/lib/sequel/adapters/jdbc/derby.rb +8 -0
  51. data/lib/sequel/adapters/jdbc/h2.rb +60 -10
  52. data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
  53. data/lib/sequel/adapters/jdbc/postgresql.rb +4 -4
  54. data/lib/sequel/adapters/jdbc.rb +16 -18
  55. data/lib/sequel/adapters/mysql.rb +80 -67
  56. data/lib/sequel/adapters/mysql2.rb +54 -49
  57. data/lib/sequel/adapters/odbc.rb +6 -2
  58. data/lib/sequel/adapters/oracle.rb +4 -3
  59. data/lib/sequel/adapters/postgres.rb +83 -40
  60. data/lib/sequel/adapters/shared/access.rb +11 -1
  61. data/lib/sequel/adapters/shared/db2.rb +30 -0
  62. data/lib/sequel/adapters/shared/mssql.rb +58 -7
  63. data/lib/sequel/adapters/shared/mysql.rb +40 -2
  64. data/lib/sequel/adapters/shared/oracle.rb +76 -0
  65. data/lib/sequel/adapters/shared/postgres.rb +418 -174
  66. data/lib/sequel/adapters/shared/sqlanywhere.rb +11 -1
  67. data/lib/sequel/adapters/shared/sqlite.rb +103 -11
  68. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  69. data/lib/sequel/adapters/sqlite.rb +60 -18
  70. data/lib/sequel/adapters/tinytds.rb +1 -1
  71. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  72. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  73. data/lib/sequel/ast_transformer.rb +6 -0
  74. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  75. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
  76. data/lib/sequel/connection_pool/single.rb +6 -8
  77. data/lib/sequel/connection_pool/threaded.rb +8 -8
  78. data/lib/sequel/connection_pool/timed_queue.rb +257 -0
  79. data/lib/sequel/connection_pool.rb +47 -30
  80. data/lib/sequel/core.rb +28 -18
  81. data/lib/sequel/database/connecting.rb +26 -2
  82. data/lib/sequel/database/misc.rb +69 -14
  83. data/lib/sequel/database/query.rb +73 -2
  84. data/lib/sequel/database/schema_generator.rb +45 -52
  85. data/lib/sequel/database/schema_methods.rb +17 -1
  86. data/lib/sequel/dataset/actions.rb +107 -13
  87. data/lib/sequel/dataset/features.rb +20 -0
  88. data/lib/sequel/dataset/misc.rb +1 -1
  89. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  90. data/lib/sequel/dataset/query.rb +118 -16
  91. data/lib/sequel/dataset/sql.rb +177 -47
  92. data/lib/sequel/extensions/_model_pg_row.rb +0 -12
  93. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  94. data/lib/sequel/extensions/any_not_empty.rb +1 -1
  95. data/lib/sequel/extensions/async_thread_pool.rb +438 -0
  96. data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
  97. data/lib/sequel/extensions/blank.rb +8 -0
  98. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  99. data/lib/sequel/extensions/core_refinements.rb +36 -11
  100. data/lib/sequel/extensions/date_arithmetic.rb +71 -31
  101. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  102. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  103. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
  104. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  105. data/lib/sequel/extensions/inflector.rb +9 -1
  106. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  107. data/lib/sequel/extensions/looser_typecasting.rb +3 -0
  108. data/lib/sequel/extensions/migration.rb +7 -2
  109. data/lib/sequel/extensions/named_timezones.rb +26 -6
  110. data/lib/sequel/extensions/pagination.rb +1 -1
  111. data/lib/sequel/extensions/pg_array.rb +23 -3
  112. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  113. data/lib/sequel/extensions/pg_auto_parameterize.rb +478 -0
  114. data/lib/sequel/extensions/pg_enum.rb +1 -1
  115. data/lib/sequel/extensions/pg_extended_date_support.rb +28 -25
  116. data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  117. data/lib/sequel/extensions/pg_hstore.rb +6 -1
  118. data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
  119. data/lib/sequel/extensions/pg_inet.rb +10 -11
  120. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  121. data/lib/sequel/extensions/pg_interval.rb +45 -19
  122. data/lib/sequel/extensions/pg_json.rb +13 -15
  123. data/lib/sequel/extensions/pg_json_ops.rb +73 -2
  124. data/lib/sequel/extensions/pg_loose_count.rb +3 -1
  125. data/lib/sequel/extensions/pg_multirange.rb +367 -0
  126. data/lib/sequel/extensions/pg_range.rb +10 -23
  127. data/lib/sequel/extensions/pg_range_ops.rb +37 -9
  128. data/lib/sequel/extensions/pg_row.rb +19 -13
  129. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  130. data/lib/sequel/extensions/query.rb +2 -0
  131. data/lib/sequel/extensions/s.rb +2 -1
  132. data/lib/sequel/extensions/schema_dumper.rb +13 -2
  133. data/lib/sequel/extensions/server_block.rb +8 -12
  134. data/lib/sequel/extensions/sql_comments.rb +110 -3
  135. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  136. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  137. data/lib/sequel/extensions/string_agg.rb +1 -1
  138. data/lib/sequel/extensions/string_date_time.rb +19 -23
  139. data/lib/sequel/extensions/symbol_aref.rb +2 -0
  140. data/lib/sequel/model/associations.rb +330 -96
  141. data/lib/sequel/model/base.rb +51 -27
  142. data/lib/sequel/model/errors.rb +10 -1
  143. data/lib/sequel/model/inflections.rb +1 -1
  144. data/lib/sequel/model/plugins.rb +5 -0
  145. data/lib/sequel/plugins/association_proxies.rb +2 -0
  146. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  147. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  148. data/lib/sequel/plugins/auto_validations.rb +87 -15
  149. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  150. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  151. data/lib/sequel/plugins/column_encryption.rb +728 -0
  152. data/lib/sequel/plugins/composition.rb +10 -4
  153. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  154. data/lib/sequel/plugins/constraint_validations.rb +2 -1
  155. data/lib/sequel/plugins/dataset_associations.rb +4 -1
  156. data/lib/sequel/plugins/dirty.rb +1 -1
  157. data/lib/sequel/plugins/enum.rb +124 -0
  158. data/lib/sequel/plugins/finder.rb +3 -1
  159. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  160. data/lib/sequel/plugins/instance_specific_default.rb +1 -1
  161. data/lib/sequel/plugins/json_serializer.rb +39 -24
  162. data/lib/sequel/plugins/lazy_attributes.rb +3 -0
  163. data/lib/sequel/plugins/list.rb +3 -1
  164. data/lib/sequel/plugins/many_through_many.rb +109 -10
  165. data/lib/sequel/plugins/nested_attributes.rb +12 -7
  166. data/lib/sequel/plugins/pg_array_associations.rb +56 -38
  167. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -1
  168. data/lib/sequel/plugins/prepared_statements.rb +10 -1
  169. data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  170. data/lib/sequel/plugins/rcte_tree.rb +27 -19
  171. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  172. data/lib/sequel/plugins/serialization.rb +9 -3
  173. data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
  174. data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
  175. data/lib/sequel/plugins/sql_comments.rb +189 -0
  176. data/lib/sequel/plugins/static_cache.rb +1 -1
  177. data/lib/sequel/plugins/subclasses.rb +28 -11
  178. data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
  179. data/lib/sequel/plugins/timestamps.rb +1 -1
  180. data/lib/sequel/plugins/unused_associations.rb +521 -0
  181. data/lib/sequel/plugins/update_or_create.rb +1 -1
  182. data/lib/sequel/plugins/validate_associated.rb +22 -12
  183. data/lib/sequel/plugins/validation_helpers.rb +38 -11
  184. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  185. data/lib/sequel/sql.rb +1 -1
  186. data/lib/sequel/timezones.rb +12 -14
  187. data/lib/sequel/version.rb +1 -1
  188. metadata +99 -43
data/doc/security.rdoc CHANGED
@@ -127,8 +127,8 @@ a ruby string as raw SQL. For example:
127
127
  DB.literal(Date.today) # "'2013-03-22'"
128
128
  DB.literal('a') # "'a'"
129
129
  DB.literal(Sequel.lit('a')) # "a"
130
- DB.literal(:a => 'a') # "(\"a\" = 'a')"
131
- DB.literal(:a => Sequel.lit('a')) # "(\"a\" = a)"
130
+ DB.literal(a: 'a') # "(\"a\" = 'a')"
131
+ DB.literal(a: Sequel.lit('a')) # "(\"a\" = a)"
132
132
 
133
133
  ==== SQL Filter Fragments
134
134
 
@@ -178,7 +178,7 @@ user input for function names.
178
178
  For backwards compatibility, Sequel supports regular strings in the
179
179
  window function :frame option, which will be treated as a literal string:
180
180
 
181
- DB[:table].select{fun(arg).over(:frame=>'SQL Here')}
181
+ DB[:table].select{fun(arg).over(frame: 'SQL Here')}
182
182
 
183
183
  You should make sure the frame argument is not derived from user input,
184
184
  or switch to using a hash as the :frame option value.
@@ -237,7 +237,7 @@ or:
237
237
 
238
238
  Instead, you should do:
239
239
 
240
- DB[:table].update(:column => params[:value].to_s) # Safe
240
+ DB[:table].update(column: params[:value].to_s) # Safe
241
241
 
242
242
  Because using the auto_literal_strings extension makes SQL injection
243
243
  so much eaiser, it is recommended to not use it, and instead
@@ -402,29 +402,29 @@ This issue isn't necessarily specific to Sequel, but it is a good general practi
402
402
  If you are using values derived from user input, it is best to be explicit about
403
403
  their type. For example:
404
404
 
405
- Album.where(:id=>params[:id])
405
+ Album.where(id: params[:id])
406
406
 
407
407
  is probably a bad idea. Assuming you are using a web framework, <tt>params[:id]</tt> could
408
408
  be a string, an array, a hash, nil, or potentially something else.
409
409
 
410
410
  Assuming that +id+ is an integer field, you probably want to do:
411
411
 
412
- Album.where(:id=>params[:id].to_i)
412
+ Album.where(id: params[:id].to_i)
413
413
 
414
414
  If you are looking something up by name, you should try to enforce the value to be
415
415
  a string:
416
416
 
417
- Album.where(:name=>params[:name].to_s)
417
+ Album.where(name: params[:name].to_s)
418
418
 
419
419
  If you are trying to use an IN clause with a list of id values based on input provided
420
420
  on a web form:
421
421
 
422
- Album.where(:id=>params[:ids].to_a.map(&:to_i))
422
+ Album.where(id: params[:ids].to_a.map(&:to_i))
423
423
 
424
424
  Basically, be as explicit as possible. While there aren't any known security issues
425
425
  in Sequel when you do:
426
426
 
427
- Album.where(:id=>params[:id])
427
+ Album.where(id: params[:id])
428
428
 
429
429
  It allows the attacker to choose to do any of the following queries:
430
430
 
data/doc/sql.rdoc CHANGED
@@ -223,22 +223,22 @@ If the database supports window functions, Sequel can handle them by calling the
223
223
  DB[:albums].select{count.function.*.over}
224
224
  # SELECT count(*) OVER () FROM albums
225
225
 
226
- DB[:albums].select{function(:col1).over(:partition=>col2, :order=>col3)}
226
+ DB[:albums].select{function(:col1).over(partition: col2, order: col3)}
227
227
  # SELECT function(col1) OVER (PARTITION BY col2 ORDER BY col3) FROM albums
228
228
 
229
- DB[:albums].select{function(c1, c2).over(:partition=>[c3, c4], :order=>[c5, c6.desc])}
229
+ DB[:albums].select{function(c1, c2).over(partition: [c3, c4], order: [c5, c6.desc])}
230
230
  # SELECT function(c1, c2) OVER (PARTITION BY c3, c4 ORDER BY c5, c6 DESC) FROM albums
231
231
 
232
- DB[:albums].select{function(c1).over(:partition=>c2, :order=>:c3, :frame=>:rows)}
232
+ DB[:albums].select{function(c1).over(partition: c2, order: :c3, frame: :rows)}
233
233
  # SELECT function(c1) OVER (PARTITION BY c2 ORDER BY c3 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM albums
234
234
 
235
- DB[:albums].select{function(c1).over(:partition=>c2, :order=>:c3, :frame=>{:type=>:range, :start=>1, :end=>1})}
235
+ DB[:albums].select{function(c1).over(partition: c2, order: :c3, frame: {type: :range, start: 1, end: 1})}
236
236
  # SELECT function(c1) OVER (PARTITION BY c2 ORDER BY c3 RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM albums
237
237
 
238
- DB[:albums].select{function(c1).over(:partition=>c2, :order=>:c3, :frame=>{:type=>:groups, :start=>[2, :preceding], :end=>[1, :preceding]})}
238
+ DB[:albums].select{function(c1).over(partition: c2, order: :c3, frame: {type: :groups, start: [2, :preceding], end: [1, :preceding]})}
239
239
  # SELECT function(c1) OVER (PARTITION BY c2 ORDER BY c3 GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING) FROM albums
240
240
 
241
- DB[:albums].select{function(c1).over(:partition=>c2, :order=>:c3, :frame=>{:type=>:range, :start=>:preceding, :exclude=>:current})}
241
+ DB[:albums].select{function(c1).over(partition: c2, order: :c3, frame: {type: :range, start: :preceding, exclude: :current})}
242
242
  # SELECT function(c1) OVER (PARTITION BY c2 ORDER BY c3 RANGE UNBOUNDED PRECEDING EXCLUDE CURRENT ROW) FROM albums
243
243
 
244
244
  === Schema Qualified Functions
@@ -428,6 +428,18 @@ As you can see, these literalize with ANDs by default. You can use the <tt>Sequ
428
428
 
429
429
  Sequel.or(column1: 1, column2: 2) # (("column1" = 1) OR ("column2" = 2))
430
430
 
431
+ As you can see in the above examples, <tt>Sequel.|</tt> and <tt>Sequel.or</tt> work differently.
432
+ <tt>Sequel.|</tt> is for combining an arbitrary number of expressions using OR. If you pass a single
433
+ argument, <tt>Sequel.|</tt> will just convert it to a Sequel expression, similar to <tt>Sequel.expr</tt>.
434
+ <tt>Sequel.or</tt> is for taking a single hash or array of two element arrays and combining the
435
+ elements of that single argument using OR instead of AND:
436
+
437
+ Sequel.|(column1: 1, column2: 2) # (("column1" = 1) AND ("column2" = 2))
438
+ Sequel.or(column1: 1, column2: 2) # (("column1" = 1) OR ("column2" = 2))
439
+
440
+ Sequel.|({column1: 1}, {column2: 2}) # (("column1" = 1) OR ("column2" = 2))
441
+ Sequel.or({column1: 1}, {column2: 2}) # ArgumentError
442
+
431
443
  You've already seen the <tt>Sequel.negate</tt> method, which will use ANDs if multiple entries are used:
432
444
 
433
445
  Sequel.negate(column1: 1, column2: 2) # (("column1" != 1) AND ("column2" != 2))
@@ -516,7 +528,7 @@ Inverting the LIKE operator works like other inversions:
516
528
 
517
529
  ~Sequel.like(:name, 'A%') # ("name" NOT LIKE 'A%' ESCAPE '\')
518
530
 
519
- Sequel also supports SQL regular expressions on MySQL and PostgreSQL. You can use these by passing a Ruby regular expression to +like+ or +ilike+, or by making the regular expression a hash value:
531
+ Sequel also supports SQL regular expressions on MySQL and PostgreSQL (and SQLite when using the sqlite adapter with the :setup_regexp_function Database option). You can use these by passing a Ruby regular expression to +like+ or +ilike+, or by making the regular expression a hash value:
520
532
 
521
533
  Sequel.like(:name, /^A/) # ("name" ~ '^A')
522
534
  ~Sequel.ilike(:name, /^A/) # ("name" !~* '^A')
@@ -539,12 +551,12 @@ You can also use the <tt>Sequel.asc</tt> and <tt>Sequel.desc</tt> methods:
539
551
 
540
552
  On some databases, you can specify null ordering:
541
553
 
542
- Sequel.asc(:column, :nulls=>:first) # "column" ASC NULLS FIRST
543
- Sequel.desc(Sequel[:table][:column], :nulls=>:last) # "table"."column" DESC NULLS LAST
554
+ Sequel.asc(:column, nulls: :first) # "column" ASC NULLS FIRST
555
+ Sequel.desc(Sequel[:table][:column], nulls: :last) # "table"."column" DESC NULLS LAST
544
556
 
545
557
  === All Columns (.*)
546
558
 
547
- To select all columns in a table, Sequel supports the * method on identifiers and qualified without an argument:
559
+ To select all columns in a table, Sequel supports the * method on identifiers and qualified identifiers without an argument:
548
560
 
549
561
  Sequel[:table].* # "table".*
550
562
  Sequel[:schema][:table].* # "schema"."table".*
@@ -617,16 +629,16 @@ Also note that while the SELECT clause is displayed when you look at a dataset,
617
629
 
618
630
  ds = DB[:albums]
619
631
  ds.all # SELECT * FROM albums
620
- ds.insert(:name=>'RF') # INSERT INTO albums (name) VALUES ('RF')
621
- ds.update(:name=>'RF') # UPDATE albums SET name = 'RF'
632
+ ds.insert(name: 'RF') # INSERT INTO albums (name) VALUES ('RF')
633
+ ds.update(name: 'RF') # UPDATE albums SET name = 'RF'
622
634
  ds.delete # DELETE FROM albums
623
635
 
624
636
  In general, the +insert+, +update+, and +delete+ methods use the appropriate clauses you defined on the dataset:
625
637
 
626
- ds = DB[:albums].where(:id=>1)
638
+ ds = DB[:albums].where(id: 1)
627
639
  ds.all # SELECT * FROM albums WHERE (id = 1)
628
- ds.insert(:name=>'RF') # INSERT INTO albums (name) VALUES ('RF')
629
- ds.update(:name=>'RF') # UPDATE albums SET name = 'RF' WHERE (id = 1)
640
+ ds.insert(name: 'RF') # INSERT INTO albums (name) VALUES ('RF')
641
+ ds.update(name: 'RF') # UPDATE albums SET name = 'RF' WHERE (id = 1)
630
642
  ds.delete # DELETE FROM albums WHERE (id = 1)
631
643
 
632
644
  Note how +update+ and +delete+ used the +where+ argument, but +insert+ did not, because INSERT doesn't use a WHERE clause.
data/doc/testing.rdoc CHANGED
@@ -15,7 +15,7 @@ These run each test in its own transaction, the recommended way to test.
15
15
 
16
16
  class Minitest::HooksSpec
17
17
  def around
18
- DB.transaction(:rollback=>:always, :auto_savepoint=>true){super}
18
+ DB.transaction(rollback: :always, auto_savepoint: true){super}
19
19
  end
20
20
  end
21
21
 
@@ -24,7 +24,7 @@ These run each test in its own transaction, the recommended way to test.
24
24
 
25
25
  class Minitest::Spec
26
26
  def run(*args, &block)
27
- DB.transaction(:rollback=>:always, :auto_savepoint=>true){super}
27
+ DB.transaction(rollback: :always, auto_savepoint: true){super}
28
28
  end
29
29
  end
30
30
 
@@ -34,7 +34,7 @@ These run each test in its own transaction, the recommended way to test.
34
34
  # Use this class as the base class for your tests
35
35
  class SequelTestCase < Minitest::Test
36
36
  def run(*args, &block)
37
- DB.transaction(:rollback=>:always, :auto_savepoint=>true){super}
37
+ DB.transaction(rollback: :always, auto_savepoint: true){super}
38
38
  end
39
39
  end
40
40
 
@@ -43,7 +43,7 @@ These run each test in its own transaction, the recommended way to test.
43
43
 
44
44
  RSpec.configure do |c|
45
45
  c.around(:each) do |example|
46
- DB.transaction(:rollback=>:always, :auto_savepoint=>true){example.run}
46
+ DB.transaction(rollback: :always, auto_savepoint: true){example.run}
47
47
  end
48
48
  end
49
49
 
@@ -51,11 +51,11 @@ These run each test in its own transaction, the recommended way to test.
51
51
 
52
52
  You can use the Sequel.transaction method to run a transaction on multiple databases, rolling all of them back. Instead of:
53
53
 
54
- DB.transaction(:rollback=>:always)
54
+ DB.transaction(rollback: :always)
55
55
 
56
56
  Use Sequel.transaction with an array of databases:
57
57
 
58
- Sequel.transaction([DB1, DB2, DB3], :rollback=>:always)
58
+ Sequel.transaction([DB1, DB2, DB3], rollback: :always)
59
59
 
60
60
  == Transactional testing with savepoints
61
61
 
@@ -71,11 +71,11 @@ Example:
71
71
  require 'minitest/hooks/default'
72
72
  class Minitest::HooksSpec
73
73
  def around
74
- DB.transaction(:rollback=>:always, :savepoint=>true, :auto_savepoint=>true){super}
74
+ DB.transaction(rollback: :always, savepoint: true, auto_savepoint: true){super}
75
75
  end
76
76
 
77
77
  def around_all
78
- DB.transaction(:rollback=>:always){super}
78
+ DB.transaction(rollback: :always){super}
79
79
  end
80
80
  end
81
81
 
@@ -113,7 +113,7 @@ The order in which you delete/truncate the tables is important if you are using
113
113
 
114
114
  = Testing Sequel Itself
115
115
 
116
- Sequel has multiple separate test suites. All test suites use minitest/spec, with the minitest-hooks and minitest-shared_description extensions.
116
+ Sequel has multiple separate test suites. All test suites use minitest/spec, with the minitest-hooks and minitest-global_expectations extensions. To install the dependencies necessary to test Sequel, run <tt>gem install --development sequel</tt>.
117
117
 
118
118
  == rake
119
119
 
@@ -145,6 +145,8 @@ The <tt>spec_<i>adapter</i></tt> specs run against a real database connection wi
145
145
 
146
146
  These specs are broken down into two parts. For each database, there are specific specs that only apply to that database, and these are called the adapter specs. There are also shared specs that apply to all (or almost all) databases, these are called the integration specs. For database types that don't have specific adapter tests, you can use <tt>rake spec_integration</tt> to just run the shared integration tests.
147
147
 
148
+ Each adapter needs a specific gem installed in order to run. Please see the {connecting to a database guide}[rdoc-ref:doc/opening_databases.rdoc] for which gem you need to install for the adapter you are testing.
149
+
148
150
  == Environment variables
149
151
 
150
152
  Sequel uses environment variables when testing to specify either the database to be tested or specify how testing should be done. You can also specify the databases to test by copying <tt>spec/spec_config.rb.example</tt> to <tt>spec/spec_config.rb</tt> and modifying it. See that file for details. It may be necessary to use +spec_config.rb+ as opposed to an environment variable if your database connection cannot be specified by a connection string.
@@ -157,21 +159,30 @@ The SEQUEL_INTEGRATION_URL environment variable specifies the Database connectio
157
159
 
158
160
  === Other
159
161
 
162
+ SEQUEL_ASYNC_THREAD_POOL :: Use the async_thread_pool extension when running the specs
163
+ SEQUEL_ASYNC_THREAD_POOL_PREEMPT :: Use the async_thread_pool extension when running the specs, with the :preempt_async_thread option
164
+ SEQUEL_CHECK_PENDING :: Try running all specs (note, can cause lockups for some adapters), and raise errors for skipped specs that don't fail
160
165
  SEQUEL_COLUMNS_INTROSPECTION :: Use the columns_introspection extension when running the specs
166
+ SEQUEL_CONCURRENT_EAGER_LOADING :: Use the async_thread_pool extension and concurrent_eager_loading plugin when running the specs
161
167
  SEQUEL_CONNECTION_VALIDATOR :: Use the connection validator extension when running the specs
162
168
  SEQUEL_DUPLICATE_COLUMNS_HANDLER :: Use the duplicate columns handler extension with value given when running the specs
163
169
  SEQUEL_ERROR_SQL :: Use the error_sql extension when running the specs
164
- SEQUEL_INDEX_CACHING :: Use the index_caching extension when running the specs
165
170
  SEQUEL_FIBER_CONCURRENCY :: Use the fiber_concurrency extension when running the adapter and integration specs
166
171
  SEQUEL_FREEZE_DATABASE :: Freeze the database before running the integration specs
167
172
  SEQUEL_IDENTIFIER_MANGLING :: Use the identifier_mangling extension when running the specs
173
+ SEQUEL_INDEX_CACHING :: Use the index_caching extension when running the specs
168
174
  SEQUEL_INTEGER64 :: Use the integer64 extension when running the adapter or integration specs
169
175
  SEQUEL_MODEL_PREPARED_STATEMENTS :: Use the prepared_statements plugin when running the specs
170
176
  SEQUEL_MODEL_THROW_FAILURES :: Use the throw_failures plugin when running the specs
171
177
  SEQUEL_NO_CACHE_ASSOCIATIONS :: Don't cache association metadata when running the specs
172
- SEQUEL_CHECK_PENDING :: Try running all specs (note, can cause lockups for some adapters), and raise errors for skipped specs that don't fail
173
178
  SEQUEL_NO_PENDING :: Don't skip any specs, try running all specs (note, can cause lockups for some adapters)
179
+ SEQUEL_PG_AUTO_PARAMETERIZE :: Use the pg_auto_parameterize extension when running the postgres specs
174
180
  SEQUEL_PG_TIMESTAMPTZ :: Use the pg_timestamptz extension when running the postgres specs
181
+ SEQUEL_PRIMARY_KEY_LOOKUP_CHECK_VALUES :: Use the primary_key_lookup_check_values extension when running the adapter or integration specs
182
+ SEQUEL_QUERY_PER_ASSOCIATION_DB_0_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
183
+ SEQUEL_QUERY_PER_ASSOCIATION_DB_1_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
184
+ SEQUEL_QUERY_PER_ASSOCIATION_DB_2_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
185
+ SEQUEL_QUERY_PER_ASSOCIATION_DB_3_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
175
186
  SEQUEL_SPLIT_SYMBOLS :: Turn on symbol splitting when running the adapter and integration specs
176
187
  SEQUEL_SYNCHRONIZE_SQL :: Use the synchronize_sql extension when running the specs
177
188
  SEQUEL_TZINFO_VERSION :: Force the given tzinfo version when running the specs (e.g. '>=2')
@@ -127,28 +127,28 @@ Other exceptions, unless rescued inside the outer transaction block, will rollba
127
127
  end # ROLLBACK
128
128
  # ArgumentError raised
129
129
 
130
- If you want the current savepoint to be rolled back when the savepoint block exits instead of being committed (even if an exception is not raised), use <tt>Database#rollback_on_exit(:savepoint=>true)</tt>
130
+ If you want the current savepoint to be rolled back when the savepoint block exits instead of being committed (even if an exception is not raised), use <tt>Database#rollback_on_exit(savepoint: true)</tt>
131
131
 
132
132
  DB.transaction do # BEGIN
133
133
  DB.transaction(savepoint: true) do # SAVEPOINT
134
- DB.rollback_on_exit(:savepoint=>true)
134
+ DB.rollback_on_exit(savepoint: true)
135
135
  end # ROLLBACK TO SAVEPOINT
136
136
  end # COMMIT
137
137
 
138
138
  DB.transaction do # BEGIN
139
139
  DB.transaction(savepoint: true) do # SAVEPOINT
140
140
  DB.transaction(savepoint: true) do # SAVEPOINT
141
- DB.rollback_on_exit(:savepoint=>true)
141
+ DB.rollback_on_exit(savepoint: true)
142
142
  end # ROLLBACK TO SAVEPOINT
143
143
  end # RELEASE SAVEPOINT
144
144
  end # COMMIT
145
145
 
146
- If you want the current savepoint and potentially enclosing savepoints to be rolled back when the savepoint blocks exit (even if an exception is not raised), use <tt>Database#rollback_on_exit(:savepoint=>integer)</tt>
146
+ If you want the current savepoint and potentially enclosing savepoints to be rolled back when the savepoint blocks exit (even if an exception is not raised), use <tt>Database#rollback_on_exit(savepoint: integer)</tt>
147
147
 
148
148
  DB.transaction do # BEGIN
149
149
  DB.transaction(savepoint: true) do # SAVEPOINT
150
150
  DB.transaction(savepoint: true) do # SAVEPOINT
151
- DB.rollback_on_exit(:savepoint=>2)
151
+ DB.rollback_on_exit(savepoint: 2)
152
152
  end # ROLLBACK TO SAVEPOINT
153
153
  end # ROLLBACK TO SAVEPOINT
154
154
  end # COMMIT
@@ -156,7 +156,7 @@ If you want the current savepoint and potentially enclosing savepoints to be rol
156
156
  DB.transaction do # BEGIN
157
157
  DB.transaction(savepoint: true) do # SAVEPOINT
158
158
  DB.transaction(savepoint: true) do # SAVEPOINT
159
- DB.rollback_on_exit(:savepoint=>3)
159
+ DB.rollback_on_exit(savepoint: 3)
160
160
  end # ROLLBACK TO SAVEPOINT
161
161
  end # ROLLBACK TO SAVEPOINT
162
162
  end # ROLLBACK
@@ -23,7 +23,7 @@ With virtual rows, you can use the less verbose:
23
23
  Virtual row blocks behave differently depending on whether the block accepts
24
24
  an argument. If the block accepts an argument, it is called with an instance
25
25
  of Sequel::SQL::VirtualRow. If it does not accept an argument, it is
26
- evaluated in the context of an instance of Sequel::SQL::VirtualRow.
26
+ evaluated in the <em> context of an instance </em> of Sequel::SQL::VirtualRow.
27
27
 
28
28
  ds = DB[:items]
29
29
  # Regular block
@@ -54,7 +54,7 @@ methods in the surrounding scope. For example:
54
54
 
55
55
  # Regular block
56
56
  ds.where{|o| o.c > a - b + @d}
57
- # WHERE (c > 100)
57
+ # WHERE (c > 110)
58
58
 
59
59
  # Instance-evaled block
60
60
  ds.where{c > a - b + @d}
@@ -318,7 +318,7 @@ module Sequel
318
318
  conn.OpenSchema(ado_schema.type, ado_schema.criteria)
319
319
  end
320
320
  }
321
- yield(r) if block_given?
321
+ yield(r) if defined?(yield)
322
322
  rescue ::WIN32OLERuntimeError => e
323
323
  raise_error(e)
324
324
  end
@@ -161,7 +161,7 @@ module Sequel
161
161
  begin
162
162
  r = log_connection_yield(sql, conn){conn.Execute(sql)}
163
163
  begin
164
- yield r if block_given?
164
+ yield r if defined?(yield)
165
165
  ensure
166
166
  begin
167
167
  r.close
@@ -195,10 +195,25 @@ module Sequel
195
195
  end
196
196
 
197
197
  @conversion_procs = CONVERSION_PROCS.dup
198
+ @conversion_procs[AdDBTimeStamp] = method(:adb_timestamp_to_application_timestamp)
198
199
 
199
200
  super
200
201
  end
201
202
 
203
+ def adb_timestamp_to_application_timestamp(v)
204
+ # This hard codes a timestamp_precision of 6 when converting.
205
+ # That is the default timestamp_precision, but the ado/mssql adapter uses a timestamp_precision
206
+ # of 3. However, timestamps returned by ado/mssql have nsec values that end up rounding to a
207
+ # the same value as if a timestamp_precision of 3 was hard coded (either xxx999yzz, where y is
208
+ # 5-9 or xxx000yzz where y is 0-4).
209
+ #
210
+ # ADO subadapters should override this they would like a different timestamp precision and the
211
+ # this code does not work for them (for example, if they provide full nsec precision).
212
+ #
213
+ # Note that fractional second handling for WIN32OLE objects is not correct on ruby <2.2
214
+ to_application_timestamp([v.year, v.month, v.day, v.hour, v.min, v.sec, (v.nsec/1000.0).round * 1000])
215
+ end
216
+
202
217
  def dataset_class_default
203
218
  Dataset
204
219
  end
@@ -233,23 +248,8 @@ module Sequel
233
248
  cols = []
234
249
  conversion_procs = db.conversion_procs
235
250
 
236
- ts_cp = nil
237
251
  recordset.Fields.each do |field|
238
- type = field.Type
239
- cp = if type == AdDBTimeStamp
240
- ts_cp ||= begin
241
- nsec_div = 1000000000.0/(10**(timestamp_precision))
242
- nsec_mul = 10**(timestamp_precision+3)
243
- meth = db.method(:to_application_timestamp)
244
- lambda do |v|
245
- # Fractional second handling is not correct on ruby <2.2
246
- meth.call([v.year, v.month, v.day, v.hour, v.min, v.sec, (v.nsec/nsec_div).round * nsec_mul])
247
- end
248
- end
249
- else
250
- conversion_procs[type]
251
- end
252
- cols << [output_identifier(field.Name), cp]
252
+ cols << [output_identifier(field.Name), conversion_procs[field.Type]]
253
253
  end
254
254
 
255
255
  self.columns = cols.map(&:first)
@@ -118,11 +118,9 @@ module Sequel
118
118
  # Yield an available connection. Rescue
119
119
  # any Amalgalite::Errors and turn them into DatabaseErrors.
120
120
  def _execute(sql, opts)
121
- begin
122
- synchronize(opts[:server]){|conn| yield conn}
123
- rescue ::Amalgalite::Error, ::Amalgalite::SQLite3::Error => e
124
- raise_error(e)
125
- end
121
+ synchronize(opts[:server]){|conn| yield conn}
122
+ rescue ::Amalgalite::Error, ::Amalgalite::SQLite3::Error => e
123
+ raise_error(e)
126
124
  end
127
125
 
128
126
  # The Amagalite adapter does not need the pool to convert exceptions.
@@ -246,7 +246,7 @@ module Sequel
246
246
  end
247
247
  begin
248
248
  stmt = log_connection_yield(log_sql, conn, args){conn.execute_prepared(ps_name, *args)}
249
- if block_given?
249
+ if defined?(yield)
250
250
  yield(stmt)
251
251
  else
252
252
  stmt.affected
@@ -268,7 +268,7 @@ module Sequel
268
268
  # is given or returning the number of affected rows if not, and ensuring the statement is freed.
269
269
  def _execute(conn, sql, opts)
270
270
  stmt = log_connection_yield(sql, conn){conn.execute(sql)}
271
- if block_given?
271
+ if defined?(yield)
272
272
  yield(stmt)
273
273
  else
274
274
  stmt.affected
@@ -2,6 +2,7 @@
2
2
 
3
3
  Sequel::JDBC.load_driver('org.apache.derby.jdbc.EmbeddedDriver', :Derby)
4
4
  require_relative 'transactions'
5
+ require_relative '../utils/columns_limit_1'
5
6
 
6
7
  module Sequel
7
8
  module JDBC
@@ -182,6 +183,8 @@ module Sequel
182
183
  end
183
184
 
184
185
  class Dataset < JDBC::Dataset
186
+ include ::Sequel::Dataset::ColumnsLimit1
187
+
185
188
  # Derby doesn't support an expression between CASE and WHEN,
186
189
  # so remove conditions.
187
190
  def case_expression_sql_append(sql, ce)
@@ -232,6 +235,11 @@ module Sequel
232
235
  false
233
236
  end
234
237
 
238
+ # Derby 10.11+ supports MERGE.
239
+ def supports_merge?
240
+ db.svn_version >= 1616546
241
+ end
242
+
235
243
  # Derby does not support IN/NOT IN with multiple columns
236
244
  def supports_multiple_column_in?
237
245
  false
@@ -24,6 +24,7 @@ module Sequel
24
24
 
25
25
  def freeze
26
26
  h2_version
27
+ version2?
27
28
  super
28
29
  end
29
30
 
@@ -140,13 +141,36 @@ module Sequel
140
141
  DATABASE_ERROR_REGEXPS
141
142
  end
142
143
 
143
- # Use IDENTITY() to get the last inserted id.
144
+ def execute_statement_insert(stmt, sql)
145
+ stmt.executeUpdate(sql, JavaSQL::Statement::RETURN_GENERATED_KEYS)
146
+ end
147
+
148
+ def prepare_jdbc_statement(conn, sql, opts)
149
+ opts[:type] == :insert ? conn.prepareStatement(sql, JavaSQL::Statement::RETURN_GENERATED_KEYS) : super
150
+ end
151
+
152
+ # Get the last inserted id using getGeneratedKeys, scope_identity, or identity.
144
153
  def last_insert_id(conn, opts=OPTS)
145
- statement(conn) do |stmt|
146
- sql = 'SELECT IDENTITY();'
147
- rs = log_connection_yield(sql, conn){stmt.executeQuery(sql)}
148
- rs.next
149
- rs.getLong(1)
154
+ if stmt = opts[:stmt]
155
+ rs = stmt.getGeneratedKeys
156
+ begin
157
+ if rs.next
158
+ begin
159
+ rs.getLong(1)
160
+ rescue
161
+ rs.getObject(1) rescue nil
162
+ end
163
+ end
164
+ ensure
165
+ rs.close
166
+ end
167
+ elsif !version2?
168
+ statement(conn) do |stmt|
169
+ sql = 'SELECT IDENTITY()'
170
+ rs = log_connection_yield(sql, conn){stmt.executeQuery(sql)}
171
+ rs.next
172
+ rs.getLong(1)
173
+ end
150
174
  end
151
175
  end
152
176
 
@@ -161,7 +185,12 @@ module Sequel
161
185
 
162
186
  # Use BIGINT IDENTITY for identity columns that use :Bignum type
163
187
  def type_literal_generic_bignum_symbol(column)
164
- column[:identity] ? 'BIGINT IDENTITY' : super
188
+ column[:identity] ? 'BIGINT AUTO_INCREMENT' : super
189
+ end
190
+
191
+ def version2?
192
+ return @version2 if defined?(@version2)
193
+ @version2 = h2_version.to_i >= 2
165
194
  end
166
195
  end
167
196
 
@@ -200,6 +229,11 @@ module Sequel
200
229
  false
201
230
  end
202
231
 
232
+ # H2 supports MERGE
233
+ def supports_merge?
234
+ true
235
+ end
236
+
203
237
  # H2 doesn't support multiple columns in IN/NOT IN
204
238
  def supports_multiple_column_in?
205
239
  false
@@ -209,9 +243,21 @@ module Sequel
209
243
 
210
244
  # H2 expects hexadecimal strings for blob values
211
245
  def literal_blob_append(sql, v)
212
- sql << "'" << v.unpack("H*").first << "'"
246
+ if db.send(:version2?)
247
+ super
248
+ else
249
+ sql << "'" << v.unpack("H*").first << "'"
250
+ end
251
+ end
252
+
253
+ def literal_false
254
+ 'FALSE'
213
255
  end
214
256
 
257
+ def literal_true
258
+ 'TRUE'
259
+ end
260
+
215
261
  # H2 handles fractional seconds in timestamps, but not in times
216
262
  def literal_sqltime(v)
217
263
  v.strftime("'%H:%M:%S'")
@@ -223,8 +269,12 @@ module Sequel
223
269
  end
224
270
 
225
271
  def select_only_offset_sql(sql)
226
- sql << " LIMIT -1 OFFSET "
227
- literal_append(sql, @opts[:offset])
272
+ if db.send(:version2?)
273
+ super
274
+ else
275
+ sql << " LIMIT -1 OFFSET "
276
+ literal_append(sql, @opts[:offset])
277
+ end
228
278
  end
229
279
 
230
280
  # H2 supports quoted function names.
@@ -179,6 +179,12 @@ module Sequel
179
179
  true
180
180
  end
181
181
 
182
+ # HSQLDB 2.3.4+ supports MERGE. Older versions also support MERGE, but not all
183
+ # features that are in Sequel's tests.
184
+ def supports_merge?
185
+ db.db_version >= 20304
186
+ end
187
+
182
188
  private
183
189
 
184
190
  def empty_from_sql
@@ -35,9 +35,9 @@ module Sequel
35
35
  data = opts[:data]
36
36
  data = Array(data) if data.is_a?(String)
37
37
 
38
- if block_given? && data
38
+ if defined?(yield) && data
39
39
  raise Error, "Cannot provide both a :data option and a block to copy_into"
40
- elsif !block_given? && !data
40
+ elsif !defined?(yield) && !data
41
41
  raise Error, "Must provide either a :data option or a block to copy_into"
42
42
  end
43
43
 
@@ -45,7 +45,7 @@ module Sequel
45
45
  begin
46
46
  copy_manager = org.postgresql.copy.CopyManager.new(conn)
47
47
  copier = copy_manager.copy_in(copy_into_sql(table, opts))
48
- if block_given?
48
+ if defined?(yield)
49
49
  while buf = yield
50
50
  java_bytes = buf.to_java_bytes
51
51
  copier.writeToCopy(java_bytes, 0, java_bytes.length)
@@ -77,7 +77,7 @@ module Sequel
77
77
  copy_manager = org.postgresql.copy.CopyManager.new(conn)
78
78
  copier = copy_manager.copy_out(copy_table_sql(table, opts))
79
79
  begin
80
- if block_given?
80
+ if defined?(yield)
81
81
  while buf = copier.readFromCopy
82
82
  yield(String.from_java_bytes(buf))
83
83
  end