sequel 5.58.0 → 5.78.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.
- checksums.yaml +4 -4
- data/CHANGELOG +288 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +24 -23
- data/bin/sequel +11 -3
- data/doc/advanced_associations.rdoc +16 -14
- data/doc/association_basics.rdoc +53 -17
- data/doc/cheat_sheet.rdoc +3 -3
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +15 -0
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +20 -12
- data/doc/postgresql.rdoc +8 -8
- data/doc/querying.rdoc +1 -1
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/release_notes/5.61.0.txt +43 -0
- data/doc/release_notes/5.62.0.txt +132 -0
- data/doc/release_notes/5.63.0.txt +33 -0
- data/doc/release_notes/5.64.0.txt +50 -0
- data/doc/release_notes/5.65.0.txt +21 -0
- data/doc/release_notes/5.66.0.txt +24 -0
- data/doc/release_notes/5.67.0.txt +32 -0
- data/doc/release_notes/5.68.0.txt +61 -0
- data/doc/release_notes/5.69.0.txt +26 -0
- data/doc/release_notes/5.70.0.txt +35 -0
- data/doc/release_notes/5.71.0.txt +21 -0
- data/doc/release_notes/5.72.0.txt +33 -0
- data/doc/release_notes/5.73.0.txt +66 -0
- data/doc/release_notes/5.74.0.txt +45 -0
- data/doc/release_notes/5.75.0.txt +35 -0
- data/doc/release_notes/5.76.0.txt +86 -0
- data/doc/release_notes/5.77.0.txt +63 -0
- data/doc/release_notes/5.78.0.txt +67 -0
- data/doc/schema_modification.rdoc +3 -3
- data/doc/security.rdoc +9 -9
- data/doc/sharding.rdoc +3 -1
- data/doc/sql.rdoc +14 -14
- data/doc/testing.rdoc +16 -12
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/ibmdb.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +3 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -0
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +15 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +10 -6
- data/lib/sequel/adapters/mysql.rb +19 -7
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +1 -0
- data/lib/sequel/adapters/postgres.rb +62 -16
- data/lib/sequel/adapters/shared/access.rb +9 -1
- data/lib/sequel/adapters/shared/db2.rb +12 -0
- data/lib/sequel/adapters/shared/mssql.rb +71 -9
- data/lib/sequel/adapters/shared/mysql.rb +80 -1
- data/lib/sequel/adapters/shared/oracle.rb +17 -7
- data/lib/sequel/adapters/shared/postgres.rb +494 -164
- data/lib/sequel/adapters/shared/sqlanywhere.rb +18 -5
- data/lib/sequel/adapters/shared/sqlite.rb +40 -4
- data/lib/sequel/adapters/sqlite.rb +42 -3
- data/lib/sequel/adapters/trilogy.rb +117 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +16 -11
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
- data/lib/sequel/connection_pool/threaded.rb +14 -8
- data/lib/sequel/connection_pool/timed_queue.rb +270 -0
- data/lib/sequel/connection_pool.rb +57 -31
- data/lib/sequel/database/connecting.rb +25 -1
- data/lib/sequel/database/dataset.rb +16 -6
- data/lib/sequel/database/misc.rb +65 -14
- data/lib/sequel/database/query.rb +72 -1
- data/lib/sequel/database/schema_generator.rb +2 -1
- data/lib/sequel/database/schema_methods.rb +13 -3
- data/lib/sequel/database/transactions.rb +6 -0
- data/lib/sequel/dataset/actions.rb +60 -13
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
- data/lib/sequel/dataset/features.rb +15 -1
- data/lib/sequel/dataset/misc.rb +12 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
- data/lib/sequel/dataset/query.rb +62 -37
- data/lib/sequel/dataset/sql.rb +58 -36
- data/lib/sequel/dataset.rb +4 -0
- data/lib/sequel/exceptions.rb +5 -0
- data/lib/sequel/extensions/_model_pg_row.rb +0 -12
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/any_not_empty.rb +2 -2
- data/lib/sequel/extensions/async_thread_pool.rb +21 -13
- data/lib/sequel/extensions/auto_cast_date_and_time.rb +94 -0
- data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/connection_expiration.rb +15 -9
- data/lib/sequel/extensions/connection_validator.rb +16 -11
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +36 -8
- data/lib/sequel/extensions/duplicate_columns_handler.rb +10 -9
- data/lib/sequel/extensions/index_caching.rb +5 -1
- data/lib/sequel/extensions/is_distinct_from.rb +3 -1
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/migration.rb +65 -15
- data/lib/sequel/extensions/named_timezones.rb +22 -6
- data/lib/sequel/extensions/pg_array.rb +33 -4
- data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
- data/lib/sequel/extensions/pg_enum.rb +1 -2
- data/lib/sequel/extensions/pg_extended_date_support.rb +38 -27
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +5 -0
- data/lib/sequel/extensions/pg_inet.rb +10 -11
- data/lib/sequel/extensions/pg_interval.rb +10 -11
- data/lib/sequel/extensions/pg_json.rb +10 -10
- data/lib/sequel/extensions/pg_json_ops.rb +52 -0
- data/lib/sequel/extensions/pg_multirange.rb +6 -11
- data/lib/sequel/extensions/pg_range.rb +9 -14
- data/lib/sequel/extensions/pg_row.rb +20 -19
- data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
- data/lib/sequel/extensions/round_timestamps.rb +1 -1
- data/lib/sequel/extensions/schema_caching.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +32 -9
- data/lib/sequel/extensions/server_block.rb +2 -1
- data/lib/sequel/extensions/set_literalizer.rb +58 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +76 -18
- data/lib/sequel/extensions/symbol_aref.rb +2 -0
- data/lib/sequel/extensions/transaction_connection_validator.rb +78 -0
- data/lib/sequel/model/associations.rb +50 -11
- data/lib/sequel/model/base.rb +45 -21
- data/lib/sequel/model/dataset_module.rb +3 -0
- data/lib/sequel/model/exceptions.rb +15 -3
- data/lib/sequel/plugins/auto_validations.rb +53 -15
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/column_encryption.rb +27 -6
- data/lib/sequel/plugins/composition.rb +2 -2
- data/lib/sequel/plugins/concurrent_eager_loading.rb +4 -4
- data/lib/sequel/plugins/constraint_validations.rb +8 -5
- data/lib/sequel/plugins/defaults_setter.rb +16 -0
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/finder.rb +4 -2
- data/lib/sequel/plugins/list.rb +8 -3
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
- data/lib/sequel/plugins/nested_attributes.rb +4 -4
- data/lib/sequel/plugins/optimistic_locking.rb +9 -42
- data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
- data/lib/sequel/plugins/paged_operations.rb +181 -0
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +9 -3
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
- data/lib/sequel/plugins/prepared_statements.rb +2 -1
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -1
- data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
- data/lib/sequel/plugins/rcte_tree.rb +7 -4
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
- data/lib/sequel/plugins/sql_comments.rb +5 -5
- data/lib/sequel/plugins/static_cache.rb +38 -0
- data/lib/sequel/plugins/static_cache_cache.rb +5 -1
- data/lib/sequel/plugins/tactical_eager_loading.rb +21 -14
- data/lib/sequel/plugins/validate_associated.rb +22 -12
- data/lib/sequel/plugins/validation_helpers.rb +29 -2
- data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
- data/lib/sequel/version.rb +1 -1
- metadata +76 -6
@@ -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.
|
@@ -0,0 +1,67 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* SQLite 3.45+ jsonb functions are now supported in the sqlite_json_ops
|
4
|
+
extension. Similar to the postgres_json_ops extension, there are
|
5
|
+
now separate methods for dealing with json and jsonb types:
|
6
|
+
|
7
|
+
Sequel.sqlite_json_op(:column) # json
|
8
|
+
Sequel.sqlite_jsonb_op(:column) # jsonb
|
9
|
+
|
10
|
+
Some methods that use json_* functions for json ops use jsonb_*
|
11
|
+
functions for jsonb ops:
|
12
|
+
|
13
|
+
jb = Sequel.sqlite_jsonb_op(:column)
|
14
|
+
jb.extract('$.a') # jsonb_extract(column, '$.a')
|
15
|
+
jb.insert('$.a', 1) # jsonb_insert(column, '$.a', 1)
|
16
|
+
jb.set('$.a', 1) # jsonb_set(column, '$.a', 1)
|
17
|
+
jb.replace('$.a', 1) # jsonb_replace(column, '$.a', 1)
|
18
|
+
jb.remove('$.a') # jsonb_remove(column, '$.a')
|
19
|
+
jb.patch('{"a":2}') # jsonb_patch(column, '{"a":2}')
|
20
|
+
|
21
|
+
You can use the json and jsonb methods to convert jsonb to json
|
22
|
+
and json to jsonb, respectively.
|
23
|
+
|
24
|
+
jb.json # json(column)
|
25
|
+
|
26
|
+
Use of the json method on jsonb types is important, because if you
|
27
|
+
want to be able to deal with the values in Ruby, you must convert
|
28
|
+
the jsonb value to json in the database before the database returns
|
29
|
+
the value. Unlike PostgreSQL, SQLite will not convert the value
|
30
|
+
from jsonb to json on retrieval, and direct use of SQLite's jsonb
|
31
|
+
format is unsupported by SQLite as it is subject to change.
|
32
|
+
|
33
|
+
* Database#with_advisory_lock is now supported on PostgreSQL, MySQL,
|
34
|
+
and Microsoft SQL Server. This supports advisory (explicit)
|
35
|
+
locking, using the database-specific APIs. To work on all three
|
36
|
+
servers, lock ids should be integers in the signed 64-bit range.
|
37
|
+
|
38
|
+
DB.with_advisory_lock(1234) do
|
39
|
+
# do something
|
40
|
+
end
|
41
|
+
|
42
|
+
By default, an AdvisoryLockError is raised if the lock cannot be
|
43
|
+
immediately acquired. You can use the :wait option to wait until
|
44
|
+
the lock can be acquired, instead of raising.
|
45
|
+
|
46
|
+
DB.with_advisory_lock(1234, wait: true) do
|
47
|
+
# do something
|
48
|
+
end
|
49
|
+
|
50
|
+
* Migrator.run now supports a :use_advisory_lock option to use
|
51
|
+
advisory locks when running migrations, so that it does not
|
52
|
+
attempt to run the same migration more than once in the case
|
53
|
+
where multiple processes are running the migrator simultaneously.
|
54
|
+
It's probably best to avoid running the migrator in multiple
|
55
|
+
processes simultaneously instead of relying on this option.
|
56
|
+
|
57
|
+
= Other Improvements
|
58
|
+
|
59
|
+
* Database#values now supports chaining with compounds on
|
60
|
+
PostgreSQL.
|
61
|
+
|
62
|
+
DB.values([[1, 2]]).union(DB.values([[3, 4]]))
|
63
|
+
# SELECT * FROM (VALUES (1, 2) UNION (VALUES (3, 4))) AS t1
|
64
|
+
|
65
|
+
* The internal hash used to store transaction metadata now uses
|
66
|
+
compare_by_identity, which is faster and avoids potential
|
67
|
+
issues if a driver implements connection object equality.
|
@@ -81,8 +81,8 @@ appropriate 64-bit integer type for the database you are using.
|
|
81
81
|
|
82
82
|
=== Column options
|
83
83
|
|
84
|
-
When using the type name as method, the
|
85
|
-
method, the
|
84
|
+
When using the type name as method, the second argument is an options hash, and when using the +column+
|
85
|
+
method, the third argument is the options hash. The following options are supported:
|
86
86
|
|
87
87
|
:default :: The default value for the column.
|
88
88
|
:index :: Create an index on this column. If given a hash, use the hash as the
|
@@ -377,7 +377,7 @@ Sequel will not add a column, but will add a composite primary key constraint:
|
|
377
377
|
It is possible to specify a name for the primary key constraint: via the :name option:
|
378
378
|
|
379
379
|
alter_table(:albums_artists) do
|
380
|
-
add_primary_key [:album_id, :artist_id], :
|
380
|
+
add_primary_key [:album_id, :artist_id], name: :albums_artists_pkey
|
381
381
|
end
|
382
382
|
|
383
383
|
If you just want to take an existing single column and make it a primary key, call
|
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(:
|
131
|
-
DB.literal(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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/sharding.rdoc
CHANGED
@@ -39,7 +39,9 @@ is the simplest configuration:
|
|
39
39
|
servers: {read_only: {host: 'replica_server'}})
|
40
40
|
|
41
41
|
This will use the replica_server for SELECT queries and primary_server for
|
42
|
-
other queries.
|
42
|
+
other queries. The :read_only key in the :servers hash is special in that
|
43
|
+
it sets the default database for Dataset methods that use SELECT queries
|
44
|
+
(which are generally read queries that do not modify the database).
|
43
45
|
|
44
46
|
If you want to ensure your queries are going to a specific database, you
|
45
47
|
can force this for a given query by using the .server method and passing
|
data/doc/sql.rdoc
CHANGED
@@ -59,7 +59,7 @@ Then, you call the +insert+, +update+, or +delete+ method on the returned datase
|
|
59
59
|
update_ds.update
|
60
60
|
delete_ds.delete
|
61
61
|
|
62
|
-
+update+ and +delete+
|
62
|
+
+update+ and +delete+ generally return the number of rows affected, and +insert+ generally returns the autogenerated primary key integer for the row inserted (if any), but not all adapters/databases support this behavior for datasets using custom SQL (notably it is not supported for +insert+ on PostgreSQL).
|
63
63
|
|
64
64
|
=== Other Queries
|
65
65
|
|
@@ -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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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
|
@@ -551,8 +551,8 @@ You can also use the <tt>Sequel.asc</tt> and <tt>Sequel.desc</tt> methods:
|
|
551
551
|
|
552
552
|
On some databases, you can specify null ordering:
|
553
553
|
|
554
|
-
Sequel.asc(:column, :
|
555
|
-
Sequel.desc(Sequel[:table][:column], :
|
554
|
+
Sequel.asc(:column, nulls: :first) # "column" ASC NULLS FIRST
|
555
|
+
Sequel.desc(Sequel[:table][:column], nulls: :last) # "table"."column" DESC NULLS LAST
|
556
556
|
|
557
557
|
=== All Columns (.*)
|
558
558
|
|
@@ -629,16 +629,16 @@ Also note that while the SELECT clause is displayed when you look at a dataset,
|
|
629
629
|
|
630
630
|
ds = DB[:albums]
|
631
631
|
ds.all # SELECT * FROM albums
|
632
|
-
ds.insert(:
|
633
|
-
ds.update(:
|
632
|
+
ds.insert(name: 'RF') # INSERT INTO albums (name) VALUES ('RF')
|
633
|
+
ds.update(name: 'RF') # UPDATE albums SET name = 'RF'
|
634
634
|
ds.delete # DELETE FROM albums
|
635
635
|
|
636
636
|
In general, the +insert+, +update+, and +delete+ methods use the appropriate clauses you defined on the dataset:
|
637
637
|
|
638
|
-
ds = DB[:albums].where(:
|
638
|
+
ds = DB[:albums].where(id: 1)
|
639
639
|
ds.all # SELECT * FROM albums WHERE (id = 1)
|
640
|
-
ds.insert(:
|
641
|
-
ds.update(:
|
640
|
+
ds.insert(name: 'RF') # INSERT INTO albums (name) VALUES ('RF')
|
641
|
+
ds.update(name: 'RF') # UPDATE albums SET name = 'RF' WHERE (id = 1)
|
642
642
|
ds.delete # DELETE FROM albums WHERE (id = 1)
|
643
643
|
|
644
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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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], :
|
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(:
|
74
|
+
DB.transaction(rollback: :always, savepoint: true, auto_savepoint: true){super}
|
75
75
|
end
|
76
76
|
|
77
77
|
def around_all
|
78
|
-
DB.transaction(:
|
78
|
+
DB.transaction(rollback: :always){super}
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -159,28 +159,32 @@ 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
|
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
|
164
166
|
SEQUEL_COLUMNS_INTROSPECTION :: Use the columns_introspection extension when running the specs
|
165
|
-
SEQUEL_CONNECTION_VALIDATOR :: Use the connection validator extension when running the specs
|
166
|
-
SEQUEL_DUPLICATE_COLUMNS_HANDLER :: Use the duplicate columns handler extension with value given when running the specs
|
167
167
|
SEQUEL_CONCURRENT_EAGER_LOADING :: Use the async_thread_pool extension and concurrent_eager_loading plugin when running the specs
|
168
|
+
SEQUEL_CONNECTION_VALIDATOR :: Use the connection_validator extension when running the adapter/integration specs
|
169
|
+
SEQUEL_DUPLICATE_COLUMNS_HANDLER :: Use the duplicate columns handler extension with value given when running the specs
|
168
170
|
SEQUEL_ERROR_SQL :: Use the error_sql extension when running the specs
|
169
|
-
SEQUEL_INDEX_CACHING :: Use the index_caching extension when running the specs
|
170
171
|
SEQUEL_FIBER_CONCURRENCY :: Use the fiber_concurrency extension when running the adapter and integration specs
|
171
172
|
SEQUEL_FREEZE_DATABASE :: Freeze the database before running the integration specs
|
172
173
|
SEQUEL_IDENTIFIER_MANGLING :: Use the identifier_mangling extension when running the specs
|
174
|
+
SEQUEL_INDEX_CACHING :: Use the index_caching extension when running the specs
|
173
175
|
SEQUEL_INTEGER64 :: Use the integer64 extension when running the adapter or integration specs
|
174
176
|
SEQUEL_MODEL_PREPARED_STATEMENTS :: Use the prepared_statements plugin when running the specs
|
175
177
|
SEQUEL_MODEL_THROW_FAILURES :: Use the throw_failures plugin when running the specs
|
176
178
|
SEQUEL_NO_CACHE_ASSOCIATIONS :: Don't cache association metadata when running the specs
|
177
|
-
SEQUEL_CHECK_PENDING :: Try running all specs (note, can cause lockups for some adapters), and raise errors for skipped specs that don't fail
|
178
179
|
SEQUEL_NO_PENDING :: Don't skip any specs, try running all specs (note, can cause lockups for some adapters)
|
180
|
+
SEQUEL_PG_AUTO_PARAMETERIZE :: Use the pg_auto_parameterize extension when running the postgres specs. Value can be +in_array+ to test the pg_auto_parameterize_in_array extension, and +in_array_string+ to test the pg_auto_parameterize_in_array extension with the +:treat_in_string_list_as_text_array+ Database option set.
|
179
181
|
SEQUEL_PG_TIMESTAMPTZ :: Use the pg_timestamptz extension when running the postgres specs
|
182
|
+
SEQUEL_PRIMARY_KEY_LOOKUP_CHECK_VALUES :: Use the primary_key_lookup_check_values extension when running the adapter or integration specs
|
180
183
|
SEQUEL_QUERY_PER_ASSOCIATION_DB_0_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
|
181
184
|
SEQUEL_QUERY_PER_ASSOCIATION_DB_1_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
|
182
185
|
SEQUEL_QUERY_PER_ASSOCIATION_DB_2_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
|
183
186
|
SEQUEL_QUERY_PER_ASSOCIATION_DB_3_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
|
184
187
|
SEQUEL_SPLIT_SYMBOLS :: Turn on symbol splitting when running the adapter and integration specs
|
185
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
|
186
190
|
SEQUEL_TZINFO_VERSION :: Force the given tzinfo version when running the specs (e.g. '>=2')
|
data/doc/transactions.rdoc
CHANGED
@@ -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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
159
|
+
DB.rollback_on_exit(savepoint: 3)
|
160
160
|
end # ROLLBACK TO SAVEPOINT
|
161
161
|
end # ROLLBACK TO SAVEPOINT
|
162
162
|
end # ROLLBACK
|
data/doc/virtual_rows.rdoc
CHANGED
@@ -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
|
@@ -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
|
@@ -199,6 +199,7 @@ module Sequel
|
|
199
199
|
v.strftime("'%H:%M:%S#{sprintf(".%03d", (v.usec/1000.0).round)}'")
|
200
200
|
end
|
201
201
|
|
202
|
+
INTEGER_TYPE = Java::JavaSQL::Types::INTEGER
|
202
203
|
STRING_TYPE = Java::JavaSQL::Types::VARCHAR
|
203
204
|
ARRAY_TYPE = Java::JavaSQL::Types::ARRAY
|
204
205
|
PG_SPECIFIC_TYPES = [Java::JavaSQL::Types::ARRAY, Java::JavaSQL::Types::OTHER, Java::JavaSQL::Types::STRUCT, Java::JavaSQL::Types::TIME_WITH_TIMEZONE, Java::JavaSQL::Types::TIME].freeze
|
@@ -219,6 +220,8 @@ module Sequel
|
|
219
220
|
oid = meta.getField(i).getOID
|
220
221
|
if pr = db.oid_convertor_proc(oid)
|
221
222
|
pr
|
223
|
+
elsif oid == 28 # XID (Transaction ID)
|
224
|
+
map[INTEGER_TYPE]
|
222
225
|
elsif oid == 2950 # UUID
|
223
226
|
map[STRING_TYPE]
|
224
227
|
elsif meta.getPGType(i) == 'hstore'
|
@@ -36,6 +36,10 @@ module Sequel
|
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
+
def database_exception_use_sqlstates?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
39
43
|
# Use @@IDENTITY to get the last inserted id
|
40
44
|
def last_insert_id(conn, opts=OPTS)
|
41
45
|
statement(conn) do |stmt|
|
@@ -52,6 +56,17 @@ module Sequel
|
|
52
56
|
|
53
57
|
private
|
54
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
|
+
|
55
70
|
SMALLINT_TYPE = Java::JavaSQL::Types::SMALLINT
|
56
71
|
BOOLEAN_METHOD = Object.new
|
57
72
|
def BOOLEAN_METHOD.call(r, i)
|