diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 3cd0a99d07..7789fc6177 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1863,22 +1863,22 @@ testdb=>
\echo text [ ... ]
- Prints the arguments to the standard output, separated by one
- space and followed by a newline. This can be useful to
+ Prints the evaluated arguments to standard output, separated by
+ spaces and followed by a newline. This can be useful to
intersperse information in the output of scripts. For example:
=> \echo `date`
Tue Oct 26 21:40:57 CEST 1999
If the first argument is an unquoted -n the trailing
- newline is not written.
+ newline is not written (nor is the first argument).
If you use the \o command to redirect your
query output you might wish to use \qecho
- instead of this command.
+ instead of this command. See also \warn.
@@ -3226,6 +3226,18 @@ testdb=> \setenv LESS -imx4F
+
+ \warn text [ ... ]
+
+
+ This command is identical to \echo except
+ that the output will be written to psql's
+ standard error channel, rather than standard output.
+
+
+
+
+
\watch [ seconds ]
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 66e1aec011..c0a7a5566e 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -319,7 +319,8 @@ exec_command(const char *cmd,
status = exec_command_ef_ev(scan_state, active_branch, query_buf, true);
else if (strcmp(cmd, "ev") == 0)
status = exec_command_ef_ev(scan_state, active_branch, query_buf, false);
- else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
+ else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0 ||
+ strcmp(cmd, "warn") == 0)
status = exec_command_echo(scan_state, active_branch, cmd);
else if (strcmp(cmd, "elif") == 0)
status = exec_command_elif(scan_state, cstack, query_buf);
@@ -1114,7 +1115,7 @@ exec_command_ef_ev(PsqlScanState scan_state, bool active_branch,
}
/*
- * \echo and \qecho -- echo arguments to stdout or query output
+ * \echo, \qecho, and \warn -- echo arguments to stdout, query output, or stderr
*/
static backslashResult
exec_command_echo(PsqlScanState scan_state, bool active_branch, const char *cmd)
@@ -1129,13 +1130,15 @@ exec_command_echo(PsqlScanState scan_state, bool active_branch, const char *cmd)
if (strcmp(cmd, "qecho") == 0)
fout = pset.queryFout;
+ else if (strcmp(cmd, "warn") == 0)
+ fout = stderr;
else
fout = stdout;
while ((value = psql_scan_slash_option(scan_state,
OT_NORMAL, "ed, false)))
{
- if (!quoted && strcmp(value, "-n") == 0)
+ if (first && !no_newline && !quoted && strcmp(value, "-n") == 0)
no_newline = true;
else
{
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 5fb1baadc5..d9b982d3a0 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -169,7 +169,7 @@ slashUsage(unsigned short int pager)
* Use "psql --help=commands | wc" to count correctly. It's okay to count
* the USE_READLINE line even in builds without that.
*/
- output = PageOutput(127, pager ? &(pset.popt.topt) : NULL);
+ output = PageOutput(128, pager ? &(pset.popt.topt) : NULL);
fprintf(output, _("General\n"));
fprintf(output, _(" \\copyright show PostgreSQL usage and distribution terms\n"));
@@ -206,11 +206,12 @@ slashUsage(unsigned short int pager)
fprintf(output, _("Input/Output\n"));
fprintf(output, _(" \\copy ... perform SQL COPY with data stream to the client host\n"));
- fprintf(output, _(" \\echo [STRING] write string to standard output\n"));
+ fprintf(output, _(" \\echo [-n] [STRING] write string to standard output (-n for no newline)\n"));
fprintf(output, _(" \\i FILE execute commands from file\n"));
fprintf(output, _(" \\ir FILE as \\i, but relative to location of current script\n"));
fprintf(output, _(" \\o [FILE] send all query results to file or |pipe\n"));
- fprintf(output, _(" \\qecho [STRING] write string to query output stream (see \\o)\n"));
+ fprintf(output, _(" \\qecho [-n] [STRING] write string to \\o output stream (-n for no newline)\n"));
+ fprintf(output, _(" \\warn [-n] [STRING] write string to standard error (-n for no newline)\n"));
fprintf(output, "\n");
fprintf(output, _("Conditional\n"));
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 12355348c9..9009b05e12 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1438,7 +1438,7 @@ psql_completion(const char *text, int start, int end)
"\\t", "\\T", "\\timing",
"\\unset",
"\\x",
- "\\w", "\\watch",
+ "\\w", "\\warn", "\\watch",
"\\z",
"\\!", "\\?",
NULL
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 4bcf0cc5df..9021c808dc 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -4180,6 +4180,25 @@ drop table psql_serial_tab;
\pset format aligned
\pset expanded off
\pset border 1
+-- \echo and allied features
+\echo this is a test
+this is a test
+\echo -n without newline
+without newline\echo with -n newline
+with -n newline
+\echo '-n' with newline
+-n with newline
+\set foo bar
+\echo foo = :foo
+foo = bar
+\qecho this is a test
+this is a test
+\qecho foo = :foo
+foo = bar
+\warn this is a test
+this is a test
+\warn foo = :foo
+foo = bar
-- tests for \if ... \endif
\if true
select 'okay';
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index 26f436ae40..cefe41bdc2 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -771,6 +771,22 @@ drop table psql_serial_tab;
\pset expanded off
\pset border 1
+-- \echo and allied features
+
+\echo this is a test
+\echo -n without newline
+\echo with -n newline
+\echo '-n' with newline
+
+\set foo bar
+\echo foo = :foo
+
+\qecho this is a test
+\qecho foo = :foo
+
+\warn this is a test
+\warn foo = :foo
+
-- tests for \if ... \endif
\if true