Skip to content

Stop a raise inside a UDF block from deadlocking other threads - #731

Merged
flavorjones merged 1 commit into
mainfrom
card-321-callback-rb-protect
Aug 11, 2026
Merged

Stop a raise inside a UDF block from deadlocking other threads#731
flavorjones merged 1 commit into
mainfrom
card-321-callback-rb-protect

Conversation

@flavorjones

Copy link
Copy Markdown
Member

When a block registered with Database#define_function raised an exception, the connection was left holding sqlite's per-connection mutex. Any other thread that subsequently used the connection blocked forever while holding the GVL, wedging the entire process.

The scalar function callback now invokes the block under rb_protect, following the pattern established by the aggregate handlers in aggregator.c: a raise is converted into sqlite3_result_error so that sqlite unwinds and releases its mutex normally, and Statement#step re-raises the original exception to the caller.

When a block registered with `Database#define_function` raised an
exception, the connection was left holding sqlite's per-connection
mutex. Any other thread that subsequently used the connection blocked
forever while holding the GVL, wedging the entire process.

The scalar function callback will now invoke the block under
`rb_protect`, following the pattern established by the aggregate
handlers in `aggregator.c`: a raise will be converted into
`sqlite3_result_error` so that sqlite unwinds and releases its mutex
normally, and `Statement#step` will re-raise the original exception to
the caller.
@flavorjones
flavorjones merged commit 7230171 into main Aug 11, 2026
135 checks passed
@flavorjones
flavorjones deleted the card-321-callback-rb-protect branch August 11, 2026 19: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.

1 participant