sequel 4.21.0 → 4.22.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 +32 -0
- data/README.rdoc +3 -4
- data/doc/opening_databases.rdoc +10 -75
- data/doc/release_notes/4.22.0.txt +72 -0
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/cubrid.rb +3 -3
- data/lib/sequel/adapters/db2.rb +1 -0
- data/lib/sequel/adapters/dbi.rb +1 -0
- data/lib/sequel/adapters/fdbsql.rb +3 -2
- data/lib/sequel/adapters/firebird.rb +1 -0
- data/lib/sequel/adapters/ibmdb.rb +1 -21
- data/lib/sequel/adapters/informix.rb +1 -0
- data/lib/sequel/adapters/jdbc.rb +37 -49
- data/lib/sequel/adapters/jdbc/fdbsql.rb +1 -0
- data/lib/sequel/adapters/mysql.rb +5 -3
- data/lib/sequel/adapters/mysql2.rb +5 -2
- data/lib/sequel/adapters/odbc.rb +8 -4
- data/lib/sequel/adapters/openbase.rb +1 -0
- data/lib/sequel/adapters/oracle.rb +3 -46
- data/lib/sequel/adapters/postgres.rb +3 -36
- data/lib/sequel/adapters/shared/access.rb +1 -1
- data/lib/sequel/adapters/shared/fdbsql.rb +3 -3
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +12 -44
- data/lib/sequel/adapters/shared/oracle.rb +6 -2
- data/lib/sequel/adapters/shared/postgres.rb +6 -6
- data/lib/sequel/adapters/shared/sqlite.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +3 -46
- data/lib/sequel/adapters/tinytds.rb +12 -28
- data/lib/sequel/adapters/utils/pg_types.rb +1 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +63 -16
- data/lib/sequel/connection_pool/threaded.rb +72 -18
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/connecting.rb +2 -2
- data/lib/sequel/database/misc.rb +5 -5
- data/lib/sequel/database/query.rb +3 -2
- data/lib/sequel/database/schema_generator.rb +19 -19
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/database/transactions.rb +3 -3
- data/lib/sequel/dataset/actions.rb +18 -8
- data/lib/sequel/dataset/graph.rb +2 -2
- data/lib/sequel/dataset/prepared_statements.rb +28 -1
- data/lib/sequel/dataset/query.rb +7 -7
- data/lib/sequel/exceptions.rb +27 -24
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/constraint_validations.rb +2 -2
- data/lib/sequel/extensions/date_arithmetic.rb +2 -2
- data/lib/sequel/extensions/pg_array.rb +10 -1
- data/lib/sequel/extensions/pg_row.rb +1 -1
- data/lib/sequel/extensions/pg_static_cache_updater.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +8 -8
- data/lib/sequel/extensions/split_array_nil.rb +1 -1
- data/lib/sequel/model.rb +1 -1
- data/lib/sequel/model/associations.rb +18 -11
- data/lib/sequel/model/base.rb +15 -15
- data/lib/sequel/model/exceptions.rb +11 -2
- data/lib/sequel/plugins/accessed_columns.rb +1 -1
- data/lib/sequel/plugins/auto_validations.rb +1 -1
- data/lib/sequel/plugins/boolean_readers.rb +1 -1
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -7
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/constraint_validations.rb +2 -2
- data/lib/sequel/plugins/csv_serializer.rb +171 -0
- data/lib/sequel/plugins/dirty.rb +2 -2
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +5 -5
- data/lib/sequel/plugins/pg_array_associations.rb +4 -4
- data/lib/sequel/plugins/prepared_statements.rb +2 -2
- data/lib/sequel/plugins/prepared_statements_safe.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +6 -6
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +3 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +5 -13
- data/lib/sequel/plugins/static_cache.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/plugins/tree.rb +1 -1
- data/lib/sequel/plugins/validation_class_methods.rb +2 -2
- data/lib/sequel/plugins/validation_helpers.rb +4 -4
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +17 -0
- data/spec/core/connection_pool_spec.rb +1 -1
- data/spec/core/dataset_spec.rb +22 -0
- data/spec/extensions/auto_validations_spec.rb +1 -1
- data/spec/extensions/blacklist_security_spec.rb +2 -2
- data/spec/extensions/csv_serializer_spec.rb +173 -0
- data/spec/extensions/json_serializer_spec.rb +2 -2
- data/spec/extensions/nested_attributes_spec.rb +9 -9
- data/spec/extensions/pg_array_spec.rb +5 -0
- data/spec/extensions/single_table_inheritance_spec.rb +21 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/tree_spec.rb +4 -0
- data/spec/extensions/xml_serializer_spec.rb +3 -3
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +7 -0
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +108 -14
- data/spec/model/base_spec.rb +8 -8
- data/spec/model/record_spec.rb +7 -7
- metadata +6 -2
|
@@ -71,18 +71,24 @@ module Sequel
|
|
|
71
71
|
|
|
72
72
|
# Return the number of rows modified by the given +sql+.
|
|
73
73
|
def execute_dui(sql, opts=OPTS)
|
|
74
|
-
|
|
74
|
+
opts = Hash[opts]
|
|
75
|
+
opts[:return] = :do
|
|
76
|
+
execute(sql, opts)
|
|
75
77
|
end
|
|
76
78
|
|
|
77
79
|
# Return the value of the autogenerated primary key (if any)
|
|
78
80
|
# for the row inserted by the given +sql+.
|
|
79
81
|
def execute_insert(sql, opts=OPTS)
|
|
80
|
-
|
|
82
|
+
opts = Hash[opts]
|
|
83
|
+
opts[:return] = :insert
|
|
84
|
+
execute(sql, opts)
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
# Execute the DDL +sql+ on the database and return nil.
|
|
84
88
|
def execute_ddl(sql, opts=OPTS)
|
|
85
|
-
|
|
89
|
+
opts = Hash[opts]
|
|
90
|
+
opts[:return] = :each
|
|
91
|
+
execute(sql, opts)
|
|
86
92
|
nil
|
|
87
93
|
end
|
|
88
94
|
|
|
@@ -202,30 +208,8 @@ module Sequel
|
|
|
202
208
|
end
|
|
203
209
|
end
|
|
204
210
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
module PreparedStatementMethods
|
|
208
|
-
include ArgumentMapper
|
|
209
|
-
|
|
210
|
-
private
|
|
211
|
-
|
|
212
|
-
# Run execute_select on the database with the given SQL and the stored
|
|
213
|
-
# bind arguments.
|
|
214
|
-
def execute(sql, opts=OPTS, &block)
|
|
215
|
-
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
# Same as execute, explicit due to intricacies of alias and super.
|
|
219
|
-
def execute_dui(sql, opts=OPTS, &block)
|
|
220
|
-
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
# Same as execute, explicit due to intricacies of alias and super.
|
|
224
|
-
def execute_insert(sql, opts=OPTS, &block)
|
|
225
|
-
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
211
|
+
PreparedStatementMethods = prepared_statements_module("sql = prepared_sql; opts = Hash[opts]; opts[:arguments] = bind_arguments", ArgumentMapper)
|
|
212
|
+
|
|
229
213
|
# Yield hashes with symbol keys, attempting to optimize for
|
|
230
214
|
# various cases.
|
|
231
215
|
def fetch_rows(sql)
|
|
@@ -238,7 +222,7 @@ module Sequel
|
|
|
238
222
|
result.each(*args) do |r|
|
|
239
223
|
unless cols
|
|
240
224
|
cols = result.fields.map{|c| [c, output_identifier(c)]}
|
|
241
|
-
@columns = columns = cols.map
|
|
225
|
+
@columns = columns = cols.map(&:last)
|
|
242
226
|
end
|
|
243
227
|
h = {}
|
|
244
228
|
cols.each do |s, sym|
|
|
@@ -18,6 +18,12 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
18
18
|
@available_connections = {}
|
|
19
19
|
@connections_to_remove = []
|
|
20
20
|
@servers = opts.fetch(:servers_hash, Hash.new(:default))
|
|
21
|
+
|
|
22
|
+
if USE_WAITER
|
|
23
|
+
@waiter = nil
|
|
24
|
+
@waiters = {}
|
|
25
|
+
end
|
|
26
|
+
|
|
21
27
|
add_servers([:default])
|
|
22
28
|
add_servers(opts[:servers].keys) if opts[:servers]
|
|
23
29
|
end
|
|
@@ -32,6 +38,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
32
38
|
@servers[server] = server
|
|
33
39
|
@available_connections[server] = []
|
|
34
40
|
@allocated[server] = {}
|
|
41
|
+
@waiters[server] = ConditionVariable.new if USE_WAITER
|
|
35
42
|
end
|
|
36
43
|
end
|
|
37
44
|
end
|
|
@@ -115,16 +122,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
115
122
|
return yield(conn)
|
|
116
123
|
end
|
|
117
124
|
begin
|
|
118
|
-
|
|
119
|
-
time = Time.now
|
|
120
|
-
timeout = time + @timeout
|
|
121
|
-
sleep_time = @sleep_time
|
|
122
|
-
sleep sleep_time
|
|
123
|
-
until conn = acquire(t, server)
|
|
124
|
-
raise(::Sequel::PoolTimeout) if Time.now > timeout
|
|
125
|
-
sleep sleep_time
|
|
126
|
-
end
|
|
127
|
-
end
|
|
125
|
+
conn = acquire(t, server)
|
|
128
126
|
yield conn
|
|
129
127
|
rescue Sequel::DatabaseDisconnectError
|
|
130
128
|
sync{@connections_to_remove << conn} if conn
|
|
@@ -144,6 +142,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
144
142
|
servers.each do |server|
|
|
145
143
|
if @servers.include?(server)
|
|
146
144
|
disconnect_server(server)
|
|
145
|
+
@waiters.delete(server) if USE_WAITER
|
|
147
146
|
@available_connections.delete(server)
|
|
148
147
|
@allocated.delete(server)
|
|
149
148
|
@servers.delete(server)
|
|
@@ -164,16 +163,60 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
164
163
|
private
|
|
165
164
|
|
|
166
165
|
# Assigns a connection to the supplied thread for the given server, if one
|
|
167
|
-
# is available. The calling code should
|
|
166
|
+
# is available. The calling code should already have the mutex when
|
|
168
167
|
# calling this.
|
|
169
|
-
def
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
allocated(server)[thread] = conn
|
|
173
|
-
end
|
|
168
|
+
def _acquire(thread, server)
|
|
169
|
+
if conn = available(server)
|
|
170
|
+
allocated(server)[thread] = conn
|
|
174
171
|
end
|
|
175
172
|
end
|
|
176
173
|
|
|
174
|
+
if USE_WAITER
|
|
175
|
+
# Assigns a connection to the supplied thread, if one
|
|
176
|
+
# is available. The calling code should NOT already have the mutex when
|
|
177
|
+
# calling this.
|
|
178
|
+
#
|
|
179
|
+
# This should return a connection is one is available within the timeout,
|
|
180
|
+
# or nil if a connection could not be acquired within the timeout.
|
|
181
|
+
def acquire(thread, server)
|
|
182
|
+
sync do
|
|
183
|
+
if conn = _acquire(thread, server)
|
|
184
|
+
return conn
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
time = Time.now
|
|
188
|
+
@waiters[server].wait(@mutex, @timeout)
|
|
189
|
+
Thread.pass
|
|
190
|
+
|
|
191
|
+
until conn = _acquire(thread, server)
|
|
192
|
+
deadline ||= time + @timeout
|
|
193
|
+
current_time = Time.now
|
|
194
|
+
raise(::Sequel::PoolTimeout, "timeout: #{@timeout}, elapsed: #{current_time - time}") if current_time > deadline
|
|
195
|
+
@waiters[server].wait(@mutex, deadline - current_time)
|
|
196
|
+
Thread.pass
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
conn
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
else
|
|
203
|
+
# :nocov:
|
|
204
|
+
def acquire(thread, server)
|
|
205
|
+
unless conn = sync{_acquire(thread, server)}
|
|
206
|
+
time = Time.now
|
|
207
|
+
timeout = time + @timeout
|
|
208
|
+
sleep_time = @sleep_time
|
|
209
|
+
sleep sleep_time
|
|
210
|
+
until conn = sync{_acquire(thread, server)}
|
|
211
|
+
raise(::Sequel::PoolTimeout, "timeout: #{@timeout}, elapsed: #{Time.now - time}") if Time.now > timeout
|
|
212
|
+
sleep sleep_time
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
conn
|
|
216
|
+
end
|
|
217
|
+
# :nocov:
|
|
218
|
+
end
|
|
219
|
+
|
|
177
220
|
# Returns an available connection to the given server. If no connection is
|
|
178
221
|
# available, tries to create a new connection. The calling code should already
|
|
179
222
|
# have the mutex before calling this.
|
|
@@ -186,6 +229,10 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
186
229
|
# before calling this.
|
|
187
230
|
def checkin_connection(server, conn)
|
|
188
231
|
available_connections(server) << conn
|
|
232
|
+
if USE_WAITER
|
|
233
|
+
@waiters[server].signal
|
|
234
|
+
Thread.pass
|
|
235
|
+
end
|
|
189
236
|
conn
|
|
190
237
|
end
|
|
191
238
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# A connection pool allowing multi-threaded access to a pool of connections.
|
|
2
2
|
# This is the default connection pool used by Sequel.
|
|
3
3
|
class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
4
|
+
# Whether or not a ConditionVariable should be used to wait for connections.
|
|
5
|
+
# True except on ruby 1.8, where ConditionVariable#wait does not support a
|
|
6
|
+
# timeout.
|
|
7
|
+
USE_WAITER = RUBY_VERSION >= '1.9'
|
|
8
|
+
|
|
4
9
|
# The maximum number of connections this pool will create (per shard/server
|
|
5
10
|
# if sharding).
|
|
6
11
|
attr_reader :max_size
|
|
@@ -19,7 +24,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
19
24
|
# * :max_connections - The maximum number of connections the connection pool
|
|
20
25
|
# will open (default 4)
|
|
21
26
|
# * :pool_sleep_time - The amount of time to sleep before attempting to acquire
|
|
22
|
-
# a connection again (default 0.001)
|
|
27
|
+
# a connection again, only used on ruby 1.8. (default 0.001)
|
|
23
28
|
# * :pool_timeout - The amount of seconds to wait to acquire a connection
|
|
24
29
|
# before raising a PoolTimeoutError (default 5)
|
|
25
30
|
def initialize(db, opts = OPTS)
|
|
@@ -31,7 +36,12 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
31
36
|
@available_connections = []
|
|
32
37
|
@allocated = {}
|
|
33
38
|
@timeout = Float(opts[:pool_timeout] || 5)
|
|
34
|
-
|
|
39
|
+
|
|
40
|
+
if USE_WAITER
|
|
41
|
+
@waiter = ConditionVariable.new
|
|
42
|
+
else
|
|
43
|
+
@sleep_time = Float(opts[:pool_sleep_time] || 0.001)
|
|
44
|
+
end
|
|
35
45
|
end
|
|
36
46
|
|
|
37
47
|
# Yield all of the available connections, and the one currently allocated to
|
|
@@ -85,16 +95,7 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
85
95
|
return yield(conn)
|
|
86
96
|
end
|
|
87
97
|
begin
|
|
88
|
-
|
|
89
|
-
time = Time.now
|
|
90
|
-
timeout = time + @timeout
|
|
91
|
-
sleep_time = @sleep_time
|
|
92
|
-
sleep sleep_time
|
|
93
|
-
until conn = acquire(t)
|
|
94
|
-
raise(::Sequel::PoolTimeout) if Time.now > timeout
|
|
95
|
-
sleep sleep_time
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
+
conn = acquire(t)
|
|
98
99
|
yield conn
|
|
99
100
|
rescue Sequel::DatabaseDisconnectError
|
|
100
101
|
oconn = conn
|
|
@@ -120,16 +121,65 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
120
121
|
private
|
|
121
122
|
|
|
122
123
|
# Assigns a connection to the supplied thread, if one
|
|
123
|
-
# is available. The calling code should
|
|
124
|
+
# is available. The calling code should already have the mutex when
|
|
124
125
|
# calling this.
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
@allocated[thread] = conn
|
|
129
|
-
end
|
|
126
|
+
def _acquire(thread)
|
|
127
|
+
if conn = available
|
|
128
|
+
@allocated[thread] = conn
|
|
130
129
|
end
|
|
131
130
|
end
|
|
132
131
|
|
|
132
|
+
if USE_WAITER
|
|
133
|
+
# Assigns a connection to the supplied thread, if one
|
|
134
|
+
# is available. The calling code should NOT already have the mutex when
|
|
135
|
+
# calling this.
|
|
136
|
+
#
|
|
137
|
+
# This should return a connection is one is available within the timeout,
|
|
138
|
+
# or nil if a connection could not be acquired within the timeout.
|
|
139
|
+
def acquire(thread)
|
|
140
|
+
sync do
|
|
141
|
+
if conn = _acquire(thread)
|
|
142
|
+
return conn
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
time = Time.now
|
|
146
|
+
@waiter.wait(@mutex, @timeout)
|
|
147
|
+
|
|
148
|
+
# Not sure why this is helpful, but calling Thread.pass after conditional
|
|
149
|
+
# variable access dramatically increases reliability when under heavy
|
|
150
|
+
# resource contention (almost eliminating timeouts), at a small cost to
|
|
151
|
+
# runtime performance.
|
|
152
|
+
Thread.pass
|
|
153
|
+
|
|
154
|
+
until conn = _acquire(thread)
|
|
155
|
+
deadline ||= time + @timeout
|
|
156
|
+
current_time = Time.now
|
|
157
|
+
raise(::Sequel::PoolTimeout, "timeout: #{@timeout}, elapsed: #{current_time - time}") if current_time > deadline
|
|
158
|
+
@waiter.wait(@mutex, deadline - current_time)
|
|
159
|
+
Thread.pass
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
conn
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
else
|
|
166
|
+
# :nocov:
|
|
167
|
+
def acquire(thread)
|
|
168
|
+
unless conn = sync{_acquire(thread)}
|
|
169
|
+
time = Time.now
|
|
170
|
+
timeout = time + @timeout
|
|
171
|
+
sleep_time = @sleep_time
|
|
172
|
+
sleep sleep_time
|
|
173
|
+
until conn = sync{_acquire(thread)}
|
|
174
|
+
raise(::Sequel::PoolTimeout, "timeout: #{@timeout}, elapsed: #{Time.now - time}") if Time.now > timeout
|
|
175
|
+
sleep sleep_time
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
conn
|
|
179
|
+
end
|
|
180
|
+
# :nocov:
|
|
181
|
+
end
|
|
182
|
+
|
|
133
183
|
# Returns an available connection. If no connection is
|
|
134
184
|
# available, tries to create a new connection. The calling code should already
|
|
135
185
|
# have the mutex before calling this.
|
|
@@ -141,6 +191,10 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
141
191
|
# The calling code should already have the mutex before calling this.
|
|
142
192
|
def checkin_connection(conn)
|
|
143
193
|
@available_connections << conn
|
|
194
|
+
if USE_WAITER
|
|
195
|
+
@waiter.signal
|
|
196
|
+
Thread.pass
|
|
197
|
+
end
|
|
144
198
|
conn
|
|
145
199
|
end
|
|
146
200
|
|
data/lib/sequel/core.rb
CHANGED
|
@@ -328,7 +328,7 @@ module Sequel
|
|
|
328
328
|
def self.transaction(dbs, opts=OPTS, &block)
|
|
329
329
|
unless opts[:rollback]
|
|
330
330
|
rescue_rollback = true
|
|
331
|
-
opts = opts.merge(:rollback=>:reraise)
|
|
331
|
+
opts = Hash[opts].merge!(:rollback=>:reraise)
|
|
332
332
|
end
|
|
333
333
|
pr = dbs.reverse.inject(block){|bl, db| proc{db.transaction(opts, &bl)}}
|
|
334
334
|
if rescue_rollback
|
|
@@ -6,7 +6,7 @@ module Sequel
|
|
|
6
6
|
# ---------------------
|
|
7
7
|
|
|
8
8
|
# Array of supported database adapters
|
|
9
|
-
ADAPTERS = %w'ado amalgalite cubrid db2 dbi do fdbsql firebird ibmdb informix jdbc mock mysql mysql2 odbc openbase oracle postgres sqlanywhere sqlite swift tinytds'.collect
|
|
9
|
+
ADAPTERS = %w'ado amalgalite cubrid db2 dbi do fdbsql firebird ibmdb informix jdbc mock mysql mysql2 odbc openbase oracle postgres sqlanywhere sqlite swift tinytds'.collect(&:to_sym)
|
|
10
10
|
|
|
11
11
|
@single_threaded = false
|
|
12
12
|
|
|
@@ -38,7 +38,7 @@ module Sequel
|
|
|
38
38
|
if match = /\A(jdbc|do):/o.match(conn_string)
|
|
39
39
|
c = adapter_class(match[1].to_sym)
|
|
40
40
|
opts = opts.merge(:orig_opts=>opts.dup)
|
|
41
|
-
opts = {:uri=>conn_string}.merge(opts)
|
|
41
|
+
opts = {:uri=>conn_string}.merge!(opts)
|
|
42
42
|
else
|
|
43
43
|
uri = URI.parse(conn_string)
|
|
44
44
|
scheme = uri.scheme
|
data/lib/sequel/database/misc.rb
CHANGED
|
@@ -390,11 +390,11 @@ module Sequel
|
|
|
390
390
|
nil
|
|
391
391
|
end
|
|
392
392
|
|
|
393
|
-
NOT_NULL_CONSTRAINT_SQLSTATES = %w'23502'.freeze.each
|
|
394
|
-
FOREIGN_KEY_CONSTRAINT_SQLSTATES = %w'23503 23506 23504'.freeze.each
|
|
395
|
-
UNIQUE_CONSTRAINT_SQLSTATES = %w'23505'.freeze.each
|
|
396
|
-
CHECK_CONSTRAINT_SQLSTATES = %w'23513 23514'.freeze.each
|
|
397
|
-
SERIALIZATION_CONSTRAINT_SQLSTATES = %w'40001'.freeze.each
|
|
393
|
+
NOT_NULL_CONSTRAINT_SQLSTATES = %w'23502'.freeze.each(&:freeze)
|
|
394
|
+
FOREIGN_KEY_CONSTRAINT_SQLSTATES = %w'23503 23506 23504'.freeze.each(&:freeze)
|
|
395
|
+
UNIQUE_CONSTRAINT_SQLSTATES = %w'23505'.freeze.each(&:freeze)
|
|
396
|
+
CHECK_CONSTRAINT_SQLSTATES = %w'23513 23514'.freeze.each(&:freeze)
|
|
397
|
+
SERIALIZATION_CONSTRAINT_SQLSTATES = %w'40001'.freeze.each(&:freeze)
|
|
398
398
|
# Given the SQLState, return the appropriate DatabaseError subclass.
|
|
399
399
|
def database_specific_error_class_from_sqlstate(sqlstate)
|
|
400
400
|
case sqlstate
|
|
@@ -91,7 +91,8 @@ module Sequel
|
|
|
91
91
|
#
|
|
92
92
|
# :allow_null :: Whether NULL is an allowed value for the column.
|
|
93
93
|
# :db_type :: The database type for the column, as a database specific string.
|
|
94
|
-
# :default :: The database default for the column, as a database specific string
|
|
94
|
+
# :default :: The database default for the column, as a database specific string, or nil if there is
|
|
95
|
+
# no default value.
|
|
95
96
|
# :primary_key :: Whether the columns is a primary key column. If this column is not present,
|
|
96
97
|
# it means that primary key information is unavailable, not that the column
|
|
97
98
|
# is not a primary key.
|
|
@@ -166,7 +167,7 @@ module Sequel
|
|
|
166
167
|
end
|
|
167
168
|
|
|
168
169
|
cols.each do |_,c|
|
|
169
|
-
c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type])
|
|
170
|
+
c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type]) unless c.has_key?(:ruby_default)
|
|
170
171
|
if c[:primary_key] && !auto_increment_set
|
|
171
172
|
# If adapter didn't set it, assume that integer primary keys are auto incrementing
|
|
172
173
|
c[:auto_increment] = primary_keys == 1 && !!(c[:db_type] =~ /int/io)
|
|
@@ -109,7 +109,7 @@ module Sequel
|
|
|
109
109
|
# creating a unique index on the column.
|
|
110
110
|
# :unique_constraint_name :: The name to give the unique key constraint
|
|
111
111
|
def column(name, type, opts = OPTS)
|
|
112
|
-
columns << {:name => name, :type => type}.merge(opts)
|
|
112
|
+
columns << {:name => name, :type => type}.merge!(opts)
|
|
113
113
|
if index_opts = opts[:index]
|
|
114
114
|
index(name, index_opts.is_a?(Hash) ? index_opts : {})
|
|
115
115
|
end
|
|
@@ -206,7 +206,7 @@ module Sequel
|
|
|
206
206
|
# index [:artist_id, :name]
|
|
207
207
|
# # CREATE INDEX table_artist_id_name_index ON table (artist_id, name)
|
|
208
208
|
def index(columns, opts = OPTS)
|
|
209
|
-
indexes << {:columns => Array(columns)}.merge(opts)
|
|
209
|
+
indexes << {:columns => Array(columns)}.merge!(opts)
|
|
210
210
|
end
|
|
211
211
|
|
|
212
212
|
# Add a column with the given type, name, and opts to the DDL. See +column+ for available
|
|
@@ -267,7 +267,7 @@ module Sequel
|
|
|
267
267
|
# Supports the same :deferrable option as #column. The :name option can be used
|
|
268
268
|
# to name the constraint.
|
|
269
269
|
def unique(columns, opts = OPTS)
|
|
270
|
-
constraints << {:type => :unique, :columns => Array(columns)}.merge(opts)
|
|
270
|
+
constraints << {:type => :unique, :columns => Array(columns)}.merge!(opts)
|
|
271
271
|
end
|
|
272
272
|
|
|
273
273
|
private
|
|
@@ -275,12 +275,12 @@ module Sequel
|
|
|
275
275
|
# Add a composite primary key constraint
|
|
276
276
|
def composite_primary_key(columns, *args)
|
|
277
277
|
opts = args.pop || {}
|
|
278
|
-
constraints << {:type => :primary_key, :columns => columns}.merge(opts)
|
|
278
|
+
constraints << {:type => :primary_key, :columns => columns}.merge!(opts)
|
|
279
279
|
end
|
|
280
280
|
|
|
281
281
|
# Add a composite foreign key constraint
|
|
282
282
|
def composite_foreign_key(columns, opts)
|
|
283
|
-
constraints << {:type => :foreign_key, :columns => columns}.merge(opts)
|
|
283
|
+
constraints << {:type => :foreign_key, :columns => columns}.merge!(opts)
|
|
284
284
|
end
|
|
285
285
|
|
|
286
286
|
add_type_method(*GENERIC_TYPES)
|
|
@@ -315,7 +315,7 @@ module Sequel
|
|
|
315
315
|
#
|
|
316
316
|
# add_column(:name, String) # ADD COLUMN name varchar(255)
|
|
317
317
|
def add_column(name, type, opts = OPTS)
|
|
318
|
-
@operations << {:op => :add_column, :name => name, :type => type}.merge(opts)
|
|
318
|
+
@operations << {:op => :add_column, :name => name, :type => type}.merge!(opts)
|
|
319
319
|
end
|
|
320
320
|
|
|
321
321
|
# Add a constraint with the given name and args to the DDL for the table.
|
|
@@ -337,7 +337,7 @@ module Sequel
|
|
|
337
337
|
#
|
|
338
338
|
# Supports the same :deferrable option as CreateTableGenerator#column.
|
|
339
339
|
def add_unique_constraint(columns, opts = OPTS)
|
|
340
|
-
@operations << {:op => :add_constraint, :type => :unique, :columns => Array(columns)}.merge(opts)
|
|
340
|
+
@operations << {:op => :add_constraint, :type => :unique, :columns => Array(columns)}.merge!(opts)
|
|
341
341
|
end
|
|
342
342
|
|
|
343
343
|
# Add a foreign key with the given name and referencing the given table
|
|
@@ -364,13 +364,13 @@ module Sequel
|
|
|
364
364
|
# sense when using an array of columns.
|
|
365
365
|
def add_foreign_key(name, table, opts = OPTS)
|
|
366
366
|
return add_composite_foreign_key(name, table, opts) if name.is_a?(Array)
|
|
367
|
-
add_column(name, Integer, {:table=>table}.merge(opts))
|
|
367
|
+
add_column(name, Integer, {:table=>table}.merge!(opts))
|
|
368
368
|
end
|
|
369
369
|
|
|
370
370
|
# Add a full text index on the given columns to the DDL for the table.
|
|
371
371
|
# See CreateTableGenerator#index for available options.
|
|
372
372
|
def add_full_text_index(columns, opts = OPTS)
|
|
373
|
-
add_index(columns, {:type=>:full_text}.merge(opts))
|
|
373
|
+
add_index(columns, {:type=>:full_text}.merge!(opts))
|
|
374
374
|
end
|
|
375
375
|
|
|
376
376
|
# Add an index on the given columns to the DDL for the table. See
|
|
@@ -378,7 +378,7 @@ module Sequel
|
|
|
378
378
|
#
|
|
379
379
|
# add_index(:artist_id) # CREATE INDEX table_artist_id_index ON table (artist_id)
|
|
380
380
|
def add_index(columns, opts = OPTS)
|
|
381
|
-
@operations << {:op => :add_index, :columns => Array(columns)}.merge(opts)
|
|
381
|
+
@operations << {:op => :add_index, :columns => Array(columns)}.merge!(opts)
|
|
382
382
|
end
|
|
383
383
|
|
|
384
384
|
# Add a primary key to the DDL for the table. See CreateTableGenerator#column
|
|
@@ -396,7 +396,7 @@ module Sequel
|
|
|
396
396
|
# Add a spatial index on the given columns to the DDL for the table.
|
|
397
397
|
# See CreateTableGenerator#index for available options.
|
|
398
398
|
def add_spatial_index(columns, opts = OPTS)
|
|
399
|
-
add_index(columns, {:type=>:spatial}.merge(opts))
|
|
399
|
+
add_index(columns, {:type=>:spatial}.merge!(opts))
|
|
400
400
|
end
|
|
401
401
|
|
|
402
402
|
# Remove a column from the DDL for the table.
|
|
@@ -404,7 +404,7 @@ module Sequel
|
|
|
404
404
|
# drop_column(:artist_id) # DROP COLUMN artist_id
|
|
405
405
|
# drop_column(:artist_id, :cascade=>true) # DROP COLUMN artist_id CASCADE
|
|
406
406
|
def drop_column(name, opts=OPTS)
|
|
407
|
-
@operations << {:op => :drop_column, :name => name}.merge(opts)
|
|
407
|
+
@operations << {:op => :drop_column, :name => name}.merge!(opts)
|
|
408
408
|
end
|
|
409
409
|
|
|
410
410
|
# Remove a constraint from the DDL for the table. MySQL/SQLite specific options:
|
|
@@ -415,7 +415,7 @@ module Sequel
|
|
|
415
415
|
# drop_constraint(:unique_name) # DROP CONSTRAINT unique_name
|
|
416
416
|
# drop_constraint(:unique_name, :cascade=>true) # DROP CONSTRAINT unique_name CASCADE
|
|
417
417
|
def drop_constraint(name, opts=OPTS)
|
|
418
|
-
@operations << {:op => :drop_constraint, :name => name}.merge(opts)
|
|
418
|
+
@operations << {:op => :drop_constraint, :name => name}.merge!(opts)
|
|
419
419
|
end
|
|
420
420
|
|
|
421
421
|
# Remove a foreign key and the associated column from the DDL for the table. General options:
|
|
@@ -449,14 +449,14 @@ module Sequel
|
|
|
449
449
|
# drop_index([:a, :b]) # DROP INDEX table_a_b_index
|
|
450
450
|
# drop_index([:a, :b], :name=>:foo) # DROP INDEX foo
|
|
451
451
|
def drop_index(columns, options=OPTS)
|
|
452
|
-
@operations << {:op => :drop_index, :columns => Array(columns)}.merge(options)
|
|
452
|
+
@operations << {:op => :drop_index, :columns => Array(columns)}.merge!(options)
|
|
453
453
|
end
|
|
454
454
|
|
|
455
455
|
# Modify a column's name in the DDL for the table.
|
|
456
456
|
#
|
|
457
457
|
# rename_column(:name, :artist_name) # RENAME COLUMN name TO artist_name
|
|
458
458
|
def rename_column(name, new_name, opts = OPTS)
|
|
459
|
-
@operations << {:op => :rename_column, :name => name, :new_name => new_name}.merge(opts)
|
|
459
|
+
@operations << {:op => :rename_column, :name => name, :new_name => new_name}.merge!(opts)
|
|
460
460
|
end
|
|
461
461
|
|
|
462
462
|
# Modify a column's default value in the DDL for the table.
|
|
@@ -480,7 +480,7 @@ module Sequel
|
|
|
480
480
|
# On MySQL, make sure to use a symbol for the name of the column, as otherwise you
|
|
481
481
|
# can lose the default and NULL/NOT NULL setting for the column.
|
|
482
482
|
def set_column_type(name, type, opts=OPTS)
|
|
483
|
-
@operations << {:op => :set_column_type, :name => name, :type => type}.merge(opts)
|
|
483
|
+
@operations << {:op => :set_column_type, :name => name, :type => type}.merge!(opts)
|
|
484
484
|
end
|
|
485
485
|
|
|
486
486
|
# Set a given column as allowing NULL values.
|
|
@@ -507,17 +507,17 @@ module Sequel
|
|
|
507
507
|
|
|
508
508
|
# Add a composite primary key constraint
|
|
509
509
|
def add_composite_primary_key(columns, opts)
|
|
510
|
-
@operations << {:op => :add_constraint, :type => :primary_key, :columns => columns}.merge(opts)
|
|
510
|
+
@operations << {:op => :add_constraint, :type => :primary_key, :columns => columns}.merge!(opts)
|
|
511
511
|
end
|
|
512
512
|
|
|
513
513
|
# Add a composite foreign key constraint
|
|
514
514
|
def add_composite_foreign_key(columns, table, opts)
|
|
515
|
-
@operations << {:op => :add_constraint, :type => :foreign_key, :columns => columns, :table => table}.merge(opts)
|
|
515
|
+
@operations << {:op => :add_constraint, :type => :foreign_key, :columns => columns, :table => table}.merge!(opts)
|
|
516
516
|
end
|
|
517
517
|
|
|
518
518
|
# Drop a composite foreign key constraint
|
|
519
519
|
def drop_composite_foreign_key(columns, opts)
|
|
520
|
-
@operations << {:op => :drop_constraint, :type => :foreign_key, :columns => columns}.merge(opts)
|
|
520
|
+
@operations << {:op => :drop_constraint, :type => :foreign_key, :columns => columns}.merge!(opts)
|
|
521
521
|
end
|
|
522
522
|
end
|
|
523
523
|
end
|