Skip to content

Avoid completion refresh crash when a view references an unavailable function - #272

Open
dajiaohuang wants to merge 1 commit into
dbcli:mainfrom
dajiaohuang:fix-completion-refresh-unavailable-function
Open

dajiaohuang wants to merge 1 commit into
dbcli:mainfrom
dajiaohuang:fix-completion-refresh-unavailable-function

Conversation

@dajiaohuang

Copy link
Copy Markdown

Description

When a database schema contains a relation (e.g. a view) that references a function which is not available in the current session — such as crypto_blake3 provided by the sqlean crypto extension loaded via .load in a previous session — SQLExecute.table_columns() fails to prepare its combined pragma_table_info query with sqlite3.OperationalError: no such function: ....

Because that query runs in the background completion refresh thread, the failure kills the refresh thread and prints a full Python traceback to the console, the completer is left partially initialized, and the refresh callbacks never run, so no completions are installed. This is the crash reported in #265 (reproducible on the current main; e.g. a database whose view is SELECT hex(crypto_blake3(product_id)) FROM products triggers the traceback on every startup).

This PR makes the introspection resilient at the boundary where schema objects are external data:

  • SQLExecute.table_columns() keeps using the fast combined query; only when it cannot be prepared does it introspect each relation individually (via a parameterized pragma_table_info(?)) and skip relations that cannot be introspected (with a debug log).
  • refresh_tables registers relation names from SQLExecute.tables() before adding column names, so a relation whose columns cannot be introspected in this session still completes by name (previously names were only derived from the columns query).

Other relations keep their full column completions, and healthy schemas take the same single combined query as before.

Checklist

  • I've added this contribution to the CHANGELOG.md file.

…function


When the database schema contains a relation (e.g. a view) that references
a function which is not available in the current session, such as one
provided by a loadable extension (`crypto_blake3` from the sqlean crypto
extension loaded via `.load`), `SQLExecute.table_columns()` fails with
`sqlite3.OperationalError: no such function: ...`. That kills the
background completion refresh thread and prints a traceback to the
console, while the completer is left partially initialized and the
refresh callbacks never run.

- Introspect each relation individually when the combined columns query
  cannot be prepared, and skip relations that cannot be introspected.
- Register relation names from `SQLExecute.tables()` so that relations
  whose columns cannot be introspected still complete by name.

Reported in dbcli#265.

Validation:
- tests/test_sqlexecute.py::test_table_columns_with_function_only_available_in_another_session
- tests/test_completion_refresher.py::test_refresh_with_view_referencing_unavailable_function

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant