sequel 5.79.0 → 5.81.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +16 -0
- data/doc/code_order.rdoc +5 -3
- data/doc/release_notes/5.80.0.txt +40 -0
- data/doc/release_notes/5.81.0.txt +31 -0
- data/lib/sequel/adapters/shared/mysql.rb +2 -2
- data/lib/sequel/dataset/graph.rb +1 -0
- data/lib/sequel/dataset/query.rb +13 -0
- data/lib/sequel/extensions/caller_logging.rb +4 -1
- data/lib/sequel/extensions/provenance.rb +110 -0
- data/lib/sequel/extensions/temporarily_release_connection.rb +178 -0
- data/lib/sequel/plugins/column_encryption.rb +1 -1
- data/lib/sequel/plugins/input_transformer.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a23afa1510b7bd1ba6918319eedce156450672520ab4798e6de56461a59660e1
|
4
|
+
data.tar.gz: bb6bbfbf0f1f82fe117fa8c725e9cf4fde49644a74b463ab8682018744a8a1de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e26620f8f1df2715205e9019c2012ec2e9f392d14ed427d66c76f488bccc3e5d3f27e4d626a47d54903d611695db0487f987d99191602024a1864d6c10f7bde
|
7
|
+
data.tar.gz: cd070d8c35960949039d226b5eaf8c90ebec8d0cef3f09b5dae533551bb35170ca6e2503d88f1b1512110b6617ff9c03d9cb2afb62395c4d953314aa5a5ca87c
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
=== 5.81.0 (2024-06-01)
|
2
|
+
|
3
|
+
* Fix ignored block warnings in a couple plugin apply methods on Ruby 3.4 (jeremyevans)
|
4
|
+
|
5
|
+
* Skip Ruby internal caller locations when searching for caller locations in caller_logging and provenance extensions (jeremyevans)
|
6
|
+
|
7
|
+
* Add temporarily_release_connection Database extension for multithreaded transactional testing (jeremyevans)
|
8
|
+
|
9
|
+
=== 5.80.0 (2024-05-01)
|
10
|
+
|
11
|
+
* Support Dataset#skip_locked on MariaDB 10.6+ (simi) (#2150)
|
12
|
+
|
13
|
+
* Avoid allocating datasets in cases where the returned dataset would be the same as the receiver (jeremyevans)
|
14
|
+
|
15
|
+
* Add provenance dataset extension, which includes comments in queries showing how and where the dataset was built (jeremyevans)
|
16
|
+
|
1
17
|
=== 5.79.0 (2024-04-01)
|
2
18
|
|
3
19
|
* Support create_or_replace_view with :materialized option on PostgreSQL (nashby) (#2144)
|
data/doc/code_order.rdoc
CHANGED
@@ -91,9 +91,11 @@ unsafe runtime modification of the configuration:
|
|
91
91
|
model_classes.each(&:freeze)
|
92
92
|
DB.freeze
|
93
93
|
|
94
|
-
|
95
|
-
|
96
|
-
|
94
|
+
`model_classes` is not a Sequel method, it indicates an array of model
|
95
|
+
classes you defined. Instead of listing them manually, the `subclasses`
|
96
|
+
plugin can be used to keep track of all model classes that have been
|
97
|
+
setup in your application. Finalizing their associations and freezing
|
98
|
+
them can easily be achieved through the plugin:
|
97
99
|
|
98
100
|
# Register the plugin before setting up the models
|
99
101
|
Sequel::Model.plugin :subclasses
|
@@ -0,0 +1,40 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A provenance dataset extension has been added. This extension makes
|
4
|
+
SQL queries include a comment describing how the dataset was built.
|
5
|
+
This can make debugging complex cases significantly easier. Here's
|
6
|
+
a simple example:
|
7
|
+
|
8
|
+
DB.extension :provenance
|
9
|
+
|
10
|
+
DB[:table].
|
11
|
+
select(:a).
|
12
|
+
where{b > 10}.
|
13
|
+
order(:c).
|
14
|
+
limit(10)
|
15
|
+
# SQL:
|
16
|
+
# SELECT a FROM table WHERE (b > 10) ORDER BY c LIMIT 10 --
|
17
|
+
# -- Dataset Provenance
|
18
|
+
# -- Keys:[:from] Source:(eval at bin/sequel:257):2:in `<main>'
|
19
|
+
# -- Keys:[:select] Source:(eval at bin/sequel:257):3:in `<main>'
|
20
|
+
# -- Keys:[:where] Source:(eval at bin/sequel:257):4:in `<main>'
|
21
|
+
# -- Keys:[:order] Source:(eval at bin/sequel:257):5:in `<main>'
|
22
|
+
# -- Keys:[:limit] Source:(eval at bin/sequel:257):6:in `<main>'
|
23
|
+
|
24
|
+
With the above example, it's obvious how the dataset is created, but
|
25
|
+
but in real applications, where datasets can be built from multiple
|
26
|
+
files, seeing where each dataset clone was made can be helpful.
|
27
|
+
|
28
|
+
The source listed will skip locations in the Ruby standard library
|
29
|
+
as well as Sequel itself. Other locations can be skipped by
|
30
|
+
providing a Database :provenance_caller_ignore Regexp option:
|
31
|
+
|
32
|
+
DB.opts[:provenance_caller_ignore] = /\/gems\/library_name-/
|
33
|
+
|
34
|
+
= Other Improvements
|
35
|
+
|
36
|
+
* For dataset methods where Sequel can determine that the return
|
37
|
+
value would be equivalent to the receiver, Sequel now returns the
|
38
|
+
receiver. This reduces the number of dataset allocations.
|
39
|
+
|
40
|
+
* Sequel now supports Dataset#skip_locked on MariaDB 10.6+.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A temporarily_release_connection Database extension has been added,
|
4
|
+
designed for multithreaded transactional testing.
|
5
|
+
|
6
|
+
This allows one thread to start a transaction, and then release
|
7
|
+
the connection back for usage by the connection pool, so that
|
8
|
+
other threads can operate on the connection object safely inside
|
9
|
+
the transaction. This requires the connection pool be limited
|
10
|
+
to a single connection, to ensure that the released connection
|
11
|
+
can be reacquired. It's not perfect, because if the connection
|
12
|
+
is disconnected and removed from the pool while temporarily
|
13
|
+
released, there is no way to handle that situation correctly.
|
14
|
+
Example:
|
15
|
+
|
16
|
+
DB.transaction(rollback: :always, auto_savepoint: true) do |conn|
|
17
|
+
DB.temporarily_release_connection(conn) do
|
18
|
+
# Other threads can operate on connection safely inside
|
19
|
+
# the transaction
|
20
|
+
yield
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
= Other Improvements
|
25
|
+
|
26
|
+
* In the caller_logging and provenance extensions, Ruby internal
|
27
|
+
caller locations are skipped when trying to locate the appropriate
|
28
|
+
caller line to include.
|
29
|
+
|
30
|
+
* A couple ignored block warnings in plugin apply methods have been
|
31
|
+
fixed on Ruby 3.4.
|
@@ -926,9 +926,9 @@ module Sequel
|
|
926
926
|
(type == :insert && db.mariadb? && db.adapter_scheme != :jdbc) ? (db.server_version >= 100500) : false
|
927
927
|
end
|
928
928
|
|
929
|
-
# MySQL 8+
|
929
|
+
# MySQL 8+ and MariaDB 10.6+ support SKIP LOCKED.
|
930
930
|
def supports_skip_locked?
|
931
|
-
|
931
|
+
db.server_version >= (db.mariadb? ? 100600 : 80000)
|
932
932
|
end
|
933
933
|
|
934
934
|
# Check the database setting for whether fractional timestamps
|
data/lib/sequel/dataset/graph.rb
CHANGED
data/lib/sequel/dataset/query.rb
CHANGED
@@ -129,6 +129,7 @@ module Sequel
|
|
129
129
|
def distinct(*args, &block)
|
130
130
|
virtual_row_columns(args, block)
|
131
131
|
if args.empty?
|
132
|
+
return self if opts[:distinct] == EMPTY_ARRAY
|
132
133
|
cached_dataset(:_distinct_ds){clone(:distinct => EMPTY_ARRAY)}
|
133
134
|
else
|
134
135
|
raise(InvalidOperation, "DISTINCT ON not supported") unless supports_distinct_on?
|
@@ -230,6 +231,7 @@ module Sequel
|
|
230
231
|
#
|
231
232
|
# DB[:table].for_update # SELECT * FROM table FOR UPDATE
|
232
233
|
def for_update
|
234
|
+
return self if opts[:lock] == :update
|
233
235
|
cached_dataset(:_for_update_ds){lock_style(:update)}
|
234
236
|
end
|
235
237
|
|
@@ -641,6 +643,7 @@ module Sequel
|
|
641
643
|
# DB.from(:a, DB[:b].where(Sequel[:a][:c]=>Sequel[:b][:d]).lateral)
|
642
644
|
# # SELECT * FROM a, LATERAL (SELECT * FROM b WHERE (a.c = b.d))
|
643
645
|
def lateral
|
646
|
+
return self if opts[:lateral]
|
644
647
|
cached_dataset(:_lateral_ds){clone(:lateral=>true)}
|
645
648
|
end
|
646
649
|
|
@@ -744,6 +747,7 @@ module Sequel
|
|
744
747
|
# ds.all # => [{2=>:id}]
|
745
748
|
# ds.naked.all # => [{:id=>2}]
|
746
749
|
def naked
|
750
|
+
return self unless opts[:row_proc]
|
747
751
|
cached_dataset(:_naked_ds){with_row_proc(nil)}
|
748
752
|
end
|
749
753
|
|
@@ -753,6 +757,7 @@ module Sequel
|
|
753
757
|
# DB[:items].for_update.nowait
|
754
758
|
# # SELECT * FROM items FOR UPDATE NOWAIT
|
755
759
|
def nowait
|
760
|
+
return self if opts[:nowait]
|
756
761
|
cached_dataset(:_nowait_ds) do
|
757
762
|
raise(Error, 'This dataset does not support raises errors instead of waiting for locked rows') unless supports_nowait?
|
758
763
|
clone(:nowait=>true)
|
@@ -878,6 +883,7 @@ module Sequel
|
|
878
883
|
# end
|
879
884
|
def returning(*values)
|
880
885
|
if values.empty?
|
886
|
+
return self if opts[:returning] == EMPTY_ARRAY
|
881
887
|
cached_dataset(:_returning_ds) do
|
882
888
|
raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
|
883
889
|
clone(:returning=>EMPTY_ARRAY)
|
@@ -930,6 +936,7 @@ module Sequel
|
|
930
936
|
# DB[:items].select_all(:items, :foo) # SELECT items.*, foo.* FROM items
|
931
937
|
def select_all(*tables)
|
932
938
|
if tables.empty?
|
939
|
+
return self unless opts[:select]
|
933
940
|
cached_dataset(:_select_all_ds){clone(:select => nil)}
|
934
941
|
else
|
935
942
|
select(*tables.map{|t| i, a = split_alias(t); a || i}.map!{|t| SQL::ColumnAll.new(t)}.freeze)
|
@@ -1005,6 +1012,7 @@ module Sequel
|
|
1005
1012
|
|
1006
1013
|
# Specify that the check for limits/offsets when updating/deleting be skipped for the dataset.
|
1007
1014
|
def skip_limit_check
|
1015
|
+
return self if opts[:skip_limit_check]
|
1008
1016
|
cached_dataset(:_skip_limit_check_ds) do
|
1009
1017
|
clone(:skip_limit_check=>true)
|
1010
1018
|
end
|
@@ -1012,6 +1020,7 @@ module Sequel
|
|
1012
1020
|
|
1013
1021
|
# Skip locked rows when returning results from this dataset.
|
1014
1022
|
def skip_locked
|
1023
|
+
return self if opts[:skip_locked]
|
1015
1024
|
cached_dataset(:_skip_locked_ds) do
|
1016
1025
|
raise(Error, 'This dataset does not support skipping locked rows') unless supports_skip_locked?
|
1017
1026
|
clone(:skip_locked=>true)
|
@@ -1023,6 +1032,7 @@ module Sequel
|
|
1023
1032
|
# DB[:items].group(:a).having(a: 1).where(:b).unfiltered
|
1024
1033
|
# # SELECT * FROM items GROUP BY a
|
1025
1034
|
def unfiltered
|
1035
|
+
return self unless opts[:where] || opts[:having]
|
1026
1036
|
cached_dataset(:_unfiltered_ds){clone(:where => nil, :having => nil)}
|
1027
1037
|
end
|
1028
1038
|
|
@@ -1031,6 +1041,7 @@ module Sequel
|
|
1031
1041
|
# DB[:items].group(:a).having(a: 1).where(:b).ungrouped
|
1032
1042
|
# # SELECT * FROM items WHERE b
|
1033
1043
|
def ungrouped
|
1044
|
+
return self unless opts[:group] || opts[:having]
|
1034
1045
|
cached_dataset(:_ungrouped_ds){clone(:group => nil, :having => nil)}
|
1035
1046
|
end
|
1036
1047
|
|
@@ -1058,6 +1069,7 @@ module Sequel
|
|
1058
1069
|
#
|
1059
1070
|
# DB[:items].limit(10, 20).unlimited # SELECT * FROM items
|
1060
1071
|
def unlimited
|
1072
|
+
return self unless opts[:limit] || opts[:offset]
|
1061
1073
|
cached_dataset(:_unlimited_ds){clone(:limit=>nil, :offset=>nil)}
|
1062
1074
|
end
|
1063
1075
|
|
@@ -1065,6 +1077,7 @@ module Sequel
|
|
1065
1077
|
#
|
1066
1078
|
# DB[:items].order(:a).unordered # SELECT * FROM items
|
1067
1079
|
def unordered
|
1080
|
+
return self unless opts[:order]
|
1068
1081
|
cached_dataset(:_unordered_ds){clone(:order=>nil)}
|
1069
1082
|
end
|
1070
1083
|
|
@@ -36,6 +36,8 @@ require 'rbconfig'
|
|
36
36
|
module Sequel
|
37
37
|
module CallerLogging
|
38
38
|
SEQUEL_LIB_PATH = (File.expand_path('../../..', __FILE__) + '/').freeze
|
39
|
+
RUBY_STDLIB = RbConfig::CONFIG["rubylibdir"]
|
40
|
+
INTERNAL = '<internal'
|
39
41
|
|
40
42
|
# A regexp of caller lines to ignore, in addition to internal Sequel and Ruby code.
|
41
43
|
attr_accessor :caller_logging_ignore
|
@@ -59,7 +61,8 @@ module Sequel
|
|
59
61
|
ignore = caller_logging_ignore
|
60
62
|
c = caller.find do |line|
|
61
63
|
!(line.start_with?(SEQUEL_LIB_PATH) ||
|
62
|
-
line.start_with?(
|
64
|
+
line.start_with?(RUBY_STDLIB) ||
|
65
|
+
line.start_with?(INTERNAL) ||
|
63
66
|
(ignore && line =~ ignore))
|
64
67
|
end
|
65
68
|
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
#
|
3
|
+
# The provenance dataset extension tracks the locations of all
|
4
|
+
# dataset clones that resulted in the current dataset, and includes
|
5
|
+
# the information as a comment in the dataset's SQL. This makes it
|
6
|
+
# possible to see how a query was built, which can aid debugging.
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# DB[:table].
|
10
|
+
# select(:a).
|
11
|
+
# where{b > 10}.
|
12
|
+
# order(:c).
|
13
|
+
# limit(10)
|
14
|
+
# # SQL:
|
15
|
+
# # SELECT a FROM table WHERE (b > 10) ORDER BY c LIMIT 10 --
|
16
|
+
# # -- Dataset Provenance
|
17
|
+
# # -- Keys:[:from] Source:(eval at bin/sequel:257):2:in `<main>'
|
18
|
+
# # -- Keys:[:select] Source:(eval at bin/sequel:257):3:in `<main>'
|
19
|
+
# # -- Keys:[:where] Source:(eval at bin/sequel:257):4:in `<main>'
|
20
|
+
# # -- Keys:[:order] Source:(eval at bin/sequel:257):5:in `<main>'
|
21
|
+
# # -- Keys:[:limit] Source:(eval at bin/sequel:257):6:in `<main>'
|
22
|
+
#
|
23
|
+
# With the above example, the source is fairly obvious and not helpful,
|
24
|
+
# but in real applications, where datasets can be built from multiple
|
25
|
+
# files, seeing where each dataset clone was made can be helpful.
|
26
|
+
#
|
27
|
+
# The Source listed will skip locations in the Ruby standard library
|
28
|
+
# as well as Sequel itself. Other locations can be skipped by
|
29
|
+
# providing a Database :provenance_caller_ignore Regexp option:
|
30
|
+
#
|
31
|
+
# DB.opts[:provenance_caller_ignore] = /\/gems\/library_name-/
|
32
|
+
#
|
33
|
+
# Related module: Sequel::Dataset::Provenance
|
34
|
+
|
35
|
+
#
|
36
|
+
module Sequel
|
37
|
+
class Dataset
|
38
|
+
module Provenance
|
39
|
+
SEQUEL_LIB_PATH = (File.expand_path('../../..', __FILE__) + '/').freeze
|
40
|
+
RUBY_STDLIB = RbConfig::CONFIG["rubylibdir"]
|
41
|
+
INTERNAL = '<internal'
|
42
|
+
|
43
|
+
if TRUE_FREEZE
|
44
|
+
# Include provenance information when cloning datasets.
|
45
|
+
def clone(opts = nil || (return self))
|
46
|
+
super(provenance_opts(opts))
|
47
|
+
end
|
48
|
+
else
|
49
|
+
# :nocov:
|
50
|
+
def clone(opts = OPTS) # :nodoc:
|
51
|
+
super(provenance_opts(opts))
|
52
|
+
end
|
53
|
+
# :nocov:
|
54
|
+
end
|
55
|
+
|
56
|
+
%w'select insert update delete'.each do |type|
|
57
|
+
# Include the provenance information as a comment when preparing dataset SQL
|
58
|
+
define_method(:"#{type}_sql") do |*a|
|
59
|
+
sql = super(*a)
|
60
|
+
|
61
|
+
if provenance = @opts[:provenance]
|
62
|
+
comment = provenance.map do |hash|
|
63
|
+
" -- Keys:#{hash[:keys].inspect} Source:#{hash[:source]}".to_s.gsub(/\s+/, ' ')
|
64
|
+
end
|
65
|
+
comment << ""
|
66
|
+
comment.unshift " -- Dataset Provenance"
|
67
|
+
comment.unshift " -- "
|
68
|
+
comment = comment.join("\n")
|
69
|
+
|
70
|
+
if sql.frozen?
|
71
|
+
sql += comment
|
72
|
+
sql.freeze
|
73
|
+
elsif @opts[:append_sql] || @opts[:placeholder_literalizer]
|
74
|
+
sql << comment
|
75
|
+
else
|
76
|
+
sql += comment
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
sql
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Return a copy of opts with provenance information added.
|
87
|
+
def provenance_opts(opts)
|
88
|
+
provenance = {source: provenance_source, keys: opts.keys.freeze}.freeze
|
89
|
+
opts = opts.dup
|
90
|
+
opts[:provenance] = ((@opts[:provenance] || EMPTY_ARRAY).dup << provenance).freeze
|
91
|
+
opts
|
92
|
+
end
|
93
|
+
|
94
|
+
# Return the caller line for the provenance change. This skips
|
95
|
+
# Sequel itself and the standard library. Additional locations
|
96
|
+
# can be skipped using the :provenance_caller_ignore Dataset option.
|
97
|
+
def provenance_source
|
98
|
+
ignore = db.opts[:provenance_caller_ignore]
|
99
|
+
caller.find do |line|
|
100
|
+
!(line.start_with?(SEQUEL_LIB_PATH) ||
|
101
|
+
line.start_with?(RUBY_STDLIB) ||
|
102
|
+
line.start_with?(INTERNAL) ||
|
103
|
+
(ignore && line =~ ignore))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
register_extension(:provenance, Provenance)
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
#
|
3
|
+
# The temporarily_release_connection extension adds support for temporarily
|
4
|
+
# releasing a checked out connection back to the connection pool. It is
|
5
|
+
# designed for use in multithreaded transactional integration tests, allowing
|
6
|
+
# a connection to start a transaction in one thread, but be temporarily
|
7
|
+
# released back to the connection pool, so it can be operated on safely
|
8
|
+
# by multiple threads inside a block. For example, the main thread could be
|
9
|
+
# running tests that send web requests, and a separate thread running a web
|
10
|
+
# server that is responding to those requests, and the same connection and
|
11
|
+
# transaction would be used for both.
|
12
|
+
#
|
13
|
+
# To load the extension into the database:
|
14
|
+
#
|
15
|
+
# DB.extension :temporarily_release_connection
|
16
|
+
#
|
17
|
+
# After the extension is loaded, call the +temporarily_release_connection+
|
18
|
+
# method with the connection object to temporarily release the connection
|
19
|
+
# back to the pool. Example:
|
20
|
+
#
|
21
|
+
# DB.transaction(rollback: :always, auto_savepoint: true) do |conn|
|
22
|
+
# DB.temporarily_release_connection(conn) do
|
23
|
+
# # Other threads can operate on connection safely inside the transaction
|
24
|
+
# yield
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# For sharded connection pools, the second argument to +temporarily_release_connection+
|
29
|
+
# is respected, and specifies the server on which to temporarily release the connection.
|
30
|
+
#
|
31
|
+
# The temporarily_release_connection extension is only supported with the
|
32
|
+
# threaded and timed_queue connection pools that ship with Sequel (and the sharded
|
33
|
+
# versions of each). To make sure that same connection object can be reacquired, it
|
34
|
+
# is only supported if the maximum connection pool size is 1, so set the Database
|
35
|
+
# :max_connections option to 1 if you plan to use this extension.
|
36
|
+
#
|
37
|
+
# If the +temporarily_release_connection+ method cannot reacquire the same connection
|
38
|
+
# it released to the pool, it will raise a Sequel::UnableToReacquireConnectionError
|
39
|
+
# exception. This should only happen if the connection has been disconnected
|
40
|
+
# while it was temporarily released. If this error is raised, Database#transaction
|
41
|
+
# will not rollback the transaction, since the connection object is likely no longer
|
42
|
+
# valid, and on poorly written database drivers, that could cause the process to crash.
|
43
|
+
#
|
44
|
+
# Related modules: Sequel::TemporarilyReleaseConnection,
|
45
|
+
# Sequel::UnableToReacquireConnectionError
|
46
|
+
|
47
|
+
#
|
48
|
+
module Sequel
|
49
|
+
# Error class raised if the connection pool does not provide the same connection
|
50
|
+
# object when checking a temporarily released connection out.
|
51
|
+
class UnableToReacquireConnectionError < Error
|
52
|
+
end
|
53
|
+
|
54
|
+
module TemporarilyReleaseConnection
|
55
|
+
module DatabaseMethods
|
56
|
+
# Temporarily release the connection back to the connection pool for the
|
57
|
+
# duration of the block.
|
58
|
+
def temporarily_release_connection(conn, server=:default, &block)
|
59
|
+
pool.temporarily_release_connection(conn, server, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Do nothing if UnableToReacquireConnectionError is raised, as it is
|
65
|
+
# likely the connection is not in a usable state.
|
66
|
+
def rollback_transaction(conn, opts)
|
67
|
+
return if UnableToReacquireConnectionError === $!
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module PoolMethods
|
73
|
+
# Temporarily release a currently checked out connection, then yield to the block. Reacquire the same
|
74
|
+
# connection upon the exit of the block.
|
75
|
+
def temporarily_release_connection(conn, server)
|
76
|
+
t = Sequel.current
|
77
|
+
raise Error, "connection not currently checked out" unless conn.equal?(trc_owned_connection(t, server))
|
78
|
+
|
79
|
+
begin
|
80
|
+
trc_release(t, conn, server)
|
81
|
+
yield
|
82
|
+
ensure
|
83
|
+
c = trc_acquire(t, server)
|
84
|
+
unless conn.equal?(c)
|
85
|
+
raise UnableToReacquireConnectionError, "reacquired connection not the same as initial connection"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
module TimedQueue
|
92
|
+
private
|
93
|
+
|
94
|
+
def trc_owned_connection(t, server)
|
95
|
+
owned_connection(t)
|
96
|
+
end
|
97
|
+
|
98
|
+
def trc_release(t, conn, server)
|
99
|
+
release(t)
|
100
|
+
end
|
101
|
+
|
102
|
+
def trc_acquire(t, server)
|
103
|
+
acquire(t)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
module ShardedTimedQueue
|
108
|
+
# Normalize the server name for sharded connection pools
|
109
|
+
def temporarily_release_connection(conn, server)
|
110
|
+
server = pick_server(server)
|
111
|
+
super
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def trc_owned_connection(t, server)
|
117
|
+
owned_connection(t, server)
|
118
|
+
end
|
119
|
+
|
120
|
+
def trc_release(t, conn, server)
|
121
|
+
release(t, conn, server)
|
122
|
+
end
|
123
|
+
|
124
|
+
def trc_acquire(t, server)
|
125
|
+
acquire(t, server)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
module ThreadedBase
|
130
|
+
private
|
131
|
+
|
132
|
+
def trc_release(t, conn, server)
|
133
|
+
sync{super}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
module Threaded
|
138
|
+
include TimedQueue
|
139
|
+
include ThreadedBase
|
140
|
+
end
|
141
|
+
|
142
|
+
module ShardedThreaded
|
143
|
+
include ShardedTimedQueue
|
144
|
+
include ThreadedBase
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
trc = TemporarilyReleaseConnection
|
149
|
+
trc_map = {
|
150
|
+
:threaded => trc::Threaded,
|
151
|
+
:sharded_threaded => trc::ShardedThreaded,
|
152
|
+
:timed_queue => trc::TimedQueue,
|
153
|
+
:sharded_timed_queue => trc::ShardedTimedQueue,
|
154
|
+
}.freeze
|
155
|
+
|
156
|
+
Database.register_extension(:temporarily_release_connection) do |db|
|
157
|
+
unless pool_mod = trc_map[db.pool.pool_type]
|
158
|
+
raise(Error, "temporarily_release_connection extension not supported for connection pool type #{db.pool.pool_type}")
|
159
|
+
end
|
160
|
+
|
161
|
+
case db.pool.pool_type
|
162
|
+
when :threaded, :sharded_threaded
|
163
|
+
if db.opts[:connection_handling] == :disconnect
|
164
|
+
raise Error, "temporarily_release_connection extension not supported with connection_handling: :disconnect option"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
unless db.pool.max_size == 1
|
169
|
+
raise Error, "temporarily_release_connection extension not supported unless :max_connections option is 1"
|
170
|
+
end
|
171
|
+
|
172
|
+
db.extend(trc::DatabaseMethods)
|
173
|
+
db.pool.extend(trc::PoolMethods)
|
174
|
+
db.pool.extend(pool_mod)
|
175
|
+
end
|
176
|
+
|
177
|
+
private_constant :TemporarilyReleaseConnection
|
178
|
+
end
|
@@ -24,7 +24,7 @@ module Sequel
|
|
24
24
|
# # Make the Album class support input transformers
|
25
25
|
# Album.plugin :input_transformer
|
26
26
|
module InputTransformer
|
27
|
-
def self.apply(model,
|
27
|
+
def self.apply(model, *, &_)
|
28
28
|
model.instance_exec do
|
29
29
|
@input_transformers = {}
|
30
30
|
@skip_input_transformer_columns = {}
|
data/lib/sequel/version.rb
CHANGED
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
8
8
|
# release, generally around once a month.
|
9
|
-
MINOR =
|
9
|
+
MINOR = 81
|
10
10
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
12
12
|
# releases that fix regressions from previous versions.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.81.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bigdecimal
|
@@ -227,6 +227,8 @@ extra_rdoc_files:
|
|
227
227
|
- doc/release_notes/5.78.0.txt
|
228
228
|
- doc/release_notes/5.79.0.txt
|
229
229
|
- doc/release_notes/5.8.0.txt
|
230
|
+
- doc/release_notes/5.80.0.txt
|
231
|
+
- doc/release_notes/5.81.0.txt
|
230
232
|
- doc/release_notes/5.9.0.txt
|
231
233
|
files:
|
232
234
|
- CHANGELOG
|
@@ -334,6 +336,8 @@ files:
|
|
334
336
|
- doc/release_notes/5.78.0.txt
|
335
337
|
- doc/release_notes/5.79.0.txt
|
336
338
|
- doc/release_notes/5.8.0.txt
|
339
|
+
- doc/release_notes/5.80.0.txt
|
340
|
+
- doc/release_notes/5.81.0.txt
|
337
341
|
- doc/release_notes/5.9.0.txt
|
338
342
|
- doc/schema_modification.rdoc
|
339
343
|
- doc/security.rdoc
|
@@ -496,6 +500,7 @@ files:
|
|
496
500
|
- lib/sequel/extensions/pg_static_cache_updater.rb
|
497
501
|
- lib/sequel/extensions/pg_timestamptz.rb
|
498
502
|
- lib/sequel/extensions/pretty_table.rb
|
503
|
+
- lib/sequel/extensions/provenance.rb
|
499
504
|
- lib/sequel/extensions/query.rb
|
500
505
|
- lib/sequel/extensions/round_timestamps.rb
|
501
506
|
- lib/sequel/extensions/run_transaction_hooks.rb
|
@@ -519,6 +524,7 @@ files:
|
|
519
524
|
- lib/sequel/extensions/symbol_as.rb
|
520
525
|
- lib/sequel/extensions/symbol_as_refinement.rb
|
521
526
|
- lib/sequel/extensions/synchronize_sql.rb
|
527
|
+
- lib/sequel/extensions/temporarily_release_connection.rb
|
522
528
|
- lib/sequel/extensions/thread_local_timezones.rb
|
523
529
|
- lib/sequel/extensions/to_dot.rb
|
524
530
|
- lib/sequel/extensions/transaction_connection_validator.rb
|
@@ -666,7 +672,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
666
672
|
- !ruby/object:Gem::Version
|
667
673
|
version: '0'
|
668
674
|
requirements: []
|
669
|
-
rubygems_version: 3.5.
|
675
|
+
rubygems_version: 3.5.9
|
670
676
|
signing_key:
|
671
677
|
specification_version: 4
|
672
678
|
summary: The Database Toolkit for Ruby
|