From e0e2a9e7a88d910e5dd1491404ca04668c1d12af Mon Sep 17 00:00:00 2001 From: itssme Date: Mon, 20 Jun 2022 00:59:24 +0200 Subject: [PATCH 1/2] gh-79009: sqlite3.iterdump now correctly handles tables with autoincrement (GH-9621) Co-authored-by: Erlend E. Aasland (cherry picked from commit affa9f22cfd1e83a5fb413e5ce2feef9ea1a49ac) Co-authored-by: itssme --- Lib/sqlite3/dump.py | 14 +++++- Lib/sqlite3/test/dump.py | 47 +++++++++++++++++++ Misc/ACKS | 1 + .../2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst | 1 + 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index de9c368be3014e..07b9da10b920f9 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -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_'): @@ -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;') diff --git a/Lib/sqlite3/test/dump.py b/Lib/sqlite3/test/dump.py index 618a7fd31c1543..b4ad78a37fbc36 100644 --- a/Lib/sqlite3/test/dump.py +++ b/Lib/sqlite3/test/dump.py @@ -2,6 +2,8 @@ import unittest import sqlite3 as sqlite +from .test_dbapi import memory_database + class DumpTests(unittest.TestCase): def setUp(self): @@ -49,6 +51,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() + + with memory_database() as cx2: + 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: diff --git a/Misc/ACKS b/Misc/ACKS index c690200c15dd1a..f356d029f3276d 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -928,6 +928,7 @@ Ron Klatchko Reid Kleckner Carsten Klein Bastian Kleineidam +Joel Klimont Bob Kline Matthias Klose Jeremy Kloth diff --git a/Misc/NEWS.d/next/Library/2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst b/Misc/NEWS.d/next/Library/2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst new file mode 100644 index 00000000000000..b0e10a158b5b19 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-09-28-22-18-03.bpo-34828.5Zyi_S.rst @@ -0,0 +1 @@ +:meth:`sqlite3.Connection.iterdump` now handles databases that use ``AUTOINCREMENT`` in one or more tables. From 2f9326c37d0ebf5077ad874c619640a515b058ed Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Mon, 20 Jun 2022 01:51:34 +0200 Subject: [PATCH 2/2] Fix backport --- Lib/sqlite3/test/dump.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Lib/sqlite3/test/dump.py b/Lib/sqlite3/test/dump.py index b4ad78a37fbc36..0e324ee1769e87 100644 --- a/Lib/sqlite3/test/dump.py +++ b/Lib/sqlite3/test/dump.py @@ -2,7 +2,6 @@ import unittest import sqlite3 as sqlite -from .test_dbapi import memory_database class DumpTests(unittest.TestCase): @@ -79,22 +78,22 @@ def test_dump_autoincrement_create_new_db(self): self.cu.executemany("INSERT INTO t2 VALUES(?)", ((None,) for _ in range(4))) self.cx.commit() - with memory_database() as cx2: - query = "".join(self.cx.iterdump()) - cx2.executescript(query) - cu2 = cx2.cursor() + 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) + 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) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy