sequel 3.35.0 → 3.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +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
|