sequel 4.8.0 → 4.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +48 -0
- data/doc/association_basics.rdoc +1 -1
- data/doc/opening_databases.rdoc +4 -0
- data/doc/postgresql.rdoc +27 -3
- data/doc/release_notes/4.9.0.txt +190 -0
- data/doc/security.rdoc +1 -1
- data/doc/testing.rdoc +2 -2
- data/doc/validations.rdoc +8 -0
- data/lib/sequel/adapters/jdbc.rb +5 -3
- data/lib/sequel/adapters/jdbc/derby.rb +2 -8
- data/lib/sequel/adapters/jdbc/h2.rb +2 -13
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -16
- data/lib/sequel/adapters/mysql2.rb +11 -1
- data/lib/sequel/adapters/postgres.rb +33 -10
- data/lib/sequel/adapters/shared/db2.rb +2 -10
- data/lib/sequel/adapters/shared/mssql.rb +10 -8
- data/lib/sequel/adapters/shared/oracle.rb +9 -24
- data/lib/sequel/adapters/shared/postgres.rb +32 -9
- data/lib/sequel/adapters/shared/sqlanywhere.rb +2 -4
- data/lib/sequel/adapters/shared/sqlite.rb +4 -7
- data/lib/sequel/database/schema_methods.rb +15 -0
- data/lib/sequel/dataset.rb +1 -1
- data/lib/sequel/dataset/actions.rb +159 -27
- data/lib/sequel/dataset/graph.rb +29 -7
- data/lib/sequel/dataset/misc.rb +6 -0
- data/lib/sequel/dataset/placeholder_literalizer.rb +164 -0
- data/lib/sequel/dataset/query.rb +2 -0
- data/lib/sequel/dataset/sql.rb +103 -91
- data/lib/sequel/extensions/current_datetime_timestamp.rb +57 -0
- data/lib/sequel/extensions/pg_array.rb +68 -106
- data/lib/sequel/extensions/pg_hstore.rb +5 -5
- data/lib/sequel/extensions/schema_dumper.rb +49 -49
- data/lib/sequel/model.rb +4 -2
- data/lib/sequel/model/associations.rb +1 -1
- data/lib/sequel/model/base.rb +136 -3
- data/lib/sequel/model/errors.rb +6 -0
- data/lib/sequel/plugins/defaults_setter.rb +1 -1
- data/lib/sequel/plugins/eager_each.rb +9 -0
- data/lib/sequel/plugins/nested_attributes.rb +2 -2
- data/lib/sequel/plugins/timestamps.rb +2 -2
- data/lib/sequel/plugins/touch.rb +2 -2
- data/lib/sequel/sql.rb +20 -15
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +70 -8
- data/spec/core/dataset_spec.rb +172 -27
- data/spec/core/expression_filters_spec.rb +3 -3
- data/spec/core/object_graph_spec.rb +17 -1
- data/spec/core/placeholder_literalizer_spec.rb +128 -0
- data/spec/core/schema_spec.rb +54 -0
- data/spec/extensions/current_datetime_timestamp_spec.rb +27 -0
- data/spec/extensions/defaults_setter_spec.rb +12 -0
- data/spec/extensions/eager_each_spec.rb +6 -0
- data/spec/extensions/nested_attributes_spec.rb +14 -2
- data/spec/extensions/pg_array_spec.rb +15 -7
- data/spec/extensions/shared_caching_spec.rb +5 -5
- data/spec/extensions/timestamps_spec.rb +9 -0
- data/spec/extensions/touch_spec.rb +9 -0
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +27 -5
- data/spec/model/eager_loading_spec.rb +32 -0
- data/spec/model/model_spec.rb +119 -9
- metadata +8 -2
data/lib/sequel/dataset/graph.rb
CHANGED
@@ -90,11 +90,18 @@ module Sequel
|
|
90
90
|
# Only allow table aliases that haven't been used
|
91
91
|
raise_alias_error.call if @opts[:graph] && @opts[:graph][:table_aliases] && @opts[:graph][:table_aliases].include?(table_alias)
|
92
92
|
|
93
|
+
table_alias_qualifier = qualifier_from_alias_symbol(table_alias, table)
|
94
|
+
implicit_qualifier = options[:implicit_qualifier]
|
95
|
+
ds = self
|
96
|
+
|
93
97
|
# Use a from_self if this is already a joined table (or from_self specifically disabled for graphs)
|
94
|
-
|
98
|
+
if (@opts[:graph_from_self] != false && !@opts[:graph] && (@opts[:from].length > 1 || @opts[:join]))
|
99
|
+
implicit_qualifier = options[:from_self_alias] || first_source
|
100
|
+
ds = ds.from_self(:alias=>implicit_qualifier)
|
101
|
+
end
|
95
102
|
|
96
103
|
# Join the table early in order to avoid cloning the dataset twice
|
97
|
-
ds = ds.join_table(options[:join_type] || :left_outer, table, join_conditions, :table_alias=>
|
104
|
+
ds = ds.join_table(options[:join_type] || :left_outer, table, join_conditions, :table_alias=>table_alias_qualifier, :implicit_qualifier=>implicit_qualifier, :qualify=>options[:qualify], &block)
|
98
105
|
opts = ds.opts
|
99
106
|
|
100
107
|
# Whether to include the table in the result set
|
@@ -108,7 +115,8 @@ module Sequel
|
|
108
115
|
select = opts[:select].dup
|
109
116
|
[:column_aliases, :table_aliases, :column_alias_num].each{|k| graph[k] = graph[k].dup}
|
110
117
|
else
|
111
|
-
|
118
|
+
qualifier = ds.first_source_alias
|
119
|
+
master = alias_symbol(qualifier)
|
112
120
|
raise_alias_error.call if master == table_alias
|
113
121
|
# Master hash storing all .graph related information
|
114
122
|
graph = opts[:graph] = {}
|
@@ -143,11 +151,11 @@ module Sequel
|
|
143
151
|
end
|
144
152
|
column_aliases[column] = [master, column]
|
145
153
|
end
|
146
|
-
select = qualified_expression(select,
|
154
|
+
select = qualified_expression(select, qualifier)
|
147
155
|
else
|
148
156
|
select = columns.map do |column|
|
149
157
|
column_aliases[column] = [master, column]
|
150
|
-
SQL::QualifiedIdentifier.new(
|
158
|
+
SQL::QualifiedIdentifier.new(qualifier, column)
|
151
159
|
end
|
152
160
|
end
|
153
161
|
end
|
@@ -179,9 +187,9 @@ module Sequel
|
|
179
187
|
column_alias = :"#{column_alias}_#{column_alias_num}"
|
180
188
|
ca_num[column_alias] += 1
|
181
189
|
end
|
182
|
-
[column_alias, SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(
|
190
|
+
[column_alias, SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(table_alias_qualifier, column), column_alias)]
|
183
191
|
else
|
184
|
-
ident = SQL::QualifiedIdentifier.new(
|
192
|
+
ident = SQL::QualifiedIdentifier.new(table_alias_qualifier, column)
|
185
193
|
[column, ident]
|
186
194
|
end
|
187
195
|
column_aliases[col_alias] = [table_alias, column]
|
@@ -229,6 +237,20 @@ module Sequel
|
|
229
237
|
|
230
238
|
private
|
231
239
|
|
240
|
+
# Wrap the alias symbol in an SQL::Identifier if the identifier on which is based
|
241
|
+
# is an SQL::Identifier. This works around cases where the alias symbol contains
|
242
|
+
# double embedded underscores which would be considered an implicit qualified identifier
|
243
|
+
# if not wrapped in an SQL::Identifier.
|
244
|
+
def qualifier_from_alias_symbol(aliaz, identifier)
|
245
|
+
identifier = identifier.column if identifier.is_a?(SQL::QualifiedIdentifier)
|
246
|
+
case identifier
|
247
|
+
when SQL::Identifier
|
248
|
+
Sequel.identifier(aliaz)
|
249
|
+
else
|
250
|
+
aliaz
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
232
254
|
# Transform the hash of graph aliases and return a two element array
|
233
255
|
# where the first element is an array of identifiers suitable to pass to
|
234
256
|
# a select method, and the second is a new hash of preprocessed graph aliases.
|
data/lib/sequel/dataset/misc.rb
CHANGED
@@ -36,6 +36,12 @@ module Sequel
|
|
36
36
|
o.is_a?(self.class) && db == o.db && opts == o.opts && sql == o.sql
|
37
37
|
end
|
38
38
|
|
39
|
+
# An object representing the current date or time, should be an instance
|
40
|
+
# of Sequel.datetime_class.
|
41
|
+
def current_datetime
|
42
|
+
Sequel.datetime_class.now
|
43
|
+
end
|
44
|
+
|
39
45
|
# Alias for ==
|
40
46
|
def eql?(o)
|
41
47
|
self == o
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Dataset
|
3
|
+
# PlaceholderLiteralizer allows you to record the application of arbitrary changes
|
4
|
+
# to a dataset with placeholder arguments, recording where those placeholder arguments
|
5
|
+
# are used in the query. When running the query, the literalization process is much
|
6
|
+
# faster as Sequel can skip most of the work it normal has to do when literalizing a
|
7
|
+
# dataset.
|
8
|
+
#
|
9
|
+
# Basically, this enables optimizations that allow Sequel to cache the SQL produced
|
10
|
+
# for a given dataset, so that it doesn't need to recompute that information every
|
11
|
+
# time.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# loader = Sequel::Dataset::PlaceholderLiteralizer.loader(DB[:items]) do |pl, ds|
|
16
|
+
# ds.where(:id=>pl.arg).exclude(:name=>pl.arg).limit(1)
|
17
|
+
# end
|
18
|
+
# loader.first(1, "foo")
|
19
|
+
# # SELECT * FROM items WHERE ((id = 1) AND (name != 'foo')) LIMIT 1
|
20
|
+
# loader.first(2, "bar")
|
21
|
+
# # SELECT * FROM items WHERE ((id = 2) AND (name != 'bar')) LIMIT 1
|
22
|
+
#
|
23
|
+
# Caveats:
|
24
|
+
#
|
25
|
+
# Note that this method does not handle all possible cases. For example:
|
26
|
+
#
|
27
|
+
# loader = Sequel::Dataset::PlaceholderLiteralizer.loader(DB[:items]) do |pl, ds|
|
28
|
+
# ds.join(pl.arg, :item_id=>:id)
|
29
|
+
# end
|
30
|
+
# loader(:cart_items)
|
31
|
+
#
|
32
|
+
# Will not qualify the item_id column with cart_items. In this type of situation it's
|
33
|
+
# best to add a table alias when joining:
|
34
|
+
#
|
35
|
+
# loader = Sequel::Dataset::PlaceholderLiteralizer.loader(DB[:items]) do |pl, ds|
|
36
|
+
# ds.join(Sequel.as(pl.arg, :t), :item_id=>:id)
|
37
|
+
# end
|
38
|
+
# loader(:cart_items)
|
39
|
+
#
|
40
|
+
# There are other similar cases that are not handled, mainly when Sequel changes the
|
41
|
+
# SQL produced depending on the types of the arguments.
|
42
|
+
class PlaceholderLiteralizer
|
43
|
+
# A placeholder argument used by the PlaceholderLiteralizer. This records the offset
|
44
|
+
# that the argument should be used in the resulting SQL.
|
45
|
+
class Argument
|
46
|
+
# Set the recorder, the argument position, and any transforming block to use
|
47
|
+
# for this placeholder.
|
48
|
+
def initialize(recorder, pos, transformer=nil)
|
49
|
+
@recorder = recorder
|
50
|
+
@pos = pos
|
51
|
+
@transformer = transformer
|
52
|
+
end
|
53
|
+
|
54
|
+
# Record the SQL query offset, argument position, and transforming block where the
|
55
|
+
# argument should be literalized.
|
56
|
+
def sql_literal_append(ds, sql)
|
57
|
+
@recorder.use(sql, @pos, @transformer)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return a new Argument object for the same recorder and argument position, but with a
|
61
|
+
# different transformer block.
|
62
|
+
def transform(&block)
|
63
|
+
Argument.new(@recorder, @pos, block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Records the offsets at which the placeholder arguments are used in
|
68
|
+
# the SQL query.
|
69
|
+
class Recorder
|
70
|
+
# Yields the receiver and the dataset to the block, which should
|
71
|
+
# call #arg on the receiver for each placeholder argument, and
|
72
|
+
# return the dataset that you want to load.
|
73
|
+
def loader(dataset)
|
74
|
+
@argn = -1
|
75
|
+
@args = []
|
76
|
+
ds = yield self, dataset
|
77
|
+
sql = ds.sql
|
78
|
+
|
79
|
+
last_offset = 0
|
80
|
+
fragments = @args.map do |used_sql, offset, arg, t|
|
81
|
+
raise Error, "placeholder literalizer argument literalized into different string than dataset returned" unless used_sql.equal?(sql)
|
82
|
+
a = [sql[last_offset...offset], arg, t]
|
83
|
+
last_offset = offset
|
84
|
+
a
|
85
|
+
end
|
86
|
+
final_sql = sql[last_offset..-1]
|
87
|
+
|
88
|
+
arity = @argn+1
|
89
|
+
PlaceholderLiteralizer.new(ds.clone, fragments, final_sql, arity)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Return an Argument with the specified position, or the next position. In
|
93
|
+
# general you shouldn't mix calls with an argument and calls without an
|
94
|
+
# argument for the same receiver.
|
95
|
+
def arg(v=(no_arg_given = true; @argn+=1))
|
96
|
+
unless no_arg_given
|
97
|
+
@argn = v if @argn < v
|
98
|
+
end
|
99
|
+
Argument.new(self, v)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Record the offset at which the argument is used in the SQL query, and any
|
103
|
+
# transforming
|
104
|
+
def use(sql, arg, transformer)
|
105
|
+
@args << [sql, sql.length, arg, transformer]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create a PlaceholderLiteralizer by yielding a Recorder and dataset to the
|
110
|
+
# given block, recording the offsets at which the recorders arguments
|
111
|
+
# are used in the query.
|
112
|
+
def self.loader(dataset, &block)
|
113
|
+
Recorder.new.loader(dataset, &block)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Save the dataset, array of SQL fragments, and ending SQL string.
|
117
|
+
def initialize(dataset, fragments, final_sql, arity)
|
118
|
+
@dataset = dataset
|
119
|
+
@fragments = fragments
|
120
|
+
@final_sql = final_sql
|
121
|
+
@arity = arity
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return an array of all objects by running the SQL query for the given arguments.
|
125
|
+
# If a block is given, yields all objects to the block after loading them.
|
126
|
+
def all(*args, &block)
|
127
|
+
@dataset.with_sql_all(sql(*args), &block)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Run the SQL query for the given arguments, yielding each returned row to the block.
|
131
|
+
def each(*args, &block)
|
132
|
+
@dataset.with_sql_each(sql(*args), &block)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Run the SQL query for the given arguments, returning the first row.
|
136
|
+
def first(*args)
|
137
|
+
@dataset.with_sql_first(sql(*args))
|
138
|
+
end
|
139
|
+
|
140
|
+
# Run the SQL query for the given arguments, returning the first value. For this to
|
141
|
+
# make sense, the dataset should return a single row with a single value (or no rows).
|
142
|
+
def get(*args)
|
143
|
+
@dataset.with_sql_single_value(sql(*args))
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return the SQL query to use for the given arguments.
|
147
|
+
def sql(*args)
|
148
|
+
raise Error, "wrong number of arguments (#{args.length} for #{@arity})" unless args.length == @arity
|
149
|
+
s = ''
|
150
|
+
ds = @dataset
|
151
|
+
@fragments.each do |sql, i, transformer|
|
152
|
+
s << sql
|
153
|
+
v = args.fetch(i)
|
154
|
+
v = transformer.call(v) if transformer
|
155
|
+
ds.literal_append(s, v)
|
156
|
+
end
|
157
|
+
if sql = @final_sql
|
158
|
+
s << sql
|
159
|
+
end
|
160
|
+
s
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
data/lib/sequel/dataset/query.rb
CHANGED
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -62,15 +62,8 @@ module Sequel
|
|
62
62
|
clone(:columns=>columns, :values=>values)._insert_sql
|
63
63
|
end
|
64
64
|
|
65
|
-
#
|
66
|
-
# of an SQL expression.
|
65
|
+
# Append a literal representation of a value to the given SQL string.
|
67
66
|
#
|
68
|
-
# DB[:items].literal("abc'def\\") #=> "'abc''def\\\\'"
|
69
|
-
# DB[:items].literal(:items__id) #=> "items.id"
|
70
|
-
# DB[:items].literal([1, 2, 3]) => "(1, 2, 3)"
|
71
|
-
# DB[:items].literal(DB[:items]) => "(SELECT * FROM items)"
|
72
|
-
# DB[:items].literal(:x + 1 > :y) => "((x + 1) > y)"
|
73
|
-
#
|
74
67
|
# If an unsupported object is given, an +Error+ is raised.
|
75
68
|
def literal_append(sql, v)
|
76
69
|
case v
|
@@ -104,9 +97,9 @@ module Sequel
|
|
104
97
|
when Array
|
105
98
|
literal_array_append(sql, v)
|
106
99
|
when Time
|
107
|
-
|
100
|
+
v.is_a?(SQLTime) ? literal_sqltime_append(sql, v) : literal_time_append(sql, v)
|
108
101
|
when DateTime
|
109
|
-
sql
|
102
|
+
literal_datetime_append(sql, v)
|
110
103
|
when Date
|
111
104
|
sql << literal_date(v)
|
112
105
|
when Dataset
|
@@ -190,6 +183,9 @@ module Sequel
|
|
190
183
|
AS = ' AS '.freeze
|
191
184
|
ASC = ' ASC'.freeze
|
192
185
|
BACKSLASH = "\\".freeze
|
186
|
+
BITCOMP_CLOSE = ") - 1)".freeze
|
187
|
+
BITCOMP_OPEN = "((0 - ".freeze
|
188
|
+
BITWISE_METHOD_MAP = {:& =>:BITAND, :| => :BITOR, :^ => :BITXOR}
|
193
189
|
BOOL_FALSE = "'f'".freeze
|
194
190
|
BOOL_TRUE = "'t'".freeze
|
195
191
|
BRACKET_CLOSE = ']'.freeze
|
@@ -295,13 +291,13 @@ module Sequel
|
|
295
291
|
END
|
296
292
|
end
|
297
293
|
|
298
|
-
#
|
294
|
+
# Append literalization of aliased expression to SQL string.
|
299
295
|
def aliased_expression_sql_append(sql, ae)
|
300
296
|
literal_append(sql, ae.expression)
|
301
297
|
as_sql_append(sql, ae.alias)
|
302
298
|
end
|
303
299
|
|
304
|
-
#
|
300
|
+
# Append literalization of array to SQL string.
|
305
301
|
def array_sql_append(sql, a)
|
306
302
|
if a.empty?
|
307
303
|
sql << ARRAY_EMPTY
|
@@ -312,7 +308,7 @@ module Sequel
|
|
312
308
|
end
|
313
309
|
end
|
314
310
|
|
315
|
-
#
|
311
|
+
# Append literalization of boolean constant to SQL string.
|
316
312
|
def boolean_constant_sql_append(sql, constant)
|
317
313
|
if (constant == true || constant == false) && !supports_where_true?
|
318
314
|
sql << (constant == true ? CONDITION_TRUE : CONDITION_FALSE)
|
@@ -321,7 +317,7 @@ module Sequel
|
|
321
317
|
end
|
322
318
|
end
|
323
319
|
|
324
|
-
#
|
320
|
+
# Append literalization of case expression to SQL string.
|
325
321
|
def case_expression_sql_append(sql, ce)
|
326
322
|
sql << CASE_OPEN
|
327
323
|
if ce.expression?
|
@@ -341,7 +337,7 @@ module Sequel
|
|
341
337
|
sql << CASE_END
|
342
338
|
end
|
343
339
|
|
344
|
-
#
|
340
|
+
# Append literalization of cast expression to SQL string.
|
345
341
|
def cast_sql_append(sql, expr, type)
|
346
342
|
sql << CAST_OPEN
|
347
343
|
literal_append(sql, expr)
|
@@ -349,12 +345,12 @@ module Sequel
|
|
349
345
|
sql << PAREN_CLOSE
|
350
346
|
end
|
351
347
|
|
352
|
-
#
|
348
|
+
# Append literalization of column all selection to SQL string.
|
353
349
|
def column_all_sql_append(sql, ca)
|
354
350
|
qualified_identifier_sql_append(sql, ca.table, WILDCARD)
|
355
351
|
end
|
356
352
|
|
357
|
-
#
|
353
|
+
# Append literalization of complex expression to SQL string.
|
358
354
|
def complex_expression_sql_append(sql, op, args)
|
359
355
|
case op
|
360
356
|
when *IS_OPERATORS
|
@@ -459,18 +455,18 @@ module Sequel
|
|
459
455
|
end
|
460
456
|
end
|
461
457
|
|
462
|
-
#
|
458
|
+
# Append literalization of constant to SQL string.
|
463
459
|
def constant_sql_append(sql, constant)
|
464
460
|
sql << constant.to_s
|
465
461
|
end
|
466
462
|
|
467
|
-
#
|
468
|
-
#
|
463
|
+
# Append literalization of delayed evaluation to SQL string,
|
464
|
+
# causing the delayed evaluation proc to be evaluated.
|
469
465
|
def delayed_evaluation_sql_append(sql, callable)
|
470
466
|
literal_append(sql, callable.call)
|
471
467
|
end
|
472
468
|
|
473
|
-
#
|
469
|
+
# Append literalization of emulated function call to SQL string.
|
474
470
|
# By default, assumes just the function name may need to
|
475
471
|
# be emulated, adapters should set an EMULATED_FUNCTION_MAP
|
476
472
|
# hash mapping emulated functions to native functions in
|
@@ -479,12 +475,12 @@ module Sequel
|
|
479
475
|
_function_sql_append(sql, native_function_name(f.f), f.args)
|
480
476
|
end
|
481
477
|
|
482
|
-
#
|
478
|
+
# Append literalization of function call to SQL string.
|
483
479
|
def function_sql_append(sql, f)
|
484
480
|
_function_sql_append(sql, f.f, f.args)
|
485
481
|
end
|
486
482
|
|
487
|
-
#
|
483
|
+
# Append literalization of JOIN clause without ON or USING to SQL string.
|
488
484
|
def join_clause_sql_append(sql, jc)
|
489
485
|
table = jc.table
|
490
486
|
table_alias = jc.table_alias
|
@@ -494,14 +490,14 @@ module Sequel
|
|
494
490
|
as_sql_append(sql, table_alias) if table_alias
|
495
491
|
end
|
496
492
|
|
497
|
-
#
|
493
|
+
# Append literalization of JOIN ON clause to SQL string.
|
498
494
|
def join_on_clause_sql_append(sql, jc)
|
499
495
|
join_clause_sql_append(sql, jc)
|
500
496
|
sql << ON
|
501
497
|
literal_append(sql, filter_expr(jc.on))
|
502
498
|
end
|
503
499
|
|
504
|
-
#
|
500
|
+
# Append literalization of JOIN USING clause to SQL string.
|
505
501
|
def join_using_clause_sql_append(sql, jc)
|
506
502
|
join_clause_sql_append(sql, jc)
|
507
503
|
sql << USING
|
@@ -509,14 +505,13 @@ module Sequel
|
|
509
505
|
sql << PAREN_CLOSE
|
510
506
|
end
|
511
507
|
|
512
|
-
#
|
508
|
+
# Append literalization of negative boolean constant to SQL string.
|
513
509
|
def negative_boolean_constant_sql_append(sql, constant)
|
514
510
|
sql << NOT_SPACE
|
515
511
|
boolean_constant_sql_append(sql, constant)
|
516
512
|
end
|
517
513
|
|
518
|
-
#
|
519
|
-
# clause.
|
514
|
+
# Append literalization of ordered expression to SQL string.
|
520
515
|
def ordered_expression_sql_append(sql, oe)
|
521
516
|
literal_append(sql, oe.expression)
|
522
517
|
sql << (oe.descending ? DESC : ASC)
|
@@ -528,7 +523,7 @@ module Sequel
|
|
528
523
|
end
|
529
524
|
end
|
530
525
|
|
531
|
-
#
|
526
|
+
# Append literalization of placeholder literal string to SQL string.
|
532
527
|
def placeholder_literal_string_sql_append(sql, pls)
|
533
528
|
args = pls.args
|
534
529
|
str = pls.str
|
@@ -572,8 +567,7 @@ module Sequel
|
|
572
567
|
sql << PAREN_CLOSE if pls.parens
|
573
568
|
end
|
574
569
|
|
575
|
-
#
|
576
|
-
# a table and a column (or schema and table).
|
570
|
+
# Append literalization of qualified identifier to SQL string.
|
577
571
|
# If 3 arguments are given, the 2nd should be the table/qualifier and the third should be
|
578
572
|
# column/qualified. If 2 arguments are given, the 2nd should be an SQL::QualifiedIdentifier.
|
579
573
|
def qualified_identifier_sql_append(sql, table, column=(c = table.column; table = table.table; c))
|
@@ -582,6 +576,7 @@ module Sequel
|
|
582
576
|
identifier_append(sql, column)
|
583
577
|
end
|
584
578
|
|
579
|
+
# Append literalization of unqualified identifier to SQL string.
|
585
580
|
# Adds quoting to identifiers (columns and tables). If identifiers are not
|
586
581
|
# being quoted, returns name as a string. If identifiers are being quoted
|
587
582
|
# quote the name with quoted_identifier.
|
@@ -599,8 +594,7 @@ module Sequel
|
|
599
594
|
end
|
600
595
|
end
|
601
596
|
|
602
|
-
#
|
603
|
-
# quoted (if quoting identifiers)
|
597
|
+
# Append literalization of identifier or unqualified identifier to SQL string.
|
604
598
|
def quote_schema_table_append(sql, table)
|
605
599
|
schema, table = schema_and_table(table)
|
606
600
|
if schema
|
@@ -610,6 +604,7 @@ module Sequel
|
|
610
604
|
quote_identifier_append(sql, table)
|
611
605
|
end
|
612
606
|
|
607
|
+
# Append literalization of quoted identifier to SQL string.
|
613
608
|
# This method quotes the given name with the SQL standard double quote.
|
614
609
|
# should be overridden by subclasses to provide quoting not matching the
|
615
610
|
# SQL standard, such as backtick (used by MySQL and SQLite).
|
@@ -657,7 +652,7 @@ module Sequel
|
|
657
652
|
end
|
658
653
|
end
|
659
654
|
|
660
|
-
#
|
655
|
+
# Append literalization of subscripts (SQL array accesses) to SQL string.
|
661
656
|
def subscript_sql_append(sql, s)
|
662
657
|
literal_append(sql, s.f)
|
663
658
|
sql << BRACKET_OPEN
|
@@ -673,7 +668,7 @@ module Sequel
|
|
673
668
|
sql << BRACKET_CLOSE
|
674
669
|
end
|
675
670
|
|
676
|
-
#
|
671
|
+
# Append literalization of windows (for window functions) to SQL string.
|
677
672
|
def window_sql_append(sql, opts)
|
678
673
|
raise(Error, 'This dataset does not support window functions') unless supports_window_functions?
|
679
674
|
sql << PAREN_OPEN
|
@@ -714,7 +709,7 @@ module Sequel
|
|
714
709
|
sql << PAREN_CLOSE
|
715
710
|
end
|
716
711
|
|
717
|
-
#
|
712
|
+
# Append literalization of window function calls to SQL string.
|
718
713
|
def window_function_sql_append(sql, function, window)
|
719
714
|
literal_append(sql, function)
|
720
715
|
sql << OVER
|
@@ -815,7 +810,7 @@ module Sequel
|
|
815
810
|
options_overlap(COUNT_FROM_SELF_OPTS) ? from_self : unordered
|
816
811
|
end
|
817
812
|
|
818
|
-
#
|
813
|
+
# Append aliasing expression to SQL string.
|
819
814
|
def as_sql_append(sql, aliaz)
|
820
815
|
sql << AS
|
821
816
|
quote_identifier_append(sql, aliaz)
|
@@ -840,6 +835,7 @@ module Sequel
|
|
840
835
|
sql
|
841
836
|
end
|
842
837
|
|
838
|
+
# Append column list to SQL string.
|
843
839
|
# Converts an array of column names into a comma seperated string of
|
844
840
|
# column names. If the array is empty, a wildcard (*) is returned.
|
845
841
|
def column_list_append(sql, columns)
|
@@ -850,24 +846,50 @@ module Sequel
|
|
850
846
|
end
|
851
847
|
end
|
852
848
|
|
853
|
-
# Yield each
|
854
|
-
# return
|
855
|
-
# two arguments.
|
856
|
-
#
|
857
|
-
# as the first argument, representing the application of the block to
|
858
|
-
# the previous arguments.
|
849
|
+
# Yield each pair of arguments to the block, which should
|
850
|
+
# return an object representing the SQL expression for those
|
851
|
+
# two arguments. For more than two arguments, the first
|
852
|
+
# argument to the block will be result of the previous block call.
|
859
853
|
def complex_expression_arg_pairs(args)
|
860
854
|
case args.length
|
861
855
|
when 1
|
862
|
-
|
856
|
+
args.at(0)
|
863
857
|
when 2
|
864
858
|
yield args.at(0), args.at(1)
|
865
859
|
else
|
866
|
-
args.inject{|m, a|
|
860
|
+
args.inject{|m, a| yield(m, a)}
|
861
|
+
end
|
862
|
+
end
|
863
|
+
|
864
|
+
# Append the literalization of the args using complex_expression_arg_pairs
|
865
|
+
# to the given SQL string, used when database operator/function is 2-ary
|
866
|
+
# where Sequel expression is N-ary.
|
867
|
+
def complex_expression_arg_pairs_append(sql, args, &block)
|
868
|
+
literal_append(sql, complex_expression_arg_pairs(args, &block))
|
869
|
+
end
|
870
|
+
|
871
|
+
# Append literalization of complex expression to SQL string, for
|
872
|
+
# operators unsupported by some databases. Used by adapters for databases
|
873
|
+
# that don't support the operators natively.
|
874
|
+
def complex_expression_emulate_append(sql, op, args)
|
875
|
+
case op
|
876
|
+
when :%
|
877
|
+
complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.function(:MOD, a, b)}
|
878
|
+
when :>>
|
879
|
+
complex_expression_arg_pairs_append(sql, args){|a, b| Sequel./(a, Sequel.function(:power, 2, b))}
|
880
|
+
when :<<
|
881
|
+
complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.*(a, Sequel.function(:power, 2, b))}
|
882
|
+
when :&, :|, :^
|
883
|
+
f = BITWISE_METHOD_MAP[op]
|
884
|
+
complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.function(f, a, b)}
|
885
|
+
when :'B~'
|
886
|
+
sql << BITCOMP_OPEN
|
887
|
+
literal_append(sql, args.at(0))
|
888
|
+
sql << BITCOMP_CLOSE
|
867
889
|
end
|
868
890
|
end
|
869
891
|
|
870
|
-
#
|
892
|
+
# Append literalization of dataset used in UNION/INTERSECT/EXCEPT clause to SQL string.
|
871
893
|
def compound_dataset_sql_append(sql, ds)
|
872
894
|
subselect_sql_append(sql, ds)
|
873
895
|
end
|
@@ -891,8 +913,7 @@ module Sequel
|
|
891
913
|
sql << DELETE
|
892
914
|
end
|
893
915
|
|
894
|
-
#
|
895
|
-
# expressions.
|
916
|
+
# Append literalization of array of expressions to SQL string.
|
896
917
|
def expression_list_append(sql, columns)
|
897
918
|
c = false
|
898
919
|
co = COMMA
|
@@ -941,8 +962,8 @@ module Sequel
|
|
941
962
|
sprintf(FORMAT_TIMESTAMP_USEC, usec)
|
942
963
|
end
|
943
964
|
|
944
|
-
# Append
|
945
|
-
#
|
965
|
+
# Append literalization of identifier to SQL string, considering regular strings
|
966
|
+
# as SQL identifiers instead of SQL strings.
|
946
967
|
def identifier_append(sql, v)
|
947
968
|
if v.is_a?(String)
|
948
969
|
case v
|
@@ -958,7 +979,7 @@ module Sequel
|
|
958
979
|
end
|
959
980
|
end
|
960
981
|
|
961
|
-
# Append
|
982
|
+
# Append literalization of array of identifiers to SQL string.
|
962
983
|
def identifier_list_append(sql, args)
|
963
984
|
c = false
|
964
985
|
comma = COMMA
|
@@ -975,7 +996,6 @@ module Sequel
|
|
975
996
|
(i = identifier_input_method) ? v.to_s.send(i) : v.to_s
|
976
997
|
end
|
977
998
|
|
978
|
-
# SQL fragment specifying the table to insert INTO
|
979
999
|
def insert_into_sql(sql)
|
980
1000
|
sql << INTO
|
981
1001
|
source_list_append(sql, @opts[:from])
|
@@ -986,7 +1006,6 @@ module Sequel
|
|
986
1006
|
INSERT_CLAUSE_METHODS
|
987
1007
|
end
|
988
1008
|
|
989
|
-
# SQL fragment specifying the columns to insert into
|
990
1009
|
def insert_columns_sql(sql)
|
991
1010
|
columns = opts[:columns]
|
992
1011
|
if columns && !columns.empty?
|
@@ -1000,7 +1019,6 @@ module Sequel
|
|
1000
1019
|
sql << INSERT
|
1001
1020
|
end
|
1002
1021
|
|
1003
|
-
# SQL fragment specifying the values to insert.
|
1004
1022
|
def insert_values_sql(sql)
|
1005
1023
|
case values = opts[:values]
|
1006
1024
|
when Array
|
@@ -1020,7 +1038,6 @@ module Sequel
|
|
1020
1038
|
end
|
1021
1039
|
end
|
1022
1040
|
|
1023
|
-
# SQL fragment specifying the values to return.
|
1024
1041
|
def insert_returning_sql(sql)
|
1025
1042
|
if opts.has_key?(:returning)
|
1026
1043
|
sql << RETURNING
|
@@ -1041,7 +1058,8 @@ module Sequel
|
|
1041
1058
|
(opts[:from].is_a?(Array) && opts[:from].size > 1) || opts[:join]
|
1042
1059
|
end
|
1043
1060
|
|
1044
|
-
#
|
1061
|
+
# Append a literalization of the array to SQL string.
|
1062
|
+
# Treats as an expression if an array of all two pairs, or as a SQL array otherwise.
|
1045
1063
|
def literal_array_append(sql, v)
|
1046
1064
|
if Sequel.condition_specifier?(v)
|
1047
1065
|
literal_expression_append(sql, SQL::BooleanExpression.from_value_pairs(v))
|
@@ -1056,12 +1074,12 @@ module Sequel
|
|
1056
1074
|
v.nan? || v.infinite? ? "'#{d}'" : d
|
1057
1075
|
end
|
1058
1076
|
|
1059
|
-
#
|
1077
|
+
# Append literalization of SQL::Blob to SQL string.
|
1060
1078
|
def literal_blob_append(sql, v)
|
1061
1079
|
literal_string_append(sql, v)
|
1062
1080
|
end
|
1063
1081
|
|
1064
|
-
#
|
1082
|
+
# Append literalization of dataset to SQL string. Does a subselect inside parantheses.
|
1065
1083
|
def literal_dataset_append(sql, v)
|
1066
1084
|
sql << LATERAL if v.opts[:lateral]
|
1067
1085
|
sql << PAREN_OPEN
|
@@ -1083,7 +1101,12 @@ module Sequel
|
|
1083
1101
|
format_timestamp(v)
|
1084
1102
|
end
|
1085
1103
|
|
1086
|
-
#
|
1104
|
+
# Append literalization of DateTime to SQL string.
|
1105
|
+
def literal_datetime_append(sql, v)
|
1106
|
+
sql << literal_datetime(v)
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
# Append literalization of SQL::Expression to SQL string.
|
1087
1110
|
def literal_expression_append(sql, v)
|
1088
1111
|
v.to_s_append(self, sql)
|
1089
1112
|
end
|
@@ -1098,7 +1121,7 @@ module Sequel
|
|
1098
1121
|
v.to_s
|
1099
1122
|
end
|
1100
1123
|
|
1101
|
-
#
|
1124
|
+
# Append literalization of Hash to SQL string, treating hash as a boolean expression.
|
1102
1125
|
def literal_hash_append(sql, v)
|
1103
1126
|
literal_expression_append(sql, SQL::BooleanExpression.from_value_pairs(v))
|
1104
1127
|
end
|
@@ -1113,11 +1136,9 @@ module Sequel
|
|
1113
1136
|
NULL
|
1114
1137
|
end
|
1115
1138
|
|
1116
|
-
#
|
1117
|
-
# Calls +
|
1118
|
-
#
|
1119
|
-
# provided and should add that method to Sequel::Dataset, allowing for adapters
|
1120
|
-
# to provide customized literalizations.
|
1139
|
+
# Append a literalization of the object to the given SQL string.
|
1140
|
+
# Calls +sql_literal_append+ if object responds to it, otherwise
|
1141
|
+
# calls +sql_literal+ if object responds to it, otherwise raises an error.
|
1121
1142
|
# If a database specific type is allowed, this should be overriden in a subclass.
|
1122
1143
|
def literal_other_append(sql, v)
|
1123
1144
|
if v.respond_to?(:sql_literal_append)
|
@@ -1134,19 +1155,17 @@ module Sequel
|
|
1134
1155
|
v.strftime("'%H:%M:%S#{format_timestamp_usec(v.usec) if supports_timestamp_usecs?}'")
|
1135
1156
|
end
|
1136
1157
|
|
1137
|
-
#
|
1158
|
+
# Append literalization of Sequel::SQLTime to SQL string.
|
1159
|
+
def literal_sqltime_append(sql, v)
|
1160
|
+
sql << literal_sqltime(v)
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
# Append literalization of string to SQL string.
|
1138
1164
|
def literal_string_append(sql, v)
|
1139
1165
|
sql << APOS << v.gsub(APOS_RE, DOUBLE_APOS) << APOS
|
1140
1166
|
end
|
1141
1167
|
|
1142
|
-
#
|
1143
|
-
# notation in order to express qualified (two underscores) and aliased
|
1144
|
-
# (three underscores) columns:
|
1145
|
-
#
|
1146
|
-
# dataset.literal(:abc) #=> "abc"
|
1147
|
-
# dataset.literal(:abc___a) #=> "abc AS a"
|
1148
|
-
# dataset.literal(:items__abc) #=> "items.abc"
|
1149
|
-
# dataset.literal(:items__abc___a) #=> "items.abc AS a"
|
1168
|
+
# Append literalization of symbol to SQL string.
|
1150
1169
|
def literal_symbol_append(sql, v)
|
1151
1170
|
c_table, column, c_alias = split_symbol(v)
|
1152
1171
|
if c_table
|
@@ -1162,6 +1181,11 @@ module Sequel
|
|
1162
1181
|
format_timestamp(v)
|
1163
1182
|
end
|
1164
1183
|
|
1184
|
+
# Append literalization of Time to SQL string.
|
1185
|
+
def literal_time_append(sql, v)
|
1186
|
+
sql << literal_time(v)
|
1187
|
+
end
|
1188
|
+
|
1165
1189
|
# SQL fragment for true
|
1166
1190
|
def literal_true
|
1167
1191
|
BOOL_TRUE
|
@@ -1203,13 +1227,11 @@ module Sequel
|
|
1203
1227
|
SELECT_CLAUSE_METHODS
|
1204
1228
|
end
|
1205
1229
|
|
1206
|
-
# Modify the sql to add the columns selected
|
1207
1230
|
def select_columns_sql(sql)
|
1208
1231
|
sql << SPACE
|
1209
1232
|
column_list_append(sql, @opts[:select])
|
1210
1233
|
end
|
1211
1234
|
|
1212
|
-
# Modify the sql to add the DISTINCT modifier
|
1213
1235
|
def select_distinct_sql(sql)
|
1214
1236
|
if distinct = @opts[:distinct]
|
1215
1237
|
sql << DISTINCT
|
@@ -1234,7 +1256,6 @@ module Sequel
|
|
1234
1256
|
end
|
1235
1257
|
end
|
1236
1258
|
|
1237
|
-
# Modify the sql to add the list of tables to select FROM
|
1238
1259
|
def select_from_sql(sql)
|
1239
1260
|
if f = @opts[:from]
|
1240
1261
|
sql << FROM
|
@@ -1243,7 +1264,6 @@ module Sequel
|
|
1243
1264
|
end
|
1244
1265
|
alias delete_from_sql select_from_sql
|
1245
1266
|
|
1246
|
-
# Modify the sql to add the expressions to GROUP BY
|
1247
1267
|
def select_group_sql(sql)
|
1248
1268
|
if group = @opts[:group]
|
1249
1269
|
sql << GROUP_BY
|
@@ -1262,7 +1282,6 @@ module Sequel
|
|
1262
1282
|
end
|
1263
1283
|
end
|
1264
1284
|
|
1265
|
-
# Modify the sql to add the filter criteria in the HAVING clause
|
1266
1285
|
def select_having_sql(sql)
|
1267
1286
|
if having = @opts[:having]
|
1268
1287
|
sql << HAVING
|
@@ -1270,14 +1289,12 @@ module Sequel
|
|
1270
1289
|
end
|
1271
1290
|
end
|
1272
1291
|
|
1273
|
-
# Modify the sql to add the list of tables to JOIN to
|
1274
1292
|
def select_join_sql(sql)
|
1275
1293
|
if js = @opts[:join]
|
1276
1294
|
js.each{|j| literal_append(sql, j)}
|
1277
1295
|
end
|
1278
1296
|
end
|
1279
1297
|
|
1280
|
-
# Modify the sql to limit the number of rows returned and offset
|
1281
1298
|
def select_limit_sql(sql)
|
1282
1299
|
if l = @opts[:limit]
|
1283
1300
|
sql << LIMIT
|
@@ -1289,7 +1306,6 @@ module Sequel
|
|
1289
1306
|
end
|
1290
1307
|
end
|
1291
1308
|
|
1292
|
-
# Modify the sql to support the different types of locking modes.
|
1293
1309
|
def select_lock_sql(sql)
|
1294
1310
|
case l = @opts[:lock]
|
1295
1311
|
when :update
|
@@ -1299,7 +1315,6 @@ module Sequel
|
|
1299
1315
|
end
|
1300
1316
|
end
|
1301
1317
|
|
1302
|
-
# Modify the sql to add the expressions to ORDER BY
|
1303
1318
|
def select_order_sql(sql)
|
1304
1319
|
if o = @opts[:order]
|
1305
1320
|
sql << ORDER_BY
|
@@ -1313,7 +1328,6 @@ module Sequel
|
|
1313
1328
|
sql << SELECT
|
1314
1329
|
end
|
1315
1330
|
|
1316
|
-
# Modify the sql to add the filter criteria in the WHERE clause
|
1317
1331
|
def select_where_sql(sql)
|
1318
1332
|
if w = @opts[:where]
|
1319
1333
|
sql << WHERE
|
@@ -1323,7 +1337,6 @@ module Sequel
|
|
1323
1337
|
alias delete_where_sql select_where_sql
|
1324
1338
|
alias update_where_sql select_where_sql
|
1325
1339
|
|
1326
|
-
# SQL Fragment specifying the WITH clause
|
1327
1340
|
def select_with_sql(sql)
|
1328
1341
|
ws = opts[:with]
|
1329
1342
|
return if !ws || ws.empty?
|
@@ -1353,7 +1366,8 @@ module Sequel
|
|
1353
1366
|
SQL_WITH
|
1354
1367
|
end
|
1355
1368
|
|
1356
|
-
#
|
1369
|
+
# Append literalization of array of sources/tables to SQL string, raising an Error if there
|
1370
|
+
# are no sources.
|
1357
1371
|
def source_list_append(sql, sources)
|
1358
1372
|
raise(Error, 'No source specified for query') if sources.nil? || sources == []
|
1359
1373
|
identifier_list_append(sql, sources)
|
@@ -1372,7 +1386,8 @@ module Sequel
|
|
1372
1386
|
|
1373
1387
|
# SQL to use if this dataset uses static SQL. Since static SQL
|
1374
1388
|
# can be a PlaceholderLiteralString in addition to a String,
|
1375
|
-
# we literalize nonstrings.
|
1389
|
+
# we literalize nonstrings. If there is an append_sql for this
|
1390
|
+
# dataset, append to that SQL instead of returning the value.
|
1376
1391
|
def static_sql(sql)
|
1377
1392
|
if append_sql = @opts[:append_sql]
|
1378
1393
|
if sql.is_a?(String)
|
@@ -1389,7 +1404,7 @@ module Sequel
|
|
1389
1404
|
end
|
1390
1405
|
end
|
1391
1406
|
|
1392
|
-
#
|
1407
|
+
# Append literalization of the subselect to SQL String.
|
1393
1408
|
def subselect_sql_append(sql, ds)
|
1394
1409
|
ds.clone(:append_sql=>sql).sql
|
1395
1410
|
end
|
@@ -1399,15 +1414,12 @@ module Sequel
|
|
1399
1414
|
UPDATE_CLAUSE_METHODS
|
1400
1415
|
end
|
1401
1416
|
|
1402
|
-
# SQL fragment specifying the tables from with to delete.
|
1403
|
-
# Includes join table if modifying joins is allowed.
|
1404
1417
|
def update_table_sql(sql)
|
1405
1418
|
sql << SPACE
|
1406
1419
|
source_list_append(sql, @opts[:from])
|
1407
1420
|
select_join_sql(sql) if supports_modifying_joins?
|
1408
1421
|
end
|
1409
1422
|
|
1410
|
-
# The SQL fragment specifying the columns and values to SET.
|
1411
1423
|
def update_set_sql(sql)
|
1412
1424
|
values = opts[:values]
|
1413
1425
|
sql << SET
|