sequel 3.35.0 → 3.36.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +78 -0
- data/Rakefile +3 -3
- data/bin/sequel +3 -1
- data/doc/advanced_associations.rdoc +154 -11
- data/doc/migration.rdoc +18 -0
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +4 -1
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/schema_modification.rdoc +0 -6
- data/lib/sequel/adapters/do/mysql.rb +7 -0
- data/lib/sequel/adapters/jdbc.rb +11 -3
- data/lib/sequel/adapters/jdbc/mysql.rb +3 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +10 -8
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/mock.rb +2 -6
- data/lib/sequel/adapters/mysql.rb +3 -9
- data/lib/sequel/adapters/mysql2.rb +12 -11
- data/lib/sequel/adapters/postgres.rb +32 -40
- data/lib/sequel/adapters/shared/mssql.rb +15 -11
- data/lib/sequel/adapters/shared/mysql.rb +28 -3
- data/lib/sequel/adapters/shared/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/postgres.rb +59 -5
- data/lib/sequel/adapters/shared/sqlite.rb +3 -13
- data/lib/sequel/adapters/sqlite.rb +0 -7
- data/lib/sequel/adapters/swift/mysql.rb +2 -5
- data/lib/sequel/adapters/tinytds.rb +1 -2
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
- data/lib/sequel/connection_pool/threaded.rb +9 -1
- data/lib/sequel/database/dataset_defaults.rb +3 -1
- data/lib/sequel/database/misc.rb +7 -1
- data/lib/sequel/database/query.rb +11 -3
- data/lib/sequel/database/schema_generator.rb +40 -9
- data/lib/sequel/database/schema_methods.rb +6 -1
- data/lib/sequel/dataset/actions.rb +5 -5
- data/lib/sequel/dataset/prepared_statements.rb +3 -1
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/extensions/migration.rb +28 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +0 -9
- data/lib/sequel/extensions/pg_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -0
- data/lib/sequel/extensions/schema_dumper.rb +24 -6
- data/lib/sequel/model/associations.rb +19 -15
- data/lib/sequel/model/base.rb +11 -12
- data/lib/sequel/plugins/composition.rb +1 -2
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/json_serializer.rb +41 -4
- data/lib/sequel/plugins/nested_attributes.rb +72 -52
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +271 -1
- data/spec/adapters/sqlite_spec.rb +11 -0
- data/spec/core/connection_pool_spec.rb +26 -1
- data/spec/core/database_spec.rb +19 -0
- data/spec/core/dataset_spec.rb +45 -5
- data/spec/core/expression_filters_spec.rb +31 -67
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/extensions/core_extensions_spec.rb +83 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/json_serializer_spec.rb +32 -1
- data/spec/extensions/migration_spec.rb +28 -0
- data/spec/extensions/nested_attributes_spec.rb +134 -1
- data/spec/extensions/optimistic_locking_spec.rb +15 -1
- data/spec/extensions/pg_hstore_spec.rb +1 -1
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/prepared_statements_spec.rb +30 -0
- data/spec/extensions/rcte_tree_spec.rb +9 -0
- data/spec/extensions/schema_dumper_spec.rb +195 -7
- data/spec/extensions/serialization_spec.rb +4 -0
- data/spec/extensions/spec_helper.rb +9 -1
- data/spec/extensions/tactical_eager_loading_spec.rb +8 -0
- data/spec/integration/database_test.rb +5 -1
- data/spec/integration/prepared_statement_test.rb +20 -2
- data/spec/model/associations_spec.rb +27 -0
- data/spec/model/base_spec.rb +54 -0
- data/spec/model/model_spec.rb +6 -0
- data/spec/model/record_spec.rb +18 -0
- data/spec/rcov.opts +2 -0
- metadata +14 -3
@@ -118,19 +118,13 @@ module Sequel
|
|
118
118
|
Mysql::CLIENT_MULTI_STATEMENTS +
|
119
119
|
(opts[:compress] == false ? 0 : Mysql::CLIENT_COMPRESS)
|
120
120
|
)
|
121
|
-
sqls =
|
121
|
+
sqls = mysql_connection_setting_sqls
|
122
|
+
|
122
123
|
# Set encoding a slightly different way after connecting,
|
123
124
|
# in case the READ_DEFAULT_GROUP overrode the provided encoding.
|
124
125
|
# Doesn't work across implicit reconnects, but Sequel doesn't turn on
|
125
126
|
# that feature.
|
126
|
-
sqls
|
127
|
-
|
128
|
-
# Increase timeout so mysql server doesn't disconnect us
|
129
|
-
# Value used by default is maximum allowed value on Windows.
|
130
|
-
sqls << "SET @@wait_timeout = #{opts[:timeout] || 2147483}"
|
131
|
-
|
132
|
-
# By default, MySQL 'where id is null' selects the last inserted id
|
133
|
-
sqls << "SET SQL_AUTO_IS_NULL=0" unless opts[:auto_is_null]
|
127
|
+
sqls.unshift("SET NAMES #{literal(encoding.to_s)}") if encoding
|
134
128
|
|
135
129
|
sqls.each{|sql| log_yield(sql){conn.query(sql)}}
|
136
130
|
|
@@ -10,7 +10,7 @@ module Sequel
|
|
10
10
|
include Sequel::MySQL::PreparedStatements::DatabaseMethods
|
11
11
|
|
12
12
|
# Mysql::Error messages that indicate the current connection should be disconnected
|
13
|
-
MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away|This connection is still waiting for a result, try again once you have the result)/
|
13
|
+
MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away|This connection is still waiting for a result, try again once you have the result|closed MySQL connection)/
|
14
14
|
|
15
15
|
set_adapter_scheme :mysql2
|
16
16
|
|
@@ -48,22 +48,16 @@ module Sequel
|
|
48
48
|
opts[:flags] = ::Mysql2::Client::FOUND_ROWS if ::Mysql2::Client.const_defined?(:FOUND_ROWS)
|
49
49
|
conn = ::Mysql2::Client.new(opts)
|
50
50
|
|
51
|
-
sqls =
|
51
|
+
sqls = mysql_connection_setting_sqls
|
52
|
+
|
52
53
|
# Set encoding a slightly different way after connecting,
|
53
54
|
# in case the READ_DEFAULT_GROUP overrode the provided encoding.
|
54
55
|
# Doesn't work across implicit reconnects, but Sequel doesn't turn on
|
55
56
|
# that feature.
|
56
57
|
if encoding = opts[:encoding] || opts[:charset]
|
57
|
-
sqls
|
58
|
+
sqls.unshift("SET NAMES #{conn.escape(encoding.to_s)}")
|
58
59
|
end
|
59
60
|
|
60
|
-
# Increase timeout so mysql server doesn't disconnect us.
|
61
|
-
# Value used by default is maximum allowed value on Windows.
|
62
|
-
sqls << "SET @@wait_timeout = #{opts[:timeout] || 2147483}"
|
63
|
-
|
64
|
-
# By default, MySQL 'where id is null' selects the last inserted id
|
65
|
-
sqls << "SET SQL_AUTO_IS_NULL=0" unless opts[:auto_is_null]
|
66
|
-
|
67
61
|
sqls.each{|sql| log_yield(sql){conn.query(sql)}}
|
68
62
|
|
69
63
|
add_prepared_statements_cache(conn)
|
@@ -113,8 +107,15 @@ module Sequel
|
|
113
107
|
[::Mysql2::Error]
|
114
108
|
end
|
115
109
|
|
110
|
+
# If a connection object is available, try pinging it. Otherwise, if the
|
111
|
+
# error is a Mysql2::Error, check the SQL state and exception message for
|
112
|
+
# disconnects.
|
116
113
|
def disconnect_error?(e, opts)
|
117
|
-
super ||
|
114
|
+
super ||
|
115
|
+
((conn = opts[:conn]) && !conn.ping) ||
|
116
|
+
(e.is_a?(::Mysql2::Error) &&
|
117
|
+
(e.sql_state =~ /\A08/ ||
|
118
|
+
MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message)))
|
118
119
|
end
|
119
120
|
|
120
121
|
# The database name when using the native adapter is always stored in
|
@@ -294,10 +294,7 @@ module Sequel
|
|
294
294
|
|
295
295
|
# Execute the given SQL with the given args on an available connection.
|
296
296
|
def execute(sql, opts={}, &block)
|
297
|
-
check_database_errors
|
298
|
-
return execute_prepared_statement(sql, opts, &block) if Symbol === sql
|
299
|
-
synchronize(opts[:server]){|conn| conn.execute(sql, opts[:arguments], &block)}
|
300
|
-
end
|
297
|
+
synchronize(opts[:server]){|conn| check_database_errors{_execute(conn, sql, opts, &block)}}
|
301
298
|
end
|
302
299
|
|
303
300
|
if SEQUEL_POSTGRES_USES_PG
|
@@ -436,6 +433,15 @@ module Sequel
|
|
436
433
|
|
437
434
|
private
|
438
435
|
|
436
|
+
# Execute the given SQL string or prepared statement on the connection object.
|
437
|
+
def _execute(conn, sql, opts, &block)
|
438
|
+
if sql.is_a?(Symbol)
|
439
|
+
execute_prepared_statement(conn, sql, opts, &block)
|
440
|
+
else
|
441
|
+
conn.execute(sql, opts[:arguments], &block)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
439
445
|
# Convert exceptions raised from the block into DatabaseErrors.
|
440
446
|
def check_database_errors
|
441
447
|
begin
|
@@ -466,38 +472,34 @@ module Sequel
|
|
466
472
|
# has prepared a statement with the same name and different SQL,
|
467
473
|
# deallocate that statement first and then prepare this statement.
|
468
474
|
# If a block is given, yield the result, otherwise, return the number
|
469
|
-
# of rows changed.
|
470
|
-
|
471
|
-
def execute_prepared_statement(name, opts={})
|
475
|
+
# of rows changed.
|
476
|
+
def execute_prepared_statement(conn, name, opts={}, &block)
|
472
477
|
ps = prepared_statement(name)
|
473
478
|
sql = ps.prepared_sql
|
474
479
|
ps_name = name.to_s
|
475
|
-
synchronize(opts[:server]) do |conn|
|
476
|
-
if args = opts[:arguments]
|
477
|
-
args = args.map{|arg| bound_variable_arg(arg, conn)}
|
478
|
-
end
|
479
480
|
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
end
|
484
|
-
conn.prepared_statements[ps_name] = sql
|
485
|
-
conn.check_disconnect_errors{log_yield("PREPARE #{ps_name} AS #{sql}"){conn.prepare(ps_name, sql)}}
|
486
|
-
end
|
481
|
+
if args = opts[:arguments]
|
482
|
+
args = args.map{|arg| bound_variable_arg(arg, conn)}
|
483
|
+
end
|
487
484
|
|
488
|
-
|
489
|
-
if
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
end
|
485
|
+
unless conn.prepared_statements[ps_name] == sql
|
486
|
+
conn.execute("DEALLOCATE #{ps_name}") if conn.prepared_statements.include?(ps_name)
|
487
|
+
conn.prepared_statements[ps_name] = sql
|
488
|
+
conn.check_disconnect_errors{log_yield("PREPARE #{ps_name} AS #{sql}"){conn.prepare(ps_name, sql)}}
|
489
|
+
end
|
494
490
|
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
491
|
+
log_sql = "EXECUTE #{ps_name}"
|
492
|
+
if ps.log_sql
|
493
|
+
log_sql << " ("
|
494
|
+
log_sql << sql
|
495
|
+
log_sql << ")"
|
496
|
+
end
|
497
|
+
|
498
|
+
q = conn.check_disconnect_errors{log_yield(log_sql, args){conn.exec_prepared(ps_name, args)}}
|
499
|
+
begin
|
500
|
+
block_given? ? yield(q) : q.cmd_tuples
|
501
|
+
ensure
|
502
|
+
q.clear
|
501
503
|
end
|
502
504
|
end
|
503
505
|
|
@@ -640,11 +642,6 @@ module Sequel
|
|
640
642
|
def execute_dui(sql, opts={}, &block)
|
641
643
|
super(sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
642
644
|
end
|
643
|
-
|
644
|
-
# Same as execute, explicit due to intricacies of alias and super.
|
645
|
-
def execute_insert(sql, opts={}, &block)
|
646
|
-
super(sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
647
|
-
end
|
648
645
|
end
|
649
646
|
|
650
647
|
# Allow use of server side prepared statements for PostgreSQL using the
|
@@ -670,11 +667,6 @@ module Sequel
|
|
670
667
|
def execute_dui(sql, opts={}, &block)
|
671
668
|
super(prepared_statement_name, opts, &block)
|
672
669
|
end
|
673
|
-
|
674
|
-
# Same as execute, explicit due to intricacies of alias and super.
|
675
|
-
def execute_insert(sql, opts={}, &block)
|
676
|
-
super(prepared_statement_name, opts, &block)
|
677
|
-
end
|
678
670
|
end
|
679
671
|
|
680
672
|
# Execute the given type of statement with the hash of values.
|
@@ -28,6 +28,11 @@ module Sequel
|
|
28
28
|
:mssql
|
29
29
|
end
|
30
30
|
|
31
|
+
# Microsoft SQL Server namespaces indexes per table.
|
32
|
+
def global_index_namespace?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
31
36
|
# Use the system tables to get index information
|
32
37
|
def indexes(table, opts={})
|
33
38
|
m = output_identifier_meth
|
@@ -187,6 +192,16 @@ module Sequel
|
|
187
192
|
"DROP INDEX #{quote_identifier(op[:name] || default_index_name(table, op[:columns]))} ON #{quote_schema_table(table)}"
|
188
193
|
end
|
189
194
|
|
195
|
+
# support for clustered index type
|
196
|
+
def index_definition_sql(table_name, index)
|
197
|
+
index_name = index[:name] || default_index_name(table_name, index[:columns])
|
198
|
+
if index[:type] == :full_text
|
199
|
+
"CREATE FULLTEXT INDEX ON #{quote_schema_table(table_name)} #{literal(index[:columns])} KEY INDEX #{literal(index[:key_index])}"
|
200
|
+
else
|
201
|
+
"CREATE #{'UNIQUE ' if index[:unique]}#{'CLUSTERED ' if index[:type] == :clustered}INDEX #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}#{" INCLUDE #{literal(index[:include])}" if index[:include]}#{" WHERE #{filter_expr(index[:where])}" if index[:where]}"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
190
205
|
# Backbone of the tables and views support.
|
191
206
|
def information_schema_tables(type, opts)
|
192
207
|
m = output_identifier_meth
|
@@ -290,17 +305,6 @@ module Sequel
|
|
290
305
|
def type_literal_generic_file(column)
|
291
306
|
:'varbinary(max)'
|
292
307
|
end
|
293
|
-
|
294
|
-
# support for clustered index type
|
295
|
-
def index_definition_sql(table_name, index)
|
296
|
-
index_name = index[:name] || default_index_name(table_name, index[:columns])
|
297
|
-
raise Error, "Partial indexes are not supported for this database" if index[:where]
|
298
|
-
if index[:type] == :full_text
|
299
|
-
"CREATE FULLTEXT INDEX ON #{quote_schema_table(table_name)} #{literal(index[:columns])} KEY INDEX #{literal(index[:key_index])}"
|
300
|
-
else
|
301
|
-
"CREATE #{'UNIQUE ' if index[:unique]}#{'CLUSTERED ' if index[:type] == :clustered}INDEX #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}#{" INCLUDE #{literal(index[:include])}" if index[:include]}"
|
302
|
-
end
|
303
|
-
end
|
304
308
|
end
|
305
309
|
|
306
310
|
module DatasetMethods
|
@@ -76,6 +76,11 @@ module Sequel
|
|
76
76
|
h.values
|
77
77
|
end
|
78
78
|
|
79
|
+
# MySQL namespaces indexes per table.
|
80
|
+
def global_index_namespace?
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
79
84
|
# Use SHOW INDEX FROM to get the index information for the
|
80
85
|
# table.
|
81
86
|
#
|
@@ -124,10 +129,10 @@ module Sequel
|
|
124
129
|
server_version >= 50000
|
125
130
|
end
|
126
131
|
|
127
|
-
# MySQL doesn't
|
128
|
-
# see http://bugs.mysql.com/bug.php?id=64374
|
132
|
+
# MySQL doesn't support savepoints inside prepared transactions in from
|
133
|
+
# 5.5.12 to 5.5.23, see http://bugs.mysql.com/bug.php?id=64374
|
129
134
|
def supports_savepoints_in_prepared_transactions?
|
130
|
-
super && server_version <= 50512
|
135
|
+
super && (server_version <= 50512 || server_version >= 50523)
|
131
136
|
end
|
132
137
|
|
133
138
|
# MySQL supports transaction isolation levels
|
@@ -208,6 +213,26 @@ module Sequel
|
|
208
213
|
super(table, op)
|
209
214
|
end
|
210
215
|
end
|
216
|
+
|
217
|
+
# The SQL queries to execute on initial connection
|
218
|
+
def mysql_connection_setting_sqls
|
219
|
+
sqls = []
|
220
|
+
|
221
|
+
# Increase timeout so mysql server doesn't disconnect us
|
222
|
+
# Value used by default is maximum allowed value on Windows.
|
223
|
+
sqls << "SET @@wait_timeout = #{opts[:timeout] || 2147483}"
|
224
|
+
|
225
|
+
# By default, MySQL 'where id is null' selects the last inserted id
|
226
|
+
sqls << "SET SQL_AUTO_IS_NULL=0" unless opts[:auto_is_null]
|
227
|
+
|
228
|
+
# If the user has specified one or more sql modes, enable them
|
229
|
+
if sql_mode = opts[:sql_mode]
|
230
|
+
sql_mode = Array(sql_mode).join(',').upcase
|
231
|
+
sqls << "SET sql_mode = '#{sql_mode}'"
|
232
|
+
end
|
233
|
+
|
234
|
+
sqls
|
235
|
+
end
|
211
236
|
|
212
237
|
# Use MySQL specific AUTO_INCREMENT text.
|
213
238
|
def auto_increment_sql
|
@@ -29,6 +29,11 @@ module Sequel
|
|
29
29
|
:oracle
|
30
30
|
end
|
31
31
|
|
32
|
+
# Oracle namespaces indexes per table.
|
33
|
+
def global_index_namespace?
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
32
37
|
def tables(opts={})
|
33
38
|
m = output_identifier_meth
|
34
39
|
metadata_dataset.from(:tab).server(opts[:server]).select(:tname).filter(:tabtype => 'TABLE').map{|r| m.call(r[:tname])}
|
@@ -247,9 +247,9 @@ module Sequel
|
|
247
247
|
# If a schema is given, we only search in that schema, and the returned :table
|
248
248
|
# entry is schema qualified as well.
|
249
249
|
if schema
|
250
|
-
ds.join
|
251
|
-
where(:
|
252
|
-
ref_ds.join
|
250
|
+
ds = ds.join(:pg_namespace___nsp, :oid=>:cl__relnamespace).
|
251
|
+
where(:nsp__nspname=>im.call(schema))
|
252
|
+
ref_ds = ref_ds.join(:pg_namespace___nsp2, :oid=>:cl2__relnamespace).
|
253
253
|
select_more(:nsp2__nspname___schema)
|
254
254
|
end
|
255
255
|
|
@@ -264,7 +264,7 @@ module Sequel
|
|
264
264
|
end
|
265
265
|
ref_ds.each do |row|
|
266
266
|
r = h[row[:name]]
|
267
|
-
r[:table] ||=
|
267
|
+
r[:table] ||= schema ? SQL::QualifiedIdentifier.new(m.call(row[:schema]), m.call(row[:table])) : m.call(row[:table])
|
268
268
|
r[:key] ||= []
|
269
269
|
r[:key] << m.call(row[:refcolumn])
|
270
270
|
end
|
@@ -444,6 +444,41 @@ module Sequel
|
|
444
444
|
|
445
445
|
private
|
446
446
|
|
447
|
+
# Handle :using option for set_column_type op.
|
448
|
+
def alter_table_sql(table, op)
|
449
|
+
case op[:op]
|
450
|
+
when :set_column_type
|
451
|
+
s = super
|
452
|
+
if using = op[:using]
|
453
|
+
using = Sequel::LiteralString.new(using) if using.is_a?(String)
|
454
|
+
s << ' USING '
|
455
|
+
s << literal(using)
|
456
|
+
end
|
457
|
+
s
|
458
|
+
else
|
459
|
+
super
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
# If the :synchronous option is given and non-nil, set synchronous_commit
|
464
|
+
# appropriately. Valid values for the :synchronous option are true,
|
465
|
+
# :on, false, :off, :local, and :remote_write.
|
466
|
+
def begin_new_transaction(conn, opts)
|
467
|
+
super
|
468
|
+
if opts.has_key?(:synchronous)
|
469
|
+
case sync = opts[:synchronous]
|
470
|
+
when true
|
471
|
+
sync = :on
|
472
|
+
when false
|
473
|
+
sync = :off
|
474
|
+
when nil
|
475
|
+
return
|
476
|
+
end
|
477
|
+
|
478
|
+
log_connection_execute(conn, "SET LOCAL synchronous_commit = #{sync}")
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
447
482
|
# If the :prepare option is given and we aren't in a savepoint,
|
448
483
|
# prepare the transaction for a two-phase commit.
|
449
484
|
def commit_transaction(conn, opts={})
|
@@ -511,6 +546,11 @@ module Sequel
|
|
511
546
|
def drop_function_sql(name, opts={})
|
512
547
|
"DROP FUNCTION#{' IF EXISTS' if opts[:if_exists]} #{name}#{sql_function_args(opts[:args])}#{' CASCADE' if opts[:cascade]}"
|
513
548
|
end
|
549
|
+
|
550
|
+
# Support :if_exists, :cascade, and :concurrently options.
|
551
|
+
def drop_index_sql(table, op)
|
552
|
+
"DROP INDEX#{' CONCURRENTLY' if op[:concurrently]}#{' IF EXISTS' if op[:if_exists]} #{quote_identifier(op[:name] || default_index_name(table, op[:columns]))}#{' CASCADE' if op[:cascade]}"
|
553
|
+
end
|
514
554
|
|
515
555
|
# SQL for dropping a procedural language from the database.
|
516
556
|
def drop_language_sql(name, opts={})
|
@@ -567,7 +607,7 @@ module Sequel
|
|
567
607
|
when :spatial
|
568
608
|
index_type = :gist
|
569
609
|
end
|
570
|
-
"CREATE #{unique}INDEX #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{"USING #{index_type} " if index_type}#{expr}#{filter}"
|
610
|
+
"CREATE #{unique}INDEX#{' CONCURRENTLY' if index[:concurrently]} #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{"USING #{index_type} " if index_type}#{expr}#{filter}"
|
571
611
|
end
|
572
612
|
|
573
613
|
# Backbone of the tables and views support.
|
@@ -642,6 +682,20 @@ module Sequel
|
|
642
682
|
end
|
643
683
|
end
|
644
684
|
|
685
|
+
# Set the transaction isolation level on the given connection
|
686
|
+
def set_transaction_isolation(conn, opts)
|
687
|
+
level = opts.fetch(:isolation, transaction_isolation_level)
|
688
|
+
read_only = opts[:read_only]
|
689
|
+
deferrable = opts[:deferrable]
|
690
|
+
if level || !read_only.nil? || !deferrable.nil?
|
691
|
+
sql = "SET TRANSACTION"
|
692
|
+
sql << " ISOLATION LEVEL #{Sequel::Database::TRANSACTION_ISOLATION_LEVELS[level]}" if level
|
693
|
+
sql << " READ #{read_only ? 'ONLY' : 'WRITE'}" unless read_only.nil?
|
694
|
+
sql << " #{'NOT ' unless deferrable}DEFERRABLE" unless deferrable.nil?
|
695
|
+
log_connection_execute(conn, sql)
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
645
699
|
# Turns an array of argument specifiers into an SQL fragment used for function arguments. See create_function_sql.
|
646
700
|
def sql_function_args(args)
|
647
701
|
"(#{Array(args).map{|a| Array(a).reverse.join(' ')}.join(', ')})"
|
@@ -28,12 +28,6 @@ module Sequel
|
|
28
28
|
pragma_set(:auto_vacuum, value)
|
29
29
|
end
|
30
30
|
|
31
|
-
# Boolean signifying the value of the case_sensitive_likePRAGMA, or nil
|
32
|
-
# if not using SQLite 3.2.3+.
|
33
|
-
def case_sensitive_like
|
34
|
-
pragma_get(:case_sensitive_like).to_i == 1 if sqlite_version >= 30203
|
35
|
-
end
|
36
|
-
|
37
31
|
# Set the case_sensitive_like PRAGMA using the given boolean value, if using
|
38
32
|
# SQLite 3.2.3+. If not using 3.2.3+, no error is raised. See pragma_set.
|
39
33
|
# Consider using the :case_sensitive_like Database option instead.
|
@@ -252,7 +246,7 @@ module Sequel
|
|
252
246
|
end
|
253
247
|
end
|
254
248
|
|
255
|
-
#
|
249
|
+
# A name to use for the backup table
|
256
250
|
def backup_table_name(table, opts={})
|
257
251
|
table = table.gsub('`', '')
|
258
252
|
(opts[:times]||1000).times do |i|
|
@@ -283,17 +277,13 @@ module Sequel
|
|
283
277
|
ps
|
284
278
|
end
|
285
279
|
|
286
|
-
# The array of column schema hashes
|
287
|
-
def defined_columns_for(table
|
280
|
+
# The array of column schema hashes for the current columns in the table
|
281
|
+
def defined_columns_for(table)
|
288
282
|
cols = parse_pragma(table, {})
|
289
283
|
cols.each do |c|
|
290
284
|
c[:default] = LiteralString.new(c[:default]) if c[:default]
|
291
285
|
c[:type] = c[:db_type]
|
292
286
|
end
|
293
|
-
if opts[:except]
|
294
|
-
nono= Array(opts[:except]).compact.map{|n| n.to_s}
|
295
|
-
cols.reject!{|c| nono.include? c[:name] }
|
296
|
-
end
|
297
287
|
cols
|
298
288
|
end
|
299
289
|
|
@@ -144,11 +144,6 @@ module Sequel
|
|
144
144
|
_execute(:insert, sql, opts)
|
145
145
|
end
|
146
146
|
|
147
|
-
# Run the given SQL with the given arguments and return the first value of the first row.
|
148
|
-
def single_value(sql, opts={})
|
149
|
-
_execute(:single_value, sql, opts)
|
150
|
-
end
|
151
|
-
|
152
147
|
# Handle Integer and Float arguments, since SQLite can store timestamps as integers and floats.
|
153
148
|
def to_application_timestamp(s)
|
154
149
|
case s
|
@@ -177,8 +172,6 @@ module Sequel
|
|
177
172
|
case type
|
178
173
|
when :select
|
179
174
|
log_yield(sql, log_args){conn.query(sql, args, &block)}
|
180
|
-
when :single_value
|
181
|
-
log_yield(sql, log_args){conn.get_first_value(sql, args)}
|
182
175
|
when :insert
|
183
176
|
log_yield(sql, log_args){conn.execute(sql, args)}
|
184
177
|
conn.last_insert_row_id
|