Refactored get_sql_flush() to DatabaseOperations.sql_flush(). Refs #5106

git-svn-id: http://code.djangoproject.com/svn/django/trunk@5963 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2007-08-20 00:15:53 +00:00
parent c44fb66551
commit aaed6e04ec
10 changed files with 197 additions and 230 deletions

View File

@ -178,9 +178,9 @@ def sql_reset(app, style):
return sql_delete(app, style) + sql_all(app, style) return sql_delete(app, style) + sql_all(app, style)
def sql_flush(style): def sql_flush(style):
"Returns a list of the SQL statements used to flush the database" "Returns a list of the SQL statements used to flush the database."
from django.db import backend from django.db import connection
statements = backend.get_sql_flush(style, table_list(), sequence_list()) statements = connection.ops.sql_flush(style, table_list(), sequence_list())
return statements return statements
def sql_custom(app): def sql_custom(app):

View File

@ -139,3 +139,14 @@ class BaseDatabaseOperations(object):
Returns a SQL expression that returns a random value. Returns a SQL expression that returns a random value.
""" """
return 'RANDOM()' return 'RANDOM()'
def sql_flush(self, style, tables, sequences):
"""
Returns a list of SQL statements required to remove all data from
the given database tables (without actually removing the tables
themselves).
The `style` argument is a Style object as returned by either
color_style() or no_style() in django.core.management.color.
"""
raise NotImplementedError()

View File

@ -109,19 +109,6 @@ def get_start_transaction_sql():
def get_tablespace_sql(tablespace, inline=False): def get_tablespace_sql(tablespace, inline=False):
return "ON %s" % quote_name(tablespace) return "ON %s" % quote_name(tablespace)
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
# TODO - SQL not actually tested against ADO MSSQL yet!
# TODO - autoincrement indices reset required? See other get_sql_flush() implementations
sql_list = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
def get_sql_sequence_reset(style, model_list): def get_sql_sequence_reset(style, model_list):
"Returns a list of the SQL statements to reset sequences for the given models." "Returns a list of the SQL statements to reset sequences for the given models."
# No sequence reset required # No sequence reset required

View File

@ -44,7 +44,6 @@ dictfetchone = complain
dictfetchmany = complain dictfetchmany = complain
dictfetchall = complain dictfetchall = complain
get_start_transaction_sql = complain get_start_transaction_sql = complain
get_sql_flush = complain
get_sql_sequence_reset = complain get_sql_sequence_reset = complain
OPERATOR_MAPPING = {} OPERATOR_MAPPING = {}

View File

@ -87,6 +87,29 @@ class DatabaseOperations(BaseDatabaseOperations):
def random_function_sql(self): def random_function_sql(self):
return 'RAND()' return 'RAND()'
def sql_flush(self, style, tables, sequences):
# NB: The generated SQL below is specific to MySQL
# 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
# to clear all tables of all data
if tables:
sql = ['SET FOREIGN_KEY_CHECKS = 0;']
for table in tables:
sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(quote_name(table))))
sql.append('SET FOREIGN_KEY_CHECKS = 1;')
# 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
# to reset sequence indices
sql.extend(["%s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('TABLE'),
style.SQL_TABLE(quote_name(sequence['table'])),
style.SQL_KEYWORD('AUTO_INCREMENT'),
style.SQL_FIELD('= 1'),
) for sequence in sequences])
return sql
else:
return []
class DatabaseWrapper(BaseDatabaseWrapper): class DatabaseWrapper(BaseDatabaseWrapper):
ops = DatabaseOperations() ops = DatabaseOperations()
@ -168,36 +191,6 @@ dictfetchall = util.dictfetchall
def get_start_transaction_sql(): def get_start_transaction_sql():
return "BEGIN;" return "BEGIN;"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# NB: The generated SQL below is specific to MySQL
# 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
# to clear all tables of all data
if tables:
sql = ['SET FOREIGN_KEY_CHECKS = 0;'] + \
['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(quote_name(table))
) for table in tables] + \
['SET FOREIGN_KEY_CHECKS = 1;']
# 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
# to reset sequence indices
sql.extend(["%s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('TABLE'),
style.SQL_TABLE(quote_name(sequence['table'])),
style.SQL_KEYWORD('AUTO_INCREMENT'),
style.SQL_FIELD('= 1'),
) for sequence in sequences])
return sql
else:
return []
def get_sql_sequence_reset(style, model_list): def get_sql_sequence_reset(style, model_list):
"Returns a list of the SQL statements to reset sequences for the given models." "Returns a list of the SQL statements to reset sequences for the given models."
# No sequence reset required # No sequence reset required

View File

@ -97,6 +97,29 @@ class DatabaseOperations(BaseDatabaseOperations):
def random_function_sql(self): def random_function_sql(self):
return 'RAND()' return 'RAND()'
def sql_flush(self, style, tables, sequences):
# NB: The generated SQL below is specific to MySQL
# 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
# to clear all tables of all data
if tables:
sql = ['SET FOREIGN_KEY_CHECKS = 0;']
for table in tables:
sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(quote_name(table))))
sql.append('SET FOREIGN_KEY_CHECKS = 1;')
# 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
# to reset sequence indices
sql.extend(["%s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('TABLE'),
style.SQL_TABLE(quote_name(sequence['table'])),
style.SQL_KEYWORD('AUTO_INCREMENT'),
style.SQL_FIELD('= 1'),
) for sequence in sequences])
return sql
else:
return []
class DatabaseWrapper(BaseDatabaseWrapper): class DatabaseWrapper(BaseDatabaseWrapper):
ops = DatabaseOperations() ops = DatabaseOperations()
@ -187,36 +210,6 @@ dictfetchall = util.dictfetchall
def get_start_transaction_sql(): def get_start_transaction_sql():
return "BEGIN;" return "BEGIN;"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# NB: The generated SQL below is specific to MySQL
# 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
# to clear all tables of all data
if tables:
sql = ['SET FOREIGN_KEY_CHECKS = 0;'] + \
['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(quote_name(table))
) for table in tables] + \
['SET FOREIGN_KEY_CHECKS = 1;']
# 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
# to reset sequence indices
sql.extend(["%s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('TABLE'),
style.SQL_TABLE(quote_name(sequence['table'])),
style.SQL_KEYWORD('AUTO_INCREMENT'),
style.SQL_FIELD('= 1'),
) for sequence in sequences])
return sql
else:
return []
def get_sql_sequence_reset(style, model_list): def get_sql_sequence_reset(style, model_list):
"Returns a list of the SQL statements to reset sequences for the given models." "Returns a list of the SQL statements to reset sequences for the given models."
# No sequence reset required # No sequence reset required

View File

@ -73,6 +73,28 @@ class DatabaseOperations(BaseDatabaseOperations):
def random_function_sql(self): def random_function_sql(self):
return "DBMS_RANDOM.RANDOM" return "DBMS_RANDOM.RANDOM"
def sql_flush(self, style, tables, sequences):
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
# 'TRUNCATE z;'... style SQL statements
if tables:
# Oracle does support TRUNCATE, but it seems to get us into
# FK referential trouble, whereas DELETE FROM table works.
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# Since we've just deleted all the rows, running our sequence
# ALTER code will reset the sequence to 0.
for sequence_info in sequences:
table_name = sequence_info['table']
seq_name = get_sequence_name(table_name)
query = _get_sequence_reset_sql() % {'sequence':seq_name, 'table':quote_name(table_name)}
sql.append(query)
return sql
else:
return []
class DatabaseWrapper(BaseDatabaseWrapper): class DatabaseWrapper(BaseDatabaseWrapper):
ops = DatabaseOperations() ops = DatabaseOperations()
@ -218,33 +240,6 @@ def _get_sequence_reset_sql():
END; END;
/""" /"""
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
# 'TRUNCATE z;'... style SQL statements
if tables:
# Oracle does support TRUNCATE, but it seems to get us into
# FK referential trouble, whereas DELETE FROM table works.
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# Since we've just deleted all the rows, running our sequence
# ALTER code will reset the sequence to 0.
for sequence_info in sequences:
table_name = sequence_info['table']
seq_name = get_sequence_name(table_name)
query = _get_sequence_reset_sql() % {'sequence':seq_name,
'table':quote_name(table_name)}
sql.append(query)
return sql
else:
return []
def get_sequence_name(table): def get_sequence_name(table):
name_length = DatabaseOperations().max_name_length() - 3 name_length = DatabaseOperations().max_name_length() - 3
return '%s_SQ' % util.truncate_name(table, name_length).upper() return '%s_SQ' % util.truncate_name(table, name_length).upper()

View File

@ -73,6 +73,57 @@ class DatabaseOperations(BaseDatabaseOperations):
cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
return cursor.fetchone()[0] return cursor.fetchone()[0]
def sql_flush(self, style, tables, sequences):
if tables:
if postgres_version[0] >= 8 and postgres_version[1] >= 1:
# Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
# in order to be able to truncate tables referenced by a foreign
# key in any other table. The result is a single SQL TRUNCATE
# statement.
sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
)]
else:
# Older versions of Postgres can't do TRUNCATE in a single call, so
# they must use a simple delete.
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
# to reset sequence indices
for sequence_info in sequences:
table_name = sequence_info['table']
column_name = sequence_info['column']
if column_name and len(column_name)>0:
# sequence name in this case will be <table>_<column>_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
else:
# sequence name in this case will be <table>_id_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_id_seq' % table_name)),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
return sql
else:
return []
class DatabaseWrapper(BaseDatabaseWrapper): class DatabaseWrapper(BaseDatabaseWrapper):
ops = DatabaseOperations() ops = DatabaseOperations()
@ -134,62 +185,6 @@ def dictfetchall(cursor):
def get_start_transaction_sql(): def get_start_transaction_sql():
return "BEGIN;" return "BEGIN;"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
if tables:
if postgres_version[0] >= 8 and postgres_version[1] >= 1:
# Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
# in order to be able to truncate tables referenced by a foreign
# key in any other table. The result is a single SQL TRUNCATE
# statement.
sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
)]
else:
# Older versions of Postgres can't do TRUNCATE in a single call, so
# they must use a simple delete.
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
# to reset sequence indices
for sequence_info in sequences:
table_name = sequence_info['table']
column_name = sequence_info['column']
if column_name and len(column_name)>0:
# sequence name in this case will be <table>_<column>_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
else:
# sequence name in this case will be <table>_id_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_id_seq' % table_name)),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
return sql
else:
return []
def get_sql_sequence_reset(style, model_list): def get_sql_sequence_reset(style, model_list):
"Returns a list of the SQL statements to reset sequences for the given models." "Returns a list of the SQL statements to reset sequences for the given models."
from django.db import models from django.db import models

View File

@ -35,6 +35,57 @@ class DatabaseOperations(BaseDatabaseOperations):
cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
return cursor.fetchone()[0] return cursor.fetchone()[0]
def sql_flush(self, style, tables, sequences):
if tables:
if postgres_version[0] >= 8 and postgres_version[1] >= 1:
# Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
# in order to be able to truncate tables referenced by a foreign
# key in any other table. The result is a single SQL TRUNCATE
# statement.
sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
)]
else:
# Older versions of Postgres can't do TRUNCATE in a single call, so
# they must use a simple delete.
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
# to reset sequence indices
for sequence_info in sequences:
table_name = sequence_info['table']
column_name = sequence_info['column']
if column_name and len(column_name)>0:
# sequence name in this case will be <table>_<column>_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
else:
# sequence name in this case will be <table>_id_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_id_seq' % table_name)),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
return sql
else:
return []
class DatabaseWrapper(BaseDatabaseWrapper): class DatabaseWrapper(BaseDatabaseWrapper):
ops = DatabaseOperations() ops = DatabaseOperations()
@ -88,58 +139,6 @@ dictfetchall = util.dictfetchall
def get_start_transaction_sql(): def get_start_transaction_sql():
return "BEGIN;" return "BEGIN;"
def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
if tables:
if postgres_version[0] >= 8 and postgres_version[1] >= 1:
# Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
# truncate tables referenced by a foreign key in any other table. The result is a
# single SQL TRUNCATE statement
sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
)]
else:
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
# to reset sequence indices
for sequence in sequences:
table_name = sequence['table']
column_name = sequence['column']
if column_name and len(column_name) > 0:
# sequence name in this case will be <table>_<column>_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
else:
# sequence name in this case will be <table>_id_seq
sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_id_seq' % table_name)),
style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1')
)
)
return sql
else:
return []
def get_sql_sequence_reset(style, model_list): def get_sql_sequence_reset(style, model_list):
"Returns a list of the SQL statements to reset sequences for the given models." "Returns a list of the SQL statements to reset sequences for the given models."
from django.db import models from django.db import models

View File

@ -51,6 +51,19 @@ class DatabaseOperations(BaseDatabaseOperations):
def pk_default_value(self): def pk_default_value(self):
return 'NULL' return 'NULL'
def sql_flush(self, style, tables, sequences):
# NB: The generated SQL below is specific to SQLite
# Note: The DELETE FROM... SQL generated below works for SQLite databases
# because constraints don't exist
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# Note: No requirement for reset of auto-incremented indices (cf. other
# sql_flush() implementations). Just return SQL at this point
return sql
class DatabaseWrapper(BaseDatabaseWrapper): class DatabaseWrapper(BaseDatabaseWrapper):
ops = DatabaseOperations() ops = DatabaseOperations()
@ -121,24 +134,6 @@ def _sqlite_extract(lookup_type, dt):
def get_start_transaction_sql(): def get_start_transaction_sql():
return "BEGIN;" return "BEGIN;"
def get_sql_flush(style, tables, sequences):
"""
Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
themselves) and put the database in an empty 'initial' state
"""
# NB: The generated SQL below is specific to SQLite
# Note: The DELETE FROM... SQL generated below works for SQLite databases
# because constraints don't exist
sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table))
) for table in tables]
# Note: No requirement for reset of auto-incremented indices (cf. other
# get_sql_flush() implementations). Just return SQL at this point
return sql
def get_sql_sequence_reset(style, model_list): def get_sql_sequence_reset(style, model_list):
"Returns a list of the SQL statements to reset sequences for the given models." "Returns a list of the SQL statements to reset sequences for the given models."
# No sequence reset required # No sequence reset required