Is there public API to fetch errcode?

Started by Sergey Fukanchik3 months ago7 messages
#1Sergey Fukanchik
s.fukanchik@postgrespro.ru

Hi Postgres hackers,
ereport() can accept an error code. For example:
            ereport(FATAL,
                    (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
                     errmsg("number of requested standby connections
exceeds \"max_wal_senders\" (currently %d)",
                            max_wal_senders)));

In this case the error happens during connection initialization, outside
of an SQL query. I.e. PGresult is not available.

I suspect that the error code is available on the client as
PGconn->last_sqlstate however it is private and I can't find any public
API to fetch it.

Does libpq have an API to extract this code?

---

Sergey

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Sergey Fukanchik (#1)
Re: Is there public API to fetch errcode?

Sergey Fukanchik <s.fukanchik@postgrespro.ru> writes:

Does libpq have an API to extract this code?

PQresultErrorField(res, PG_DIAG_SQLSTATE) should do, no?

regards, tom lane

#3David G. Johnston
david.g.johnston@gmail.com
In reply to: Tom Lane (#2)
Re: Is there public API to fetch errcode?

On Sun, Oct 12, 2025 at 1:27 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Sergey Fukanchik <s.fukanchik@postgrespro.ru> writes:

Does libpq have an API to extract this code?

PQresultErrorField(res, PG_DIAG_SQLSTATE) should do, no?

I believe the call flow is the following - no "res"/result is ever
constructed:

PGconn *PQconnectdb(const char *conninfo);
ConnStatusType PQstatus(const PGconn *conn);
// Connection_Bad
char *PQerrorMessage(const PGconn *conn);
// Obtains the error message; but there seems to be no equivalent of
PQresultErrorField (e.g. PQconnErrorField) to obtain the SQLState field
component thereof

David J.

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: David G. Johnston (#3)
Re: Is there public API to fetch errcode?

"David G. Johnston" <david.g.johnston@gmail.com> writes:

On Sun, Oct 12, 2025 at 1:27 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

PQresultErrorField(res, PG_DIAG_SQLSTATE) should do, no?

I believe the call flow is the following - no "res"/result is ever
constructed:

Hmm ... no, we do construct a PGresult containing the error (including
SQLSTATE), because pqGetErrorNotice3 is what's used to read the
server's error response. But it looks like for a connection-time
failure, PQconnectPoll clears it before returning.

In principle maybe we could keep that around, allowing the application
to do PQgetResult from the failed connection object. Seems like it'd
be a bit of a mess though. Also, given all the logic that's there
to retry different server addresses etc, it's not clear which failure
result to preserve. We sidestep that question so far as the textual
PQerrorMessage output is concerned by concatenating all the failures,
but that's not workable for PGresults.

regards, tom lane

#5Sergey Fukanchik
s.fukanchik@postgrespro.ru
In reply to: Tom Lane (#4)
Re: Is there public API to fetch errcode?

sqlstate is saved into conn->last_sqlstate along with the error message
in pqGetErrorNotice3:

        if (id == PG_DIAG_SQLSTATE)
            strlcpy(conn->last_sqlstate, workBuf.data,
                    sizeof(conn->last_sqlstate));

is this usable? Can it be extracted somehow?

---

Sergey

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Sergey Fukanchik (#5)
Re: Is there public API to fetch errcode?

Sergey Fukanchik <s.fukanchik@postgrespro.ru> writes:

sqlstate is saved into conn->last_sqlstate along with the error message
in pqGetErrorNotice3:
        if (id == PG_DIAG_SQLSTATE)
            strlcpy(conn->last_sqlstate, workBuf.data,
                    sizeof(conn->last_sqlstate));
is this usable? Can it be extracted somehow?

It is not exposed, and if it were you'd have the same problem of lack
of context: you don't know which connection attempt set the value,
nor whether that's the most interesting failure.

If we wanted to up our game in this area, I'd envision making it
possible to extract a PGresult or PGresult-like structure for each
connection attempt that libpq made. It'd need to carry the connection
details (server address, encryption options, etc) as well as the
failure info. Not a trivial project, but doubtless do-able if
someone cared to put in the effort.

Of course, that just begs the question of what an application
would do with this data if it had it.

regards, tom lane

#7Sergey Fukanchik
s.fukanchik@postgrespro.ru
In reply to: Tom Lane (#6)
Re: Is there public API to fetch errcode?

So the difference between conn->errorMessage and conn->last_sqlstate is
that erorrMessage is appended and last_sqstate is overwritten.

And it seems that changing this is not easy.

As to why I want this - there are several reasons for connection to be
rejected, like ERRCODE_CANNOT_CONNECT_NOW, ERRCODE_TOO_MANY_CONNECTIONS,
ERRCODE_INSUFFICIENT_PRIVILEGE, ERRCODE_DATA_CORRUPTED etc

I would like my client to behave differently based on a particular
errcode - sometimes wait and retry, sometimes choose another server,
sometimes just fail.

It would be perfect if I could simply configure libpq to do such
reactions automatically for me, but designing this properly seems to be
even harder than exposing connection sqlstate.

SQLSTATE codes are locale independent and it would help a lot if I could
use them instead of relying on localized messages.

---

Sergey