11import datetime
22import uuid
33import warnings
4+ import django
45
56from django .conf import settings
67from django .db .backends .base .operations import BaseDatabaseOperations
8+ from django .db .models import Exists , ExpressionWrapper
9+ from django .db .models .expressions import RawSQL
10+ from django .db .models .sql .where import WhereNode
711from django .utils import timezone
812from django .utils .encoding import force_str
913
@@ -310,7 +314,7 @@ def savepoint_rollback_sql(self, sid):
310314 """
311315 return "ROLLBACK TRANSACTION %s" % sid
312316
313- def sql_flush (self , style , tables , sequences , allow_cascade = False ):
317+ def sql_flush (self , style , tables , * , reset_sequences = False , allow_cascade = False ):
314318 """
315319 Returns a list of SQL statements required to remove all data from
316320 the given database tables (without actually removing the tables
@@ -325,14 +329,21 @@ def sql_flush(self, style, tables, sequences, allow_cascade=False):
325329 The `allow_cascade` argument determines whether truncation may cascade
326330 to tables with foreign keys pointing the tables being truncated.
327331 """
328- if tables :
329- # Cannot use TRUNCATE on tables that are referenced by a FOREIGN KEY
330- # So must use the much slower DELETE
331- from django .db import connections
332- cursor = connections [self .connection .alias ].cursor ()
333- # Try to minimize the risks of the braindeaded inconsistency in
334- # DBCC CHEKIDENT(table, RESEED, n) behavior.
335- seqs = []
332+ if not tables :
333+ return []
334+
335+ # Cannot use TRUNCATE on tables that are referenced by a FOREIGN KEY
336+ # So must use the much slower DELETE
337+ from django .db import connections
338+ cursor = connections [self .connection .alias ].cursor ()
339+ # Try to minimize the risks of the braindeaded inconsistency in
340+ # DBCC CHEKIDENT(table, RESEED, n) behavior.
341+ seqs = []
342+ if reset_sequences :
343+ sequences = [
344+ sequence
345+ for sequence in self .connection .introspection .sequence_list ()
346+ ]
336347 for seq in sequences :
337348 cursor .execute ("SELECT COUNT(*) FROM %s" % self .quote_name (seq ["table" ]))
338349 rowcnt = cursor .fetchone ()[0 ]
@@ -343,37 +354,36 @@ def sql_flush(self, style, tables, sequences, allow_cascade=False):
343354 elem ['start_id' ] = 1
344355 elem .update (seq )
345356 seqs .append (elem )
346- COLUMNS = "TABLE_NAME, CONSTRAINT_NAME"
347- WHERE = "CONSTRAINT_TYPE not in ('PRIMARY KEY','UNIQUE')"
348- cursor .execute (
349- "SELECT {} FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE {}" .format (COLUMNS , WHERE ))
350- fks = cursor .fetchall ()
351- sql_list = ['ALTER TABLE %s NOCHECK CONSTRAINT %s;' %
352- (self .quote_name (fk [0 ]), self .quote_name (fk [1 ])) for fk in fks ]
353- sql_list .extend (['%s %s %s;' % (style .SQL_KEYWORD ('DELETE' ), style .SQL_KEYWORD ('FROM' ),
354- style .SQL_FIELD (self .quote_name (table ))) for table in tables ])
355-
356- if self .connection .to_azure_sql_db and self .connection .sql_server_version < 2014 :
357- warnings .warn ("Resetting identity columns is not supported "
358- "on this versios of Azure SQL Database." ,
359- RuntimeWarning )
360- else :
361- # Then reset the counters on each table.
362- sql_list .extend (['%s %s (%s, %s, %s) %s %s;' % (
363- style .SQL_KEYWORD ('DBCC' ),
364- style .SQL_KEYWORD ('CHECKIDENT' ),
365- style .SQL_FIELD (self .quote_name (seq ["table" ])),
366- style .SQL_KEYWORD ('RESEED' ),
367- style .SQL_FIELD ('%d' % seq ['start_id' ]),
368- style .SQL_KEYWORD ('WITH' ),
369- style .SQL_KEYWORD ('NO_INFOMSGS' ),
370- ) for seq in seqs ])
371-
372- sql_list .extend (['ALTER TABLE %s CHECK CONSTRAINT %s;' %
373- (self .quote_name (fk [0 ]), self .quote_name (fk [1 ])) for fk in fks ])
374- return sql_list
357+
358+ COLUMNS = "TABLE_NAME, CONSTRAINT_NAME"
359+ WHERE = "CONSTRAINT_TYPE not in ('PRIMARY KEY','UNIQUE')"
360+ cursor .execute (
361+ "SELECT {} FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE {}" .format (COLUMNS , WHERE ))
362+ fks = cursor .fetchall ()
363+ sql_list = ['ALTER TABLE %s NOCHECK CONSTRAINT %s;' %
364+ (self .quote_name (fk [0 ]), self .quote_name (fk [1 ])) for fk in fks ]
365+ sql_list .extend (['%s %s %s;' % (style .SQL_KEYWORD ('DELETE' ), style .SQL_KEYWORD ('FROM' ),
366+ style .SQL_FIELD (self .quote_name (table ))) for table in tables ])
367+
368+ if self .connection .to_azure_sql_db and self .connection .sql_server_version < 2014 :
369+ warnings .warn ("Resetting identity columns is not supported "
370+ "on this versios of Azure SQL Database." ,
371+ RuntimeWarning )
375372 else :
376- return []
373+ # Then reset the counters on each table.
374+ sql_list .extend (['%s %s (%s, %s, %s) %s %s;' % (
375+ style .SQL_KEYWORD ('DBCC' ),
376+ style .SQL_KEYWORD ('CHECKIDENT' ),
377+ style .SQL_FIELD (self .quote_name (seq ["table" ])),
378+ style .SQL_KEYWORD ('RESEED' ),
379+ style .SQL_FIELD ('%d' % seq ['start_id' ]),
380+ style .SQL_KEYWORD ('WITH' ),
381+ style .SQL_KEYWORD ('NO_INFOMSGS' ),
382+ ) for seq in seqs ])
383+
384+ sql_list .extend (['ALTER TABLE %s CHECK CONSTRAINT %s;' %
385+ (self .quote_name (fk [0 ]), self .quote_name (fk [1 ])) for fk in fks ])
386+ return sql_list
377387
378388 def start_transaction_sql (self ):
379389 """
@@ -440,3 +450,18 @@ def time_trunc_sql(self, lookup_type, field_name):
440450 elif lookup_type == 'second' :
441451 sql = "CONVERT(time, SUBSTRING(CONVERT(varchar, %s, 114), 0, 9))" % field_name
442452 return sql
453+
454+ def conditional_expression_supported_in_where_clause (self , expression ):
455+ """
456+ Following "Moved conditional expression wrapping to the Exact lookup" in django 3.1
457+ https://github.com/django/django/commit/37e6c5b79bd0529a3c85b8c478e4002fd33a2a1d
458+ """
459+ if django .VERSION >= (3 , 1 ):
460+ if isinstance (expression , (Exists , WhereNode )):
461+ return True
462+ if isinstance (expression , ExpressionWrapper ) and expression .conditional :
463+ return self .conditional_expression_supported_in_where_clause (expression .expression )
464+ if isinstance (expression , RawSQL ) and expression .conditional :
465+ return True
466+ return False
467+ return True
0 commit comments