pg: More verbose error traces

Partly because some errors currently appeared to come from within FU::PG
itself, which is useless, and partly because it's common to wrap
database access methods, while that's exactly the kind of operation
where you *really* want to know where the error originated from.

(Source: too much time wasted debugging VNDB errors)
This commit is contained in:
Yorhel 2025-02-07 10:59:27 +01:00
parent 96aee880ce
commit 7c8473533d
4 changed files with 46 additions and 27 deletions

View file

@ -142,11 +142,11 @@ static fupg_conn *fupg_get_transaction(pTHX_ SV *sv) {
v = av_fetch(av, 1, 0);
if (!v || !*v) goto invalid;
if (!SvOK(*v)) croak("Invalid attempt to run a query on a transaction that has already finished");
if (c->cookie != SvUV(*v)) croak("Invalid cross-transaction operation");
if (!SvOK(*v)) fu_confess("Invalid attempt to run a query on a transaction that has already finished");
if (c->cookie != SvUV(*v)) fu_confess("Invalid cross-transaction operation");
return c;
invalid:
croak("invalid transaction object");
fu_confess("invalid transaction object");
}
/* Read a Perl value from a PGresult.
@ -196,7 +196,7 @@ static SV *fupg_q(pTHX_ fupg_conn *c, const char *query, I32 ax, I32 argc) {
static void fupg_st_prepare(pTHX_ fupg_st *st) {
if (st->describe) return;
if (st->prepared) croak("invalid attempt to re-prepare invalid statement");
if (st->prepared) fu_confess("invalid attempt to re-prepare invalid statement");
/* TODO: This is where we check for any cached prepared statements */
@ -253,7 +253,7 @@ static void fupg_st_check_dupcols(pTHX_ PGresult *r) {
int len = -strlen(key);
if (hv_exists(hv, key, len)) {
SvREFCNT_dec((SV *)hv);
croak("Query returns multiple columns with the same name ('%s')", key);
fu_confess("Query returns multiple columns with the same name ('%s')", key);
}
hv_store(hv, key, len, &PL_sv_yes, 0);
}
@ -264,7 +264,7 @@ static void fupg_st_execute(pTHX_ fupg_st *st) {
/* Disallow fetching the results more than once. I don't see a reason why
* someone would need that and disallowing it leaves room for fetching the
* results in a streaming fashion without breaking API compat. */
if (st->result) croak("Invalid attempt to execute statement multiple times");
if (st->result) fu_confess("Invalid attempt to execute statement multiple times");
/* TODO: prepare can be skipped when prepared statement caching is disabled and (text-format queries or no bind params) */
fupg_st_prepare(aTHX_ st);
@ -302,10 +302,10 @@ static SV *fupg_st_exec(pTHX_ fupg_st *st) {
static SV *fupg_st_val(pTHX_ fupg_st *st) {
fupg_st_prepare(aTHX_ st);
if (PQnfields(st->describe) > 1) croak("Invalid use of $st->val() on query returning more than one column");
if (PQnfields(st->describe) == 0) croak("Invalid use of $st->val() on query returning no data");
if (PQnfields(st->describe) > 1) fu_confess("Invalid use of $st->val() on query returning more than one column");
if (PQnfields(st->describe) == 0) fu_confess("Invalid use of $st->val() on query returning no data");
fupg_st_execute(aTHX_ st);
if (PQntuples(st->result) > 1) croak("Invalid use of $st->val() on query returning more than one row");
if (PQntuples(st->result) > 1) fu_confess("Invalid use of $st->val() on query returning more than one row");
SV *sv = PQntuples(st->result) == 0 ? newSV(0) : fupg_val(aTHX_ st->result, 0, 0);
return sv_2mortal(sv);
}
@ -313,8 +313,8 @@ static SV *fupg_st_val(pTHX_ fupg_st *st) {
static I32 fupg_st_rowl(pTHX_ fupg_st *st, I32 ax) {
dSP;
fupg_st_execute(aTHX_ st);
if (PQntuples(st->result) == 0) croak("Invalid use of $st->rowl() on query returning zero rows");
if (PQntuples(st->result) > 1) croak("Invalid use of $st->rowl() on query returning more than one row");
if (PQntuples(st->result) == 0) fu_confess("Invalid use of $st->rowl() on query returning zero rows");
if (PQntuples(st->result) > 1) fu_confess("Invalid use of $st->rowl() on query returning more than one row");
if (GIMME_V != G_LIST) {
ST(0) = sv_2mortal(newSViv(PQnfields(st->result)));
return 1;
@ -328,8 +328,8 @@ static I32 fupg_st_rowl(pTHX_ fupg_st *st, I32 ax) {
static SV *fupg_st_rowa(pTHX_ fupg_st *st) {
fupg_st_execute(aTHX_ st);
if (PQntuples(st->result) == 0) croak("Invalid use of $st->rowl() on query returning zero rows");
if (PQntuples(st->result) > 1) croak("Invalid use of $st->rowl() on query returning more than one row");
if (PQntuples(st->result) == 0) fu_confess("Invalid use of $st->rowl() on query returning zero rows");
if (PQntuples(st->result) > 1) fu_confess("Invalid use of $st->rowl() on query returning more than one row");
int i, nfields = PQnfields(st->result);
AV *av = newAV_alloc_x(nfields);
SV *sv = sv_2mortal(newRV_noinc((SV *)av));
@ -341,8 +341,8 @@ static SV *fupg_st_rowh(pTHX_ fupg_st *st) {
fupg_st_prepare(aTHX_ st);
fupg_st_check_dupcols(aTHX_ st->describe);
fupg_st_execute(aTHX_ st);
if (PQntuples(st->result) == 0) croak("Invalid use of $st->rowh() on query returning zero rows");
if (PQntuples(st->result) > 1) croak("Invalid use of $st->rowh() on query returning more than one row");
if (PQntuples(st->result) == 0) fu_confess("Invalid use of $st->rowh() on query returning zero rows");
if (PQntuples(st->result) > 1) fu_confess("Invalid use of $st->rowh() on query returning more than one row");
int i, nfields = PQnfields(st->result);
HV *hv = newHV();
SV *sv = sv_2mortal(newRV_noinc((SV *)hv));