diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index 35344ecceff526..e3af2cd75ba5fc 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -62,11 +62,28 @@ def runsource(self, source, filename="", symbol="single"): return False if source[0] == ".": match source[1:].strip(): + case "tables": + schema_names = (row[1] + for row in self._cur.execute("PRAGMA database_list")) + select_clauses = (f"""SELECT + CASE '{schema}' + WHEN 'main' THEN name + ELSE '{schema}.' || name + END + FROM "{schema}".sqlite_master + WHERE type IN ('table', 'view') + AND name NOT LIKE 'sqlite_%' ESCAPE '_'""" + for schema in schema_names + ) + command = " UNION ALL ".join(select_clauses) + " ORDER BY 1" + for row in self._cur.execute(command): + print(row[0]) case "version": print(sqlite3.sqlite_version) case "help": t = theme.syntax print(f"Enter SQL code or one of the below commands, and press enter.\n\n" + f"{t.builtin}.tables{t.reset} Print names of tables\n" f"{t.builtin}.version{t.reset} Print underlying SQLite library version\n" f"{t.builtin}.help{t.reset} Print this help message\n" f"{t.builtin}.quit{t.reset} Exit the CLI, equivalent to CTRL-D\n") diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index 720fa3c4c1ea8b..594b07a55d19ed 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -125,6 +125,36 @@ def test_interact_version(self): self.assertEqual(out.count(self.PS2), 0) self.assertIn(sqlite3.sqlite_version, out) + def test_interact_tables(self): + out, err = self.run_cli(commands=( + "CREATE TABLE table_ (id INTEGER);", + "CREATE TABLE sqlitee (id INTEGER);", + "CREATE TEMP TABLE temp_table (id INTEGER);", + "CREATE VIEW view_ AS SELECT 1;", + "CREATE TEMP VIEW temp_view AS SELECT 1;", + "ATTACH ':memory:' AS attach_;", + "CREATE TABLE attach_.table_ (id INTEGER);", + "CREATE VIEW attach_.view_ AS SELECT 1;", + "ATTACH ':memory:' AS 123;", + "CREATE TABLE \"123\".table_ (id INTEGER);", + "CREATE VIEW \"123\".view_ AS SELECT 1;", + ".tables", + )) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 13) + self.assertEqual(out.count(self.PS2), 0) + tables = ("123.table_", + "123.view_", + "attach_.table_", + "attach_.view_", + "sqlitee", + "table_", + "temp.temp_table", + "temp.temp_view", + "view_") + self.assertIn("\n".join(tables), out) + def test_interact_empty_source(self): out, err = self.run_cli(commands=("", " ")) self.assertIn(self.MEMORY_DB_MSG, err) diff --git a/Misc/NEWS.d/next/Library/2025-06-22-02-15-09.gh-issue-135795.5HPn-r.rst b/Misc/NEWS.d/next/Library/2025-06-22-02-15-09.gh-issue-135795.5HPn-r.rst new file mode 100644 index 00000000000000..3e50d7501622ff --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-22-02-15-09.gh-issue-135795.5HPn-r.rst @@ -0,0 +1 @@ +Support ``.tables`` in the :mod:`sqlite3` command-line interface.