sequel 3.28.0 → 3.29.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 +119 -3
- data/Rakefile +5 -3
- data/bin/sequel +1 -5
- data/doc/model_hooks.rdoc +9 -1
- data/doc/opening_databases.rdoc +49 -40
- data/doc/prepared_statements.rdoc +27 -6
- data/doc/release_notes/3.28.0.txt +2 -2
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +18 -9
- data/doc/transactions.rdoc +41 -1
- data/lib/sequel/adapters/ado.rb +28 -17
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/amalgalite.rb +11 -7
- data/lib/sequel/adapters/db2.rb +122 -70
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do.rb +5 -36
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/firebird.rb +3 -6
- data/lib/sequel/adapters/ibmdb.rb +24 -16
- data/lib/sequel/adapters/informix.rb +2 -4
- data/lib/sequel/adapters/jdbc.rb +47 -11
- data/lib/sequel/adapters/jdbc/as400.rb +5 -24
- data/lib/sequel/adapters/jdbc/db2.rb +0 -5
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
- data/lib/sequel/adapters/jdbc/h2.rb +10 -12
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +0 -5
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
- data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +64 -51
- data/lib/sequel/adapters/mysql2.rb +15 -9
- data/lib/sequel/adapters/odbc.rb +13 -6
- data/lib/sequel/adapters/odbc/db2.rb +0 -4
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +333 -51
- data/lib/sequel/adapters/postgres.rb +80 -27
- data/lib/sequel/adapters/shared/access.rb +0 -6
- data/lib/sequel/adapters/shared/db2.rb +13 -15
- data/lib/sequel/adapters/shared/firebird.rb +6 -6
- data/lib/sequel/adapters/shared/mssql.rb +23 -18
- data/lib/sequel/adapters/shared/mysql.rb +6 -6
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -30
- data/lib/sequel/adapters/shared/postgres.rb +35 -18
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +116 -37
- data/lib/sequel/adapters/sqlite.rb +16 -8
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/tinytds.rb +13 -10
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
- data/lib/sequel/core.rb +40 -0
- data/lib/sequel/database/connecting.rb +1 -2
- data/lib/sequel/database/dataset.rb +3 -3
- data/lib/sequel/database/dataset_defaults.rb +58 -0
- data/lib/sequel/database/misc.rb +62 -2
- data/lib/sequel/database/query.rb +113 -49
- data/lib/sequel/database/schema_methods.rb +7 -2
- data/lib/sequel/dataset/actions.rb +37 -19
- data/lib/sequel/dataset/features.rb +24 -0
- data/lib/sequel/dataset/graph.rb +7 -6
- data/lib/sequel/dataset/misc.rb +11 -3
- data/lib/sequel/dataset/mutation.rb +2 -3
- data/lib/sequel/dataset/prepared_statements.rb +6 -4
- data/lib/sequel/dataset/query.rb +46 -15
- data/lib/sequel/dataset/sql.rb +28 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/model.rb +2 -1
- data/lib/sequel/model/associations.rb +115 -33
- data/lib/sequel/model/base.rb +91 -31
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +6 -10
- data/lib/sequel/plugins/prepared_statements.rb +12 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/sharding.rb +0 -5
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/timezones.rb +42 -42
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +29 -29
- data/spec/adapters/mysql_spec.rb +86 -104
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +98 -33
- data/spec/adapters/spec_helper.rb +0 -5
- data/spec/adapters/sqlite_spec.rb +24 -21
- data/spec/core/connection_pool_spec.rb +9 -15
- data/spec/core/core_sql_spec.rb +20 -31
- data/spec/core/database_spec.rb +491 -227
- data/spec/core/dataset_spec.rb +638 -1051
- data/spec/core/expression_filters_spec.rb +0 -1
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +51 -114
- data/spec/core/spec_helper.rb +3 -90
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +3 -0
- data/spec/extensions/schema_spec.rb +1 -1
- data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/spec_helper.rb +4 -0
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/integration/associations_test.rb +123 -12
- data/spec/integration/dataset_test.rb +140 -47
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +179 -128
- data/spec/integration/prepared_statement_test.rb +92 -91
- data/spec/integration/schema_test.rb +42 -23
- data/spec/integration/spec_helper.rb +25 -31
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +161 -34
- data/spec/integration/type_test.rb +3 -3
- data/spec/model/association_reflection_spec.rb +83 -7
- data/spec/model/associations_spec.rb +393 -676
- data/spec/model/base_spec.rb +186 -116
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +343 -867
- data/spec/model/hooks_spec.rb +160 -79
- data/spec/model/model_spec.rb +118 -165
- data/spec/model/plugins_spec.rb +7 -13
- data/spec/model/record_spec.rb +138 -207
- data/spec/model/spec_helper.rb +10 -73
- metadata +14 -8
|
@@ -71,11 +71,11 @@ module Sequel
|
|
|
71
71
|
# See <tt>Schema::AlterTableGenerator</tt> and the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
|
|
72
72
|
def alter_table(name, generator=nil, &block)
|
|
73
73
|
generator ||= Schema::AlterTableGenerator.new(self, &block)
|
|
74
|
-
alter_table_sql_list(name, generator.operations).flatten.each {|sql| execute_ddl(sql)}
|
|
75
74
|
remove_cached_schema(name)
|
|
75
|
+
apply_alter_table(name, generator.operations)
|
|
76
76
|
nil
|
|
77
77
|
end
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
# Creates a table with the columns given in the provided block:
|
|
80
80
|
#
|
|
81
81
|
# DB.create_table :posts do
|
|
@@ -231,6 +231,11 @@ module Sequel
|
|
|
231
231
|
|
|
232
232
|
private
|
|
233
233
|
|
|
234
|
+
# Apply the changes in the given alter table ops to the table given by name.
|
|
235
|
+
def apply_alter_table(name, ops)
|
|
236
|
+
alter_table_sql_list(name, ops).flatten.each{|sql| execute_ddl(sql)}
|
|
237
|
+
end
|
|
238
|
+
|
|
234
239
|
# The SQL to execute to modify the DDL for the given table name. op
|
|
235
240
|
# should be one of the operations returned by the AlterTableGenerator.
|
|
236
241
|
def alter_table_sql(table, op)
|
|
@@ -8,15 +8,20 @@ module Sequel
|
|
|
8
8
|
# ---------------------
|
|
9
9
|
|
|
10
10
|
# Action methods defined by Sequel that execute code on the database.
|
|
11
|
-
ACTION_METHODS =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
ACTION_METHODS = (<<-METHS).split.map{|x| x.to_sym}
|
|
12
|
+
<< [] []= all avg count columns columns! delete each
|
|
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
|
|
16
|
+
METHS
|
|
15
17
|
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# Inserts the given argument into the database. Returns self so it
|
|
19
|
+
# can be used safely when chaining:
|
|
20
|
+
#
|
|
21
|
+
# DB[:items] << {:id=>0, :name=>'Zero'} << DB[:old_items].select(:id, name)
|
|
22
|
+
def <<(arg)
|
|
23
|
+
insert(arg)
|
|
24
|
+
self
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
# Returns the first record matching the conditions. Examples:
|
|
@@ -72,7 +77,7 @@ module Sequel
|
|
|
72
77
|
# # => [:id, :name]
|
|
73
78
|
def columns
|
|
74
79
|
return @columns if @columns
|
|
75
|
-
ds = unfiltered.unordered.clone(:distinct => nil, :limit => 1)
|
|
80
|
+
ds = unfiltered.unordered.clone(:distinct => nil, :limit => 1, :offset=>nil)
|
|
76
81
|
ds.each{break}
|
|
77
82
|
@columns = ds.instance_variable_get(:@columns)
|
|
78
83
|
@columns || []
|
|
@@ -354,8 +359,9 @@ module Sequel
|
|
|
354
359
|
def map(column=nil, &block)
|
|
355
360
|
if column
|
|
356
361
|
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
|
362
|
+
return naked.map(column) if row_proc
|
|
357
363
|
if column.is_a?(Array)
|
|
358
|
-
super(){|r| column
|
|
364
|
+
super(){|r| r.values_at(*column)}
|
|
359
365
|
else
|
|
360
366
|
super(){|r| r[column]}
|
|
361
367
|
end
|
|
@@ -546,21 +552,22 @@ module Sequel
|
|
|
546
552
|
def to_hash(key_column, value_column = nil)
|
|
547
553
|
h = {}
|
|
548
554
|
if value_column
|
|
555
|
+
return naked.to_hash(key_column, value_column) if row_proc
|
|
549
556
|
if value_column.is_a?(Array)
|
|
550
557
|
if key_column.is_a?(Array)
|
|
551
|
-
each{|r| h[key_column
|
|
558
|
+
each{|r| h[r.values_at(*key_column)] = r.values_at(*value_column)}
|
|
552
559
|
else
|
|
553
|
-
each{|r| h[r[key_column]] = value_column
|
|
560
|
+
each{|r| h[r[key_column]] = r.values_at(*value_column)}
|
|
554
561
|
end
|
|
555
562
|
else
|
|
556
563
|
if key_column.is_a?(Array)
|
|
557
|
-
each{|r| h[key_column
|
|
564
|
+
each{|r| h[r.values_at(*key_column)] = r[value_column]}
|
|
558
565
|
else
|
|
559
566
|
each{|r| h[r[key_column]] = r[value_column]}
|
|
560
567
|
end
|
|
561
568
|
end
|
|
562
569
|
elsif key_column.is_a?(Array)
|
|
563
|
-
each{|r| h[key_column
|
|
570
|
+
each{|r| h[r.values_at(*key_column)] = r}
|
|
564
571
|
else
|
|
565
572
|
each{|r| h[r[key_column]] = r}
|
|
566
573
|
end
|
|
@@ -594,6 +601,18 @@ module Sequel
|
|
|
594
601
|
end
|
|
595
602
|
end
|
|
596
603
|
|
|
604
|
+
protected
|
|
605
|
+
|
|
606
|
+
# Return an array of arrays of values given by the symbols in ret_cols.
|
|
607
|
+
def _select_map_multiple(ret_cols)
|
|
608
|
+
map{|r| r.values_at(*ret_cols)}
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
# Returns an array of the first value in each row.
|
|
612
|
+
def _select_map_single
|
|
613
|
+
map{|r| r.values.first}
|
|
614
|
+
end
|
|
615
|
+
|
|
597
616
|
private
|
|
598
617
|
|
|
599
618
|
# Internals of +select_map+ and +select_order_map+
|
|
@@ -609,14 +628,13 @@ module Sequel
|
|
|
609
628
|
ds = ds.select(&block)
|
|
610
629
|
ds = ds.order(&block) if order
|
|
611
630
|
end
|
|
612
|
-
if
|
|
613
|
-
|
|
614
|
-
ds.map{|r| ret_cols.map{|c| r[c]}}
|
|
631
|
+
if column.is_a?(Array)
|
|
632
|
+
ds._select_map_multiple(select_cols.map{|c| hash_key_symbol(c)})
|
|
615
633
|
else
|
|
616
|
-
ds.
|
|
634
|
+
ds._select_map_single
|
|
617
635
|
end
|
|
618
636
|
end
|
|
619
|
-
|
|
637
|
+
|
|
620
638
|
# Set the server to use to :default unless it is already set in the passed opts
|
|
621
639
|
def default_server_opts(opts)
|
|
622
640
|
{:server=>@opts[:server] || :default}.merge(opts)
|
|
@@ -24,12 +24,24 @@ module Sequel
|
|
|
24
24
|
true
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# Whether you must use a column alias list for recursive CTEs (false by
|
|
28
|
+
# default).
|
|
29
|
+
def recursive_cte_requires_column_aliases?
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
|
|
27
33
|
# Whether the dataset requires SQL standard datetimes (false by default,
|
|
28
34
|
# as most allow strings with ISO 8601 format).
|
|
29
35
|
def requires_sql_standard_datetimes?
|
|
30
36
|
false
|
|
31
37
|
end
|
|
32
38
|
|
|
39
|
+
# Whether type specifiers are required for prepared statement/bound
|
|
40
|
+
# variable argument placeholders (i.e. :bv__integer)
|
|
41
|
+
def requires_placeholder_type_specifiers?
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
|
|
33
45
|
# Whether the dataset supports common table expressions (the WITH clause).
|
|
34
46
|
# If given, +type+ can be :select, :insert, :update, or :delete, in which case it
|
|
35
47
|
# determines whether WITH is supported for the respective statement type.
|
|
@@ -126,6 +138,18 @@ module Sequel
|
|
|
126
138
|
|
|
127
139
|
private
|
|
128
140
|
|
|
141
|
+
# Whether insert(nil) or insert({}) must be emulated by
|
|
142
|
+
# using at least one value, false by default.
|
|
143
|
+
def insert_supports_empty_values?
|
|
144
|
+
true
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Whether using an offset returns an extra row number column that should be
|
|
148
|
+
# eliminated, false by default.
|
|
149
|
+
def offset_returns_row_number_column?
|
|
150
|
+
false
|
|
151
|
+
end
|
|
152
|
+
|
|
129
153
|
# Whether the RETURNING clause is used for the given dataset.
|
|
130
154
|
# +type+ can be :insert, :update, or :delete.
|
|
131
155
|
def uses_returning?(type)
|
data/lib/sequel/dataset/graph.rb
CHANGED
|
@@ -113,6 +113,8 @@ module Sequel
|
|
|
113
113
|
add_table = options[:select] == false ? false : true
|
|
114
114
|
# Whether to add the columns to the list of column aliases
|
|
115
115
|
add_columns = !ds.opts.include?(:graph_aliases)
|
|
116
|
+
# columns to select
|
|
117
|
+
select = (opts[:select] || []).dup
|
|
116
118
|
|
|
117
119
|
# Setup the initial graph data structure if it doesn't exist
|
|
118
120
|
unless graph = opts[:graph]
|
|
@@ -130,7 +132,6 @@ module Sequel
|
|
|
130
132
|
# aliased, but are not included if set_graph_aliases
|
|
131
133
|
# has been used.
|
|
132
134
|
if add_columns
|
|
133
|
-
select = opts[:select] = []
|
|
134
135
|
columns.each do |column|
|
|
135
136
|
column_aliases[column] = [master, column]
|
|
136
137
|
select.push(SQL::QualifiedIdentifier.new(master, column))
|
|
@@ -147,7 +148,6 @@ module Sequel
|
|
|
147
148
|
|
|
148
149
|
# Add the columns to the selection unless we are ignoring them
|
|
149
150
|
if add_table && add_columns
|
|
150
|
-
select = opts[:select]
|
|
151
151
|
column_aliases = graph[:column_aliases]
|
|
152
152
|
ca_num = graph[:column_alias_num]
|
|
153
153
|
# Which columns to add to the result set
|
|
@@ -165,15 +165,16 @@ module Sequel
|
|
|
165
165
|
column_alias = :"#{column_alias}_#{column_alias_num}"
|
|
166
166
|
ca_num[column_alias] += 1
|
|
167
167
|
end
|
|
168
|
-
[column_alias, SQL::QualifiedIdentifier.new(table_alias, column)
|
|
168
|
+
[column_alias, SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(table_alias, column), column_alias)]
|
|
169
169
|
else
|
|
170
|
-
|
|
170
|
+
ident = SQL::QualifiedIdentifier.new(table_alias, column)
|
|
171
|
+
[column, ident]
|
|
171
172
|
end
|
|
172
173
|
column_aliases[col_alias] = [table_alias, column]
|
|
173
174
|
select.push(identifier)
|
|
174
175
|
end
|
|
175
176
|
end
|
|
176
|
-
ds
|
|
177
|
+
ds.select(*select)
|
|
177
178
|
end
|
|
178
179
|
|
|
179
180
|
# This allows you to manually specify the graph aliases to use
|
|
@@ -225,7 +226,7 @@ module Sequel
|
|
|
225
226
|
column ||= col_alias
|
|
226
227
|
gas[col_alias] = [table, column]
|
|
227
228
|
identifier = value || SQL::QualifiedIdentifier.new(table, column)
|
|
228
|
-
identifier = SQL::AliasedExpression.new(identifier, col_alias) if value
|
|
229
|
+
identifier = SQL::AliasedExpression.new(identifier, col_alias) if value || column != col_alias
|
|
229
230
|
identifier
|
|
230
231
|
end
|
|
231
232
|
[identifiers, gas]
|
data/lib/sequel/dataset/misc.rb
CHANGED
|
@@ -137,7 +137,9 @@ module Sequel
|
|
|
137
137
|
# Returns a string representation of the dataset including the class name
|
|
138
138
|
# and the corresponding SQL select statement.
|
|
139
139
|
def inspect
|
|
140
|
-
|
|
140
|
+
c = self.class
|
|
141
|
+
c = c.superclass while c.name.nil? || c.name == ''
|
|
142
|
+
"#<#{c.name}: #{sql.inspect}>"
|
|
141
143
|
end
|
|
142
144
|
|
|
143
145
|
# The alias to use for the row_number column, used when emulating OFFSET
|
|
@@ -170,6 +172,10 @@ module Sequel
|
|
|
170
172
|
# used, where N is an integer starting at 0 and increasing until an
|
|
171
173
|
# unused one is found.
|
|
172
174
|
#
|
|
175
|
+
# You can provide a second addition array argument containing symbols
|
|
176
|
+
# that should not be considered valid table aliases. The current aliases
|
|
177
|
+
# for the FROM and JOIN tables are automatically included in this array.
|
|
178
|
+
#
|
|
173
179
|
# DB[:table].unused_table_alias(:t)
|
|
174
180
|
# # => :t
|
|
175
181
|
#
|
|
@@ -178,9 +184,11 @@ module Sequel
|
|
|
178
184
|
#
|
|
179
185
|
# DB[:table, :table_0].unused_table_alias(:table)
|
|
180
186
|
# # => :table_1
|
|
181
|
-
|
|
187
|
+
#
|
|
188
|
+
# DB[:table, :table_0].unused_table_alias(:table, [:table_1, :table_2])
|
|
189
|
+
# # => :table_3
|
|
190
|
+
def unused_table_alias(table_alias, used_aliases = [])
|
|
182
191
|
table_alias = alias_symbol(table_alias)
|
|
183
|
-
used_aliases = []
|
|
184
192
|
used_aliases += opts[:from].map{|t| alias_symbol(t)} if opts[:from]
|
|
185
193
|
used_aliases += opts[:join].map{|j| j.table_alias ? alias_alias_symbol(j.table_alias) : alias_symbol(j.table)} if opts[:join]
|
|
186
194
|
if used_aliases.include?(table_alias)
|
|
@@ -29,9 +29,8 @@ module Sequel
|
|
|
29
29
|
# Whether to quote identifiers for this dataset
|
|
30
30
|
attr_writer :quote_identifiers
|
|
31
31
|
|
|
32
|
-
# The row_proc for this database, should be
|
|
33
|
-
# a single hash argument and returns the object you want
|
|
34
|
-
# each to return.
|
|
32
|
+
# The row_proc for this database, should be any object that responds to +call+ with
|
|
33
|
+
# a single hash argument and returns the object you want #each to return.
|
|
35
34
|
attr_accessor :row_proc
|
|
36
35
|
|
|
37
36
|
# Add a mutation method to this dataset instance.
|
|
@@ -35,7 +35,7 @@ module Sequel
|
|
|
35
35
|
return @prepared_sql if @prepared_sql
|
|
36
36
|
@prepared_args ||= []
|
|
37
37
|
@prepared_sql = super
|
|
38
|
-
|
|
38
|
+
@opts[:sql] = @prepared_sql
|
|
39
39
|
@prepared_sql
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -121,8 +121,7 @@ module Sequel
|
|
|
121
121
|
when :select, :all
|
|
122
122
|
all(&block)
|
|
123
123
|
when :insert_select
|
|
124
|
-
|
|
125
|
-
first
|
|
124
|
+
with_sql(prepared_sql).first
|
|
126
125
|
when :first
|
|
127
126
|
first
|
|
128
127
|
when :insert
|
|
@@ -211,7 +210,10 @@ module Sequel
|
|
|
211
210
|
end
|
|
212
211
|
|
|
213
212
|
# Prepare an SQL statement for later execution. Takes a type similar to #call,
|
|
214
|
-
# and the name symbol of the prepared statement.
|
|
213
|
+
# and the +name+ symbol of the prepared statement. While +name+ defaults to +nil+,
|
|
214
|
+
# it should always be provided as a symbol for the name of the prepared statement,
|
|
215
|
+
# as some databases require that prepared statements have names.
|
|
216
|
+
#
|
|
215
217
|
# This returns a clone of the dataset extended with PreparedStatementMethods,
|
|
216
218
|
# which you can +call+ with the hash of bind variables to use.
|
|
217
219
|
# The prepared statement is also stored in
|
data/lib/sequel/dataset/query.rb
CHANGED
|
@@ -28,12 +28,14 @@ module Sequel
|
|
|
28
28
|
JOIN_METHODS = (CONDITIONED_JOIN_TYPES + UNCONDITIONED_JOIN_TYPES).map{|x| "#{x}_join".to_sym} + [:join, :join_table]
|
|
29
29
|
|
|
30
30
|
# Methods that return modified datasets
|
|
31
|
-
QUERY_METHODS =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
QUERY_METHODS = (<<-METHS).split.map{|x| x.to_sym} + JOIN_METHODS
|
|
32
|
+
add_graph_aliases and distinct except exclude exclude_having exclude_where
|
|
33
|
+
filter for_update from from_self graph grep group group_and_count group_by having intersect invert
|
|
34
|
+
limit lock_style naked or order order_append order_by order_more order_prepend paginate qualify query
|
|
35
|
+
reverse reverse_order select select_all select_append select_group select_more server
|
|
36
|
+
set_defaults set_graph_aliases set_overrides unfiltered ungraphed ungrouped union
|
|
37
|
+
unlimited unordered where with with_recursive with_sql
|
|
38
|
+
METHS
|
|
37
39
|
|
|
38
40
|
# Adds an further filter to an existing filter using AND. If no filter
|
|
39
41
|
# exists an error is raised. This method is identical to #filter except
|
|
@@ -201,11 +203,17 @@ module Sequel
|
|
|
201
203
|
def from(*source)
|
|
202
204
|
table_alias_num = 0
|
|
203
205
|
sources = []
|
|
206
|
+
ctes = nil
|
|
204
207
|
source.each do |s|
|
|
205
208
|
case s
|
|
206
209
|
when Hash
|
|
207
210
|
s.each{|k,v| sources << SQL::AliasedExpression.new(k,v)}
|
|
208
211
|
when Dataset
|
|
212
|
+
if hoist_cte?(s)
|
|
213
|
+
ctes ||= []
|
|
214
|
+
ctes += s.opts[:with]
|
|
215
|
+
s = s.clone(:with=>nil)
|
|
216
|
+
end
|
|
209
217
|
sources << SQL::AliasedExpression.new(s, dataset_alias(table_alias_num+=1))
|
|
210
218
|
when Symbol
|
|
211
219
|
sch, table, aliaz = split_symbol(s)
|
|
@@ -220,6 +228,7 @@ module Sequel
|
|
|
220
228
|
end
|
|
221
229
|
end
|
|
222
230
|
o = {:from=>sources.empty? ? nil : sources}
|
|
231
|
+
o[:with] = (opts[:with] || []) + ctes if ctes
|
|
223
232
|
o[:num_dataset_sources] = table_alias_num if table_alias_num > 0
|
|
224
233
|
clone(o)
|
|
225
234
|
end
|
|
@@ -433,7 +442,7 @@ module Sequel
|
|
|
433
442
|
# # SELECT * FROM a NATURAL JOIN b INNER JOIN c
|
|
434
443
|
# # ON ((c.d > b.e) AND (c.f IN (SELECT g FROM b)))
|
|
435
444
|
def join_table(type, table, expr=nil, options={}, &block)
|
|
436
|
-
if
|
|
445
|
+
if hoist_cte?(table)
|
|
437
446
|
s, ds = hoist_cte(table)
|
|
438
447
|
return s.join_table(type, ds, expr, options, &block)
|
|
439
448
|
end
|
|
@@ -881,7 +890,12 @@ module Sequel
|
|
|
881
890
|
# # WITH items AS (SELECT * FROM syx WHERE (name LIKE 'A%')) SELECT * FROM items
|
|
882
891
|
def with(name, dataset, opts={})
|
|
883
892
|
raise(Error, 'This datatset does not support common table expressions') unless supports_cte?
|
|
884
|
-
|
|
893
|
+
if hoist_cte?(dataset)
|
|
894
|
+
s, ds = hoist_cte(dataset)
|
|
895
|
+
s.with(name, ds, opts)
|
|
896
|
+
else
|
|
897
|
+
clone(:with=>(@opts[:with]||[]) + [opts.merge(:name=>name, :dataset=>dataset)])
|
|
898
|
+
end
|
|
885
899
|
end
|
|
886
900
|
|
|
887
901
|
# Add a recursive common table expression (CTE) with the given name, a dataset that
|
|
@@ -903,7 +917,15 @@ module Sequel
|
|
|
903
917
|
# # SELECT i AS id, pi AS parent_id FROM t
|
|
904
918
|
def with_recursive(name, nonrecursive, recursive, opts={})
|
|
905
919
|
raise(Error, 'This datatset does not support common table expressions') unless supports_cte?
|
|
906
|
-
|
|
920
|
+
if hoist_cte?(nonrecursive)
|
|
921
|
+
s, ds = hoist_cte(nonrecursive)
|
|
922
|
+
s.with_recursive(name, ds, recursive, opts)
|
|
923
|
+
elsif hoist_cte?(recursive)
|
|
924
|
+
s, ds = hoist_cte(recursive)
|
|
925
|
+
s.with_recursive(name, nonrecursive, ds, opts)
|
|
926
|
+
else
|
|
927
|
+
clone(:with=>(@opts[:with]||[]) + [opts.merge(:recursive=>true, :name=>name, :dataset=>nonrecursive.union(recursive, {:all=>opts[:union_all] != false, :from_self=>false}))])
|
|
928
|
+
end
|
|
907
929
|
end
|
|
908
930
|
|
|
909
931
|
# Returns a copy of the dataset with the static SQL used. This is useful if you want
|
|
@@ -929,6 +951,16 @@ module Sequel
|
|
|
929
951
|
|
|
930
952
|
protected
|
|
931
953
|
|
|
954
|
+
# Add the dataset to the list of compounds
|
|
955
|
+
def compound_clone(type, dataset, opts)
|
|
956
|
+
if hoist_cte?(dataset)
|
|
957
|
+
s, ds = hoist_cte(dataset)
|
|
958
|
+
return s.compound_clone(type, ds, opts)
|
|
959
|
+
end
|
|
960
|
+
ds = compound_from_self.clone(:compounds=>Array(@opts[:compounds]).map{|x| x.dup} + [[type, dataset.compound_from_self, opts[:all]]])
|
|
961
|
+
opts[:from_self] == false ? ds : ds.from_self(opts)
|
|
962
|
+
end
|
|
963
|
+
|
|
932
964
|
# Return true if the dataset has a non-nil value for any key in opts.
|
|
933
965
|
def options_overlap(opts)
|
|
934
966
|
!(@opts.collect{|k,v| k unless v.nil?}.compact & opts).empty?
|
|
@@ -960,12 +992,6 @@ module Sequel
|
|
|
960
992
|
_filter_or_exclude(false, clause, *cond, &block)
|
|
961
993
|
end
|
|
962
994
|
|
|
963
|
-
# Add the dataset to the list of compounds
|
|
964
|
-
def compound_clone(type, dataset, opts)
|
|
965
|
-
ds = compound_from_self.clone(:compounds=>Array(@opts[:compounds]).map{|x| x.dup} + [[type, dataset.compound_from_self, opts[:all]]])
|
|
966
|
-
opts[:from_self] == false ? ds : ds.from_self(opts)
|
|
967
|
-
end
|
|
968
|
-
|
|
969
995
|
# SQL expression object based on the expr type. See +filter+.
|
|
970
996
|
def filter_expr(expr = nil, &block)
|
|
971
997
|
expr = nil if expr == []
|
|
@@ -1013,6 +1039,11 @@ module Sequel
|
|
|
1013
1039
|
[clone(:with => (opts[:with] || []) + ds.opts[:with]), ds.clone(:with => nil)]
|
|
1014
1040
|
end
|
|
1015
1041
|
|
|
1042
|
+
# Whether CTEs need to be hoisted from the given ds into the current ds.
|
|
1043
|
+
def hoist_cte?(ds)
|
|
1044
|
+
ds.is_a?(Dataset) && ds.opts[:with] && !supports_cte_in_subqueries?
|
|
1045
|
+
end
|
|
1046
|
+
|
|
1016
1047
|
# Inverts the given order by breaking it into a list of column references
|
|
1017
1048
|
# and inverting them.
|
|
1018
1049
|
#
|
data/lib/sequel/dataset/sql.rb
CHANGED
|
@@ -62,6 +62,10 @@ module Sequel
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
columns = columns.map{|k| literal(String === k ? k.to_sym : k)}
|
|
65
|
+
if values.is_a?(Array) && values.empty? && !insert_supports_empty_values?
|
|
66
|
+
columns = [literal(columns().last)]
|
|
67
|
+
values = ['DEFAULT'.lit]
|
|
68
|
+
end
|
|
65
69
|
clone(:columns=>columns, :values=>values)._insert_sql
|
|
66
70
|
end
|
|
67
71
|
|
|
@@ -554,6 +558,28 @@ module Sequel
|
|
|
554
558
|
(columns.nil? || columns.empty?) ? WILDCARD : expression_list(columns)
|
|
555
559
|
end
|
|
556
560
|
|
|
561
|
+
# Yield each two pair of arguments to the block, which should
|
|
562
|
+
# return a string representing the SQL code for those
|
|
563
|
+
# two arguments. If more than 2 arguments are provided, all
|
|
564
|
+
# calls to the block # after the first will have a LiteralString
|
|
565
|
+
# as the first argument, representing the application of the block to
|
|
566
|
+
# the previous arguments.
|
|
567
|
+
def complex_expression_arg_pairs(args)
|
|
568
|
+
case args.length
|
|
569
|
+
when 1
|
|
570
|
+
literal(args.at(0))
|
|
571
|
+
when 2
|
|
572
|
+
yield args.at(0), args.at(1)
|
|
573
|
+
else
|
|
574
|
+
args.inject{|m, a| LiteralString.new(yield(m, a))}
|
|
575
|
+
end
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
# The SQL to use for the dataset used in a UNION/INTERSECT/EXCEPT clause.
|
|
579
|
+
def compound_dataset_sql(ds)
|
|
580
|
+
subselect_sql(ds)
|
|
581
|
+
end
|
|
582
|
+
|
|
557
583
|
# The alias to use for datasets, takes a number to make sure the name is unique.
|
|
558
584
|
def dataset_alias(number)
|
|
559
585
|
:"#{DATASET_ALIAS_BASE_NAME}#{number}"
|
|
@@ -580,7 +606,7 @@ module Sequel
|
|
|
580
606
|
# database supports them), and override %z to always use a numeric offset
|
|
581
607
|
# of hours and minutes.
|
|
582
608
|
def format_timestamp(v)
|
|
583
|
-
v2 =
|
|
609
|
+
v2 = db.from_application_timestamp(v)
|
|
584
610
|
fmt = default_timestamp_format.gsub(/%[Nz]/) do |m|
|
|
585
611
|
if m == '%N'
|
|
586
612
|
format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION < '1.9.0' ? 86400000000 : 1000000) : v.usec) if supports_timestamp_usecs?
|
|
@@ -821,8 +847,7 @@ module Sequel
|
|
|
821
847
|
def select_compounds_sql(sql)
|
|
822
848
|
return unless @opts[:compounds]
|
|
823
849
|
@opts[:compounds].each do |type, dataset, all|
|
|
824
|
-
|
|
825
|
-
sql << " #{type.to_s.upcase}#{' ALL' if all} #{compound_sql}"
|
|
850
|
+
sql << " #{type.to_s.upcase}#{' ALL' if all} #{compound_dataset_sql(dataset)}"
|
|
826
851
|
end
|
|
827
852
|
end
|
|
828
853
|
|
|
@@ -886,7 +911,6 @@ module Sequel
|
|
|
886
911
|
alias delete_with_sql select_with_sql
|
|
887
912
|
alias insert_with_sql select_with_sql
|
|
888
913
|
alias update_with_sql select_with_sql
|
|
889
|
-
|
|
890
914
|
|
|
891
915
|
# The base keyword to use for the SQL WITH clause
|
|
892
916
|
def select_with_sql_base
|