sequel 3.45.0 → 3.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +34 -0
- data/README.rdoc +6 -0
- data/Rakefile +46 -33
- data/doc/release_notes/3.46.0.txt +122 -0
- data/doc/schema_modification.rdoc +42 -6
- data/doc/security.rdoc +379 -0
- data/doc/transactions.rdoc +1 -1
- data/lib/sequel/adapters/jdbc/as400.rb +1 -0
- data/lib/sequel/adapters/jdbc/h2.rb +11 -0
- data/lib/sequel/adapters/mysql2.rb +3 -9
- data/lib/sequel/adapters/postgres.rb +34 -2
- data/lib/sequel/adapters/shared/cubrid.rb +5 -0
- data/lib/sequel/adapters/shared/mssql.rb +27 -3
- data/lib/sequel/adapters/shared/mysql.rb +25 -4
- data/lib/sequel/adapters/shared/sqlite.rb +12 -1
- data/lib/sequel/connection_pool.rb +3 -3
- data/lib/sequel/connection_pool/sharded_threaded.rb +7 -8
- data/lib/sequel/connection_pool/threaded.rb +7 -8
- data/lib/sequel/core.rb +5 -2
- data/lib/sequel/database.rb +1 -1
- data/lib/sequel/database/connecting.rb +7 -7
- data/lib/sequel/database/features.rb +88 -0
- data/lib/sequel/database/misc.rb +14 -64
- data/lib/sequel/database/query.rb +0 -332
- data/lib/sequel/database/schema_generator.rb +36 -3
- data/lib/sequel/database/schema_methods.rb +48 -12
- data/lib/sequel/database/transactions.rb +344 -0
- data/lib/sequel/dataset/actions.rb +24 -9
- data/lib/sequel/dataset/mutation.rb +20 -0
- data/lib/sequel/dataset/query.rb +0 -17
- data/lib/sequel/dataset/sql.rb +7 -0
- data/lib/sequel/exceptions.rb +10 -6
- data/lib/sequel/extensions/_pretty_table.rb +2 -2
- data/lib/sequel/extensions/looser_typecasting.rb +10 -0
- data/lib/sequel/extensions/migration.rb +5 -2
- data/lib/sequel/model.rb +1 -1
- data/lib/sequel/model/associations.rb +16 -14
- data/lib/sequel/model/base.rb +14 -2
- data/lib/sequel/plugins/composition.rb +3 -3
- data/lib/sequel/plugins/dirty.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +3 -0
- data/lib/sequel/plugins/serialization.rb +7 -17
- data/lib/sequel/plugins/string_stripper.rb +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/sql.rb +3 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +21 -0
- data/spec/adapters/postgres_spec.rb +35 -8
- data/spec/core/database_spec.rb +4 -0
- data/spec/core/dataset_spec.rb +48 -2
- data/spec/core/schema_generator_spec.rb +10 -1
- data/spec/core/schema_spec.rb +69 -0
- data/spec/extensions/composition_spec.rb +21 -2
- data/spec/extensions/dirty_spec.rb +17 -10
- data/spec/extensions/eager_each_spec.rb +4 -1
- data/spec/extensions/looser_typecasting_spec.rb +16 -19
- data/spec/extensions/migration_spec.rb +7 -1
- data/spec/extensions/serialization_spec.rb +22 -0
- data/spec/extensions/single_table_inheritance_spec.rb +3 -2
- data/spec/extensions/validation_helpers_spec.rb +6 -0
- data/spec/integration/dataset_test.rb +5 -0
- data/spec/integration/schema_test.rb +16 -0
- data/spec/model/associations_spec.rb +40 -0
- data/spec/model/base_spec.rb +21 -1
- data/spec/model/record_spec.rb +3 -0
- metadata +14 -10
data/doc/transactions.rdoc
CHANGED
@@ -8,7 +8,7 @@ Sequel uses autocommit mode by default for all of its database adapters, so in g
|
|
8
8
|
* Migrations if the database supports transactional schema
|
9
9
|
* A few model plugins
|
10
10
|
|
11
|
-
Everywhere else, it is up to
|
11
|
+
Everywhere else, it is up to you to use a database transaction if you want to.
|
12
12
|
|
13
13
|
== Basic Transaction Usage
|
14
14
|
|
@@ -85,6 +85,12 @@ module Sequel
|
|
85
85
|
sql = "ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(op[:name])} #{type_literal(op)}"
|
86
86
|
column_definition_order.each{|m| send(:"column_definition_#{m}_sql", sql, op)}
|
87
87
|
sql
|
88
|
+
when :drop_constraint
|
89
|
+
if op[:type] == :primary_key
|
90
|
+
"ALTER TABLE #{quote_schema_table(table)} DROP PRIMARY KEY"
|
91
|
+
else
|
92
|
+
super(table, op)
|
93
|
+
end
|
88
94
|
else
|
89
95
|
super(table, op)
|
90
96
|
end
|
@@ -121,6 +127,11 @@ module Sequel
|
|
121
127
|
PRIMARY_KEY_INDEX_RE
|
122
128
|
end
|
123
129
|
|
130
|
+
# H2 does not support named column constraints.
|
131
|
+
def supports_named_column_constraints?
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
124
135
|
# Use BIGINT IDENTITY for identity columns that use bigint, fixes
|
125
136
|
# the case where primary_key :column, :type=>Bignum is used.
|
126
137
|
def type_literal_generic_bignum(column)
|
@@ -27,17 +27,11 @@ module Sequel
|
|
27
27
|
# a filter for an autoincrement column equals NULL to return the last
|
28
28
|
# inserted row.
|
29
29
|
# * :charset - Same as :encoding (:encoding takes precendence)
|
30
|
-
# * :config_default_group - The default group to read from the in
|
31
|
-
# the MySQL config file.
|
32
|
-
# * :config_local_infile - If provided, sets the Mysql::OPT_LOCAL_INFILE
|
33
|
-
# option on the connection with the given value.
|
34
|
-
# * :connect_timeout - Set the timeout in seconds before a connection
|
35
|
-
# attempt is abandoned.
|
36
30
|
# * :encoding - Set all the related character sets for this
|
37
31
|
# connection (connection, client, database, server, and results).
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
32
|
+
#
|
33
|
+
# The options hash is also passed to mysql2, and can include mysql2
|
34
|
+
# options such as :local_infile.
|
41
35
|
def connect(server)
|
42
36
|
opts = server_opts(server)
|
43
37
|
opts[:host] ||= 'localhost'
|
@@ -164,7 +164,7 @@ module Sequel
|
|
164
164
|
# conversion is done, so an error is raised if you attempt to retrieve an infinite
|
165
165
|
# timestamp. You can set this to :nil to convert to nil, :string to leave
|
166
166
|
# as a string, or :float to convert to an infinite float.
|
167
|
-
|
167
|
+
attr_reader :convert_infinite_timestamps
|
168
168
|
|
169
169
|
# Add the primary_keys and primary_key_sequences instance variables,
|
170
170
|
# so we can get the correct return values for inserted rows.
|
@@ -233,6 +233,22 @@ module Sequel
|
|
233
233
|
conn
|
234
234
|
end
|
235
235
|
|
236
|
+
def convert_infinite_timestamps=(v)
|
237
|
+
@convert_infinite_timestamps = v
|
238
|
+
pr = old_pr = Postgres.use_iso_date_format ? TYPE_TRANSLATOR.method(:date) : Sequel.method(:string_to_date)
|
239
|
+
if v
|
240
|
+
pr = lambda do |v|
|
241
|
+
case v
|
242
|
+
when *INFINITE_TIMESTAMP_STRINGS
|
243
|
+
infinite_timestamp_value(v)
|
244
|
+
else
|
245
|
+
old_pr.call(v)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
conversion_procs[1082] = pr
|
250
|
+
end
|
251
|
+
|
236
252
|
# Disconnect given connection
|
237
253
|
def disconnect_connection(conn)
|
238
254
|
begin
|
@@ -396,7 +412,7 @@ module Sequel
|
|
396
412
|
# If convert_infinite_timestamps is true and the value is infinite, return an appropriate
|
397
413
|
# value based on the convert_infinite_timestamps setting.
|
398
414
|
def to_application_timestamp(value)
|
399
|
-
if
|
415
|
+
if convert_infinite_timestamps
|
400
416
|
case value
|
401
417
|
when *INFINITE_TIMESTAMP_STRINGS
|
402
418
|
infinite_timestamp_value(value)
|
@@ -504,6 +520,22 @@ module Sequel
|
|
504
520
|
conn.execute(sql)
|
505
521
|
end
|
506
522
|
|
523
|
+
# If the value is an infinite value (either an infinite float or a string returned by
|
524
|
+
# by PostgreSQL for an infinite timestamp), return it without converting it if
|
525
|
+
# convert_infinite_timestamps is set.
|
526
|
+
def typecast_value_date(value)
|
527
|
+
if convert_infinite_timestamps
|
528
|
+
case value
|
529
|
+
when *INFINITE_DATETIME_VALUES
|
530
|
+
value
|
531
|
+
else
|
532
|
+
super
|
533
|
+
end
|
534
|
+
else
|
535
|
+
super
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
507
539
|
# If the value is an infinite value (either an infinite float or a string returned by
|
508
540
|
# by PostgreSQL for an infinite timestamp), return it without converting it if
|
509
541
|
# convert_infinite_timestamps is set.
|
@@ -146,6 +146,11 @@ module Sequel
|
|
146
146
|
nil
|
147
147
|
end
|
148
148
|
|
149
|
+
# CUBRID does not support named column constraints.
|
150
|
+
def supports_named_column_constraints?
|
151
|
+
false
|
152
|
+
end
|
153
|
+
|
149
154
|
# CUBRID doesn't support booleans, it recommends using smallint.
|
150
155
|
def type_literal_generic_trueclass(column)
|
151
156
|
:smallint
|
@@ -414,6 +414,7 @@ module Sequel
|
|
414
414
|
APOS_RE = Dataset::APOS_RE
|
415
415
|
DOUBLE_APOS = Dataset::DOUBLE_APOS
|
416
416
|
INTO = Dataset::INTO
|
417
|
+
DOUBLE_BRACKET_CLOSE = ']]'.freeze
|
417
418
|
DATEPART_SECOND_OPEN = "CAST((datepart(".freeze
|
418
419
|
DATEPART_SECOND_MIDDLE = ') + datepart(ns, '.freeze
|
419
420
|
DATEPART_SECOND_CLOSE = ")/1000000000.0) AS double precision)".freeze
|
@@ -434,6 +435,8 @@ module Sequel
|
|
434
435
|
CASE_INSENSITIVE_COLLATION = 'Latin1_General_CI_AS'.freeze
|
435
436
|
DEFAULT_TIMESTAMP_FORMAT = "'%Y-%m-%dT%H:%M:%S%N%z'".freeze
|
436
437
|
FORMAT_DATE = "'%Y%m%d'".freeze
|
438
|
+
CROSS_APPLY = 'CROSS APPLY'.freeze
|
439
|
+
OUTER_APPLY = 'OUTER APPLY'.freeze
|
437
440
|
|
438
441
|
Sequel::Dataset.def_mutation_method(:disable_insert_output, :output, :module=>self)
|
439
442
|
|
@@ -484,6 +487,11 @@ module Sequel
|
|
484
487
|
end
|
485
488
|
end
|
486
489
|
|
490
|
+
# Uses CROSS APPLY to join the given table into the current dataset.
|
491
|
+
def cross_apply(table)
|
492
|
+
join_table(:cross_apply, table)
|
493
|
+
end
|
494
|
+
|
487
495
|
# Disable the use of INSERT OUTPUT
|
488
496
|
def disable_insert_output
|
489
497
|
clone(:disable_insert_output=>true)
|
@@ -545,6 +553,11 @@ module Sequel
|
|
545
553
|
lock_style(:dirty)
|
546
554
|
end
|
547
555
|
|
556
|
+
# Uses OUTER APPLY to join the given table into the current dataset.
|
557
|
+
def outer_apply(table)
|
558
|
+
join_table(:outer_apply, table)
|
559
|
+
end
|
560
|
+
|
548
561
|
# Include an OUTPUT clause in the eventual INSERT, UPDATE, or DELETE query.
|
549
562
|
#
|
550
563
|
# The first argument is the table to output into, and the second argument
|
@@ -570,10 +583,9 @@ module Sequel
|
|
570
583
|
clone({:output => output})
|
571
584
|
end
|
572
585
|
|
573
|
-
# MSSQL uses [] to quote identifiers.
|
574
|
-
# escaping of ], so you cannot use that character in an identifier.
|
586
|
+
# MSSQL uses [] to quote identifiers.
|
575
587
|
def quoted_identifier_append(sql, name)
|
576
|
-
sql << BRACKET_OPEN << name.to_s << BRACKET_CLOSE
|
588
|
+
sql << BRACKET_OPEN << name.to_s.gsub(/\]/, DOUBLE_BRACKET_CLOSE) << BRACKET_CLOSE
|
577
589
|
end
|
578
590
|
|
579
591
|
# The version of the database server.
|
@@ -729,6 +741,18 @@ module Sequel
|
|
729
741
|
end
|
730
742
|
end
|
731
743
|
|
744
|
+
# Handle CROSS APPLY and OUTER APPLY JOIN types
|
745
|
+
def join_type_sql(join_type)
|
746
|
+
case join_type
|
747
|
+
when :cross_apply
|
748
|
+
CROSS_APPLY
|
749
|
+
when :outer_apply
|
750
|
+
OUTER_APPLY
|
751
|
+
else
|
752
|
+
super
|
753
|
+
end
|
754
|
+
end
|
755
|
+
|
732
756
|
# MSSQL uses a literal hexidecimal number for blob strings
|
733
757
|
def literal_blob_append(sql, v)
|
734
758
|
sql << HEX_START << v.unpack(HSTAR).first
|
@@ -199,13 +199,16 @@ module Sequel
|
|
199
199
|
unless op[:type] || opts[:type]
|
200
200
|
raise Error, "cannot determine database type to use for CHANGE COLUMN operation"
|
201
201
|
end
|
202
|
-
|
202
|
+
opts = op.merge(opts)
|
203
|
+
opts.delete(:auto_increment) if op[:auto_increment] == false
|
204
|
+
"CHANGE COLUMN #{quote_identifier(op[:name])} #{column_definition_sql(opts)}"
|
203
205
|
when :drop_constraint
|
204
206
|
type = case op[:type]
|
205
207
|
when :primary_key
|
206
208
|
"DROP PRIMARY KEY"
|
207
209
|
when :foreign_key
|
208
|
-
|
210
|
+
name = op[:name] || foreign_key_name(table, op[:columns])
|
211
|
+
"DROP FOREIGN KEY #{quote_identifier(name)}"
|
209
212
|
when :unique
|
210
213
|
"DROP INDEX #{quote_identifier(op[:name])}"
|
211
214
|
end
|
@@ -224,6 +227,13 @@ module Sequel
|
|
224
227
|
case op[:op]
|
225
228
|
when :drop_index
|
226
229
|
"#{drop_index_sql(table, op)} ON #{quote_schema_table(table)}"
|
230
|
+
when :drop_constraint
|
231
|
+
if op[:type] == :primary_key
|
232
|
+
if (pk = primary_key_from_schema(table)).length == 1
|
233
|
+
return [alter_table_sql(table, {:op=>:rename_column, :name=>pk.first, :new_name=>pk.first, :auto_increment=>false}), super]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
super
|
227
237
|
else
|
228
238
|
super
|
229
239
|
end
|
@@ -242,7 +252,7 @@ module Sequel
|
|
242
252
|
# operations, since in some cases adding a foreign key constraint in
|
243
253
|
# the same query as other operations results in MySQL error 150.
|
244
254
|
def combinable_alter_table_op?(op)
|
245
|
-
super && !(op[:op] == :add_constraint && op[:type] == :foreign_key)
|
255
|
+
super && !(op[:op] == :add_constraint && op[:type] == :foreign_key) && !(op[:op] == :drop_constraint && op[:type] == :primary_key)
|
246
256
|
end
|
247
257
|
|
248
258
|
# The SQL queries to execute on initial connection
|
@@ -317,6 +327,7 @@ module Sequel
|
|
317
327
|
collate = options.fetch(:collate, Sequel::MySQL.default_collate)
|
318
328
|
generator.constraints.sort_by{|c| (c[:type] == :primary_key) ? -1 : 1}
|
319
329
|
|
330
|
+
# Proc for figuring out the primary key for a given table.
|
320
331
|
key_proc = lambda do |t|
|
321
332
|
if t == name
|
322
333
|
if pk = generator.primary_key_name
|
@@ -329,12 +340,17 @@ module Sequel
|
|
329
340
|
end
|
330
341
|
end
|
331
342
|
|
343
|
+
# Manually set the keys, since MySQL requires one, it doesn't use the primary
|
344
|
+
# key if none are specified.
|
332
345
|
generator.constraints.each do |c|
|
333
346
|
if c[:type] == :foreign_key
|
334
347
|
c[:key] ||= key_proc.call(c[:table])
|
335
348
|
end
|
336
349
|
end
|
337
350
|
|
351
|
+
# Split column constraints into table constraints in some cases:
|
352
|
+
# * foreign key - Always
|
353
|
+
# * unique, primary_key - Only if constraint has a name
|
338
354
|
generator.columns.each do |c|
|
339
355
|
if t = c.delete(:table)
|
340
356
|
same_table = t == name
|
@@ -346,7 +362,7 @@ module Sequel
|
|
346
362
|
generator.constraints.unshift(:type=>:unique, :columns=>Array(k))
|
347
363
|
end
|
348
364
|
|
349
|
-
generator.foreign_key([c[:name]], t, c.merge(:name=>
|
365
|
+
generator.foreign_key([c[:name]], t, c.merge(:name=>c[:foreign_key_constraint_name], :type=>:foreign_key, :key=>key))
|
350
366
|
end
|
351
367
|
end
|
352
368
|
|
@@ -448,6 +464,11 @@ module Sequel
|
|
448
464
|
true
|
449
465
|
end
|
450
466
|
|
467
|
+
# MySQL does not support named column constraints.
|
468
|
+
def supports_named_column_constraints?
|
469
|
+
false
|
470
|
+
end
|
471
|
+
|
451
472
|
# Respect the :size option if given to produce
|
452
473
|
# tinyblob, mediumblob, and longblob if :tiny,
|
453
474
|
# :medium, or :long is given.
|
@@ -221,6 +221,7 @@ module Sequel
|
|
221
221
|
ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
|
222
222
|
end
|
223
223
|
end
|
224
|
+
ensure
|
224
225
|
self.foreign_keys = true if fks
|
225
226
|
end
|
226
227
|
|
@@ -255,7 +256,11 @@ module Sequel
|
|
255
256
|
when :primary_key
|
256
257
|
duplicate_table(table){|columns| columns.each{|s| s[:primary_key] = nil}}
|
257
258
|
when :foreign_key
|
258
|
-
|
259
|
+
if op[:columns]
|
260
|
+
duplicate_table(table, :skip_foreign_key_columns=>op[:columns])
|
261
|
+
else
|
262
|
+
duplicate_table(table, :no_foreign_keys=>true)
|
263
|
+
end
|
259
264
|
else
|
260
265
|
duplicate_table(table)
|
261
266
|
end
|
@@ -366,6 +371,12 @@ module Sequel
|
|
366
371
|
if ocp = opts[:old_columns_proc]
|
367
372
|
fks.delete_if{|c| ocp.call(c[:columns].dup) != c[:columns]}
|
368
373
|
end
|
374
|
+
|
375
|
+
# Skip any foreign key columns where a constraint for those
|
376
|
+
# foreign keys is being dropped.
|
377
|
+
if sfkc = opts[:skip_foreign_key_columns]
|
378
|
+
fks.delete_if{|c| c[:columns] == sfkc}
|
379
|
+
end
|
369
380
|
|
370
381
|
constraints.concat(fks.each{|h| h[:type] = :foreign_key})
|
371
382
|
end
|
@@ -18,8 +18,8 @@
|
|
18
18
|
#
|
19
19
|
# add_servers(Array of Symbols) :: start recognizing all shards/servers specified
|
20
20
|
# by the array of symbols.
|
21
|
-
#
|
22
|
-
#
|
21
|
+
# remove_servers(Array of Symbols) :: no longer recognize all shards/servers
|
22
|
+
# specified by the array of symbols.
|
23
23
|
class Sequel::ConnectionPool
|
24
24
|
# The default server to use
|
25
25
|
DEFAULT_SERVER = :default
|
@@ -42,7 +42,7 @@ class Sequel::ConnectionPool
|
|
42
42
|
when Class
|
43
43
|
v.new(db, opts)
|
44
44
|
when Symbol
|
45
|
-
Sequel.
|
45
|
+
Sequel.tsk_require("sequel/connection_pool/#{v}")
|
46
46
|
connection_pool_class(opts).new(db, opts) || raise(Sequel::Error, "No connection pool class found")
|
47
47
|
end
|
48
48
|
end
|
@@ -185,13 +185,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
185
185
|
# returns the connection. The calling code should already have the mutex
|
186
186
|
# before calling this.
|
187
187
|
def checkin_connection(server, conn)
|
188
|
-
|
189
|
-
when :queue
|
190
|
-
available_connections(server).unshift(conn)
|
191
|
-
else
|
192
|
-
available_connections(server) << conn
|
193
|
-
end
|
194
|
-
|
188
|
+
available_connections(server) << conn
|
195
189
|
conn
|
196
190
|
end
|
197
191
|
|
@@ -222,7 +216,12 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
222
216
|
# if there is not currently an available connection for the server.
|
223
217
|
# The calling code should already have the mutex before calling this.
|
224
218
|
def next_available(server)
|
225
|
-
|
219
|
+
case @connection_handling
|
220
|
+
when :queue
|
221
|
+
available_connections(server).shift
|
222
|
+
else
|
223
|
+
available_connections(server).pop
|
224
|
+
end
|
226
225
|
end
|
227
226
|
|
228
227
|
# Returns the connection owned by the supplied thread for the given server,
|
@@ -140,13 +140,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
140
140
|
# Return a connection to the pool of available connections, returns the connection.
|
141
141
|
# The calling code should already have the mutex before calling this.
|
142
142
|
def checkin_connection(conn)
|
143
|
-
|
144
|
-
when :queue
|
145
|
-
@available_connections.unshift(conn)
|
146
|
-
else
|
147
|
-
@available_connections << conn
|
148
|
-
end
|
149
|
-
|
143
|
+
@available_connections << conn
|
150
144
|
conn
|
151
145
|
end
|
152
146
|
|
@@ -168,7 +162,12 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
168
162
|
# is not currently an available connection. The calling code should already
|
169
163
|
# have the mutex before calling this.
|
170
164
|
def next_available
|
171
|
-
@
|
165
|
+
case @connection_handling
|
166
|
+
when :queue
|
167
|
+
@available_connections.shift
|
168
|
+
else
|
169
|
+
@available_connections.pop
|
170
|
+
end
|
172
171
|
end
|
173
172
|
|
174
173
|
# Returns the connection owned by the supplied thread,
|
data/lib/sequel/core.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
# Sequel currently adds methods to the Array, Hash, String and Symbol classes by
|
21
21
|
# default. You can either require 'sequel/no_core_ext' or set the
|
22
22
|
# +SEQUEL_NO_CORE_EXTENSIONS+ constant or environment variable before requiring
|
23
|
-
# sequel to have
|
23
|
+
# sequel to have Sequel not add methods to those classes.
|
24
24
|
#
|
25
25
|
# For a more expanded introduction, see the {README}[link:files/README_rdoc.html].
|
26
26
|
# For a quicker introduction, see the {cheat sheet}[link:files/doc/cheat_sheet_rdoc.html].
|
@@ -332,7 +332,7 @@ module Sequel
|
|
332
332
|
else
|
333
333
|
# Yield directly to the block. You don't need to synchronize
|
334
334
|
# access on MRI because the GVL makes certain methods atomic.
|
335
|
-
def self.synchronize
|
335
|
+
def self.synchronize
|
336
336
|
yield
|
337
337
|
end
|
338
338
|
end
|
@@ -422,6 +422,9 @@ module Sequel
|
|
422
422
|
|
423
423
|
# Method that adds a database adapter class method to Sequel that calls
|
424
424
|
# Sequel.adapter_method.
|
425
|
+
#
|
426
|
+
# Do not call this method with untrusted input, as that can result in
|
427
|
+
# arbitrary code execution.
|
425
428
|
def self.def_adapter_method(*adapters) # :nodoc:
|
426
429
|
adapters.each do |adapter|
|
427
430
|
instance_eval("def #{adapter}(*args, &block); adapter_method('#{adapter}', *args, &block) end", __FILE__, __LINE__)
|
data/lib/sequel/database.rb
CHANGED
@@ -15,5 +15,5 @@ module Sequel
|
|
15
15
|
class Database
|
16
16
|
end
|
17
17
|
|
18
|
-
require(%w"connecting dataset dataset_defaults logging misc query schema_generator schema_methods", 'database')
|
18
|
+
require(%w"connecting dataset dataset_defaults logging features misc query transactions schema_generator schema_methods", 'database')
|
19
19
|
end
|
@@ -56,10 +56,7 @@ module Sequel
|
|
56
56
|
uri_options = c.send(:uri_to_options, uri)
|
57
57
|
uri.query.split('&').collect{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
|
58
58
|
uri_options.to_a.each{|k,v| uri_options[k] = URI.unescape(v) if v.is_a?(String)}
|
59
|
-
opts = opts.merge(:orig_opts=>opts.dup)
|
60
|
-
opts[:uri] = conn_string
|
61
|
-
opts = uri_options.merge(opts)
|
62
|
-
opts[:adapter] = scheme
|
59
|
+
opts = uri_options.merge(opts).merge!(:orig_opts=>opts.dup, :uri=>conn_string, :adapter=>scheme)
|
63
60
|
end
|
64
61
|
when Hash
|
65
62
|
opts = conn_string.merge(opts)
|
@@ -77,14 +74,16 @@ module Sequel
|
|
77
74
|
begin
|
78
75
|
db = c.new(opts)
|
79
76
|
db.test_connection if opts[:test] && db.send(:typecast_value_boolean, opts[:test])
|
80
|
-
|
77
|
+
if block_given?
|
78
|
+
return yield(db)
|
79
|
+
end
|
81
80
|
ensure
|
82
81
|
if block_given?
|
83
82
|
db.disconnect if db
|
84
83
|
Sequel.synchronize{::Sequel::DATABASES.delete(db)}
|
85
84
|
end
|
86
85
|
end
|
87
|
-
|
86
|
+
db
|
88
87
|
end
|
89
88
|
|
90
89
|
# Sets the default single_threaded mode for new databases.
|
@@ -107,7 +106,7 @@ module Sequel
|
|
107
106
|
# Sequel.connect('mydb://user:password@dbserver/mydb')
|
108
107
|
def self.set_adapter_scheme(scheme) # :nodoc:
|
109
108
|
@scheme = scheme
|
110
|
-
ADAPTER_MAP[scheme
|
109
|
+
ADAPTER_MAP[scheme] = self
|
111
110
|
end
|
112
111
|
private_class_method :set_adapter_scheme
|
113
112
|
|
@@ -186,6 +185,7 @@ module Sequel
|
|
186
185
|
#
|
187
186
|
# DB.each_server{|db| db.create_table(:users){primary_key :id; String :name}}
|
188
187
|
def each_server(&block)
|
188
|
+
raise(Error, "Database#each_server must be passed a block") unless block
|
189
189
|
servers.each{|s| self.class.connect(server_opts(s), &block)}
|
190
190
|
end
|
191
191
|
|