Skip to content

Install pre-close vtab on readonly connections - #207

Merged
simolus3 merged 5 commits into
mainfrom
allow-readonly-init
Jul 30, 2026
Merged

Install pre-close vtab on readonly connections#207
simolus3 merged 5 commits into
mainfrom
allow-readonly-init

Conversation

@simolus3

Copy link
Copy Markdown
Contributor

Some functions using StorageAdapter state may reasonably be called on read-only connections:

  1. powersync_offline_sync_status() is read-only, and uses the adapter since Use microsecond precision for timestamps #183.
  2. powersync_control('target_checkpoint_request_id', null) (added in 0.5.1) is read-only, and also uses the adapter.

Using the storage adapter is generally a good thing because it caches prepared statements. However, these statements need to be finalized before the database can fully close. For write connections, SDKs call powersync_init() which registers a custom vtab for this purpose. This function is not called on read-only connections though, so these statements leak and the connection is not properly closed.

As a simple fix that won't require SDK changes, this installs the pre-close hook only when it's needed to clean something up: When hooks are installed or when the storage adapter is created. For this to work on read-only connections, the vtab is now based on SELECT statements as INSERTs, even into virtual tables, are forbidden.

AI use: Migrating the vtab was done by Claude Code.

@simolus3
simolus3 marked this pull request as ready for review July 29, 2026 15:42
@simolus3
simolus3 requested a review from rkistner July 29, 2026 15:42

@rkistner rkistner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach sounds good to me. Just want to check: How often would ensure_has_internal_close_vtab be called now? Just to confirm we're not effectively just preparing SELECT 1 FROM powersync_internal_close on every call now, which would kinda defeat the purpose of using prepared statements. It looks like it's called at most once per connection, but just want to confirm.

@simolus3

Copy link
Copy Markdown
Contributor Author

Just to confirm we're not effectively just preparing SELECT 1 FROM powersync_internal_close on every call now, which would kinda defeat the purpose of using prepared statements

It's just done once per connection, I also confirmed this with breakpoints to be sure. The only call site that creates a new storage adapter is DatabaseState::storage_adapter, and the only way for for the adapter to be dropped is for release_resources to be called, which only happens when the connection is closed.

@simolus3
simolus3 merged commit 5af4ec3 into main Jul 30, 2026
32 checks passed
@simolus3
simolus3 deleted the allow-readonly-init branch July 30, 2026 08:58
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.

2 participants