sequel 3.34.1 → 3.35.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|