Hi,
This patch gives the end user control over psql's
error stream. This allows a single psql session
to use \o to send both errors and table output
to multiple files. Useful when capturing test output, etc.
Control is provided via a new "estream" \pset. Here's
the docs.
-------------------------<snip>------------------------
estream
Controls the output stream(s) used to report error messages. Value
must be one of: stderr (the default), which sends errors to the
standard error stream; query, which injects error messages into the
query result output stream; or both, which sends errors to both output
streams. "Error messages" are comprised of errors from psql and notice
messages and errors from the database server.
-------------------------<snip>------------------------
Against head.
psql-estream.patch The patch.
psql-estream_test.patch Adds a regression test to test the patch.
There's a number of problems with psql-estream_test.patch,
the most notable is that it probably won't work on
MS Windows because it uses /dev/null to avoid touching the
host filesystem. I'm not sure whether this should have
a regression test and if so what the right way is to do it.
Note that psql-stream.patch includes some re-writing of
the docs for the psql \o option that goes slightly beyond
the minimum change required to explain \pset estream's effects.
Regards,
Karl <[email protected]>
Free Software: "You don't pay back, you pay forward."
-- Robert A. Heinlein
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index c41593c..695739e 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1800,11 +1800,16 @@ lo_import 152801
specified, the query output will be reset to the standard output.
</para>
- <para><quote>Query results</quote> includes all tables, command
- responses, and notices obtained from the database server, as
- well as output of various backslash commands that query the
- database (such as <command>\d</command>), but not error
- messages.
+ <para><quote>Query results</quote> includes all tables, sql
+ command responses and status information, notifications from
+ <command>LISTEN</command>, and output of various backslash
+ commands that query the database (such as
+ <command>\d</command>). <quote>Query results</quote> do not
+ include errors from <application>psql</application>or notice
+ messages or errors from the database server unless
+ <command>\pset estream</command> is used. Nor do they include
+ output of backslash commands which do not query the database
+ (such as <command>\h</command>).
</para>
<tip>
@@ -1863,16 +1868,18 @@ lo_import 152801
<listitem>
<para>
- This command sets options affecting the output of query result tables.
- <replaceable class="parameter">option</replaceable>
- indicates which option is to be set. The semantics of
- <replaceable class="parameter">value</replaceable> vary depending
- on the selected option. For some options, omitting <replaceable
- class="parameter">value</replaceable> causes the option to be toggled
- or unset, as described under the particular option. If no such
- behavior is mentioned, then omitting
- <replaceable class="parameter">value</replaceable> just results in
- the current setting being displayed.
+ This command sets options affecting the output of errors and
+ query results. There are extensive options regarding table
+ formatting. <replaceable
+ class="parameter">option</replaceable> indicates which option
+ is to be set. The semantics of <replaceable
+ class="parameter">value</replaceable> vary depending on the
+ selected option. For some options, omitting <replaceable
+ class="parameter">value</replaceable> causes the option to be
+ toggled or unset, as described under the particular option.
+ If no such behavior is mentioned, then omitting <replaceable
+ class="parameter">value</replaceable> just results in the
+ current setting being displayed.
</para>
<para>
@@ -1914,6 +1921,24 @@ lo_import 152801
</varlistentry>
<varlistentry>
+ <term><literal>estream</literal></term>
+ <listitem>
+ <para>
+ Controls the output stream(s) used to report error messages.
+ <replaceable class="parameter">Value</replaceable> must be
+ one of: <literal>stderr</literal> (the default), which sends
+ errors to the standard error stream;
+ <literal>query</literal>, which injects error messages into
+ the query result output stream; or <literal>both</literal>,
+ which sends errors to both output streams. <quote>Error
+ messages</quote> are comprised of errors from
+ <application>psql</application> and notice messages and
+ errors from the database server.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><literal>expanded</literal> (or <literal>x</literal>)</term>
<listitem>
<para>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 8ccd00d..454a4b9 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -2448,6 +2448,32 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
printf(_("Target width is %d.\n"), popt->topt.columns);
}
+ /* set error output stream */
+ else if (strcmp(param, "estream") == 0)
+ {
+ if (!value)
+ ;
+ else if (pg_strncasecmp("stderr", value, vallen) == 0)
+ pset.estream = PSQL_ESTREAM_STDERR;
+ else if (pg_strncasecmp("query", value, vallen) == 0)
+ pset.estream = PSQL_ESTREAM_QUERY;
+ else if (pg_strncasecmp("both", value, vallen) == 0)
+ pset.estream = PSQL_ESTREAM_BOTH;
+ else
+ {
+ psql_error("\\pset: allowed estream values are stderr, query, both\n");
+ return false;
+ }
+
+ if (!quiet)
+ if (pset.estream == PSQL_ESTREAM_STDERR)
+ puts(_("Errors sent to stderr."));
+ else if (pset.estream == PSQL_ESTREAM_QUERY)
+ puts(_("Errors injected into query output."));
+ else
+ puts(_("Errors sent to stderr and injected into query output."));
+ }
+
else
{
psql_error("\\pset: unknown option: %s\n", param);
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 179c162..6183064 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -153,10 +153,19 @@ psql_error(const char *fmt,...)
if (pset.queryFout && pset.queryFout != stdout)
fflush(pset.queryFout);
- if (pset.inputfile)
- fprintf(stderr, "%s:%s:" UINT64_FORMAT ": ", pset.progname, pset.inputfile, pset.lineno);
+ if (pset.inputfile) {
+ if (pset.estream != PSQL_ESTREAM_QUERY)
+ fprintf(stderr, "%s:%s:" UINT64_FORMAT ": ",
+ pset.progname, pset.inputfile, pset.lineno);
+ if (pset.estream != PSQL_ESTREAM_STDERR)
+ fprintf(pset.queryFout, "%s:%s:" UINT64_FORMAT ": ",
+ pset.progname, pset.inputfile, pset.lineno);
+ }
va_start(ap, fmt);
- vfprintf(stderr, _(fmt), ap);
+ if (pset.estream != PSQL_ESTREAM_QUERY)
+ vfprintf(stderr, _(fmt), ap);
+ if (pset.estream != PSQL_ESTREAM_STDERR)
+ vfprintf(pset.queryFout, _(fmt), ap);
va_end(ap);
}
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index c907fa0..5efb782 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -63,12 +63,20 @@ enum trivalue
TRI_YES
};
+typedef enum
+{
+ PSQL_ESTREAM_STDERR,
+ PSQL_ESTREAM_QUERY,
+ PSQL_ESTREAM_BOTH
+} PSQL_ESTREAM;
+
typedef struct _psqlSettings
{
PGconn *db; /* connection to backend */
int encoding; /* client_encoding */
FILE *queryFout; /* where to send the query results */
bool queryFoutPipe; /* queryFout is from a popen() */
+ PSQL_ESTREAM estream; /* where to send errors */
printQueryOpt popt;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 1fcc47f..bd91025 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -120,6 +120,7 @@ main(int argc, char *argv[])
pset.encoding = PQenv2encoding();
pset.queryFout = stdout;
pset.queryFoutPipe = false;
+ pset.estream = PSQL_ESTREAM_STDERR;
pset.cur_cmd_source = stdin;
pset.cur_cmd_interactive = false;
diff --git a/src/test/regress/expected/estream.out b/src/test/regress/expected/estream.out
new file mode 100644
index 0000000..1461aed
--- /dev/null
+++ b/src/test/regress/expected/estream.out
@@ -0,0 +1,40 @@
+--
+-- Test of psql's \pset estream parameter.
+-- Don't use an actual table name since we might be running in parallel.
+--
+-- Bugs:
+-- o Uses /dev/null, which probably breaks on non-Unix boxes.
+-- o Due to the nature of the test framework, never looks at
+-- what's saved to the output file. Instead tests what's
+-- missing from stdout/stderr.
+--
+\o /dev/null
+-- This should not send an error into the output file, but
+-- should send it to stderr.
+select * from f oo;
+ERROR: relation "f" does not exist
+LINE 1: select * from f oo;
+ ^
+-- This should send an error into the output file, but not stderr.
+\pset estream query
+select * from f oo;
+-- This should send an error both places.
+\pset estream both
+select * from f oo;
+ERROR: relation "f" does not exist
+LINE 1: select * from f oo;
+ ^
+-- And this should return to the initial (default) setting,
+-- not send an error to the output file but do send it
+-- to stderr.
+\pset estream stderr
+select * from f oo;
+ERROR: relation "f" does not exist
+LINE 1: select * from f oo;
+ ^
+-- This should produce an error from psql.
+\pset estream bar
+\pset: allowed estream values are stderr, query, both
+-- This should display the current estream setting.
+-- (But does not in pg_regress.)
+\pset estream
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 663bf8a..594d60d 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -88,7 +88,7 @@ test: privileges security_label collate
# ----------
# Another group of parallel tests
# ----------
-test: misc alter_generic
+test: misc alter_generic estream
# rules cannot run concurrently with any test that creates a view
test: rules
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index be789e3..d8f2867 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -96,6 +96,7 @@ test: security_label
test: collate
test: misc
test: alter_generic
+test: estream
test: rules
test: event_trigger
test: select_views
diff --git a/src/test/regress/sql/estream.sql b/src/test/regress/sql/estream.sql
new file mode 100644
index 0000000..25f3b80
--- /dev/null
+++ b/src/test/regress/sql/estream.sql
@@ -0,0 +1,37 @@
+--
+-- Test of psql's \pset estream parameter.
+-- Don't use an actual table name since we might be running in parallel.
+--
+-- Bugs:
+-- o Uses /dev/null, which probably breaks on non-Unix boxes.
+-- o Due to the nature of the test framework, never looks at
+-- what's saved to the output file. Instead tests what's
+-- missing from stdout/stderr.
+--
+
+\o /dev/null
+
+-- This should not send an error into the output file, but
+-- should send it to stderr.
+select * from f oo;
+
+-- This should send an error into the output file, but not stderr.
+\pset estream query
+select * from f oo;
+
+-- This should send an error both places.
+\pset estream both
+select * from f oo;
+
+-- And this should return to the initial (default) setting,
+-- not send an error to the output file but do send it
+-- to stderr.
+\pset estream stderr
+select * from f oo;
+
+-- This should produce an error from psql.
+\pset estream bar
+
+-- This should display the current estream setting.
+-- (But does not in pg_regress.)
+\pset estream
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers