Don't run prepare_connection() on internal database, closes #2468

This commit is contained in:
Simon Willison 2025-02-18 10:23:23 -08:00
commit 209bdee0e8
3 changed files with 13 additions and 3 deletions

View file

@ -116,6 +116,8 @@ app_root = Path(__file__).parent.parent
# https://github.com/simonw/datasette/issues/283#issuecomment-781591015
SQLITE_LIMIT_ATTACHED = 10
INTERNAL_DB_NAME = "__INTERNAL__"
Setting = collections.namedtuple("Setting", ("name", "default", "help"))
SETTINGS = (
Setting("default_page_size", 100, "Default page size for the table view"),
@ -328,7 +330,7 @@ class Datasette:
self._internal_database = Database(self, memory_name=secrets.token_hex())
else:
self._internal_database = Database(self, path=internal, mode="rwc")
self._internal_database.name = "__INTERNAL__"
self._internal_database.name = INTERNAL_DB_NAME
self.cache_headers = cache_headers
self.cors = cors
@ -878,7 +880,7 @@ class Datasette:
def _prepare_connection(self, conn, database):
conn.row_factory = sqlite3.Row
conn.text_factory = lambda x: str(x, "utf-8", "replace")
if self.sqlite_extensions:
if self.sqlite_extensions and database != INTERNAL_DB_NAME:
conn.enable_load_extension(True)
for extension in self.sqlite_extensions:
# "extension" is either a string path to the extension
@ -891,7 +893,8 @@ class Datasette:
if self.setting("cache_size_kb"):
conn.execute(f"PRAGMA cache_size=-{self.setting('cache_size_kb')}")
# pylint: disable=no-member
pm.hook.prepare_connection(conn=conn, database=database, datasette=self)
if database != INTERNAL_DB_NAME:
pm.hook.prepare_connection(conn=conn, database=database, datasette=self)
# If self.crossdb and this is _memory, connect the first SQLITE_LIMIT_ATTACHED databases
if self.crossdb and database == "_memory":
count = 0

View file

@ -57,6 +57,8 @@ arguments and can be called like this::
select random_integer(1, 10);
``prepare_connection()`` hooks are not called for Datasette's :ref:`internal database <internals_internal>`.
Examples: `datasette-jellyfish <https://datasette.io/plugins/datasette-jellyfish>`__, `datasette-jq <https://datasette.io/plugins/datasette-jq>`__, `datasette-haversine <https://datasette.io/plugins/datasette-haversine>`__, `datasette-rure <https://datasette.io/plugins/datasette-rure>`__
.. _plugin_hook_prepare_jinja2_environment:

View file

@ -59,6 +59,11 @@ async def test_hook_plugin_prepare_connection_arguments(ds_client):
"database=fixtures, datasette.plugin_config(\"name-of-plugin\")={'depth': 'root'}"
] == response.json()
# Function should not be available on the internal database
db = ds_client.ds.get_internal_database()
with pytest.raises(sqlite3.OperationalError):
await db.execute("select prepare_connection_args()")
@pytest.mark.asyncio
@pytest.mark.parametrize(