mirror of
https://github.com/postgres/postgres.git
synced 2025-04-29 13:56:47 +03:00
Add a "SQLSTATE-only" error verbosity option to libpq and psql.
This is intended for use mostly in test scripts for external tools, which could do without cross-PG-version variations in error message wording. Of course, the SQLSTATE isn't guaranteed stable either, but it should be more so than the error message text. Note: there's a bit of an ABI change for libpq here, but it seems OK because if somebody compiles against a newer version of libpq-fe.h, and then tries to pass PQERRORS_SQLSTATE to PQsetErrorVerbosity() of an older libpq library, it will be accepted and then act like PQERRORS_DEFAULT, thanks to the way the tests in pqBuildErrorMessage3 have historically been phrased. That seems acceptable. Didier Gautheron, reviewed by Dagfinn Ilmari Mannsåker Discussion: https://postgr.es/m/CAJRYxuKyj4zA+JGVrtx8OWAuBfE-_wN4sUMK4H49EuPed=mOBw@mail.gmail.com
This commit is contained in:
parent
413ccaa74d
commit
7bac3acab4
@ -6014,21 +6014,30 @@ typedef enum
|
|||||||
{
|
{
|
||||||
PQERRORS_TERSE,
|
PQERRORS_TERSE,
|
||||||
PQERRORS_DEFAULT,
|
PQERRORS_DEFAULT,
|
||||||
PQERRORS_VERBOSE
|
PQERRORS_VERBOSE,
|
||||||
|
PQERRORS_SQLSTATE
|
||||||
} PGVerbosity;
|
} PGVerbosity;
|
||||||
|
|
||||||
PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
|
PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
<function>PQsetErrorVerbosity</function> sets the verbosity mode, returning
|
<function>PQsetErrorVerbosity</function> sets the verbosity mode,
|
||||||
the connection's previous setting. In <firstterm>TERSE</firstterm> mode,
|
returning the connection's previous setting.
|
||||||
returned messages include severity, primary text, and position only;
|
In <firstterm>TERSE</firstterm> mode, returned messages include
|
||||||
this will normally fit on a single line. The default mode produces
|
severity, primary text, and position only; this will normally fit on a
|
||||||
messages that include the above plus any detail, hint, or context
|
single line. The default mode produces messages that include the above
|
||||||
fields (these might span multiple lines). The <firstterm>VERBOSE</firstterm>
|
plus any detail, hint, or context fields (these might span multiple
|
||||||
mode includes all available fields. Changing the verbosity does not
|
lines). The <firstterm>VERBOSE</firstterm> mode includes all available
|
||||||
affect the messages available from already-existing
|
fields. The <firstterm>SQLSTATE</firstterm> mode includes only the
|
||||||
<structname>PGresult</structname> objects, only subsequently-created ones.
|
error severity and the <symbol>SQLSTATE</symbol> error code, if one is
|
||||||
|
available (if not, the output is like <firstterm>TERSE</firstterm>
|
||||||
|
mode).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Changing the verbosity setting does not affect the messages available
|
||||||
|
from already-existing <structname>PGresult</structname> objects, only
|
||||||
|
subsequently-created ones.
|
||||||
(But see <function>PQresultVerboseErrorMessage</function> if you
|
(But see <function>PQresultVerboseErrorMessage</function> if you
|
||||||
want to print a previous error with a different verbosity.)
|
want to print a previous error with a different verbosity.)
|
||||||
</para>
|
</para>
|
||||||
@ -6061,13 +6070,19 @@ PGContextVisibility PQsetErrorContextVisibility(PGconn *conn, PGContextVisibilit
|
|||||||
|
|
||||||
<function>PQsetErrorContextVisibility</function> sets the context display mode,
|
<function>PQsetErrorContextVisibility</function> sets the context display mode,
|
||||||
returning the connection's previous setting. This mode controls
|
returning the connection's previous setting. This mode controls
|
||||||
whether the <literal>CONTEXT</literal> field is included in messages
|
whether the <literal>CONTEXT</literal> field is included in messages.
|
||||||
(unless the verbosity setting is <firstterm>TERSE</firstterm>, in which
|
The <firstterm>NEVER</firstterm> mode
|
||||||
case <literal>CONTEXT</literal> is never shown). The <firstterm>NEVER</firstterm> mode
|
|
||||||
never includes <literal>CONTEXT</literal>, while <firstterm>ALWAYS</firstterm> always
|
never includes <literal>CONTEXT</literal>, while <firstterm>ALWAYS</firstterm> always
|
||||||
includes it if available. In <firstterm>ERRORS</firstterm> mode (the
|
includes it if available. In <firstterm>ERRORS</firstterm> mode (the
|
||||||
default), <literal>CONTEXT</literal> fields are included only for error
|
default), <literal>CONTEXT</literal> fields are included only in error
|
||||||
messages, not for notices and warnings. Changing this mode does not
|
messages, not in notices and warnings.
|
||||||
|
(However, if the verbosity setting is <firstterm>TERSE</firstterm>
|
||||||
|
or <firstterm>SQLSTATE</firstterm>, <literal>CONTEXT</literal> fields
|
||||||
|
are omitted regardless of the context display mode.)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Changing this mode does not
|
||||||
affect the messages available from
|
affect the messages available from
|
||||||
already-existing <structname>PGresult</structname> objects, only
|
already-existing <structname>PGresult</structname> objects, only
|
||||||
subsequently-created ones.
|
subsequently-created ones.
|
||||||
|
@ -3892,7 +3892,8 @@ bar
|
|||||||
messages from the server. The default is <literal>errors</literal> (meaning
|
messages from the server. The default is <literal>errors</literal> (meaning
|
||||||
that context will be shown in error messages, but not in notice or
|
that context will be shown in error messages, but not in notice or
|
||||||
warning messages). This setting has no effect
|
warning messages). This setting has no effect
|
||||||
when <varname>VERBOSITY</varname> is set to <literal>terse</literal>.
|
when <varname>VERBOSITY</varname> is set to <literal>terse</literal>
|
||||||
|
or <literal>sqlstate</literal>.
|
||||||
(See also <command>\errverbose</command>, for use when you want a verbose
|
(See also <command>\errverbose</command>, for use when you want a verbose
|
||||||
version of the error you just got.)
|
version of the error you just got.)
|
||||||
</para>
|
</para>
|
||||||
@ -3946,8 +3947,9 @@ bar
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
This variable can be set to the values <literal>default</literal>,
|
This variable can be set to the values <literal>default</literal>,
|
||||||
<literal>verbose</literal>, or <literal>terse</literal> to control the verbosity
|
<literal>verbose</literal>, <literal>terse</literal>,
|
||||||
of error reports.
|
or <literal>sqlstate</literal> to control the verbosity of error
|
||||||
|
reports.
|
||||||
(See also <command>\errverbose</command>, for use when you want a verbose
|
(See also <command>\errverbose</command>, for use when you want a verbose
|
||||||
version of the error you just got.)
|
version of the error you just got.)
|
||||||
</para>
|
</para>
|
||||||
|
@ -340,7 +340,7 @@ helpVariables(unsigned short int pager)
|
|||||||
* Windows builds currently print one more line than non-Windows builds.
|
* Windows builds currently print one more line than non-Windows builds.
|
||||||
* Using the larger number is fine.
|
* Using the larger number is fine.
|
||||||
*/
|
*/
|
||||||
output = PageOutput(156, pager ? &(pset.popt.topt) : NULL);
|
output = PageOutput(158, pager ? &(pset.popt.topt) : NULL);
|
||||||
|
|
||||||
fprintf(output, _("List of specially treated variables\n\n"));
|
fprintf(output, _("List of specially treated variables\n\n"));
|
||||||
|
|
||||||
@ -414,7 +414,7 @@ helpVariables(unsigned short int pager)
|
|||||||
fprintf(output, _(" USER\n"
|
fprintf(output, _(" USER\n"
|
||||||
" the currently connected database user\n"));
|
" the currently connected database user\n"));
|
||||||
fprintf(output, _(" VERBOSITY\n"
|
fprintf(output, _(" VERBOSITY\n"
|
||||||
" controls verbosity of error reports [default, verbose, terse]\n"));
|
" controls verbosity of error reports [default, verbose, terse, sqlstate]\n"));
|
||||||
fprintf(output, _(" VERSION\n"
|
fprintf(output, _(" VERSION\n"
|
||||||
" VERSION_NAME\n"
|
" VERSION_NAME\n"
|
||||||
" VERSION_NUM\n"
|
" VERSION_NUM\n"
|
||||||
|
@ -1110,13 +1110,15 @@ verbosity_hook(const char *newval)
|
|||||||
Assert(newval != NULL); /* else substitute hook messed up */
|
Assert(newval != NULL); /* else substitute hook messed up */
|
||||||
if (pg_strcasecmp(newval, "default") == 0)
|
if (pg_strcasecmp(newval, "default") == 0)
|
||||||
pset.verbosity = PQERRORS_DEFAULT;
|
pset.verbosity = PQERRORS_DEFAULT;
|
||||||
else if (pg_strcasecmp(newval, "terse") == 0)
|
|
||||||
pset.verbosity = PQERRORS_TERSE;
|
|
||||||
else if (pg_strcasecmp(newval, "verbose") == 0)
|
else if (pg_strcasecmp(newval, "verbose") == 0)
|
||||||
pset.verbosity = PQERRORS_VERBOSE;
|
pset.verbosity = PQERRORS_VERBOSE;
|
||||||
|
else if (pg_strcasecmp(newval, "terse") == 0)
|
||||||
|
pset.verbosity = PQERRORS_TERSE;
|
||||||
|
else if (pg_strcasecmp(newval, "sqlstate") == 0)
|
||||||
|
pset.verbosity = PQERRORS_SQLSTATE;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PsqlVarEnumError("VERBOSITY", newval, "default, terse, verbose");
|
PsqlVarEnumError("VERBOSITY", newval, "default, verbose, terse, sqlstate");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3652,7 +3652,7 @@ psql_completion(const char *text, int start, int end)
|
|||||||
else if (TailMatchesCS("SHOW_CONTEXT"))
|
else if (TailMatchesCS("SHOW_CONTEXT"))
|
||||||
COMPLETE_WITH_CS("never", "errors", "always");
|
COMPLETE_WITH_CS("never", "errors", "always");
|
||||||
else if (TailMatchesCS("VERBOSITY"))
|
else if (TailMatchesCS("VERBOSITY"))
|
||||||
COMPLETE_WITH_CS("default", "verbose", "terse");
|
COMPLETE_WITH_CS("default", "verbose", "terse", "sqlstate");
|
||||||
}
|
}
|
||||||
else if (TailMatchesCS("\\sf*"))
|
else if (TailMatchesCS("\\sf*"))
|
||||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_routines, NULL);
|
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_routines, NULL);
|
||||||
|
@ -1017,6 +1017,24 @@ pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res,
|
|||||||
val = PQresultErrorField(res, PG_DIAG_SEVERITY);
|
val = PQresultErrorField(res, PG_DIAG_SEVERITY);
|
||||||
if (val)
|
if (val)
|
||||||
appendPQExpBuffer(msg, "%s: ", val);
|
appendPQExpBuffer(msg, "%s: ", val);
|
||||||
|
|
||||||
|
if (verbosity == PQERRORS_SQLSTATE)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If we have a SQLSTATE, print that and nothing else. If not (which
|
||||||
|
* shouldn't happen for server-generated errors, but might possibly
|
||||||
|
* happen for libpq-generated ones), fall back to TERSE format, as
|
||||||
|
* that seems better than printing nothing at all.
|
||||||
|
*/
|
||||||
|
val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(msg, "%s\n", val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verbosity = PQERRORS_TERSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (verbosity == PQERRORS_VERBOSE)
|
if (verbosity == PQERRORS_VERBOSE)
|
||||||
{
|
{
|
||||||
val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
|
val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
|
||||||
|
@ -112,7 +112,8 @@ typedef enum
|
|||||||
{
|
{
|
||||||
PQERRORS_TERSE, /* single-line error messages */
|
PQERRORS_TERSE, /* single-line error messages */
|
||||||
PQERRORS_DEFAULT, /* recommended style */
|
PQERRORS_DEFAULT, /* recommended style */
|
||||||
PQERRORS_VERBOSE /* all the facts, ma'am */
|
PQERRORS_VERBOSE, /* all the facts, ma'am */
|
||||||
|
PQERRORS_SQLSTATE /* only error severity and SQLSTATE code */
|
||||||
} PGVerbosity;
|
} PGVerbosity;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -4491,6 +4491,26 @@ number of rows: 0
|
|||||||
last error message: table "this_table_does_not_exist" does not exist
|
last error message: table "this_table_does_not_exist" does not exist
|
||||||
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
||||||
last error code: 42P01
|
last error code: 42P01
|
||||||
|
-- nondefault verbosity error settings (except verbose, which is too unstable)
|
||||||
|
\set VERBOSITY terse
|
||||||
|
SELECT 1 UNION;
|
||||||
|
ERROR: syntax error at or near ";" at character 15
|
||||||
|
\echo 'error:' :ERROR
|
||||||
|
error: true
|
||||||
|
\echo 'error code:' :SQLSTATE
|
||||||
|
error code: 42601
|
||||||
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
||||||
|
last error message: syntax error at or near ";"
|
||||||
|
\set VERBOSITY sqlstate
|
||||||
|
SELECT 1/0;
|
||||||
|
ERROR: 22012
|
||||||
|
\echo 'error:' :ERROR
|
||||||
|
error: true
|
||||||
|
\echo 'error code:' :SQLSTATE
|
||||||
|
error code: 22012
|
||||||
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
||||||
|
last error message: division by zero
|
||||||
|
\set VERBOSITY default
|
||||||
-- working \gdesc
|
-- working \gdesc
|
||||||
SELECT 3 AS three, 4 AS four \gdesc
|
SELECT 3 AS three, 4 AS four \gdesc
|
||||||
Column | Type
|
Column | Type
|
||||||
|
@ -1001,6 +1001,21 @@ DROP TABLE this_table_does_not_exist;
|
|||||||
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
||||||
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
\echo 'last error code:' :LAST_ERROR_SQLSTATE
|
||||||
|
|
||||||
|
-- nondefault verbosity error settings (except verbose, which is too unstable)
|
||||||
|
\set VERBOSITY terse
|
||||||
|
SELECT 1 UNION;
|
||||||
|
\echo 'error:' :ERROR
|
||||||
|
\echo 'error code:' :SQLSTATE
|
||||||
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
||||||
|
|
||||||
|
\set VERBOSITY sqlstate
|
||||||
|
SELECT 1/0;
|
||||||
|
\echo 'error:' :ERROR
|
||||||
|
\echo 'error code:' :SQLSTATE
|
||||||
|
\echo 'last error message:' :LAST_ERROR_MESSAGE
|
||||||
|
|
||||||
|
\set VERBOSITY default
|
||||||
|
|
||||||
-- working \gdesc
|
-- working \gdesc
|
||||||
SELECT 3 AS three, 4 AS four \gdesc
|
SELECT 3 AS three, 4 AS four \gdesc
|
||||||
\echo 'error:' :ERROR
|
\echo 'error:' :ERROR
|
||||||
|
Loading…
x
Reference in New Issue
Block a user