sequel 3.21.0 → 3.32.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 +539 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/advanced_associations.rdoc +17 -0
- data/doc/association_basics.rdoc +293 -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/release_notes/3.32.0.txt +202 -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 +52 -0
- data/lib/sequel/adapters/jdbc/derby.rb +260 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +66 -30
- data/lib/sequel/adapters/jdbc/hsqldb.rb +177 -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 +88 -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 +339 -0
- data/lib/sequel/adapters/mysql.rb +85 -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 +355 -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 +328 -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 +278 -107
- data/lib/sequel/adapters/shared/mysql.rb +203 -65
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +237 -46
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +200 -50
- 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 +68 -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 +163 -59
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +240 -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 +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +59 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +676 -267
- 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/query.rb +1 -1
- 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 +1081 -344
- data/lib/sequel/model/base.rb +420 -133
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +20 -10
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +43 -10
- 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 +68 -7
- data/lib/sequel/plugins/nested_attributes.rb +65 -10
- 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 +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -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 +135 -30
- data/spec/adapters/mysql_spec.rb +244 -212
- data/spec/adapters/oracle_spec.rb +67 -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 +789 -512
- data/spec/core/dataset_spec.rb +1176 -1061
- 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/active_model_spec.rb +13 -0
- 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/query_spec.rb +6 -0
- 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 +72 -0
- data/spec/extensions/serialization_spec.rb +81 -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 +661 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +500 -67
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +367 -119
- data/spec/integration/prepared_statement_test.rb +222 -125
- data/spec/integration/schema_test.rb +217 -39
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +182 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +955 -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 +349 -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 +117 -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)
|
|
@@ -256,147 +419,219 @@ module Sequel
|
|
|
256
419
|
val_array = true
|
|
257
420
|
empty_val_array = vals == []
|
|
258
421
|
end
|
|
259
|
-
if
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
else
|
|
264
|
-
literal(1=>1)
|
|
265
|
-
end
|
|
266
|
-
elsif !supports_multiple_column_in?
|
|
422
|
+
if empty_val_array
|
|
423
|
+
literal_append(sql, empty_array_value(op, cols))
|
|
424
|
+
elsif col_array
|
|
425
|
+
if !supports_multiple_column_in?
|
|
267
426
|
if val_array
|
|
268
427
|
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
|
-
|
|
428
|
+
literal_append(sql, op == :IN ? expr : ~expr)
|
|
270
429
|
else
|
|
271
430
|
old_vals = vals
|
|
431
|
+
vals = vals.naked if vals.is_a?(Sequel::Dataset)
|
|
272
432
|
vals = vals.to_a
|
|
273
433
|
val_cols = old_vals.columns
|
|
274
|
-
|
|
434
|
+
complex_expression_sql_append(sql, op, [cols, vals.map!{|x| x.values_at(*val_cols)}])
|
|
275
435
|
end
|
|
276
436
|
else
|
|
277
437
|
# If the columns and values are both arrays, use array_sql instead of
|
|
278
438
|
# literal so that if values is an array of two element arrays, it
|
|
279
439
|
# will be treated as a value list instead of a condition specifier.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
literal(SQL::BooleanExpression.from_value_pairs([[cols, cols]], :AND, true))
|
|
440
|
+
sql << PAREN_OPEN
|
|
441
|
+
literal_append(sql, cols)
|
|
442
|
+
sql << SPACE << op.to_s << SPACE
|
|
443
|
+
if val_array
|
|
444
|
+
array_sql_append(sql, vals)
|
|
286
445
|
else
|
|
287
|
-
|
|
446
|
+
literal_append(sql, vals)
|
|
288
447
|
end
|
|
289
|
-
|
|
290
|
-
"(#{literal(cols)} #{op} #{literal(vals)})"
|
|
448
|
+
sql << PAREN_CLOSE
|
|
291
449
|
end
|
|
450
|
+
else
|
|
451
|
+
sql << PAREN_OPEN
|
|
452
|
+
literal_append(sql, cols)
|
|
453
|
+
sql << SPACE << op.to_s << SPACE
|
|
454
|
+
literal_append(sql, vals)
|
|
455
|
+
sql << PAREN_CLOSE
|
|
292
456
|
end
|
|
293
457
|
when *TWO_ARITY_OPERATORS
|
|
294
|
-
|
|
458
|
+
sql << PAREN_OPEN
|
|
459
|
+
literal_append(sql, args.at(0))
|
|
460
|
+
sql << SPACE << op.to_s << SPACE
|
|
461
|
+
literal_append(sql, args.at(1))
|
|
462
|
+
sql << PAREN_CLOSE
|
|
295
463
|
when *N_ARITY_OPERATORS
|
|
296
|
-
|
|
464
|
+
sql << PAREN_OPEN
|
|
465
|
+
c = false
|
|
466
|
+
op_str = " #{op} "
|
|
467
|
+
args.each do |a|
|
|
468
|
+
sql << op_str if c
|
|
469
|
+
literal_append(sql, a)
|
|
470
|
+
c ||= true
|
|
471
|
+
end
|
|
472
|
+
sql << PAREN_CLOSE
|
|
297
473
|
when :NOT
|
|
298
|
-
|
|
474
|
+
sql << NOT_SPACE
|
|
475
|
+
literal_append(sql, args.at(0))
|
|
299
476
|
when :NOOP
|
|
300
|
-
|
|
477
|
+
literal_append(sql, args.at(0))
|
|
301
478
|
when :'B~'
|
|
302
|
-
|
|
479
|
+
sql << TILDE
|
|
480
|
+
literal_append(sql, args.at(0))
|
|
481
|
+
when :extract
|
|
482
|
+
sql << EXTRACT << args.at(0).to_s << FROM
|
|
483
|
+
literal_append(sql, args.at(1))
|
|
484
|
+
sql << PAREN_CLOSE
|
|
303
485
|
else
|
|
304
486
|
raise(InvalidOperation, "invalid operator #{op}")
|
|
305
487
|
end
|
|
306
488
|
end
|
|
307
489
|
|
|
308
490
|
# SQL fragment for constants
|
|
309
|
-
def
|
|
310
|
-
constant.to_s
|
|
491
|
+
def constant_sql_append(sql, constant)
|
|
492
|
+
sql << constant.to_s
|
|
311
493
|
end
|
|
312
494
|
|
|
313
495
|
# SQL fragment specifying an SQL function call
|
|
314
|
-
def
|
|
496
|
+
def function_sql_append(sql, f)
|
|
497
|
+
sql << f.f.to_s
|
|
315
498
|
args = f.args
|
|
316
|
-
|
|
499
|
+
if args.empty?
|
|
500
|
+
sql << FUNCTION_EMPTY
|
|
501
|
+
else
|
|
502
|
+
literal_append(sql, args)
|
|
503
|
+
end
|
|
317
504
|
end
|
|
318
505
|
|
|
319
506
|
# SQL fragment specifying a JOIN clause without ON or USING.
|
|
320
|
-
def
|
|
507
|
+
def join_clause_sql_append(sql, jc)
|
|
321
508
|
table = jc.table
|
|
322
509
|
table_alias = jc.table_alias
|
|
323
510
|
table_alias = nil if table == table_alias
|
|
324
|
-
|
|
325
|
-
|
|
511
|
+
sql << SPACE << join_type_sql(jc.join_type) << SPACE
|
|
512
|
+
table_ref_append(sql, table)
|
|
513
|
+
as_sql_append(sql, table_alias) if table_alias
|
|
326
514
|
end
|
|
327
515
|
|
|
328
516
|
# SQL fragment specifying a JOIN clause with ON.
|
|
329
|
-
def
|
|
330
|
-
|
|
517
|
+
def join_on_clause_sql_append(sql, jc)
|
|
518
|
+
join_clause_sql_append(sql, jc)
|
|
519
|
+
sql << ON
|
|
520
|
+
literal_append(sql, filter_expr(jc.on))
|
|
331
521
|
end
|
|
332
522
|
|
|
333
523
|
# SQL fragment specifying a JOIN clause with USING.
|
|
334
|
-
def
|
|
335
|
-
|
|
524
|
+
def join_using_clause_sql_append(sql, jc)
|
|
525
|
+
join_clause_sql_append(sql, jc)
|
|
526
|
+
sql << USING
|
|
527
|
+
column_list_append(sql, jc.using)
|
|
528
|
+
sql << PAREN_CLOSE
|
|
336
529
|
end
|
|
337
530
|
|
|
338
531
|
# SQL fragment for NegativeBooleanConstants
|
|
339
|
-
def
|
|
340
|
-
|
|
532
|
+
def negative_boolean_constant_sql_append(sql, constant)
|
|
533
|
+
sql << NOT_SPACE
|
|
534
|
+
boolean_constant_sql_append(sql, constant)
|
|
341
535
|
end
|
|
342
536
|
|
|
343
537
|
# SQL fragment for the ordered expression, used in the ORDER BY
|
|
344
538
|
# clause.
|
|
345
|
-
def
|
|
346
|
-
|
|
539
|
+
def ordered_expression_sql_append(sql, oe)
|
|
540
|
+
literal_append(sql, oe.expression)
|
|
541
|
+
sql << (oe.descending ? DESC : ASC)
|
|
347
542
|
case oe.nulls
|
|
348
543
|
when :first
|
|
349
|
-
|
|
544
|
+
sql << NULLS_FIRST
|
|
350
545
|
when :last
|
|
351
|
-
|
|
352
|
-
else
|
|
353
|
-
s
|
|
546
|
+
sql << NULLS_LAST
|
|
354
547
|
end
|
|
355
548
|
end
|
|
356
549
|
|
|
357
550
|
# SQL fragment for a literal string with placeholders
|
|
358
|
-
def
|
|
551
|
+
def placeholder_literal_string_sql_append(sql, pls)
|
|
359
552
|
args = pls.args
|
|
360
|
-
|
|
553
|
+
sql << PAREN_OPEN if pls.parens
|
|
554
|
+
if args.is_a?(Hash)
|
|
361
555
|
re = /:(#{args.keys.map{|k| Regexp.escape(k.to_s)}.join('|')})\b/
|
|
362
|
-
|
|
556
|
+
if RUBY_VERSION >= '1.8.7'
|
|
557
|
+
str = pls.str
|
|
558
|
+
loop do
|
|
559
|
+
previous, q, str = str.partition(re)
|
|
560
|
+
sql << previous
|
|
561
|
+
literal_append(sql, args[($1||q[1..-1].to_s).to_sym]) unless q.empty?
|
|
562
|
+
break if str.empty?
|
|
563
|
+
end
|
|
564
|
+
else
|
|
565
|
+
sql << pls.str.gsub(re){literal(args[$1.to_sym])}
|
|
566
|
+
end
|
|
363
567
|
else
|
|
364
568
|
i = -1
|
|
365
|
-
|
|
569
|
+
if RUBY_VERSION >= '1.8.7'
|
|
570
|
+
str = pls.str
|
|
571
|
+
loop do
|
|
572
|
+
previous, q, str = str.partition(QUESTION_MARK)
|
|
573
|
+
sql << previous
|
|
574
|
+
literal_append(sql, args.at(i+=1)) unless q.empty?
|
|
575
|
+
break if str.empty?
|
|
576
|
+
end
|
|
577
|
+
else
|
|
578
|
+
sql << pls.str.gsub(QUESTION_MARK_RE){literal(args.at(i+=1))}
|
|
579
|
+
end
|
|
366
580
|
end
|
|
367
|
-
|
|
368
|
-
s
|
|
581
|
+
sql << PAREN_CLOSE if pls.parens
|
|
369
582
|
end
|
|
370
583
|
|
|
371
584
|
# SQL fragment for the qualifed identifier, specifying
|
|
372
585
|
# a table and a column (or schema and table).
|
|
373
|
-
def
|
|
374
|
-
|
|
586
|
+
def qualified_identifier_sql_append(sql, qcr)
|
|
587
|
+
case t = qcr.table
|
|
588
|
+
when Symbol, SQL::QualifiedIdentifier, SQL::Identifier
|
|
589
|
+
literal_append(sql, t)
|
|
590
|
+
else
|
|
591
|
+
quote_identifier_append(sql, t)
|
|
592
|
+
end
|
|
593
|
+
sql << DOT
|
|
594
|
+
case c = qcr.column
|
|
595
|
+
when Symbol, SQL::QualifiedIdentifier, SQL::Identifier
|
|
596
|
+
literal_append(sql, c)
|
|
597
|
+
else
|
|
598
|
+
quote_identifier_append(sql, c)
|
|
599
|
+
end
|
|
375
600
|
end
|
|
376
601
|
|
|
377
602
|
# Adds quoting to identifiers (columns and tables). If identifiers are not
|
|
378
603
|
# being quoted, returns name as a string. If identifiers are being quoted
|
|
379
604
|
# quote the name with quoted_identifier.
|
|
380
|
-
def
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
605
|
+
def quote_identifier_append(sql, name)
|
|
606
|
+
if name.is_a?(LiteralString)
|
|
607
|
+
sql << name
|
|
608
|
+
else
|
|
609
|
+
name = name.value if name.is_a?(SQL::Identifier)
|
|
610
|
+
name = input_identifier(name)
|
|
611
|
+
if quote_identifiers?
|
|
612
|
+
quoted_identifier_append(sql, name)
|
|
613
|
+
else
|
|
614
|
+
sql << name
|
|
615
|
+
end
|
|
616
|
+
end
|
|
386
617
|
end
|
|
387
618
|
|
|
388
619
|
# Separates the schema from the table and returns a string with them
|
|
389
620
|
# quoted (if quoting identifiers)
|
|
390
|
-
def
|
|
621
|
+
def quote_schema_table_append(sql, table)
|
|
391
622
|
schema, table = schema_and_table(table)
|
|
392
|
-
|
|
623
|
+
if schema
|
|
624
|
+
quote_identifier_append(sql, schema)
|
|
625
|
+
sql << DOT
|
|
626
|
+
end
|
|
627
|
+
quote_identifier_append(sql, table)
|
|
393
628
|
end
|
|
394
629
|
|
|
395
630
|
# This method quotes the given name with the SQL standard double quote.
|
|
396
631
|
# should be overridden by subclasses to provide quoting not matching the
|
|
397
632
|
# SQL standard, such as backtick (used by MySQL and SQLite).
|
|
398
|
-
def
|
|
399
|
-
|
|
633
|
+
def quoted_identifier_append(sql, name)
|
|
634
|
+
sql << QUOTE << name.to_s.gsub(QUOTE_RE, DOUBLE_QUOTE) << QUOTE
|
|
400
635
|
end
|
|
401
636
|
|
|
402
637
|
# Split the schema information from the table
|
|
@@ -418,34 +653,59 @@ module Sequel
|
|
|
418
653
|
end
|
|
419
654
|
|
|
420
655
|
# SQL fragment for specifying subscripts (SQL array accesses)
|
|
421
|
-
def
|
|
422
|
-
|
|
656
|
+
def subscript_sql_append(sql, s)
|
|
657
|
+
literal_append(sql, s.f)
|
|
658
|
+
sql << BRACKET_OPEN
|
|
659
|
+
expression_list_append(sql, s.sub)
|
|
660
|
+
sql << BRACKET_CLOSE
|
|
423
661
|
end
|
|
424
662
|
|
|
425
663
|
# The SQL fragment for the given window's options.
|
|
426
|
-
def
|
|
664
|
+
def window_sql_append(sql, opts)
|
|
427
665
|
raise(Error, 'This dataset does not support window functions') unless supports_window_functions?
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
666
|
+
sql << PAREN_OPEN
|
|
667
|
+
window, part, order, frame = opts.values_at(:window, :partition, :order, :frame)
|
|
668
|
+
space = false
|
|
669
|
+
space_s = SPACE
|
|
670
|
+
if window
|
|
671
|
+
literal_append(sql, window)
|
|
672
|
+
space = true
|
|
673
|
+
end
|
|
674
|
+
if part
|
|
675
|
+
sql << space_s if space
|
|
676
|
+
sql << PARTITION_BY
|
|
677
|
+
expression_list_append(sql, Array(part))
|
|
678
|
+
space = true
|
|
679
|
+
end
|
|
680
|
+
if order
|
|
681
|
+
sql << space_s if space
|
|
682
|
+
sql << ORDER_BY_NS
|
|
683
|
+
expression_list_append(sql, Array(order))
|
|
684
|
+
space = true
|
|
685
|
+
end
|
|
686
|
+
case frame
|
|
432
687
|
when nil
|
|
433
|
-
|
|
688
|
+
# nothing
|
|
434
689
|
when :all
|
|
435
|
-
|
|
690
|
+
sql << space_s if space
|
|
691
|
+
sql << FRAME_ALL
|
|
436
692
|
when :rows
|
|
437
|
-
|
|
693
|
+
sql << space_s if space
|
|
694
|
+
sql << FRAME_ROWS
|
|
438
695
|
when String
|
|
439
|
-
|
|
696
|
+
sql << space_s if space
|
|
697
|
+
sql << frame
|
|
440
698
|
else
|
|
441
699
|
raise Error, "invalid window frame clause, should be :all, :rows, a string, or nil"
|
|
442
700
|
end
|
|
443
|
-
|
|
701
|
+
sql << PAREN_CLOSE
|
|
444
702
|
end
|
|
445
703
|
|
|
446
704
|
# The SQL fragment for the given window function's function and window.
|
|
447
|
-
def
|
|
448
|
-
|
|
705
|
+
def window_function_sql_append(sql, function, window)
|
|
706
|
+
literal_append(sql, function)
|
|
707
|
+
sql << OVER
|
|
708
|
+
literal_append(sql, window)
|
|
449
709
|
end
|
|
450
710
|
|
|
451
711
|
protected
|
|
@@ -517,14 +777,20 @@ module Sequel
|
|
|
517
777
|
options_overlap(COUNT_FROM_SELF_OPTS) ? from_self : unordered
|
|
518
778
|
end
|
|
519
779
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
780
|
+
def argument_list_append(sql, args)
|
|
781
|
+
c = false
|
|
782
|
+
comma = COMMA
|
|
783
|
+
args.each do |a|
|
|
784
|
+
sql << comma if c
|
|
785
|
+
sql << a.to_s
|
|
786
|
+
c ||= true
|
|
787
|
+
end
|
|
523
788
|
end
|
|
524
789
|
|
|
525
790
|
# SQL fragment for specifying an alias. expression should already be literalized.
|
|
526
|
-
def
|
|
527
|
-
|
|
791
|
+
def as_sql_append(sql, aliaz)
|
|
792
|
+
sql << AS
|
|
793
|
+
quote_identifier_append(sql, aliaz)
|
|
528
794
|
end
|
|
529
795
|
|
|
530
796
|
# Raise an InvalidOperation exception if deletion is not allowed
|
|
@@ -536,36 +802,81 @@ module Sequel
|
|
|
536
802
|
|
|
537
803
|
# Prepare an SQL statement by calling all clause methods for the given statement type.
|
|
538
804
|
def clause_sql(type)
|
|
539
|
-
sql =
|
|
805
|
+
sql = @opts[:append_sql] || ''
|
|
540
806
|
send("#{type}_clause_methods").each{|x| send(x, sql)}
|
|
541
807
|
sql
|
|
542
808
|
end
|
|
543
809
|
|
|
544
810
|
# Converts an array of column names into a comma seperated string of
|
|
545
811
|
# column names. If the array is empty, a wildcard (*) is returned.
|
|
546
|
-
def
|
|
547
|
-
(columns.nil? || columns.empty?)
|
|
812
|
+
def column_list_append(sql, columns)
|
|
813
|
+
if (columns.nil? || columns.empty?)
|
|
814
|
+
sql << WILDCARD
|
|
815
|
+
else
|
|
816
|
+
expression_list_append(sql, columns)
|
|
817
|
+
end
|
|
548
818
|
end
|
|
549
|
-
|
|
819
|
+
|
|
820
|
+
# Yield each two pair of arguments to the block, which should
|
|
821
|
+
# return a string representing the SQL code for those
|
|
822
|
+
# two arguments. If more than 2 arguments are provided, all
|
|
823
|
+
# calls to the block # after the first will have a LiteralString
|
|
824
|
+
# as the first argument, representing the application of the block to
|
|
825
|
+
# the previous arguments.
|
|
826
|
+
def complex_expression_arg_pairs(args)
|
|
827
|
+
case args.length
|
|
828
|
+
when 1
|
|
829
|
+
literal(args.at(0))
|
|
830
|
+
when 2
|
|
831
|
+
yield args.at(0), args.at(1)
|
|
832
|
+
else
|
|
833
|
+
args.inject{|m, a| LiteralString.new(yield(m, a))}
|
|
834
|
+
end
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
# The SQL to use for the dataset used in a UNION/INTERSECT/EXCEPT clause.
|
|
838
|
+
def compound_dataset_sql_append(sql, ds)
|
|
839
|
+
subselect_sql_append(sql, ds)
|
|
840
|
+
end
|
|
841
|
+
|
|
550
842
|
# The alias to use for datasets, takes a number to make sure the name is unique.
|
|
551
843
|
def dataset_alias(number)
|
|
552
844
|
:"#{DATASET_ALIAS_BASE_NAME}#{number}"
|
|
553
845
|
end
|
|
554
846
|
|
|
847
|
+
# The strftime format to use when literalizing the time.
|
|
848
|
+
def default_timestamp_format
|
|
849
|
+
requires_sql_standard_datetimes? ? STANDARD_TIMESTAMP_FORMAT : TIMESTAMP_FORMAT
|
|
850
|
+
end
|
|
851
|
+
|
|
555
852
|
# The order of methods to call to build the DELETE SQL statement
|
|
556
853
|
def delete_clause_methods
|
|
557
854
|
DELETE_CLAUSE_METHODS
|
|
558
855
|
end
|
|
559
856
|
|
|
857
|
+
def delete_delete_sql(sql)
|
|
858
|
+
sql << DELETE
|
|
859
|
+
end
|
|
860
|
+
|
|
560
861
|
# Converts an array of expressions into a comma separated string of
|
|
561
862
|
# expressions.
|
|
562
|
-
def
|
|
563
|
-
|
|
863
|
+
def expression_list_append(sql, columns)
|
|
864
|
+
c = false
|
|
865
|
+
co = COMMA
|
|
866
|
+
columns.each do |col|
|
|
867
|
+
sql << co if c
|
|
868
|
+
literal_append(sql, col)
|
|
869
|
+
c ||= true
|
|
870
|
+
end
|
|
564
871
|
end
|
|
565
872
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
873
|
+
def empty_array_value(op, cols)
|
|
874
|
+
if Sequel.empty_array_handle_nulls
|
|
875
|
+
c = Array(cols)
|
|
876
|
+
SQL::BooleanExpression.from_value_pairs(c.zip(c), :AND, op == :IN)
|
|
877
|
+
else
|
|
878
|
+
{1 => ((op == :IN) ? 0 : 1)}
|
|
879
|
+
end
|
|
569
880
|
end
|
|
570
881
|
|
|
571
882
|
# Format the timestamp based on the default_timestamp_format, with a couple
|
|
@@ -573,9 +884,9 @@ module Sequel
|
|
|
573
884
|
# database supports them), and override %z to always use a numeric offset
|
|
574
885
|
# of hours and minutes.
|
|
575
886
|
def format_timestamp(v)
|
|
576
|
-
v2 =
|
|
577
|
-
fmt = default_timestamp_format.gsub(
|
|
578
|
-
if m ==
|
|
887
|
+
v2 = db.from_application_timestamp(v)
|
|
888
|
+
fmt = default_timestamp_format.gsub(FORMAT_TIMESTAMP_RE) do |m|
|
|
889
|
+
if m == FORMAT_USEC
|
|
579
890
|
format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION < '1.9.0' ? 86400000000 : 1000000) : v.usec) if supports_timestamp_usecs?
|
|
580
891
|
else
|
|
581
892
|
if supports_timestamp_timezones?
|
|
@@ -591,13 +902,13 @@ module Sequel
|
|
|
591
902
|
|
|
592
903
|
# Return the SQL timestamp fragment to use for the timezone offset.
|
|
593
904
|
def format_timestamp_offset(hour, minute)
|
|
594
|
-
sprintf(
|
|
905
|
+
sprintf(FORMAT_OFFSET, hour, minute)
|
|
595
906
|
end
|
|
596
907
|
|
|
597
908
|
# Return the SQL timestamp fragment to use for the fractional time part.
|
|
598
909
|
# Should start with the decimal point. Uses 6 decimal places by default.
|
|
599
910
|
def format_timestamp_usec(usec)
|
|
600
|
-
sprintf(
|
|
911
|
+
sprintf(FORMAT_TIMESTAMP_USEC, usec)
|
|
601
912
|
end
|
|
602
913
|
|
|
603
914
|
# Modify the identifier returned from the database based on the
|
|
@@ -608,7 +919,8 @@ module Sequel
|
|
|
608
919
|
|
|
609
920
|
# SQL fragment specifying the table to insert INTO
|
|
610
921
|
def insert_into_sql(sql)
|
|
611
|
-
sql <<
|
|
922
|
+
sql << INTO
|
|
923
|
+
source_list_append(sql, @opts[:from])
|
|
612
924
|
end
|
|
613
925
|
|
|
614
926
|
# The order of methods to call to build the INSERT SQL statement
|
|
@@ -619,27 +931,61 @@ module Sequel
|
|
|
619
931
|
# SQL fragment specifying the columns to insert into
|
|
620
932
|
def insert_columns_sql(sql)
|
|
621
933
|
columns = opts[:columns]
|
|
622
|
-
|
|
934
|
+
if columns && !columns.empty?
|
|
935
|
+
sql << PAREN_SPACE_OPEN
|
|
936
|
+
c = false
|
|
937
|
+
co = COMMA
|
|
938
|
+
columns.each do |col|
|
|
939
|
+
sql << co if c
|
|
940
|
+
if col.is_a?(String) && !col.is_a?(LiteralString)
|
|
941
|
+
quote_identifier_append(sql, col)
|
|
942
|
+
else
|
|
943
|
+
literal_append(sql, col)
|
|
944
|
+
end
|
|
945
|
+
c ||= true
|
|
946
|
+
end
|
|
947
|
+
sql << PAREN_CLOSE
|
|
948
|
+
end
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
def insert_insert_sql(sql)
|
|
952
|
+
sql << INSERT
|
|
623
953
|
end
|
|
624
954
|
|
|
625
955
|
# SQL fragment specifying the values to insert.
|
|
626
956
|
def insert_values_sql(sql)
|
|
627
957
|
case values = opts[:values]
|
|
628
958
|
when Array
|
|
629
|
-
|
|
959
|
+
if values.empty?
|
|
960
|
+
sql << DEFAULT_VALUES
|
|
961
|
+
else
|
|
962
|
+
sql << VALUES
|
|
963
|
+
literal_append(sql, values)
|
|
964
|
+
end
|
|
630
965
|
when Dataset
|
|
631
|
-
sql <<
|
|
966
|
+
sql << SPACE
|
|
967
|
+
subselect_sql_append(sql, values)
|
|
632
968
|
when LiteralString
|
|
633
|
-
sql <<
|
|
969
|
+
sql << SPACE << values
|
|
634
970
|
else
|
|
635
971
|
raise Error, "Unsupported INSERT values type, should be an Array or Dataset: #{values.inspect}"
|
|
636
972
|
end
|
|
637
973
|
end
|
|
638
974
|
|
|
975
|
+
# SQL fragment specifying the values to return.
|
|
976
|
+
def insert_returning_sql(sql)
|
|
977
|
+
if opts.has_key?(:returning)
|
|
978
|
+
sql << RETURNING
|
|
979
|
+
column_list_append(sql, Array(opts[:returning]))
|
|
980
|
+
end
|
|
981
|
+
end
|
|
982
|
+
alias delete_returning_sql insert_returning_sql
|
|
983
|
+
alias update_returning_sql insert_returning_sql
|
|
984
|
+
|
|
639
985
|
# SQL fragment specifying a JOIN type, converts underscores to
|
|
640
986
|
# spaces and upcases.
|
|
641
987
|
def join_type_sql(join_type)
|
|
642
|
-
"#{join_type.to_s.gsub(
|
|
988
|
+
"#{join_type.to_s.gsub(UNDERSCORE, SPACE).upcase} JOIN"
|
|
643
989
|
end
|
|
644
990
|
|
|
645
991
|
# Whether this dataset is a joined dataset
|
|
@@ -648,8 +994,12 @@ module Sequel
|
|
|
648
994
|
end
|
|
649
995
|
|
|
650
996
|
# 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)
|
|
997
|
+
def literal_array_append(sql, v)
|
|
998
|
+
if Sequel.condition_specifier?(v)
|
|
999
|
+
literal_expression_append(sql, SQL::BooleanExpression.from_value_pairs(v))
|
|
1000
|
+
else
|
|
1001
|
+
array_sql_append(sql, v)
|
|
1002
|
+
end
|
|
653
1003
|
end
|
|
654
1004
|
|
|
655
1005
|
# SQL fragment for BigDecimal
|
|
@@ -659,18 +1009,24 @@ module Sequel
|
|
|
659
1009
|
end
|
|
660
1010
|
|
|
661
1011
|
# SQL fragment for SQL::Blob
|
|
662
|
-
def
|
|
663
|
-
|
|
1012
|
+
def literal_blob_append(sql, v)
|
|
1013
|
+
literal_string_append(sql, v)
|
|
664
1014
|
end
|
|
665
1015
|
|
|
666
1016
|
# SQL fragment for Dataset. Does a subselect inside parantheses.
|
|
667
|
-
def
|
|
668
|
-
|
|
1017
|
+
def literal_dataset_append(sql, v)
|
|
1018
|
+
sql << PAREN_OPEN
|
|
1019
|
+
subselect_sql_append(sql, v)
|
|
1020
|
+
sql << PAREN_CLOSE
|
|
669
1021
|
end
|
|
670
1022
|
|
|
671
1023
|
# SQL fragment for Date, using the ISO8601 format.
|
|
672
1024
|
def literal_date(v)
|
|
673
|
-
|
|
1025
|
+
if requires_sql_standard_datetimes?
|
|
1026
|
+
v.strftime(FORMAT_DATE_STANDARD)
|
|
1027
|
+
else
|
|
1028
|
+
v.strftime(FORMAT_DATE)
|
|
1029
|
+
end
|
|
674
1030
|
end
|
|
675
1031
|
|
|
676
1032
|
# SQL fragment for DateTime
|
|
@@ -679,8 +1035,8 @@ module Sequel
|
|
|
679
1035
|
end
|
|
680
1036
|
|
|
681
1037
|
# SQL fragment for SQL::Expression, result depends on the specific type of expression.
|
|
682
|
-
def
|
|
683
|
-
v.
|
|
1038
|
+
def literal_expression_append(sql, v)
|
|
1039
|
+
v.to_s_append(self, sql)
|
|
684
1040
|
end
|
|
685
1041
|
|
|
686
1042
|
# SQL fragment for false
|
|
@@ -694,8 +1050,8 @@ module Sequel
|
|
|
694
1050
|
end
|
|
695
1051
|
|
|
696
1052
|
# SQL fragment for Hash, treated as an expression
|
|
697
|
-
def
|
|
698
|
-
|
|
1053
|
+
def literal_hash_append(sql, v)
|
|
1054
|
+
literal_expression_append(sql, SQL::BooleanExpression.from_value_pairs(v))
|
|
699
1055
|
end
|
|
700
1056
|
|
|
701
1057
|
# SQL fragment for Integer
|
|
@@ -714,17 +1070,24 @@ module Sequel
|
|
|
714
1070
|
# provided and should add that method to Sequel::Dataset, allowing for adapters
|
|
715
1071
|
# to provide customized literalizations.
|
|
716
1072
|
# If a database specific type is allowed, this should be overriden in a subclass.
|
|
717
|
-
def
|
|
718
|
-
if v.respond_to?(:
|
|
719
|
-
v.
|
|
1073
|
+
def literal_other_append(sql, v)
|
|
1074
|
+
if v.respond_to?(:sql_literal_append)
|
|
1075
|
+
v.sql_literal_append(self, sql)
|
|
1076
|
+
elsif v.respond_to?(:sql_literal)
|
|
1077
|
+
sql << v.sql_literal(self)
|
|
720
1078
|
else
|
|
721
1079
|
raise Error, "can't express #{v.inspect} as a SQL literal"
|
|
722
1080
|
end
|
|
723
1081
|
end
|
|
724
1082
|
|
|
1083
|
+
# SQL fragment for Sequel::SQLTime, containing just the time part
|
|
1084
|
+
def literal_sqltime(v)
|
|
1085
|
+
v.strftime("'%H:%M:%S#{format_timestamp_usec(v.usec) if supports_timestamp_usecs?}'")
|
|
1086
|
+
end
|
|
1087
|
+
|
|
725
1088
|
# SQL fragment for String. Doubles \ and ' by default.
|
|
726
|
-
def
|
|
727
|
-
|
|
1089
|
+
def literal_string_append(sql, v)
|
|
1090
|
+
sql << APOS << v.gsub(BACKSLASH_RE, QUAD_BACKSLASH).gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
728
1091
|
end
|
|
729
1092
|
|
|
730
1093
|
# Converts a symbol into a column name. This method supports underscore
|
|
@@ -735,10 +1098,14 @@ module Sequel
|
|
|
735
1098
|
# dataset.literal(:abc___a) #=> "abc AS a"
|
|
736
1099
|
# dataset.literal(:items__abc) #=> "items.abc"
|
|
737
1100
|
# dataset.literal(:items__abc___a) #=> "items.abc AS a"
|
|
738
|
-
def
|
|
1101
|
+
def literal_symbol_append(sql, v)
|
|
739
1102
|
c_table, column, c_alias = split_symbol(v)
|
|
740
|
-
|
|
741
|
-
|
|
1103
|
+
if c_table
|
|
1104
|
+
quote_identifier_append(sql, c_table)
|
|
1105
|
+
sql << DOT
|
|
1106
|
+
end
|
|
1107
|
+
quote_identifier_append(sql, column)
|
|
1108
|
+
as_sql_append(sql, c_alias) if c_alias
|
|
742
1109
|
end
|
|
743
1110
|
|
|
744
1111
|
# SQL fragment for Time
|
|
@@ -774,59 +1141,7 @@ module Sequel
|
|
|
774
1141
|
|
|
775
1142
|
# Qualify the given expression e to the given table.
|
|
776
1143
|
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
|
|
1144
|
+
Qualifier.new(self, table).transform(e)
|
|
830
1145
|
end
|
|
831
1146
|
|
|
832
1147
|
# The order of methods to call to build the SELECT SQL statement
|
|
@@ -836,13 +1151,19 @@ module Sequel
|
|
|
836
1151
|
|
|
837
1152
|
# Modify the sql to add the columns selected
|
|
838
1153
|
def select_columns_sql(sql)
|
|
839
|
-
sql <<
|
|
1154
|
+
sql << SPACE
|
|
1155
|
+
column_list_append(sql, @opts[:select])
|
|
840
1156
|
end
|
|
841
1157
|
|
|
842
1158
|
# Modify the sql to add the DISTINCT modifier
|
|
843
1159
|
def select_distinct_sql(sql)
|
|
844
1160
|
if distinct = @opts[:distinct]
|
|
845
|
-
sql <<
|
|
1161
|
+
sql << DISTINCT
|
|
1162
|
+
unless distinct.empty?
|
|
1163
|
+
sql << ON_PAREN
|
|
1164
|
+
expression_list_append(sql, distinct)
|
|
1165
|
+
sql << PAREN_CLOSE
|
|
1166
|
+
end
|
|
846
1167
|
end
|
|
847
1168
|
end
|
|
848
1169
|
|
|
@@ -850,60 +1171,94 @@ module Sequel
|
|
|
850
1171
|
# This uses a subselect for the compound datasets used, because using parantheses doesn't
|
|
851
1172
|
# work on all databases. I consider this an ugly hack, but can't I think of a better default.
|
|
852
1173
|
def select_compounds_sql(sql)
|
|
853
|
-
return unless @opts[:compounds]
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
sql <<
|
|
1174
|
+
return unless c = @opts[:compounds]
|
|
1175
|
+
c.each do |type, dataset, all|
|
|
1176
|
+
sql << SPACE << type.to_s.upcase
|
|
1177
|
+
sql << ALL if all
|
|
1178
|
+
sql << SPACE
|
|
1179
|
+
compound_dataset_sql_append(sql, dataset)
|
|
857
1180
|
end
|
|
858
1181
|
end
|
|
859
1182
|
|
|
860
1183
|
# Modify the sql to add the list of tables to select FROM
|
|
861
1184
|
def select_from_sql(sql)
|
|
862
|
-
|
|
1185
|
+
if f = @opts[:from]
|
|
1186
|
+
sql << FROM
|
|
1187
|
+
source_list_append(sql, f)
|
|
1188
|
+
end
|
|
863
1189
|
end
|
|
864
1190
|
alias delete_from_sql select_from_sql
|
|
865
1191
|
|
|
866
1192
|
# Modify the sql to add the expressions to GROUP BY
|
|
867
1193
|
def select_group_sql(sql)
|
|
868
|
-
|
|
1194
|
+
if group = @opts[:group]
|
|
1195
|
+
sql << GROUP_BY
|
|
1196
|
+
if go = @opts[:group_options]
|
|
1197
|
+
sql << go.to_s.upcase
|
|
1198
|
+
sql << PAREN_OPEN
|
|
1199
|
+
end
|
|
1200
|
+
expression_list_append(sql, group)
|
|
1201
|
+
sql << PAREN_CLOSE if go
|
|
1202
|
+
end
|
|
869
1203
|
end
|
|
870
1204
|
|
|
871
1205
|
# Modify the sql to add the filter criteria in the HAVING clause
|
|
872
1206
|
def select_having_sql(sql)
|
|
873
|
-
|
|
1207
|
+
if having = @opts[:having]
|
|
1208
|
+
sql << HAVING
|
|
1209
|
+
literal_append(sql, having)
|
|
1210
|
+
end
|
|
874
1211
|
end
|
|
875
1212
|
|
|
876
1213
|
# Modify the sql to add the list of tables to JOIN to
|
|
877
1214
|
def select_join_sql(sql)
|
|
878
|
-
|
|
1215
|
+
if js = @opts[:join]
|
|
1216
|
+
js.each{|j| literal_append(sql, j)}
|
|
1217
|
+
end
|
|
879
1218
|
end
|
|
880
1219
|
|
|
881
1220
|
# Modify the sql to limit the number of rows returned and offset
|
|
882
1221
|
def select_limit_sql(sql)
|
|
883
|
-
|
|
884
|
-
|
|
1222
|
+
if l = @opts[:limit]
|
|
1223
|
+
sql << LIMIT
|
|
1224
|
+
literal_append(sql, l)
|
|
1225
|
+
end
|
|
1226
|
+
if o = @opts[:offset]
|
|
1227
|
+
sql << OFFSET
|
|
1228
|
+
literal_append(sql, o)
|
|
1229
|
+
end
|
|
885
1230
|
end
|
|
886
1231
|
|
|
887
1232
|
# Modify the sql to support the different types of locking modes.
|
|
888
1233
|
def select_lock_sql(sql)
|
|
889
|
-
case @opts[:lock]
|
|
1234
|
+
case l = @opts[:lock]
|
|
890
1235
|
when :update
|
|
891
1236
|
sql << FOR_UPDATE
|
|
892
1237
|
when String
|
|
893
|
-
sql <<
|
|
1238
|
+
sql << SPACE << l
|
|
894
1239
|
end
|
|
895
1240
|
end
|
|
896
1241
|
|
|
897
1242
|
# Modify the sql to add the expressions to ORDER BY
|
|
898
1243
|
def select_order_sql(sql)
|
|
899
|
-
|
|
1244
|
+
if o = @opts[:order]
|
|
1245
|
+
sql << ORDER_BY
|
|
1246
|
+
expression_list_append(sql, o)
|
|
1247
|
+
end
|
|
900
1248
|
end
|
|
901
1249
|
alias delete_order_sql select_order_sql
|
|
902
1250
|
alias update_order_sql select_order_sql
|
|
903
1251
|
|
|
1252
|
+
def select_select_sql(sql)
|
|
1253
|
+
sql << SELECT
|
|
1254
|
+
end
|
|
1255
|
+
|
|
904
1256
|
# Modify the sql to add the filter criteria in the WHERE clause
|
|
905
1257
|
def select_where_sql(sql)
|
|
906
|
-
|
|
1258
|
+
if w = @opts[:where]
|
|
1259
|
+
sql << WHERE
|
|
1260
|
+
literal_append(sql, w)
|
|
1261
|
+
end
|
|
907
1262
|
end
|
|
908
1263
|
alias delete_where_sql select_where_sql
|
|
909
1264
|
alias update_where_sql select_where_sql
|
|
@@ -912,8 +1267,26 @@ module Sequel
|
|
|
912
1267
|
def select_with_sql(sql)
|
|
913
1268
|
ws = opts[:with]
|
|
914
1269
|
return if !ws || ws.empty?
|
|
915
|
-
sql
|
|
1270
|
+
sql << select_with_sql_base
|
|
1271
|
+
c = false
|
|
1272
|
+
comma = COMMA
|
|
1273
|
+
ws.each do |w|
|
|
1274
|
+
sql << comma if c
|
|
1275
|
+
quote_identifier_append(sql, w[:name])
|
|
1276
|
+
if args = w[:args]
|
|
1277
|
+
sql << PAREN_OPEN
|
|
1278
|
+
argument_list_append(sql, args)
|
|
1279
|
+
sql << PAREN_CLOSE
|
|
1280
|
+
end
|
|
1281
|
+
sql << AS
|
|
1282
|
+
literal_dataset_append(sql, w[:dataset])
|
|
1283
|
+
c ||= true
|
|
1284
|
+
end
|
|
1285
|
+
sql << SPACE
|
|
916
1286
|
end
|
|
1287
|
+
alias delete_with_sql select_with_sql
|
|
1288
|
+
alias insert_with_sql select_with_sql
|
|
1289
|
+
alias update_with_sql select_with_sql
|
|
917
1290
|
|
|
918
1291
|
# The base keyword to use for the SQL WITH clause
|
|
919
1292
|
def select_with_sql_base
|
|
@@ -921,9 +1294,15 @@ module Sequel
|
|
|
921
1294
|
end
|
|
922
1295
|
|
|
923
1296
|
# Converts an array of source names into into a comma separated list.
|
|
924
|
-
def
|
|
925
|
-
raise(Error, 'No source specified for query') if
|
|
926
|
-
|
|
1297
|
+
def source_list_append(sql, sources)
|
|
1298
|
+
raise(Error, 'No source specified for query') if sources.nil? || sources == []
|
|
1299
|
+
c = false
|
|
1300
|
+
co = COMMA
|
|
1301
|
+
sources.each do |s|
|
|
1302
|
+
sql << co if c
|
|
1303
|
+
table_ref_append(sql, s)
|
|
1304
|
+
c ||= true
|
|
1305
|
+
end
|
|
927
1306
|
end
|
|
928
1307
|
|
|
929
1308
|
# Splits the symbol into three parts. Each part will
|
|
@@ -932,13 +1311,13 @@ module Sequel
|
|
|
932
1311
|
# For columns, these parts are the table, column, and alias.
|
|
933
1312
|
# For tables, these parts are the schema, table, and alias.
|
|
934
1313
|
def split_symbol(sym)
|
|
935
|
-
s = sym.to_s
|
|
936
|
-
|
|
937
|
-
[
|
|
938
|
-
|
|
939
|
-
[nil,
|
|
940
|
-
|
|
941
|
-
[
|
|
1314
|
+
case s = sym.to_s
|
|
1315
|
+
when COLUMN_REF_RE1
|
|
1316
|
+
[$1, $2, $3]
|
|
1317
|
+
when COLUMN_REF_RE2
|
|
1318
|
+
[nil, $1, $2]
|
|
1319
|
+
when COLUMN_REF_RE3
|
|
1320
|
+
[$1, $2, nil]
|
|
942
1321
|
else
|
|
943
1322
|
[nil, s, nil]
|
|
944
1323
|
end
|
|
@@ -948,18 +1327,35 @@ module Sequel
|
|
|
948
1327
|
# can be a PlaceholderLiteralString in addition to a String,
|
|
949
1328
|
# we literalize nonstrings.
|
|
950
1329
|
def static_sql(sql)
|
|
951
|
-
|
|
1330
|
+
if append_sql = @opts[:append_sql]
|
|
1331
|
+
if sql.is_a?(String)
|
|
1332
|
+
append_sql << sql
|
|
1333
|
+
else
|
|
1334
|
+
literal_append(append_sql, sql)
|
|
1335
|
+
end
|
|
1336
|
+
else
|
|
1337
|
+
if sql.is_a?(String)
|
|
1338
|
+
sql
|
|
1339
|
+
else
|
|
1340
|
+
literal(sql)
|
|
1341
|
+
end
|
|
1342
|
+
end
|
|
952
1343
|
end
|
|
953
1344
|
|
|
954
1345
|
# SQL fragment for a subselect using the given database's SQL.
|
|
955
|
-
def
|
|
956
|
-
ds.sql
|
|
1346
|
+
def subselect_sql_append(sql, ds)
|
|
1347
|
+
ds.clone(:append_sql=>sql).sql
|
|
957
1348
|
end
|
|
958
1349
|
|
|
959
1350
|
# SQL fragment specifying a table name.
|
|
960
|
-
def
|
|
961
|
-
t.is_a?(String)
|
|
1351
|
+
def table_ref_append(sql, t)
|
|
1352
|
+
if t.is_a?(String)
|
|
1353
|
+
quote_identifier_append(sql, t)
|
|
1354
|
+
else
|
|
1355
|
+
literal_append(sql, t)
|
|
1356
|
+
end
|
|
962
1357
|
end
|
|
1358
|
+
alias identifier_append table_ref_append
|
|
963
1359
|
|
|
964
1360
|
# The order of methods to call to build the UPDATE SQL statement
|
|
965
1361
|
def update_clause_methods
|
|
@@ -969,25 +1365,38 @@ module Sequel
|
|
|
969
1365
|
# SQL fragment specifying the tables from with to delete.
|
|
970
1366
|
# Includes join table if modifying joins is allowed.
|
|
971
1367
|
def update_table_sql(sql)
|
|
972
|
-
sql <<
|
|
1368
|
+
sql << SPACE
|
|
1369
|
+
source_list_append(sql, @opts[:from])
|
|
973
1370
|
select_join_sql(sql) if supports_modifying_joins?
|
|
974
1371
|
end
|
|
975
1372
|
|
|
976
1373
|
# The SQL fragment specifying the columns and values to SET.
|
|
977
1374
|
def update_set_sql(sql)
|
|
978
1375
|
values = opts[:values]
|
|
979
|
-
|
|
1376
|
+
sql << SET
|
|
1377
|
+
if values.is_a?(Hash)
|
|
980
1378
|
values = opts[:defaults].merge(values) if opts[:defaults]
|
|
981
1379
|
values = values.merge(opts[:overrides]) if opts[:overrides]
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1380
|
+
c = false
|
|
1381
|
+
eq = EQUAL
|
|
1382
|
+
values.each do |k, v|
|
|
1383
|
+
sql << COMMA if c
|
|
1384
|
+
if k.is_a?(String) && !k.is_a?(LiteralString)
|
|
1385
|
+
quote_identifier_append(sql, k)
|
|
1386
|
+
else
|
|
1387
|
+
literal_append(sql, k)
|
|
1388
|
+
end
|
|
1389
|
+
sql << eq
|
|
1390
|
+
literal_append(sql, v)
|
|
1391
|
+
c ||= true
|
|
1392
|
+
end
|
|
986
1393
|
else
|
|
987
|
-
|
|
988
|
-
values
|
|
1394
|
+
sql << values
|
|
989
1395
|
end
|
|
990
|
-
|
|
1396
|
+
end
|
|
1397
|
+
|
|
1398
|
+
def update_update_sql(sql)
|
|
1399
|
+
sql << UPDATE
|
|
991
1400
|
end
|
|
992
1401
|
end
|
|
993
1402
|
end
|