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