Skip to content

Commit a03f298

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

File tree

4 files changed

+104
-13
lines changed

4 files changed

+104
-13
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: 64 additions & 6 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: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,7 +1983,7 @@ Returns iterator to the dump of the database in an SQL text format.
19831983
[clinic start generated code]*/
19841984

19851985
static PyObject *
1986-
pysqlite_connection_iterdump_impl(pysqlite_Connection *self)
1986+
pysqlite_connection_iterdump_impl(pysqlite_Connection *self, const char *filter)
19871987
/*[clinic end generated code: output=586997aaf9808768 input=1911ca756066da89]*/
19881988
{
19891989
if (!pysqlite_check_connection(self)) {
@@ -1998,8 +1998,9 @@ pysqlite_connection_iterdump_impl(pysqlite_Connection *self)
19981998
}
19991999
return NULL;
20002000
}
2001-
2002-
PyObject *retval = PyObject_CallOneArg(iterdump, (PyObject *)self);
2001+
PyObject *py_filter = NULL;
2002+
py_filter = PyUnicode_FromString(filter);
2003+
PyObject *retval = PyObject_Call(iterdump, (PyObject *)self, py_filter);
20032004
Py_DECREF(iterdump);
20042005
return retval;
20052006
}

0 commit comments

Comments
 (0)