+
+
+ PQresultVerboseErrorMessage
+
+
PQresultVerboseErrorMessage
+
+
+
+
+ Returns a reformatted version of the error message associated with
+ a PGresult> object.
+
+char *PQresultVerboseErrorMessage(const PGresult *res,
+ PGVerbosity verbosity,
+ PGContextVisibility show_context);
+
+ In some situations a client might wish to obtain a more detailed
+ version of a previously-reported error.
+ PQresultVerboseErrorMessage addresses this need
+ by computing the message that would have been produced
+ by PQresultErrorMessage if the specified
+ verbosity settings had been in effect for the connection when the
+ given PGresult> was generated. If
+ the PGresult> is not an error result,
+ PGresult is not an error result> is reported instead.
+ The returned string includes a trailing newline.
+
+
+ Unlike most other functions for extracting data from
+ a PGresult>, the result of this function is a freshly
+ allocated string. The caller must free it
+ using PQfreemem()> when the string is no longer needed.
+
+
+ A NULL return is possible if there is insufficient memory.
+
+
+
+
PQresultErrorFieldPQresultErrorField>>
mode includes all available fields. Changing the verbosity does not
affect the messages available from already-existing
PGresult> objects, only subsequently-created ones.
+ (But see PQresultVerboseErrorMessage if you
+ want to print a previous error with a different verbosity.)
affect the messages available from
already-existing PGresult> objects, only
subsequently-created ones.
+ (But see PQresultVerboseErrorMessage if you
+ want to print a previous error with a different display mode.)
receiver function is called. It is passed the message in the form of
a PGRES_NONFATAL_ERROR
PGresult. (This allows the receiver to extract
- individual fields using PQresultErrorField>, or the complete
- preformatted message using PQresultErrorMessage>.) The same
+ individual fields using PQresultErrorField>, or obtain a
+ complete preformatted message using PQresultErrorMessage>
+ or PQresultVerboseErrorMessage>.) The same
void pointer passed to PQsetNoticeReceiver is also
passed. (This pointer can be used to access application-specific state
if needed.)
pqGetErrorNotice3(PGconn *conn, bool isError)
{
PGresult *res = NULL;
+ bool have_position = false;
PQExpBufferData workBuf;
char id;
- const char *val;
- const char *querytext = NULL;
- int querypos = 0;
/*
* Since the fields might be pretty long, we create a temporary
/*
* Read the fields and save into res.
+ *
+ * While at it, save the SQLSTATE in conn->last_sqlstate, and note whether
+ * we saw a PG_DIAG_STATEMENT_POSITION field.
*/
for (;;)
{
if (pqGets(&workBuf, conn))
goto fail;
pqSaveMessageField(res, id, workBuf.data);
+ if (id == PG_DIAG_SQLSTATE)
+ strlcpy(conn->last_sqlstate, workBuf.data,
+ sizeof(conn->last_sqlstate));
+ else if (id == PG_DIAG_STATEMENT_POSITION)
+ have_position = true;
}
+ /*
+ * Save the active query text, if any, into res as well; but only if we
+ * might need it for an error cursor display, which is only true if there
+ * is a PG_DIAG_STATEMENT_POSITION field.
+ */
+ if (have_position && conn->last_query && res)
+ res->errQuery = pqResultStrdup(res, conn->last_query);
+
/*
* Now build the "overall" error message for PQresultErrorMessage.
- *
- * Also, save the SQLSTATE in conn->last_sqlstate.
*/
resetPQExpBuffer(&workBuf);
+ pqBuildErrorMessage3(&workBuf, res, conn->verbosity, conn->show_context);
+
+ /*
+ * Either save error as current async result, or just emit the notice.
+ */
+ if (isError)
+ {
+ if (res)
+ res->errMsg = pqResultStrdup(res, workBuf.data);
+ pqClearAsyncResult(conn);
+ conn->result = res;
+ if (PQExpBufferDataBroken(workBuf))
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("out of memory"));
+ else
+ appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
+ }
+ else
+ {
+ /* if we couldn't allocate the result set, just discard the NOTICE */
+ if (res)
+ {
+ /* We can cheat a little here and not copy the message. */
+ res->errMsg = workBuf.data;
+ if (res->noticeHooks.noticeRec != NULL)
+ (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
+ PQclear(res);
+ }
+ }
+
+ termPQExpBuffer(&workBuf);
+ return 0;
+
+fail:
+ PQclear(res);
+ termPQExpBuffer(&workBuf);
+ return EOF;
+}
+
+/*
+ * Construct an error message from the fields in the given PGresult,
+ * appending it to the contents of "msg".
+ */
+void
+pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res,
+ PGVerbosity verbosity, PGContextVisibility show_context)
+{
+ const char *val;
+ const char *querytext = NULL;
+ int querypos = 0;
+
+ /* If we couldn't allocate a PGresult, just say "out of memory" */
+ if (res == NULL)
+ {
+ appendPQExpBuffer(msg, libpq_gettext("out of memory\n"));
+ return;
+ }
+
+ /*
+ * If we don't have any broken-down fields, just return the base message.
+ * This mainly applies if we're given a libpq-generated error result.
+ */
+ if (res->errFields == NULL)
+ {
+ if (res->errMsg && res->errMsg[0])
+ appendPQExpBufferStr(msg, res->errMsg);
+ else
+ appendPQExpBuffer(msg, libpq_gettext("no error message available\n"));
+ return;
+ }
+
+ /* Else build error message from relevant fields */
val = PQresultErrorField(res, PG_DIAG_SEVERITY);
if (val)
- appendPQExpBuffer(&workBuf, "%s: ", val);
- val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
- if (val)
+ appendPQExpBuffer(msg, "%s: ", val);
+ if (verbosity == PQERRORS_VERBOSE)
{
- if (strlen(val) < sizeof(conn->last_sqlstate))
- strcpy(conn->last_sqlstate, val);
- if (conn->verbosity == PQERRORS_VERBOSE)
- appendPQExpBuffer(&workBuf, "%s: ", val);
+ val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+ if (val)
+ appendPQExpBuffer(msg, "%s: ", val);
}
val = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
if (val)
- appendPQExpBufferStr(&workBuf, val);
+ appendPQExpBufferStr(msg, val);
val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION);
if (val)
{
- if (conn->verbosity != PQERRORS_TERSE && conn->last_query != NULL)
+ if (verbosity != PQERRORS_TERSE && res->errQuery != NULL)
{
/* emit position as a syntax cursor display */
- querytext = conn->last_query;
+ querytext = res->errQuery;
querypos = atoi(val);
}
else
{
/* emit position as text addition to primary message */
/* translator: %s represents a digit string */
- appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
+ appendPQExpBuffer(msg, libpq_gettext(" at character %s"),
val);
}
}
if (val)
{
querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
- if (conn->verbosity != PQERRORS_TERSE && querytext != NULL)
+ if (verbosity != PQERRORS_TERSE && querytext != NULL)
{
/* emit position as a syntax cursor display */
querypos = atoi(val);
{
/* emit position as text addition to primary message */
/* translator: %s represents a digit string */
- appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
+ appendPQExpBuffer(msg, libpq_gettext(" at character %s"),
val);
}
}
}
- appendPQExpBufferChar(&workBuf, '\n');
- if (conn->verbosity != PQERRORS_TERSE)
+ appendPQExpBufferChar(msg, '\n');
+ if (verbosity != PQERRORS_TERSE)
{
if (querytext && querypos > 0)
- reportErrorPosition(&workBuf, querytext, querypos,
- conn->client_encoding);
+ reportErrorPosition(msg, querytext, querypos,
+ res->client_encoding);
val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
if (val)
- appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL: %s\n"), val);
+ appendPQExpBuffer(msg, libpq_gettext("DETAIL: %s\n"), val);
val = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
if (val)
- appendPQExpBuffer(&workBuf, libpq_gettext("HINT: %s\n"), val);
+ appendPQExpBuffer(msg, libpq_gettext("HINT: %s\n"), val);
val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
if (val)
- appendPQExpBuffer(&workBuf, libpq_gettext("QUERY: %s\n"), val);
- if (conn->show_context == PQSHOW_CONTEXT_ALWAYS ||
- (conn->show_context == PQSHOW_CONTEXT_ERRORS && isError))
+ appendPQExpBuffer(msg, libpq_gettext("QUERY: %s\n"), val);
+ if (show_context == PQSHOW_CONTEXT_ALWAYS ||
+ (show_context == PQSHOW_CONTEXT_ERRORS &&
+ res->resultStatus == PGRES_FATAL_ERROR))
{
val = PQresultErrorField(res, PG_DIAG_CONTEXT);
if (val)
- appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT: %s\n"),
+ appendPQExpBuffer(msg, libpq_gettext("CONTEXT: %s\n"),
val);
}
}
- if (conn->verbosity == PQERRORS_VERBOSE)
+ if (verbosity == PQERRORS_VERBOSE)
{
val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME);
if (val)
- appendPQExpBuffer(&workBuf,
+ appendPQExpBuffer(msg,
libpq_gettext("SCHEMA NAME: %s\n"), val);
val = PQresultErrorField(res, PG_DIAG_TABLE_NAME);
if (val)
- appendPQExpBuffer(&workBuf,
+ appendPQExpBuffer(msg,
libpq_gettext("TABLE NAME: %s\n"), val);
val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME);
if (val)
- appendPQExpBuffer(&workBuf,
+ appendPQExpBuffer(msg,
libpq_gettext("COLUMN NAME: %s\n"), val);
val = PQresultErrorField(res, PG_DIAG_DATATYPE_NAME);
if (val)
- appendPQExpBuffer(&workBuf,
+ appendPQExpBuffer(msg,
libpq_gettext("DATATYPE NAME: %s\n"), val);
val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME);
if (val)
- appendPQExpBuffer(&workBuf,
+ appendPQExpBuffer(msg,
libpq_gettext("CONSTRAINT NAME: %s\n"), val);
}
- if (conn->verbosity == PQERRORS_VERBOSE)
+ if (verbosity == PQERRORS_VERBOSE)
{
const char *valf;
const char *vall;
val = PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION);
if (val || valf || vall)
{
- appendPQExpBufferStr(&workBuf, libpq_gettext("LOCATION: "));
+ appendPQExpBufferStr(msg, libpq_gettext("LOCATION: "));
if (val)
- appendPQExpBuffer(&workBuf, libpq_gettext("%s, "), val);
+ appendPQExpBuffer(msg, libpq_gettext("%s, "), val);
if (valf && vall) /* unlikely we'd have just one */
- appendPQExpBuffer(&workBuf, libpq_gettext("%s:%s"),
+ appendPQExpBuffer(msg, libpq_gettext("%s:%s"),
valf, vall);
- appendPQExpBufferChar(&workBuf, '\n');
+ appendPQExpBufferChar(msg, '\n');
}
}
-
- /*
- * Either save error as current async result, or just emit the notice.
- */
- if (isError)
- {
- if (res)
- res->errMsg = pqResultStrdup(res, workBuf.data);
- pqClearAsyncResult(conn);
- conn->result = res;
- if (PQExpBufferDataBroken(workBuf))
- printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("out of memory"));
- else
- appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
- }
- else
- {
- /* if we couldn't allocate the result set, just discard the NOTICE */
- if (res)
- {
- /* We can cheat a little here and not copy the message. */
- res->errMsg = workBuf.data;
- if (res->noticeHooks.noticeRec != NULL)
- (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
- PQclear(res);
- }
- }
-
- termPQExpBuffer(&workBuf);
- return 0;
-
-fail:
- PQclear(res);
- termPQExpBuffer(&workBuf);
- return EOF;
}
/*