sequel 3.30.0 → 3.31.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|