summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Dufresne <jon.dufresne@gmail.com>2020-04-18 09:38:42 -0700
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-04-21 10:41:47 +0200
commit75866b93cc285c87cfc764a32d081493b19c1dc5 (patch)
tree0d7a65c3f324a524ee156e26a1d8582b40f171a3
parent5220ca8d8a109721378e8d4c7f32e342c3a83af6 (diff)
Fixed #31479 -- Added support to reset sequences on SQLite.
-rw-r--r--django/db/backends/sqlite3/features.py1
-rw-r--r--django/db/backends/sqlite3/operations.py26
-rw-r--r--docs/releases/3.1.txt3
-rw-r--r--tests/backends/sqlite/test_operations.py17
4 files changed, 40 insertions, 7 deletions
diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py
index 84eca98644..817b1067e3 100644
--- a/django/db/backends/sqlite3/features.py
+++ b/django/db/backends/sqlite3/features.py
@@ -26,7 +26,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_atomic_references_rename = Database.sqlite_version_info >= (3, 26, 0)
can_create_inline_fk = False
supports_paramstyle_pyformat = False
- supports_sequence_reset = False
can_clone_databases = True
supports_temporal_subtraction = True
ignores_table_name_case = True
diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py
index 3f55332c99..9510b5edd9 100644
--- a/django/db/backends/sqlite3/operations.py
+++ b/django/db/backends/sqlite3/operations.py
@@ -201,13 +201,33 @@ class DatabaseOperations(BaseDatabaseOperations):
# Simulate TRUNCATE CASCADE by recursively collecting the tables
# referencing the tables to be flushed.
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_flush() implementations). Just return SQL at this point
- return ['%s %s %s;' % (
+ sql = ['%s %s %s;' % (
style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(self.quote_name(table))
) 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):
if value is None:
diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt
index 4cf8183d4b..ceb1b0f0bf 100644
--- a/docs/releases/3.1.txt
+++ b/docs/releases/3.1.txt
@@ -320,6 +320,9 @@ Management Commands
* The new :option:`dbshell -- ARGUMENTS <dbshell -->` option allows passing
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
~~~~~~~~~~
diff --git a/tests/backends/sqlite/test_operations.py b/tests/backends/sqlite/test_operations.py
index 0ee70061f8..863a978580 100644
--- a/tests/backends/sqlite/test_operations.py
+++ b/tests/backends/sqlite/test_operations.py
@@ -40,7 +40,6 @@ class SQLiteOperationsTests(TestCase):
)
def test_sql_flush_sequences(self):
- # sequences doesn't change statements on SQLite.
self.assertEqual(
connection.ops.sql_flush(
no_style(),
@@ -50,11 +49,12 @@ class SQLiteOperationsTests(TestCase):
[
'DELETE FROM "backends_person";',
'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):
- # sequences doesn't change statements on SQLite.
statements = connection.ops.sql_flush(
no_style(),
[Person._meta.db_table, Tag._meta.db_table],
@@ -63,7 +63,7 @@ class SQLiteOperationsTests(TestCase):
)
self.assertEqual(
# The tables are processed in an unordered set.
- sorted(statements),
+ sorted(statements[:-1]),
[
'DELETE FROM "backends_person";',
'DELETE FROM "backends_tag";',
@@ -72,3 +72,14 @@ class SQLiteOperationsTests(TestCase):
'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],
+ )