sequel 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +76 -0
- data/Rakefile +2 -2
- data/bin/sequel +9 -4
- data/doc/opening_databases.rdoc +279 -0
- data/doc/release_notes/3.2.0.txt +268 -0
- data/doc/virtual_rows.rdoc +42 -51
- data/lib/sequel/adapters/ado.rb +2 -5
- data/lib/sequel/adapters/db2.rb +5 -0
- data/lib/sequel/adapters/do.rb +3 -0
- data/lib/sequel/adapters/firebird.rb +6 -4
- data/lib/sequel/adapters/informix.rb +5 -3
- data/lib/sequel/adapters/jdbc.rb +10 -8
- data/lib/sequel/adapters/jdbc/h2.rb +17 -4
- data/lib/sequel/adapters/mysql.rb +6 -19
- data/lib/sequel/adapters/odbc.rb +14 -18
- data/lib/sequel/adapters/openbase.rb +8 -0
- data/lib/sequel/adapters/shared/mssql.rb +14 -8
- data/lib/sequel/adapters/shared/mysql.rb +53 -28
- data/lib/sequel/adapters/shared/oracle.rb +21 -12
- data/lib/sequel/adapters/shared/postgres.rb +46 -26
- data/lib/sequel/adapters/shared/progress.rb +10 -5
- data/lib/sequel/adapters/shared/sqlite.rb +28 -12
- data/lib/sequel/adapters/sqlite.rb +4 -3
- data/lib/sequel/adapters/utils/stored_procedures.rb +18 -9
- data/lib/sequel/connection_pool.rb +4 -3
- data/lib/sequel/database.rb +110 -10
- data/lib/sequel/database/schema_sql.rb +12 -3
- data/lib/sequel/dataset.rb +40 -3
- data/lib/sequel/dataset/convenience.rb +0 -11
- data/lib/sequel/dataset/graph.rb +25 -11
- data/lib/sequel/dataset/sql.rb +176 -68
- data/lib/sequel/extensions/migration.rb +37 -21
- data/lib/sequel/extensions/schema_dumper.rb +8 -61
- data/lib/sequel/model.rb +3 -3
- data/lib/sequel/model/associations.rb +9 -1
- data/lib/sequel/model/base.rb +8 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/sql.rb +125 -18
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/ado_spec.rb +1 -0
- data/spec/adapters/firebird_spec.rb +1 -0
- data/spec/adapters/informix_spec.rb +1 -0
- data/spec/adapters/mysql_spec.rb +23 -8
- data/spec/adapters/oracle_spec.rb +1 -0
- data/spec/adapters/postgres_spec.rb +52 -4
- data/spec/adapters/spec_helper.rb +2 -2
- data/spec/adapters/sqlite_spec.rb +2 -1
- data/spec/core/connection_pool_spec.rb +16 -0
- data/spec/core/database_spec.rb +174 -0
- data/spec/core/dataset_spec.rb +121 -26
- data/spec/core/expression_filters_spec.rb +156 -0
- data/spec/core/object_graph_spec.rb +20 -1
- data/spec/core/schema_spec.rb +5 -5
- data/spec/extensions/migration_spec.rb +140 -74
- data/spec/extensions/schema_dumper_spec.rb +3 -69
- data/spec/extensions/single_table_inheritance_spec.rb +6 -0
- data/spec/integration/dataset_test.rb +84 -2
- data/spec/integration/schema_test.rb +24 -5
- data/spec/integration/spec_helper.rb +8 -6
- data/spec/model/eager_loading_spec.rb +9 -0
- data/spec/model/record_spec.rb +35 -8
- metadata +8 -7
- data/lib/sequel/adapters/utils/date_format.rb +0 -21
- data/lib/sequel/adapters/utils/savepoint_transactions.rb +0 -80
- data/lib/sequel/adapters/utils/unsupported.rb +0 -50
@@ -1,10 +1,4 @@
|
|
1
|
-
Sequel.require %w'unsupported savepoint_transactions', 'adapters/utils'
|
2
|
-
|
3
1
|
module Sequel
|
4
|
-
class Database
|
5
|
-
# Keep default column_references_sql for add_foreign_key support
|
6
|
-
alias default_column_references_sql column_references_sql
|
7
|
-
end
|
8
2
|
module MySQL
|
9
3
|
class << self
|
10
4
|
# Set the default options used for CREATE TABLE
|
@@ -14,8 +8,6 @@ module Sequel
|
|
14
8
|
# Methods shared by Database instances that connect to MySQL,
|
15
9
|
# currently supported by the native and JDBC adapters.
|
16
10
|
module DatabaseMethods
|
17
|
-
include Sequel::Database::SavepointTransactions
|
18
|
-
|
19
11
|
AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze
|
20
12
|
CAST_TYPES = {String=>:CHAR, Integer=>:SIGNED, Time=>:DATETIME, DateTime=>:DATETIME, Numeric=>:DECIMAL, BigDecimal=>:DECIMAL, File=>:BINARY}
|
21
13
|
PRIMARY = 'PRIMARY'.freeze
|
@@ -68,6 +60,11 @@ module Sequel
|
|
68
60
|
metadata_dataset.with_sql('SHOW TABLES').server(opts[:server]).map{|r| m.call(r.values.first)}
|
69
61
|
end
|
70
62
|
|
63
|
+
# MySQL supports savepoints
|
64
|
+
def supports_savepoints?
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
71
68
|
# Changes the database in use by issuing a USE statement. I would be
|
72
69
|
# very careful if I used this.
|
73
70
|
def use(db_name)
|
@@ -87,7 +84,7 @@ module Sequel
|
|
87
84
|
if related = op.delete(:table)
|
88
85
|
sql = super(table, op)
|
89
86
|
op[:table] = related
|
90
|
-
[sql, "ALTER TABLE #{quote_schema_table(table)} ADD FOREIGN KEY (#{quote_identifier(op[:name])})#{
|
87
|
+
[sql, "ALTER TABLE #{quote_schema_table(table)} ADD FOREIGN KEY (#{quote_identifier(op[:name])})#{column_references_sql(op)}"]
|
91
88
|
else
|
92
89
|
super(table, op)
|
93
90
|
end
|
@@ -98,8 +95,8 @@ module Sequel
|
|
98
95
|
name = o == :rename_column ? op[:new_name] : op[:name]
|
99
96
|
type = o == :set_column_type ? op[:type] : old_opts[:db_type]
|
100
97
|
null = o == :set_column_null ? op[:null] : old_opts[:allow_null]
|
101
|
-
default = o == :set_column_default ? op[:default] :
|
102
|
-
"ALTER TABLE #{quote_schema_table(table)} CHANGE COLUMN #{quote_identifier(op[:name])} #{column_definition_sql(:name=>name, :type=>type, :null=>null, :default=>default)}"
|
98
|
+
default = o == :set_column_default ? op[:default] : old_opts[:ruby_default]
|
99
|
+
"ALTER TABLE #{quote_schema_table(table)} CHANGE COLUMN #{quote_identifier(op[:name])} #{column_definition_sql(op.merge(:name=>name, :type=>type, :null=>null, :default=>default))}"
|
103
100
|
when :drop_index
|
104
101
|
"#{drop_index_sql(table, op)} ON #{quote_schema_table(table)}"
|
105
102
|
else
|
@@ -119,9 +116,9 @@ module Sequel
|
|
119
116
|
super
|
120
117
|
end
|
121
118
|
|
122
|
-
#
|
123
|
-
def
|
124
|
-
"#{", FOREIGN KEY (#{quote_identifier(column[:name])})" unless column[:type] == :check}#{
|
119
|
+
# MySQL doesn't handle references as column constraints, it must use a separate table constraint
|
120
|
+
def column_references_column_constraint_sql(column)
|
121
|
+
"#{", FOREIGN KEY (#{quote_identifier(column[:name])})" unless column[:type] == :check}#{column_references_sql(column)}"
|
125
122
|
end
|
126
123
|
|
127
124
|
# Use MySQL specific syntax for engine type and character encoding
|
@@ -199,12 +196,11 @@ module Sequel
|
|
199
196
|
|
200
197
|
# Dataset methods shared by datasets that use MySQL databases.
|
201
198
|
module DatasetMethods
|
202
|
-
include Dataset::UnsupportedIntersectExcept
|
203
|
-
|
204
199
|
BOOL_TRUE = '1'.freeze
|
205
200
|
BOOL_FALSE = '0'.freeze
|
206
201
|
TIMESTAMP_FORMAT = "'%Y-%m-%d %H:%M:%S'".freeze
|
207
202
|
COMMA_SEPARATOR = ', '.freeze
|
203
|
+
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
|
208
204
|
|
209
205
|
# MySQL specific syntax for LIKE/REGEXP searches, as well as
|
210
206
|
# string concatenation.
|
@@ -231,12 +227,6 @@ module Sequel
|
|
231
227
|
sql
|
232
228
|
end
|
233
229
|
|
234
|
-
# MySQL doesn't support DISTINCT ON
|
235
|
-
def distinct(*columns)
|
236
|
-
raise(Error, "DISTINCT ON not supported by MySQL") unless columns.empty?
|
237
|
-
super
|
238
|
-
end
|
239
|
-
|
240
230
|
# Adds full text filter
|
241
231
|
def full_text_search(cols, terms, opts = {})
|
242
232
|
filter(full_text_sql(cols, terms, opts))
|
@@ -313,15 +303,11 @@ module Sequel
|
|
313
303
|
def on_duplicate_key_update(*args)
|
314
304
|
clone(:on_duplicate_key_update => args)
|
315
305
|
end
|
316
|
-
|
306
|
+
|
317
307
|
# MySQL specific syntax for inserting multiple values at once.
|
318
308
|
def multi_insert_sql(columns, values)
|
319
|
-
if update_cols = opts[:on_duplicate_key_update]
|
320
|
-
update_cols = columns if update_cols.empty?
|
321
|
-
update_string = update_cols.map{|c| "#{quote_identifier(c)}=VALUES(#{quote_identifier(c)})"}.join(COMMA_SEPARATOR)
|
322
|
-
end
|
323
309
|
values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR)
|
324
|
-
["#{insert_sql_base}#{source_list(@opts[:from])} (#{identifier_list(columns)}) VALUES #{values}#{
|
310
|
+
["#{insert_sql_base}#{source_list(@opts[:from])} (#{identifier_list(columns)}) VALUES #{values}#{insert_sql_suffix}"]
|
325
311
|
end
|
326
312
|
|
327
313
|
# MySQL uses the nonstandard ` (backtick) for quoting identifiers.
|
@@ -365,6 +351,16 @@ module Sequel
|
|
365
351
|
end
|
366
352
|
end
|
367
353
|
|
354
|
+
# does not support DISTINCT ON
|
355
|
+
def supports_distinct_on?
|
356
|
+
false
|
357
|
+
end
|
358
|
+
|
359
|
+
# MySQL does not support INTERSECT or EXCEPT
|
360
|
+
def supports_intersect_except?
|
361
|
+
false
|
362
|
+
end
|
363
|
+
|
368
364
|
# MySQL supports ORDER and LIMIT clauses in UPDATE statements.
|
369
365
|
def update_sql(values)
|
370
366
|
sql = super
|
@@ -380,6 +376,11 @@ module Sequel
|
|
380
376
|
"INSERT #{'IGNORE ' if opts[:insert_ignore]}INTO "
|
381
377
|
end
|
382
378
|
|
379
|
+
# MySQL supports INSERT ... ON DUPLICATE KEY UPDATE
|
380
|
+
def insert_sql_suffix
|
381
|
+
on_duplicate_key_update_sql if opts[:on_duplicate_key_update]
|
382
|
+
end
|
383
|
+
|
383
384
|
# MySQL doesn't use the SQL standard DEFAULT VALUES.
|
384
385
|
def insert_default_values_sql
|
385
386
|
"#{insert_sql_base}#{source_list(@opts[:from])} () VALUES ()"
|
@@ -404,6 +405,30 @@ module Sequel
|
|
404
405
|
def literal_true
|
405
406
|
BOOL_TRUE
|
406
407
|
end
|
408
|
+
|
409
|
+
# MySQL specific syntax for ON DUPLICATE KEY UPDATE
|
410
|
+
def on_duplicate_key_update_sql
|
411
|
+
if update_cols = opts[:on_duplicate_key_update]
|
412
|
+
update_vals = nil
|
413
|
+
|
414
|
+
if update_cols.empty?
|
415
|
+
update_cols = columns
|
416
|
+
elsif update_cols.last.is_a?(Hash)
|
417
|
+
update_vals = update_cols.last
|
418
|
+
update_cols = update_cols[0..-2]
|
419
|
+
end
|
420
|
+
|
421
|
+
updating = update_cols.map{|c| "#{quote_identifier(c)}=VALUES(#{quote_identifier(c)})" }
|
422
|
+
updating += update_vals.map{|c,v| "#{quote_identifier(c)}=#{literal(v)}" } if update_vals
|
423
|
+
|
424
|
+
" ON DUPLICATE KEY UPDATE #{updating.join(COMMA_SEPARATOR)}"
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
# MySQL does not support the SQL WITH clause
|
429
|
+
def select_clause_order
|
430
|
+
SELECT_CLAUSE_ORDER
|
431
|
+
end
|
407
432
|
end
|
408
433
|
end
|
409
434
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
Sequel.require %w'date_format unsupported', 'adapters/utils'
|
2
|
-
|
3
1
|
module Sequel
|
4
2
|
module Oracle
|
5
3
|
module DatabaseMethods
|
@@ -96,16 +94,7 @@ module Sequel
|
|
96
94
|
end
|
97
95
|
|
98
96
|
module DatasetMethods
|
99
|
-
|
100
|
-
include Dataset::SQLStandardDateFormat
|
101
|
-
|
102
|
-
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
|
103
|
-
|
104
|
-
# Oracle doesn't support DISTINCT ON
|
105
|
-
def distinct(*columns)
|
106
|
-
raise(Error, "DISTINCT ON not supported by Oracle") unless columns.empty?
|
107
|
-
super
|
108
|
-
end
|
97
|
+
SELECT_CLAUSE_ORDER = %w'with distinct columns from join where group having compounds order limit'.freeze
|
109
98
|
|
110
99
|
# Oracle uses MINUS instead of EXCEPT, and doesn't support EXCEPT ALL
|
111
100
|
def except(dataset, all = false)
|
@@ -117,6 +106,26 @@ module Sequel
|
|
117
106
|
db[:dual].where(exists).get(1) == nil
|
118
107
|
end
|
119
108
|
|
109
|
+
# Oracle requires SQL standard datetimes
|
110
|
+
def requires_sql_standard_datetimes?
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
114
|
+
# Oracle does not support DISTINCT ON
|
115
|
+
def supports_distinct_on?
|
116
|
+
false
|
117
|
+
end
|
118
|
+
|
119
|
+
# Oracle does not support INTERSECT ALL or EXCEPT ALL
|
120
|
+
def supports_intersect_except_all?
|
121
|
+
false
|
122
|
+
end
|
123
|
+
|
124
|
+
# Oracle supports window functions
|
125
|
+
def supports_window_functions?
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
120
129
|
private
|
121
130
|
|
122
131
|
# Oracle doesn't support the use of AS when aliasing a dataset. It doesn't require
|
@@ -1,5 +1,3 @@
|
|
1
|
-
Sequel.require 'adapters/utils/savepoint_transactions'
|
2
|
-
|
3
1
|
module Sequel
|
4
2
|
# Top level module for holding all PostgreSQL-related modules and classes
|
5
3
|
# for Sequel. There are a few module level accessors that are added via
|
@@ -165,13 +163,8 @@ module Sequel
|
|
165
163
|
|
166
164
|
# Methods shared by Database instances that connect to PostgreSQL.
|
167
165
|
module DatabaseMethods
|
168
|
-
include Sequel::Database::SavepointTransactions
|
169
|
-
|
170
166
|
PREPARED_ARG_PLACEHOLDER = LiteralString.new('$').freeze
|
171
167
|
RE_CURRVAL_ERROR = /currval of sequence "(.*)" is not yet defined in this session|relation "(.*)" does not exist/.freeze
|
172
|
-
SQL_BEGIN = 'BEGIN'.freeze
|
173
|
-
SQL_COMMIT = 'COMMIT'.freeze
|
174
|
-
SQL_ROLLBACK = 'ROLLBACK'.freeze
|
175
168
|
SYSTEM_TABLE_REGEXP = /^pg|sql/.freeze
|
176
169
|
|
177
170
|
# Creates the function in the database. Arguments:
|
@@ -277,16 +270,20 @@ module Sequel
|
|
277
270
|
m = output_identifier_meth
|
278
271
|
im = input_identifier_meth
|
279
272
|
schema, table = schema_and_table(table)
|
273
|
+
range = 0...32
|
274
|
+
attnums = server_version >= 80100 ? SQL::Function.new(:ANY, :ind__indkey) : range.map{|x| SQL::Subscript.new(:ind__indkey, [x])}
|
280
275
|
ds = metadata_dataset.
|
281
276
|
from(:pg_class___tab).
|
282
277
|
join(:pg_index___ind, :indrelid=>:oid, im.call(table)=>:relname).
|
283
278
|
join(:pg_class___indc, :oid=>:indexrelid).
|
284
|
-
join(:pg_attribute___att, :attrelid=>:tab__oid, :attnum=>
|
285
|
-
filter(:indc__relkind=>'i', :ind__indisprimary=>false, :indexprs=>nil, :indpred=>nil
|
286
|
-
order(:indc__relname,
|
279
|
+
join(:pg_attribute___att, :attrelid=>:tab__oid, :attnum=>attnums).
|
280
|
+
filter(:indc__relkind=>'i', :ind__indisprimary=>false, :indexprs=>nil, :indpred=>nil).
|
281
|
+
order(:indc__relname, range.map{|x| [SQL::Subscript.new(:ind__indkey, [x]), x]}.case(32, :att__attnum)).
|
287
282
|
select(:indc__relname___name, :ind__indisunique___unique, :att__attname___column)
|
288
283
|
|
289
|
-
ds.join!(:pg_namespace___nsp, :oid=>:tab__relnamespace, :nspname=>schema) if schema
|
284
|
+
ds.join!(:pg_namespace___nsp, :oid=>:tab__relnamespace, :nspname=>schema.to_s) if schema
|
285
|
+
ds.filter!(:indisvalid=>true) if server_version >= 80200
|
286
|
+
ds.filter!(:indisready=>true, :indcheckxmin=>false) if server_version >= 80300
|
290
287
|
|
291
288
|
indexes = {}
|
292
289
|
ds.each do |r|
|
@@ -346,12 +343,17 @@ module Sequel
|
|
346
343
|
(conn.server_version rescue nil) if conn.respond_to?(:server_version)
|
347
344
|
end
|
348
345
|
unless @server_version
|
349
|
-
m = /PostgreSQL (\d+)\.(\d+)
|
346
|
+
m = /PostgreSQL (\d+)\.(\d+)(?:(?:rc\d+)|\.(\d+))?/.match(fetch('SELECT version()').single_value)
|
350
347
|
@server_version = (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
|
351
348
|
end
|
352
349
|
@server_version
|
353
350
|
end
|
354
351
|
|
352
|
+
# PostgreSQL supports savepoints
|
353
|
+
def supports_savepoints?
|
354
|
+
true
|
355
|
+
end
|
356
|
+
|
355
357
|
# Whether the given table exists in the database
|
356
358
|
#
|
357
359
|
# Options:
|
@@ -451,7 +453,11 @@ module Sequel
|
|
451
453
|
def index_definition_sql(table_name, index)
|
452
454
|
cols = index[:columns]
|
453
455
|
index_name = index[:name] || default_index_name(table_name, cols)
|
454
|
-
expr =
|
456
|
+
expr = if o = index[:opclass]
|
457
|
+
"(#{Array(cols).map{|c| "#{literal(c)} #{o}"}.join(', ')})"
|
458
|
+
else
|
459
|
+
literal(Array(cols))
|
460
|
+
end
|
455
461
|
unique = "UNIQUE " if index[:unique]
|
456
462
|
index_type = index[:type]
|
457
463
|
filter = index[:where] || index[:filter]
|
@@ -582,9 +588,11 @@ module Sequel
|
|
582
588
|
ROW_EXCLUSIVE = 'ROW EXCLUSIVE'.freeze
|
583
589
|
ROW_SHARE = 'ROW SHARE'.freeze
|
584
590
|
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit lock'.freeze
|
591
|
+
SELECT_CLAUSE_ORDER_84 = %w'with distinct columns from join where group having window compounds order limit lock'.freeze
|
585
592
|
SHARE = 'SHARE'.freeze
|
586
593
|
SHARE_ROW_EXCLUSIVE = 'SHARE ROW EXCLUSIVE'.freeze
|
587
594
|
SHARE_UPDATE_EXCLUSIVE = 'SHARE UPDATE EXCLUSIVE'.freeze
|
595
|
+
SQL_WITH_RECURSIVE = "WITH RECURSIVE ".freeze
|
588
596
|
|
589
597
|
# Shared methods for prepared statements when used with PostgreSQL databases.
|
590
598
|
module PreparedStatementMethods
|
@@ -611,12 +619,8 @@ module Sequel
|
|
611
619
|
end
|
612
620
|
|
613
621
|
# Return the results of an ANALYZE query as a string
|
614
|
-
def analyze
|
615
|
-
|
616
|
-
fetch_rows(EXPLAIN_ANALYZE + select_sql(opts)) do |r|
|
617
|
-
analysis << r[QUERY_PLAN]
|
618
|
-
end
|
619
|
-
analysis.join("\r\n")
|
622
|
+
def analyze
|
623
|
+
explain(:analyze=>true)
|
620
624
|
end
|
621
625
|
|
622
626
|
# Disable the use of INSERT RETURNING, even if the server supports it
|
@@ -625,12 +629,8 @@ module Sequel
|
|
625
629
|
end
|
626
630
|
|
627
631
|
# Return the results of an EXPLAIN query as a string
|
628
|
-
def explain(opts
|
629
|
-
|
630
|
-
fetch_rows(EXPLAIN + select_sql(opts)) do |r|
|
631
|
-
analysis << r[QUERY_PLAN]
|
632
|
-
end
|
633
|
-
analysis.join("\r\n")
|
632
|
+
def explain(opts={})
|
633
|
+
with_sql((opts[:analyze] ? EXPLAIN_ANALYZE : EXPLAIN) + select_sql).map(QUERY_PLAN).join("\r\n")
|
634
634
|
end
|
635
635
|
|
636
636
|
# Return a cloned dataset with a :share lock type.
|
@@ -693,6 +693,16 @@ module Sequel
|
|
693
693
|
["#{insert_sql_base}#{source_list(@opts[:from])} (#{identifier_list(columns)}) VALUES #{values}"]
|
694
694
|
end
|
695
695
|
|
696
|
+
# PostgreSQL 8.4+ supports window functions
|
697
|
+
def supports_window_functions?
|
698
|
+
server_version >= 80400
|
699
|
+
end
|
700
|
+
|
701
|
+
# Return a clone of the dataset with an addition named window that can be referenced in window functions.
|
702
|
+
def window(name, opts)
|
703
|
+
clone(:window=>(@opts[:windows]||[]) + [[name, SQL::Window.new(opts)]])
|
704
|
+
end
|
705
|
+
|
696
706
|
private
|
697
707
|
|
698
708
|
# Use the RETURNING clause to return the primary key of the inserted record, if it exists
|
@@ -733,7 +743,12 @@ module Sequel
|
|
733
743
|
|
734
744
|
# The order of clauses in the SELECT SQL statement
|
735
745
|
def select_clause_order
|
736
|
-
SELECT_CLAUSE_ORDER
|
746
|
+
server_version >= 80400 ? SELECT_CLAUSE_ORDER_84 : SELECT_CLAUSE_ORDER
|
747
|
+
end
|
748
|
+
|
749
|
+
# SQL fragment for named window specifications
|
750
|
+
def select_window_sql(sql)
|
751
|
+
sql << " WINDOW #{@opts[:window].map{|name, window| "#{literal(name)} AS #{literal(window)}"}.join(', ')}" if @opts[:window]
|
737
752
|
end
|
738
753
|
|
739
754
|
# Support lock mode, allowing FOR SHARE and FOR UPDATE queries.
|
@@ -746,6 +761,11 @@ module Sequel
|
|
746
761
|
end
|
747
762
|
end
|
748
763
|
|
764
|
+
# Use WITH RECURSIVE instead of WITH if any of the CTEs is recursive
|
765
|
+
def select_with_sql_base
|
766
|
+
opts[:with].any?{|w| w[:recursive]} ? SQL_WITH_RECURSIVE : super
|
767
|
+
end
|
768
|
+
|
749
769
|
# The version of the database server
|
750
770
|
def server_version
|
751
771
|
db.server_version(@opts[:server])
|
@@ -1,5 +1,3 @@
|
|
1
|
-
Sequel.require %w'date_format unsupported', 'adapters/utils'
|
2
|
-
|
3
1
|
module Sequel
|
4
2
|
module Progress
|
5
3
|
module DatabaseMethods
|
@@ -17,11 +15,18 @@ module Sequel
|
|
17
15
|
end
|
18
16
|
|
19
17
|
module DatasetMethods
|
20
|
-
include Dataset::UnsupportedIntersectExcept
|
21
|
-
include Dataset::SQLStandardDateFormat
|
22
|
-
|
23
18
|
SELECT_CLAUSE_ORDER = %w'limit distinct columns from join where group order having compounds'.freeze
|
24
19
|
|
20
|
+
# Progress requires SQL standard datetimes
|
21
|
+
def requires_sql_standard_datetimes?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
# Progress does not support INTERSECT or EXCEPT
|
26
|
+
def supports_intersect_except?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
25
30
|
private
|
26
31
|
|
27
32
|
def select_clause_order
|
@@ -1,10 +1,6 @@
|
|
1
|
-
Sequel.require %w'savepoint_transactions unsupported', 'adapters/utils'
|
2
|
-
|
3
1
|
module Sequel
|
4
2
|
module SQLite
|
5
3
|
module DatabaseMethods
|
6
|
-
include Sequel::Database::SavepointTransactions
|
7
|
-
|
8
4
|
AUTO_VACUUM = [:none, :full, :incremental].freeze
|
9
5
|
PRIMARY_KEY_INDEX_RE = /\Asqlite_autoindex_/.freeze
|
10
6
|
SYNCHRONOUS = [:off, :normal, :full].freeze
|
@@ -67,6 +63,11 @@ module Sequel
|
|
67
63
|
execute_ddl("PRAGMA #{name} = #{value}")
|
68
64
|
end
|
69
65
|
|
66
|
+
# SQLite supports savepoints
|
67
|
+
def supports_savepoints?
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
70
71
|
# A symbol signifying the value of the synchronous PRAGMA.
|
71
72
|
def synchronous
|
72
73
|
SYNCHRONOUS[pragma_get(:synchronous).to_i]
|
@@ -233,9 +234,8 @@ module Sequel
|
|
233
234
|
|
234
235
|
# Instance methods for datasets that connect to an SQLite database
|
235
236
|
module DatasetMethods
|
236
|
-
|
237
|
-
|
238
|
-
|
237
|
+
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
|
238
|
+
|
239
239
|
# SQLite does not support pattern matching via regular expressions.
|
240
240
|
# SQLite is case insensitive (depending on pragma), so use LIKE for
|
241
241
|
# ILIKE.
|
@@ -277,19 +277,35 @@ module Sequel
|
|
277
277
|
"`#{c}`"
|
278
278
|
end
|
279
279
|
|
280
|
-
|
280
|
+
# SQLite does not support INTERSECT ALL or EXCEPT ALL
|
281
|
+
def supports_intersect_except_all?
|
282
|
+
false
|
283
|
+
end
|
281
284
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
"X'#{blob}'"
|
285
|
+
# SQLite does not support IS TRUE
|
286
|
+
def supports_is_true?
|
287
|
+
false
|
286
288
|
end
|
289
|
+
|
290
|
+
private
|
287
291
|
|
288
292
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
289
293
|
def as_sql(expression, aliaz)
|
290
294
|
aliaz = aliaz.value if aliaz.is_a?(SQL::Identifier)
|
291
295
|
"#{expression} AS #{literal(aliaz.to_s)}"
|
292
296
|
end
|
297
|
+
|
298
|
+
# SQLite uses a preceding X for hex escaping strings
|
299
|
+
def literal_blob(v)
|
300
|
+
blob = ''
|
301
|
+
v.each_byte{|x| blob << sprintf('%02x', x)}
|
302
|
+
"X'#{blob}'"
|
303
|
+
end
|
304
|
+
|
305
|
+
# SQLite does not support the SQL WITH clause
|
306
|
+
def select_clause_order
|
307
|
+
SELECT_CLAUSE_ORDER
|
308
|
+
end
|
293
309
|
end
|
294
310
|
end
|
295
311
|
end
|