sequel 5.45.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.
- checksums.yaml +4 -4
- data/CHANGELOG +434 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +59 -27
- data/bin/sequel +11 -3
- data/doc/advanced_associations.rdoc +16 -14
- data/doc/association_basics.rdoc +119 -24
- data/doc/cheat_sheet.rdoc +11 -3
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +27 -6
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +28 -12
- data/doc/postgresql.rdoc +16 -8
- data/doc/querying.rdoc +5 -3
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/release_notes/5.50.0.txt +78 -0
- data/doc/release_notes/5.51.0.txt +47 -0
- data/doc/release_notes/5.52.0.txt +87 -0
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/release_notes/5.57.0.txt +23 -0
- data/doc/release_notes/5.58.0.txt +31 -0
- 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/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +9 -9
- data/doc/sharding.rdoc +3 -1
- data/doc/sql.rdoc +27 -15
- data/doc/testing.rdoc +23 -13
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/ibmdb.rb +3 -3
- data/lib/sequel/adapters/jdbc/derby.rb +8 -0
- data/lib/sequel/adapters/jdbc/h2.rb +63 -10
- data/lib/sequel/adapters/jdbc/hsqldb.rb +8 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +7 -4
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +15 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +24 -22
- data/lib/sequel/adapters/mysql.rb +92 -67
- data/lib/sequel/adapters/mysql2.rb +56 -51
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +4 -3
- data/lib/sequel/adapters/postgres.rb +89 -45
- data/lib/sequel/adapters/shared/access.rb +11 -1
- data/lib/sequel/adapters/shared/db2.rb +42 -0
- data/lib/sequel/adapters/shared/mssql.rb +91 -10
- data/lib/sequel/adapters/shared/mysql.rb +78 -3
- data/lib/sequel/adapters/shared/oracle.rb +86 -7
- data/lib/sequel/adapters/shared/postgres.rb +576 -171
- data/lib/sequel/adapters/shared/sqlanywhere.rb +21 -5
- data/lib/sequel/adapters/shared/sqlite.rb +92 -8
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +99 -18
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/adapters/trilogy.rb +117 -0
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -7
- 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/single.rb +6 -8
- 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/core.rb +17 -18
- data/lib/sequel/database/connecting.rb +27 -3
- data/lib/sequel/database/dataset.rb +16 -6
- data/lib/sequel/database/misc.rb +70 -14
- data/lib/sequel/database/query.rb +73 -2
- data/lib/sequel/database/schema_generator.rb +11 -6
- data/lib/sequel/database/schema_methods.rb +23 -4
- data/lib/sequel/database/transactions.rb +6 -0
- data/lib/sequel/dataset/actions.rb +111 -15
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
- data/lib/sequel/dataset/features.rb +20 -1
- data/lib/sequel/dataset/misc.rb +12 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
- data/lib/sequel/dataset/query.rb +170 -41
- data/lib/sequel/dataset/sql.rb +190 -71
- data/lib/sequel/dataset.rb +4 -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 +14 -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/core_refinements.rb +36 -11
- data/lib/sequel/extensions/date_arithmetic.rb +36 -8
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +11 -10
- data/lib/sequel/extensions/index_caching.rb +5 -1
- data/lib/sequel/extensions/inflector.rb +1 -1
- data/lib/sequel/extensions/is_distinct_from.rb +141 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/migration.rb +57 -15
- data/lib/sequel/extensions/named_timezones.rb +22 -6
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +33 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- 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 +39 -28
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +6 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
- data/lib/sequel/extensions/pg_inet.rb +10 -11
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +11 -11
- data/lib/sequel/extensions/pg_json.rb +13 -15
- data/lib/sequel/extensions/pg_json_ops.rb +125 -2
- data/lib/sequel/extensions/pg_multirange.rb +367 -0
- data/lib/sequel/extensions/pg_range.rb +13 -26
- data/lib/sequel/extensions/pg_range_ops.rb +37 -9
- data/lib/sequel/extensions/pg_row.rb +20 -19
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/pg_timestamptz.rb +27 -3
- data/lib/sequel/extensions/round_timestamps.rb +1 -1
- data/lib/sequel/extensions/s.rb +2 -1
- data/lib/sequel/extensions/schema_caching.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +45 -11
- data/lib/sequel/extensions/server_block.rb +10 -13
- data/lib/sequel/extensions/set_literalizer.rb +58 -0
- data/lib/sequel/extensions/sql_comments.rb +110 -3
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_agg.rb +1 -1
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- 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 +286 -92
- data/lib/sequel/model/base.rb +53 -33
- data/lib/sequel/model/dataset_module.rb +3 -0
- data/lib/sequel/model/errors.rb +10 -1
- data/lib/sequel/model/exceptions.rb +15 -3
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/auto_validations.rb +74 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/column_encryption.rb +29 -8
- data/lib/sequel/plugins/composition.rb +3 -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/enum.rb +124 -0
- data/lib/sequel/plugins/finder.rb +4 -2
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/instance_specific_default.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +3 -0
- data/lib/sequel/plugins/list.rb +8 -3
- data/lib/sequel/plugins/many_through_many.rb +109 -10
- 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_array_associations.rb +46 -34
- 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 +12 -2
- 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/serialization.rb +1 -0
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +39 -1
- data/lib/sequel/plugins/static_cache_cache.rb +5 -1
- data/lib/sequel/plugins/subclasses.rb +28 -11
- data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validate_associated.rb +22 -12
- data/lib/sequel/plugins/validation_helpers.rb +41 -11
- data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/timezones.rb +12 -14
- data/lib/sequel/version.rb +1 -1
- metadata +109 -19
@@ -0,0 +1,270 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
# :nocov:
|
4
|
+
raise LoadError, "Sequel::TimedQueueConnectionPool is only available on Ruby 3.2+" unless RUBY_VERSION >= '3.2'
|
5
|
+
# :nocov:
|
6
|
+
|
7
|
+
# A connection pool allowing multi-threaded access to a pool of connections,
|
8
|
+
# using a timed queue (only available in Ruby 3.2+).
|
9
|
+
class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
|
10
|
+
# The maximum number of connections this pool will create.
|
11
|
+
attr_reader :max_size
|
12
|
+
|
13
|
+
# The following additional options are respected:
|
14
|
+
# :max_connections :: The maximum number of connections the connection pool
|
15
|
+
# will open (default 4)
|
16
|
+
# :pool_timeout :: The amount of seconds to wait to acquire a connection
|
17
|
+
# before raising a PoolTimeout (default 5)
|
18
|
+
def initialize(db, opts = OPTS)
|
19
|
+
super
|
20
|
+
@max_size = Integer(opts[:max_connections] || 4)
|
21
|
+
raise(Sequel::Error, ':max_connections must be positive') if @max_size < 1
|
22
|
+
@mutex = Mutex.new
|
23
|
+
# Size inside array so this still works while the pool is frozen.
|
24
|
+
@size = [0]
|
25
|
+
@allocated = {}
|
26
|
+
@allocated.compare_by_identity
|
27
|
+
@timeout = Float(opts[:pool_timeout] || 5)
|
28
|
+
@queue = Queue.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# Yield all of the available connections, and the one currently allocated to
|
32
|
+
# this thread. This will not yield connections currently allocated to other
|
33
|
+
# threads, as it is not safe to operate on them.
|
34
|
+
def all_connections
|
35
|
+
hold do |conn|
|
36
|
+
yield conn
|
37
|
+
|
38
|
+
# Use a hash to record all connections already seen. As soon as we
|
39
|
+
# come across a connection we've already seen, we stop the loop.
|
40
|
+
conns = {}
|
41
|
+
conns.compare_by_identity
|
42
|
+
while true
|
43
|
+
conn = nil
|
44
|
+
begin
|
45
|
+
break unless (conn = @queue.pop(timeout: 0)) && !conns[conn]
|
46
|
+
conns[conn] = true
|
47
|
+
yield conn
|
48
|
+
ensure
|
49
|
+
@queue.push(conn) if conn
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Removes all connections currently in the pool's queue. This method has the effect of
|
56
|
+
# disconnecting from the database, assuming that no connections are currently
|
57
|
+
# being used.
|
58
|
+
#
|
59
|
+
# Once a connection is requested using #hold, the connection pool
|
60
|
+
# creates new connections to the database.
|
61
|
+
def disconnect(opts=OPTS)
|
62
|
+
while conn = @queue.pop(timeout: 0)
|
63
|
+
disconnect_connection(conn)
|
64
|
+
end
|
65
|
+
fill_queue
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# Chooses the first available connection, or if none are
|
70
|
+
# available, creates a new connection. Passes the connection to the supplied
|
71
|
+
# block:
|
72
|
+
#
|
73
|
+
# pool.hold {|conn| conn.execute('DROP TABLE posts')}
|
74
|
+
#
|
75
|
+
# Pool#hold is re-entrant, meaning it can be called recursively in
|
76
|
+
# the same thread without blocking.
|
77
|
+
#
|
78
|
+
# If no connection is immediately available and the pool is already using the maximum
|
79
|
+
# number of connections, Pool#hold will block until a connection
|
80
|
+
# is available or the timeout expires. If the timeout expires before a
|
81
|
+
# connection can be acquired, a Sequel::PoolTimeout is raised.
|
82
|
+
def hold(server=nil)
|
83
|
+
t = Sequel.current
|
84
|
+
if conn = owned_connection(t)
|
85
|
+
return yield(conn)
|
86
|
+
end
|
87
|
+
|
88
|
+
begin
|
89
|
+
conn = acquire(t)
|
90
|
+
yield conn
|
91
|
+
rescue Sequel::DatabaseDisconnectError, *@error_classes => e
|
92
|
+
if disconnect_error?(e)
|
93
|
+
oconn = conn
|
94
|
+
conn = nil
|
95
|
+
disconnect_connection(oconn) if oconn
|
96
|
+
sync{@allocated.delete(t)}
|
97
|
+
fill_queue
|
98
|
+
end
|
99
|
+
raise
|
100
|
+
ensure
|
101
|
+
release(t) if conn
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def pool_type
|
106
|
+
:timed_queue
|
107
|
+
end
|
108
|
+
|
109
|
+
# The total number of connections in the pool.
|
110
|
+
def size
|
111
|
+
sync{@size[0]}
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
# Create a new connection, after the pool's current size has already
|
117
|
+
# been updated to account for the new connection. If there is an exception
|
118
|
+
# when creating the connection, decrement the current size.
|
119
|
+
#
|
120
|
+
# This should only be called after can_make_new?. If there is an exception
|
121
|
+
# between when can_make_new? is called and when preallocated_make_new
|
122
|
+
# is called, it has the effect of reducing the maximum size of the
|
123
|
+
# connection pool by 1, since the current size of the pool will show a
|
124
|
+
# higher number than the number of connections allocated or
|
125
|
+
# in the queue.
|
126
|
+
#
|
127
|
+
# Calling code should not have the mutex when calling this.
|
128
|
+
def preallocated_make_new
|
129
|
+
make_new(:default)
|
130
|
+
rescue Exception
|
131
|
+
sync{@size[0] -= 1}
|
132
|
+
raise
|
133
|
+
end
|
134
|
+
|
135
|
+
# Decrement the current size of the pool when disconnecting connections.
|
136
|
+
#
|
137
|
+
# Calling code should not have the mutex when calling this.
|
138
|
+
def disconnect_connection(conn)
|
139
|
+
sync{@size[0] -= 1}
|
140
|
+
super
|
141
|
+
end
|
142
|
+
|
143
|
+
# If there are any threads waiting on the queue, try to create
|
144
|
+
# new connections in a separate thread if the pool is not yet at the
|
145
|
+
# maximum size.
|
146
|
+
#
|
147
|
+
# The reason for this method is to handle cases where acquire
|
148
|
+
# could not retrieve a connection immediately, and the pool
|
149
|
+
# was already at the maximum size. In that case, the acquire will
|
150
|
+
# wait on the queue until the timeout. This method is called
|
151
|
+
# after disconnecting to potentially add new connections to the
|
152
|
+
# pool, so the threads that are currently waiting for connections
|
153
|
+
# do not timeout after the pool is no longer full.
|
154
|
+
def fill_queue
|
155
|
+
if @queue.num_waiting > 0
|
156
|
+
Thread.new do
|
157
|
+
while @queue.num_waiting > 0 && (conn = try_make_new)
|
158
|
+
@queue.push(conn)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Whether the given size is less than the maximum size of the pool.
|
165
|
+
# In that case, the pool's current size is incremented. If this
|
166
|
+
# method returns true, space in the pool for the connection is
|
167
|
+
# preallocated, and preallocated_make_new should be called to
|
168
|
+
# create the connection.
|
169
|
+
#
|
170
|
+
# Calling code should have the mutex when calling this.
|
171
|
+
def can_make_new?(current_size)
|
172
|
+
if @max_size > current_size
|
173
|
+
@size[0] += 1
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Try to make a new connection if there is space in the pool.
|
178
|
+
# If the pool is already full, look for dead threads/fibers and
|
179
|
+
# disconnect the related connections.
|
180
|
+
#
|
181
|
+
# Calling code should not have the mutex when calling this.
|
182
|
+
def try_make_new
|
183
|
+
return preallocated_make_new if sync{can_make_new?(@size[0])}
|
184
|
+
|
185
|
+
to_disconnect = nil
|
186
|
+
do_make_new = false
|
187
|
+
|
188
|
+
sync do
|
189
|
+
current_size = @size[0]
|
190
|
+
@allocated.keys.each do |t|
|
191
|
+
unless t.alive?
|
192
|
+
(to_disconnect ||= []) << @allocated.delete(t)
|
193
|
+
current_size -= 1
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
do_make_new = true if can_make_new?(current_size)
|
198
|
+
end
|
199
|
+
|
200
|
+
begin
|
201
|
+
preallocated_make_new if do_make_new
|
202
|
+
ensure
|
203
|
+
if to_disconnect
|
204
|
+
to_disconnect.each{|conn| disconnect_connection(conn)}
|
205
|
+
fill_queue
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Assigns a connection to the supplied thread, if one
|
211
|
+
# is available.
|
212
|
+
#
|
213
|
+
# This should return a connection is one is available within the timeout,
|
214
|
+
# or raise PoolTimeout if a connection could not be acquired within the timeout.
|
215
|
+
#
|
216
|
+
# Calling code should not have the mutex when calling this.
|
217
|
+
def acquire(thread)
|
218
|
+
if conn = @queue.pop(timeout: 0) || try_make_new || @queue.pop(timeout: @timeout)
|
219
|
+
sync{@allocated[thread] = conn}
|
220
|
+
else
|
221
|
+
name = db.opts[:name]
|
222
|
+
raise ::Sequel::PoolTimeout, "timeout: #{@timeout}#{", database name: #{name}" if name}"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# Returns the connection owned by the supplied thread,
|
227
|
+
# if any. The calling code should NOT already have the mutex before calling this.
|
228
|
+
def owned_connection(thread)
|
229
|
+
sync{@allocated[thread]}
|
230
|
+
end
|
231
|
+
|
232
|
+
# Create the maximum number of connections immediately. This should not be called
|
233
|
+
# with a true argument unless no code is currently operating on the database.
|
234
|
+
#
|
235
|
+
# Calling code should not have the mutex when calling this.
|
236
|
+
def preconnect(concurrent = false)
|
237
|
+
if concurrent
|
238
|
+
if times = sync{@max_size > (size = @size[0]) ? @max_size - size : false}
|
239
|
+
times.times.map{Thread.new{if conn = try_make_new; @queue.push(conn) end}}.map(&:value)
|
240
|
+
end
|
241
|
+
else
|
242
|
+
while conn = try_make_new
|
243
|
+
@queue.push(conn)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
nil
|
248
|
+
end
|
249
|
+
|
250
|
+
# Releases the connection assigned to the supplied thread back to the pool.
|
251
|
+
#
|
252
|
+
# Calling code should not have the mutex when calling this.
|
253
|
+
def release(thread)
|
254
|
+
checkin_connection(sync{@allocated.delete(thread)})
|
255
|
+
nil
|
256
|
+
end
|
257
|
+
|
258
|
+
# Adds a connection to the queue of available connections, returns the connection.
|
259
|
+
def checkin_connection(conn)
|
260
|
+
@queue.push(conn)
|
261
|
+
conn
|
262
|
+
end
|
263
|
+
|
264
|
+
# Yield to the block while inside the mutex.
|
265
|
+
#
|
266
|
+
# Calling code should not have the mutex when calling this.
|
267
|
+
def sync
|
268
|
+
@mutex.synchronize{yield}
|
269
|
+
end
|
270
|
+
end
|
@@ -30,8 +30,12 @@ class Sequel::ConnectionPool
|
|
30
30
|
:threaded => :ThreadedConnectionPool,
|
31
31
|
:single => :SingleConnectionPool,
|
32
32
|
:sharded_threaded => :ShardedThreadedConnectionPool,
|
33
|
-
:sharded_single => :ShardedSingleConnectionPool
|
34
|
-
|
33
|
+
:sharded_single => :ShardedSingleConnectionPool,
|
34
|
+
:timed_queue => :TimedQueueConnectionPool,
|
35
|
+
:sharded_timed_queue => :ShardedTimedQueueConnectionPool,
|
36
|
+
}
|
37
|
+
POOL_CLASS_MAP.to_a.each{|k, v| POOL_CLASS_MAP[k.to_s] = v}
|
38
|
+
POOL_CLASS_MAP.freeze
|
35
39
|
|
36
40
|
# Class methods used to return an appropriate pool subclass, separated
|
37
41
|
# into a module for easier overridding by extensions.
|
@@ -39,7 +43,8 @@ class Sequel::ConnectionPool
|
|
39
43
|
# Return a pool subclass instance based on the given options. If a <tt>:pool_class</tt>
|
40
44
|
# option is provided is provided, use that pool class, otherwise
|
41
45
|
# use a new instance of an appropriate pool subclass based on the
|
42
|
-
#
|
46
|
+
# +SEQUEL_DEFAULT_CONNECTION_POOL+ environment variable if set, or
|
47
|
+
# the <tt>:single_threaded</tt> and <tt>:servers</tt> options, otherwise.
|
43
48
|
def get_pool(db, opts = OPTS)
|
44
49
|
connection_pool_class(opts).new(db, opts)
|
45
50
|
end
|
@@ -59,9 +64,16 @@ class Sequel::ConnectionPool
|
|
59
64
|
end
|
60
65
|
|
61
66
|
pc
|
67
|
+
elsif pc = ENV['SEQUEL_DEFAULT_CONNECTION_POOL']
|
68
|
+
pc = "sharded_#{pc}" if opts[:servers] && !pc.start_with?('sharded_')
|
69
|
+
connection_pool_class(:pool_class=>pc)
|
62
70
|
else
|
63
71
|
pc = if opts[:single_threaded]
|
64
72
|
opts[:servers] ? :sharded_single : :single
|
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:
|
65
77
|
else
|
66
78
|
opts[:servers] ? :sharded_threaded : :threaded
|
67
79
|
end
|
@@ -74,26 +86,35 @@ class Sequel::ConnectionPool
|
|
74
86
|
|
75
87
|
# The after_connect proc used for this pool. This is called with each new
|
76
88
|
# connection made, and is usually used to set custom per-connection settings.
|
77
|
-
|
89
|
+
# Deprecated.
|
90
|
+
attr_reader :after_connect # SEQUEL6: Remove
|
91
|
+
|
92
|
+
# Override the after_connect proc for the connection pool. Deprecated.
|
93
|
+
# Disables support for shard-specific :after_connect and :connect_sqls if used.
|
94
|
+
def after_connect=(v) # SEQUEL6: Remove
|
95
|
+
@use_old_connect_api = true
|
96
|
+
@after_connect = v
|
97
|
+
end
|
78
98
|
|
79
|
-
# An array of sql strings to execute on each new connection.
|
80
|
-
|
99
|
+
# An array of sql strings to execute on each new connection. Deprecated.
|
100
|
+
attr_reader :connect_sqls # SEQUEL6: Remove
|
101
|
+
|
102
|
+
# Override the connect_sqls for the connection pool. Deprecated.
|
103
|
+
# Disables support for shard-specific :after_connect and :connect_sqls if used.
|
104
|
+
def connect_sqls=(v) # SEQUEL6: Remove
|
105
|
+
@use_old_connect_api = true
|
106
|
+
@connect_sqls = v
|
107
|
+
end
|
81
108
|
|
82
109
|
# The Sequel::Database object tied to this connection pool.
|
83
110
|
attr_accessor :db
|
84
111
|
|
85
|
-
# Instantiates a connection pool with the given options.
|
86
|
-
|
87
|
-
# connection is needed. The following options are respected for all connection
|
88
|
-
# pools:
|
89
|
-
# :after_connect :: A callable object called after each new connection is made, with the
|
90
|
-
# connection object (and server argument if the callable accepts 2 arguments),
|
91
|
-
# useful for customizations that you want to apply to all connections.
|
92
|
-
# :connect_sqls :: An array of sql strings to execute on each new connection, after :after_connect runs.
|
93
|
-
def initialize(db, opts=OPTS)
|
112
|
+
# Instantiates a connection pool with the given Database and options.
|
113
|
+
def initialize(db, opts=OPTS) # SEQUEL6: Remove second argument, always use db.opts
|
94
114
|
@db = db
|
95
|
-
@
|
96
|
-
@
|
115
|
+
@use_old_connect_api = false # SEQUEL6: Remove
|
116
|
+
@after_connect = opts[:after_connect] # SEQUEL6: Remove
|
117
|
+
@connect_sqls = opts[:connect_sqls] # SEQUEL6: Remove
|
97
118
|
@error_classes = db.send(:database_error_classes).dup.freeze
|
98
119
|
end
|
99
120
|
|
@@ -119,25 +140,30 @@ class Sequel::ConnectionPool
|
|
119
140
|
# and checking for connection errors.
|
120
141
|
def make_new(server)
|
121
142
|
begin
|
122
|
-
|
143
|
+
if @use_old_connect_api
|
144
|
+
# SEQUEL6: Remove block
|
145
|
+
conn = @db.connect(server)
|
123
146
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
147
|
+
if ac = @after_connect
|
148
|
+
if ac.arity == 2
|
149
|
+
ac.call(conn, server)
|
150
|
+
else
|
151
|
+
ac.call(conn)
|
152
|
+
end
|
129
153
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
154
|
+
|
155
|
+
if cs = @connect_sqls
|
156
|
+
cs.each do |sql|
|
157
|
+
db.send(:log_connection_execute, conn, sql)
|
158
|
+
end
|
135
159
|
end
|
160
|
+
|
161
|
+
conn
|
162
|
+
else
|
163
|
+
@db.new_connection(server)
|
136
164
|
end
|
137
165
|
rescue Exception=>exception
|
138
166
|
raise Sequel.convert_exception_class(exception, Sequel::DatabaseConnectionError)
|
139
|
-
end
|
140
|
-
raise(Sequel::DatabaseConnectionError, "Connection parameters not valid") unless conn
|
141
|
-
conn
|
167
|
+
end || raise(Sequel::DatabaseConnectionError, "Connection parameters not valid")
|
142
168
|
end
|
143
169
|
end
|
data/lib/sequel/core.rb
CHANGED
@@ -278,11 +278,9 @@ module Sequel
|
|
278
278
|
#
|
279
279
|
# Sequel.string_to_date('2010-09-10') # Date.civil(2010, 09, 10)
|
280
280
|
def string_to_date(string)
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
raise convert_exception_class(e, InvalidValue)
|
285
|
-
end
|
281
|
+
Date.parse(string, Sequel.convert_two_digit_years)
|
282
|
+
rescue => e
|
283
|
+
raise convert_exception_class(e, InvalidValue)
|
286
284
|
end
|
287
285
|
|
288
286
|
# Converts the given +string+ into a +Time+ or +DateTime+ object, depending on the
|
@@ -290,15 +288,13 @@ module Sequel
|
|
290
288
|
#
|
291
289
|
# Sequel.string_to_datetime('2010-09-10 10:20:30') # Time.local(2010, 09, 10, 10, 20, 30)
|
292
290
|
def string_to_datetime(string)
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
datetime_class.parse(string)
|
298
|
-
end
|
299
|
-
rescue => e
|
300
|
-
raise convert_exception_class(e, InvalidValue)
|
291
|
+
if datetime_class == DateTime
|
292
|
+
DateTime.parse(string, convert_two_digit_years)
|
293
|
+
else
|
294
|
+
datetime_class.parse(string)
|
301
295
|
end
|
296
|
+
rescue => e
|
297
|
+
raise convert_exception_class(e, InvalidValue)
|
302
298
|
end
|
303
299
|
|
304
300
|
# Converts the given +string+ into a <tt>Sequel::SQLTime</tt> object.
|
@@ -306,11 +302,9 @@ module Sequel
|
|
306
302
|
# v = Sequel.string_to_time('10:20:30') # Sequel::SQLTime.parse('10:20:30')
|
307
303
|
# DB.literal(v) # => '10:20:30'
|
308
304
|
def string_to_time(string)
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
raise convert_exception_class(e, InvalidValue)
|
313
|
-
end
|
305
|
+
SQLTime.parse(string)
|
306
|
+
rescue => e
|
307
|
+
raise convert_exception_class(e, InvalidValue)
|
314
308
|
end
|
315
309
|
|
316
310
|
# Unless in single threaded mode, protects access to any mutable
|
@@ -400,6 +394,11 @@ module Sequel
|
|
400
394
|
|
401
395
|
private
|
402
396
|
|
397
|
+
# Return a hash of date information parsed from the given string.
|
398
|
+
def _date_parse(string)
|
399
|
+
Date._parse(string)
|
400
|
+
end
|
401
|
+
|
403
402
|
# Helper method that the database adapter class methods that are added to Sequel via
|
404
403
|
# metaprogramming use to parse arguments.
|
405
404
|
def adapter_method(adapter, *args, &block)
|
@@ -8,7 +8,7 @@ module Sequel
|
|
8
8
|
# ---------------------
|
9
9
|
|
10
10
|
# Array of supported database adapters
|
11
|
-
ADAPTERS = %w'ado amalgalite ibmdb jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite tinytds'.map(&:to_sym)
|
11
|
+
ADAPTERS = %w'ado amalgalite ibmdb jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite tinytds trilogy'.map(&:to_sym)
|
12
12
|
|
13
13
|
# The Database subclass for the given adapter scheme.
|
14
14
|
# Raises Sequel::AdapterNotFound if the adapter
|
@@ -55,11 +55,11 @@ module Sequel
|
|
55
55
|
|
56
56
|
begin
|
57
57
|
db = c.new(opts)
|
58
|
-
if
|
58
|
+
if defined?(yield)
|
59
59
|
return yield(db)
|
60
60
|
end
|
61
61
|
ensure
|
62
|
-
if
|
62
|
+
if defined?(yield)
|
63
63
|
db.disconnect if db
|
64
64
|
Sequel.synchronize{::Sequel::DATABASES.delete(db)}
|
65
65
|
end
|
@@ -241,6 +241,30 @@ module Sequel
|
|
241
241
|
pool.servers
|
242
242
|
end
|
243
243
|
|
244
|
+
# Connect to the given server/shard. Handles database-generic post-connection
|
245
|
+
# setup not handled by #connect, using the :after_connect and :connect_sqls
|
246
|
+
# options.
|
247
|
+
def new_connection(server)
|
248
|
+
conn = connect(server)
|
249
|
+
opts = server_opts(server)
|
250
|
+
|
251
|
+
if ac = opts[:after_connect]
|
252
|
+
if ac.arity == 2
|
253
|
+
ac.call(conn, server)
|
254
|
+
else
|
255
|
+
ac.call(conn)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
if cs = opts[:connect_sqls]
|
260
|
+
cs.each do |sql|
|
261
|
+
log_connection_execute(conn, sql)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
conn
|
266
|
+
end
|
267
|
+
|
244
268
|
# Returns true if the database is using a single-threaded connection pool.
|
245
269
|
def single_threaded?
|
246
270
|
@single_threaded
|
@@ -30,19 +30,29 @@ module Sequel
|
|
30
30
|
@dataset_class.new(self)
|
31
31
|
end
|
32
32
|
|
33
|
-
#
|
34
|
-
# it is used to iterate over the records:
|
33
|
+
# Returns a dataset instance for the given SQL string:
|
35
34
|
#
|
36
|
-
# DB.fetch('SELECT * FROM items')
|
35
|
+
# ds = DB.fetch('SELECT * FROM items')
|
36
|
+
#
|
37
|
+
# You can then call methods on the dataset to retrieve results:
|
37
38
|
#
|
38
|
-
#
|
39
|
+
# ds.all
|
40
|
+
# # SELECT * FROM items
|
41
|
+
# # => [{:column=>value, ...}, ...]
|
39
42
|
#
|
40
|
-
#
|
43
|
+
# If a block is given, it is passed to #each on the resulting dataset to
|
44
|
+
# iterate over the records returned by the query:
|
45
|
+
#
|
46
|
+
# DB.fetch('SELECT * FROM items'){|r| p r}
|
47
|
+
# # {:column=>value, ...}
|
48
|
+
# # ...
|
41
49
|
#
|
42
50
|
# +fetch+ can also perform parameterized queries for protection against SQL
|
43
51
|
# injection:
|
44
52
|
#
|
45
|
-
# DB.fetch('SELECT * FROM items WHERE name = ?',
|
53
|
+
# ds = DB.fetch('SELECT * FROM items WHERE name = ?', "my name")
|
54
|
+
# ds.all
|
55
|
+
# # SELECT * FROM items WHERE name = 'my name'
|
46
56
|
#
|
47
57
|
# See caveats listed in Dataset#with_sql regarding datasets using custom
|
48
58
|
# SQL and the methods that can be called on them.
|