docs(spi): clarify SpiClient::select vs update for read-only vs writable SPI#2328
Open
uded wants to merge 1 commit into
Open
docs(spi): clarify SpiClient::select vs update for read-only vs writable SPI#2328uded wants to merge 1 commit into
uded wants to merge 1 commit into
Conversation
…ble SPI
Expand the docstrings on SpiClient::select and SpiClient::update so that
callers can tell which to reach for without having to read the underlying
SPI_execute call site.
The previous one-line docstrings ("Perform a SELECT statement" /
"Perform any query that modifies the database in some way") frame the
distinction purely as "read query vs write query." That framing is
incomplete: SpiClient::select runs in read-only SPI mode, which also
forbids locking clauses on a plain SELECT (FOR UPDATE / SKIP LOCKED /
FOR SHARE / NOWAIT). A reader who uses select for "SELECT id FROM t
ORDER BY id LIMIT 5 FOR UPDATE SKIP LOCKED" hits
ERROR: SELECT FOR UPDATE is not allowed in a non-volatile function
and then a BGW context turns that ERROR into a panic in the abort path
and the worker SIGABRTs. The fix is mechanical (switch to
SpiClient::update which calls Spi::mark_mutable() first), but the
docstrings don't currently nudge the reader toward it.
This patch:
* Adds a paragraph to SpiClient::select describing read-only mode, the
error message a misuse produces, and the pointer to SpiClient::update.
* Adds a paragraph to SpiClient::update explicitly listing the locking
clauses as cases that need writable SPI even when the statement
looks like a SELECT.
* Links to Spi::is_xact_still_immutable and Spi::mark_mutable from
both docstrings so the read_only flag's lifecycle is discoverable.
No behaviour changes. Intra-doc links use the existing pgrx convention.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pure docs change. No behaviour change.
Motivation
The current docstrings on
SpiClient::selectandSpiClient::updateframe the distinction as "read query vs write query":That framing is incomplete.
selectruns the underlyingSPI_execute*withread_only = is_xact_still_immutable(), which on a fresh BGW transaction meansread_only = true. PostgreSQL then rejects any locking clause — including on a plain SELECT — with:A reader who writes
client.select("SELECT id FROM t ORDER BY id LIMIT 5 FOR UPDATE SKIP LOCKED", …)because it "is a SELECT" hits this error. In a BGW the abort path turns it into a panic-while-handling-panic, the worker SIGABRTs, and the postmaster crash-recovers. The fix is mechanical (connect→connect_mut,select→update), but the docs don't currently nudge the reader toward it.I had this exact misread last week and filed it as a bug (#2327) before re-reading
client.updateand realising pgrx had the right shape all along. Closed the issue as user error. This PR is a follow-up to make the next person less likely to make the same mistake.What this PR does
SpiClient::selectdescribing the read-only-SPI execution mode, the specific error message a misuse produces, and the pointer toSpiClient::update.SpiClient::updateexplicitly listing the locking clauses (FOR UPDATE,FOR SHARE,SKIP LOCKED,NOWAIT) as cases that need writable SPI even when the statement looks like a SELECT.Spi::is_xact_still_immutable] and [Spi::mark_mutable] from both docstrings so theread_onlyflag's lifecycle is discoverable.Intra-doc link format matches the existing pgrx convention (
[Spi::foo]). No code changes;rustfmt --checkclean.Why not a code change
The behaviour is correct —
client.updatecallsSpi::mark_mutable()first, so locking clauses work through that path. The gap is purely doc-level.If you'd prefer different wording (terser, or with a runnable example, or moved to
Spi::connect/Spi::connect_mutinstead of the client methods), happy to revise.Closes the docs side of #2327.