sequel 3.30.0 → 3.31.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 +40 -0
- data/Rakefile +12 -2
- data/doc/association_basics.rdoc +28 -0
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/opening_databases.rdoc +1 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/lib/sequel/adapters/jdbc.rb +7 -6
- data/lib/sequel/adapters/jdbc/derby.rb +5 -0
- data/lib/sequel/adapters/jdbc/h2.rb +6 -1
- data/lib/sequel/adapters/mock.rb +21 -2
- data/lib/sequel/adapters/shared/db2.rb +10 -0
- data/lib/sequel/adapters/shared/mssql.rb +40 -5
- data/lib/sequel/adapters/shared/mysql.rb +19 -2
- data/lib/sequel/adapters/shared/oracle.rb +13 -1
- data/lib/sequel/adapters/shared/postgres.rb +52 -8
- data/lib/sequel/adapters/shared/sqlite.rb +4 -3
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/database/schema_generator.rb +9 -2
- data/lib/sequel/dataset/actions.rb +37 -19
- data/lib/sequel/dataset/features.rb +10 -0
- data/lib/sequel/dataset/prepared_statements.rb +0 -10
- data/lib/sequel/dataset/query.rb +13 -1
- data/lib/sequel/dataset/sql.rb +6 -1
- data/lib/sequel/model/associations.rb +14 -4
- data/lib/sequel/model/base.rb +10 -0
- data/lib/sequel/plugins/serialization.rb +82 -43
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +46 -0
- data/spec/adapters/mysql_spec.rb +3 -0
- data/spec/adapters/postgres_spec.rb +61 -24
- data/spec/core/database_spec.rb +31 -18
- data/spec/core/dataset_spec.rb +90 -13
- data/spec/core/mock_adapter_spec.rb +37 -0
- data/spec/extensions/instance_filters_spec.rb +1 -0
- data/spec/extensions/nested_attributes_spec.rb +1 -1
- data/spec/extensions/serialization_spec.rb +49 -5
- data/spec/extensions/sharding_spec.rb +1 -1
- data/spec/integration/associations_test.rb +15 -0
- data/spec/integration/dataset_test.rb +71 -0
- data/spec/integration/prepared_statement_test.rb +8 -0
- data/spec/model/association_reflection_spec.rb +27 -0
- data/spec/model/associations_spec.rb +18 -3
- data/spec/model/base_spec.rb +20 -0
- data/spec/model/eager_loading_spec.rb +21 -0
- metadata +4 -2
@@ -345,6 +345,7 @@ module Sequel
|
|
345
345
|
INSERT = Dataset::INSERT
|
346
346
|
COMMA = Dataset::COMMA
|
347
347
|
LIMIT = Dataset::LIMIT
|
348
|
+
GROUP_BY = Dataset::GROUP_BY
|
348
349
|
REGEXP = 'REGEXP'.freeze
|
349
350
|
LIKE = 'LIKE'.freeze
|
350
351
|
BINARY = 'BINARY '.freeze
|
@@ -361,6 +362,7 @@ module Sequel
|
|
361
362
|
ON_DUPLICATE_KEY_UPDATE = " ON DUPLICATE KEY UPDATE ".freeze
|
362
363
|
EQ_VALUES = '=VALUES('.freeze
|
363
364
|
EQ = '='.freeze
|
365
|
+
WITH_ROLLUP = ' WITH ROLLUP'.freeze
|
364
366
|
|
365
367
|
# MySQL specific syntax for LIKE/REGEXP searches, as well as
|
366
368
|
# string concatenation.
|
@@ -423,8 +425,9 @@ module Sequel
|
|
423
425
|
end
|
424
426
|
|
425
427
|
# MySQL specific full text search syntax.
|
426
|
-
def full_text_sql(cols,
|
427
|
-
|
428
|
+
def full_text_sql(cols, terms, opts = {})
|
429
|
+
terms = terms.join(' ') if terms.is_a?(Array)
|
430
|
+
SQL::PlaceholderLiteralString.new("MATCH ? AGAINST (?#{" IN BOOLEAN MODE" if opts[:boolean]})", [Array(cols), terms], true)
|
428
431
|
end
|
429
432
|
|
430
433
|
# MySQL allows HAVING clause on ungrouped datasets.
|
@@ -518,6 +521,11 @@ module Sequel
|
|
518
521
|
true
|
519
522
|
end
|
520
523
|
|
524
|
+
# MySQL supports GROUP BY WITH ROLLUP (but not CUBE)
|
525
|
+
def supports_group_rollup?
|
526
|
+
true
|
527
|
+
end
|
528
|
+
|
521
529
|
# MySQL does not support INTERSECT or EXCEPT
|
522
530
|
def supports_intersect_except?
|
523
531
|
false
|
@@ -661,6 +669,15 @@ module Sequel
|
|
661
669
|
SELECT_CLAUSE_METHODS
|
662
670
|
end
|
663
671
|
|
672
|
+
# MySQL supports ROLLUP via nonstandard SQL syntax
|
673
|
+
def select_group_sql(sql)
|
674
|
+
if group = @opts[:group]
|
675
|
+
sql << GROUP_BY
|
676
|
+
expression_list_append(sql, group)
|
677
|
+
sql << WITH_ROLLUP if @opts[:group_options] == :rollup
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
664
681
|
# Support FOR SHARE locking when using the :share lock style.
|
665
682
|
def select_lock_sql(sql)
|
666
683
|
@opts[:lock] == :share ? (sql << FOR_SHARE) : super
|
@@ -247,8 +247,10 @@ module Sequel
|
|
247
247
|
compound_clone(:minus, dataset, opts)
|
248
248
|
end
|
249
249
|
|
250
|
+
# Use a custom expression with EXISTS to determine whether a dataset
|
251
|
+
# is empty.
|
250
252
|
def empty?
|
251
|
-
db[:dual].where(unordered.exists).get(1) == nil
|
253
|
+
db[:dual].where(@opts[:offset] ? exists : unordered.exists).get(1) == nil
|
252
254
|
end
|
253
255
|
|
254
256
|
# Oracle requires SQL standard datetimes
|
@@ -283,6 +285,16 @@ module Sequel
|
|
283
285
|
true
|
284
286
|
end
|
285
287
|
|
288
|
+
# Oracle supports GROUP BY CUBE
|
289
|
+
def supports_group_cube?
|
290
|
+
true
|
291
|
+
end
|
292
|
+
|
293
|
+
# Oracle supports GROUP BY ROLLUP
|
294
|
+
def supports_group_rollup?
|
295
|
+
true
|
296
|
+
end
|
297
|
+
|
286
298
|
# Oracle does not support INTERSECT ALL or EXCEPT ALL
|
287
299
|
def supports_intersect_except_all?
|
288
300
|
false
|
@@ -345,8 +345,11 @@ module Sequel
|
|
345
345
|
(conn.server_version rescue nil) if conn.respond_to?(:server_version)
|
346
346
|
end
|
347
347
|
unless @server_version
|
348
|
-
m = /PostgreSQL (\d+)\.(\d+)(?:(?:rc\d+)|\.(\d+))?/.match(fetch('SELECT version()').single_value)
|
349
|
-
|
348
|
+
@server_version = if m = /PostgreSQL (\d+)\.(\d+)(?:(?:rc\d+)|\.(\d+))?/.match(fetch('SELECT version()').single_value)
|
349
|
+
(m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
|
350
|
+
else
|
351
|
+
0
|
352
|
+
end
|
350
353
|
end
|
351
354
|
@server_version
|
352
355
|
end
|
@@ -493,7 +496,7 @@ module Sequel
|
|
493
496
|
filter = " WHERE #{filter_expr(filter)}" if filter
|
494
497
|
case index_type
|
495
498
|
when :full_text
|
496
|
-
expr = "(to_tsvector(#{literal(index[:language] || 'simple')}, #{dataset.send(:full_text_string_join, cols)}))"
|
499
|
+
expr = "(to_tsvector(#{literal(index[:language] || 'simple')}, #{literal(dataset.send(:full_text_string_join, cols))}))"
|
497
500
|
index_type = :gin
|
498
501
|
when :spatial
|
499
502
|
index_type = :gist
|
@@ -577,7 +580,8 @@ module Sequel
|
|
577
580
|
SQL::Function.new(:format_type, :pg_type__oid, :pg_attribute__atttypmod).as(:db_type),
|
578
581
|
SQL::Function.new(:pg_get_expr, :pg_attrdef__adbin, :pg_class__oid).as(:default),
|
579
582
|
SQL::BooleanExpression.new(:NOT, :pg_attribute__attnotnull).as(:allow_null),
|
580
|
-
SQL::Function.new(:COALESCE, SQL::BooleanExpression.from_value_pairs(:pg_attribute__attnum => SQL::Function.new(:ANY, :pg_index__indkey)), false).as(:primary_key)
|
583
|
+
SQL::Function.new(:COALESCE, SQL::BooleanExpression.from_value_pairs(:pg_attribute__attnum => SQL::Function.new(:ANY, :pg_index__indkey)), false).as(:primary_key),
|
584
|
+
:pg_namespace__nspname).
|
581
585
|
from(:pg_class).
|
582
586
|
join(:pg_attribute, :attrelid=>:oid).
|
583
587
|
join(:pg_type, :oid=>:atttypid).
|
@@ -589,7 +593,16 @@ module Sequel
|
|
589
593
|
filter(:pg_class__relname=>m2.call(table_name)).
|
590
594
|
order(:pg_attribute__attnum)
|
591
595
|
ds = filter_schema(ds, opts)
|
596
|
+
current_schema = nil
|
592
597
|
ds.map do |row|
|
598
|
+
sch = row.delete(:nspname)
|
599
|
+
if current_schema
|
600
|
+
if sch != current_schema
|
601
|
+
raise Error, "columns from tables in two separate schema were returned (please specify a schema): #{current_schema.inspect}, #{sch.inspect}"
|
602
|
+
end
|
603
|
+
else
|
604
|
+
current_schema = sch
|
605
|
+
end
|
593
606
|
row[:default] = nil if blank_object?(row[:default])
|
594
607
|
row[:type] = schema_column_type(row[:db_type])
|
595
608
|
[m.call(row.delete(:name)), row]
|
@@ -746,7 +759,8 @@ module Sequel
|
|
746
759
|
# in 8.3 by default, and available for earlier versions as an add-on).
|
747
760
|
def full_text_search(cols, terms, opts = {})
|
748
761
|
lang = opts[:language] || 'simple'
|
749
|
-
|
762
|
+
terms = terms.join(' | ') if terms.is_a?(Array)
|
763
|
+
filter("to_tsvector(?, ?) @@ to_tsquery(?, ?)", lang, full_text_string_join(cols), lang, terms)
|
750
764
|
end
|
751
765
|
|
752
766
|
# Insert given values into the database.
|
@@ -756,7 +770,14 @@ module Sequel
|
|
756
770
|
elsif !@opts[:sql] && supports_insert_select?
|
757
771
|
returning(insert_pk).insert(*values){|r| return r.values.first}
|
758
772
|
elsif (f = opts[:from]) && !f.empty?
|
759
|
-
|
773
|
+
v = if values.size == 1
|
774
|
+
values.first
|
775
|
+
elsif values.size == 2 && values.all?{|v0| v0.is_a?(Array)}
|
776
|
+
Hash[*values.first.zip(values.last).flatten]
|
777
|
+
else
|
778
|
+
values
|
779
|
+
end
|
780
|
+
execute_insert(insert_sql(*values), :table=>f.first, :values=>v)
|
760
781
|
else
|
761
782
|
super
|
762
783
|
end
|
@@ -812,7 +833,7 @@ module Sequel
|
|
812
833
|
if type == :insert
|
813
834
|
server_version >= 80200 && !opts[:disable_insert_returning]
|
814
835
|
else
|
815
|
-
server_version >=
|
836
|
+
server_version >= 80200
|
816
837
|
end
|
817
838
|
end
|
818
839
|
|
@@ -831,6 +852,29 @@ module Sequel
|
|
831
852
|
clone(:window=>(@opts[:window]||[]) + [[name, SQL::Window.new(opts)]])
|
832
853
|
end
|
833
854
|
|
855
|
+
protected
|
856
|
+
|
857
|
+
# If returned primary keys are requested, use RETURNING unless already set on the
|
858
|
+
# dataset. If RETURNING is already set, use existing returning values. If RETURNING
|
859
|
+
# is only set to return a single columns, return an array of just that column.
|
860
|
+
# Otherwise, return an array of hashes.
|
861
|
+
def _import(columns, values, opts={})
|
862
|
+
if server_version >= 80200
|
863
|
+
if opts[:return] == :primary_key && !@opts[:returning]
|
864
|
+
returning(insert_pk)._import(columns, values, opts)
|
865
|
+
elsif @opts[:returning]
|
866
|
+
statements = multi_insert_sql(columns, values)
|
867
|
+
@db.transaction(opts.merge(:server=>@opts[:server])) do
|
868
|
+
statements.map{|st| returning_fetch_rows(st)}
|
869
|
+
end.first.map{|v| v.length == 1 ? v.values.first : v}
|
870
|
+
else
|
871
|
+
super
|
872
|
+
end
|
873
|
+
else
|
874
|
+
super
|
875
|
+
end
|
876
|
+
end
|
877
|
+
|
834
878
|
private
|
835
879
|
|
836
880
|
# PostgreSQL allows deleting from joined datasets
|
@@ -948,7 +992,7 @@ module Sequel
|
|
948
992
|
cols = Array(cols).map{|x| SQL::Function.new(:COALESCE, x, EMPTY_STRING)}
|
949
993
|
cols = cols.zip([SPACE] * cols.length).flatten
|
950
994
|
cols.pop
|
951
|
-
|
995
|
+
SQL::StringExpression.new(:'||', *cols)
|
952
996
|
end
|
953
997
|
|
954
998
|
# PostgreSQL splits the main table from the joined tables
|
@@ -405,7 +405,7 @@ module Sequel
|
|
405
405
|
AS = Dataset::AS
|
406
406
|
APOS = Dataset::APOS
|
407
407
|
EXTRACT_OPEN = "CAST(strftime(".freeze
|
408
|
-
|
408
|
+
EXTRACT_CLOSE = ') AS '.freeze
|
409
409
|
NUMERIC = 'NUMERIC'.freeze
|
410
410
|
INTEGER = 'INTEGER'.freeze
|
411
411
|
BACKTICK = '`'.freeze
|
@@ -435,13 +435,14 @@ module Sequel
|
|
435
435
|
raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
|
436
436
|
sql << EXTRACT_OPEN << format << COMMA
|
437
437
|
literal_append(sql, args.at(1))
|
438
|
-
sql <<
|
438
|
+
sql << EXTRACT_CLOSE << (part == :second ? NUMERIC : INTEGER) << PAREN_CLOSE
|
439
439
|
else
|
440
440
|
super
|
441
441
|
end
|
442
442
|
end
|
443
443
|
|
444
|
-
#
|
444
|
+
# SQLite has CURRENT_TIMESTAMP and related constants in UTC instead
|
445
|
+
# of in localtime, so convert those constants to local time.
|
445
446
|
def constant_sql_append(sql, constant)
|
446
447
|
if c = CONSTANT_MAP[constant]
|
447
448
|
sql << c
|
@@ -1,9 +1,6 @@
|
|
1
1
|
module Sequel
|
2
2
|
class Dataset
|
3
3
|
module StoredProcedureMethods
|
4
|
-
SQL_QUERY_TYPE = Hash.new{|h,k| h[k] = k}
|
5
|
-
SQL_QUERY_TYPE[:first] = SQL_QUERY_TYPE[:all] = :select
|
6
|
-
|
7
4
|
# The name of the stored procedure to call
|
8
5
|
attr_accessor :sproc_name
|
9
6
|
|
@@ -44,14 +41,7 @@ module Sequel
|
|
44
41
|
# ignored anyway).
|
45
42
|
def sproc_type=(type)
|
46
43
|
@sproc_type = type
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
# The type of query (:select, :insert, :delete, :update).
|
53
|
-
def sql_query_type
|
54
|
-
SQL_QUERY_TYPE[@sproc_type]
|
44
|
+
@opts[:sql] = ''
|
55
45
|
end
|
56
46
|
end
|
57
47
|
|
@@ -125,6 +125,13 @@ module Sequel
|
|
125
125
|
# foreign_key(:artist_id) # artist_id INTEGER
|
126
126
|
# foreign_key(:artist_id, :artists) # artist_id INTEGER REFERENCES artists
|
127
127
|
# foreign_key(:artist_id, :artists, :key=>:id) # artist_id INTEGER REFERENCES artists(id)
|
128
|
+
#
|
129
|
+
# If you want a foreign key constraint without adding a column (usually because it is a
|
130
|
+
# composite foreign key), you can provide an array of columns as the first argument, and
|
131
|
+
# you can provide the :name option to name the constraint:
|
132
|
+
#
|
133
|
+
# foreign_key([:artist_name, :artist_location], :artists, :name=>:artist_fk)
|
134
|
+
# # ADD CONSTRAINT artist_fk FOREIGN KEY (artist_name, artist_location) REFERENCES artists
|
128
135
|
def foreign_key(name, table=nil, opts = {})
|
129
136
|
opts = case table
|
130
137
|
when Hash
|
@@ -282,8 +289,8 @@ module Sequel
|
|
282
289
|
# to the DDL for the table. See Generator#column for the available options.
|
283
290
|
#
|
284
291
|
# You can also pass an array of column names for creating composite foreign
|
285
|
-
# keys. In this case, it will assume the columns
|
286
|
-
# the constraint.
|
292
|
+
# keys. In this case, it will assume the columns exist and will only add
|
293
|
+
# the constraint. You can provide a :name option to name the constraint.
|
287
294
|
#
|
288
295
|
# NOTE: If you need to add a foreign key constraint to a single existing column
|
289
296
|
# use the composite key syntax even if it is only one column.
|
@@ -137,10 +137,10 @@ module Sequel
|
|
137
137
|
|
138
138
|
# Returns true if no records exist in the dataset, false otherwise
|
139
139
|
#
|
140
|
-
# DB[:table].empty? # SELECT 1 FROM table LIMIT 1
|
140
|
+
# DB[:table].empty? # SELECT 1 AS one FROM table LIMIT 1
|
141
141
|
# # => false
|
142
142
|
def empty?
|
143
|
-
get(1).nil?
|
143
|
+
get(Sequel::SQL::AliasedExpression.new(1, :one)).nil?
|
144
144
|
end
|
145
145
|
|
146
146
|
# Executes a select query and fetches records, yielding each record to the
|
@@ -229,31 +229,33 @@ module Sequel
|
|
229
229
|
# DB[:table].import([:x, :y], DB[:table2].select(:a, :b))
|
230
230
|
# # INSERT INTO table (x, y) SELECT a, b FROM table2
|
231
231
|
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
232
|
+
# Options:
|
233
|
+
# :commit_every :: Open a new transaction for every given number of records.
|
234
|
+
# For example, if you provide a value of 50, will commit
|
235
|
+
# after every 50 records.
|
236
|
+
# :server :: Set the server/shard to use for the transaction and insert
|
237
|
+
# queries.
|
238
|
+
# :slice :: Same as :commit_every, :commit_every takes precedence.
|
238
239
|
def import(columns, values, opts={})
|
239
240
|
return @db.transaction{insert(columns, values)} if values.is_a?(Dataset)
|
240
241
|
|
241
242
|
return if values.empty?
|
242
243
|
raise(Error, IMPORT_ERROR_MSG) if columns.empty?
|
244
|
+
ds = opts[:server] ? server(opts[:server]) : self
|
243
245
|
|
244
246
|
if slice_size = opts[:commit_every] || opts[:slice]
|
245
247
|
offset = 0
|
246
|
-
|
247
|
-
|
248
|
+
rows = []
|
249
|
+
while offset < values.length
|
250
|
+
rows << ds._import(columns, values[offset, slice_size], opts)
|
248
251
|
offset += slice_size
|
249
|
-
break if offset >= values.length
|
250
252
|
end
|
253
|
+
rows.flatten
|
251
254
|
else
|
252
|
-
|
253
|
-
@db.transaction{statements.each{|st| execute_dui(st)}}
|
255
|
+
ds._import(columns, values, opts)
|
254
256
|
end
|
255
257
|
end
|
256
|
-
|
258
|
+
|
257
259
|
# Inserts values into the associated table. The returned value is generally
|
258
260
|
# the value of the primary key for the inserted row, but that is adapter dependent.
|
259
261
|
#
|
@@ -300,21 +302,24 @@ module Sequel
|
|
300
302
|
|
301
303
|
# Inserts multiple values. If a block is given it is invoked for each
|
302
304
|
# item in the given array before inserting it. See +multi_insert+ as
|
303
|
-
# a
|
304
|
-
# SQL statement.
|
305
|
+
# a possibly faster version that may be able to insert multiple
|
306
|
+
# records in one SQL statement (if supported by the database).
|
307
|
+
# Returns an array of primary keys of inserted rows.
|
305
308
|
#
|
306
309
|
# DB[:table].insert_multiple([{:x=>1}, {:x=>2}])
|
310
|
+
# # => [4, 5]
|
307
311
|
# # INSERT INTO table (x) VALUES (1)
|
308
312
|
# # INSERT INTO table (x) VALUES (2)
|
309
313
|
#
|
310
314
|
# DB[:table].insert_multiple([{:x=>1}, {:x=>2}]){|row| row[:y] = row[:x] * 2}
|
315
|
+
# # => [6, 7]
|
311
316
|
# # INSERT INTO table (x, y) VALUES (1, 2)
|
312
317
|
# # INSERT INTO table (x, y) VALUES (2, 4)
|
313
318
|
def insert_multiple(array, &block)
|
314
319
|
if block
|
315
|
-
array.
|
320
|
+
array.map{|i| insert(block.call(i))}
|
316
321
|
else
|
317
|
-
array.
|
322
|
+
array.map{|i| insert(i)}
|
318
323
|
end
|
319
324
|
end
|
320
325
|
|
@@ -397,7 +402,7 @@ module Sequel
|
|
397
402
|
# otherwise some columns could be missed or set to null instead of to default
|
398
403
|
# values.
|
399
404
|
#
|
400
|
-
#
|
405
|
+
# This respects the same options as #import.
|
401
406
|
def multi_insert(hashes, opts={})
|
402
407
|
return if hashes.empty?
|
403
408
|
columns = hashes.first.keys
|
@@ -603,6 +608,19 @@ module Sequel
|
|
603
608
|
|
604
609
|
protected
|
605
610
|
|
611
|
+
# Internals of #import. If primary key values are requested, use
|
612
|
+
# separate insert commands for each row. Otherwise, call #multi_insert_sql
|
613
|
+
# and execute each statement it gives separately.
|
614
|
+
def _import(columns, values, opts)
|
615
|
+
trans_opts = opts.merge(:server=>@opts[:server])
|
616
|
+
if opts[:return] == :primary_key
|
617
|
+
@db.transaction(trans_opts){values.map{|v| insert(columns, v)}}
|
618
|
+
else
|
619
|
+
stmts = multi_insert_sql(columns, values)
|
620
|
+
@db.transaction(trans_opts){stmts.each{|st| execute_dui(st)}}
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
606
624
|
# Return an array of arrays of values given by the symbols in ret_cols.
|
607
625
|
def _select_map_multiple(ret_cols)
|
608
626
|
map{|r| r.values_at(*ret_cols)}
|
@@ -61,6 +61,16 @@ module Sequel
|
|
61
61
|
false
|
62
62
|
end
|
63
63
|
|
64
|
+
# Whether the dataset supports CUBE with GROUP BY.
|
65
|
+
def supports_group_cube?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
# Whether the dataset supports ROLLUP with GROUP BY.
|
70
|
+
def supports_group_rollup?
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
64
74
|
# Whether this dataset supports the +insert_select+ method for returning all columns values
|
65
75
|
# directly from an insert query.
|
66
76
|
def supports_insert_select?
|
@@ -12,9 +12,6 @@ module Sequel
|
|
12
12
|
# native database support for bind variables and prepared
|
13
13
|
# statements (as opposed to the emulated ones used by default).
|
14
14
|
module ArgumentMapper
|
15
|
-
SQL_QUERY_TYPE = Hash.new{|h,k| h[k] = k}
|
16
|
-
SQL_QUERY_TYPE[:first] = SQL_QUERY_TYPE[:all] = :select
|
17
|
-
|
18
15
|
# The name of the prepared statement, if any.
|
19
16
|
attr_accessor :prepared_statement_name
|
20
17
|
|
@@ -38,13 +35,6 @@ module Sequel
|
|
38
35
|
@opts[:sql] = @prepared_sql
|
39
36
|
@prepared_sql
|
40
37
|
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
# The type of query (:select, :insert, :delete, :update).
|
45
|
-
def sql_query_type
|
46
|
-
SQL_QUERY_TYPE[@prepared_type]
|
47
|
-
end
|
48
38
|
end
|
49
39
|
|
50
40
|
# Backbone of the prepared statement support. Grafts bind variable
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -218,7 +218,7 @@ module Sequel
|
|
218
218
|
when Symbol
|
219
219
|
sch, table, aliaz = split_symbol(s)
|
220
220
|
if aliaz
|
221
|
-
s = sch ? SQL::QualifiedIdentifier.new(sch
|
221
|
+
s = sch ? SQL::QualifiedIdentifier.new(sch, table) : SQL::Identifier.new(table)
|
222
222
|
sources << SQL::AliasedExpression.new(s, aliaz.to_sym)
|
223
223
|
else
|
224
224
|
sources << s
|
@@ -337,6 +337,18 @@ module Sequel
|
|
337
337
|
select_group(*columns, &block).select_more(COUNT_OF_ALL_AS_COUNT)
|
338
338
|
end
|
339
339
|
|
340
|
+
# Adds the appropriate CUBE syntax to GROUP BY.
|
341
|
+
def group_cube
|
342
|
+
raise Error, "GROUP BY CUBE not supported on #{db.database_type}" unless supports_group_cube?
|
343
|
+
clone(:group_options=>:cube)
|
344
|
+
end
|
345
|
+
|
346
|
+
# Adds the appropriate ROLLUP syntax to GROUP BY.
|
347
|
+
def group_rollup
|
348
|
+
raise Error, "GROUP BY ROLLUP not supported on #{db.database_type}" unless supports_group_rollup?
|
349
|
+
clone(:group_options=>:rollup)
|
350
|
+
end
|
351
|
+
|
340
352
|
# Returns a copy of the dataset with the HAVING conditions changed. See #filter for argument types.
|
341
353
|
#
|
342
354
|
# DB[:items].group(:sum).having(:sum=>10)
|