Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e3161b2

Browse files
committed
Add libpq support for recreating an error message with different verbosity.
Often, upon getting an unexpected error in psql, one's first wish is that the verbosity setting had been higher; for example, to be able to see the schema-name field or the server code location info. Up to now the only way has been to adjust the VERBOSITY variable and repeat the failing query. That's a pain, and it doesn't work if the error isn't reproducible. This commit adds support in libpq for regenerating the error message for an existing error PGresult at any desired verbosity level. This is almost just a matter of refactoring the existing code into a subroutine, but there is one bit of possibly-needed information that was not getting put into PGresults: the text of the last query sent to the server. We must add that string to the contents of an error PGresult. But we only need to save it if it might be used, which with the existing error-formatting code only happens if there is a PG_DIAG_STATEMENT_POSITION error field, which is probably pretty rare for errors in production situations. So really the overhead when the feature isn't used should be negligible. Alex Shulgin, reviewed by Daniel Vérité, some improvements by me
1 parent 5a5b917 commit e3161b2

File tree

6 files changed

+217
-77
lines changed

6 files changed

+217
-77
lines changed

doc/src/sgml/libpq.sgml

+49-2
Original file line numberDiff line numberDiff line change
@@ -2691,6 +2691,48 @@ char *PQresultErrorMessage(const PGresult *res);
26912691
</listitem>
26922692
</varlistentry>
26932693

2694+
<varlistentry id="libpq-pqresultverboseerrormessage">
2695+
<term>
2696+
<function>PQresultVerboseErrorMessage</function>
2697+
<indexterm>
2698+
<primary>PQresultVerboseErrorMessage</primary>
2699+
</indexterm>
2700+
</term>
2701+
2702+
<listitem>
2703+
<para>
2704+
Returns a reformatted version of the error message associated with
2705+
a <structname>PGresult</> object.
2706+
<synopsis>
2707+
char *PQresultVerboseErrorMessage(const PGresult *res,
2708+
PGVerbosity verbosity,
2709+
PGContextVisibility show_context);
2710+
</synopsis>
2711+
In some situations a client might wish to obtain a more detailed
2712+
version of a previously-reported error.
2713+
<function>PQresultVerboseErrorMessage</function> addresses this need
2714+
by computing the message that would have been produced
2715+
by <function>PQresultErrorMessage</function> if the specified
2716+
verbosity settings had been in effect for the connection when the
2717+
given <structname>PGresult</> was generated. If
2718+
the <structname>PGresult</> is not an error result,
2719+
<quote>PGresult is not an error result</> is reported instead.
2720+
The returned string includes a trailing newline.
2721+
</para>
2722+
2723+
<para>
2724+
Unlike most other functions for extracting data from
2725+
a <structname>PGresult</>, the result of this function is a freshly
2726+
allocated string. The caller must free it
2727+
using <function>PQfreemem()</> when the string is no longer needed.
2728+
</para>
2729+
2730+
<para>
2731+
A NULL return is possible if there is insufficient memory.
2732+
</para>
2733+
</listitem>
2734+
</varlistentry>
2735+
26942736
<varlistentry id="libpq-pqresulterrorfield">
26952737
<term><function>PQresultErrorField</function><indexterm><primary>PQresultErrorField</></></term>
26962738
<listitem>
@@ -5582,6 +5624,8 @@ PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
55825624
mode includes all available fields. Changing the verbosity does not
55835625
affect the messages available from already-existing
55845626
<structname>PGresult</> objects, only subsequently-created ones.
5627+
(But see <function>PQresultVerboseErrorMessage</function> if you
5628+
want to print a previous error with a different verbosity.)
55855629
</para>
55865630
</listitem>
55875631
</varlistentry>
@@ -5622,6 +5666,8 @@ PGContextVisibility PQsetErrorContextVisibility(PGconn *conn, PGContextVisibilit
56225666
affect the messages available from
56235667
already-existing <structname>PGresult</> objects, only
56245668
subsequently-created ones.
5669+
(But see <function>PQresultVerboseErrorMessage</function> if you
5670+
want to print a previous error with a different display mode.)
56255671
</para>
56265672
</listitem>
56275673
</varlistentry>
@@ -6089,8 +6135,9 @@ PQsetNoticeProcessor(PGconn *conn,
60896135
receiver function is called. It is passed the message in the form of
60906136
a <symbol>PGRES_NONFATAL_ERROR</symbol>
60916137
<structname>PGresult</structname>. (This allows the receiver to extract
6092-
individual fields using <function>PQresultErrorField</>, or the complete
6093-
preformatted message using <function>PQresultErrorMessage</>.) The same
6138+
individual fields using <function>PQresultErrorField</>, or obtain a
6139+
complete preformatted message using <function>PQresultErrorMessage</>
6140+
or <function>PQresultVerboseErrorMessage</>.) The same
60946141
void pointer passed to <function>PQsetNoticeReceiver</function> is also
60956142
passed. (This pointer can be used to access application-specific state
60966143
if needed.)

src/interfaces/libpq/exports.txt

+1
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,4 @@ PQsslStruct 167
170170
PQsslAttributeNames 168
171171
PQsslAttribute 169
172172
PQsetErrorContextVisibility 170
173+
PQresultVerboseErrorMessage 171

src/interfaces/libpq/fe-exec.c

+39
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
159159
result->nEvents = 0;
160160
result->errMsg = NULL;
161161
result->errFields = NULL;
162+
result->errQuery = NULL;
162163
result->null_field[0] = '\0';
163164
result->curBlock = NULL;
164165
result->curOffset = 0;
@@ -2598,6 +2599,44 @@ PQresultErrorMessage(const PGresult *res)
25982599
return res->errMsg;
25992600
}
26002601

2602+
char *
2603+
PQresultVerboseErrorMessage(const PGresult *res,
2604+
PGVerbosity verbosity,
2605+
PGContextVisibility show_context)
2606+
{
2607+
PQExpBufferData workBuf;
2608+
2609+
/*
2610+
* Because the caller is expected to free the result string, we must
2611+
* strdup any constant result. We use plain strdup and document that
2612+
* callers should expect NULL if out-of-memory.
2613+
*/
2614+
if (!res ||
2615+
(res->resultStatus != PGRES_FATAL_ERROR &&
2616+
res->resultStatus != PGRES_NONFATAL_ERROR))
2617+
return strdup(libpq_gettext("PGresult is not an error result\n"));
2618+
2619+
initPQExpBuffer(&workBuf);
2620+
2621+
/*
2622+
* Currently, we pass this off to fe-protocol3.c in all cases; it will
2623+
* behave reasonably sanely with an error reported by fe-protocol2.c as
2624+
* well. If necessary, we could record the protocol version in PGresults
2625+
* so as to be able to invoke a version-specific message formatter, but
2626+
* for now there's no need.
2627+
*/
2628+
pqBuildErrorMessage3(&workBuf, res, verbosity, show_context);
2629+
2630+
/* If insufficient memory to format the message, fail cleanly */
2631+
if (PQExpBufferDataBroken(workBuf))
2632+
{
2633+
termPQExpBuffer(&workBuf);
2634+
return strdup(libpq_gettext("out of memory\n"));
2635+
}
2636+
2637+
return workBuf.data;
2638+
}
2639+
26012640
char *
26022641
PQresultErrorField(const PGresult *res, int fieldcode)
26032642
{

0 commit comments

Comments
 (0)