sequel 5.75.0 → 5.77.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +48 -0
  3. data/doc/opening_databases.rdoc +4 -2
  4. data/doc/release_notes/5.76.0.txt +86 -0
  5. data/doc/release_notes/5.77.0.txt +63 -0
  6. data/doc/testing.rdoc +3 -1
  7. data/lib/sequel/adapters/jdbc/h2.rb +3 -0
  8. data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -0
  9. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +11 -0
  10. data/lib/sequel/adapters/mysql2.rb +2 -2
  11. data/lib/sequel/adapters/odbc/mssql.rb +1 -1
  12. data/lib/sequel/adapters/postgres.rb +2 -2
  13. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  14. data/lib/sequel/adapters/shared/mysql.rb +10 -0
  15. data/lib/sequel/adapters/shared/oracle.rb +4 -6
  16. data/lib/sequel/adapters/shared/postgres.rb +22 -1
  17. data/lib/sequel/adapters/shared/sqlanywhere.rb +10 -4
  18. data/lib/sequel/adapters/shared/sqlite.rb +20 -2
  19. data/lib/sequel/adapters/sqlite.rb +42 -3
  20. data/lib/sequel/connection_pool.rb +4 -2
  21. data/lib/sequel/database/misc.rb +2 -2
  22. data/lib/sequel/database/schema_methods.rb +6 -0
  23. data/lib/sequel/dataset/features.rb +10 -1
  24. data/lib/sequel/dataset/sql.rb +47 -34
  25. data/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
  26. data/lib/sequel/extensions/duplicate_columns_handler.rb +10 -9
  27. data/lib/sequel/extensions/named_timezones.rb +1 -1
  28. data/lib/sequel/extensions/pg_array.rb +2 -0
  29. data/lib/sequel/extensions/pg_extended_date_support.rb +4 -4
  30. data/lib/sequel/extensions/pg_range.rb +2 -2
  31. data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
  32. data/lib/sequel/extensions/round_timestamps.rb +1 -1
  33. data/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
  34. data/lib/sequel/model/associations.rb +9 -2
  35. data/lib/sequel/model/base.rb +5 -2
  36. data/lib/sequel/plugins/list.rb +5 -2
  37. data/lib/sequel/plugins/rcte_tree.rb +7 -4
  38. data/lib/sequel/plugins/validation_helpers.rb +1 -1
  39. data/lib/sequel/version.rb +1 -1
  40. metadata +9 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3047129164c9cdffee31414419904329e410db71e7e4243c0549614498a2b0d4
4
- data.tar.gz: 9cc84ed8e9dba53aac7175be04699089932566e4015aed7a465c43552808c8b4
3
+ metadata.gz: 9951772dd3785c8ce91090bd31034a1e57ac5dcbc17af774b980a115cea15347
4
+ data.tar.gz: 3cfcaefaf6aa4758ef2cfaf78cbe6ccdc688e8b3836718bd63c42c5bdb220026
5
5
  SHA512:
6
- metadata.gz: 15ed5c13e4793191546cd452aa5865e65fd7b3bb0458ffdb674d526398b7c9446e2da0f43a339daa3f1dc256eb551f0b773ac9ffc192b4d19f389d0c7e296d98
7
- data.tar.gz: 1f25851b50857fbbf8378216794f26d0d8e9baa247f008feac466a218ae6b0777249252b6d05756e075096c5312b9d3b1334b7c4bc1884251e7b892cc17ae7c6
6
+ metadata.gz: '0885577c11fd7285a5278d0a1b52ae411e557cec7bce2f3a49f8128a0be63928ebfa55b2b1a86c8b28ee1c3782c1dc5ebf5d4ecf00f0194ad33da89cb6ffc12a'
7
+ data.tar.gz: ccc7b8b6c68049ee1fed2211a3d193157ee36fde9c340324eba2a8cebd8925bc97b4dc1777b61f8a2fb94d83439c41f33afb832c080f4d54bab16d09924a4fe2
data/CHANGELOG CHANGED
@@ -1,3 +1,51 @@
1
+ === 5.77.0 (2024-02-01)
2
+
3
+ * Support create_table :without_rowid option on SQLite (loranger32) (#2126)
4
+
5
+ * Warn by default if trying to eager_graph/association_join an association that uses a block, when the block would be ignored (jeremyevans)
6
+
7
+ * Speed up validates_unique in validation_helpers plugin by using empty? instead of count == 0 (numbata) (#2122)
8
+
9
+ * Speed up regexp matches in sqlite adapter on Ruby 2.4+ (jeremyevans)
10
+
11
+ * Add sqlite adapter :regexp_function_cache option for specifying the cache object to use (paddor, jeremyevans) (#2116)
12
+
13
+ * Respect list plugin :top option when inserting the first row into the model's table (johanmagnusson) (#2115)
14
+
15
+ * Switch default connection pool to timed_queue on Ruby 3.4+ (jeremyevans)
16
+
17
+ * Support on_duplicate_columns={raise,warn} parameter in connection URL when using duplicate_columns_handler extension (jeremyevans)
18
+
19
+ * Add transaction_connection_validator extension for retrying transactions on new connection if ther is a disconnect error when starting transaction (jeremyevans)
20
+
21
+ === 5.76.0 (2024-01-01)
22
+
23
+ * Improve performance and flexibility of regexp matching in sqlite adapter (paddor) (#2108)
24
+
25
+ * Support SQL::Identifier for Database#tables :schema option values on PostgreSQL (jeremyevans)
26
+
27
+ * Support generating rcte queries using UNION or UNION ALL in the rcte plugin (jonathanfrias) (#2107)
28
+
29
+ * Make Database#table_exists? on PostgreSQL handle lock or statement timeout errors as evidence the table exists (jeremyevans) (#2106)
30
+
31
+ * Work around DateTime.jd fractional second bug on JRuby in named_timezones extension (jeremyevans)
32
+
33
+ * Support fractional times and timestamps on SQLAnywhere (jeremyevans)
34
+
35
+ * Make round_timestamps extension use Dataset#sqltime_precision for rounding Sequel::SQLTime values (jeremyevans)
36
+
37
+ * Remove special handling of %N modifier in Dataset#default_timestamp_format (jeremyevans)
38
+
39
+ * Add Dataset#default_time_format private method, for adapters to override for time (not timestamp) formatting (jeremyevans)
40
+
41
+ * Remove Dataset#format_timestamp_offset private method (jeremyevans)
42
+
43
+ * Remove special handling of %z modifier in Dataset#default_timestamp_format (jeremyevans)
44
+
45
+ * Add Dataset#literal_date_or_time, for simpler use by bound argument code (jeremyevans)
46
+
47
+ * Add auto_cast_date_and_time extension, for casting date and time values using SQL standard functions (jeremyevans)
48
+
1
49
  === 5.75.0 (2023-12-01)
2
50
 
3
51
  * Make any_not_empty? extension support passing pattern argument to any? (jeremyevans) (#2100)
@@ -388,8 +388,10 @@ The following additional options are supported:
388
388
  :readonly :: open database in read-only mode
389
389
  :timeout :: the busy timeout to use in milliseconds (default: 5000).
390
390
  :setup_regexp_function :: Whether to setup a REGEXP function in the underlying SQLite3::Database object. Doing so
391
- allows you to use regexp support in dataset expressions. Note that this creates a new
392
- Regexp object per call to the function, so it is not an efficient implementation.
391
+ allows you to use regexp support in dataset expressions. If +:cached+ or <tt>"cached"</tt>+, caches each
392
+ unique regex (more efficient but risk of memory leak). If a Proc is provided, it will be called with
393
+ a string for the regexp and a string for the value to compare, and should return whether the regexp
394
+ string matches the string value to compare. The default Proc used does <tt>Regexp.new(regexp_str).match(str)</tt>.
393
395
 
394
396
  Note that SQLite memory databases are restricted to a single connection by
395
397
  default. This is because SQLite does not allow multiple connections to
@@ -0,0 +1,86 @@
1
+ = New Features
2
+
3
+ * An auto_cast_date_and_time extension has been added, which will
4
+ automatically cast date and time values using SQL standard functions.
5
+ This makes sure the database will treat the value as a date, time,
6
+ or timestamp, instead of treating it as a string or unknown type:
7
+
8
+ DB.get(Date.today).class
9
+ # SELECT '2024-01-01' AS v LIMIT 1
10
+ String
11
+
12
+ DB.extension(:auto_cast_date_and_time)
13
+ DB.get(Date.today).class
14
+ # SELECT DATE '2024-01-01' AS v LIMIT 1
15
+ Date
16
+
17
+ This was already Sequel's default behavior on adapters that required
18
+ it. This extension is usable on PostgreSQL and MySQL. It is not
19
+ usable on SQLite (no date/time types) or Microsoft SQL Server (no
20
+ support for the SQL standard conversion syntax).
21
+
22
+ This extension can break code that currently works. If using it on
23
+ PostgreSQL, it will cast the values to TIMESTAMP, not TIMESTAMP
24
+ WITH TIME ZONE, which can break code that depended on an implicit
25
+ conversion to TIMESTAMP WITH TIME ZONE. The pg_timestamptz
26
+ extension integrates with the the auto_cast_date_and_time extension
27
+ and will implicitly cast Time/DateTime to TIMESTAMP WITH TIME ZONE.
28
+
29
+ * The sqlite adapter now supports a :cached value for the
30
+ :setup_regexp_function Database option, which will cache regexp
31
+ values instead of creating a new regexp per value to compare. This
32
+ is much faster when using a regexp comparison on a large dataset,
33
+ but can result in a memory leak if using dynamic regexps. You can
34
+ also provide a Proc value for the :setup_regexp_function option,
35
+ which will be passed both the regexp source string and the database
36
+ string to compare, and should return whether the database string
37
+ matches the regexp string.
38
+
39
+ * The rcte_tree plugin now supports a :union_all option, which can
40
+ be set to false to use UNION instead of UNION ALL in the recursive
41
+ common table expression.
42
+
43
+ = Other Improvements
44
+
45
+ * Time/DateTime/SQLTime literalization speed has more than doubled
46
+ compared to the previous version. The internal code is also much
47
+ simpler, as the speedup resulted from removing multiple abstraction
48
+ layers that mostly existed for Ruby 1.8 support.
49
+
50
+ * Database#table_exists? on PostgreSQL now handles lock or statement
51
+ timeout errors as evidence the table exists.
52
+
53
+ * The round_timestamps extension now correctly rounds SQLTime values
54
+ on Microsoft SQL Server (the only database Sequel supports where
55
+ time precision is different than timestamp precision).
56
+
57
+ * Fractional times and timestamps are now supported on SQLAnywhere,
58
+ except for time values when using the jdbc adapter due to a
59
+ limitation in the JDBC sqlanywhere driver.
60
+
61
+ * Database#tables and #views on PostgreSQL now supports
62
+ SQL::Identifier values for the :schema option.
63
+
64
+ * The named_timezones extension now works around a bug in DateTime.jd
65
+ on JRuby.
66
+
67
+ = Backwards Compatibility
68
+
69
+ * Time/DateTime/SQLTime literalization internals have changed.
70
+ If you are using an external adapter and the external adapter
71
+ overrides or calls any of the following methods:
72
+
73
+ * requires_sql_standard_datetimes?
74
+ * supports_timestamp_usecs?
75
+ * supports_timestamp_timezones?
76
+ * timestamp_precision
77
+ * sqltime_precision
78
+
79
+ then the adapter may need to be updated to support Sequel 5.76.0.
80
+ Additionally, if the adapter uses %N or %z in
81
+ default_timestamp_format, it may need to be updated. Adapters
82
+ should now just override default_timestamp_format and/or
83
+ default_time_format methods as appropriate for the database.
84
+
85
+ * The Dataset#format_timestamp_offset private method has been
86
+ removed.
@@ -0,0 +1,63 @@
1
+ = New Features
2
+
3
+ * A transaction_connection_validator extension has been added. This
4
+ extension allows for transparently switching to a new connection if
5
+ a disconnect error is raised while trying to start a transaction, as
6
+ long as a connection was not already checked out from the pool
7
+ when the transaction method was called. Transparent reconnection
8
+ is safe in this case, since no user code is retried.
9
+
10
+ This extension can have lower overhead than the
11
+ connection_validator extension if that is configured to check for
12
+ validity more often than the default of one hour. However, it
13
+ only handles cases where transactions are used. It can detect
14
+ disconnects that would not be detected by default with the
15
+ connection_validator extension, since that extension defaults to
16
+ only checking validity if the connection has not been used in the
17
+ last hour.
18
+
19
+ * Sequel now supports a create_table :without_rowid option on SQLite,
20
+ to create a table WITHOUT ROWID, for better performance in some
21
+ cases. Users are encouraged to read the SQLite documentation on
22
+ WITHOUT ROWID before using this option.
23
+
24
+ * The sqlite adapter now supports a :regexp_function_cache option, if
25
+ the :setup_regexp_function option is set to :cached. The
26
+ :regexp_function_cache option should be a Proc (returning a cache
27
+ object to use), or a class. It's possible to use
28
+ ObjectSpace::WeakKeyMap as the value of the option on Ruby 3.3+
29
+ to avoid the memory leaks that are possible when using
30
+ :setup_regexp_function option :cached value with dynamic regexps.
31
+
32
+ * The duplicate_columns_handler extension now supports specifying
33
+ the on_duplicate_columns option as a connection string parameter.
34
+
35
+ = Other Improvements
36
+
37
+ * The list plugin now honors the :top option for the position when
38
+ adding the first item to the list, instead of always using 1.
39
+
40
+ * Regexp matches on SQLite are now faster on Ruby 2.4+, using
41
+ Regexp#match?.
42
+
43
+ * The uniqueness validation in the validation_helpers plugin now
44
+ uses empty? instead of count == 0, for better performance.
45
+
46
+ * On Ruby 3.4+, Sequel uses the timed_queue connection pool instead
47
+ of the threaded connection pool by default. This should make it
48
+ so no existing applications are affected by the default switch.
49
+ This should hopefully allow ample testing of the timed_queue
50
+ connection pool. At some point in the future, if no problems
51
+ are repoted, Sequel will likely switch to using the timed_queue
52
+ connection pool by default on Ruby 3.2+.
53
+
54
+ = Backwards Compatibility
55
+
56
+ * Sequel now warns by default if using eager_graph/association_join
57
+ with an association that uses a block, in the cases where the
58
+ block would be ignored and there are no appropriate graph options
59
+ set. In Sequel 6, this warning will be turned into an exception.
60
+ It is recommended that users use the auto_restrict_eager_graph
61
+ plugin to turn this into an exception now, or use the
62
+ :graph_use_association_block option so that the block is not
63
+ ignored when graphing.
data/doc/testing.rdoc CHANGED
@@ -159,12 +159,13 @@ The SEQUEL_INTEGRATION_URL environment variable specifies the Database connectio
159
159
 
160
160
  === Other
161
161
 
162
+ SEQUEL_AUTO_CAST_DATE_TIME :: Use the auto_cast_date_and_time extension when running the specs
162
163
  SEQUEL_ASYNC_THREAD_POOL :: Use the async_thread_pool extension when running the specs
163
164
  SEQUEL_ASYNC_THREAD_POOL_PREEMPT :: Use the async_thread_pool extension when running the specs, with the :preempt_async_thread option
164
165
  SEQUEL_CHECK_PENDING :: Try running all specs (note, can cause lockups for some adapters), and raise errors for skipped specs that don't fail
165
166
  SEQUEL_COLUMNS_INTROSPECTION :: Use the columns_introspection extension when running the specs
166
167
  SEQUEL_CONCURRENT_EAGER_LOADING :: Use the async_thread_pool extension and concurrent_eager_loading plugin when running the specs
167
- SEQUEL_CONNECTION_VALIDATOR :: Use the connection validator extension when running the specs
168
+ SEQUEL_CONNECTION_VALIDATOR :: Use the connection_validator extension when running the adapter/integration specs
168
169
  SEQUEL_DUPLICATE_COLUMNS_HANDLER :: Use the duplicate columns handler extension with value given when running the specs
169
170
  SEQUEL_ERROR_SQL :: Use the error_sql extension when running the specs
170
171
  SEQUEL_FIBER_CONCURRENCY :: Use the fiber_concurrency extension when running the adapter and integration specs
@@ -185,4 +186,5 @@ SEQUEL_QUERY_PER_ASSOCIATION_DB_2_URL :: Run query-per-association integration t
185
186
  SEQUEL_QUERY_PER_ASSOCIATION_DB_3_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
186
187
  SEQUEL_SPLIT_SYMBOLS :: Turn on symbol splitting when running the adapter and integration specs
187
188
  SEQUEL_SYNCHRONIZE_SQL :: Use the synchronize_sql extension when running the specs
189
+ SEQUEL_TRANSACTION_CONNECTION_VALIDATOR :: Use the transaction_connection_validator extension when running the adapter/integration specs
188
190
  SEQUEL_TZINFO_VERSION :: Force the given tzinfo version when running the specs (e.g. '>=2')
@@ -1,6 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  Sequel::JDBC.load_driver('org.h2.Driver', :H2)
4
+ require_relative '../../extensions/auto_cast_date_and_time'
4
5
 
5
6
  module Sequel
6
7
  module JDBC
@@ -14,6 +15,8 @@ module Sequel
14
15
 
15
16
  module H2
16
17
  module DatabaseMethods
18
+ include AutoCastDateAndTime
19
+
17
20
  def commit_prepared_transaction(transaction_id, opts=OPTS)
18
21
  run("COMMIT TRANSACTION #{transaction_id}", opts)
19
22
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  Sequel::JDBC.load_driver('org.hsqldb.jdbcDriver', :HSQLDB)
4
4
  require_relative 'transactions'
5
+ require_relative '../../extensions/auto_cast_date_and_time'
5
6
 
6
7
  module Sequel
7
8
  module JDBC
@@ -15,6 +16,7 @@ module Sequel
15
16
 
16
17
  module HSQLDB
17
18
  module DatabaseMethods
19
+ include AutoCastDateAndTime
18
20
  include ::Sequel::JDBC::Transactions
19
21
 
20
22
  def database_type
@@ -56,6 +56,17 @@ module Sequel
56
56
 
57
57
  private
58
58
 
59
+ # JDBC SQLAnywhere driver does not appear to handle fractional
60
+ # times correctly.
61
+ def default_time_format
62
+ "'%H:%M:%S'"
63
+ end
64
+
65
+ # Set to zero to work around JDBC SQLAnywhere driver bug.
66
+ def sqltime_precision
67
+ 0
68
+ end
69
+
59
70
  SMALLINT_TYPE = Java::JavaSQL::Types::SMALLINT
60
71
  BOOLEAN_METHOD = Object.new
61
72
  def BOOLEAN_METHOD.call(r, i)
@@ -182,8 +182,8 @@ module Sequel
182
182
  1
183
183
  when false
184
184
  0
185
- when DateTime, Time
186
- literal(arg)[1...-1]
185
+ when Time, Date
186
+ @default_dataset.literal_date_or_time(arg, true)
187
187
  else
188
188
  arg
189
189
  end
@@ -43,7 +43,7 @@ module Sequel
43
43
  # Use ODBC format, not Microsoft format, as the ODBC layer does
44
44
  # some translation, but allow for millisecond precision.
45
45
  def default_timestamp_format
46
- "{ts '%Y-%m-%d %H:%M:%S%N'}"
46
+ "{ts '%Y-%m-%d %H:%M:%S.%3N'}"
47
47
  end
48
48
 
49
49
  # Use ODBC format, not Microsoft format, as the ODBC layer does
@@ -188,8 +188,8 @@ module Sequel
188
188
  # :nocov:
189
189
  # Not covered by tests as tests use pg_extended_date_support
190
190
  # extension, which has basically the same code.
191
- when DateTime, Time
192
- literal(arg)
191
+ when Time, DateTime
192
+ @default_dataset.literal_date_or_time(arg)
193
193
  # :nocov:
194
194
  else
195
195
  arg
@@ -932,7 +932,7 @@ module Sequel
932
932
  # since that is the format that is multilanguage and not
933
933
  # DATEFORMAT dependent.
934
934
  def default_timestamp_format
935
- "'%Y-%m-%dT%H:%M:%S%N%z'"
935
+ "'%Y-%m-%dT%H:%M:%S.%3N'"
936
936
  end
937
937
 
938
938
  # Only include the primary table in the main delete clause
@@ -929,6 +929,16 @@ module Sequel
929
929
  super if type == :truncate || @opts[:offset]
930
930
  end
931
931
 
932
+ # The strftime format to use when literalizing time (Sequel::SQLTime) values.
933
+ def default_time_format
934
+ db.supports_timestamp_usecs? ? super : "'%H:%M:%S'"
935
+ end
936
+
937
+ # The strftime format to use when literalizing timestamp (Time/DateTime) values.
938
+ def default_timestamp_format
939
+ db.supports_timestamp_usecs? ? super : "'%Y-%m-%d %H:%M:%S'"
940
+ end
941
+
932
942
  # Consider the first table in the joined dataset is the table to delete
933
943
  # from, but include the others for the purposes of selecting rows.
934
944
  def delete_from_sql(sql)
@@ -1,6 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  require_relative '../utils/emulate_offset_with_row_number'
4
+ require_relative '../../extensions/auto_cast_date_and_time'
4
5
 
5
6
  module Sequel
6
7
  module Oracle
@@ -326,6 +327,8 @@ module Sequel
326
327
  end
327
328
 
328
329
  module DatasetMethods
330
+ include AutoCastDateAndTime
331
+
329
332
  ROW_NUMBER_EXPRESSION = LiteralString.new('ROWNUM').freeze
330
333
  BITAND_PROC = lambda{|a, b| Sequel.lit(["CAST(BITAND(", ", ", ") AS INTEGER)"], a, b)}
331
334
 
@@ -623,7 +626,7 @@ module Sequel
623
626
 
624
627
  # The strftime format to use when literalizing the time.
625
628
  def default_timestamp_format
626
- "TIMESTAMP '%Y-%m-%d %H:%M:%S%N %z'"
629
+ "'%Y-%m-%d %H:%M:%S.%6N %:z'"
627
630
  end
628
631
 
629
632
  def empty_from_sql
@@ -660,11 +663,6 @@ module Sequel
660
663
  super
661
664
  end
662
665
 
663
- # Use a colon for the timestamp offset, since Oracle appears to require it.
664
- def format_timestamp_offset(hour, minute)
665
- sprintf("%+03i:%02i", hour, minute)
666
- end
667
-
668
666
  # Oracle doesn't support empty values when inserting.
669
667
  def insert_supports_empty_values?
670
668
  false
@@ -1092,6 +1092,14 @@ module Sequel
1092
1092
  sql << type
1093
1093
  end
1094
1094
 
1095
+ # Consider lock or statement timeout errors as evidence that the table exists
1096
+ # but is locked.
1097
+ def _table_exists?(ds)
1098
+ super
1099
+ rescue DatabaseError => e
1100
+ raise e unless /canceling statement due to (?:statement|lock) timeout/ =~ e.message
1101
+ end
1102
+
1095
1103
  def alter_table_add_column_sql(table, op)
1096
1104
  "ADD COLUMN#{' IF NOT EXISTS' if op[:if_not_exists]} #{column_definition_sql(op)}"
1097
1105
  end
@@ -1505,7 +1513,11 @@ module Sequel
1505
1513
  # currently visible schemas.
1506
1514
  def filter_schema(ds, opts)
1507
1515
  expr = if schema = opts[:schema]
1508
- schema.to_s
1516
+ if schema.is_a?(SQL::Identifier)
1517
+ schema.value.to_s
1518
+ else
1519
+ schema.to_s
1520
+ end
1509
1521
  else
1510
1522
  Sequel.function(:any, Sequel.function(:current_schemas, false))
1511
1523
  end
@@ -2138,10 +2150,14 @@ module Sequel
2138
2150
  server_version >= 90500
2139
2151
  end
2140
2152
 
2153
+ # :nocov:
2154
+
2141
2155
  # PostgreSQL supports timezones in literal timestamps
2142
2156
  def supports_timestamp_timezones?
2157
+ # SEQUEL6: Remove
2143
2158
  true
2144
2159
  end
2160
+ # :nocov:
2145
2161
 
2146
2162
  # PostgreSQL 8.4+ supports WINDOW clause.
2147
2163
  def supports_window_clause?
@@ -2261,6 +2277,11 @@ module Sequel
2261
2277
  raise(InvalidOperation, "Joined datasets cannot be truncated") if opts[:join]
2262
2278
  end
2263
2279
 
2280
+ # The strftime format to use when literalizing the time.
2281
+ def default_timestamp_format
2282
+ "'%Y-%m-%d %H:%M:%S.%6N%z'"
2283
+ end
2284
+
2264
2285
  # Only include the primary table in the main delete clause
2265
2286
  def delete_from_sql(sql)
2266
2287
  sql << ' FROM '
@@ -281,10 +281,6 @@ module Sequel
281
281
  false
282
282
  end
283
283
 
284
- def supports_timestamp_usecs?
285
- false
286
- end
287
-
288
284
  def supports_window_clause?
289
285
  true
290
286
  end
@@ -378,6 +374,16 @@ module Sequel
378
374
 
379
375
  private
380
376
 
377
+ # SQLAnywhere only supports 3 digits after the decimal point for times.
378
+ def default_time_format
379
+ "'%H:%M:%S.%3N'"
380
+ end
381
+
382
+ # SQLAnywhere only supports 3 digits after the decimal point for timestamps.
383
+ def default_timestamp_format
384
+ "'%Y-%m-%d %H:%M:%S.%3N'"
385
+ end
386
+
381
387
  # Use 1 for true on Sybase
382
388
  def literal_true
383
389
  '1'
@@ -145,6 +145,11 @@ module Sequel
145
145
  sqlite_version >= 30608
146
146
  end
147
147
 
148
+ # SQLite 3.8.2+ supports the without rowid table constraint
149
+ def support_without_rowid?
150
+ sqlite_version >= 30802
151
+ end
152
+
148
153
  # Override the default setting for whether to use timezones in timestamps.
149
154
  # It is set to +false+ by default, as SQLite's date/time methods do not
150
155
  # support timezones in timestamps.
@@ -344,9 +349,17 @@ module Sequel
344
349
  ps
345
350
  end
346
351
 
347
- # Support creating STRICT tables via :strict option
352
+ # Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options
348
353
  def create_table_sql(name, generator, options)
349
- "#{super}#{' STRICT' if options[:strict]}"
354
+ if options[:strict] && options[:without_rowid]
355
+ "#{super} STRICT, WITHOUT ROWID"
356
+ elsif options[:strict]
357
+ "#{super} STRICT"
358
+ elsif options[:without_rowid]
359
+ "#{super} WITHOUT ROWID"
360
+ else
361
+ super
362
+ end
350
363
  end
351
364
 
352
365
  # SQLite support creating temporary views.
@@ -917,6 +930,11 @@ module Sequel
917
930
  500
918
931
  end
919
932
 
933
+ # The strftime format to use when literalizing the time.
934
+ def default_timestamp_format
935
+ db.use_timestamp_timezones? ? "'%Y-%m-%d %H:%M:%S.%6N%z'" : super
936
+ end
937
+
920
938
  # SQL fragment specifying a list of identifiers
921
939
  def identifier_list(columns)
922
940
  columns.map{|i| quote_identifier(i)}.join(', ')
@@ -111,6 +111,18 @@ module Sequel
111
111
  # static data that you do not want to modify
112
112
  # :timeout :: how long to wait for the database to be available if it
113
113
  # is locked, given in milliseconds (default is 5000)
114
+ # :setup_regexp_function :: enable use of Regexp objects with SQL
115
+ # 'REGEXP' operator. If the value is :cached or "cached",
116
+ # caches the generated regexps, which can result in a memory
117
+ # leak if dynamic regexps are used. If the value is a Proc,
118
+ # it will be called with a string for the regexp and a string
119
+ # for the value to compare, and should return whether the regexp
120
+ # matches.
121
+ # :regexp_function_cache :: If setting +setup_regexp_function+ to +cached+, this
122
+ # determines the cache to use. It should either be a proc or a class, and it
123
+ # defaults to +Hash+. You can use +ObjectSpace::WeakKeyMap+ on Ruby 3.3+ to
124
+ # have the VM automatically remove regexps from the cache after they
125
+ # are no longer used.
114
126
  def connect(server)
115
127
  opts = server_opts(server)
116
128
  opts[:database] = ':memory:' if blank_object?(opts[:database])
@@ -126,9 +138,7 @@ module Sequel
126
138
  connection_pragmas.each{|s| log_connection_yield(s, db){db.execute_batch(s)}}
127
139
 
128
140
  if typecast_value_boolean(opts[:setup_regexp_function])
129
- db.create_function("regexp", 2) do |func, regexp_str, string|
130
- func.result = Regexp.new(regexp_str).match(string) ? 1 : 0
131
- end
141
+ setup_regexp_function(db, opts[:setup_regexp_function])
132
142
  end
133
143
 
134
144
  class << db
@@ -202,6 +212,35 @@ module Sequel
202
212
  @conversion_procs['datetime'] = @conversion_procs['timestamp'] = method(:to_application_timestamp)
203
213
  set_integer_booleans
204
214
  end
215
+
216
+ def setup_regexp_function(db, how)
217
+ case how
218
+ when Proc
219
+ # nothing
220
+ when :cached, "cached"
221
+ cache = @opts[:regexp_function_cache] || Hash
222
+ cache = cache.is_a?(Proc) ? cache.call : cache.new
223
+ how = if RUBY_VERSION >= '2.4'
224
+ lambda do |regexp_str, str|
225
+ (cache[regexp_str] ||= Regexp.new(regexp_str)).match?(str)
226
+ end
227
+ else
228
+ lambda do |regexp_str, str|
229
+ (cache[regexp_str] ||= Regexp.new(regexp_str)).match(str)
230
+ end
231
+ end
232
+ else
233
+ how = if RUBY_VERSION >= '2.4'
234
+ lambda{|regexp_str, str| Regexp.new(regexp_str).match?(str)}
235
+ else
236
+ lambda{|regexp_str, str| Regexp.new(regexp_str).match(str)}
237
+ end
238
+ end
239
+
240
+ db.create_function("regexp", 2) do |func, regexp_str, str|
241
+ func.result = how.call(regexp_str, str) ? 1 : 0
242
+ end
243
+ end
205
244
 
206
245
  # Yield an available connection. Rescue
207
246
  # any SQLite3::Exceptions and turn them into DatabaseErrors.
@@ -70,8 +70,10 @@ class Sequel::ConnectionPool
70
70
  else
71
71
  pc = if opts[:single_threaded]
72
72
  opts[:servers] ? :sharded_single : :single
73
- #elsif RUBY_VERSION >= '3.2' # SEQUEL6 or maybe earlier
74
- # opts[:servers] ? :sharded_timed_queue : :timed_queue
73
+ # :nocov:
74
+ elsif RUBY_VERSION >= '3.4' # SEQUEL6 or maybe earlier switch to 3.2
75
+ opts[:servers] ? :sharded_timed_queue : :timed_queue
76
+ # :nocov:
75
77
  else
76
78
  opts[:servers] ? :sharded_threaded : :threaded
77
79
  end
@@ -263,8 +263,8 @@ module Sequel
263
263
  # Proxy the literal call to the dataset.
264
264
  #
265
265
  # DB.literal(1) # 1
266
- # DB.literal(:a) # a
267
- # DB.literal('a') # 'a'
266
+ # DB.literal(:a) # "a" # or `a`, [a], or a, depending on identifier quoting
267
+ # DB.literal("a") # 'a'
268
268
  def literal(v)
269
269
  schema_utility_dataset.literal(v)
270
270
  end
@@ -191,6 +191,12 @@ module Sequel
191
191
  # The +any+ type is treated like a SQLite column in a non-strict table,
192
192
  # allowing any type of data to be stored. This option is supported on
193
193
  # SQLite 3.37.0+.
194
+ # :without_rowid :: Create a WITHOUT ROWID table. Every row in SQLite has a special
195
+ # 'rowid' column, that uniquely identifies that row within the table.
196
+ # If this option is used, the 'rowid' column is omitted, which can
197
+ # sometimes provide some space and speed advantages. Note that you
198
+ # must then provide an explicit primary key when you create the table.
199
+ # This option is supported on SQLite 3.8.2+.
194
200
  #
195
201
  # See <tt>Schema::CreateTableGenerator</tt> and the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc].
196
202
  def create_table(name, options=OPTS, &block)