Fixed #31479 -- Added support to reset sequences on SQLite.
This commit is contained in:
parent
5220ca8d8a
commit
75866b93cc
|
@ -26,7 +26,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
supports_atomic_references_rename = Database.sqlite_version_info >= (3, 26, 0)
|
supports_atomic_references_rename = Database.sqlite_version_info >= (3, 26, 0)
|
||||||
can_create_inline_fk = False
|
can_create_inline_fk = False
|
||||||
supports_paramstyle_pyformat = False
|
supports_paramstyle_pyformat = False
|
||||||
supports_sequence_reset = False
|
|
||||||
can_clone_databases = True
|
can_clone_databases = True
|
||||||
supports_temporal_subtraction = True
|
supports_temporal_subtraction = True
|
||||||
ignores_table_name_case = True
|
ignores_table_name_case = True
|
||||||
|
|
|
@ -201,13 +201,33 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
# Simulate TRUNCATE CASCADE by recursively collecting the tables
|
# Simulate TRUNCATE CASCADE by recursively collecting the tables
|
||||||
# referencing the tables to be flushed.
|
# referencing the tables to be flushed.
|
||||||
tables = set(chain.from_iterable(self._references_graph(table) for table in tables))
|
tables = set(chain.from_iterable(self._references_graph(table) for table in tables))
|
||||||
# Note: No requirement for reset of auto-incremented indices (cf. other
|
sql = ['%s %s %s;' % (
|
||||||
# sql_flush() implementations). Just return SQL at this point
|
|
||||||
return ['%s %s %s;' % (
|
|
||||||
style.SQL_KEYWORD('DELETE'),
|
style.SQL_KEYWORD('DELETE'),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
style.SQL_FIELD(self.quote_name(table))
|
style.SQL_FIELD(self.quote_name(table))
|
||||||
) for table in tables]
|
) for table in tables]
|
||||||
|
if reset_sequences:
|
||||||
|
sequences = [{'table': table} for table in tables]
|
||||||
|
sql.extend(self.sequence_reset_by_name_sql(style, sequences))
|
||||||
|
return sql
|
||||||
|
|
||||||
|
def sequence_reset_by_name_sql(self, style, sequences):
|
||||||
|
if not sequences:
|
||||||
|
return []
|
||||||
|
return [
|
||||||
|
'%s %s %s %s = 0 %s %s %s (%s);' % (
|
||||||
|
style.SQL_KEYWORD('UPDATE'),
|
||||||
|
style.SQL_TABLE(self.quote_name('sqlite_sequence')),
|
||||||
|
style.SQL_KEYWORD('SET'),
|
||||||
|
style.SQL_FIELD(self.quote_name('seq')),
|
||||||
|
style.SQL_KEYWORD('WHERE'),
|
||||||
|
style.SQL_FIELD(self.quote_name('name')),
|
||||||
|
style.SQL_KEYWORD('IN'),
|
||||||
|
', '.join([
|
||||||
|
"'%s'" % sequence_info['table'] for sequence_info in sequences
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
def adapt_datetimefield_value(self, value):
|
def adapt_datetimefield_value(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
|
|
|
@ -320,6 +320,9 @@ Management Commands
|
||||||
* The new :option:`dbshell -- ARGUMENTS <dbshell -->` option allows passing
|
* The new :option:`dbshell -- ARGUMENTS <dbshell -->` option allows passing
|
||||||
extra arguments to the command-line client for the database.
|
extra arguments to the command-line client for the database.
|
||||||
|
|
||||||
|
* The :djadmin:`flush` and :djadmin:`sqlflush` commands now include SQL to
|
||||||
|
reset sequences on SQLite.
|
||||||
|
|
||||||
Migrations
|
Migrations
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,6 @@ class SQLiteOperationsTests(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_sql_flush_sequences(self):
|
def test_sql_flush_sequences(self):
|
||||||
# sequences doesn't change statements on SQLite.
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
connection.ops.sql_flush(
|
connection.ops.sql_flush(
|
||||||
no_style(),
|
no_style(),
|
||||||
|
@ -50,11 +49,12 @@ class SQLiteOperationsTests(TestCase):
|
||||||
[
|
[
|
||||||
'DELETE FROM "backends_person";',
|
'DELETE FROM "backends_person";',
|
||||||
'DELETE FROM "backends_tag";',
|
'DELETE FROM "backends_tag";',
|
||||||
|
'UPDATE "sqlite_sequence" SET "seq" = 0 WHERE "name" IN '
|
||||||
|
'(\'backends_person\', \'backends_tag\');',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_sql_flush_sequences_allow_cascade(self):
|
def test_sql_flush_sequences_allow_cascade(self):
|
||||||
# sequences doesn't change statements on SQLite.
|
|
||||||
statements = connection.ops.sql_flush(
|
statements = connection.ops.sql_flush(
|
||||||
no_style(),
|
no_style(),
|
||||||
[Person._meta.db_table, Tag._meta.db_table],
|
[Person._meta.db_table, Tag._meta.db_table],
|
||||||
|
@ -63,7 +63,7 @@ class SQLiteOperationsTests(TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
# The tables are processed in an unordered set.
|
# The tables are processed in an unordered set.
|
||||||
sorted(statements),
|
sorted(statements[:-1]),
|
||||||
[
|
[
|
||||||
'DELETE FROM "backends_person";',
|
'DELETE FROM "backends_person";',
|
||||||
'DELETE FROM "backends_tag";',
|
'DELETE FROM "backends_tag";',
|
||||||
|
@ -72,3 +72,14 @@ class SQLiteOperationsTests(TestCase):
|
||||||
'zzzzzzzzzzzzzzzzzzzzzzz";',
|
'zzzzzzzzzzzzzzzzzzzzzzz";',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
self.assertIs(statements[-1].startswith(
|
||||||
|
'UPDATE "sqlite_sequence" SET "seq" = 0 WHERE "name" IN ('
|
||||||
|
), True)
|
||||||
|
self.assertIn("'backends_person'", statements[-1])
|
||||||
|
self.assertIn("'backends_tag'", statements[-1])
|
||||||
|
self.assertIn(
|
||||||
|
"'backends_verylongmodelnamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||||
|
"zzzz_m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||||
|
"zzz'",
|
||||||
|
statements[-1],
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue