Skip to content

Commit 8a1bade

Browse files
[3.10] gh-79009: sqlite3.iterdump now correctly handles tables with autoincrement (GH-9621) (#94015)
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com> (cherry picked from commit affa9f2) Co-authored-by: itssme <itssme3000@gmail.com>
1 parent cdf3689 commit 8a1bade

File tree

4 files changed

+61
-1
lines changed

4 files changed

+61
-1
lines changed

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;')

Lib/sqlite3/test/dump.py

+46
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import unittest
44
import sqlite3 as sqlite
55

6+
67
class DumpTests(unittest.TestCase):
78
def setUp(self):
89
self.cx = sqlite.connect(":memory:")
@@ -49,6 +50,51 @@ def test_table_dump(self):
4950
[self.assertEqual(expected_sqls[i], actual_sqls[i])
5051
for i in range(len(expected_sqls))]
5152

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

Misc/ACKS

+1
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,7 @@ Ron Klatchko
928928
Reid Kleckner
929929
Carsten Klein
930930
Bastian Kleineidam
931+
Joel Klimont
931932
Bob Kline
932933
Matthias Klose
933934
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)