sequel 3.1.0 → 3.2.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 +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
|