From 451b564fa8714ff4ba21725b183913d651b1c925 Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig@2ndquadrant.com>
Date: Fri, 6 Dec 2019 12:50:58 +0800
Subject: [PATCH] print help in psql when users try to run pg_dump etc

New users frequently attempt to run PostgreSQL's command line utilities
from the psql prompt. Detect this and emit a useful help message:

    psql=> pg_restore
    "pg_restore" is a command line utility program.
    Use it from the system terminal or command prompt not from psql.
    psql=>

Previously we'd just add the command to the buffer - and since the user
wouldn't generally follow it with a semicolon they'd see no response except a
prompt change:

    psql=> pg_restore
    psql->
---
 src/bin/psql/mainloop.c | 48 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index f7b1b94599..2c65b7a862 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -353,6 +353,54 @@ MainLoop(FILE *source)
 #else
 				puts(_("Use control-C to quit."));
 #endif
+
+			/*
+			 * New users tend to be confused about the command line utilities
+			 * pg_dump, pg_restore, createdb, etc, and try to run them
+			 * interatively in psql. Detect this and emit a suitable hint.
+			 *
+			 * We check for them even when the buffer is non-empty because
+			 * users frequently try multiple commands without semicolons when
+			 * trying to misuse psql as a command-line shell. Like with "help"
+			 * etc, the text is still added to the buffer unless it's the
+			 * first word on an empty buffer.
+			 */
+			if (line[0] == 'p' || line[0] == 'c' || line[0] == 'd')
+			{
+				if (strncmp(line, "pg_restore", sizeof("pg_restore")) == 0
+					|| strncmp(line, "pg_dump", sizeof("pg_dump")) == 0
+					|| strncmp(line, "createdb", sizeof("createdb")) == 0
+					|| strncmp(line, "dropdb", sizeof("dropdb")) == 0
+					|| strncmp(line, "createuser", sizeof("createuser")) == 0
+					|| strncmp(line, "dropuser", sizeof("dropuser")) == 0)
+				{
+					char		cmdname[12];
+
+					strlcpy(&cmdname[0], line,
+							Min(strcspn(line, " \r\n") + 1, sizeof(cmdname)));
+					if (query_buf->len != 0)
+					{
+						/*
+						 * Print a short hint but don't swallow the input if
+						 * there's already something in the buffer.
+						 */
+						printf(_("\"%s\" is a command-line utility program "
+								 "not a psql command.\n"),
+							   cmdname);
+					}
+					else
+					{
+						/* Swallow the input and emit more help */
+						printf(_("\"%s\" is a command line utility program.\n"
+								 "Use it from the system terminal or command "
+								 "prompt not from psql.\n"),
+							   cmdname);
+						free(line);
+						fflush(stdout);
+						continue;
+					}
+				}
+			}
 		}
 
 		/* echo back if flag is set, unless interactive */
-- 
2.23.0

