sequel 3.33.0 → 3.34.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 +140 -0
- data/Rakefile +7 -0
- data/bin/sequel +22 -2
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/mass_assignment.rdoc +3 -1
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +23 -3
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/schema_modification.rdoc +18 -2
- data/doc/virtual_rows.rdoc +49 -0
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/ibmdb.rb +9 -4
- data/lib/sequel/adapters/jdbc.rb +9 -4
- data/lib/sequel/adapters/jdbc/h2.rb +8 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
- data/lib/sequel/adapters/mock.rb +24 -3
- data/lib/sequel/adapters/mysql.rb +29 -50
- data/lib/sequel/adapters/mysql2.rb +13 -28
- data/lib/sequel/adapters/oracle.rb +8 -2
- data/lib/sequel/adapters/postgres.rb +115 -20
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +14 -3
- data/lib/sequel/adapters/shared/mysql.rb +59 -11
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +127 -30
- data/lib/sequel/adapters/shared/sqlite.rb +55 -38
- data/lib/sequel/adapters/sqlite.rb +9 -3
- data/lib/sequel/adapters/swift.rb +2 -2
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +10 -0
- data/lib/sequel/ast_transformer.rb +4 -0
- data/lib/sequel/connection_pool.rb +8 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +14 -0
- data/lib/sequel/core.rb +24 -3
- data/lib/sequel/database/connecting.rb +24 -14
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +16 -25
- data/lib/sequel/database/query.rb +20 -2
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +120 -23
- data/lib/sequel/dataset/actions.rb +91 -18
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -2
- data/lib/sequel/dataset/sql.rb +68 -51
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +227 -31
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +11 -2
- data/lib/sequel/model/associations.rb +35 -7
- data/lib/sequel/model/base.rb +159 -36
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +11 -3
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +4 -3
- data/lib/sequel/plugins/prepared_statements.rb +3 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +417 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +12 -15
- data/spec/adapters/mysql_spec.rb +81 -23
- data/spec/adapters/postgres_spec.rb +444 -77
- data/spec/adapters/spec_helper.rb +2 -0
- data/spec/adapters/sqlite_spec.rb +8 -8
- data/spec/core/connection_pool_spec.rb +85 -0
- data/spec/core/database_spec.rb +29 -5
- data/spec/core/dataset_spec.rb +171 -3
- data/spec/core/expression_filters_spec.rb +364 -0
- data/spec/core/mock_adapter_spec.rb +17 -3
- data/spec/core/schema_spec.rb +133 -0
- data/spec/extensions/association_dependencies_spec.rb +13 -13
- data/spec/extensions/caching_spec.rb +26 -3
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +5 -2
- data/spec/extensions/identity_map_spec.rb +17 -0
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/lazy_attributes_spec.rb +2 -2
- data/spec/extensions/list_spec.rb +4 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +6 -2
- data/spec/extensions/nested_attributes_spec.rb +20 -0
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +2 -2
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_spec.rb +4 -0
- data/spec/extensions/pretty_table_spec.rb +6 -0
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +231 -11
- data/spec/extensions/schema_spec.rb +14 -2
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/sharding_spec.rb +6 -6
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +2 -1
- data/spec/extensions/sql_expr_spec.rb +28 -19
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +9 -1
- data/spec/integration/associations_test.rb +6 -6
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +89 -26
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +85 -22
- data/spec/integration/prepared_statement_test.rb +28 -8
- data/spec/integration/schema_test.rb +78 -7
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +4 -6
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +94 -8
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/hooks_spec.rb +2 -2
- data/spec/model/model_spec.rb +19 -7
- data/spec/model/record_spec.rb +135 -58
- data/spec/model/spec_helper.rb +1 -0
- metadata +35 -7
|
@@ -11,8 +11,8 @@ module Sequel
|
|
|
11
11
|
ACTION_METHODS = (<<-METHS).split.map{|x| x.to_sym}
|
|
12
12
|
<< [] []= all avg count columns columns! delete each
|
|
13
13
|
empty? fetch_rows first get import insert insert_multiple interval last
|
|
14
|
-
map max min multi_insert range select_hash select_map select_order_map
|
|
15
|
-
set single_record single_value sum to_csv to_hash truncate update
|
|
14
|
+
map max min multi_insert range select_hash select_hash_groups select_map select_order_map
|
|
15
|
+
set single_record single_value sum to_csv to_hash to_hash_groups truncate update
|
|
16
16
|
METHS
|
|
17
17
|
|
|
18
18
|
# Inserts the given argument into the database. Returns self so it
|
|
@@ -124,13 +124,13 @@ module Sequel
|
|
|
124
124
|
# running additional queries inside the provided block. If you are
|
|
125
125
|
# running queries inside the block, you should use +all+ instead of +each+
|
|
126
126
|
# for the outer queries, or use a separate thread or shard inside +each+:
|
|
127
|
-
def each
|
|
127
|
+
def each
|
|
128
128
|
if @opts[:graph]
|
|
129
|
-
graph_each
|
|
129
|
+
graph_each{|r| yield r}
|
|
130
130
|
elsif row_proc = @row_proc
|
|
131
131
|
fetch_rows(select_sql){|r| yield row_proc.call(r)}
|
|
132
132
|
else
|
|
133
|
-
fetch_rows(select_sql
|
|
133
|
+
fetch_rows(select_sql){|r| yield r}
|
|
134
134
|
end
|
|
135
135
|
self
|
|
136
136
|
end
|
|
@@ -421,7 +421,7 @@ module Sequel
|
|
|
421
421
|
end
|
|
422
422
|
|
|
423
423
|
# Returns a hash with key_column values as keys and value_column values as
|
|
424
|
-
# values. Similar to to_hash, but only selects the
|
|
424
|
+
# values. Similar to to_hash, but only selects the columns given.
|
|
425
425
|
#
|
|
426
426
|
# DB[:table].select_hash(:id, :name) # SELECT id, name FROM table
|
|
427
427
|
# # => {1=>'a', 2=>'b', ...}
|
|
@@ -436,19 +436,28 @@ module Sequel
|
|
|
436
436
|
# that Sequel can determine. Usually you can do this by calling the #as method
|
|
437
437
|
# on the expression and providing an alias.
|
|
438
438
|
def select_hash(key_column, value_column)
|
|
439
|
-
|
|
440
|
-
if value_column.is_a?(Array)
|
|
441
|
-
select(*(key_column + value_column)).to_hash(key_column.map{|c| hash_key_symbol(c)}, value_column.map{|c| hash_key_symbol(c)})
|
|
442
|
-
else
|
|
443
|
-
select(*(key_column + [value_column])).to_hash(key_column.map{|c| hash_key_symbol(c)}, hash_key_symbol(value_column))
|
|
444
|
-
end
|
|
445
|
-
elsif value_column.is_a?(Array)
|
|
446
|
-
select(key_column, *value_column).to_hash(hash_key_symbol(key_column), value_column.map{|c| hash_key_symbol(c)})
|
|
447
|
-
else
|
|
448
|
-
select(key_column, value_column).to_hash(hash_key_symbol(key_column), hash_key_symbol(value_column))
|
|
449
|
-
end
|
|
439
|
+
_select_hash(:to_hash, key_column, value_column)
|
|
450
440
|
end
|
|
451
441
|
|
|
442
|
+
# Returns a hash with key_column values as keys and an array of value_column values.
|
|
443
|
+
# Similar to to_hash_groups, but only selects the columns given.
|
|
444
|
+
#
|
|
445
|
+
# DB[:table].select_hash(:name, :id) # SELECT id, name FROM table
|
|
446
|
+
# # => {'a'=>[1, 4, ...], 'b'=>[2, ...], ...}
|
|
447
|
+
#
|
|
448
|
+
# You can also provide an array of column names for either the key_column,
|
|
449
|
+
# the value column, or both:
|
|
450
|
+
#
|
|
451
|
+
# DB[:table].select_hash([:first, :middle], [:last, :id]) # SELECT * FROM table
|
|
452
|
+
# # {['a', 'b']=>[['c', 1], ['d', 2], ...], ...}
|
|
453
|
+
#
|
|
454
|
+
# When using this method, you must be sure that each expression has an alias
|
|
455
|
+
# that Sequel can determine. Usually you can do this by calling the #as method
|
|
456
|
+
# on the expression and providing an alias.
|
|
457
|
+
def select_hash_groups(key_column, value_column)
|
|
458
|
+
_select_hash(:to_hash_groups, key_column, value_column)
|
|
459
|
+
end
|
|
460
|
+
|
|
452
461
|
# Selects the column given (either as an argument or as a block), and
|
|
453
462
|
# returns an array of all values of that column in the dataset. If you
|
|
454
463
|
# give a block argument that returns an array with multiple entries,
|
|
@@ -472,7 +481,6 @@ module Sequel
|
|
|
472
481
|
def select_map(column=nil, &block)
|
|
473
482
|
_select_map(column, false, &block)
|
|
474
483
|
end
|
|
475
|
-
|
|
476
484
|
|
|
477
485
|
# The same as select_map, but in addition orders the array by the column.
|
|
478
486
|
#
|
|
@@ -591,6 +599,49 @@ module Sequel
|
|
|
591
599
|
h
|
|
592
600
|
end
|
|
593
601
|
|
|
602
|
+
# Returns a hash with one column used as key and the values being an
|
|
603
|
+
# array of column values. If the value_column is not given or nil, uses
|
|
604
|
+
# the entire hash as the value.
|
|
605
|
+
#
|
|
606
|
+
# DB[:table].to_hash(:name, :id) # SELECT * FROM table
|
|
607
|
+
# # {'Jim'=>[1, 4, 16, ...], 'Bob'=>[2], ...}
|
|
608
|
+
#
|
|
609
|
+
# DB[:table].to_hash(:name) # SELECT * FROM table
|
|
610
|
+
# # {'Jim'=>[{:id=>1, :name=>'Jim'}, {:id=>4, :name=>'Jim'}, ...], 'Bob'=>[{:id=>2, :name=>'Bob'}], ...}
|
|
611
|
+
#
|
|
612
|
+
# You can also provide an array of column names for either the key_column,
|
|
613
|
+
# the value column, or both:
|
|
614
|
+
#
|
|
615
|
+
# DB[:table].to_hash([:first, :middle], [:last, :id]) # SELECT * FROM table
|
|
616
|
+
# # {['Jim', 'Bob']=>[['Smith', 1], ['Jackson', 4], ...], ...}
|
|
617
|
+
#
|
|
618
|
+
# DB[:table].to_hash([:first, :middle]) # SELECT * FROM table
|
|
619
|
+
# # {['Jim', 'Bob']=>[{:id=>1, :first=>'Jim', :middle=>'Bob', :last=>'Smith'}, ...], ...}
|
|
620
|
+
def to_hash_groups(key_column, value_column = nil)
|
|
621
|
+
h = {}
|
|
622
|
+
if value_column
|
|
623
|
+
return naked.to_hash_groups(key_column, value_column) if row_proc
|
|
624
|
+
if value_column.is_a?(Array)
|
|
625
|
+
if key_column.is_a?(Array)
|
|
626
|
+
each{|r| (h[r.values_at(*key_column)] ||= []) << r.values_at(*value_column)}
|
|
627
|
+
else
|
|
628
|
+
each{|r| (h[r[key_column]] ||= []) << r.values_at(*value_column)}
|
|
629
|
+
end
|
|
630
|
+
else
|
|
631
|
+
if key_column.is_a?(Array)
|
|
632
|
+
each{|r| (h[r.values_at(*key_column)] ||= []) << r[value_column]}
|
|
633
|
+
else
|
|
634
|
+
each{|r| (h[r[key_column]] ||= []) << r[value_column]}
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
elsif key_column.is_a?(Array)
|
|
638
|
+
each{|r| (h[r.values_at(*key_column)] ||= []) << r}
|
|
639
|
+
else
|
|
640
|
+
each{|r| (h[r[key_column]] ||= []) << r}
|
|
641
|
+
end
|
|
642
|
+
h
|
|
643
|
+
end
|
|
644
|
+
|
|
594
645
|
# Truncates the dataset. Returns nil.
|
|
595
646
|
#
|
|
596
647
|
# DB[:table].truncate # TRUNCATE table
|
|
@@ -618,6 +669,13 @@ module Sequel
|
|
|
618
669
|
end
|
|
619
670
|
end
|
|
620
671
|
|
|
672
|
+
# Execute the given SQL and return the number of rows deleted. This exists
|
|
673
|
+
# solely as an optimization, replacing with_sql(sql).delete. It's significantly
|
|
674
|
+
# faster as it does not require cloning the current dataset.
|
|
675
|
+
def with_sql_delete(sql)
|
|
676
|
+
execute_dui(sql)
|
|
677
|
+
end
|
|
678
|
+
|
|
621
679
|
protected
|
|
622
680
|
|
|
623
681
|
# Internals of #import. If primary key values are requested, use
|
|
@@ -645,6 +703,21 @@ module Sequel
|
|
|
645
703
|
|
|
646
704
|
private
|
|
647
705
|
|
|
706
|
+
# Internals of +select_hash+ and +select_hash_groups+
|
|
707
|
+
def _select_hash(meth, key_column, value_column)
|
|
708
|
+
if key_column.is_a?(Array)
|
|
709
|
+
if value_column.is_a?(Array)
|
|
710
|
+
select(*(key_column + value_column)).send(meth, key_column.map{|c| hash_key_symbol(c)}, value_column.map{|c| hash_key_symbol(c)})
|
|
711
|
+
else
|
|
712
|
+
select(*(key_column + [value_column])).send(meth, key_column.map{|c| hash_key_symbol(c)}, hash_key_symbol(value_column))
|
|
713
|
+
end
|
|
714
|
+
elsif value_column.is_a?(Array)
|
|
715
|
+
select(key_column, *value_column).send(meth, hash_key_symbol(key_column), value_column.map{|c| hash_key_symbol(c)})
|
|
716
|
+
else
|
|
717
|
+
select(key_column, value_column).send(meth, hash_key_symbol(key_column), hash_key_symbol(value_column))
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
|
|
648
721
|
# Internals of +select_map+ and +select_order_map+
|
|
649
722
|
def _select_map(column, order, &block)
|
|
650
723
|
ds = naked.ungraphed
|
|
@@ -165,5 +165,10 @@ module Sequel
|
|
|
165
165
|
def uses_returning?(type)
|
|
166
166
|
opts[:returning] && !@opts[:sql] && supports_returning?(type)
|
|
167
167
|
end
|
|
168
|
+
|
|
169
|
+
# Whether the dataset uses WITH ROLLUP/CUBE instead of ROLLUP()/CUBE().
|
|
170
|
+
def uses_with_rollup?
|
|
171
|
+
false
|
|
172
|
+
end
|
|
168
173
|
end
|
|
169
174
|
end
|
|
@@ -17,7 +17,7 @@ module Sequel
|
|
|
17
17
|
|
|
18
18
|
# The bind arguments to use for running this prepared statement
|
|
19
19
|
attr_accessor :bind_arguments
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
# Set the bind arguments based on the hash and call super.
|
|
22
22
|
def call(bind_vars={}, &block)
|
|
23
23
|
ds = bind(bind_vars)
|
|
@@ -46,6 +46,10 @@ module Sequel
|
|
|
46
46
|
module PreparedStatementMethods
|
|
47
47
|
PLACEHOLDER_RE = /\A\$(.*)\z/
|
|
48
48
|
|
|
49
|
+
# Whether to log the full SQL query. By default, just the prepared statement
|
|
50
|
+
# name is generally logged on adapters that support native prepared statements.
|
|
51
|
+
attr_accessor :log_sql
|
|
52
|
+
|
|
49
53
|
# The type of prepared statement, should be one of :select, :first,
|
|
50
54
|
# :insert, :update, or :delete
|
|
51
55
|
attr_accessor :prepared_type
|
|
@@ -139,7 +143,7 @@ module Sequel
|
|
|
139
143
|
delete
|
|
140
144
|
when Array
|
|
141
145
|
case @prepared_type.at(0)
|
|
142
|
-
when :map, :to_hash
|
|
146
|
+
when :map, :to_hash, :to_hash_groups
|
|
143
147
|
send(*@prepared_type, &block)
|
|
144
148
|
end
|
|
145
149
|
else
|
data/lib/sequel/dataset/sql.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Sequel
|
|
|
20
20
|
# DB.select(1).where(DB[:items].exists)
|
|
21
21
|
# # SELECT 1 WHERE (EXISTS (SELECT * FROM items))
|
|
22
22
|
def exists
|
|
23
|
-
SQL::PlaceholderLiteralString.new(
|
|
23
|
+
SQL::PlaceholderLiteralString.new(EXISTS, [self], true)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# Returns an INSERT SQL query string. See +insert+.
|
|
@@ -63,7 +63,7 @@ module Sequel
|
|
|
63
63
|
|
|
64
64
|
if values.is_a?(Array) && values.empty? && !insert_supports_empty_values?
|
|
65
65
|
columns = [columns().last]
|
|
66
|
-
values = [
|
|
66
|
+
values = [DEFAULT]
|
|
67
67
|
end
|
|
68
68
|
clone(:columns=>columns, :values=>values)._insert_sql
|
|
69
69
|
end
|
|
@@ -182,6 +182,7 @@ module Sequel
|
|
|
182
182
|
clauses.map{|clause| :"#{type}_#{clause}_sql"}.freeze
|
|
183
183
|
end
|
|
184
184
|
|
|
185
|
+
WILDCARD = LiteralString.new('*').freeze
|
|
185
186
|
ALL = ' ALL'.freeze
|
|
186
187
|
AND_SEPARATOR = " AND ".freeze
|
|
187
188
|
APOS = "'".freeze
|
|
@@ -200,7 +201,6 @@ module Sequel
|
|
|
200
201
|
CASE_THEN = " THEN ".freeze
|
|
201
202
|
CASE_WHEN = " WHEN ".freeze
|
|
202
203
|
CAST_OPEN = 'CAST('.freeze
|
|
203
|
-
COLUMN_ALL = '.*'.freeze
|
|
204
204
|
COLUMN_REF_RE1 = /\A((?:(?!__).)+)__((?:(?!___).)+)___(.+)\z/.freeze
|
|
205
205
|
COLUMN_REF_RE2 = /\A((?:(?!___).)+)___(.+)\z/.freeze
|
|
206
206
|
COLUMN_REF_RE3 = /\A((?:(?!__).)+)__(.+)\z/.freeze
|
|
@@ -209,8 +209,9 @@ module Sequel
|
|
|
209
209
|
CONDITION_FALSE = '(1 = 0)'.freeze
|
|
210
210
|
CONDITION_TRUE = '(1 = 1)'.freeze
|
|
211
211
|
COUNT_FROM_SELF_OPTS = [:distinct, :group, :sql, :limit, :compounds]
|
|
212
|
-
COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count,
|
|
212
|
+
COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, WILDCARD).as(:count)
|
|
213
213
|
DATASET_ALIAS_BASE_NAME = 't'.freeze
|
|
214
|
+
DEFAULT = LiteralString.new('DEFAULT').freeze
|
|
214
215
|
DEFAULT_VALUES = " DEFAULT VALUES".freeze
|
|
215
216
|
DELETE = 'DELETE'.freeze
|
|
216
217
|
DELETE_CLAUSE_METHODS = clause_methods(:delete, %w'delete from where')
|
|
@@ -221,6 +222,7 @@ module Sequel
|
|
|
221
222
|
DOUBLE_QUOTE = '""'.freeze
|
|
222
223
|
EQUAL = ' = '.freeze
|
|
223
224
|
EXTRACT = 'extract('.freeze
|
|
225
|
+
EXISTS = ['EXISTS '.freeze].freeze
|
|
224
226
|
FOR_UPDATE = ' FOR UPDATE'.freeze
|
|
225
227
|
FORMAT_DATE = "'%Y-%m-%d'".freeze
|
|
226
228
|
FORMAT_DATE_STANDARD = "DATE '%Y-%m-%d'".freeze
|
|
@@ -267,6 +269,7 @@ module Sequel
|
|
|
267
269
|
SET = ' SET '.freeze
|
|
268
270
|
SPACE = ' '.freeze
|
|
269
271
|
SQL_WITH = "WITH ".freeze
|
|
272
|
+
SPACE_WITH = " WITH ".freeze
|
|
270
273
|
TILDE = '~'.freeze
|
|
271
274
|
TIMESTAMP_FORMAT = "'%Y-%m-%d %H:%M:%S%N%z'".freeze
|
|
272
275
|
STANDARD_TIMESTAMP_FORMAT = "TIMESTAMP #{TIMESTAMP_FORMAT}".freeze
|
|
@@ -276,8 +279,9 @@ module Sequel
|
|
|
276
279
|
UPDATE_CLAUSE_METHODS = clause_methods(:update, %w'update table set where')
|
|
277
280
|
USING = ' USING ('.freeze
|
|
278
281
|
VALUES = " VALUES ".freeze
|
|
282
|
+
V187 = '1.8.7'.freeze
|
|
283
|
+
V190 = '1.9.0'.freeze
|
|
279
284
|
WHERE = " WHERE ".freeze
|
|
280
|
-
WILDCARD = LiteralString.new('*').freeze
|
|
281
285
|
|
|
282
286
|
PUBLIC_APPEND_METHODS = (<<-END).split.map{|x| x.to_sym}
|
|
283
287
|
literal
|
|
@@ -392,10 +396,10 @@ module Sequel
|
|
|
392
396
|
|
|
393
397
|
# SQL fragment for specifying all columns in a given table
|
|
394
398
|
def column_all_sql_append(sql, ca)
|
|
395
|
-
|
|
396
|
-
sql << COLUMN_ALL
|
|
399
|
+
qualified_identifier_sql_append(sql, ca.table, WILDCARD)
|
|
397
400
|
end
|
|
398
401
|
|
|
402
|
+
# SQL fragment for the complex expression.
|
|
399
403
|
def complex_expression_sql_append(sql, op, args)
|
|
400
404
|
case op
|
|
401
405
|
when *IS_OPERATORS
|
|
@@ -509,7 +513,7 @@ module Sequel
|
|
|
509
513
|
table_alias = jc.table_alias
|
|
510
514
|
table_alias = nil if table == table_alias
|
|
511
515
|
sql << SPACE << join_type_sql(jc.join_type) << SPACE
|
|
512
|
-
|
|
516
|
+
identifier_append(sql, table)
|
|
513
517
|
as_sql_append(sql, table_alias) if table_alias
|
|
514
518
|
end
|
|
515
519
|
|
|
@@ -550,11 +554,11 @@ module Sequel
|
|
|
550
554
|
# SQL fragment for a literal string with placeholders
|
|
551
555
|
def placeholder_literal_string_sql_append(sql, pls)
|
|
552
556
|
args = pls.args
|
|
557
|
+
str = pls.str
|
|
553
558
|
sql << PAREN_OPEN if pls.parens
|
|
554
559
|
if args.is_a?(Hash)
|
|
555
560
|
re = /:(#{args.keys.map{|k| Regexp.escape(k.to_s)}.join('|')})\b/
|
|
556
|
-
if RUBY_VERSION >=
|
|
557
|
-
str = pls.str
|
|
561
|
+
if RUBY_VERSION >= V187
|
|
558
562
|
loop do
|
|
559
563
|
previous, q, str = str.partition(re)
|
|
560
564
|
sql << previous
|
|
@@ -562,12 +566,17 @@ module Sequel
|
|
|
562
566
|
break if str.empty?
|
|
563
567
|
end
|
|
564
568
|
else
|
|
565
|
-
sql <<
|
|
569
|
+
sql << str.gsub(re){literal(args[$1.to_sym])}
|
|
570
|
+
end
|
|
571
|
+
elsif str.is_a?(Array)
|
|
572
|
+
len = args.length
|
|
573
|
+
str.each_with_index do |s, i|
|
|
574
|
+
sql << s
|
|
575
|
+
literal_append(sql, args[i]) unless i == len
|
|
566
576
|
end
|
|
567
577
|
else
|
|
568
578
|
i = -1
|
|
569
|
-
if RUBY_VERSION >=
|
|
570
|
-
str = pls.str
|
|
579
|
+
if RUBY_VERSION >= V187
|
|
571
580
|
loop do
|
|
572
581
|
previous, q, str = str.partition(QUESTION_MARK)
|
|
573
582
|
sql << previous
|
|
@@ -575,7 +584,7 @@ module Sequel
|
|
|
575
584
|
break if str.empty?
|
|
576
585
|
end
|
|
577
586
|
else
|
|
578
|
-
sql <<
|
|
587
|
+
sql << str.gsub(QUESTION_MARK_RE){literal(args.at(i+=1))}
|
|
579
588
|
end
|
|
580
589
|
end
|
|
581
590
|
sql << PAREN_CLOSE if pls.parens
|
|
@@ -583,20 +592,12 @@ module Sequel
|
|
|
583
592
|
|
|
584
593
|
# SQL fragment for the qualifed identifier, specifying
|
|
585
594
|
# a table and a column (or schema and table).
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
else
|
|
591
|
-
quote_identifier_append(sql, t)
|
|
592
|
-
end
|
|
595
|
+
# If 3 arguments are given, the 2nd should be the table/qualifier and the third should be
|
|
596
|
+
# column/qualified. If 2 arguments are given, the 2nd should be an SQL::QualifiedIdentifier.
|
|
597
|
+
def qualified_identifier_sql_append(sql, table, column=(c = table.column; table = table.table; c))
|
|
598
|
+
identifier_append(sql, table)
|
|
593
599
|
sql << DOT
|
|
594
|
-
|
|
595
|
-
when Symbol, SQL::QualifiedIdentifier, SQL::Identifier
|
|
596
|
-
literal_append(sql, c)
|
|
597
|
-
else
|
|
598
|
-
quote_identifier_append(sql, c)
|
|
599
|
-
end
|
|
600
|
+
identifier_append(sql, column)
|
|
600
601
|
end
|
|
601
602
|
|
|
602
603
|
# Adds quoting to identifiers (columns and tables). If identifiers are not
|
|
@@ -802,7 +803,7 @@ module Sequel
|
|
|
802
803
|
|
|
803
804
|
# Prepare an SQL statement by calling all clause methods for the given statement type.
|
|
804
805
|
def clause_sql(type)
|
|
805
|
-
sql = @opts[:append_sql] ||
|
|
806
|
+
sql = @opts[:append_sql] || sql_string_origin
|
|
806
807
|
send("#{type}_clause_methods").each{|x| send(x, sql)}
|
|
807
808
|
sql
|
|
808
809
|
end
|
|
@@ -869,7 +870,7 @@ module Sequel
|
|
|
869
870
|
c ||= true
|
|
870
871
|
end
|
|
871
872
|
end
|
|
872
|
-
|
|
873
|
+
|
|
873
874
|
def empty_array_value(op, cols)
|
|
874
875
|
if Sequel.empty_array_handle_nulls
|
|
875
876
|
c = Array(cols)
|
|
@@ -887,7 +888,7 @@ module Sequel
|
|
|
887
888
|
v2 = db.from_application_timestamp(v)
|
|
888
889
|
fmt = default_timestamp_format.gsub(FORMAT_TIMESTAMP_RE) do |m|
|
|
889
890
|
if m == FORMAT_USEC
|
|
890
|
-
format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION <
|
|
891
|
+
format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION < V190 ? 86400000000 : 1000000) : v.usec) if supports_timestamp_usecs?
|
|
891
892
|
else
|
|
892
893
|
if supports_timestamp_timezones?
|
|
893
894
|
# Would like to just use %z format, but it doesn't appear to work on Windows
|
|
@@ -911,6 +912,24 @@ module Sequel
|
|
|
911
912
|
sprintf(FORMAT_TIMESTAMP_USEC, usec)
|
|
912
913
|
end
|
|
913
914
|
|
|
915
|
+
# Append the value, but special case regular (non-literal, non-blob) strings
|
|
916
|
+
# so that they are considered as identifiers and not SQL strings.
|
|
917
|
+
def identifier_append(sql, v)
|
|
918
|
+
if v.is_a?(String)
|
|
919
|
+
case v
|
|
920
|
+
when LiteralString
|
|
921
|
+
sql << v
|
|
922
|
+
when SQL::Blob
|
|
923
|
+
literal_append(sql, v)
|
|
924
|
+
else
|
|
925
|
+
quote_identifier_append(sql, v)
|
|
926
|
+
end
|
|
927
|
+
else
|
|
928
|
+
literal_append(sql, v)
|
|
929
|
+
end
|
|
930
|
+
end
|
|
931
|
+
alias table_ref_append identifier_append
|
|
932
|
+
|
|
914
933
|
# Modify the identifier returned from the database based on the
|
|
915
934
|
# identifier_output_method.
|
|
916
935
|
def input_identifier(v)
|
|
@@ -937,11 +956,7 @@ module Sequel
|
|
|
937
956
|
co = COMMA
|
|
938
957
|
columns.each do |col|
|
|
939
958
|
sql << co if c
|
|
940
|
-
|
|
941
|
-
quote_identifier_append(sql, col)
|
|
942
|
-
else
|
|
943
|
-
literal_append(sql, col)
|
|
944
|
-
end
|
|
959
|
+
identifier_append(sql, col)
|
|
945
960
|
c ||= true
|
|
946
961
|
end
|
|
947
962
|
sql << PAREN_CLOSE
|
|
@@ -1058,7 +1073,7 @@ module Sequel
|
|
|
1058
1073
|
def literal_integer(v)
|
|
1059
1074
|
v.to_s
|
|
1060
1075
|
end
|
|
1061
|
-
|
|
1076
|
+
|
|
1062
1077
|
# SQL fragment for nil
|
|
1063
1078
|
def literal_nil
|
|
1064
1079
|
NULL
|
|
@@ -1194,11 +1209,17 @@ module Sequel
|
|
|
1194
1209
|
if group = @opts[:group]
|
|
1195
1210
|
sql << GROUP_BY
|
|
1196
1211
|
if go = @opts[:group_options]
|
|
1197
|
-
|
|
1198
|
-
|
|
1212
|
+
if uses_with_rollup?
|
|
1213
|
+
expression_list_append(sql, group)
|
|
1214
|
+
sql << SPACE_WITH << go.to_s.upcase
|
|
1215
|
+
else
|
|
1216
|
+
sql << go.to_s.upcase << PAREN_OPEN
|
|
1217
|
+
expression_list_append(sql, group)
|
|
1218
|
+
sql << PAREN_CLOSE
|
|
1219
|
+
end
|
|
1220
|
+
else
|
|
1221
|
+
expression_list_append(sql, group)
|
|
1199
1222
|
end
|
|
1200
|
-
expression_list_append(sql, group)
|
|
1201
|
-
sql << PAREN_CLOSE if go
|
|
1202
1223
|
end
|
|
1203
1224
|
end
|
|
1204
1225
|
|
|
@@ -1300,7 +1321,7 @@ module Sequel
|
|
|
1300
1321
|
co = COMMA
|
|
1301
1322
|
sources.each do |s|
|
|
1302
1323
|
sql << co if c
|
|
1303
|
-
|
|
1324
|
+
identifier_append(sql, s)
|
|
1304
1325
|
c ||= true
|
|
1305
1326
|
end
|
|
1306
1327
|
end
|
|
@@ -1323,6 +1344,12 @@ module Sequel
|
|
|
1323
1344
|
end
|
|
1324
1345
|
end
|
|
1325
1346
|
|
|
1347
|
+
# The string that is appended to to create the SQL query, the empty
|
|
1348
|
+
# string by default
|
|
1349
|
+
def sql_string_origin
|
|
1350
|
+
''
|
|
1351
|
+
end
|
|
1352
|
+
|
|
1326
1353
|
# SQL to use if this dataset uses static SQL. Since static SQL
|
|
1327
1354
|
# can be a PlaceholderLiteralString in addition to a String,
|
|
1328
1355
|
# we literalize nonstrings.
|
|
@@ -1347,16 +1374,6 @@ module Sequel
|
|
|
1347
1374
|
ds.clone(:append_sql=>sql).sql
|
|
1348
1375
|
end
|
|
1349
1376
|
|
|
1350
|
-
# SQL fragment specifying a table name.
|
|
1351
|
-
def table_ref_append(sql, t)
|
|
1352
|
-
if t.is_a?(String)
|
|
1353
|
-
quote_identifier_append(sql, t)
|
|
1354
|
-
else
|
|
1355
|
-
literal_append(sql, t)
|
|
1356
|
-
end
|
|
1357
|
-
end
|
|
1358
|
-
alias identifier_append table_ref_append
|
|
1359
|
-
|
|
1360
1377
|
# The order of methods to call to build the UPDATE SQL statement
|
|
1361
1378
|
def update_clause_methods
|
|
1362
1379
|
UPDATE_CLAUSE_METHODS
|