sequel 3.21.0 → 3.31.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 +485 -3
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +249 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +89 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +129 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +5 -7
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +45 -0
- data/lib/sequel/adapters/jdbc/derby.rb +247 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +56 -29
- data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
- data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
- data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +231 -78
- data/lib/sequel/adapters/mock.rb +335 -0
- data/lib/sequel/adapters/mysql.rb +82 -184
- data/lib/sequel/adapters/mysql2.rb +26 -25
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +1 -6
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +351 -53
- data/lib/sequel/adapters/postgres.rb +194 -33
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +321 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +231 -106
- data/lib/sequel/adapters/shared/mysql.rb +181 -63
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +231 -41
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +4 -7
- data/lib/sequel/adapters/shared/sqlite.rb +201 -57
- data/lib/sequel/adapters/sqlite.rb +29 -21
- data/lib/sequel/adapters/swift/mysql.rb +12 -7
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +160 -19
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +104 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +231 -76
- data/lib/sequel/dataset/features.rb +91 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +48 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +665 -253
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1020 -337
- data/lib/sequel/model/base.rb +414 -132
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +88 -44
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +109 -52
- data/lib/sequel/timezones.rb +57 -38
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +111 -29
- data/spec/adapters/mysql_spec.rb +135 -123
- data/spec/adapters/oracle_spec.rb +49 -77
- data/spec/adapters/postgres_spec.rb +267 -78
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +21 -30
- data/spec/core/database_spec.rb +788 -512
- data/spec/core/dataset_spec.rb +1073 -1053
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +419 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +114 -22
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +53 -0
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/migration_spec.rb +35 -32
- data/spec/extensions/named_timezones_spec.rb +23 -3
- data/spec/extensions/nested_attributes_spec.rb +97 -88
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +53 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +5 -8
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +72 -43
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +18 -29
- data/spec/extensions/spec_helper.rb +13 -61
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +4 -7
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +537 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +461 -65
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +212 -122
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +865 -662
- data/spec/model/base_spec.rb +275 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +309 -67
- data/spec/model/model_spec.rb +222 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +381 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +115 -73
data/lib/sequel/dataset/sql.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
class Dataset
|
|
3
3
|
# ---------------------
|
|
4
|
-
# :section: User Methods relating to SQL Creation
|
|
4
|
+
# :section: 3 - User Methods relating to SQL Creation
|
|
5
5
|
# These are methods you can call to see what SQL will be generated by the dataset.
|
|
6
6
|
# ---------------------
|
|
7
7
|
|
|
@@ -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
|
-
|
|
23
|
+
SQL::PlaceholderLiteralString.new("EXISTS ?", [self], true)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# Returns an INSERT SQL query string. See +insert+.
|
|
@@ -61,7 +61,10 @@ module Sequel
|
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
if values.is_a?(Array) && values.empty? && !insert_supports_empty_values?
|
|
65
|
+
columns = [columns().last]
|
|
66
|
+
values = ['DEFAULT'.lit]
|
|
67
|
+
end
|
|
65
68
|
clone(:columns=>columns, :values=>values)._insert_sql
|
|
66
69
|
end
|
|
67
70
|
|
|
@@ -75,41 +78,47 @@ module Sequel
|
|
|
75
78
|
# DB[:items].literal(:x + 1 > :y) => "((x + 1) > y)"
|
|
76
79
|
#
|
|
77
80
|
# If an unsupported object is given, an +Error+ is raised.
|
|
78
|
-
def
|
|
81
|
+
def literal_append(sql, v)
|
|
79
82
|
case v
|
|
80
|
-
when String
|
|
81
|
-
return v if v.is_a?(LiteralString)
|
|
82
|
-
v.is_a?(SQL::Blob) ? literal_blob(v) : literal_string(v)
|
|
83
83
|
when Symbol
|
|
84
|
-
|
|
84
|
+
literal_symbol_append(sql, v)
|
|
85
|
+
when String
|
|
86
|
+
case v
|
|
87
|
+
when LiteralString
|
|
88
|
+
sql << v
|
|
89
|
+
when SQL::Blob
|
|
90
|
+
literal_blob_append(sql, v)
|
|
91
|
+
else
|
|
92
|
+
literal_string_append(sql, v)
|
|
93
|
+
end
|
|
85
94
|
when Integer
|
|
86
|
-
literal_integer(v)
|
|
95
|
+
sql << literal_integer(v)
|
|
87
96
|
when Hash
|
|
88
|
-
|
|
97
|
+
literal_hash_append(sql, v)
|
|
89
98
|
when SQL::Expression
|
|
90
|
-
|
|
99
|
+
literal_expression_append(sql, v)
|
|
91
100
|
when Float
|
|
92
|
-
literal_float(v)
|
|
101
|
+
sql << literal_float(v)
|
|
93
102
|
when BigDecimal
|
|
94
|
-
literal_big_decimal(v)
|
|
103
|
+
sql << literal_big_decimal(v)
|
|
95
104
|
when NilClass
|
|
96
|
-
literal_nil
|
|
105
|
+
sql << literal_nil
|
|
97
106
|
when TrueClass
|
|
98
|
-
literal_true
|
|
107
|
+
sql << literal_true
|
|
99
108
|
when FalseClass
|
|
100
|
-
literal_false
|
|
109
|
+
sql << literal_false
|
|
101
110
|
when Array
|
|
102
|
-
|
|
111
|
+
literal_array_append(sql, v)
|
|
103
112
|
when Time
|
|
104
|
-
literal_time(v)
|
|
113
|
+
sql << (v.is_a?(SQLTime) ? literal_sqltime(v) : literal_time(v))
|
|
105
114
|
when DateTime
|
|
106
|
-
literal_datetime(v)
|
|
115
|
+
sql << literal_datetime(v)
|
|
107
116
|
when Date
|
|
108
|
-
literal_date(v)
|
|
117
|
+
sql << literal_date(v)
|
|
109
118
|
when Dataset
|
|
110
|
-
|
|
119
|
+
literal_dataset_append(sql, v)
|
|
111
120
|
else
|
|
112
|
-
|
|
121
|
+
literal_other_append(sql, v)
|
|
113
122
|
end
|
|
114
123
|
end
|
|
115
124
|
|
|
@@ -163,7 +172,7 @@ module Sequel
|
|
|
163
172
|
end
|
|
164
173
|
|
|
165
174
|
# ---------------------
|
|
166
|
-
# :section: Internal Methods relating to SQL Creation
|
|
175
|
+
# :section: 9 - Internal Methods relating to SQL Creation
|
|
167
176
|
# These methods, while public, are not designed to be used directly by the end user.
|
|
168
177
|
# ---------------------
|
|
169
178
|
|
|
@@ -173,80 +182,234 @@ module Sequel
|
|
|
173
182
|
clauses.map{|clause| :"#{type}_#{clause}_sql"}.freeze
|
|
174
183
|
end
|
|
175
184
|
|
|
185
|
+
ALL = ' ALL'.freeze
|
|
176
186
|
AND_SEPARATOR = " AND ".freeze
|
|
187
|
+
APOS = "'".freeze
|
|
188
|
+
APOS_RE = /'/.freeze
|
|
189
|
+
ARRAY_EMPTY = '(NULL)'.freeze
|
|
190
|
+
AS = ' AS '.freeze
|
|
191
|
+
ASC = ' ASC'.freeze
|
|
192
|
+
BACKSLASH_RE = /\\/.freeze
|
|
177
193
|
BOOL_FALSE = "'f'".freeze
|
|
178
194
|
BOOL_TRUE = "'t'".freeze
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
BRACKET_CLOSE = ']'.freeze
|
|
196
|
+
BRACKET_OPEN = '['.freeze
|
|
197
|
+
CASE_ELSE = " ELSE ".freeze
|
|
198
|
+
CASE_END = " END)".freeze
|
|
199
|
+
CASE_OPEN = '(CASE'.freeze
|
|
200
|
+
CASE_THEN = " THEN ".freeze
|
|
201
|
+
CASE_WHEN = " WHEN ".freeze
|
|
202
|
+
CAST_OPEN = 'CAST('.freeze
|
|
203
|
+
COLUMN_ALL = '.*'.freeze
|
|
204
|
+
COLUMN_REF_RE1 = /\A((?:(?!__).)+)__((?:(?!___).)+)___(.+)\z/.freeze
|
|
205
|
+
COLUMN_REF_RE2 = /\A((?:(?!___).)+)___(.+)\z/.freeze
|
|
206
|
+
COLUMN_REF_RE3 = /\A((?:(?!__).)+)__(.+)\z/.freeze
|
|
207
|
+
COMMA = ', '.freeze
|
|
208
|
+
COMMA_SEPARATOR = COMMA
|
|
209
|
+
CONDITION_FALSE = '(1 = 0)'.freeze
|
|
210
|
+
CONDITION_TRUE = '(1 = 1)'.freeze
|
|
183
211
|
COUNT_FROM_SELF_OPTS = [:distinct, :group, :sql, :limit, :compounds]
|
|
184
212
|
COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, LiteralString.new('*'.freeze)).as(:count)
|
|
185
213
|
DATASET_ALIAS_BASE_NAME = 't'.freeze
|
|
214
|
+
DEFAULT_VALUES = " DEFAULT VALUES".freeze
|
|
215
|
+
DELETE = 'DELETE'.freeze
|
|
216
|
+
DELETE_CLAUSE_METHODS = clause_methods(:delete, %w'delete from where')
|
|
217
|
+
DESC = ' DESC'.freeze
|
|
218
|
+
DISTINCT = " DISTINCT".freeze
|
|
219
|
+
DOT = '.'.freeze
|
|
220
|
+
DOUBLE_APOS = "''".freeze
|
|
221
|
+
DOUBLE_QUOTE = '""'.freeze
|
|
222
|
+
EQUAL = ' = '.freeze
|
|
223
|
+
EXTRACT = 'extract('.freeze
|
|
186
224
|
FOR_UPDATE = ' FOR UPDATE'.freeze
|
|
225
|
+
FORMAT_DATE = "'%Y-%m-%d'".freeze
|
|
226
|
+
FORMAT_DATE_STANDARD = "DATE '%Y-%m-%d'".freeze
|
|
227
|
+
FORMAT_OFFSET = "%+03i%02i".freeze
|
|
228
|
+
FORMAT_TIMESTAMP_RE = /%[Nz]/.freeze
|
|
229
|
+
FORMAT_TIMESTAMP_USEC = ".%06d".freeze
|
|
230
|
+
FORMAT_USEC = '%N'.freeze
|
|
231
|
+
FRAME_ALL = "ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING".freeze
|
|
232
|
+
FRAME_ROWS = "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW".freeze
|
|
233
|
+
FROM = ' FROM '.freeze
|
|
234
|
+
FUNCTION_EMPTY = '()'.freeze
|
|
235
|
+
GROUP_BY = " GROUP BY ".freeze
|
|
236
|
+
HAVING = " HAVING ".freeze
|
|
237
|
+
INSERT = "INSERT".freeze
|
|
238
|
+
INSERT_CLAUSE_METHODS = clause_methods(:insert, %w'insert into columns values')
|
|
239
|
+
INTO = " INTO ".freeze
|
|
187
240
|
IS_LITERALS = {nil=>'NULL'.freeze, true=>'TRUE'.freeze, false=>'FALSE'.freeze}.freeze
|
|
188
241
|
IS_OPERATORS = ::Sequel::SQL::ComplexExpression::IS_OPERATORS
|
|
242
|
+
LIMIT = " LIMIT ".freeze
|
|
189
243
|
N_ARITY_OPERATORS = ::Sequel::SQL::ComplexExpression::N_ARITY_OPERATORS
|
|
244
|
+
NOT_SPACE = 'NOT '.freeze
|
|
190
245
|
NULL = "NULL".freeze
|
|
246
|
+
NULLS_FIRST = " NULLS FIRST".freeze
|
|
247
|
+
NULLS_LAST = " NULLS LAST".freeze
|
|
248
|
+
OFFSET = " OFFSET ".freeze
|
|
249
|
+
ON = ' ON '.freeze
|
|
250
|
+
ON_PAREN = " ON (".freeze
|
|
251
|
+
ORDER_BY = " ORDER BY ".freeze
|
|
252
|
+
ORDER_BY_NS = "ORDER BY ".freeze
|
|
253
|
+
OVER = ' OVER '.freeze
|
|
254
|
+
PAREN_CLOSE = ')'.freeze
|
|
255
|
+
PAREN_OPEN = '('.freeze
|
|
256
|
+
PAREN_SPACE_OPEN = ' ('.freeze
|
|
257
|
+
PARTITION_BY = "PARTITION BY ".freeze
|
|
258
|
+
QUAD_BACKSLASH = "\\\\\\\\".freeze
|
|
191
259
|
QUALIFY_KEYS = [:select, :where, :having, :order, :group]
|
|
192
260
|
QUESTION_MARK = '?'.freeze
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
261
|
+
QUESTION_MARK_RE = /\?/.freeze
|
|
262
|
+
QUOTE = '"'.freeze
|
|
263
|
+
QUOTE_RE = /"/.freeze
|
|
264
|
+
RETURNING = " RETURNING ".freeze
|
|
265
|
+
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
|
+
SET = ' SET '.freeze
|
|
268
|
+
SPACE = ' '.freeze
|
|
269
|
+
SQL_WITH = "WITH ".freeze
|
|
270
|
+
TILDE = '~'.freeze
|
|
197
271
|
TIMESTAMP_FORMAT = "'%Y-%m-%d %H:%M:%S%N%z'".freeze
|
|
198
272
|
STANDARD_TIMESTAMP_FORMAT = "TIMESTAMP #{TIMESTAMP_FORMAT}".freeze
|
|
199
273
|
TWO_ARITY_OPERATORS = ::Sequel::SQL::ComplexExpression::TWO_ARITY_OPERATORS
|
|
274
|
+
UNDERSCORE = '_'.freeze
|
|
275
|
+
UPDATE = 'UPDATE'.freeze
|
|
276
|
+
UPDATE_CLAUSE_METHODS = clause_methods(:update, %w'update table set where')
|
|
277
|
+
USING = ' USING ('.freeze
|
|
278
|
+
VALUES = " VALUES ".freeze
|
|
279
|
+
WHERE = " WHERE ".freeze
|
|
200
280
|
WILDCARD = LiteralString.new('*').freeze
|
|
201
|
-
|
|
281
|
+
|
|
282
|
+
PUBLIC_APPEND_METHODS = (<<-END).split.map{|x| x.to_sym}
|
|
283
|
+
literal
|
|
284
|
+
aliased_expression_sql
|
|
285
|
+
array_sql
|
|
286
|
+
boolean_constant_sql
|
|
287
|
+
case_expression_sql
|
|
288
|
+
cast_sql
|
|
289
|
+
column_all_sql
|
|
290
|
+
complex_expression_sql
|
|
291
|
+
constant_sql
|
|
292
|
+
function_sql
|
|
293
|
+
join_clause_sql
|
|
294
|
+
join_on_clause_sql
|
|
295
|
+
join_using_clause_sql
|
|
296
|
+
negative_boolean_constant_sql
|
|
297
|
+
ordered_expression_sql
|
|
298
|
+
placeholder_literal_string_sql
|
|
299
|
+
qualified_identifier_sql
|
|
300
|
+
quote_identifier
|
|
301
|
+
quote_schema_table
|
|
302
|
+
quoted_identifier
|
|
303
|
+
subscript_sql
|
|
304
|
+
window_sql
|
|
305
|
+
window_function_sql
|
|
306
|
+
END
|
|
307
|
+
PRIVATE_APPEND_METHODS = (<<-END).split.map{|x| x.to_sym}
|
|
308
|
+
argument_list
|
|
309
|
+
as_sql
|
|
310
|
+
column_list
|
|
311
|
+
compound_dataset_sql
|
|
312
|
+
expression_list
|
|
313
|
+
literal_array
|
|
314
|
+
literal_blob
|
|
315
|
+
literal_dataset
|
|
316
|
+
literal_expression
|
|
317
|
+
literal_hash
|
|
318
|
+
literal_other
|
|
319
|
+
literal_string
|
|
320
|
+
literal_symbol
|
|
321
|
+
source_list
|
|
322
|
+
subselect_sql
|
|
323
|
+
table_ref
|
|
324
|
+
END
|
|
325
|
+
def self.def_append_methods(meths)
|
|
326
|
+
meths.each do |meth|
|
|
327
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
328
|
+
def #{meth}(*args, &block)
|
|
329
|
+
s = ''
|
|
330
|
+
#{meth}_append(s, *args, &block)
|
|
331
|
+
s
|
|
332
|
+
end
|
|
333
|
+
END
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
def_append_methods(PUBLIC_APPEND_METHODS + PRIVATE_APPEND_METHODS)
|
|
337
|
+
private *PRIVATE_APPEND_METHODS
|
|
202
338
|
|
|
203
339
|
# SQL fragment for AliasedExpression
|
|
204
|
-
def
|
|
205
|
-
|
|
340
|
+
def aliased_expression_sql_append(sql, ae)
|
|
341
|
+
literal_append(sql, ae.expression)
|
|
342
|
+
as_sql_append(sql, ae.aliaz)
|
|
206
343
|
end
|
|
207
344
|
|
|
208
345
|
# SQL fragment for Array
|
|
209
|
-
def
|
|
210
|
-
a.empty?
|
|
346
|
+
def array_sql_append(sql, a)
|
|
347
|
+
if a.empty?
|
|
348
|
+
sql << ARRAY_EMPTY
|
|
349
|
+
else
|
|
350
|
+
sql << PAREN_OPEN
|
|
351
|
+
expression_list_append(sql, a)
|
|
352
|
+
sql << PAREN_CLOSE
|
|
353
|
+
end
|
|
211
354
|
end
|
|
212
355
|
|
|
213
356
|
# SQL fragment for BooleanConstants
|
|
214
|
-
def
|
|
215
|
-
|
|
357
|
+
def boolean_constant_sql_append(sql, constant)
|
|
358
|
+
if (constant == true || constant == false) && !supports_where_true?
|
|
359
|
+
sql << (constant == true ? CONDITION_TRUE : CONDITION_FALSE)
|
|
360
|
+
else
|
|
361
|
+
literal_append(sql, constant)
|
|
362
|
+
end
|
|
216
363
|
end
|
|
217
364
|
|
|
218
365
|
# SQL fragment for CaseExpression
|
|
219
|
-
def
|
|
220
|
-
sql
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
sql
|
|
224
|
-
|
|
225
|
-
|
|
366
|
+
def case_expression_sql_append(sql, ce)
|
|
367
|
+
sql << CASE_OPEN
|
|
368
|
+
if ce.expression?
|
|
369
|
+
sql << SPACE
|
|
370
|
+
literal_append(sql, ce.expression)
|
|
371
|
+
end
|
|
372
|
+
w = CASE_WHEN
|
|
373
|
+
t = CASE_THEN
|
|
374
|
+
ce.conditions.each do |c,r|
|
|
375
|
+
sql << w
|
|
376
|
+
literal_append(sql, c)
|
|
377
|
+
sql << t
|
|
378
|
+
literal_append(sql, r)
|
|
379
|
+
end
|
|
380
|
+
sql << CASE_ELSE
|
|
381
|
+
literal_append(sql, ce.default)
|
|
382
|
+
sql << CASE_END
|
|
226
383
|
end
|
|
227
384
|
|
|
228
385
|
# SQL fragment for the SQL CAST expression
|
|
229
|
-
def
|
|
230
|
-
|
|
386
|
+
def cast_sql_append(sql, expr, type)
|
|
387
|
+
sql << CAST_OPEN
|
|
388
|
+
literal_append(sql, expr)
|
|
389
|
+
sql << AS << db.cast_type_literal(type).to_s
|
|
390
|
+
sql << PAREN_CLOSE
|
|
231
391
|
end
|
|
232
392
|
|
|
233
393
|
# SQL fragment for specifying all columns in a given table
|
|
234
|
-
def
|
|
235
|
-
|
|
394
|
+
def column_all_sql_append(sql, ca)
|
|
395
|
+
quote_schema_table_append(sql, ca.table)
|
|
396
|
+
sql << COLUMN_ALL
|
|
236
397
|
end
|
|
237
398
|
|
|
238
|
-
|
|
239
|
-
def complex_expression_sql(op, args)
|
|
399
|
+
def complex_expression_sql_append(sql, op, args)
|
|
240
400
|
case op
|
|
241
401
|
when *IS_OPERATORS
|
|
242
402
|
r = args.at(1)
|
|
243
403
|
if r.nil? || supports_is_true?
|
|
244
404
|
raise(InvalidOperation, 'Invalid argument used for IS operator') unless v = IS_LITERALS[r]
|
|
245
|
-
|
|
405
|
+
sql << PAREN_OPEN
|
|
406
|
+
literal_append(sql, args.at(0))
|
|
407
|
+
sql << SPACE << op.to_s << SPACE
|
|
408
|
+
sql << v << PAREN_CLOSE
|
|
246
409
|
elsif op == :IS
|
|
247
|
-
|
|
410
|
+
complex_expression_sql_append(sql, :"=", args)
|
|
248
411
|
else
|
|
249
|
-
|
|
412
|
+
complex_expression_sql_append(sql, :OR, [SQL::BooleanExpression.new(:"!=", *args), SQL::BooleanExpression.new(:IS, args.at(0), nil)])
|
|
250
413
|
end
|
|
251
414
|
when :IN, :"NOT IN"
|
|
252
415
|
cols = args.at(0)
|
|
@@ -259,144 +422,228 @@ module Sequel
|
|
|
259
422
|
if col_array
|
|
260
423
|
if empty_val_array
|
|
261
424
|
if op == :IN
|
|
262
|
-
|
|
425
|
+
literal_append(sql, SQL::BooleanExpression.from_value_pairs(cols.to_a.map{|x| [x, x]}, :AND, true))
|
|
263
426
|
else
|
|
264
|
-
|
|
427
|
+
literal_append(sql, 1=>1)
|
|
265
428
|
end
|
|
266
429
|
elsif !supports_multiple_column_in?
|
|
267
430
|
if val_array
|
|
268
431
|
expr = SQL::BooleanExpression.new(:OR, *vals.to_a.map{|vs| SQL::BooleanExpression.from_value_pairs(cols.to_a.zip(vs).map{|c, v| [c, v]})})
|
|
269
|
-
|
|
432
|
+
literal_append(sql, op == :IN ? expr : ~expr)
|
|
270
433
|
else
|
|
271
434
|
old_vals = vals
|
|
435
|
+
vals = vals.naked if vals.is_a?(Sequel::Dataset)
|
|
272
436
|
vals = vals.to_a
|
|
273
437
|
val_cols = old_vals.columns
|
|
274
|
-
|
|
438
|
+
complex_expression_sql_append(sql, op, [cols, vals.map!{|x| x.values_at(*val_cols)}])
|
|
275
439
|
end
|
|
276
440
|
else
|
|
277
441
|
# If the columns and values are both arrays, use array_sql instead of
|
|
278
442
|
# literal so that if values is an array of two element arrays, it
|
|
279
443
|
# will be treated as a value list instead of a condition specifier.
|
|
280
|
-
|
|
444
|
+
sql << PAREN_OPEN
|
|
445
|
+
literal_append(sql, cols)
|
|
446
|
+
sql << SPACE << op.to_s << SPACE
|
|
447
|
+
if val_array
|
|
448
|
+
array_sql_append(sql, vals)
|
|
449
|
+
else
|
|
450
|
+
literal_append(sql, vals)
|
|
451
|
+
end
|
|
452
|
+
sql << PAREN_CLOSE
|
|
281
453
|
end
|
|
282
454
|
else
|
|
283
455
|
if empty_val_array
|
|
284
456
|
if op == :IN
|
|
285
|
-
|
|
457
|
+
literal_append(sql, SQL::BooleanExpression.from_value_pairs([[cols, cols]], :AND, true))
|
|
286
458
|
else
|
|
287
|
-
|
|
459
|
+
literal_append(sql, 1=>1)
|
|
288
460
|
end
|
|
289
461
|
else
|
|
290
|
-
|
|
462
|
+
sql << PAREN_OPEN
|
|
463
|
+
literal_append(sql, cols)
|
|
464
|
+
sql << SPACE << op.to_s << SPACE
|
|
465
|
+
literal_append(sql, vals)
|
|
466
|
+
sql << PAREN_CLOSE
|
|
291
467
|
end
|
|
292
468
|
end
|
|
293
469
|
when *TWO_ARITY_OPERATORS
|
|
294
|
-
|
|
470
|
+
sql << PAREN_OPEN
|
|
471
|
+
literal_append(sql, args.at(0))
|
|
472
|
+
sql << SPACE << op.to_s << SPACE
|
|
473
|
+
literal_append(sql, args.at(1))
|
|
474
|
+
sql << PAREN_CLOSE
|
|
295
475
|
when *N_ARITY_OPERATORS
|
|
296
|
-
|
|
476
|
+
sql << PAREN_OPEN
|
|
477
|
+
c = false
|
|
478
|
+
op_str = " #{op} "
|
|
479
|
+
args.each do |a|
|
|
480
|
+
sql << op_str if c
|
|
481
|
+
literal_append(sql, a)
|
|
482
|
+
c ||= true
|
|
483
|
+
end
|
|
484
|
+
sql << PAREN_CLOSE
|
|
297
485
|
when :NOT
|
|
298
|
-
|
|
486
|
+
sql << NOT_SPACE
|
|
487
|
+
literal_append(sql, args.at(0))
|
|
299
488
|
when :NOOP
|
|
300
|
-
|
|
489
|
+
literal_append(sql, args.at(0))
|
|
301
490
|
when :'B~'
|
|
302
|
-
|
|
491
|
+
sql << TILDE
|
|
492
|
+
literal_append(sql, args.at(0))
|
|
493
|
+
when :extract
|
|
494
|
+
sql << EXTRACT << args.at(0).to_s << FROM
|
|
495
|
+
literal_append(sql, args.at(1))
|
|
496
|
+
sql << PAREN_CLOSE
|
|
303
497
|
else
|
|
304
498
|
raise(InvalidOperation, "invalid operator #{op}")
|
|
305
499
|
end
|
|
306
500
|
end
|
|
307
501
|
|
|
308
502
|
# SQL fragment for constants
|
|
309
|
-
def
|
|
310
|
-
constant.to_s
|
|
503
|
+
def constant_sql_append(sql, constant)
|
|
504
|
+
sql << constant.to_s
|
|
311
505
|
end
|
|
312
506
|
|
|
313
507
|
# SQL fragment specifying an SQL function call
|
|
314
|
-
def
|
|
508
|
+
def function_sql_append(sql, f)
|
|
509
|
+
sql << f.f.to_s
|
|
315
510
|
args = f.args
|
|
316
|
-
|
|
511
|
+
if args.empty?
|
|
512
|
+
sql << FUNCTION_EMPTY
|
|
513
|
+
else
|
|
514
|
+
literal_append(sql, args)
|
|
515
|
+
end
|
|
317
516
|
end
|
|
318
517
|
|
|
319
518
|
# SQL fragment specifying a JOIN clause without ON or USING.
|
|
320
|
-
def
|
|
519
|
+
def join_clause_sql_append(sql, jc)
|
|
321
520
|
table = jc.table
|
|
322
521
|
table_alias = jc.table_alias
|
|
323
522
|
table_alias = nil if table == table_alias
|
|
324
|
-
|
|
325
|
-
|
|
523
|
+
sql << SPACE << join_type_sql(jc.join_type) << SPACE
|
|
524
|
+
table_ref_append(sql, table)
|
|
525
|
+
as_sql_append(sql, table_alias) if table_alias
|
|
326
526
|
end
|
|
327
527
|
|
|
328
528
|
# SQL fragment specifying a JOIN clause with ON.
|
|
329
|
-
def
|
|
330
|
-
|
|
529
|
+
def join_on_clause_sql_append(sql, jc)
|
|
530
|
+
join_clause_sql_append(sql, jc)
|
|
531
|
+
sql << ON
|
|
532
|
+
literal_append(sql, filter_expr(jc.on))
|
|
331
533
|
end
|
|
332
534
|
|
|
333
535
|
# SQL fragment specifying a JOIN clause with USING.
|
|
334
|
-
def
|
|
335
|
-
|
|
536
|
+
def join_using_clause_sql_append(sql, jc)
|
|
537
|
+
join_clause_sql_append(sql, jc)
|
|
538
|
+
sql << USING
|
|
539
|
+
column_list_append(sql, jc.using)
|
|
540
|
+
sql << PAREN_CLOSE
|
|
336
541
|
end
|
|
337
542
|
|
|
338
543
|
# SQL fragment for NegativeBooleanConstants
|
|
339
|
-
def
|
|
340
|
-
|
|
544
|
+
def negative_boolean_constant_sql_append(sql, constant)
|
|
545
|
+
sql << NOT_SPACE
|
|
546
|
+
boolean_constant_sql_append(sql, constant)
|
|
341
547
|
end
|
|
342
548
|
|
|
343
549
|
# SQL fragment for the ordered expression, used in the ORDER BY
|
|
344
550
|
# clause.
|
|
345
|
-
def
|
|
346
|
-
|
|
551
|
+
def ordered_expression_sql_append(sql, oe)
|
|
552
|
+
literal_append(sql, oe.expression)
|
|
553
|
+
sql << (oe.descending ? DESC : ASC)
|
|
347
554
|
case oe.nulls
|
|
348
555
|
when :first
|
|
349
|
-
|
|
556
|
+
sql << NULLS_FIRST
|
|
350
557
|
when :last
|
|
351
|
-
|
|
352
|
-
else
|
|
353
|
-
s
|
|
558
|
+
sql << NULLS_LAST
|
|
354
559
|
end
|
|
355
560
|
end
|
|
356
561
|
|
|
357
562
|
# SQL fragment for a literal string with placeholders
|
|
358
|
-
def
|
|
563
|
+
def placeholder_literal_string_sql_append(sql, pls)
|
|
359
564
|
args = pls.args
|
|
360
|
-
|
|
565
|
+
sql << PAREN_OPEN if pls.parens
|
|
566
|
+
if args.is_a?(Hash)
|
|
361
567
|
re = /:(#{args.keys.map{|k| Regexp.escape(k.to_s)}.join('|')})\b/
|
|
362
|
-
|
|
568
|
+
if RUBY_VERSION >= '1.8.7'
|
|
569
|
+
str = pls.str
|
|
570
|
+
loop do
|
|
571
|
+
previous, q, str = str.partition(re)
|
|
572
|
+
sql << previous
|
|
573
|
+
literal_append(sql, args[($1||q[1..-1].to_s).to_sym]) unless q.empty?
|
|
574
|
+
break if str.empty?
|
|
575
|
+
end
|
|
576
|
+
else
|
|
577
|
+
sql << pls.str.gsub(re){literal(args[$1.to_sym])}
|
|
578
|
+
end
|
|
363
579
|
else
|
|
364
580
|
i = -1
|
|
365
|
-
|
|
581
|
+
if RUBY_VERSION >= '1.8.7'
|
|
582
|
+
str = pls.str
|
|
583
|
+
loop do
|
|
584
|
+
previous, q, str = str.partition(QUESTION_MARK)
|
|
585
|
+
sql << previous
|
|
586
|
+
literal_append(sql, args.at(i+=1)) unless q.empty?
|
|
587
|
+
break if str.empty?
|
|
588
|
+
end
|
|
589
|
+
else
|
|
590
|
+
sql << pls.str.gsub(QUESTION_MARK_RE){literal(args.at(i+=1))}
|
|
591
|
+
end
|
|
366
592
|
end
|
|
367
|
-
|
|
368
|
-
s
|
|
593
|
+
sql << PAREN_CLOSE if pls.parens
|
|
369
594
|
end
|
|
370
595
|
|
|
371
596
|
# SQL fragment for the qualifed identifier, specifying
|
|
372
597
|
# a table and a column (or schema and table).
|
|
373
|
-
def
|
|
374
|
-
|
|
598
|
+
def qualified_identifier_sql_append(sql, qcr)
|
|
599
|
+
case t = qcr.table
|
|
600
|
+
when Symbol, SQL::QualifiedIdentifier, SQL::Identifier
|
|
601
|
+
literal_append(sql, t)
|
|
602
|
+
else
|
|
603
|
+
quote_identifier_append(sql, t)
|
|
604
|
+
end
|
|
605
|
+
sql << DOT
|
|
606
|
+
case c = qcr.column
|
|
607
|
+
when Symbol, SQL::QualifiedIdentifier, SQL::Identifier
|
|
608
|
+
literal_append(sql, c)
|
|
609
|
+
else
|
|
610
|
+
quote_identifier_append(sql, c)
|
|
611
|
+
end
|
|
375
612
|
end
|
|
376
613
|
|
|
377
614
|
# Adds quoting to identifiers (columns and tables). If identifiers are not
|
|
378
615
|
# being quoted, returns name as a string. If identifiers are being quoted
|
|
379
616
|
# quote the name with quoted_identifier.
|
|
380
|
-
def
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
617
|
+
def quote_identifier_append(sql, name)
|
|
618
|
+
if name.is_a?(LiteralString)
|
|
619
|
+
sql << name
|
|
620
|
+
else
|
|
621
|
+
name = name.value if name.is_a?(SQL::Identifier)
|
|
622
|
+
name = input_identifier(name)
|
|
623
|
+
if quote_identifiers?
|
|
624
|
+
quoted_identifier_append(sql, name)
|
|
625
|
+
else
|
|
626
|
+
sql << name
|
|
627
|
+
end
|
|
628
|
+
end
|
|
386
629
|
end
|
|
387
630
|
|
|
388
631
|
# Separates the schema from the table and returns a string with them
|
|
389
632
|
# quoted (if quoting identifiers)
|
|
390
|
-
def
|
|
633
|
+
def quote_schema_table_append(sql, table)
|
|
391
634
|
schema, table = schema_and_table(table)
|
|
392
|
-
|
|
635
|
+
if schema
|
|
636
|
+
quote_identifier_append(sql, schema)
|
|
637
|
+
sql << DOT
|
|
638
|
+
end
|
|
639
|
+
quote_identifier_append(sql, table)
|
|
393
640
|
end
|
|
394
641
|
|
|
395
642
|
# This method quotes the given name with the SQL standard double quote.
|
|
396
643
|
# should be overridden by subclasses to provide quoting not matching the
|
|
397
644
|
# SQL standard, such as backtick (used by MySQL and SQLite).
|
|
398
|
-
def
|
|
399
|
-
|
|
645
|
+
def quoted_identifier_append(sql, name)
|
|
646
|
+
sql << QUOTE << name.to_s.gsub(QUOTE_RE, DOUBLE_QUOTE) << QUOTE
|
|
400
647
|
end
|
|
401
648
|
|
|
402
649
|
# Split the schema information from the table
|
|
@@ -418,34 +665,59 @@ module Sequel
|
|
|
418
665
|
end
|
|
419
666
|
|
|
420
667
|
# SQL fragment for specifying subscripts (SQL array accesses)
|
|
421
|
-
def
|
|
422
|
-
|
|
668
|
+
def subscript_sql_append(sql, s)
|
|
669
|
+
literal_append(sql, s.f)
|
|
670
|
+
sql << BRACKET_OPEN
|
|
671
|
+
expression_list_append(sql, s.sub)
|
|
672
|
+
sql << BRACKET_CLOSE
|
|
423
673
|
end
|
|
424
674
|
|
|
425
675
|
# The SQL fragment for the given window's options.
|
|
426
|
-
def
|
|
676
|
+
def window_sql_append(sql, opts)
|
|
427
677
|
raise(Error, 'This dataset does not support window functions') unless supports_window_functions?
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
678
|
+
sql << PAREN_OPEN
|
|
679
|
+
window, part, order, frame = opts.values_at(:window, :partition, :order, :frame)
|
|
680
|
+
space = false
|
|
681
|
+
space_s = SPACE
|
|
682
|
+
if window
|
|
683
|
+
literal_append(sql, window)
|
|
684
|
+
space = true
|
|
685
|
+
end
|
|
686
|
+
if part
|
|
687
|
+
sql << space_s if space
|
|
688
|
+
sql << PARTITION_BY
|
|
689
|
+
expression_list_append(sql, Array(part))
|
|
690
|
+
space = true
|
|
691
|
+
end
|
|
692
|
+
if order
|
|
693
|
+
sql << space_s if space
|
|
694
|
+
sql << ORDER_BY_NS
|
|
695
|
+
expression_list_append(sql, Array(order))
|
|
696
|
+
space = true
|
|
697
|
+
end
|
|
698
|
+
case frame
|
|
432
699
|
when nil
|
|
433
|
-
|
|
700
|
+
# nothing
|
|
434
701
|
when :all
|
|
435
|
-
|
|
702
|
+
sql << space_s if space
|
|
703
|
+
sql << FRAME_ALL
|
|
436
704
|
when :rows
|
|
437
|
-
|
|
705
|
+
sql << space_s if space
|
|
706
|
+
sql << FRAME_ROWS
|
|
438
707
|
when String
|
|
439
|
-
|
|
708
|
+
sql << space_s if space
|
|
709
|
+
sql << frame
|
|
440
710
|
else
|
|
441
711
|
raise Error, "invalid window frame clause, should be :all, :rows, a string, or nil"
|
|
442
712
|
end
|
|
443
|
-
|
|
713
|
+
sql << PAREN_CLOSE
|
|
444
714
|
end
|
|
445
715
|
|
|
446
716
|
# The SQL fragment for the given window function's function and window.
|
|
447
|
-
def
|
|
448
|
-
|
|
717
|
+
def window_function_sql_append(sql, function, window)
|
|
718
|
+
literal_append(sql, function)
|
|
719
|
+
sql << OVER
|
|
720
|
+
literal_append(sql, window)
|
|
449
721
|
end
|
|
450
722
|
|
|
451
723
|
protected
|
|
@@ -517,14 +789,20 @@ module Sequel
|
|
|
517
789
|
options_overlap(COUNT_FROM_SELF_OPTS) ? from_self : unordered
|
|
518
790
|
end
|
|
519
791
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
792
|
+
def argument_list_append(sql, args)
|
|
793
|
+
c = false
|
|
794
|
+
comma = COMMA
|
|
795
|
+
args.each do |a|
|
|
796
|
+
sql << comma if c
|
|
797
|
+
sql << a.to_s
|
|
798
|
+
c ||= true
|
|
799
|
+
end
|
|
523
800
|
end
|
|
524
801
|
|
|
525
802
|
# SQL fragment for specifying an alias. expression should already be literalized.
|
|
526
|
-
def
|
|
527
|
-
|
|
803
|
+
def as_sql_append(sql, aliaz)
|
|
804
|
+
sql << AS
|
|
805
|
+
quote_identifier_append(sql, aliaz)
|
|
528
806
|
end
|
|
529
807
|
|
|
530
808
|
# Raise an InvalidOperation exception if deletion is not allowed
|
|
@@ -536,17 +814,43 @@ module Sequel
|
|
|
536
814
|
|
|
537
815
|
# Prepare an SQL statement by calling all clause methods for the given statement type.
|
|
538
816
|
def clause_sql(type)
|
|
539
|
-
sql =
|
|
817
|
+
sql = @opts[:append_sql] || ''
|
|
540
818
|
send("#{type}_clause_methods").each{|x| send(x, sql)}
|
|
541
819
|
sql
|
|
542
820
|
end
|
|
543
821
|
|
|
544
822
|
# Converts an array of column names into a comma seperated string of
|
|
545
823
|
# column names. If the array is empty, a wildcard (*) is returned.
|
|
546
|
-
def
|
|
547
|
-
(columns.nil? || columns.empty?)
|
|
824
|
+
def column_list_append(sql, columns)
|
|
825
|
+
if (columns.nil? || columns.empty?)
|
|
826
|
+
sql << WILDCARD
|
|
827
|
+
else
|
|
828
|
+
expression_list_append(sql, columns)
|
|
829
|
+
end
|
|
548
830
|
end
|
|
549
|
-
|
|
831
|
+
|
|
832
|
+
# Yield each two pair of arguments to the block, which should
|
|
833
|
+
# return a string representing the SQL code for those
|
|
834
|
+
# two arguments. If more than 2 arguments are provided, all
|
|
835
|
+
# calls to the block # after the first will have a LiteralString
|
|
836
|
+
# as the first argument, representing the application of the block to
|
|
837
|
+
# the previous arguments.
|
|
838
|
+
def complex_expression_arg_pairs(args)
|
|
839
|
+
case args.length
|
|
840
|
+
when 1
|
|
841
|
+
literal(args.at(0))
|
|
842
|
+
when 2
|
|
843
|
+
yield args.at(0), args.at(1)
|
|
844
|
+
else
|
|
845
|
+
args.inject{|m, a| LiteralString.new(yield(m, a))}
|
|
846
|
+
end
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
# The SQL to use for the dataset used in a UNION/INTERSECT/EXCEPT clause.
|
|
850
|
+
def compound_dataset_sql_append(sql, ds)
|
|
851
|
+
subselect_sql_append(sql, ds)
|
|
852
|
+
end
|
|
853
|
+
|
|
550
854
|
# The alias to use for datasets, takes a number to make sure the name is unique.
|
|
551
855
|
def dataset_alias(number)
|
|
552
856
|
:"#{DATASET_ALIAS_BASE_NAME}#{number}"
|
|
@@ -557,10 +861,20 @@ module Sequel
|
|
|
557
861
|
DELETE_CLAUSE_METHODS
|
|
558
862
|
end
|
|
559
863
|
|
|
864
|
+
def delete_delete_sql(sql)
|
|
865
|
+
sql << DELETE
|
|
866
|
+
end
|
|
867
|
+
|
|
560
868
|
# Converts an array of expressions into a comma separated string of
|
|
561
869
|
# expressions.
|
|
562
|
-
def
|
|
563
|
-
|
|
870
|
+
def expression_list_append(sql, columns)
|
|
871
|
+
c = false
|
|
872
|
+
co = COMMA
|
|
873
|
+
columns.each do |col|
|
|
874
|
+
sql << co if c
|
|
875
|
+
literal_append(sql, col)
|
|
876
|
+
c ||= true
|
|
877
|
+
end
|
|
564
878
|
end
|
|
565
879
|
|
|
566
880
|
# The strftime format to use when literalizing the time.
|
|
@@ -573,9 +887,9 @@ module Sequel
|
|
|
573
887
|
# database supports them), and override %z to always use a numeric offset
|
|
574
888
|
# of hours and minutes.
|
|
575
889
|
def format_timestamp(v)
|
|
576
|
-
v2 =
|
|
577
|
-
fmt = default_timestamp_format.gsub(
|
|
578
|
-
if m ==
|
|
890
|
+
v2 = db.from_application_timestamp(v)
|
|
891
|
+
fmt = default_timestamp_format.gsub(FORMAT_TIMESTAMP_RE) do |m|
|
|
892
|
+
if m == FORMAT_USEC
|
|
579
893
|
format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION < '1.9.0' ? 86400000000 : 1000000) : v.usec) if supports_timestamp_usecs?
|
|
580
894
|
else
|
|
581
895
|
if supports_timestamp_timezones?
|
|
@@ -591,13 +905,13 @@ module Sequel
|
|
|
591
905
|
|
|
592
906
|
# Return the SQL timestamp fragment to use for the timezone offset.
|
|
593
907
|
def format_timestamp_offset(hour, minute)
|
|
594
|
-
sprintf(
|
|
908
|
+
sprintf(FORMAT_OFFSET, hour, minute)
|
|
595
909
|
end
|
|
596
910
|
|
|
597
911
|
# Return the SQL timestamp fragment to use for the fractional time part.
|
|
598
912
|
# Should start with the decimal point. Uses 6 decimal places by default.
|
|
599
913
|
def format_timestamp_usec(usec)
|
|
600
|
-
sprintf(
|
|
914
|
+
sprintf(FORMAT_TIMESTAMP_USEC, usec)
|
|
601
915
|
end
|
|
602
916
|
|
|
603
917
|
# Modify the identifier returned from the database based on the
|
|
@@ -608,7 +922,8 @@ module Sequel
|
|
|
608
922
|
|
|
609
923
|
# SQL fragment specifying the table to insert INTO
|
|
610
924
|
def insert_into_sql(sql)
|
|
611
|
-
sql <<
|
|
925
|
+
sql << INTO
|
|
926
|
+
source_list_append(sql, @opts[:from])
|
|
612
927
|
end
|
|
613
928
|
|
|
614
929
|
# The order of methods to call to build the INSERT SQL statement
|
|
@@ -619,27 +934,61 @@ module Sequel
|
|
|
619
934
|
# SQL fragment specifying the columns to insert into
|
|
620
935
|
def insert_columns_sql(sql)
|
|
621
936
|
columns = opts[:columns]
|
|
622
|
-
|
|
937
|
+
if columns && !columns.empty?
|
|
938
|
+
sql << PAREN_SPACE_OPEN
|
|
939
|
+
c = false
|
|
940
|
+
co = COMMA
|
|
941
|
+
columns.each do |col|
|
|
942
|
+
sql << co if c
|
|
943
|
+
if col.is_a?(String) && !col.is_a?(LiteralString)
|
|
944
|
+
quote_identifier_append(sql, col)
|
|
945
|
+
else
|
|
946
|
+
literal_append(sql, col)
|
|
947
|
+
end
|
|
948
|
+
c ||= true
|
|
949
|
+
end
|
|
950
|
+
sql << PAREN_CLOSE
|
|
951
|
+
end
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
def insert_insert_sql(sql)
|
|
955
|
+
sql << INSERT
|
|
623
956
|
end
|
|
624
957
|
|
|
625
958
|
# SQL fragment specifying the values to insert.
|
|
626
959
|
def insert_values_sql(sql)
|
|
627
960
|
case values = opts[:values]
|
|
628
961
|
when Array
|
|
629
|
-
|
|
962
|
+
if values.empty?
|
|
963
|
+
sql << DEFAULT_VALUES
|
|
964
|
+
else
|
|
965
|
+
sql << VALUES
|
|
966
|
+
literal_append(sql, values)
|
|
967
|
+
end
|
|
630
968
|
when Dataset
|
|
631
|
-
sql <<
|
|
969
|
+
sql << SPACE
|
|
970
|
+
subselect_sql_append(sql, values)
|
|
632
971
|
when LiteralString
|
|
633
|
-
sql <<
|
|
972
|
+
sql << SPACE << values
|
|
634
973
|
else
|
|
635
974
|
raise Error, "Unsupported INSERT values type, should be an Array or Dataset: #{values.inspect}"
|
|
636
975
|
end
|
|
637
976
|
end
|
|
638
977
|
|
|
978
|
+
# SQL fragment specifying the values to return.
|
|
979
|
+
def insert_returning_sql(sql)
|
|
980
|
+
if opts.has_key?(:returning)
|
|
981
|
+
sql << RETURNING
|
|
982
|
+
column_list_append(sql, Array(opts[:returning]))
|
|
983
|
+
end
|
|
984
|
+
end
|
|
985
|
+
alias delete_returning_sql insert_returning_sql
|
|
986
|
+
alias update_returning_sql insert_returning_sql
|
|
987
|
+
|
|
639
988
|
# SQL fragment specifying a JOIN type, converts underscores to
|
|
640
989
|
# spaces and upcases.
|
|
641
990
|
def join_type_sql(join_type)
|
|
642
|
-
"#{join_type.to_s.gsub(
|
|
991
|
+
"#{join_type.to_s.gsub(UNDERSCORE, SPACE).upcase} JOIN"
|
|
643
992
|
end
|
|
644
993
|
|
|
645
994
|
# Whether this dataset is a joined dataset
|
|
@@ -648,8 +997,12 @@ module Sequel
|
|
|
648
997
|
end
|
|
649
998
|
|
|
650
999
|
# SQL fragment for Array. Treats as an expression if an array of all two pairs, or as a SQL array otherwise.
|
|
651
|
-
def
|
|
652
|
-
Sequel.condition_specifier?(v)
|
|
1000
|
+
def literal_array_append(sql, v)
|
|
1001
|
+
if Sequel.condition_specifier?(v)
|
|
1002
|
+
literal_expression_append(sql, SQL::BooleanExpression.from_value_pairs(v))
|
|
1003
|
+
else
|
|
1004
|
+
array_sql_append(sql, v)
|
|
1005
|
+
end
|
|
653
1006
|
end
|
|
654
1007
|
|
|
655
1008
|
# SQL fragment for BigDecimal
|
|
@@ -659,18 +1012,24 @@ module Sequel
|
|
|
659
1012
|
end
|
|
660
1013
|
|
|
661
1014
|
# SQL fragment for SQL::Blob
|
|
662
|
-
def
|
|
663
|
-
|
|
1015
|
+
def literal_blob_append(sql, v)
|
|
1016
|
+
literal_string_append(sql, v)
|
|
664
1017
|
end
|
|
665
1018
|
|
|
666
1019
|
# SQL fragment for Dataset. Does a subselect inside parantheses.
|
|
667
|
-
def
|
|
668
|
-
|
|
1020
|
+
def literal_dataset_append(sql, v)
|
|
1021
|
+
sql << PAREN_OPEN
|
|
1022
|
+
subselect_sql_append(sql, v)
|
|
1023
|
+
sql << PAREN_CLOSE
|
|
669
1024
|
end
|
|
670
1025
|
|
|
671
1026
|
# SQL fragment for Date, using the ISO8601 format.
|
|
672
1027
|
def literal_date(v)
|
|
673
|
-
|
|
1028
|
+
if requires_sql_standard_datetimes?
|
|
1029
|
+
v.strftime(FORMAT_DATE_STANDARD)
|
|
1030
|
+
else
|
|
1031
|
+
v.strftime(FORMAT_DATE)
|
|
1032
|
+
end
|
|
674
1033
|
end
|
|
675
1034
|
|
|
676
1035
|
# SQL fragment for DateTime
|
|
@@ -679,8 +1038,8 @@ module Sequel
|
|
|
679
1038
|
end
|
|
680
1039
|
|
|
681
1040
|
# SQL fragment for SQL::Expression, result depends on the specific type of expression.
|
|
682
|
-
def
|
|
683
|
-
v.
|
|
1041
|
+
def literal_expression_append(sql, v)
|
|
1042
|
+
v.to_s_append(self, sql)
|
|
684
1043
|
end
|
|
685
1044
|
|
|
686
1045
|
# SQL fragment for false
|
|
@@ -694,8 +1053,8 @@ module Sequel
|
|
|
694
1053
|
end
|
|
695
1054
|
|
|
696
1055
|
# SQL fragment for Hash, treated as an expression
|
|
697
|
-
def
|
|
698
|
-
|
|
1056
|
+
def literal_hash_append(sql, v)
|
|
1057
|
+
literal_expression_append(sql, SQL::BooleanExpression.from_value_pairs(v))
|
|
699
1058
|
end
|
|
700
1059
|
|
|
701
1060
|
# SQL fragment for Integer
|
|
@@ -714,17 +1073,24 @@ module Sequel
|
|
|
714
1073
|
# provided and should add that method to Sequel::Dataset, allowing for adapters
|
|
715
1074
|
# to provide customized literalizations.
|
|
716
1075
|
# If a database specific type is allowed, this should be overriden in a subclass.
|
|
717
|
-
def
|
|
718
|
-
if v.respond_to?(:
|
|
719
|
-
v.
|
|
1076
|
+
def literal_other_append(sql, v)
|
|
1077
|
+
if v.respond_to?(:sql_literal_append)
|
|
1078
|
+
v.sql_literal_append(self, sql)
|
|
1079
|
+
elsif v.respond_to?(:sql_literal)
|
|
1080
|
+
sql << v.sql_literal(self)
|
|
720
1081
|
else
|
|
721
1082
|
raise Error, "can't express #{v.inspect} as a SQL literal"
|
|
722
1083
|
end
|
|
723
1084
|
end
|
|
724
1085
|
|
|
1086
|
+
# SQL fragment for Sequel::SQLTime, containing just the time part
|
|
1087
|
+
def literal_sqltime(v)
|
|
1088
|
+
v.strftime("'%H:%M:%S#{format_timestamp_usec(v.usec) if supports_timestamp_usecs?}'")
|
|
1089
|
+
end
|
|
1090
|
+
|
|
725
1091
|
# SQL fragment for String. Doubles \ and ' by default.
|
|
726
|
-
def
|
|
727
|
-
|
|
1092
|
+
def literal_string_append(sql, v)
|
|
1093
|
+
sql << APOS << v.gsub(BACKSLASH_RE, QUAD_BACKSLASH).gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
728
1094
|
end
|
|
729
1095
|
|
|
730
1096
|
# Converts a symbol into a column name. This method supports underscore
|
|
@@ -735,10 +1101,14 @@ module Sequel
|
|
|
735
1101
|
# dataset.literal(:abc___a) #=> "abc AS a"
|
|
736
1102
|
# dataset.literal(:items__abc) #=> "items.abc"
|
|
737
1103
|
# dataset.literal(:items__abc___a) #=> "items.abc AS a"
|
|
738
|
-
def
|
|
1104
|
+
def literal_symbol_append(sql, v)
|
|
739
1105
|
c_table, column, c_alias = split_symbol(v)
|
|
740
|
-
|
|
741
|
-
|
|
1106
|
+
if c_table
|
|
1107
|
+
quote_identifier_append(sql, c_table)
|
|
1108
|
+
sql << DOT
|
|
1109
|
+
end
|
|
1110
|
+
quote_identifier_append(sql, column)
|
|
1111
|
+
as_sql_append(sql, c_alias) if c_alias
|
|
742
1112
|
end
|
|
743
1113
|
|
|
744
1114
|
# SQL fragment for Time
|
|
@@ -774,59 +1144,7 @@ module Sequel
|
|
|
774
1144
|
|
|
775
1145
|
# Qualify the given expression e to the given table.
|
|
776
1146
|
def qualified_expression(e, table)
|
|
777
|
-
|
|
778
|
-
when Symbol
|
|
779
|
-
t, column, aliaz = split_symbol(e)
|
|
780
|
-
if t
|
|
781
|
-
e
|
|
782
|
-
elsif aliaz
|
|
783
|
-
SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(table, SQL::Identifier.new(column)), aliaz)
|
|
784
|
-
else
|
|
785
|
-
SQL::QualifiedIdentifier.new(table, e)
|
|
786
|
-
end
|
|
787
|
-
when Array
|
|
788
|
-
e.map{|a| qualified_expression(a, table)}
|
|
789
|
-
when Hash
|
|
790
|
-
h = {}
|
|
791
|
-
e.each{|k,v| h[qualified_expression(k, table)] = qualified_expression(v, table)}
|
|
792
|
-
h
|
|
793
|
-
when SQL::Identifier
|
|
794
|
-
SQL::QualifiedIdentifier.new(table, e)
|
|
795
|
-
when SQL::OrderedExpression
|
|
796
|
-
SQL::OrderedExpression.new(qualified_expression(e.expression, table), e.descending, :nulls=>e.nulls)
|
|
797
|
-
when SQL::AliasedExpression
|
|
798
|
-
SQL::AliasedExpression.new(qualified_expression(e.expression, table), e.aliaz)
|
|
799
|
-
when SQL::CaseExpression
|
|
800
|
-
args = [qualified_expression(e.conditions, table), qualified_expression(e.default, table)]
|
|
801
|
-
args << qualified_expression(e.expression, table) if e.expression?
|
|
802
|
-
SQL::CaseExpression.new(*args)
|
|
803
|
-
when SQL::Cast
|
|
804
|
-
SQL::Cast.new(qualified_expression(e.expr, table), e.type)
|
|
805
|
-
when SQL::Function
|
|
806
|
-
SQL::Function.new(e.f, *qualified_expression(e.args, table))
|
|
807
|
-
when SQL::ComplexExpression
|
|
808
|
-
SQL::ComplexExpression.new(e.op, *qualified_expression(e.args, table))
|
|
809
|
-
when SQL::Subscript
|
|
810
|
-
SQL::Subscript.new(qualified_expression(e.f, table), qualified_expression(e.sub, table))
|
|
811
|
-
when SQL::WindowFunction
|
|
812
|
-
SQL::WindowFunction.new(qualified_expression(e.function, table), qualified_expression(e.window, table))
|
|
813
|
-
when SQL::Window
|
|
814
|
-
o = e.opts.dup
|
|
815
|
-
o[:partition] = qualified_expression(o[:partition], table) if o[:partition]
|
|
816
|
-
o[:order] = qualified_expression(o[:order], table) if o[:order]
|
|
817
|
-
SQL::Window.new(o)
|
|
818
|
-
when SQL::PlaceholderLiteralString
|
|
819
|
-
args = if e.args.is_a?(Hash)
|
|
820
|
-
h = {}
|
|
821
|
-
e.args.each{|k,v| h[k] = qualified_expression(v, table)}
|
|
822
|
-
h
|
|
823
|
-
else
|
|
824
|
-
qualified_expression(e.args, table)
|
|
825
|
-
end
|
|
826
|
-
SQL::PlaceholderLiteralString.new(e.str, args, e.parens)
|
|
827
|
-
else
|
|
828
|
-
e
|
|
829
|
-
end
|
|
1147
|
+
Qualifier.new(self, table).transform(e)
|
|
830
1148
|
end
|
|
831
1149
|
|
|
832
1150
|
# The order of methods to call to build the SELECT SQL statement
|
|
@@ -836,13 +1154,19 @@ module Sequel
|
|
|
836
1154
|
|
|
837
1155
|
# Modify the sql to add the columns selected
|
|
838
1156
|
def select_columns_sql(sql)
|
|
839
|
-
sql <<
|
|
1157
|
+
sql << SPACE
|
|
1158
|
+
column_list_append(sql, @opts[:select])
|
|
840
1159
|
end
|
|
841
1160
|
|
|
842
1161
|
# Modify the sql to add the DISTINCT modifier
|
|
843
1162
|
def select_distinct_sql(sql)
|
|
844
1163
|
if distinct = @opts[:distinct]
|
|
845
|
-
sql <<
|
|
1164
|
+
sql << DISTINCT
|
|
1165
|
+
unless distinct.empty?
|
|
1166
|
+
sql << ON_PAREN
|
|
1167
|
+
expression_list_append(sql, distinct)
|
|
1168
|
+
sql << PAREN_CLOSE
|
|
1169
|
+
end
|
|
846
1170
|
end
|
|
847
1171
|
end
|
|
848
1172
|
|
|
@@ -850,60 +1174,94 @@ module Sequel
|
|
|
850
1174
|
# This uses a subselect for the compound datasets used, because using parantheses doesn't
|
|
851
1175
|
# work on all databases. I consider this an ugly hack, but can't I think of a better default.
|
|
852
1176
|
def select_compounds_sql(sql)
|
|
853
|
-
return unless @opts[:compounds]
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
sql <<
|
|
1177
|
+
return unless c = @opts[:compounds]
|
|
1178
|
+
c.each do |type, dataset, all|
|
|
1179
|
+
sql << SPACE << type.to_s.upcase
|
|
1180
|
+
sql << ALL if all
|
|
1181
|
+
sql << SPACE
|
|
1182
|
+
compound_dataset_sql_append(sql, dataset)
|
|
857
1183
|
end
|
|
858
1184
|
end
|
|
859
1185
|
|
|
860
1186
|
# Modify the sql to add the list of tables to select FROM
|
|
861
1187
|
def select_from_sql(sql)
|
|
862
|
-
|
|
1188
|
+
if f = @opts[:from]
|
|
1189
|
+
sql << FROM
|
|
1190
|
+
source_list_append(sql, f)
|
|
1191
|
+
end
|
|
863
1192
|
end
|
|
864
1193
|
alias delete_from_sql select_from_sql
|
|
865
1194
|
|
|
866
1195
|
# Modify the sql to add the expressions to GROUP BY
|
|
867
1196
|
def select_group_sql(sql)
|
|
868
|
-
|
|
1197
|
+
if group = @opts[:group]
|
|
1198
|
+
sql << GROUP_BY
|
|
1199
|
+
if go = @opts[:group_options]
|
|
1200
|
+
sql << go.to_s.upcase
|
|
1201
|
+
sql << PAREN_OPEN
|
|
1202
|
+
end
|
|
1203
|
+
expression_list_append(sql, group)
|
|
1204
|
+
sql << PAREN_CLOSE if go
|
|
1205
|
+
end
|
|
869
1206
|
end
|
|
870
1207
|
|
|
871
1208
|
# Modify the sql to add the filter criteria in the HAVING clause
|
|
872
1209
|
def select_having_sql(sql)
|
|
873
|
-
|
|
1210
|
+
if having = @opts[:having]
|
|
1211
|
+
sql << HAVING
|
|
1212
|
+
literal_append(sql, having)
|
|
1213
|
+
end
|
|
874
1214
|
end
|
|
875
1215
|
|
|
876
1216
|
# Modify the sql to add the list of tables to JOIN to
|
|
877
1217
|
def select_join_sql(sql)
|
|
878
|
-
|
|
1218
|
+
if js = @opts[:join]
|
|
1219
|
+
js.each{|j| literal_append(sql, j)}
|
|
1220
|
+
end
|
|
879
1221
|
end
|
|
880
1222
|
|
|
881
1223
|
# Modify the sql to limit the number of rows returned and offset
|
|
882
1224
|
def select_limit_sql(sql)
|
|
883
|
-
|
|
884
|
-
|
|
1225
|
+
if l = @opts[:limit]
|
|
1226
|
+
sql << LIMIT
|
|
1227
|
+
literal_append(sql, l)
|
|
1228
|
+
end
|
|
1229
|
+
if o = @opts[:offset]
|
|
1230
|
+
sql << OFFSET
|
|
1231
|
+
literal_append(sql, o)
|
|
1232
|
+
end
|
|
885
1233
|
end
|
|
886
1234
|
|
|
887
1235
|
# Modify the sql to support the different types of locking modes.
|
|
888
1236
|
def select_lock_sql(sql)
|
|
889
|
-
case @opts[:lock]
|
|
1237
|
+
case l = @opts[:lock]
|
|
890
1238
|
when :update
|
|
891
1239
|
sql << FOR_UPDATE
|
|
892
1240
|
when String
|
|
893
|
-
sql <<
|
|
1241
|
+
sql << SPACE << l
|
|
894
1242
|
end
|
|
895
1243
|
end
|
|
896
1244
|
|
|
897
1245
|
# Modify the sql to add the expressions to ORDER BY
|
|
898
1246
|
def select_order_sql(sql)
|
|
899
|
-
|
|
1247
|
+
if o = @opts[:order]
|
|
1248
|
+
sql << ORDER_BY
|
|
1249
|
+
expression_list_append(sql, o)
|
|
1250
|
+
end
|
|
900
1251
|
end
|
|
901
1252
|
alias delete_order_sql select_order_sql
|
|
902
1253
|
alias update_order_sql select_order_sql
|
|
903
1254
|
|
|
1255
|
+
def select_select_sql(sql)
|
|
1256
|
+
sql << SELECT
|
|
1257
|
+
end
|
|
1258
|
+
|
|
904
1259
|
# Modify the sql to add the filter criteria in the WHERE clause
|
|
905
1260
|
def select_where_sql(sql)
|
|
906
|
-
|
|
1261
|
+
if w = @opts[:where]
|
|
1262
|
+
sql << WHERE
|
|
1263
|
+
literal_append(sql, w)
|
|
1264
|
+
end
|
|
907
1265
|
end
|
|
908
1266
|
alias delete_where_sql select_where_sql
|
|
909
1267
|
alias update_where_sql select_where_sql
|
|
@@ -912,8 +1270,26 @@ module Sequel
|
|
|
912
1270
|
def select_with_sql(sql)
|
|
913
1271
|
ws = opts[:with]
|
|
914
1272
|
return if !ws || ws.empty?
|
|
915
|
-
sql
|
|
1273
|
+
sql << select_with_sql_base
|
|
1274
|
+
c = false
|
|
1275
|
+
comma = COMMA
|
|
1276
|
+
ws.each do |w|
|
|
1277
|
+
sql << comma if c
|
|
1278
|
+
quote_identifier_append(sql, w[:name])
|
|
1279
|
+
if args = w[:args]
|
|
1280
|
+
sql << PAREN_OPEN
|
|
1281
|
+
argument_list_append(sql, args)
|
|
1282
|
+
sql << PAREN_CLOSE
|
|
1283
|
+
end
|
|
1284
|
+
sql << AS
|
|
1285
|
+
literal_dataset_append(sql, w[:dataset])
|
|
1286
|
+
c ||= true
|
|
1287
|
+
end
|
|
1288
|
+
sql << SPACE
|
|
916
1289
|
end
|
|
1290
|
+
alias delete_with_sql select_with_sql
|
|
1291
|
+
alias insert_with_sql select_with_sql
|
|
1292
|
+
alias update_with_sql select_with_sql
|
|
917
1293
|
|
|
918
1294
|
# The base keyword to use for the SQL WITH clause
|
|
919
1295
|
def select_with_sql_base
|
|
@@ -921,9 +1297,15 @@ module Sequel
|
|
|
921
1297
|
end
|
|
922
1298
|
|
|
923
1299
|
# Converts an array of source names into into a comma separated list.
|
|
924
|
-
def
|
|
925
|
-
raise(Error, 'No source specified for query') if
|
|
926
|
-
|
|
1300
|
+
def source_list_append(sql, sources)
|
|
1301
|
+
raise(Error, 'No source specified for query') if sources.nil? || sources == []
|
|
1302
|
+
c = false
|
|
1303
|
+
co = COMMA
|
|
1304
|
+
sources.each do |s|
|
|
1305
|
+
sql << co if c
|
|
1306
|
+
table_ref_append(sql, s)
|
|
1307
|
+
c ||= true
|
|
1308
|
+
end
|
|
927
1309
|
end
|
|
928
1310
|
|
|
929
1311
|
# Splits the symbol into three parts. Each part will
|
|
@@ -932,13 +1314,13 @@ module Sequel
|
|
|
932
1314
|
# For columns, these parts are the table, column, and alias.
|
|
933
1315
|
# For tables, these parts are the schema, table, and alias.
|
|
934
1316
|
def split_symbol(sym)
|
|
935
|
-
s = sym.to_s
|
|
936
|
-
|
|
937
|
-
[
|
|
938
|
-
|
|
939
|
-
[nil,
|
|
940
|
-
|
|
941
|
-
[
|
|
1317
|
+
case s = sym.to_s
|
|
1318
|
+
when COLUMN_REF_RE1
|
|
1319
|
+
[$1, $2, $3]
|
|
1320
|
+
when COLUMN_REF_RE2
|
|
1321
|
+
[nil, $1, $2]
|
|
1322
|
+
when COLUMN_REF_RE3
|
|
1323
|
+
[$1, $2, nil]
|
|
942
1324
|
else
|
|
943
1325
|
[nil, s, nil]
|
|
944
1326
|
end
|
|
@@ -948,18 +1330,35 @@ module Sequel
|
|
|
948
1330
|
# can be a PlaceholderLiteralString in addition to a String,
|
|
949
1331
|
# we literalize nonstrings.
|
|
950
1332
|
def static_sql(sql)
|
|
951
|
-
|
|
1333
|
+
if append_sql = @opts[:append_sql]
|
|
1334
|
+
if sql.is_a?(String)
|
|
1335
|
+
append_sql << sql
|
|
1336
|
+
else
|
|
1337
|
+
literal_append(append_sql, sql)
|
|
1338
|
+
end
|
|
1339
|
+
else
|
|
1340
|
+
if sql.is_a?(String)
|
|
1341
|
+
sql
|
|
1342
|
+
else
|
|
1343
|
+
literal(sql)
|
|
1344
|
+
end
|
|
1345
|
+
end
|
|
952
1346
|
end
|
|
953
1347
|
|
|
954
1348
|
# SQL fragment for a subselect using the given database's SQL.
|
|
955
|
-
def
|
|
956
|
-
ds.sql
|
|
1349
|
+
def subselect_sql_append(sql, ds)
|
|
1350
|
+
ds.clone(:append_sql=>sql).sql
|
|
957
1351
|
end
|
|
958
1352
|
|
|
959
1353
|
# SQL fragment specifying a table name.
|
|
960
|
-
def
|
|
961
|
-
t.is_a?(String)
|
|
1354
|
+
def table_ref_append(sql, t)
|
|
1355
|
+
if t.is_a?(String)
|
|
1356
|
+
quote_identifier_append(sql, t)
|
|
1357
|
+
else
|
|
1358
|
+
literal_append(sql, t)
|
|
1359
|
+
end
|
|
962
1360
|
end
|
|
1361
|
+
alias identifier_append table_ref_append
|
|
963
1362
|
|
|
964
1363
|
# The order of methods to call to build the UPDATE SQL statement
|
|
965
1364
|
def update_clause_methods
|
|
@@ -969,25 +1368,38 @@ module Sequel
|
|
|
969
1368
|
# SQL fragment specifying the tables from with to delete.
|
|
970
1369
|
# Includes join table if modifying joins is allowed.
|
|
971
1370
|
def update_table_sql(sql)
|
|
972
|
-
sql <<
|
|
1371
|
+
sql << SPACE
|
|
1372
|
+
source_list_append(sql, @opts[:from])
|
|
973
1373
|
select_join_sql(sql) if supports_modifying_joins?
|
|
974
1374
|
end
|
|
975
1375
|
|
|
976
1376
|
# The SQL fragment specifying the columns and values to SET.
|
|
977
1377
|
def update_set_sql(sql)
|
|
978
1378
|
values = opts[:values]
|
|
979
|
-
|
|
1379
|
+
sql << SET
|
|
1380
|
+
if values.is_a?(Hash)
|
|
980
1381
|
values = opts[:defaults].merge(values) if opts[:defaults]
|
|
981
1382
|
values = values.merge(opts[:overrides]) if opts[:overrides]
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1383
|
+
c = false
|
|
1384
|
+
eq = EQUAL
|
|
1385
|
+
values.each do |k, v|
|
|
1386
|
+
sql << COMMA if c
|
|
1387
|
+
if k.is_a?(String) && !k.is_a?(LiteralString)
|
|
1388
|
+
quote_identifier_append(sql, k)
|
|
1389
|
+
else
|
|
1390
|
+
literal_append(sql, k)
|
|
1391
|
+
end
|
|
1392
|
+
sql << eq
|
|
1393
|
+
literal_append(sql, v)
|
|
1394
|
+
c ||= true
|
|
1395
|
+
end
|
|
986
1396
|
else
|
|
987
|
-
|
|
988
|
-
values
|
|
1397
|
+
sql << values
|
|
989
1398
|
end
|
|
990
|
-
|
|
1399
|
+
end
|
|
1400
|
+
|
|
1401
|
+
def update_update_sql(sql)
|
|
1402
|
+
sql << UPDATE
|
|
991
1403
|
end
|
|
992
1404
|
end
|
|
993
1405
|
end
|