33
44from django .db .models .aggregates import Avg , Count , StdDev , Variance
55from 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+ )
79from django .db .models .sql import compiler
810from django .db .transaction import TransactionManagementError
911from django .db .utils import DatabaseError , NotSupportedError
1214def _as_sql_agv (self , compiler , connection ):
1315 return self .as_sql (compiler , connection , template = '%(function)s(CONVERT(float, %(field)s))' )
1416
17+ def _as_sql_chr (self , compiler , connection ):
18+ return self .as_sql (compiler , connection , function = 'NCHAR' )
19+
1520def _as_sql_concatpair (self , compiler , connection ):
1621 if connection .sql_server_version < 2012 :
1722 node = self .coalesce ()
@@ -39,6 +44,23 @@ def _as_sql_least(self, compiler, connection):
3944def _as_sql_length (self , compiler , connection ):
4045 return self .as_sql (compiler , connection , function = 'LEN' )
4146
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+
4264def _as_sql_exists (self , compiler , connection , template = None , ** extra_context ):
4365 # MS SQL doesn't allow EXISTS() in the SELECT list, so wrap it with a
4466 # CASE WHEN expression. Change the template since the When expression
@@ -55,6 +77,22 @@ def _as_sql_order_by(self, compiler, connection):
5577 template = 'CASE WHEN %(expression)s IS NULL THEN 0 ELSE 1 END, %(expression)s %(ordering)s'
5678 return self .as_sql (compiler , connection , template = template )
5779
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+
5896def _as_sql_stddev (self , compiler , connection ):
5997 function = 'STDEV'
6098 if self .function == 'STDDEV_POP' :
@@ -72,6 +110,9 @@ def _as_sql_substr(self, compiler, connection):
72110 self .get_source_expressions ().append (Value (2 ** 31 - 1 ))
73111 return self .as_sql (compiler , connection )
74112
113+ def _as_sql_trim (self , compiler , connection ):
114+ return self .as_sql (compiler , connection , template = 'LTRIM(RTRIM(%(expressions)s))' )
115+
75116def _as_sql_variance (self , compiler , connection ):
76117 function = 'VAR'
77118 if self .function == 'VAR_POP' :
@@ -120,6 +161,8 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
120161 try :
121162 extra_select , order_by , group_by = self .pre_sql_setup ()
122163 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 )
123166 combinator = self .query .combinator
124167 features = self .connection .features
125168
@@ -138,7 +181,7 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
138181 raise NotSupportedError ('{} is not supported on this database backend.' .format (combinator ))
139182 result , params = self .get_combinator_sql (combinator , self .query .combinator_all )
140183 else :
141- distinct_fields = self .get_distinct ()
184+ distinct_fields , distinct_params = self .get_distinct ()
142185 # This must come after 'select', 'ordering', and 'distinct' -- see
143186 # docstring of get_from_clause() for details.
144187 from_ , f_params = self .get_from_clause ()
@@ -148,7 +191,12 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
148191 result = ['SELECT' ]
149192
150193 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
152200
153201 # SQL Server requires the keword for limitting at the begenning
154202 if do_limit and not do_offset :
@@ -191,13 +239,11 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
191239 elif not order_by :
192240 order_by .append (((None , ('%s ASC' % offsetting_order_by , [], None ))))
193241
194- result .append (', ' .join (out_cols ))
195-
196242 if self .query .select_for_update and self .connection .features .has_select_for_update :
197243 if self .connection .get_autocommit ():
198244 raise TransactionManagementError ('select_for_update cannot be used outside of a transaction.' )
199245
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 :
201247 raise NotSupportedError (
202248 'LIMIT/OFFSET is not supported with '
203249 'select_for_update on this database backend.'
@@ -223,8 +269,7 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
223269 if for_update_part and self .connection .features .for_update_after_from :
224270 from_ .insert (1 , for_update_part )
225271
226- result .append ('FROM' )
227- result .extend (from_ )
272+ result += [', ' .join (out_cols ), 'FROM' , * from_ ]
228273 params .extend (f_params )
229274
230275 if where :
@@ -237,16 +282,20 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
237282 params .extend (g_params )
238283 if grouping :
239284 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 ()
244287 result .append ('GROUP BY %s' % ', ' .join (grouping ))
245288
246289 if having :
247290 result .append ('HAVING %s' % having )
248291 params .extend (h_params )
249292
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+
250299 if order_by :
251300 ordering = []
252301 for _ , (o_sql , o_params , _ ) in order_by :
@@ -269,9 +318,7 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
269318 if not self .query .subquery :
270319 result .append ('ORDER BY X.rn' )
271320 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 ))
275322
276323 if self .query .subquery and extra_select :
277324 # If the query is used as a subquery, the extra selects would
@@ -313,6 +360,8 @@ def _as_microsoft(self, node):
313360 as_microsoft = None
314361 if isinstance (node , Avg ):
315362 as_microsoft = _as_sql_agv
363+ elif isinstance (node , Chr ):
364+ as_microsoft = _as_sql_chr
316365 elif isinstance (node , ConcatPair ):
317366 as_microsoft = _as_sql_concatpair
318367 elif isinstance (node , Count ):
@@ -323,16 +372,24 @@ def _as_microsoft(self, node):
323372 as_microsoft = _as_sql_least
324373 elif isinstance (node , Length ):
325374 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
326379 elif isinstance (node , Exists ):
327380 as_microsoft = _as_sql_exists
328381 elif isinstance (node , OrderBy ):
329382 as_microsoft = _as_sql_order_by
383+ elif isinstance (node , Repeat ):
384+ as_microsoft = _as_sql_repeat
330385 elif isinstance (node , StdDev ):
331386 as_microsoft = _as_sql_stddev
332387 elif isinstance (node , StrIndex ):
333388 as_microsoft = _as_sql_strindex
334389 elif isinstance (node , Substr ):
335390 as_microsoft = _as_sql_substr
391+ elif isinstance (node , Trim ):
392+ as_microsoft = _as_sql_trim
336393 elif isinstance (node , Variance ):
337394 as_microsoft = _as_sql_variance
338395 if as_microsoft :
@@ -349,11 +406,9 @@ def as_sql(self):
349406 qn = self .connection .ops .quote_name
350407 opts = self .query .get_meta ()
351408 result = ['INSERT INTO %s' % qn (opts .db_table )]
409+ fields = self .query .fields or [opts .pk ]
352410
353- has_fields = bool (self .query .fields )
354-
355- if has_fields :
356- fields = self .query .fields
411+ if self .query .fields :
357412 result .append ('(%s)' % ', ' .join (qn (f .column ) for f in fields ))
358413 values_format = 'VALUES (%s)'
359414 value_rows = [
@@ -370,7 +425,7 @@ def as_sql(self):
370425 # queries and generate their own placeholders. Doing that isn't
371426 # necessary and it should be possible to use placeholders and
372427 # 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
374429
375430 placeholder_rows , param_rows = self .assemble_as_sql (fields , value_rows )
376431
@@ -390,7 +445,7 @@ def as_sql(self):
390445 for p , vals in zip (placeholder_rows , param_rows )
391446 ]
392447
393- if has_fields :
448+ if self . query . fields :
394449 if opts .auto_field is not None :
395450 # db_column is None if not explicitly specified by model field
396451 auto_field_column = opts .auto_field .db_column or opts .auto_field .column
0 commit comments