Rowtype_postgres.TransactionOne transaction on one connection, and its own failures told apart from the work's.
The work answers a result: Ok commits and Error rolls back. A failure of the transaction itself joins the work's error type as an open polymorphic variant -- the way Eio.Time.with_timeout adds `Timeout -- so a caller whose errors are polymorphic variants, as every statement's are, writes nothing, and one whose errors are ordinary variants maps once, in its own bracket.
How much of what concurrent transactions commit this one sees, as the SQL standard names the levels: Postgres's begin isolation level.
type failure = [ | `Not_committed of stringthe transaction could not begin, its COMMIT failed, or the work answered Ok from a transaction a failed statement had aborted: in words for the log. Whether it committed is known: it did not.
| `Conflict of string optionits COMMIT found a deferred constraint refusing the write because of other rows -- a unique key, an exclusion, a foreign key, declared DEFERRABLE and checked there -- named as a statement's Rowtype.error names one checked at once, and the server rolled it back
| `Not_serializable of stringits COMMIT found it could not be ordered with a concurrent transaction, as a statement's Rowtype.error says when one does, and its retries did not get past it
| `Lost of stringits COMMIT was sent and the connection failed before the answer came: it may have committed, as a statement's Rowtype.error says of a write lost in flight
| `Unsent of stringit never began: its connection, lost before it, could not be made again -- nothing answered -- so nothing of the work was sent, and running it again is safe
*) ]The transaction's own failures, which within adds to the work's: a caller tells them from its own as #Transaction.failure, and names them in an error type of its own as [ my_error | Transaction.failure ].
val within :
?keep:('e -> bool) ->
?isolation:isolation ->
?retries:int ->
conn ->
(conn -> ('a, [> failure ] as 'e) Stdlib.result) ->
('a, 'e) Stdlib.resultwithin db work: revive a connection the server dropped, begin -- once more if the first begin fails, the one point where starting again loses nothing -- run work, and commit what it answered Ok. A refusal rolls back unless keep says to keep what it wrote -- a wrong sign-in code that has to count its attempt -- and still answers the refusal: keeping what a refused request wrote is the rarer thing, and the one a reader should see named. keep keeps nothing unless given.
isolation is the level it begins at; unless given, the database's own default, which is Read_committed in a Postgres nobody configured.
retries is how many times the whole transaction runs again when the work answers `Not_serializable, or its COMMIT does -- none unless given, so a retry is always asked for. Each is an info line, and the last answer stands. Work that runs again does everything again, so work given retries does nothing but its statements: a message sent or a counter moved inside it happens once for every attempt.
`Unsent replaces the work's answer when the transaction could not begin on a connection revive could not reach. `Not_committed replaces it when the transaction could not begin otherwise -- on a connection the server refused to make again, with its reason --, when the server refused its COMMIT for anything but a conflict, or when the work answered Ok in a transaction a failed statement had already aborted -- an error the work swallowed. `Conflict replaces it when a deferred constraint refused the write at COMMIT, as it would answer from the statement had the constraint been checked there. `Lost replaces it when the connection failed with COMMIT in flight, since what the server did is not known; a statement of the work lost before it is the work's own answer, and did nothing, as the transaction ended with its connection. A refusal from an aborted transaction is the work's own answer and is kept, and a kept refusal there keeps nothing it wrote, which a warn line says. A transaction already open on the connection -- a within inside another -- is `Not_committed before anything begins, since its COMMIT would end the outer one, and the outer one goes on. Each `Not_committed and `Lost is an error line on rowtype-postgres. A raise inside work rolls back and passes.
A fiber cancelled inside work, at a statement or at any other effect, closes the connection, which ends the transaction with nothing kept, and the cancellation passes. Its statements then answer `Connection `Closed, and the next within on it, or revive, makes it again; a pooled one is made again before it is next lent.