pg: ->disconnect() and docs

This commit is contained in:
Yorhel 2025-02-07 10:49:47 +01:00
parent 171afc0268
commit 96aee880ce
3 changed files with 152 additions and 3 deletions

4
FU.xs
View file

@ -117,6 +117,10 @@ void q(fupg_conn *c, SV *sv, ...)
FUPG_CONN_COOKIE;
ST(0) = fupg_q(aTHX_ c, SvPVutf8_nolen(sv), ax, items);
void disconnect(fupg_conn *c)
CODE:
fupg_disconnect(c);
void DESTROY(fupg_conn *c)
CODE:
fupg_destroy(c);

144
FU/PG.pm
View file

@ -53,7 +53,10 @@ package FU::PG::txn {
}
sub DESTROY($t) {
$t->rollback if $t->[1];
# Can't really throw an error in DESTROY. If a rollback command fails,
# we're sufficiently screwed that the only sensible recourse is to
# disconnect and let any further operations throw an error.
eval { $t->rollback; 1 } || $t->[0]->disconnect if $t->[1];
$t->[0]->_set_cookie($t->[2] ? $t->[2][1] : 0);
}
}
@ -127,6 +130,43 @@ C<$major * 10000 + $minor>. For example, returns 170002 for PostgreSQL 17.2.
Returns the libpq version in the same format as the C<server_version> method.
Also available directly as C<FU::PG::lib_version()>.
=item B<< $conn->status >>
Returns a string indicating the status of the connection. Note that this method
does not verify that the connection is still alive, the status is updated after
each command. Possible return values:
=over
=item idle
Awaiting commands, not in a transaction.
=item txn_idle
Awaiting commands, inside a transaction.
=item txn_done
Idle, but a transaction object still exists. The connection is unusable until
that object goes out of scope.
=item txn_error
Inside a transaction that is in an error state. The transaction must be rolled
back in order to recover to a usable state. This happens automatically when the
transaction object goes out of scope.
=item bad
Connection is dead or otherwise unusable.
=back
=item B<< $conn->disconnect >>
Close the connection. Any active transactions are rolled back and any further
attempts to use C<$conn> throw an error.
=back
@ -226,7 +266,107 @@ multiple columns with the same name.
=head2 Transactions
I<TODO>
This module provides a convenient and safe API for I<scoped transactions> and
I<subtransactions>. A new transaction can be started with C<< $conn->txn >>,
which returns an object that can be used to run commands inside the transaction
and control its fate. When the object goes out of scope, the transaction is
automatically rolled back if no explicit C<< $txn->commit >> has been
performed. Any attempts to run queries on the parent C<< $conn >> object will
fail while a transaction object is alive.
{
# start a new transaction
my $txn = $conn->txn;
# run queries
$txn->q('DELETE FROM books WHERE id = $1', 1)->exec;
# run commands in a subtransaction
{
my $subtxn = $txn->txn;
# ...
}
# commit
$txn->commit;
# If $txn->commit has not been called, the transaction will be rolled back
# automatically when it goes out of scope.
}
Transaction methods:
=over
=item B<< $txn->exec(..) >> and B<< $txn->q(..) >>
Run a query inside the transaction. These work the same as the respective
methods on the parent C<$conn> object.
=item B<< $txn->commit >> and B<< $txn->rollback >>
Commit or abort the transaction. Any attempts to run queries on this
transaction object after this call will throw an error.
Calling C<rollback> is optional, the transaction is automatically rolled back
when the object goes out of scope.
=item B<< $txn->txn >>
Create a subtransaction within the current transaction. A subtransaction works
exactly the same as a top-level transaction.
=item B<< $txn->status >>
Like C<< $conn->status >>, but with the following status codes:
=over
=item idle
Current transaction is active and awaiting commands.
=item done
Current transaction has either been committed or rolled back, further commands
will throw an error.
=item error
Current transaction is in error state and must be rolled back.
=item txn_idle
A subtransaction is active and awaiting commands. The current transaction is
not usable until the subtransaction goes out of scope.
(This status code is also returned when the subtransaction is 'done', the
current implementation does not track subtransactions that closely)
=item txn_error
A subtransaction is in error state and awaiting to be rolled back.
=item bad
Connection is dead or otherwise unusable.
=back
=back
Of course, if you prefer the old-fashioned manual approach to transaction
handling, that is still available:
$conn->exec('BEGIN');
# We're now inside a transaction
$conn->exec('COMMIT') or $conn->exec('ROLLBACK');
Just don't try to use transaction objects and manual transaction commands at
the same time, that won't end well.
=back
=head2 Errors

View file

@ -94,6 +94,11 @@ static const char *fupg_status(fupg_conn *c) {
}
}
static void fupg_disconnect(fupg_conn *c) {
PQfinish(c->conn);
c->conn = NULL;
}
static void fupg_destroy(fupg_conn *c) {
PQfinish(c->conn);
safefree(c);
@ -160,8 +165,8 @@ typedef struct {
SV **bind;
int bindn;
/* Set during prepare */
char name[32];
int prepared;
char name[32];
PGresult *describe;
/* Set during execute */
int paramn;