mirror of
https://github.com/simonw/datasette.git
synced 2026-05-27 20:36:17 +02:00
Clear stale tables/other resources when DB removed, closes #2723
This commit is contained in:
parent
40e78e0927
commit
7a914f8c65
3 changed files with 67 additions and 6 deletions
|
|
@ -618,11 +618,24 @@ class Datasette:
|
|||
stale_databases = set(current_schema_versions.keys()) - set(
|
||||
self.databases.keys()
|
||||
)
|
||||
for stale_db_name in stale_databases:
|
||||
await internal_db.execute_write(
|
||||
"DELETE FROM catalog_databases WHERE database_name = ?",
|
||||
[stale_db_name],
|
||||
)
|
||||
if stale_databases:
|
||||
|
||||
def delete_stale_database_catalog(conn):
|
||||
for stale_db_name in stale_databases:
|
||||
for table in (
|
||||
"catalog_columns",
|
||||
"catalog_foreign_keys",
|
||||
"catalog_indexes",
|
||||
"catalog_views",
|
||||
"catalog_tables",
|
||||
"catalog_databases",
|
||||
):
|
||||
conn.execute(
|
||||
"DELETE FROM {} WHERE database_name = ?".format(table),
|
||||
[stale_db_name],
|
||||
)
|
||||
|
||||
await internal_db.execute_write_fn(delete_stale_database_catalog)
|
||||
for database_name, db in self.databases.items():
|
||||
schema_version = (await db.execute("PRAGMA schema_version")).first()[0]
|
||||
# Compare schema versions to see if we should skip it
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Unreleased
|
|||
----------
|
||||
|
||||
- Dropped Janus as a dependency, previously used to manage the write queue. This should not have any impact on plugin developers or end-users. (:issue:`1752`)
|
||||
|
||||
- Fixed a bug where stale tables and other related resources were not removed from ``catalog_*`` tables when a database was removed. (:issue:`2723`)
|
||||
|
||||
.. _v1_0_a29:
|
||||
|
||||
|
|
|
|||
|
|
@ -139,3 +139,51 @@ async def test_stale_catalog_entry_database_fix(tmp_path):
|
|||
f"Index page should return 200, not {response.status_code}. "
|
||||
"This fails due to stale catalog entries causing KeyError."
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stale_catalog_child_entries_removed_for_missing_database(tmp_path):
|
||||
from datasette.app import Datasette
|
||||
|
||||
import sqlite3
|
||||
|
||||
internal_db_path = str(tmp_path / "internal.db")
|
||||
alpha_db_path = str(tmp_path / "alpha.db")
|
||||
bravo_db_path = str(tmp_path / "bravo.db")
|
||||
|
||||
for db_path, table_name in (
|
||||
(alpha_db_path, "alpha_table"),
|
||||
(bravo_db_path, "bravo_table"),
|
||||
(bravo_db_path, "bravo_table_2"),
|
||||
):
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.execute(f"CREATE TABLE {table_name} (id INTEGER PRIMARY KEY)")
|
||||
conn.close()
|
||||
|
||||
ds1 = Datasette(files=[alpha_db_path, bravo_db_path], internal=internal_db_path)
|
||||
await ds1.invoke_startup()
|
||||
|
||||
catalog_tables = await ds1.get_internal_database().execute("""
|
||||
SELECT database_name, table_name
|
||||
FROM catalog_tables
|
||||
ORDER BY database_name, table_name
|
||||
""")
|
||||
assert [tuple(row) for row in catalog_tables.rows] == [
|
||||
("alpha", "alpha_table"),
|
||||
("bravo", "bravo_table"),
|
||||
("bravo", "bravo_table_2"),
|
||||
]
|
||||
|
||||
ds1.close()
|
||||
|
||||
ds2 = Datasette(files=[alpha_db_path], internal=internal_db_path)
|
||||
await ds2.invoke_startup()
|
||||
|
||||
catalog_tables = await ds2.get_internal_database().execute("""
|
||||
SELECT database_name, table_name
|
||||
FROM catalog_tables
|
||||
ORDER BY database_name, table_name
|
||||
""")
|
||||
assert [tuple(row) for row in catalog_tables.rows] == [("alpha", "alpha_table")]
|
||||
|
||||
ds2.close()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue