Skip to content

Commit 46302ad

Browse files
committed
gh-91602: Add iterdump() support for filtering database objects.
1 parent 49785b0 commit 46302ad

File tree

4 files changed

+97
-15
lines changed

4 files changed

+97
-15
lines changed

Lib/sqlite3/dump.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def _quote_value(value):
1515
return "'{0}'".format(value.replace("'", "''"))
1616

1717

18-
def _iterdump(connection):
18+
def _iterdump(connection, *, filter=None):
1919
"""
2020
Returns an iterator to the dump of the database in an SQL text format.
2121
@@ -32,15 +32,23 @@ def _iterdump(connection):
3232
yield('PRAGMA foreign_keys=OFF;')
3333
yield('BEGIN TRANSACTION;')
3434

35+
if filter:
36+
# Return database objects which match the filter pattern.
37+
filter_name_clause = 'AND "name" LIKE %s'
38+
params = [filter]
39+
else:
40+
filter_name_clause = ""
41+
params = []
3542
# sqlite_master table contains the SQL CREATE statements for the database.
36-
q = """
43+
q = f"""
3744
SELECT "name", "type", "sql"
3845
FROM "sqlite_master"
3946
WHERE "sql" NOT NULL AND
4047
"type" == 'table'
48+
{filter_name_clause}
4149
ORDER BY "name"
4250
"""
43-
schema_res = cu.execute(q)
51+
schema_res = cu.execute(q, params)
4452
sqlite_sequence = []
4553
for table_name, type, sql in schema_res.fetchall():
4654
if table_name == 'sqlite_sequence':
@@ -82,11 +90,12 @@ def _iterdump(connection):
8290
yield("{0};".format(row[0]))
8391

8492
# Now when the type is 'index', 'trigger', or 'view'
85-
q = """
93+
q = f"""
8694
SELECT "name", "type", "sql"
8795
FROM "sqlite_master"
8896
WHERE "sql" NOT NULL AND
8997
"type" IN ('index', 'trigger', 'view')
98+
{filter_name_clause}
9099
"""
91100
schema_res = cu.execute(q)
92101
for name, type, sql in schema_res.fetchall():

Lib/test/test_sqlite3/test_dump.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,29 @@ def test_table_dump(self):
5454
[self.assertEqual(expected_sqls[i], actual_sqls[i])
5555
for i in range(len(expected_sqls))]
5656

57+
def test_table_dump_filter(self):
58+
all_table_sqls = [
59+
"""CREATE TABLE "test_table_1" ("id_2" INTEGER);""",
60+
"""INSERT INTO "test_table_1" VALUES(1);""",
61+
"""INSERT INTO "test_table_1" VALUES(2);""",
62+
"""CREATE TABLE "some_table_2" ("id_1" INTEGER);""",
63+
"""INSERT INTO "some_table_2" VALUES(3);""",
64+
"""INSERT INTO "some_table_2" VALUES(4);""",
65+
]
66+
all_views_sqls = [
67+
"""CREATE VIEW view_1 AS SELECT * FROM some_table_2""",
68+
"""CREATE VIEW view_2 AS SELECT * FROM test_table_1""",
69+
]
70+
# Create database structure.
71+
for sql in [*all_table_sqls, *all_views_sqls]:
72+
self.cu.execute(sql)
73+
# %_table_% matches all tables.
74+
dump_sqls = list(self.cx.iterdump(filter="%_table_%"))
75+
self.assertEqual(dump_sqls, all_table_sqls)
76+
# view_% matches all views.
77+
dump_sqls = list(self.cx.iterdump(filter="view_%"))
78+
self.assertEqual(dump_sqls, all_views_sqls)
79+
5780
def test_dump_autoincrement(self):
5881
expected = [
5982
'CREATE TABLE "t1" (id integer primary key autoincrement);',

Modules/_sqlite/clinic/connection.c.h

Lines changed: 53 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_sqlite/connection.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,12 +1979,17 @@ pysqlite_connection_interrupt_impl(pysqlite_Connection *self)
19791979
/*[clinic input]
19801980
_sqlite3.Connection.iterdump as pysqlite_connection_iterdump
19811981
1982+
*
1983+
filter: object = None
1984+
An optional LIKE pattern for database objects to dump
1985+
19821986
Returns iterator to the dump of the database in an SQL text format.
19831987
[clinic start generated code]*/
19841988

19851989
static PyObject *
1986-
pysqlite_connection_iterdump_impl(pysqlite_Connection *self)
1987-
/*[clinic end generated code: output=586997aaf9808768 input=1911ca756066da89]*/
1990+
pysqlite_connection_iterdump_impl(pysqlite_Connection *self,
1991+
PyObject *filter)
1992+
/*[clinic end generated code: output=fd81069c4bdeb6b0 input=4ae6d9a898f108df]*/
19881993
{
19891994
if (!pysqlite_check_connection(self)) {
19901995
return NULL;
@@ -1998,8 +2003,7 @@ pysqlite_connection_iterdump_impl(pysqlite_Connection *self)
19982003
}
19992004
return NULL;
20002005
}
2001-
2002-
PyObject *retval = PyObject_CallOneArg(iterdump, (PyObject *)self);
2006+
PyObject *retval = PyObject_Call(iterdump, (PyObject *)self, filter);
20032007
Py_DECREF(iterdump);
20042008
return retval;
20052009
}

0 commit comments

Comments
 (0)