From 8381c49085bbb6dd167a960810998f2056e11186 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Tue, 22 Aug 2023 22:28:22 +0200 Subject: [PATCH 1/7] gh-64662: Add virtual table support to sqlite3.Connection.iterdump --- Doc/whatsnew/3.13.rst | 3 +++ Lib/sqlite3/dump.py | 20 ++++++++++++------- Lib/test/test_sqlite3/test_dump.py | 20 +++++++++++++++++++ ...3-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst | 2 ++ 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 8509e18a7d792e..e261b660666ea9 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -165,6 +165,9 @@ sqlite3 object is not :meth:`closed ` explicitly. (Contributed by Erlend E. Aasland in :gh:`105539`.) +* Add support for virtual tables to :meth:`sqlite3.Connection.iterdump`. + (Contributed by Aviv Palivoda in :gh:`64662`.) + tkinter ------- diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 07b9da10b920f9..e238a293da0eb5 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -16,6 +16,7 @@ def _iterdump(connection): directly but instead called from the Connection method, iterdump(). """ + writeable_schema = False cu = connection.cursor() yield('BEGIN TRANSACTION;') @@ -42,13 +43,15 @@ def _iterdump(connection): yield('ANALYZE "sqlite_master";') elif table_name.startswith('sqlite_'): continue - # NOTE: Virtual table support not implemented - #elif sql.startswith('CREATE VIRTUAL TABLE'): - # qtable = table_name.replace("'", "''") - # yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"\ - # "VALUES('table','{0}','{0}',0,'{1}');".format( - # qtable, - # sql.replace("''"))) + elif sql.startswith('CREATE VIRTUAL TABLE'): + if not writeable_schema: + writeable_schema = True + yield('PRAGMA writable_schema=ON;') + qtable = table_name.replace("'", "''") + yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"\ + "VALUES('table','{0}','{0}',0,'{1}');".format( + qtable, + sql.replace("'", "''"))) else: yield('{0};'.format(sql)) @@ -74,6 +77,9 @@ def _iterdump(connection): for name, type, sql in schema_res.fetchall(): yield('{0};'.format(sql)) + if writeable_schema: + yield('PRAGMA writable_schema=OFF;') + # gh-79009: Yield statements concerning the sqlite_sequence table at the # end of the transaction. for row in sqlite_sequence: diff --git a/Lib/test/test_sqlite3/test_dump.py b/Lib/test/test_sqlite3/test_dump.py index 5f6811fb5cc0a5..3107e1b165d950 100644 --- a/Lib/test/test_sqlite3/test_dump.py +++ b/Lib/test/test_sqlite3/test_dump.py @@ -113,6 +113,26 @@ def __getitem__(self, index): got = list(self.cx.iterdump()) self.assertEqual(expected, got) + def test_dump_virtual_tables(self): + # gh-64662 + expected = [ + "BEGIN TRANSACTION;", + "PRAGMA writable_schema=ON;", + ("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" + "VALUES('table','test','test',0,'CREATE VIRTUAL TABLE test USING fts4(example)');"), + "CREATE TABLE 'test_content'(docid INTEGER PRIMARY KEY, 'c0example');", + "CREATE TABLE 'test_docsize'(docid INTEGER PRIMARY KEY, size BLOB);", + ("CREATE TABLE 'test_segdir'(level INTEGER,idx INTEGER,start_block INTEGER," + "leaves_end_block INTEGER,end_block INTEGER,root BLOB,PRIMARY KEY(level, idx));"), + "CREATE TABLE 'test_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", + "CREATE TABLE 'test_stat'(id INTEGER PRIMARY KEY, value BLOB);", + "PRAGMA writable_schema=OFF;", + "COMMIT;" + ] + self.cu.execute("CREATE VIRTUAL TABLE test USING fts4(example)") + actual = list(self.cx.iterdump()) + self.assertEqual(expected, actual) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst b/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst new file mode 100644 index 00000000000000..3fddc8c43aa1db --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst @@ -0,0 +1,2 @@ +Add support for virtual tables to :meth:`sqlite3.Connection.iterdump`. Patch +by Aviv Palivoda. From 12d126f9acfe420ec69e7c7f7c33704e9acfc56e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 22 Aug 2023 22:33:46 +0200 Subject: [PATCH 2/7] Remove old-style line continuation --- Lib/sqlite3/dump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index e238a293da0eb5..fa4150ef6aec4c 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -48,7 +48,7 @@ def _iterdump(connection): writeable_schema = True yield('PRAGMA writable_schema=ON;') qtable = table_name.replace("'", "''") - yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"\ + yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" "VALUES('table','{0}','{0}',0,'{1}');".format( qtable, sql.replace("'", "''"))) From 9741df53f584308e1b7798dadaa51e9ad8d54a2b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 25 Aug 2023 15:13:35 +0200 Subject: [PATCH 3/7] Use new quoting helpers --- Lib/sqlite3/dump.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 20d210837b9621..969c1c9e2f770e 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -55,11 +55,11 @@ def _iterdump(connection): if not writeable_schema: writeable_schema = True yield('PRAGMA writable_schema=ON;') - qtable = table_name.replace("'", "''") + qtable = _quote_value(table_name) yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" "VALUES('table','{0}','{0}',0,'{1}');".format( qtable, - sql.replace("'", "''"))) + _quote_value(sql))) else: yield('{0};'.format(sql)) From 3af3b180612b5e14d61a7903d5284948d597acea Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 25 Aug 2023 15:14:45 +0200 Subject: [PATCH 4/7] Style --- Lib/sqlite3/dump.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 969c1c9e2f770e..5fc0bbf8a58902 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -58,8 +58,9 @@ def _iterdump(connection): qtable = _quote_value(table_name) yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" "VALUES('table','{0}','{0}',0,'{1}');".format( - qtable, - _quote_value(sql))) + qtable, + _quote_value(sql), + )) else: yield('{0};'.format(sql)) From e11bff8d94e931007a9c9e42c90fb17bc5048fa7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 25 Aug 2023 15:15:37 +0200 Subject: [PATCH 5/7] Remove temp variable --- Lib/sqlite3/dump.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 5fc0bbf8a58902..81778f793c7004 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -55,10 +55,9 @@ def _iterdump(connection): if not writeable_schema: writeable_schema = True yield('PRAGMA writable_schema=ON;') - qtable = _quote_value(table_name) yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" "VALUES('table','{0}','{0}',0,'{1}');".format( - qtable, + _quote_value(table_name), _quote_value(sql), )) else: From 62b2ef106f8bb51c2adfcdbaa391f67e36b1277c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 25 Aug 2023 15:29:41 +0200 Subject: [PATCH 6/7] Quoting --- Lib/sqlite3/dump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 81778f793c7004..7686ff37779858 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -56,7 +56,7 @@ def _iterdump(connection): writeable_schema = True yield('PRAGMA writable_schema=ON;') yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" - "VALUES('table','{0}','{0}',0,'{1}');".format( + "VALUES('table',{0},{0},'0',{1});".format( _quote_value(table_name), _quote_value(sql), )) From e30c14aafe4fe33f40e162b6774c4d538b545179 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 25 Aug 2023 15:57:23 +0200 Subject: [PATCH 7/7] Not the int literal! --- Lib/sqlite3/dump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 7686ff37779858..ead3360ce67608 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -56,7 +56,7 @@ def _iterdump(connection): writeable_schema = True yield('PRAGMA writable_schema=ON;') yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" - "VALUES('table',{0},{0},'0',{1});".format( + "VALUES('table',{0},{0},0,{1});".format( _quote_value(table_name), _quote_value(sql), ))