Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Lib/sqlite3/dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ def _iterdump(connection, *, filter=None):
_quote_value(table_name),
_quote_value(sql),
))
# Rows live in the shadow tables, dumped separately.
continue
else:
yield('{0};'.format(sql))

Expand Down
32 changes: 32 additions & 0 deletions Lib/test/test_sqlite3/test_dump.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Author: Paul Kippes <kippesp@gmail.com>

import sqlite3
import unittest
from contextlib import closing

from test.support.os_helper import TESTFN, unlink

from .util import memory_database
from .util import MemoryDatabaseMixin
Expand Down Expand Up @@ -246,6 +250,34 @@ def test_dump_virtual_tables(self):
actual = list(self.cx.iterdump())
self.assertEqual(expected, actual)

@requires_virtual_table("fts4")
def test_dump_virtual_table_data_roundtrip(self):
# gh-153729: a populated virtual table must round-trip through iterdump().
self.addCleanup(unlink, TESTFN)
with closing(sqlite3.connect(TESTFN)) as src:
src.execute("CREATE VIRTUAL TABLE test USING fts4(example)")
src.execute("INSERT INTO test(example) VALUES('hello world')")
src.execute("INSERT INTO test(example) VALUES('second row')")
src.commit()
script = "".join(src.iterdump())

# The virtual table's own rows are not dumped as INSERT statements
# (the data is preserved via the shadow tables instead).
self.assertNotIn('INSERT INTO "test"', script)

restored_path = f"{TESTFN}.restored"
self.addCleanup(unlink, restored_path)
with closing(sqlite3.connect(restored_path)) as dst:
# Defensive mode blocks writable_schema writes to sqlite_master.
dst.setconfig(sqlite3.SQLITE_DBCONFIG_DEFENSIVE, False)
dst.setconfig(sqlite3.SQLITE_DBCONFIG_WRITABLE_SCHEMA, True)
dst.executescript(script)
with closing(sqlite3.connect(restored_path)) as restored:
rows = restored.execute(
"SELECT example FROM test ORDER BY docid"
).fetchall()
self.assertEqual(rows, [("hello world",), ("second row",)])


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:meth:`sqlite3.Connection.iterdump` no longer emits ``INSERT`` statements for
a virtual table's own rows, which previously made restoring the dump raise
:exc:`sqlite3.OperationalError`. Patch by tonghuaroot.
Loading