Skip to content

Commit

Permalink
[3.10] pythongh-79009: sqlite3.iterdump now correctly handles tables …
Browse files Browse the repository at this point in the history
…with autoincrement (pythonGH-9621) (python#94015)

Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
(cherry picked from commit affa9f2)

Co-authored-by: itssme <itssme3000@gmail.com>
  • Loading branch information
miss-islington and itssme committed Jun 20, 2022
1 parent cdf3689 commit 8a1bade
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 1 deletion.
14 changes: 13 additions & 1 deletion Lib/sqlite3/dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@ def _iterdump(connection):
ORDER BY "name"
"""
schema_res = cu.execute(q)
sqlite_sequence = []
for table_name, type, sql in schema_res.fetchall():
if table_name == 'sqlite_sequence':
yield('DELETE FROM "sqlite_sequence";')
rows = cu.execute('SELECT * FROM "sqlite_sequence";').fetchall()
sqlite_sequence = ['DELETE FROM "sqlite_sequence"']
sqlite_sequence += [
f'INSERT INTO "sqlite_sequence" VALUES(\'{row[0]}\',{row[1]})'
for row in rows
]
continue
elif table_name == 'sqlite_stat1':
yield('ANALYZE "sqlite_master";')
elif table_name.startswith('sqlite_'):
Expand Down Expand Up @@ -67,4 +74,9 @@ def _iterdump(connection):
for name, type, sql in schema_res.fetchall():
yield('{0};'.format(sql))

# gh-79009: Yield statements concerning the sqlite_sequence table at the
# end of the transaction.
for row in sqlite_sequence:
yield('{0};'.format(row))

yield('COMMIT;')
46 changes: 46 additions & 0 deletions Lib/sqlite3/test/dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import unittest
import sqlite3 as sqlite


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

def test_dump_autoincrement(self):
expected = [
'CREATE TABLE "t1" (id integer primary key autoincrement);',
'INSERT INTO "t1" VALUES(NULL);',
'CREATE TABLE "t2" (id integer primary key autoincrement);',
]
self.cu.executescript("".join(expected))

# the NULL value should now be automatically be set to 1
expected[1] = expected[1].replace("NULL", "1")
expected.insert(0, "BEGIN TRANSACTION;")
expected.extend([
'DELETE FROM "sqlite_sequence";',
'INSERT INTO "sqlite_sequence" VALUES(\'t1\',1);',
'COMMIT;',
])

actual = [stmt for stmt in self.cx.iterdump()]
self.assertEqual(expected, actual)

def test_dump_autoincrement_create_new_db(self):
self.cu.execute("BEGIN TRANSACTION")
self.cu.execute("CREATE TABLE t1 (id integer primary key autoincrement)")
self.cu.execute("CREATE TABLE t2 (id integer primary key autoincrement)")
self.cu.executemany("INSERT INTO t1 VALUES(?)", ((None,) for _ in range(9)))
self.cu.executemany("INSERT INTO t2 VALUES(?)", ((None,) for _ in range(4)))
self.cx.commit()

cx2 = sqlite.connect(":memory:")
query = "".join(self.cx.iterdump())
cx2.executescript(query)
cu2 = cx2.cursor()

dataset = (
("t1", 9),
("t2", 4),
)
for table, seq in dataset:
with self.subTest(table=table, seq=seq):
res = cu2.execute("""
SELECT "seq" FROM "sqlite_sequence" WHERE "name" == ?
""", (table,))
rows = res.fetchall()
self.assertEqual(rows[0][0], seq)

def test_unorderable_row(self):
# iterdump() should be able to cope with unorderable row types (issue #15545)
class UnorderableRow:
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,7 @@ Ron Klatchko
Reid Kleckner
Carsten Klein
Bastian Kleineidam
Joel Klimont
Bob Kline
Matthias Klose
Jeremy Kloth
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:meth:`sqlite3.Connection.iterdump` now handles databases that use ``AUTOINCREMENT`` in one or more tables.

0 comments on commit 8a1bade

Please sign in to comment.