Skip to content

Commit 5abe4cb

Browse files
gh-79009: sqlite3.iterdump now correctly handles tables with autoincrement (GH-9621)
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com> (cherry picked from commit affa9f2) Co-authored-by: itssme <itssme3000@gmail.com>
1 parent b99f398 commit 5abe4cb

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

Diff for: Lib/sqlite3/dump.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,16 @@ def _iterdump(connection):
2828
ORDER BY "name"
2929
"""
3030
schema_res = cu.execute(q)
31+
sqlite_sequence = []
3132
for table_name, type, sql in schema_res.fetchall():
3233
if table_name == 'sqlite_sequence':
33-
yield('DELETE FROM "sqlite_sequence";')
34+
rows = cu.execute('SELECT * FROM "sqlite_sequence";').fetchall()
35+
sqlite_sequence = ['DELETE FROM "sqlite_sequence"']
36+
sqlite_sequence += [
37+
f'INSERT INTO "sqlite_sequence" VALUES(\'{row[0]}\',{row[1]})'
38+
for row in rows
39+
]
40+
continue
3441
elif table_name == 'sqlite_stat1':
3542
yield('ANALYZE "sqlite_master";')
3643
elif table_name.startswith('sqlite_'):
@@ -67,4 +74,9 @@ def _iterdump(connection):
6774
for name, type, sql in schema_res.fetchall():
6875
yield('{0};'.format(sql))
6976

77+
# gh-79009: Yield statements concerning the sqlite_sequence table at the
78+
# end of the transaction.
79+
for row in sqlite_sequence:
80+
yield('{0};'.format(row))
81+
7082
yield('COMMIT;')

Diff for: Lib/test/test_sqlite3/test_dump.py

+47
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import unittest
44
import sqlite3 as sqlite
5+
from .test_dbapi import memory_database
6+
57

68
class DumpTests(unittest.TestCase):
79
def setUp(self):
@@ -49,6 +51,51 @@ def test_table_dump(self):
4951
[self.assertEqual(expected_sqls[i], actual_sqls[i])
5052
for i in range(len(expected_sqls))]
5153

54+
def test_dump_autoincrement(self):
55+
expected = [
56+
'CREATE TABLE "t1" (id integer primary key autoincrement);',
57+
'INSERT INTO "t1" VALUES(NULL);',
58+
'CREATE TABLE "t2" (id integer primary key autoincrement);',
59+
]
60+
self.cu.executescript("".join(expected))
61+
62+
# the NULL value should now be automatically be set to 1
63+
expected[1] = expected[1].replace("NULL", "1")
64+
expected.insert(0, "BEGIN TRANSACTION;")
65+
expected.extend([
66+
'DELETE FROM "sqlite_sequence";',
67+
'INSERT INTO "sqlite_sequence" VALUES(\'t1\',1);',
68+
'COMMIT;',
69+
])
70+
71+
actual = [stmt for stmt in self.cx.iterdump()]
72+
self.assertEqual(expected, actual)
73+
74+
def test_dump_autoincrement_create_new_db(self):
75+
self.cu.execute("BEGIN TRANSACTION")
76+
self.cu.execute("CREATE TABLE t1 (id integer primary key autoincrement)")
77+
self.cu.execute("CREATE TABLE t2 (id integer primary key autoincrement)")
78+
self.cu.executemany("INSERT INTO t1 VALUES(?)", ((None,) for _ in range(9)))
79+
self.cu.executemany("INSERT INTO t2 VALUES(?)", ((None,) for _ in range(4)))
80+
self.cx.commit()
81+
82+
with memory_database() as cx2:
83+
query = "".join(self.cx.iterdump())
84+
cx2.executescript(query)
85+
cu2 = cx2.cursor()
86+
87+
dataset = (
88+
("t1", 9),
89+
("t2", 4),
90+
)
91+
for table, seq in dataset:
92+
with self.subTest(table=table, seq=seq):
93+
res = cu2.execute("""
94+
SELECT "seq" FROM "sqlite_sequence" WHERE "name" == ?
95+
""", (table,))
96+
rows = res.fetchall()
97+
self.assertEqual(rows[0][0], seq)
98+
5299
def test_unorderable_row(self):
53100
# iterdump() should be able to cope with unorderable row types (issue #15545)
54101
class UnorderableRow:

Diff for: Misc/ACKS

+1
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,7 @@ Ron Klatchko
934934
Reid Kleckner
935935
Carsten Klein
936936
Bastian Kleineidam
937+
Joel Klimont
937938
Bob Kline
938939
Matthias Klose
939940
Jeremy Kloth
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:meth:`sqlite3.Connection.iterdump` now handles databases that use ``AUTOINCREMENT`` in one or more tables.

0 commit comments

Comments
 (0)