sequel 5.39.0 → 5.63.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +308 -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 +89 -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/schema_modification.rdoc +1 -1
  40. data/doc/security.rdoc +9 -9
  41. data/doc/sql.rdoc +27 -15
  42. data/doc/testing.rdoc +22 -11
  43. data/doc/transactions.rdoc +6 -6
  44. data/doc/virtual_rows.rdoc +2 -2
  45. data/lib/sequel/adapters/ado/access.rb +1 -1
  46. data/lib/sequel/adapters/ado.rb +17 -17
  47. data/lib/sequel/adapters/amalgalite.rb +3 -5
  48. data/lib/sequel/adapters/ibmdb.rb +2 -2
  49. data/lib/sequel/adapters/jdbc/derby.rb +8 -0
  50. data/lib/sequel/adapters/jdbc/h2.rb +60 -10
  51. data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +4 -4
  53. data/lib/sequel/adapters/jdbc.rb +16 -18
  54. data/lib/sequel/adapters/mysql.rb +80 -67
  55. data/lib/sequel/adapters/mysql2.rb +54 -49
  56. data/lib/sequel/adapters/odbc.rb +6 -2
  57. data/lib/sequel/adapters/oracle.rb +3 -3
  58. data/lib/sequel/adapters/postgres.rb +83 -40
  59. data/lib/sequel/adapters/shared/access.rb +11 -1
  60. data/lib/sequel/adapters/shared/db2.rb +30 -0
  61. data/lib/sequel/adapters/shared/mssql.rb +58 -7
  62. data/lib/sequel/adapters/shared/mysql.rb +40 -2
  63. data/lib/sequel/adapters/shared/oracle.rb +76 -0
  64. data/lib/sequel/adapters/shared/postgres.rb +418 -174
  65. data/lib/sequel/adapters/shared/sqlanywhere.rb +10 -0
  66. data/lib/sequel/adapters/shared/sqlite.rb +102 -11
  67. data/lib/sequel/adapters/sqlanywhere.rb +1 -1
  68. data/lib/sequel/adapters/sqlite.rb +60 -18
  69. data/lib/sequel/adapters/tinytds.rb +1 -1
  70. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  71. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  72. data/lib/sequel/ast_transformer.rb +6 -0
  73. data/lib/sequel/connection_pool/sharded_single.rb +5 -7
  74. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
  75. data/lib/sequel/connection_pool/single.rb +6 -8
  76. data/lib/sequel/connection_pool/threaded.rb +8 -8
  77. data/lib/sequel/connection_pool/timed_queue.rb +257 -0
  78. data/lib/sequel/connection_pool.rb +47 -30
  79. data/lib/sequel/core.rb +28 -18
  80. data/lib/sequel/database/connecting.rb +26 -2
  81. data/lib/sequel/database/misc.rb +69 -14
  82. data/lib/sequel/database/query.rb +38 -1
  83. data/lib/sequel/database/schema_generator.rb +45 -52
  84. data/lib/sequel/database/schema_methods.rb +17 -1
  85. data/lib/sequel/dataset/actions.rb +107 -13
  86. data/lib/sequel/dataset/features.rb +20 -0
  87. data/lib/sequel/dataset/misc.rb +1 -1
  88. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  89. data/lib/sequel/dataset/query.rb +118 -16
  90. data/lib/sequel/dataset/sql.rb +177 -47
  91. data/lib/sequel/extensions/_model_pg_row.rb +0 -12
  92. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  93. data/lib/sequel/extensions/any_not_empty.rb +1 -1
  94. data/lib/sequel/extensions/async_thread_pool.rb +438 -0
  95. data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
  96. data/lib/sequel/extensions/blank.rb +8 -0
  97. data/lib/sequel/extensions/constraint_validations.rb +1 -1
  98. data/lib/sequel/extensions/core_refinements.rb +36 -11
  99. data/lib/sequel/extensions/date_arithmetic.rb +71 -31
  100. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  101. data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
  102. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
  103. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  104. data/lib/sequel/extensions/inflector.rb +9 -1
  105. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  106. data/lib/sequel/extensions/looser_typecasting.rb +3 -0
  107. data/lib/sequel/extensions/migration.rb +7 -2
  108. data/lib/sequel/extensions/named_timezones.rb +26 -6
  109. data/lib/sequel/extensions/pagination.rb +1 -1
  110. data/lib/sequel/extensions/pg_array.rb +23 -3
  111. data/lib/sequel/extensions/pg_array_ops.rb +2 -2
  112. data/lib/sequel/extensions/pg_auto_parameterize.rb +478 -0
  113. data/lib/sequel/extensions/pg_enum.rb +1 -1
  114. data/lib/sequel/extensions/pg_extended_date_support.rb +28 -25
  115. data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
  116. data/lib/sequel/extensions/pg_hstore.rb +6 -1
  117. data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
  118. data/lib/sequel/extensions/pg_inet.rb +10 -11
  119. data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
  120. data/lib/sequel/extensions/pg_interval.rb +45 -19
  121. data/lib/sequel/extensions/pg_json.rb +13 -15
  122. data/lib/sequel/extensions/pg_json_ops.rb +73 -2
  123. data/lib/sequel/extensions/pg_loose_count.rb +3 -1
  124. data/lib/sequel/extensions/pg_multirange.rb +367 -0
  125. data/lib/sequel/extensions/pg_range.rb +10 -23
  126. data/lib/sequel/extensions/pg_range_ops.rb +37 -9
  127. data/lib/sequel/extensions/pg_row.rb +19 -13
  128. data/lib/sequel/extensions/pg_row_ops.rb +1 -1
  129. data/lib/sequel/extensions/query.rb +2 -0
  130. data/lib/sequel/extensions/s.rb +2 -1
  131. data/lib/sequel/extensions/schema_dumper.rb +13 -2
  132. data/lib/sequel/extensions/server_block.rb +8 -12
  133. data/lib/sequel/extensions/sql_comments.rb +110 -3
  134. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  135. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  136. data/lib/sequel/extensions/string_agg.rb +1 -1
  137. data/lib/sequel/extensions/string_date_time.rb +19 -23
  138. data/lib/sequel/extensions/symbol_aref.rb +2 -0
  139. data/lib/sequel/model/associations.rb +325 -96
  140. data/lib/sequel/model/base.rb +51 -27
  141. data/lib/sequel/model/errors.rb +10 -1
  142. data/lib/sequel/model/inflections.rb +1 -1
  143. data/lib/sequel/model/plugins.rb +5 -0
  144. data/lib/sequel/plugins/association_proxies.rb +2 -0
  145. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  146. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  147. data/lib/sequel/plugins/auto_validations.rb +87 -15
  148. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  149. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  150. data/lib/sequel/plugins/column_encryption.rb +728 -0
  151. data/lib/sequel/plugins/composition.rb +10 -4
  152. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  153. data/lib/sequel/plugins/constraint_validations.rb +2 -1
  154. data/lib/sequel/plugins/dataset_associations.rb +4 -1
  155. data/lib/sequel/plugins/dirty.rb +1 -1
  156. data/lib/sequel/plugins/enum.rb +124 -0
  157. data/lib/sequel/plugins/finder.rb +3 -1
  158. data/lib/sequel/plugins/insert_conflict.rb +4 -0
  159. data/lib/sequel/plugins/instance_specific_default.rb +1 -1
  160. data/lib/sequel/plugins/json_serializer.rb +39 -24
  161. data/lib/sequel/plugins/lazy_attributes.rb +3 -0
  162. data/lib/sequel/plugins/list.rb +3 -1
  163. data/lib/sequel/plugins/many_through_many.rb +108 -9
  164. data/lib/sequel/plugins/nested_attributes.rb +12 -7
  165. data/lib/sequel/plugins/pg_array_associations.rb +56 -38
  166. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +3 -1
  167. data/lib/sequel/plugins/prepared_statements.rb +10 -1
  168. data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
  169. data/lib/sequel/plugins/rcte_tree.rb +27 -19
  170. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  171. data/lib/sequel/plugins/serialization.rb +9 -3
  172. data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
  173. data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
  174. data/lib/sequel/plugins/sql_comments.rb +189 -0
  175. data/lib/sequel/plugins/static_cache.rb +1 -1
  176. data/lib/sequel/plugins/subclasses.rb +28 -11
  177. data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
  178. data/lib/sequel/plugins/timestamps.rb +1 -1
  179. data/lib/sequel/plugins/unused_associations.rb +521 -0
  180. data/lib/sequel/plugins/update_or_create.rb +1 -1
  181. data/lib/sequel/plugins/validate_associated.rb +22 -12
  182. data/lib/sequel/plugins/validation_helpers.rb +38 -11
  183. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  184. data/lib/sequel/sql.rb +1 -1
  185. data/lib/sequel/timezones.rb +12 -14
  186. data/lib/sequel/version.rb +1 -1
  187. metadata +97 -43
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
@@ -32,15 +32,13 @@ module Sequel
32
32
 
33
33
  # Allow loading the necessary JDBC support via a gem.
34
34
  def self.load_gem(name)
35
- begin
36
- require "jdbc/#{name.to_s.downcase}"
37
- rescue LoadError
38
- # jdbc gem not used, hopefully the user has the .jar in their CLASSPATH
39
- else
40
- if defined?(::Jdbc) && ( ::Jdbc.const_defined?(name) rescue nil )
41
- jdbc_module = ::Jdbc.const_get(name) # e.g. Jdbc::SQLite3
42
- jdbc_module.load_driver if jdbc_module.respond_to?(:load_driver)
43
- end
35
+ require "jdbc/#{name.to_s.downcase}"
36
+ rescue LoadError
37
+ # jdbc gem not used, hopefully the user has the .jar in their CLASSPATH
38
+ else
39
+ if defined?(::Jdbc) && ( ::Jdbc.const_defined?(name) rescue nil )
40
+ jdbc_module = ::Jdbc.const_get(name) # e.g. Jdbc::SQLite3
41
+ jdbc_module.load_driver if jdbc_module.respond_to?(:load_driver)
44
42
  end
45
43
  end
46
44
 
@@ -71,11 +69,11 @@ module Sequel
71
69
  class TypeConvertor
72
70
  CONVERTORS = convertors = {}
73
71
  %w'Boolean Float Double Int Long Short'.each do |meth|
74
- x = convertors[meth.to_sym] = Object.new
72
+ x = x = convertors[meth.to_sym] = Object.new
75
73
  class_eval("def x.call(r, i) v = r.get#{meth}(i); v unless r.wasNull end", __FILE__, __LINE__)
76
74
  end
77
75
  %w'Object Array String Time Date Timestamp BigDecimal Blob Bytes Clob'.each do |meth|
78
- x = convertors[meth.to_sym] = Object.new
76
+ x = x = convertors[meth.to_sym] = Object.new
79
77
  class_eval("def x.call(r, i) r.get#{meth}(i) end", __FILE__, __LINE__)
80
78
  end
81
79
  x = convertors[:RubyTime] = Object.new
@@ -190,13 +188,13 @@ module Sequel
190
188
  args = opts[:args] || []
191
189
  sql = "{call #{name}(#{args.map{'?'}.join(',')})}"
192
190
  synchronize(opts[:server]) do |conn|
193
- cps = conn.prepareCall(sql)
191
+ begin
192
+ cps = conn.prepareCall(sql)
194
193
 
195
- i = 0
196
- args.each{|arg| set_ps_arg(cps, arg, i+=1)}
194
+ i = 0
195
+ args.each{|arg| set_ps_arg(cps, arg, i+=1)}
197
196
 
198
- begin
199
- if block_given?
197
+ if defined?(yield)
200
198
  yield log_connection_yield(sql, conn){cps.executeQuery}
201
199
  else
202
200
  log_connection_yield(sql, conn){cps.executeUpdate}
@@ -207,7 +205,7 @@ module Sequel
207
205
  rescue *DATABASE_ERROR_CLASSES => e
208
206
  raise_error(e)
209
207
  ensure
210
- cps.close
208
+ cps.close if cps
211
209
  end
212
210
  end
213
211
  end
@@ -461,7 +459,7 @@ module Sequel
461
459
  msg << ")"
462
460
  end
463
461
  begin
464
- if block_given?
462
+ if defined?(yield)
465
463
  yield log_connection_yield(msg, conn, args){cps.executeQuery}
466
464
  else
467
465
  case opts[:type]