3
3
4
4
from django .db .models .aggregates import Avg , Count , StdDev , Variance
5
5
from django .db .models .expressions import Exists , OrderBy , Ref , Value
6
- from django .db .models .functions import ConcatPair , Greatest , Least , Length , StrIndex , Substr
6
+ from django .db .models .functions import (
7
+ Chr , ConcatPair , Greatest , Least , Length , LPad , Repeat , RPad , StrIndex , Substr , Trim
8
+ )
7
9
from django .db .models .sql import compiler
8
10
from django .db .transaction import TransactionManagementError
9
11
from django .db .utils import DatabaseError , NotSupportedError
12
14
def _as_sql_agv (self , compiler , connection ):
13
15
return self .as_sql (compiler , connection , template = '%(function)s(CONVERT(float, %(field)s))' )
14
16
17
+ def _as_sql_chr (self , compiler , connection ):
18
+ return self .as_sql (compiler , connection , function = 'NCHAR' )
19
+
15
20
def _as_sql_concatpair (self , compiler , connection ):
16
21
if connection .sql_server_version < 2012 :
17
22
node = self .coalesce ()
@@ -39,6 +44,23 @@ def _as_sql_least(self, compiler, connection):
39
44
def _as_sql_length (self , compiler , connection ):
40
45
return self .as_sql (compiler , connection , function = 'LEN' )
41
46
47
+ def _as_sql_lpad (self , compiler , connection ):
48
+ i = iter (self .get_source_expressions ())
49
+ expression , expression_arg = compiler .compile (next (i ))
50
+ length , length_arg = compiler .compile (next (i ))
51
+ fill_text , fill_text_arg = compiler .compile (next (i ))
52
+ params = []
53
+ params .extend (fill_text_arg )
54
+ params .extend (length_arg )
55
+ params .extend (length_arg )
56
+ params .extend (expression_arg )
57
+ params .extend (length_arg )
58
+ params .extend (expression_arg )
59
+ params .extend (expression_arg )
60
+ template = ('LEFT(REPLICATE(%(fill_text)s, %(length)s), CASE WHEN %(length)s > LEN(%(expression)s) '
61
+ 'THEN %(length)s - LEN(%(expression)s) ELSE 0 END) + %(expression)s' )
62
+ return template % {'expression' :expression , 'length' :length , 'fill_text' :fill_text }, params
63
+
42
64
def _as_sql_exists (self , compiler , connection , template = None , ** extra_context ):
43
65
# MS SQL doesn't allow EXISTS() in the SELECT list, so wrap it with a
44
66
# CASE WHEN expression. Change the template since the When expression
@@ -55,6 +77,22 @@ def _as_sql_order_by(self, compiler, connection):
55
77
template = 'CASE WHEN %(expression)s IS NULL THEN 0 ELSE 1 END, %(expression)s %(ordering)s'
56
78
return self .as_sql (compiler , connection , template = template )
57
79
80
+ def _as_sql_repeat (self , compiler , connection ):
81
+ return self .as_sql (compiler , connection , function = 'REPLICATE' )
82
+
83
+ def _as_sql_rpad (self , compiler , connection ):
84
+ i = iter (self .get_source_expressions ())
85
+ expression , expression_arg = compiler .compile (next (i ))
86
+ length , length_arg = compiler .compile (next (i ))
87
+ fill_text , fill_text_arg = compiler .compile (next (i ))
88
+ params = []
89
+ params .extend (expression_arg )
90
+ params .extend (fill_text_arg )
91
+ params .extend (length_arg )
92
+ params .extend (length_arg )
93
+ template = 'LEFT(%(expression)s + REPLICATE(%(fill_text)s, %(length)s), %(length)s)'
94
+ return template % {'expression' :expression , 'length' :length , 'fill_text' :fill_text }, params
95
+
58
96
def _as_sql_stddev (self , compiler , connection ):
59
97
function = 'STDEV'
60
98
if self .function == 'STDDEV_POP' :
@@ -72,6 +110,9 @@ def _as_sql_substr(self, compiler, connection):
72
110
self .get_source_expressions ().append (Value (2 ** 31 - 1 ))
73
111
return self .as_sql (compiler , connection )
74
112
113
+ def _as_sql_trim (self , compiler , connection ):
114
+ return self .as_sql (compiler , connection , template = 'LTRIM(RTRIM(%(expressions)s))' )
115
+
75
116
def _as_sql_variance (self , compiler , connection ):
76
117
function = 'VAR'
77
118
if self .function == 'VAR_POP' :
@@ -120,6 +161,8 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
120
161
try :
121
162
extra_select , order_by , group_by = self .pre_sql_setup ()
122
163
for_update_part = None
164
+ # Is a LIMIT/OFFSET clause needed?
165
+ with_limit_offset = with_limits and (self .query .high_mark is not None or self .query .low_mark )
123
166
combinator = self .query .combinator
124
167
features = self .connection .features
125
168
@@ -138,7 +181,7 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
138
181
raise NotSupportedError ('{} is not supported on this database backend.' .format (combinator ))
139
182
result , params = self .get_combinator_sql (combinator , self .query .combinator_all )
140
183
else :
141
- distinct_fields = self .get_distinct ()
184
+ distinct_fields , distinct_params = self .get_distinct ()
142
185
# This must come after 'select', 'ordering', and 'distinct' -- see
143
186
# docstring of get_from_clause() for details.
144
187
from_ , f_params = self .get_from_clause ()
@@ -148,7 +191,12 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
148
191
result = ['SELECT' ]
149
192
150
193
if self .query .distinct :
151
- result .append (self .connection .ops .distinct_sql (distinct_fields ))
194
+ distinct_result , distinct_params = self .connection .ops .distinct_sql (
195
+ distinct_fields ,
196
+ distinct_params ,
197
+ )
198
+ result += distinct_result
199
+ params += distinct_params
152
200
153
201
# SQL Server requires the keword for limitting at the begenning
154
202
if do_limit and not do_offset :
@@ -191,13 +239,11 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
191
239
elif not order_by :
192
240
order_by .append (((None , ('%s ASC' % offsetting_order_by , [], None ))))
193
241
194
- result .append (', ' .join (out_cols ))
195
-
196
242
if self .query .select_for_update and self .connection .features .has_select_for_update :
197
243
if self .connection .get_autocommit ():
198
244
raise TransactionManagementError ('select_for_update cannot be used outside of a transaction.' )
199
245
200
- if with_limits and not self .connection .features .supports_select_for_update_with_limit :
246
+ if with_limit_offset and not self .connection .features .supports_select_for_update_with_limit :
201
247
raise NotSupportedError (
202
248
'LIMIT/OFFSET is not supported with '
203
249
'select_for_update on this database backend.'
@@ -223,8 +269,7 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
223
269
if for_update_part and self .connection .features .for_update_after_from :
224
270
from_ .insert (1 , for_update_part )
225
271
226
- result .append ('FROM' )
227
- result .extend (from_ )
272
+ result += [', ' .join (out_cols ), 'FROM' , * from_ ]
228
273
params .extend (f_params )
229
274
230
275
if where :
@@ -237,16 +282,20 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
237
282
params .extend (g_params )
238
283
if grouping :
239
284
if distinct_fields :
240
- raise NotImplementedError (
241
- "annotate() + distinct(fields) is not implemented." )
242
- if not order_by :
243
- order_by = self .connection .ops .force_no_ordering ()
285
+ raise NotImplementedError ('annotate() + distinct(fields) is not implemented.' )
286
+ order_by = order_by or self .connection .ops .force_no_ordering ()
244
287
result .append ('GROUP BY %s' % ', ' .join (grouping ))
245
288
246
289
if having :
247
290
result .append ('HAVING %s' % having )
248
291
params .extend (h_params )
249
292
293
+ if self .query .explain_query :
294
+ result .insert (0 , self .connection .ops .explain_query_prefix (
295
+ self .query .explain_format ,
296
+ ** self .query .explain_options
297
+ ))
298
+
250
299
if order_by :
251
300
ordering = []
252
301
for _ , (o_sql , o_params , _ ) in order_by :
@@ -269,9 +318,7 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
269
318
if not self .query .subquery :
270
319
result .append ('ORDER BY X.rn' )
271
320
else :
272
- result .append ('OFFSET %d ROWS' % low_mark )
273
- if do_limit :
274
- result .append ('FETCH FIRST %d ROWS ONLY' % (high_mark - low_mark ))
321
+ result .append (self .connection .ops .limit_offset_sql (self .query .low_mark , self .query .high_mark ))
275
322
276
323
if self .query .subquery and extra_select :
277
324
# If the query is used as a subquery, the extra selects would
@@ -313,6 +360,8 @@ def _as_microsoft(self, node):
313
360
as_microsoft = None
314
361
if isinstance (node , Avg ):
315
362
as_microsoft = _as_sql_agv
363
+ elif isinstance (node , Chr ):
364
+ as_microsoft = _as_sql_chr
316
365
elif isinstance (node , ConcatPair ):
317
366
as_microsoft = _as_sql_concatpair
318
367
elif isinstance (node , Count ):
@@ -323,16 +372,24 @@ def _as_microsoft(self, node):
323
372
as_microsoft = _as_sql_least
324
373
elif isinstance (node , Length ):
325
374
as_microsoft = _as_sql_length
375
+ elif isinstance (node , RPad ):
376
+ as_microsoft = _as_sql_rpad
377
+ elif isinstance (node , LPad ):
378
+ as_microsoft = _as_sql_lpad
326
379
elif isinstance (node , Exists ):
327
380
as_microsoft = _as_sql_exists
328
381
elif isinstance (node , OrderBy ):
329
382
as_microsoft = _as_sql_order_by
383
+ elif isinstance (node , Repeat ):
384
+ as_microsoft = _as_sql_repeat
330
385
elif isinstance (node , StdDev ):
331
386
as_microsoft = _as_sql_stddev
332
387
elif isinstance (node , StrIndex ):
333
388
as_microsoft = _as_sql_strindex
334
389
elif isinstance (node , Substr ):
335
390
as_microsoft = _as_sql_substr
391
+ elif isinstance (node , Trim ):
392
+ as_microsoft = _as_sql_trim
336
393
elif isinstance (node , Variance ):
337
394
as_microsoft = _as_sql_variance
338
395
if as_microsoft :
@@ -349,11 +406,9 @@ def as_sql(self):
349
406
qn = self .connection .ops .quote_name
350
407
opts = self .query .get_meta ()
351
408
result = ['INSERT INTO %s' % qn (opts .db_table )]
409
+ fields = self .query .fields or [opts .pk ]
352
410
353
- has_fields = bool (self .query .fields )
354
-
355
- if has_fields :
356
- fields = self .query .fields
411
+ if self .query .fields :
357
412
result .append ('(%s)' % ', ' .join (qn (f .column ) for f in fields ))
358
413
values_format = 'VALUES (%s)'
359
414
value_rows = [
@@ -370,7 +425,7 @@ def as_sql(self):
370
425
# queries and generate their own placeholders. Doing that isn't
371
426
# necessary and it should be possible to use placeholders and
372
427
# expressions in bulk inserts too.
373
- can_bulk = (not self .return_id and self .connection .features .has_bulk_insert ) and has_fields
428
+ can_bulk = (not self .return_id and self .connection .features .has_bulk_insert ) and self . query . fields
374
429
375
430
placeholder_rows , param_rows = self .assemble_as_sql (fields , value_rows )
376
431
@@ -390,7 +445,7 @@ def as_sql(self):
390
445
for p , vals in zip (placeholder_rows , param_rows )
391
446
]
392
447
393
- if has_fields :
448
+ if self . query . fields :
394
449
if opts .auto_field is not None :
395
450
# db_column is None if not explicitly specified by model field
396
451
auto_field_column = opts .auto_field .db_column or opts .auto_field .column
0 commit comments