sequel 4.9.0 → 4.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +79 -1
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/Rakefile +2 -12
- data/bin/sequel +1 -0
- data/doc/advanced_associations.rdoc +82 -25
- data/doc/association_basics.rdoc +21 -22
- data/doc/core_extensions.rdoc +1 -1
- data/doc/opening_databases.rdoc +7 -0
- data/doc/release_notes/4.10.0.txt +226 -0
- data/doc/security.rdoc +1 -0
- data/doc/testing.rdoc +7 -7
- data/doc/transactions.rdoc +8 -0
- data/lib/sequel/adapters/jdbc.rb +160 -168
- data/lib/sequel/adapters/jdbc/db2.rb +17 -18
- data/lib/sequel/adapters/jdbc/derby.rb +5 -28
- data/lib/sequel/adapters/jdbc/h2.rb +11 -22
- data/lib/sequel/adapters/jdbc/hsqldb.rb +31 -18
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -15
- data/lib/sequel/adapters/jdbc/oracle.rb +36 -35
- data/lib/sequel/adapters/jdbc/postgresql.rb +72 -90
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +18 -16
- data/lib/sequel/adapters/jdbc/sqlite.rb +7 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -30
- data/lib/sequel/adapters/jdbc/transactions.rb +5 -6
- data/lib/sequel/adapters/openbase.rb +1 -7
- data/lib/sequel/adapters/postgres.rb +1 -1
- data/lib/sequel/adapters/shared/access.rb +3 -6
- data/lib/sequel/adapters/shared/cubrid.rb +24 -9
- data/lib/sequel/adapters/shared/db2.rb +13 -5
- data/lib/sequel/adapters/shared/firebird.rb +16 -16
- data/lib/sequel/adapters/shared/informix.rb +2 -5
- data/lib/sequel/adapters/shared/mssql.rb +72 -63
- data/lib/sequel/adapters/shared/mysql.rb +72 -40
- data/lib/sequel/adapters/shared/oracle.rb +27 -15
- data/lib/sequel/adapters/shared/postgres.rb +24 -44
- data/lib/sequel/adapters/shared/progress.rb +1 -5
- data/lib/sequel/adapters/shared/sqlanywhere.rb +26 -18
- data/lib/sequel/adapters/shared/sqlite.rb +21 -6
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -2
- data/lib/sequel/adapters/utils/split_alter_table.rb +8 -0
- data/lib/sequel/core.rb +14 -9
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +12 -0
- data/lib/sequel/database/query.rb +4 -1
- data/lib/sequel/database/schema_methods.rb +3 -2
- data/lib/sequel/database/transactions.rb +47 -17
- data/lib/sequel/dataset/features.rb +12 -2
- data/lib/sequel/dataset/mutation.rb +2 -0
- data/lib/sequel/dataset/placeholder_literalizer.rb +12 -4
- data/lib/sequel/dataset/prepared_statements.rb +6 -0
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/dataset/sql.rb +132 -70
- data/lib/sequel/extensions/columns_introspection.rb +1 -1
- data/lib/sequel/extensions/null_dataset.rb +8 -4
- data/lib/sequel/extensions/pg_array.rb +4 -4
- data/lib/sequel/extensions/pg_row.rb +1 -0
- data/lib/sequel/model/associations.rb +468 -188
- data/lib/sequel/model/base.rb +88 -13
- data/lib/sequel/plugins/association_pks.rb +23 -64
- data/lib/sequel/plugins/auto_validations.rb +3 -2
- data/lib/sequel/plugins/dataset_associations.rb +1 -3
- data/lib/sequel/plugins/many_through_many.rb +18 -65
- data/lib/sequel/plugins/pg_array_associations.rb +97 -86
- data/lib/sequel/plugins/prepared_statements.rb +2 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +36 -27
- data/lib/sequel/plugins/rcte_tree.rb +12 -16
- data/lib/sequel/plugins/sharding.rb +21 -3
- data/lib/sequel/plugins/single_table_inheritance.rb +2 -1
- data/lib/sequel/plugins/subclasses.rb +1 -9
- data/lib/sequel/plugins/tactical_eager_loading.rb +9 -0
- data/lib/sequel/plugins/tree.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +57 -15
- data/spec/adapters/mysql_spec.rb +11 -0
- data/spec/bin_spec.rb +2 -2
- data/spec/core/database_spec.rb +38 -4
- data/spec/core/dataset_spec.rb +45 -7
- data/spec/core/placeholder_literalizer_spec.rb +17 -0
- data/spec/core/schema_spec.rb +6 -1
- data/spec/extensions/active_model_spec.rb +18 -9
- data/spec/extensions/association_pks_spec.rb +20 -18
- data/spec/extensions/association_proxies_spec.rb +9 -9
- data/spec/extensions/auto_validations_spec.rb +6 -0
- data/spec/extensions/columns_introspection_spec.rb +1 -0
- data/spec/extensions/constraint_validations_spec.rb +3 -1
- data/spec/extensions/many_through_many_spec.rb +191 -111
- data/spec/extensions/pg_array_associations_spec.rb +133 -103
- data/spec/extensions/prepared_statements_associations_spec.rb +23 -4
- data/spec/extensions/rcte_tree_spec.rb +35 -27
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -1
- data/spec/extensions/sharding_spec.rb +2 -2
- data/spec/extensions/tactical_eager_loading_spec.rb +4 -0
- data/spec/extensions/to_dot_spec.rb +1 -0
- data/spec/extensions/touch_spec.rb +2 -2
- data/spec/integration/associations_test.rb +130 -37
- data/spec/integration/dataset_test.rb +17 -0
- data/spec/integration/model_test.rb +17 -0
- data/spec/integration/schema_test.rb +14 -0
- data/spec/integration/transaction_test.rb +25 -1
- data/spec/model/association_reflection_spec.rb +63 -24
- data/spec/model/associations_spec.rb +104 -57
- data/spec/model/base_spec.rb +14 -1
- data/spec/model/class_dataset_methods_spec.rb +1 -0
- data/spec/model/eager_loading_spec.rb +221 -74
- data/spec/model/model_spec.rb +119 -1
- metadata +4 -2
@@ -44,7 +44,7 @@ module Sequel
|
|
44
44
|
# If given, +type+ can be :select, :insert, :update, or :delete, in which case it
|
45
45
|
# determines whether WITH is supported for the respective statement type.
|
46
46
|
def supports_cte?(type=:select)
|
47
|
-
|
47
|
+
false
|
48
48
|
end
|
49
49
|
|
50
50
|
# Whether the dataset supports common table expressions (the WITH clause)
|
@@ -99,6 +99,11 @@ module Sequel
|
|
99
99
|
def supports_lateral_subqueries?
|
100
100
|
false
|
101
101
|
end
|
102
|
+
|
103
|
+
# Whether limits are supported in correlated subqueries. True by default.
|
104
|
+
def supports_limits_in_correlated_subqueries?
|
105
|
+
true
|
106
|
+
end
|
102
107
|
|
103
108
|
# Whether modifying joined datasets is supported.
|
104
109
|
def supports_modifying_joins?
|
@@ -111,6 +116,11 @@ module Sequel
|
|
111
116
|
true
|
112
117
|
end
|
113
118
|
|
119
|
+
# Whether offsets are supported in correlated subqueries, true by default.
|
120
|
+
def supports_offsets_in_correlated_subqueries?
|
121
|
+
true
|
122
|
+
end
|
123
|
+
|
114
124
|
# Whether the dataset supports or can fully emulate the DISTINCT ON clause,
|
115
125
|
# including respecting the ORDER BY clause, false by default
|
116
126
|
def supports_ordered_distinct_on?
|
@@ -130,7 +140,7 @@ module Sequel
|
|
130
140
|
# Whether the RETURNING clause is supported for the given type of query.
|
131
141
|
# +type+ can be :insert, :update, or :delete.
|
132
142
|
def supports_returning?(type)
|
133
|
-
|
143
|
+
false
|
134
144
|
end
|
135
145
|
|
136
146
|
# Whether the database supports SELECT *, column FROM table
|
@@ -58,6 +58,7 @@ module Sequel
|
|
58
58
|
# Set the method to call on identifiers going into the database for this dataset
|
59
59
|
def identifier_input_method=(v)
|
60
60
|
raise_if_frozen!
|
61
|
+
skip_symbol_cache!
|
61
62
|
@identifier_input_method = v
|
62
63
|
end
|
63
64
|
|
@@ -77,6 +78,7 @@ module Sequel
|
|
77
78
|
# Set whether to quote identifiers for this dataset
|
78
79
|
def quote_identifiers=(v)
|
79
80
|
raise_if_frozen!
|
81
|
+
skip_symbol_cache!
|
80
82
|
@quote_identifiers = v
|
81
83
|
end
|
82
84
|
|
@@ -54,7 +54,11 @@ module Sequel
|
|
54
54
|
# Record the SQL query offset, argument position, and transforming block where the
|
55
55
|
# argument should be literalized.
|
56
56
|
def sql_literal_append(ds, sql)
|
57
|
-
|
57
|
+
if ds.opts[:placeholder_literal_null]
|
58
|
+
ds.send(:literal_append, sql, nil)
|
59
|
+
else
|
60
|
+
@recorder.use(sql, @pos, @transformer)
|
61
|
+
end
|
58
62
|
end
|
59
63
|
|
60
64
|
# Return a new Argument object for the same recorder and argument position, but with a
|
@@ -74,7 +78,7 @@ module Sequel
|
|
74
78
|
@argn = -1
|
75
79
|
@args = []
|
76
80
|
ds = yield self, dataset
|
77
|
-
sql = ds.sql
|
81
|
+
sql = ds.clone(:placeholder_literalizer=>self).sql
|
78
82
|
|
79
83
|
last_offset = 0
|
80
84
|
fragments = @args.map do |used_sql, offset, arg, t|
|
@@ -150,8 +154,12 @@ module Sequel
|
|
150
154
|
ds = @dataset
|
151
155
|
@fragments.each do |sql, i, transformer|
|
152
156
|
s << sql
|
153
|
-
|
154
|
-
|
157
|
+
if i.is_a?(Integer)
|
158
|
+
v = args.fetch(i)
|
159
|
+
v = transformer.call(v) if transformer
|
160
|
+
else
|
161
|
+
v = i.call
|
162
|
+
end
|
155
163
|
ds.literal_append(s, v)
|
156
164
|
end
|
157
165
|
if sql = @final_sql
|
@@ -165,6 +165,12 @@ module Sequel
|
|
165
165
|
@opts[:bind_vars].has_key?(k)
|
166
166
|
end
|
167
167
|
|
168
|
+
# The symbol cache should always be skipped, since placeholders
|
169
|
+
# are symbols.
|
170
|
+
def skip_symbol_cache?
|
171
|
+
true
|
172
|
+
end
|
173
|
+
|
168
174
|
# Use a clone of the dataset extended with prepared statement
|
169
175
|
# support and using the same argument hash so that you can use
|
170
176
|
# bind variables/prepared arguments in subselects.
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -892,7 +892,7 @@ module Sequel
|
|
892
892
|
# DB[:items].with(:items, DB[:syx].where(:name.like('A%')))
|
893
893
|
# # WITH items AS (SELECT * FROM syx WHERE (name LIKE 'A%')) SELECT * FROM items
|
894
894
|
def with(name, dataset, opts=OPTS)
|
895
|
-
raise(Error, 'This
|
895
|
+
raise(Error, 'This dataset does not support common table expressions') unless supports_cte?
|
896
896
|
if hoist_cte?(dataset)
|
897
897
|
s, ds = hoist_cte(dataset)
|
898
898
|
s.with(name, ds, opts)
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -5,16 +5,6 @@ module Sequel
|
|
5
5
|
# These are methods you can call to see what SQL will be generated by the dataset.
|
6
6
|
# ---------------------
|
7
7
|
|
8
|
-
# Returns a DELETE SQL query string. See +delete+.
|
9
|
-
#
|
10
|
-
# dataset.filter{|o| o.price >= 100}.delete_sql
|
11
|
-
# # => "DELETE FROM items WHERE (price >= 100)"
|
12
|
-
def delete_sql
|
13
|
-
return static_sql(opts[:sql]) if opts[:sql]
|
14
|
-
check_modification_allowed!
|
15
|
-
clause_sql(:delete)
|
16
|
-
end
|
17
|
-
|
18
8
|
# Returns an EXISTS clause for the dataset as a +LiteralString+.
|
19
9
|
#
|
20
10
|
# DB.select(1).where(DB[:items].exists)
|
@@ -59,7 +49,7 @@ module Sequel
|
|
59
49
|
columns = [columns().last]
|
60
50
|
values = [DEFAULT]
|
61
51
|
end
|
62
|
-
clone(:columns=>columns, :values=>values)._insert_sql
|
52
|
+
clone(:columns=>columns, :values=>values).send(:_insert_sql)
|
63
53
|
end
|
64
54
|
|
65
55
|
# Append a literal representation of a value to the given SQL string.
|
@@ -68,7 +58,16 @@ module Sequel
|
|
68
58
|
def literal_append(sql, v)
|
69
59
|
case v
|
70
60
|
when Symbol
|
71
|
-
|
61
|
+
if skip_symbol_cache?
|
62
|
+
literal_symbol_append(sql, v)
|
63
|
+
else
|
64
|
+
unless l = db.literal_symbol(v)
|
65
|
+
l = ''
|
66
|
+
literal_symbol_append(l, v)
|
67
|
+
db.literal_symbol_set(v, l)
|
68
|
+
end
|
69
|
+
sql << l
|
70
|
+
end
|
72
71
|
when String
|
73
72
|
case v
|
74
73
|
when LiteralString
|
@@ -116,17 +115,32 @@ module Sequel
|
|
116
115
|
# This method should be overridden by descendants if the support
|
117
116
|
# inserting multiple records in a single SQL statement.
|
118
117
|
def multi_insert_sql(columns, values)
|
119
|
-
|
118
|
+
case multi_insert_sql_strategy
|
119
|
+
when :values
|
120
|
+
sql = LiteralString.new('VALUES ')
|
121
|
+
expression_list_append(sql, values.map{|r| Array(r)})
|
122
|
+
[insert_sql(columns, sql)]
|
123
|
+
when :union
|
124
|
+
c = false
|
125
|
+
sql = LiteralString.new('')
|
126
|
+
u = UNION_ALL_SELECT
|
127
|
+
f = empty_from_sql
|
128
|
+
values.each do |v|
|
129
|
+
if c
|
130
|
+
sql << u
|
131
|
+
else
|
132
|
+
sql << SELECT << SPACE
|
133
|
+
c = true
|
134
|
+
end
|
135
|
+
expression_list_append(sql, v)
|
136
|
+
sql << f if f
|
137
|
+
end
|
138
|
+
[insert_sql(columns, sql)]
|
139
|
+
else
|
140
|
+
values.map{|r| insert_sql(columns, r)}
|
141
|
+
end
|
120
142
|
end
|
121
143
|
|
122
|
-
# Returns a SELECT SQL query string.
|
123
|
-
#
|
124
|
-
# dataset.select_sql # => "SELECT * FROM items"
|
125
|
-
def select_sql
|
126
|
-
return static_sql(@opts[:sql]) if @opts[:sql]
|
127
|
-
clause_sql(:select)
|
128
|
-
end
|
129
|
-
|
130
144
|
# Same as +select_sql+, not aliased directly to make subclassing simpler.
|
131
145
|
def sql
|
132
146
|
select_sql
|
@@ -157,7 +171,7 @@ module Sequel
|
|
157
171
|
def update_sql(values = OPTS)
|
158
172
|
return static_sql(opts[:sql]) if opts[:sql]
|
159
173
|
check_modification_allowed!
|
160
|
-
clone(:values=>values)._update_sql
|
174
|
+
clone(:values=>values).send(:_update_sql)
|
161
175
|
end
|
162
176
|
|
163
177
|
# ---------------------
|
@@ -171,6 +185,47 @@ module Sequel
|
|
171
185
|
clauses.map{|clause| :"#{type}_#{clause}_sql"}.freeze
|
172
186
|
end
|
173
187
|
|
188
|
+
# Define a dataset literalization method for the given type in the given module,
|
189
|
+
# using the given clauses.
|
190
|
+
#
|
191
|
+
# Arguments:
|
192
|
+
# mod :: Module in which to define method
|
193
|
+
# type :: Type of SQL literalization method to create, either :select, :insert, :update, or :delete
|
194
|
+
# clauses :: array of clauses that make up the SQL query for the type. This can either be a single
|
195
|
+
# array of symbols/strings, or it can be an array of pairs, with the first element in
|
196
|
+
# each pair being an if/elsif/else code fragment, and the second element in each pair
|
197
|
+
# being an array of symbol/strings for the appropriate branch.
|
198
|
+
def self.def_sql_method(mod, type, clauses)
|
199
|
+
priv = type == :update || type == :insert
|
200
|
+
|
201
|
+
lines = []
|
202
|
+
lines << 'private' if priv
|
203
|
+
lines << "def #{'_' if priv}#{type}_sql"
|
204
|
+
lines << 'if sql = opts[:sql]; return static_sql(sql) end' unless priv
|
205
|
+
lines << 'check_modification_allowed!' if type == :delete
|
206
|
+
lines << 'sql = @opts[:append_sql] || sql_string_origin'
|
207
|
+
|
208
|
+
if clauses.all?{|c| c.is_a?(Array)}
|
209
|
+
clauses.each do |i, cs|
|
210
|
+
lines << i
|
211
|
+
lines.concat(clause_methods(type, cs).map{|x| "#{x}(sql)"})
|
212
|
+
end
|
213
|
+
lines << 'end'
|
214
|
+
else
|
215
|
+
lines.concat(clause_methods(type, clauses).map{|x| "#{x}(sql)"})
|
216
|
+
end
|
217
|
+
|
218
|
+
lines << 'sql'
|
219
|
+
lines << 'end'
|
220
|
+
|
221
|
+
mod.class_eval lines.join("\n"), __FILE__, __LINE__
|
222
|
+
end
|
223
|
+
|
224
|
+
def_sql_method(self, :delete, %w'delete from where')
|
225
|
+
def_sql_method(self, :insert, %w'insert into columns values')
|
226
|
+
def_sql_method(self, :select, %w'with select distinct columns from join where group having compounds order limit lock')
|
227
|
+
def_sql_method(self, :update, %w'update table set where')
|
228
|
+
|
174
229
|
# Map of emulated function names to native function names.
|
175
230
|
EMULATED_FUNCTION_MAP = {}
|
176
231
|
|
@@ -210,7 +265,6 @@ module Sequel
|
|
210
265
|
DEFAULT = LiteralString.new('DEFAULT').freeze
|
211
266
|
DEFAULT_VALUES = " DEFAULT VALUES".freeze
|
212
267
|
DELETE = 'DELETE'.freeze
|
213
|
-
DELETE_CLAUSE_METHODS = clause_methods(:delete, %w'delete from where')
|
214
268
|
DESC = ' DESC'.freeze
|
215
269
|
DISTINCT = " DISTINCT".freeze
|
216
270
|
DOT = '.'.freeze
|
@@ -234,7 +288,6 @@ module Sequel
|
|
234
288
|
GROUP_BY = " GROUP BY ".freeze
|
235
289
|
HAVING = " HAVING ".freeze
|
236
290
|
INSERT = "INSERT".freeze
|
237
|
-
INSERT_CLAUSE_METHODS = clause_methods(:insert, %w'insert into columns values')
|
238
291
|
INTO = " INTO ".freeze
|
239
292
|
IS_LITERALS = {nil=>'NULL'.freeze, true=>'TRUE'.freeze, false=>'FALSE'.freeze}.freeze
|
240
293
|
IS_OPERATORS = ::Sequel::SQL::ComplexExpression::IS_OPERATORS
|
@@ -263,7 +316,6 @@ module Sequel
|
|
263
316
|
QUOTE_RE = /"/.freeze
|
264
317
|
RETURNING = " RETURNING ".freeze
|
265
318
|
SELECT = 'SELECT'.freeze
|
266
|
-
SELECT_CLAUSE_METHODS = clause_methods(:select, %w'with select distinct columns from join where group having compounds order limit lock')
|
267
319
|
SET = ' SET '.freeze
|
268
320
|
SPACE = ' '.freeze
|
269
321
|
SQL_WITH = "WITH ".freeze
|
@@ -275,8 +327,8 @@ module Sequel
|
|
275
327
|
REGEXP_OPERATORS = ::Sequel::SQL::ComplexExpression::REGEXP_OPERATORS
|
276
328
|
UNDERSCORE = '_'.freeze
|
277
329
|
UPDATE = 'UPDATE'.freeze
|
278
|
-
UPDATE_CLAUSE_METHODS = clause_methods(:update, %w'update table set where')
|
279
330
|
USING = ' USING ('.freeze
|
331
|
+
UNION_ALL_SELECT = ' UNION ALL SELECT '.freeze
|
280
332
|
VALUES = " VALUES ".freeze
|
281
333
|
V190 = '1.9.0'.freeze
|
282
334
|
WHERE = " WHERE ".freeze
|
@@ -463,7 +515,11 @@ module Sequel
|
|
463
515
|
# Append literalization of delayed evaluation to SQL string,
|
464
516
|
# causing the delayed evaluation proc to be evaluated.
|
465
517
|
def delayed_evaluation_sql_append(sql, callable)
|
466
|
-
|
518
|
+
if recorder = @opts[:placeholder_literalizer]
|
519
|
+
recorder.use(sql, callable, nil)
|
520
|
+
else
|
521
|
+
literal_append(sql, callable.call)
|
522
|
+
end
|
467
523
|
end
|
468
524
|
|
469
525
|
# Append literalization of emulated function call to SQL string.
|
@@ -718,16 +774,6 @@ module Sequel
|
|
718
774
|
|
719
775
|
protected
|
720
776
|
|
721
|
-
# Formats in INSERT statement using the stored columns and values.
|
722
|
-
def _insert_sql
|
723
|
-
clause_sql(:insert)
|
724
|
-
end
|
725
|
-
|
726
|
-
# Formats an UPDATE statement using the stored values.
|
727
|
-
def _update_sql
|
728
|
-
clause_sql(:update)
|
729
|
-
end
|
730
|
-
|
731
777
|
# Return a from_self dataset if an order or limit is specified, so it works as expected
|
732
778
|
# with UNION, EXCEPT, and INTERSECT clauses.
|
733
779
|
def compound_from_self
|
@@ -828,13 +874,6 @@ module Sequel
|
|
828
874
|
check_modification_allowed!
|
829
875
|
end
|
830
876
|
|
831
|
-
# Prepare an SQL statement by calling all clause methods for the given statement type.
|
832
|
-
def clause_sql(type)
|
833
|
-
sql = @opts[:append_sql] || sql_string_origin
|
834
|
-
send("#{type}_clause_methods").each{|x| send(x, sql)}
|
835
|
-
sql
|
836
|
-
end
|
837
|
-
|
838
877
|
# Append column list to SQL string.
|
839
878
|
# Converts an array of column names into a comma seperated string of
|
840
879
|
# column names. If the array is empty, a wildcard (*) is returned.
|
@@ -904,15 +943,23 @@ module Sequel
|
|
904
943
|
requires_sql_standard_datetimes? ? STANDARD_TIMESTAMP_FORMAT : TIMESTAMP_FORMAT
|
905
944
|
end
|
906
945
|
|
907
|
-
# The order of methods to call to build the DELETE SQL statement
|
908
|
-
def delete_clause_methods
|
909
|
-
DELETE_CLAUSE_METHODS
|
910
|
-
end
|
911
|
-
|
912
946
|
def delete_delete_sql(sql)
|
913
947
|
sql << DELETE
|
914
948
|
end
|
915
949
|
|
950
|
+
def delete_from_sql(sql)
|
951
|
+
if f = @opts[:from]
|
952
|
+
sql << FROM
|
953
|
+
source_list_append(sql, f)
|
954
|
+
end
|
955
|
+
end
|
956
|
+
|
957
|
+
# An SQL FROM clause to use in SELECT statements where the dataset has
|
958
|
+
# no from tables.
|
959
|
+
def empty_from_sql
|
960
|
+
nil
|
961
|
+
end
|
962
|
+
|
916
963
|
# Append literalization of array of expressions to SQL string.
|
917
964
|
def expression_list_append(sql, columns)
|
918
965
|
c = false
|
@@ -1001,11 +1048,6 @@ module Sequel
|
|
1001
1048
|
source_list_append(sql, @opts[:from])
|
1002
1049
|
end
|
1003
1050
|
|
1004
|
-
# The order of methods to call to build the INSERT SQL statement
|
1005
|
-
def insert_clause_methods
|
1006
|
-
INSERT_CLAUSE_METHODS
|
1007
|
-
end
|
1008
|
-
|
1009
1051
|
def insert_columns_sql(sql)
|
1010
1052
|
columns = opts[:columns]
|
1011
1053
|
if columns && !columns.empty?
|
@@ -1191,6 +1233,14 @@ module Sequel
|
|
1191
1233
|
BOOL_TRUE
|
1192
1234
|
end
|
1193
1235
|
|
1236
|
+
# What strategy to use for import/multi_insert. While SQL-92 defaults
|
1237
|
+
# to allowing multiple rows in a VALUES clause, there are enough databases
|
1238
|
+
# that don't allow that that it can't be the default. Use separate queries
|
1239
|
+
# by default, which works everywhere.
|
1240
|
+
def multi_insert_sql_strategy
|
1241
|
+
:separate
|
1242
|
+
end
|
1243
|
+
|
1194
1244
|
# Get the native function name given the emulated function name.
|
1195
1245
|
def native_function_name(emulated_function)
|
1196
1246
|
self.class.const_get(:EMULATED_FUNCTION_MAP).fetch(emulated_function, emulated_function)
|
@@ -1222,11 +1272,6 @@ module Sequel
|
|
1222
1272
|
Qualifier.new(self, table).transform(e)
|
1223
1273
|
end
|
1224
1274
|
|
1225
|
-
# The order of methods to call to build the SELECT SQL statement
|
1226
|
-
def select_clause_methods
|
1227
|
-
SELECT_CLAUSE_METHODS
|
1228
|
-
end
|
1229
|
-
|
1230
1275
|
def select_columns_sql(sql)
|
1231
1276
|
sql << SPACE
|
1232
1277
|
column_list_append(sql, @opts[:select])
|
@@ -1260,9 +1305,10 @@ module Sequel
|
|
1260
1305
|
if f = @opts[:from]
|
1261
1306
|
sql << FROM
|
1262
1307
|
source_list_append(sql, f)
|
1308
|
+
elsif f = empty_from_sql
|
1309
|
+
sql << f
|
1263
1310
|
end
|
1264
1311
|
end
|
1265
|
-
alias delete_from_sql select_from_sql
|
1266
1312
|
|
1267
1313
|
def select_group_sql(sql)
|
1268
1314
|
if group = @opts[:group]
|
@@ -1299,13 +1345,15 @@ module Sequel
|
|
1299
1345
|
if l = @opts[:limit]
|
1300
1346
|
sql << LIMIT
|
1301
1347
|
literal_append(sql, l)
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1348
|
+
if o = @opts[:offset]
|
1349
|
+
sql << OFFSET
|
1350
|
+
literal_append(sql, o)
|
1351
|
+
end
|
1352
|
+
elsif @opts[:offset]
|
1353
|
+
select_only_offset_sql(sql)
|
1306
1354
|
end
|
1307
1355
|
end
|
1308
|
-
|
1356
|
+
|
1309
1357
|
def select_lock_sql(sql)
|
1310
1358
|
case l = @opts[:lock]
|
1311
1359
|
when :update
|
@@ -1315,6 +1363,14 @@ module Sequel
|
|
1315
1363
|
end
|
1316
1364
|
end
|
1317
1365
|
|
1366
|
+
# Used only if there is an offset and no limit, making it easier to override
|
1367
|
+
# in the adapter, as many databases do not support just a plain offset with
|
1368
|
+
# no limit.
|
1369
|
+
def select_only_offset_sql(sql)
|
1370
|
+
sql << OFFSET
|
1371
|
+
literal_append(sql, @opts[:offset])
|
1372
|
+
end
|
1373
|
+
|
1318
1374
|
def select_order_sql(sql)
|
1319
1375
|
if o = @opts[:order]
|
1320
1376
|
sql << ORDER_BY
|
@@ -1338,6 +1394,7 @@ module Sequel
|
|
1338
1394
|
alias update_where_sql select_where_sql
|
1339
1395
|
|
1340
1396
|
def select_with_sql(sql)
|
1397
|
+
return unless supports_cte?
|
1341
1398
|
ws = opts[:with]
|
1342
1399
|
return if !ws || ws.empty?
|
1343
1400
|
sql << select_with_sql_base
|
@@ -1366,6 +1423,16 @@ module Sequel
|
|
1366
1423
|
SQL_WITH
|
1367
1424
|
end
|
1368
1425
|
|
1426
|
+
# Whether the symbol cache should be skipped when literalizing the dataset
|
1427
|
+
def skip_symbol_cache?
|
1428
|
+
@skip_symbol_cache
|
1429
|
+
end
|
1430
|
+
|
1431
|
+
# Set the dataset to skip the symbol cache
|
1432
|
+
def skip_symbol_cache!
|
1433
|
+
@skip_symbol_cache = true
|
1434
|
+
end
|
1435
|
+
|
1369
1436
|
# Append literalization of array of sources/tables to SQL string, raising an Error if there
|
1370
1437
|
# are no sources.
|
1371
1438
|
def source_list_append(sql, sources)
|
@@ -1409,11 +1476,6 @@ module Sequel
|
|
1409
1476
|
ds.clone(:append_sql=>sql).sql
|
1410
1477
|
end
|
1411
1478
|
|
1412
|
-
# The order of methods to call to build the UPDATE SQL statement
|
1413
|
-
def update_clause_methods
|
1414
|
-
UPDATE_CLAUSE_METHODS
|
1415
|
-
end
|
1416
|
-
|
1417
1479
|
def update_table_sql(sql)
|
1418
1480
|
sql << SPACE
|
1419
1481
|
source_list_append(sql, @opts[:from])
|