pg: Add transaction & subtransaction support

Was expecting the implementation of this to get overly complicated and
brittle, but using a counter-based cookie and doing parts of it in Perl
made it pretty easy actually.  Pretty happy with how this turned out so
far.

TODO: documentation -.-
This commit is contained in:
Yorhel 2025-02-06 17:38:33 +01:00
parent 9d5905e3b4
commit 171afc0268
5 changed files with 276 additions and 10 deletions

47
FU.xs
View file

@ -14,6 +14,15 @@
#include "c/pgconn.c"
#define FUPG_CONN_COOKIE \
if (c->cookie) croak("Invalid attempt to run a query on the top-level connection while a transaction object exists")
#define FUPG_ST_COOKIE \
if (st->cookie != st->conn->cookie) croak("Invalid cross-transaction operation on statement object")
typedef fupg_conn *fupg_txn;
MODULE = FU
PROTOTYPES: DISABLE
@ -22,6 +31,7 @@ PROTOTYPES: DISABLE
TYPEMAP: <<EOT
TYPEMAP
fupg_conn * FUPG_CONN
fupg_txn FUPG_TXN
fupg_st * FUPG_ST
INPUT
@ -29,6 +39,9 @@ FUPG_CONN
if (sv_derived_from($arg, \"FU::PG::conn\")) $var = (fupg_conn *)SvIVX(SvRV($arg));
else croak(\"invalid connection object\");
FUPG_TXN
$var = fupg_get_transaction(aTHX_ $arg);
FUPG_ST
if (sv_derived_from($arg, \"FU::PG::st\")) $var = (fupg_st *)SvIVX(SvRV($arg));
else croak(\"invalid statement object\");
@ -80,12 +93,28 @@ void _debug_trace(fupg_conn *c, bool on)
else PQuntrace(c->conn);
ST(0) = c->self;
void _set_cookie(fupg_conn *c, UV cookie)
CODE:
c->cookie = cookie;
UV _get_cookie(fupg_conn *c)
CODE:
RETVAL = c->cookie;
OUTPUT:
RETVAL
void status(fupg_conn *c)
CODE:
ST(0) = sv_2mortal(newSVpv(fupg_status(c), 0));
void exec(fupg_conn *c, SV *sv)
CODE:
FUPG_CONN_COOKIE;
ST(0) = fupg_exec(aTHX_ c, SvPVutf8_nolen(sv));
void q(fupg_conn *c, SV *sv, ...)
CODE:
FUPG_CONN_COOKIE;
ST(0) = fupg_q(aTHX_ c, SvPVutf8_nolen(sv), ax, items);
void DESTROY(fupg_conn *c)
@ -93,34 +122,52 @@ void DESTROY(fupg_conn *c)
fupg_destroy(c);
MODULE = FU PACKAGE = FU::PG::txn
void exec(fupg_txn c, SV *sv)
CODE:
ST(0) = fupg_exec(aTHX_ c, SvPVutf8_nolen(sv));
void q(fupg_txn c, SV *sv, ...)
CODE:
ST(0) = fupg_q(aTHX_ c, SvPVutf8_nolen(sv), ax, items);
MODULE = FU PACKAGE = FU::PG::st
void params(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_params(aTHX_ st);
void columns(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_columns(aTHX_ st);
void exec(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_exec(aTHX_ st);
void val(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_val(aTHX_ st);
void rowl(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
XSRETURN(fupg_st_rowl(aTHX_ st, ax));
void rowa(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_rowa(aTHX_ st);
void rowh(fupg_st *st)
CODE:
FUPG_ST_COOKIE;
ST(0) = fupg_st_rowh(aTHX_ st);
void DESTROY(fupg_st *st)