sequel 3.23.0 → 3.24.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +64 -0
- data/doc/association_basics.rdoc +43 -5
- data/doc/model_hooks.rdoc +64 -27
- data/doc/prepared_statements.rdoc +8 -4
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.23.0.txt +1 -1
- data/doc/release_notes/3.24.0.txt +420 -0
- data/lib/sequel/adapters/db2.rb +8 -1
- data/lib/sequel/adapters/firebird.rb +25 -9
- data/lib/sequel/adapters/informix.rb +4 -19
- data/lib/sequel/adapters/jdbc.rb +34 -17
- data/lib/sequel/adapters/jdbc/h2.rb +5 -0
- data/lib/sequel/adapters/jdbc/informix.rb +31 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
- data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
- data/lib/sequel/adapters/postgres.rb +30 -1
- data/lib/sequel/adapters/shared/access.rb +10 -0
- data/lib/sequel/adapters/shared/informix.rb +45 -0
- data/lib/sequel/adapters/shared/mssql.rb +82 -8
- data/lib/sequel/adapters/shared/mysql.rb +25 -7
- data/lib/sequel/adapters/shared/postgres.rb +39 -6
- data/lib/sequel/adapters/shared/sqlite.rb +57 -5
- data/lib/sequel/adapters/sqlite.rb +8 -3
- data/lib/sequel/adapters/swift/mysql.rb +9 -0
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/misc.rb +6 -0
- data/lib/sequel/database/query.rb +33 -3
- data/lib/sequel/database/schema_methods.rb +6 -2
- data/lib/sequel/dataset/features.rb +6 -0
- data/lib/sequel/dataset/prepared_statements.rb +17 -2
- data/lib/sequel/dataset/query.rb +17 -0
- data/lib/sequel/dataset/sql.rb +2 -53
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model.rb +5 -0
- data/lib/sequel/model/associations.rb +80 -14
- data/lib/sequel/model/base.rb +182 -55
- data/lib/sequel/model/exceptions.rb +3 -1
- data/lib/sequel/plugins/association_pks.rb +6 -4
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/many_through_many.rb +8 -3
- data/lib/sequel/plugins/prepared_statements.rb +140 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +72 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/sql.rb +8 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +43 -18
- data/spec/core/connection_pool_spec.rb +56 -77
- data/spec/core/database_spec.rb +25 -0
- data/spec/core/dataset_spec.rb +127 -16
- data/spec/core/expression_filters_spec.rb +13 -0
- data/spec/core/schema_spec.rb +6 -1
- data/spec/extensions/association_pks_spec.rb +7 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/many_through_many_spec.rb +60 -4
- data/spec/extensions/nested_attributes_spec.rb +1 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +69 -0
- data/spec/extensions/prepared_statements_spec.rb +72 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
- data/spec/extensions/to_dot_spec.rb +3 -5
- data/spec/integration/associations_test.rb +155 -1
- data/spec/integration/dataset_test.rb +8 -1
- data/spec/integration/plugin_test.rb +119 -0
- data/spec/integration/prepared_statement_test.rb +72 -1
- data/spec/integration/schema_test.rb +66 -8
- data/spec/integration/transaction_test.rb +40 -0
- data/spec/model/associations_spec.rb +349 -8
- data/spec/model/base_spec.rb +59 -0
- data/spec/model/hooks_spec.rb +161 -0
- data/spec/model/record_spec.rb +24 -0
- metadata +21 -4
@@ -1,6 +1,7 @@
|
|
1
1
|
module Sequel
|
2
2
|
module Access
|
3
3
|
module DatabaseMethods
|
4
|
+
# Access uses type :access as the database_type
|
4
5
|
def database_type
|
5
6
|
:access
|
6
7
|
end
|
@@ -16,6 +17,7 @@ module Sequel
|
|
16
17
|
from(:MSysObjects).filter(:Type=>1, :Flags=>0).select_map(:Name).map{|x| x.to_sym}
|
17
18
|
end
|
18
19
|
|
20
|
+
# Access uses type Counter for an autoincrementing keys
|
19
21
|
def serial_primary_key_options
|
20
22
|
{:primary_key => true, :type=>:Counter}
|
21
23
|
end
|
@@ -34,16 +36,24 @@ module Sequel
|
|
34
36
|
module DatasetMethods
|
35
37
|
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'limit distinct columns from join where group order having compounds')
|
36
38
|
|
39
|
+
# Access doesn't support INTERSECT or EXCEPT
|
37
40
|
def supports_intersect_except?
|
38
41
|
false
|
39
42
|
end
|
40
43
|
|
41
44
|
private
|
42
45
|
|
46
|
+
# Access uses TOP for limits
|
47
|
+
def select_limit_sql(sql)
|
48
|
+
sql << " TOP #{@opts[:limit]}" if @opts[:limit]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Access uses [] for quoting identifiers
|
43
52
|
def quoted_identifier(v)
|
44
53
|
"[#{v}]"
|
45
54
|
end
|
46
55
|
|
56
|
+
# Access requires the limit clause come before other clauses
|
47
57
|
def select_clause_methods
|
48
58
|
SELECT_CLAUSE_METHODS
|
49
59
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Sequel
|
2
|
+
module Informix
|
3
|
+
module DatabaseMethods
|
4
|
+
TEMPORARY = 'TEMP '.freeze
|
5
|
+
|
6
|
+
# Informix uses the :informix database type
|
7
|
+
def database_type
|
8
|
+
:informix
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Informix has issues with quoted identifiers, so
|
14
|
+
# turn off database quoting by default.
|
15
|
+
def quote_identifiers_default
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
# SQL fragment for showing a table is temporary
|
20
|
+
def temporary_table_sql
|
21
|
+
TEMPORARY
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module DatasetMethods
|
26
|
+
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'limit distinct columns from join where having group compounds order')
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Informix does not support INTERSECT or EXCEPT
|
31
|
+
def supports_intersect_except?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def select_clause_methods
|
36
|
+
SELECT_CLAUSE_METHODS
|
37
|
+
end
|
38
|
+
|
39
|
+
def select_limit_sql(sql)
|
40
|
+
sql << " SKIP #{@opts[:offset]}" if @opts[:offset]
|
41
|
+
sql << " FIRST #{@opts[:limit]}" if @opts[:limit]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -53,11 +53,13 @@ module Sequel
|
|
53
53
|
# Microsoft SQL Server supports using the INFORMATION_SCHEMA to get
|
54
54
|
# information on tables.
|
55
55
|
def tables(opts={})
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
56
|
+
information_schema_tables('BASE TABLE', opts)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Microsoft SQL Server supports using the INFORMATION_SCHEMA to get
|
60
|
+
# information on views.
|
61
|
+
def views(opts={})
|
62
|
+
information_schema_tables('VIEW', opts)
|
61
63
|
end
|
62
64
|
|
63
65
|
private
|
@@ -123,6 +125,15 @@ module Sequel
|
|
123
125
|
"DROP INDEX #{quote_identifier(op[:name] || default_index_name(table, op[:columns]))} ON #{quote_schema_table(table)}"
|
124
126
|
end
|
125
127
|
|
128
|
+
# Backbone of the tables and views support.
|
129
|
+
def information_schema_tables(type, opts)
|
130
|
+
m = output_identifier_meth
|
131
|
+
metadata_dataset.from(:information_schema__tables___t).
|
132
|
+
select(:table_name).
|
133
|
+
filter(:table_type=>type, :table_schema=>(opts[:schema]||default_schema||'dbo').to_s).
|
134
|
+
map{|x| m.call(x[:table_name])}
|
135
|
+
end
|
136
|
+
|
126
137
|
# Always quote identifiers in the metadata_dataset, so schema parsing works.
|
127
138
|
def metadata_dataset
|
128
139
|
ds = super
|
@@ -145,6 +156,16 @@ module Sequel
|
|
145
156
|
SQL_ROLLBACK
|
146
157
|
end
|
147
158
|
|
159
|
+
# The closest MSSQL equivalent of a boolean datatype is the bit type.
|
160
|
+
def schema_column_type(db_type)
|
161
|
+
case db_type
|
162
|
+
when /\A(bit)\z/io
|
163
|
+
:boolean
|
164
|
+
else
|
165
|
+
super
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
148
169
|
# MSSQL uses the INFORMATION_SCHEMA to hold column information. This method does
|
149
170
|
# not support the parsing of primary key information.
|
150
171
|
def schema_parse_table(table_name, opts)
|
@@ -231,6 +252,29 @@ module Sequel
|
|
231
252
|
@mssql_unicode_strings = db.mssql_unicode_strings
|
232
253
|
end
|
233
254
|
|
255
|
+
# Ugly hack. While MSSQL supports TRUE and FALSE values, you can't
|
256
|
+
# actually specify them directly in SQL. Unfortunately, you also cannot
|
257
|
+
# use an integer value when a boolean is required. Also unforunately, you
|
258
|
+
# cannot use an expression that yields a boolean type in cases where in an
|
259
|
+
# integer type is needed, such as inserting into a bit field (the closest thing
|
260
|
+
# MSSQL has to a boolean).
|
261
|
+
#
|
262
|
+
# In filters, SQL::BooleanConstants are used more, while in other places
|
263
|
+
# the ruby true/false values are used more, so use expressions that return booleans
|
264
|
+
# for SQL::BooleanConstants, and 1/0 for other places.
|
265
|
+
# The correct fix for this would require separate literalization paths for
|
266
|
+
# filters compared to other values, but that's more work than I want to do right now.
|
267
|
+
def boolean_constant_sql(constant)
|
268
|
+
case constant
|
269
|
+
when true
|
270
|
+
'(1 = 1)'
|
271
|
+
when false
|
272
|
+
'(1 = 0)'
|
273
|
+
else
|
274
|
+
super
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
234
278
|
# MSSQL uses + for string concatenation, and LIKE is case insensitive by default.
|
235
279
|
def complex_expression_sql(op, args)
|
236
280
|
case op
|
@@ -277,8 +321,8 @@ module Sequel
|
|
277
321
|
|
278
322
|
# Use the OUTPUT clause to get the value of all columns for the newly inserted record.
|
279
323
|
def insert_select(*values)
|
280
|
-
return unless
|
281
|
-
naked.clone(default_server_opts(:sql=>output(nil, [:inserted
|
324
|
+
return unless supports_insert_select?
|
325
|
+
naked.clone(default_server_opts(:sql=>output(nil, [SQL::ColumnAll.new(:inserted)]).insert_sql(*values))).single_record
|
282
326
|
end
|
283
327
|
|
284
328
|
# Specify a table for a SELECT ... INTO query.
|
@@ -367,6 +411,11 @@ module Sequel
|
|
367
411
|
db.server_version(@opts[:server])
|
368
412
|
end
|
369
413
|
|
414
|
+
# MSSQL supports insert_select via the OUTPUT clause.
|
415
|
+
def supports_insert_select?
|
416
|
+
supports_output_clause? && !opts[:disable_insert_output]
|
417
|
+
end
|
418
|
+
|
370
419
|
# MSSQL 2005+ supports INTERSECT and EXCEPT
|
371
420
|
def supports_intersect_except?
|
372
421
|
is_2005_or_later?
|
@@ -441,6 +490,22 @@ module Sequel
|
|
441
490
|
alias insert_with_sql delete_with_sql
|
442
491
|
alias update_with_sql delete_with_sql
|
443
492
|
|
493
|
+
# Special case when true or false is provided directly to filter.
|
494
|
+
def filter_expr(expr)
|
495
|
+
if block_given?
|
496
|
+
super
|
497
|
+
else
|
498
|
+
case expr
|
499
|
+
when true
|
500
|
+
Sequel::TRUE
|
501
|
+
when false
|
502
|
+
Sequel::FALSE
|
503
|
+
else
|
504
|
+
super
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
444
509
|
# MSSQL raises an error if you try to provide more than 3 decimal places
|
445
510
|
# for a fractional timestamp. This probably doesn't work for smalldatetime
|
446
511
|
# fields.
|
@@ -454,6 +519,16 @@ module Sequel
|
|
454
519
|
INSERT_CLAUSE_METHODS
|
455
520
|
end
|
456
521
|
|
522
|
+
# Use OUTPUT INSERTED.* to return all columns of the inserted row,
|
523
|
+
# for use with the prepared statement code.
|
524
|
+
def insert_output_sql(sql)
|
525
|
+
if @opts.has_key?(:returning)
|
526
|
+
sql << " OUTPUT INSERTED.*"
|
527
|
+
else
|
528
|
+
output_sql(sql)
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
457
532
|
# MSSQL uses a literal hexidecimal number for blob strings
|
458
533
|
def literal_blob(v)
|
459
534
|
blob = '0x'
|
@@ -529,7 +604,6 @@ module Sequel
|
|
529
604
|
end
|
530
605
|
alias delete_output_sql output_sql
|
531
606
|
alias update_output_sql output_sql
|
532
|
-
alias insert_output_sql output_sql
|
533
607
|
|
534
608
|
# MSSQL supports the OUTPUT clause for UPDATE statements.
|
535
609
|
# It also allows prepending a WITH clause.
|
@@ -83,13 +83,9 @@ module Sequel
|
|
83
83
|
@server_version ||= (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
|
84
84
|
end
|
85
85
|
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
# * :server - Set the server to use
|
90
|
-
def tables(opts={})
|
91
|
-
m = output_identifier_meth
|
92
|
-
metadata_dataset.with_sql('SHOW TABLES').server(opts[:server]).map{|r| m.call(r.values.first)}
|
86
|
+
# MySQL supports CREATE TABLE IF NOT EXISTS syntax.
|
87
|
+
def supports_create_table_if_not_exists?
|
88
|
+
true
|
93
89
|
end
|
94
90
|
|
95
91
|
# MySQL supports prepared transactions (two-phase commit) using XA
|
@@ -107,6 +103,14 @@ module Sequel
|
|
107
103
|
true
|
108
104
|
end
|
109
105
|
|
106
|
+
# Return an array of symbols specifying table names in the current database.
|
107
|
+
#
|
108
|
+
# Options:
|
109
|
+
# * :server - Set the server to use
|
110
|
+
def tables(opts={})
|
111
|
+
full_tables('BASE TABLE', opts)
|
112
|
+
end
|
113
|
+
|
110
114
|
# Changes the database in use by issuing a USE statement. I would be
|
111
115
|
# very careful if I used this.
|
112
116
|
def use(db_name)
|
@@ -116,6 +120,14 @@ module Sequel
|
|
116
120
|
self
|
117
121
|
end
|
118
122
|
|
123
|
+
# Return an array of symbols specifying view names in the current database.
|
124
|
+
#
|
125
|
+
# Options:
|
126
|
+
# * :server - Set the server to use
|
127
|
+
def views(opts={})
|
128
|
+
full_tables('VIEW', opts)
|
129
|
+
end
|
130
|
+
|
119
131
|
private
|
120
132
|
|
121
133
|
# Use MySQL specific syntax for rename column, set column type, and
|
@@ -205,6 +217,12 @@ module Sequel
|
|
205
217
|
"#{super}#{" ENGINE=#{engine}" if engine}#{" DEFAULT CHARSET=#{charset}" if charset}#{" DEFAULT COLLATE=#{collate}" if collate}"
|
206
218
|
end
|
207
219
|
|
220
|
+
# Backbone of the tables and views support using SHOW FULL TABLES.
|
221
|
+
def full_tables(type, opts)
|
222
|
+
m = output_identifier_meth
|
223
|
+
metadata_dataset.with_sql('SHOW FULL TABLES').server(opts[:server]).map{|r| m.call(r.values.first) if r.delete(:Table_type) == type}.compact
|
224
|
+
end
|
225
|
+
|
208
226
|
# MySQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
|
209
227
|
def identifier_input_method_default
|
210
228
|
nil
|
@@ -387,11 +387,17 @@ module Sequel
|
|
387
387
|
# Options:
|
388
388
|
# * :schema - The schema to search (default_schema by default)
|
389
389
|
# * :server - The server to use
|
390
|
-
def tables(opts={})
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
390
|
+
def tables(opts={}, &block)
|
391
|
+
pg_class_relname('r', opts, &block)
|
392
|
+
end
|
393
|
+
|
394
|
+
# Array of symbols specifying view names in the current database.
|
395
|
+
#
|
396
|
+
# Options:
|
397
|
+
# * :schema - The schema to search (default_schema by default)
|
398
|
+
# * :server - The server to use
|
399
|
+
def views(opts={})
|
400
|
+
pg_class_relname('v', opts)
|
395
401
|
end
|
396
402
|
|
397
403
|
private
|
@@ -540,6 +546,14 @@ module Sequel
|
|
540
546
|
conn.execute(sql)
|
541
547
|
end
|
542
548
|
|
549
|
+
# Backbone of the tables and views support.
|
550
|
+
def pg_class_relname(type, opts)
|
551
|
+
ds = metadata_dataset.from(:pg_class).filter(:relkind=>type).select(:relname).exclude(SQL::StringExpression.like(:relname, SYSTEM_TABLE_REGEXP)).server(opts[:server]).join(:pg_namespace, :oid=>:relnamespace)
|
552
|
+
ds = filter_schema(ds, opts)
|
553
|
+
m = output_identifier_meth
|
554
|
+
block_given? ? yield(ds) : ds.map{|r| m.call(r[:relname])}
|
555
|
+
end
|
556
|
+
|
543
557
|
# Use a dollar sign instead of question mark for the argument
|
544
558
|
# placeholder.
|
545
559
|
def prepared_arg_placeholder
|
@@ -632,6 +646,7 @@ module Sequel
|
|
632
646
|
EXPLAIN = 'EXPLAIN '.freeze
|
633
647
|
EXPLAIN_ANALYZE = 'EXPLAIN ANALYZE '.freeze
|
634
648
|
FOR_SHARE = ' FOR SHARE'.freeze
|
649
|
+
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'into columns values returning_select')
|
635
650
|
LOCK = 'LOCK TABLE %s IN %s MODE'.freeze
|
636
651
|
NULL = LiteralString.new('NULL').freeze
|
637
652
|
PG_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
|
@@ -726,7 +741,7 @@ module Sequel
|
|
726
741
|
|
727
742
|
# Insert a record returning the record inserted
|
728
743
|
def insert_select(*values)
|
729
|
-
return
|
744
|
+
return unless supports_insert_select?
|
730
745
|
naked.clone(default_server_opts(:sql=>insert_returning_sql(nil, *values))).single_record
|
731
746
|
end
|
732
747
|
|
@@ -757,6 +772,11 @@ module Sequel
|
|
757
772
|
true
|
758
773
|
end
|
759
774
|
|
775
|
+
# PostgreSQL support insert_select using the RETURNING clause.
|
776
|
+
def supports_insert_select?
|
777
|
+
server_version >= 80200 && !opts[:disable_insert_returning]
|
778
|
+
end
|
779
|
+
|
760
780
|
# PostgreSQL supports modifying joined datasets
|
761
781
|
def supports_modifying_joins?
|
762
782
|
true
|
@@ -794,11 +814,24 @@ module Sequel
|
|
794
814
|
join_from_sql(:USING, sql)
|
795
815
|
end
|
796
816
|
|
817
|
+
# PostgreSQL allows a RETURNING clause.
|
818
|
+
def insert_clause_methods
|
819
|
+
INSERT_CLAUSE_METHODS
|
820
|
+
end
|
821
|
+
|
797
822
|
# Use the RETURNING clause to return the primary key of the inserted record, if it exists
|
798
823
|
def insert_returning_pk_sql(*values)
|
799
824
|
pk = db.primary_key(opts[:from].first) if opts[:from] && !opts[:from].empty?
|
800
825
|
insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) : NULL, *values)
|
801
826
|
end
|
827
|
+
|
828
|
+
# Add a RETURNING clause if it is set and the database supports it and
|
829
|
+
# this dataset hasn't disabled it.
|
830
|
+
def insert_returning_select_sql(sql)
|
831
|
+
if supports_insert_select? && opts.has_key?(:returning)
|
832
|
+
sql << " RETURNING #{column_list(Array(opts[:returning]))}"
|
833
|
+
end
|
834
|
+
end
|
802
835
|
|
803
836
|
# For multiple table support, PostgreSQL requires at least
|
804
837
|
# two from tables, with joins allowed.
|
@@ -7,8 +7,9 @@ module Sequel
|
|
7
7
|
AUTO_VACUUM = [:none, :full, :incremental].freeze
|
8
8
|
PRIMARY_KEY_INDEX_RE = /\Asqlite_autoindex_/.freeze
|
9
9
|
SYNCHRONOUS = [:off, :normal, :full].freeze
|
10
|
-
TABLES_FILTER = "type = 'table' AND NOT name = 'sqlite_sequence'"
|
10
|
+
TABLES_FILTER = "type = 'table' AND NOT name = 'sqlite_sequence'".freeze
|
11
11
|
TEMP_STORE = [:default, :file, :memory].freeze
|
12
|
+
VIEWS_FILTER = "type = 'view'".freeze
|
12
13
|
|
13
14
|
# Run all alter_table commands in a transaction. This is technically only
|
14
15
|
# needed for drop column.
|
@@ -96,6 +97,11 @@ module Sequel
|
|
96
97
|
end
|
97
98
|
end
|
98
99
|
|
100
|
+
# SQLite supports CREATE TABLE IF NOT EXISTS syntax since 3.3.0.
|
101
|
+
def supports_create_table_if_not_exists?
|
102
|
+
sqlite_version >= 30300
|
103
|
+
end
|
104
|
+
|
99
105
|
# SQLite 3.6.8+ supports savepoints.
|
100
106
|
def supports_savepoints?
|
101
107
|
sqlite_version >= 30608
|
@@ -118,8 +124,7 @@ module Sequel
|
|
118
124
|
# Options:
|
119
125
|
# * :server - Set the server to use.
|
120
126
|
def tables(opts={})
|
121
|
-
|
122
|
-
metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(TABLES_FILTER).map{|r| m.call(r[:name])}
|
127
|
+
tables_and_views(TABLES_FILTER, opts)
|
123
128
|
end
|
124
129
|
|
125
130
|
# A symbol signifying the value of the temp_store PRAGMA.
|
@@ -134,6 +139,14 @@ module Sequel
|
|
134
139
|
pragma_set(:temp_store, value)
|
135
140
|
end
|
136
141
|
|
142
|
+
# Array of symbols specifying the view names in the current database.
|
143
|
+
#
|
144
|
+
# Options:
|
145
|
+
# * :server - Set the server to use.
|
146
|
+
def views(opts={})
|
147
|
+
tables_and_views(VIEWS_FILTER, opts)
|
148
|
+
end
|
149
|
+
|
137
150
|
private
|
138
151
|
|
139
152
|
# SQLite supports limited table modification. You can add a column
|
@@ -306,6 +319,12 @@ module Sequel
|
|
306
319
|
end
|
307
320
|
end
|
308
321
|
|
322
|
+
# Backbone of the tables and views support.
|
323
|
+
def tables_and_views(filter, opts)
|
324
|
+
m = output_identifier_meth
|
325
|
+
metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(filter).map{|r| m.call(r[:name])}
|
326
|
+
end
|
327
|
+
|
309
328
|
# SQLite uses the integer data type even for bignums. This is because they
|
310
329
|
# are both stored internally as text, and converted when returned from
|
311
330
|
# the database. Using an integer type instead of bigint makes it more likely
|
@@ -320,7 +339,24 @@ module Sequel
|
|
320
339
|
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'distinct columns from join where group having compounds order limit')
|
321
340
|
COMMA_SEPARATOR = ', '.freeze
|
322
341
|
CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}
|
323
|
-
|
342
|
+
|
343
|
+
# Ugly hack. Really, SQLite uses 0 for false and 1 for true
|
344
|
+
# but then you can't differentiate between integers and booleans.
|
345
|
+
# In filters, SQL::BooleanConstants are used more, while in other places
|
346
|
+
# the ruby true/false values are used more, so use 1/0 for SQL::BooleanConstants.
|
347
|
+
# The correct fix for this would require separate literalization paths for
|
348
|
+
# filters compared to other values, but that's more work than I want to do right now.
|
349
|
+
def boolean_constant_sql(constant)
|
350
|
+
case constant
|
351
|
+
when true
|
352
|
+
'1'
|
353
|
+
when false
|
354
|
+
'0'
|
355
|
+
else
|
356
|
+
super
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
324
360
|
# SQLite does not support pattern matching via regular expressions.
|
325
361
|
# SQLite is case insensitive (depending on pragma), so use LIKE for
|
326
362
|
# ILIKE.
|
@@ -395,6 +431,22 @@ module Sequel
|
|
395
431
|
"#{expression} AS #{literal(aliaz.to_s)}"
|
396
432
|
end
|
397
433
|
|
434
|
+
# Special case when true or false is provided directly to filter.
|
435
|
+
def filter_expr(expr)
|
436
|
+
if block_given?
|
437
|
+
super
|
438
|
+
else
|
439
|
+
case expr
|
440
|
+
when true
|
441
|
+
1
|
442
|
+
when false
|
443
|
+
0
|
444
|
+
else
|
445
|
+
super
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
398
450
|
# SQL fragment specifying a list of identifiers
|
399
451
|
def identifier_list(columns)
|
400
452
|
columns.map{|i| quote_identifier(i)}.join(COMMA_SEPARATOR)
|
@@ -406,7 +458,7 @@ module Sequel
|
|
406
458
|
v.each_byte{|x| blob << sprintf('%02x', x)}
|
407
459
|
"X'#{blob}'"
|
408
460
|
end
|
409
|
-
|
461
|
+
|
410
462
|
# SQLite does not support the SQL WITH clause
|
411
463
|
def select_clause_methods
|
412
464
|
SELECT_CLAUSE_METHODS
|