sequel 3.34.1 → 3.35.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.
- data/CHANGELOG +52 -0
- data/README.rdoc +3 -1
- data/Rakefile +2 -10
- data/doc/active_record.rdoc +1 -0
- data/doc/migration.rdoc +18 -7
- data/doc/model_hooks.rdoc +6 -0
- data/doc/opening_databases.rdoc +3 -0
- data/doc/prepared_statements.rdoc +0 -1
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/schema_modification.rdoc +16 -1
- data/doc/thread_safety.rdoc +17 -0
- data/lib/sequel/adapters/do.rb +2 -2
- data/lib/sequel/adapters/do/postgres.rb +1 -52
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/firebird.rb +1 -1
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +23 -19
- data/lib/sequel/adapters/jdbc/db2.rb +0 -5
- data/lib/sequel/adapters/jdbc/derby.rb +29 -2
- data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
- data/lib/sequel/adapters/jdbc/h2.rb +1 -1
- data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
- data/lib/sequel/adapters/jdbc/informix.rb +0 -5
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +4 -35
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
- data/lib/sequel/adapters/jdbc/transactions.rb +4 -4
- data/lib/sequel/adapters/mysql2.rb +1 -1
- data/lib/sequel/adapters/odbc.rb +3 -3
- data/lib/sequel/adapters/odbc/mssql.rb +14 -1
- data/lib/sequel/adapters/oracle.rb +6 -18
- data/lib/sequel/adapters/postgres.rb +36 -53
- data/lib/sequel/adapters/shared/db2.rb +16 -2
- data/lib/sequel/adapters/shared/mssql.rb +40 -9
- data/lib/sequel/adapters/shared/mysql.rb +16 -4
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
- data/lib/sequel/adapters/shared/oracle.rb +2 -0
- data/lib/sequel/adapters/shared/postgres.rb +135 -211
- data/lib/sequel/adapters/sqlite.rb +2 -2
- data/lib/sequel/adapters/swift.rb +1 -1
- data/lib/sequel/adapters/swift/postgres.rb +1 -71
- data/lib/sequel/adapters/tinytds.rb +3 -3
- data/lib/sequel/core.rb +27 -4
- data/lib/sequel/database/connecting.rb +7 -8
- data/lib/sequel/database/logging.rb +6 -1
- data/lib/sequel/database/misc.rb +20 -4
- data/lib/sequel/database/query.rb +38 -18
- data/lib/sequel/database/schema_generator.rb +5 -2
- data/lib/sequel/database/schema_methods.rb +34 -8
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/sql.rb +18 -24
- data/lib/sequel/extensions/core_extensions.rb +0 -23
- data/lib/sequel/extensions/migration.rb +22 -8
- data/lib/sequel/extensions/pg_auto_parameterize.rb +4 -0
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/model.rb +2 -2
- data/lib/sequel/model/associations.rb +95 -70
- data/lib/sequel/model/base.rb +16 -18
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/identity_map.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +16 -1
- data/lib/sequel/plugins/many_through_many.rb +22 -32
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +2 -2
- data/lib/sequel/plugins/prepared_statements.rb +22 -8
- data/lib/sequel/plugins/prepared_statements_associations.rb +2 -3
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/subclasses.rb +10 -2
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +12 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/postgres_spec.rb +30 -79
- data/spec/core/database_spec.rb +46 -2
- data/spec/core/dataset_spec.rb +28 -22
- data/spec/core/schema_generator_spec.rb +1 -1
- data/spec/core/schema_spec.rb +51 -0
- data/spec/extensions/arbitrary_servers_spec.rb +0 -4
- data/spec/extensions/association_autoreloading_spec.rb +17 -0
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/core_extensions_spec.rb +1 -24
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/json_serializer_spec.rb +13 -0
- data/spec/extensions/migration_spec.rb +28 -15
- data/spec/extensions/named_timezones_spec.rb +6 -8
- data/spec/extensions/pg_auto_parameterize_spec.rb +6 -5
- data/spec/extensions/schema_dumper_spec.rb +3 -1
- data/spec/extensions/xml_serializer_spec.rb +13 -0
- data/spec/files/{transactionless_migrations → transaction_specified_migrations}/001_create_alt_basic.rb +1 -1
- data/spec/files/{transactionless_migrations → transaction_specified_migrations}/002_create_basic.rb +0 -0
- data/spec/files/{transaction_migrations → transaction_unspecified_migrations}/001_create_alt_basic.rb +0 -0
- data/spec/files/{transaction_migrations → transaction_unspecified_migrations}/002_create_basic.rb +0 -0
- data/spec/integration/associations_test.rb +5 -7
- data/spec/integration/dataset_test.rb +25 -7
- data/spec/integration/plugin_test.rb +1 -1
- data/spec/integration/schema_test.rb +16 -1
- data/spec/model/associations_spec.rb +2 -2
- metadata +14 -9
- data/lib/sequel/adapters/odbc/db2.rb +0 -17
|
@@ -216,7 +216,7 @@ module Sequel
|
|
|
216
216
|
|
|
217
217
|
# Execute a prepared statement on the database using the given name.
|
|
218
218
|
def execute_prepared_statement(conn, type, name, opts, &block)
|
|
219
|
-
ps =
|
|
219
|
+
ps = prepared_statement(name)
|
|
220
220
|
sql = ps.prepared_sql
|
|
221
221
|
args = opts[:arguments]
|
|
222
222
|
ps_args = {}
|
|
@@ -382,7 +382,7 @@ module Sequel
|
|
|
382
382
|
ps.extend(PreparedStatementMethods)
|
|
383
383
|
if name
|
|
384
384
|
ps.prepared_statement_name = name
|
|
385
|
-
db.
|
|
385
|
+
db.set_prepared_statement(name, ps)
|
|
386
386
|
end
|
|
387
387
|
ps
|
|
388
388
|
end
|
|
@@ -15,7 +15,7 @@ module Sequel
|
|
|
15
15
|
DATABASE_SETUP = {:postgres=>proc do |db|
|
|
16
16
|
Sequel.ts_require 'adapters/swift/postgres'
|
|
17
17
|
db.extend(Sequel::Swift::Postgres::DatabaseMethods)
|
|
18
|
-
db.
|
|
18
|
+
db.extend_datasets Sequel::Postgres::DatasetMethods
|
|
19
19
|
db.swift_class = ::Swift::DB::Postgres
|
|
20
20
|
end,
|
|
21
21
|
:mysql=>proc do |db|
|
|
@@ -7,27 +7,6 @@ module Sequel
|
|
|
7
7
|
# Adapter, Database, and Dataset support for accessing a PostgreSQL
|
|
8
8
|
# database via Swift.
|
|
9
9
|
module Postgres
|
|
10
|
-
# Methods to add to the Swift adapter/connection to allow it to work
|
|
11
|
-
# with the shared PostgreSQL code.
|
|
12
|
-
module AdapterMethods
|
|
13
|
-
include Sequel::Postgres::AdapterMethods
|
|
14
|
-
|
|
15
|
-
# Log all SQL that goes through the execute method to the related
|
|
16
|
-
# database object.
|
|
17
|
-
def execute(sql, *args)
|
|
18
|
-
@db.log_yield(sql){super}
|
|
19
|
-
rescue SwiftError => e
|
|
20
|
-
@db.send(:raise_error, e)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
# Swift specific method of getting specific values from a result set.
|
|
26
|
-
def single_value(row)
|
|
27
|
-
row.values.at(0)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
10
|
# Methods to add to Database instances that access PostgreSQL via Swift.
|
|
32
11
|
module DatabaseMethods
|
|
33
12
|
include Sequel::Postgres::DatabaseMethods
|
|
@@ -41,51 +20,8 @@ module Sequel
|
|
|
41
20
|
end
|
|
42
21
|
end
|
|
43
22
|
|
|
44
|
-
# Run the SELECT SQL on the database and yield the rows
|
|
45
|
-
def execute(sql, opts={})
|
|
46
|
-
synchronize(opts[:server]) do |conn|
|
|
47
|
-
begin
|
|
48
|
-
res = conn.execute(sql)
|
|
49
|
-
yield res if block_given?
|
|
50
|
-
nil
|
|
51
|
-
rescue SwiftError => e
|
|
52
|
-
raise_error(e)
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# Run the DELETE/UPDATE SQL on the database and return the number
|
|
58
|
-
# of matched rows.
|
|
59
|
-
def execute_dui(sql, opts={})
|
|
60
|
-
synchronize(opts[:server]) do |conn|
|
|
61
|
-
begin
|
|
62
|
-
conn.execute(sql).rows
|
|
63
|
-
rescue SwiftError => e
|
|
64
|
-
raise_error(e)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Run the INSERT SQL on the database and return the primary key
|
|
70
|
-
# for the record.
|
|
71
|
-
def execute_insert(sql, opts={})
|
|
72
|
-
synchronize(opts[:server]) do |conn|
|
|
73
|
-
begin
|
|
74
|
-
conn.execute(sql)
|
|
75
|
-
insert_result(conn, opts[:table], opts[:values])
|
|
76
|
-
rescue SwiftError => e
|
|
77
|
-
raise_error(e)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
23
|
private
|
|
83
24
|
|
|
84
|
-
# Execute SQL on the connection.
|
|
85
|
-
def log_connection_execute(conn, sql)
|
|
86
|
-
conn.execute(sql)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
25
|
# Remove all other options except for ones specifically handled, as
|
|
90
26
|
# otherwise swift passes them to dbic++ which passes them to PostgreSQL
|
|
91
27
|
# which can raise an error.
|
|
@@ -99,16 +35,10 @@ module Sequel
|
|
|
99
35
|
# Extend the adapter with the Swift PostgreSQL AdapterMethods.
|
|
100
36
|
def setup_connection(conn)
|
|
101
37
|
conn = super(conn)
|
|
102
|
-
conn.
|
|
103
|
-
conn.db = self
|
|
104
|
-
conn.apply_connection_settings
|
|
38
|
+
connection_configuration_sqls.each{|sql| log_yield(sql){conn.execute(sql)}}
|
|
105
39
|
conn
|
|
106
40
|
end
|
|
107
41
|
end
|
|
108
|
-
|
|
109
|
-
class Dataset < Swift::Dataset
|
|
110
|
-
include Sequel::Postgres::DatasetMethods
|
|
111
|
-
end
|
|
112
42
|
end
|
|
113
43
|
end
|
|
114
44
|
end
|
|
@@ -249,7 +249,7 @@ module Sequel
|
|
|
249
249
|
ps.extend(PreparedStatementMethods)
|
|
250
250
|
if name
|
|
251
251
|
ps.prepared_statement_name = name
|
|
252
|
-
db.
|
|
252
|
+
db.set_prepared_statement(name, ps)
|
|
253
253
|
end
|
|
254
254
|
ps
|
|
255
255
|
end
|
|
@@ -258,8 +258,8 @@ module Sequel
|
|
|
258
258
|
|
|
259
259
|
# Properly escape the given string +v+.
|
|
260
260
|
def literal_string_append(sql, v)
|
|
261
|
-
sql <<
|
|
262
|
-
sql <<
|
|
261
|
+
sql << (mssql_unicode_strings ? UNICODE_STRING_START : APOS)
|
|
262
|
+
sql << db.synchronize{|c| c.escape(v)}.gsub(BACKSLASH_CRLF_RE, BACKSLASH_CRLF_REPLACE) << APOS
|
|
263
263
|
end
|
|
264
264
|
end
|
|
265
265
|
end
|
data/lib/sequel/core.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
warn 'Sequel support for ruby <1.8.7 is deprecated and will be removed in 3.35.0' if RUBY_VERSION < '1.8.7'
|
|
2
1
|
%w'bigdecimal date thread time uri'.each{|f| require f}
|
|
3
2
|
|
|
4
3
|
# Top level module for Sequel
|
|
@@ -35,6 +34,9 @@ module Sequel
|
|
|
35
34
|
# Mutex used to protect file loading/requireing
|
|
36
35
|
@require_mutex = Mutex.new
|
|
37
36
|
|
|
37
|
+
# Whether Sequel is being run in single threaded mode
|
|
38
|
+
@single_threaded = false
|
|
39
|
+
|
|
38
40
|
class << self
|
|
39
41
|
# Sequel converts two digit years in <tt>Date</tt>s and <tt>DateTime</tt>s by default,
|
|
40
42
|
# so 01/02/03 is interpreted at January 2nd, 2003, and 12/13/99 is interpreted
|
|
@@ -89,6 +91,7 @@ module Sequel
|
|
|
89
91
|
|
|
90
92
|
# Make thread safe requiring reentrant to prevent deadlocks.
|
|
91
93
|
def check_requiring_thread
|
|
94
|
+
return yield if @single_threaded
|
|
92
95
|
t = Thread.current
|
|
93
96
|
return(yield) if @require_thread == t
|
|
94
97
|
@require_mutex.synchronize do
|
|
@@ -234,13 +237,15 @@ module Sequel
|
|
|
234
237
|
Array(files).each{|f| super("#{File.dirname(__FILE__).untaint}/#{"#{subdir}/" if subdir}#{f}")}
|
|
235
238
|
end
|
|
236
239
|
|
|
237
|
-
# Set whether
|
|
240
|
+
# Set whether Sequel is being used in single threaded mode. By default,
|
|
238
241
|
# Sequel uses a thread-safe connection pool, which isn't as fast as the
|
|
239
|
-
# single threaded connection pool
|
|
240
|
-
#
|
|
242
|
+
# single threaded connection pool, and also has some additional thread
|
|
243
|
+
# safety checks. If your program will only have one thread,
|
|
244
|
+
# and speed is a priority, you should set this to true:
|
|
241
245
|
#
|
|
242
246
|
# Sequel.single_threaded = true
|
|
243
247
|
def self.single_threaded=(value)
|
|
248
|
+
@single_threaded = value
|
|
244
249
|
Database.single_threaded = value
|
|
245
250
|
end
|
|
246
251
|
|
|
@@ -283,6 +288,24 @@ module Sequel
|
|
|
283
288
|
end
|
|
284
289
|
end
|
|
285
290
|
|
|
291
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby'
|
|
292
|
+
# Mutex used to protect mutable data structures
|
|
293
|
+
@data_mutex = Mutex.new
|
|
294
|
+
|
|
295
|
+
# Unless in single threaded mode, protects access to any mutable
|
|
296
|
+
# global data structure in Sequel.
|
|
297
|
+
# Uses a non-reentrant mutex, so calling code should be careful.
|
|
298
|
+
def self.synchronize(&block)
|
|
299
|
+
@single_threaded ? yield : @data_mutex.synchronize(&block)
|
|
300
|
+
end
|
|
301
|
+
else
|
|
302
|
+
# Yield directly to the block. You don't need to synchronize
|
|
303
|
+
# access on MRI because the GVL makes certain methods atomic.
|
|
304
|
+
def self.synchronize(&block)
|
|
305
|
+
yield
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
286
309
|
# Uses a transaction on all given databases with the given options. This:
|
|
287
310
|
#
|
|
288
311
|
# Sequel.transaction([DB1, DB2, DB3]){...}
|
|
@@ -81,7 +81,7 @@ module Sequel
|
|
|
81
81
|
ensure
|
|
82
82
|
if block_given?
|
|
83
83
|
db.disconnect if db
|
|
84
|
-
::Sequel::DATABASES.delete(db)
|
|
84
|
+
Sequel.synchronize{::Sequel::DATABASES.delete(db)}
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
block_given? ? result : db
|
|
@@ -135,8 +135,10 @@ module Sequel
|
|
|
135
135
|
#
|
|
136
136
|
# DB.add_servers(:f=>{:host=>"hash_host_f"})
|
|
137
137
|
def add_servers(servers)
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
if h = @opts[:servers]
|
|
139
|
+
Sequel.synchronize{h.merge!(servers)}
|
|
140
|
+
@pool.add_servers(servers.keys)
|
|
141
|
+
end
|
|
140
142
|
end
|
|
141
143
|
|
|
142
144
|
# Connects to the database. This method should be overridden by descendants.
|
|
@@ -191,11 +193,8 @@ module Sequel
|
|
|
191
193
|
#
|
|
192
194
|
# DB.remove_servers(:f1, :f2)
|
|
193
195
|
def remove_servers(*servers)
|
|
194
|
-
if
|
|
195
|
-
|
|
196
|
-
servers.flatten!
|
|
197
|
-
servers.each{|s| servs.delete(s)}
|
|
198
|
-
@opts[:servers] = servs
|
|
196
|
+
if h = @opts[:servers]
|
|
197
|
+
servers.flatten.each{|s| Sequel.synchronize{h.delete(s)}}
|
|
199
198
|
@pool.remove_servers(servers)
|
|
200
199
|
end
|
|
201
200
|
end
|
|
@@ -17,6 +17,11 @@ module Sequel
|
|
|
17
17
|
# is :info, it can be set to :debug to log at DEBUG level.
|
|
18
18
|
attr_accessor :sql_log_level
|
|
19
19
|
|
|
20
|
+
# Log a message at error level, with information about the exception.
|
|
21
|
+
def log_exception(exception, message)
|
|
22
|
+
log_each(:error, "#{exception.class}: #{exception.message.strip}: #{message}")
|
|
23
|
+
end
|
|
24
|
+
|
|
20
25
|
# Log a message at level info to all loggers.
|
|
21
26
|
def log_info(message, args=nil)
|
|
22
27
|
log_each(:info, args ? "#{message}; #{args.inspect}" : message)
|
|
@@ -31,7 +36,7 @@ module Sequel
|
|
|
31
36
|
begin
|
|
32
37
|
yield
|
|
33
38
|
rescue => e
|
|
34
|
-
|
|
39
|
+
log_exception(e, sql)
|
|
35
40
|
raise
|
|
36
41
|
ensure
|
|
37
42
|
log_duration(Time.now - start, sql) unless e
|
data/lib/sequel/database/misc.rb
CHANGED
|
@@ -59,11 +59,12 @@ module Sequel
|
|
|
59
59
|
@quote_identifiers = nil
|
|
60
60
|
@timezone = nil
|
|
61
61
|
@dataset_class = dataset_class_default
|
|
62
|
+
@cache_schema = typecast_value_boolean(@opts.fetch(:cache_schema, true))
|
|
62
63
|
@dataset_modules = []
|
|
63
64
|
self.sql_log_level = @opts[:sql_log_level] ? @opts[:sql_log_level].to_sym : :info
|
|
64
65
|
@pool = ConnectionPool.get_pool(@opts, &block)
|
|
65
66
|
|
|
66
|
-
::Sequel::DATABASES.push(self)
|
|
67
|
+
Sequel.synchronize{::Sequel::DATABASES.push(self)}
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
# If a transaction is not currently in process, yield to the block immediately.
|
|
@@ -74,7 +75,7 @@ module Sequel
|
|
|
74
75
|
def after_commit(opts={}, &block)
|
|
75
76
|
raise Error, "must provide block to after_commit" unless block
|
|
76
77
|
synchronize(opts[:server]) do |conn|
|
|
77
|
-
if h =
|
|
78
|
+
if h = _trans(conn)
|
|
78
79
|
raise Error, "cannot call after_commit in a prepared transaction" if h[:prepare]
|
|
79
80
|
(h[:after_commit] ||= []) << block
|
|
80
81
|
else
|
|
@@ -91,7 +92,7 @@ module Sequel
|
|
|
91
92
|
def after_rollback(opts={}, &block)
|
|
92
93
|
raise Error, "must provide block to after_rollback" unless block
|
|
93
94
|
synchronize(opts[:server]) do |conn|
|
|
94
|
-
if h =
|
|
95
|
+
if h = _trans(conn)
|
|
95
96
|
raise Error, "cannot call after_rollback in a prepared transaction" if h[:prepare]
|
|
96
97
|
(h[:after_rollback] ||= []) << block
|
|
97
98
|
end
|
|
@@ -117,7 +118,7 @@ module Sequel
|
|
|
117
118
|
# false otherwise. Respects the :server option for selecting
|
|
118
119
|
# a shard.
|
|
119
120
|
def in_transaction?(opts={})
|
|
120
|
-
synchronize(opts[:server]){|conn|
|
|
121
|
+
synchronize(opts[:server]){|conn| !!_trans(conn)}
|
|
121
122
|
end
|
|
122
123
|
|
|
123
124
|
# Returns a string representation of the database object including the
|
|
@@ -140,12 +141,22 @@ module Sequel
|
|
|
140
141
|
schema_utility_dataset.literal(v)
|
|
141
142
|
end
|
|
142
143
|
|
|
144
|
+
# Synchronize access to the prepared statements cache.
|
|
145
|
+
def prepared_statement(name)
|
|
146
|
+
Sequel.synchronize{prepared_statements[name]}
|
|
147
|
+
end
|
|
148
|
+
|
|
143
149
|
# Default serial primary key options, used by the table creation
|
|
144
150
|
# code.
|
|
145
151
|
def serial_primary_key_options
|
|
146
152
|
{:primary_key => true, :type => Integer, :auto_increment => true}
|
|
147
153
|
end
|
|
148
154
|
|
|
155
|
+
# Cache the prepared statement object at the given name.
|
|
156
|
+
def set_prepared_statement(name, ps)
|
|
157
|
+
Sequel.synchronize{prepared_statements[name] = ps}
|
|
158
|
+
end
|
|
159
|
+
|
|
149
160
|
# Whether the database supports CREATE TABLE IF NOT EXISTS syntax,
|
|
150
161
|
# false by default.
|
|
151
162
|
def supports_create_table_if_not_exists?
|
|
@@ -180,6 +191,11 @@ module Sequel
|
|
|
180
191
|
false
|
|
181
192
|
end
|
|
182
193
|
|
|
194
|
+
# Whether DDL statements work correctly in transactions, false by default.
|
|
195
|
+
def supports_transactional_ddl?
|
|
196
|
+
false
|
|
197
|
+
end
|
|
198
|
+
|
|
183
199
|
# The timezone to use for this database, defaulting to <tt>Sequel.database_timezone</tt>.
|
|
184
200
|
def timezone
|
|
185
201
|
@timezone || Sequel.database_timezone
|
|
@@ -35,6 +35,11 @@ module Sequel
|
|
|
35
35
|
# Database#transaction, as on MSSQL if affects all future transactions
|
|
36
36
|
# on the same connection.
|
|
37
37
|
attr_accessor :transaction_isolation_level
|
|
38
|
+
|
|
39
|
+
# Whether the schema should be cached for this database. True by default
|
|
40
|
+
# for performance, can be set to false to always issue a database query to
|
|
41
|
+
# get the schema.
|
|
42
|
+
attr_accessor :cache_schema
|
|
38
43
|
|
|
39
44
|
# Runs the supplied SQL statement string on the database server.
|
|
40
45
|
# Returns self so it can be safely chained:
|
|
@@ -51,7 +56,7 @@ module Sequel
|
|
|
51
56
|
# DB[:items].filter(:id=>1).prepare(:first, :sa)
|
|
52
57
|
# DB.call(:sa) # SELECT * FROM items WHERE id = 1
|
|
53
58
|
def call(ps_name, hash={})
|
|
54
|
-
|
|
59
|
+
prepared_statement(ps_name).call(hash)
|
|
55
60
|
end
|
|
56
61
|
|
|
57
62
|
# Executes the given SQL on the database. This method should be overridden in descendants.
|
|
@@ -189,13 +194,14 @@ module Sequel
|
|
|
189
194
|
end
|
|
190
195
|
opts[:schema] = sch if sch && !opts.include?(:schema)
|
|
191
196
|
|
|
192
|
-
@schemas.delete(quoted_name) if opts[:reload]
|
|
193
|
-
return @schemas[quoted_name] if @schemas[quoted_name]
|
|
197
|
+
Sequel.synchronize{@schemas.delete(quoted_name)} if opts[:reload]
|
|
198
|
+
return Sequel.synchronize{@schemas[quoted_name]} if @schemas[quoted_name]
|
|
194
199
|
|
|
195
200
|
cols = schema_parse_table(table_name, opts)
|
|
196
201
|
raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.nil? || cols.empty?
|
|
197
202
|
cols.each{|_,c| c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type])}
|
|
198
|
-
@schemas[quoted_name] = cols
|
|
203
|
+
Sequel.synchronize{@schemas[quoted_name] = cols} if cache_schema
|
|
204
|
+
cols
|
|
199
205
|
end
|
|
200
206
|
|
|
201
207
|
# Returns true if a table with the given name exists. This requires a query
|
|
@@ -286,7 +292,11 @@ module Sequel
|
|
|
286
292
|
yield(conn)
|
|
287
293
|
end
|
|
288
294
|
rescue Exception => e
|
|
289
|
-
|
|
295
|
+
begin
|
|
296
|
+
rollback_transaction(conn, opts)
|
|
297
|
+
rescue Exception => e3
|
|
298
|
+
raise_error(e3, :classes=>database_error_classes, :conn=>conn)
|
|
299
|
+
end
|
|
290
300
|
transaction_error(e, :conn=>conn, :rollback=>rollback)
|
|
291
301
|
ensure
|
|
292
302
|
begin
|
|
@@ -299,36 +309,46 @@ module Sequel
|
|
|
299
309
|
end
|
|
300
310
|
end
|
|
301
311
|
|
|
312
|
+
# Synchronize access to the current transactions, returning the hash
|
|
313
|
+
# of options for the current transaction (if any)
|
|
314
|
+
def _trans(conn)
|
|
315
|
+
Sequel.synchronize{@transactions[conn]}
|
|
316
|
+
end
|
|
317
|
+
|
|
302
318
|
# Add the current thread to the list of active transactions
|
|
303
319
|
def add_transaction(conn, opts)
|
|
304
320
|
if supports_savepoints?
|
|
305
|
-
unless
|
|
306
|
-
|
|
307
|
-
|
|
321
|
+
unless _trans(conn)
|
|
322
|
+
if (prep = opts[:prepare]) && supports_prepared_transactions?
|
|
323
|
+
Sequel.synchronize{@transactions[conn] = {:savepoint_level=>0, :prepare=>prep}}
|
|
324
|
+
else
|
|
325
|
+
Sequel.synchronize{@transactions[conn] = {:savepoint_level=>0}}
|
|
326
|
+
end
|
|
308
327
|
end
|
|
328
|
+
elsif (prep = opts[:prepare]) && supports_prepared_transactions?
|
|
329
|
+
Sequel.synchronize{@transactions[conn] = {:prepare => prep}}
|
|
309
330
|
else
|
|
310
|
-
@transactions[conn] = {}
|
|
311
|
-
@transactions[conn][:prepare] = opts[:prepare] if opts[:prepare] && supports_prepared_transactions?
|
|
331
|
+
Sequel.synchronize{@transactions[conn] = {}}
|
|
312
332
|
end
|
|
313
333
|
end
|
|
314
334
|
|
|
315
335
|
# Call all stored after_commit blocks for the given transaction
|
|
316
336
|
def after_transaction_commit(conn)
|
|
317
|
-
if ary =
|
|
337
|
+
if ary = _trans(conn)[:after_commit]
|
|
318
338
|
ary.each{|b| b.call}
|
|
319
339
|
end
|
|
320
340
|
end
|
|
321
341
|
|
|
322
342
|
# Call all stored after_rollback blocks for the given transaction
|
|
323
343
|
def after_transaction_rollback(conn)
|
|
324
|
-
if ary =
|
|
344
|
+
if ary = _trans(conn)[:after_rollback]
|
|
325
345
|
ary.each{|b| b.call}
|
|
326
346
|
end
|
|
327
347
|
end
|
|
328
348
|
|
|
329
349
|
# Whether the current thread/connection is already inside a transaction
|
|
330
350
|
def already_in_transaction?(conn, opts)
|
|
331
|
-
|
|
351
|
+
_trans(conn) && (!supports_savepoints? || !opts[:savepoint])
|
|
332
352
|
end
|
|
333
353
|
|
|
334
354
|
# SQL to start a new savepoint
|
|
@@ -345,7 +365,7 @@ module Sequel
|
|
|
345
365
|
# Start a new database transaction or a new savepoint on the given connection.
|
|
346
366
|
def begin_transaction(conn, opts={})
|
|
347
367
|
if supports_savepoints?
|
|
348
|
-
th =
|
|
368
|
+
th = _trans(conn)
|
|
349
369
|
if (depth = th[:savepoint_level]) > 0
|
|
350
370
|
log_connection_execute(conn, begin_savepoint_sql(depth))
|
|
351
371
|
else
|
|
@@ -452,7 +472,7 @@ module Sequel
|
|
|
452
472
|
# Commit the active transaction on the connection
|
|
453
473
|
def commit_transaction(conn, opts={})
|
|
454
474
|
if supports_savepoints?
|
|
455
|
-
depth =
|
|
475
|
+
depth = _trans(conn)[:savepoint_level]
|
|
456
476
|
log_connection_execute(conn, depth > 1 ? commit_savepoint_sql(depth-1) : commit_transaction_sql)
|
|
457
477
|
else
|
|
458
478
|
log_connection_execute(conn, commit_transaction_sql)
|
|
@@ -502,7 +522,7 @@ module Sequel
|
|
|
502
522
|
|
|
503
523
|
# Remove the current thread from the list of active transactions
|
|
504
524
|
def remove_transaction(conn, committed)
|
|
505
|
-
if !supports_savepoints? || ((
|
|
525
|
+
if !supports_savepoints? || ((_trans(conn)[:savepoint_level] -= 1) <= 0)
|
|
506
526
|
begin
|
|
507
527
|
if committed
|
|
508
528
|
after_transaction_commit(conn)
|
|
@@ -510,7 +530,7 @@ module Sequel
|
|
|
510
530
|
after_transaction_rollback(conn)
|
|
511
531
|
end
|
|
512
532
|
ensure
|
|
513
|
-
@transactions.delete(conn)
|
|
533
|
+
Sequel.synchronize{@transactions.delete(conn)}
|
|
514
534
|
end
|
|
515
535
|
end
|
|
516
536
|
end
|
|
@@ -523,7 +543,7 @@ module Sequel
|
|
|
523
543
|
# Rollback the active transaction on the connection
|
|
524
544
|
def rollback_transaction(conn, opts={})
|
|
525
545
|
if supports_savepoints?
|
|
526
|
-
depth =
|
|
546
|
+
depth = _trans(conn)[:savepoint_level]
|
|
527
547
|
log_connection_execute(conn, depth > 1 ? rollback_savepoint_sql(depth-1) : rollback_transaction_sql)
|
|
528
548
|
else
|
|
529
549
|
log_connection_execute(conn, rollback_transaction_sql)
|