pg: ->disconnect() and docs
This commit is contained in:
parent
171afc0268
commit
96aee880ce
3 changed files with 152 additions and 3 deletions
4
FU.xs
4
FU.xs
|
|
@ -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
144
FU/PG.pm
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue