Skip to content

Commit

Permalink
Backup of SQLite fail if there are Virtual Tables (e.g. FTS tables). (j…
Browse files Browse the repository at this point in the history
  • Loading branch information
xbello authored Aug 17, 2022
1 parent d601574 commit 3d94b0d
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 6 deletions.
11 changes: 5 additions & 6 deletions dbbackup/db/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,16 @@ class SqliteConnector(BaseDBConnector):
def _write_dump(self, fileobj):
cursor = self.connection.cursor()
cursor.execute(DUMP_TABLES)
for table_name, type, sql in cursor.fetchall():
for table_name, _, sql in cursor.fetchall():
if table_name.startswith("sqlite_") or table_name in self.exclude:
continue
elif sql.startswith("CREATE TABLE"):
if sql.startswith("CREATE TABLE"):
sql = sql.replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS")
# Make SQL commands in 1 line
sql = sql.replace("\n ", "")
sql = sql.replace("\n)", ")")
fileobj.write(f"{sql};\n".encode())
else:
fileobj.write(f"{sql};\n")
fileobj.write(f"{sql};\n".encode())

table_name_ident = table_name.replace('"', '""')
res = cursor.execute(f'PRAGMA table_info("{table_name_ident}")')
column_names = [str(table_info[1]) for table_info in res.fetchall()]
Expand All @@ -54,7 +53,7 @@ def _write_dump(self, fileobj):
for row in query_res:
fileobj.write(f"{row[0]};\n".encode())
schema_res = cursor.execute(DUMP_ETC)
for name, type, sql in schema_res.fetchall():
for name, _, sql in schema_res.fetchall():
if sql.startswith("CREATE INDEX"):
sql = sql.replace("CREATE INDEX", "CREATE INDEX IF NOT EXISTS")
fileobj.write(f"{sql};\n".encode())
Expand Down
9 changes: 9 additions & 0 deletions dbbackup/tests/test_connectors/test_sqlite.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from io import BytesIO

from django.db import connection
from django.test import TestCase
from mock import mock_open, patch

Expand Down Expand Up @@ -32,6 +33,14 @@ def test_restore_dump(self):
dump = connector.create_dump()
connector.restore_dump(dump)

def test_create_dump_with_virtual_tables(self):
with connection.cursor() as c:
c.execute("CREATE VIRTUAL TABLE lookup USING fts5(field)")

connector = SqliteConnector()
dump = connector.create_dump()
self.assertTrue(dump.read())


@patch("dbbackup.db.sqlite.open", mock_open(read_data=b"foo"), create=True)
class SqliteCPConnectorTest(TestCase):
Expand Down

0 comments on commit 3d94b0d

Please sign in to comment.