From 77a47299366e0246e3ec7419a9f8472281394b1e Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Fri, 10 Dec 1999 03:59:30 +0000
Subject: [PATCH] This should fix the \e (\p, \g, ...) behaviour on an empty
 query buffer. Also, minor tweakage of tab completion, and I hope the output
 is flushed on time now.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

--
Peter Eisentraut                  Sernanders väg 10:115
---
 src/bin/psql/command.c      |  2 +-
 src/bin/psql/common.c       | 10 +++---
 src/bin/psql/input.c        |  4 ---
 src/bin/psql/mainloop.c     | 65 ++++++++++++++++++++++++-------------
 src/bin/psql/print.c        |  7 +++-
 src/bin/psql/settings.h     |  2 +-
 src/bin/psql/tab-complete.c | 13 +++++---
 7 files changed, 63 insertions(+), 40 deletions(-)

diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 59b596d6f22..9489a8e2af6 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -624,7 +624,7 @@ exec_command(const char *cmd,
 
 		if (!options[0])
 		{
-			fprintf(stderr, "Usage \\%s <filename>\n", cmd);
+			fprintf(stderr, "Usage: \\%s <filename>\n", cmd);
 			success = false;
 		}
 		else
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 30167847a0f..6bbf663733c 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -433,7 +433,6 @@ SendQuery(PsqlSettings *pset, const char *query)
 		fgets(buf, 3, stdin);
 		if (buf[0] == 'x')
 			return false;
-		fflush(stdin);
 	}
 
 	cancelConn = pset->db;
@@ -479,7 +478,6 @@ SendQuery(PsqlSettings *pset, const char *query)
 				{
 					success = true;
 					printQuery(results, &pset->popt, pset->queryFout);
-					fflush(pset->queryFout);
 				}
 				break;
 			case PGRES_EMPTY_QUERY:
@@ -488,10 +486,8 @@ SendQuery(PsqlSettings *pset, const char *query)
 			case PGRES_COMMAND_OK:
 				success = true;
                 pset->lastOid = PQoidValue(results);
-                if (!GetVariableBool(pset->vars, "quiet")) {
+                if (!GetVariableBool(pset->vars, "quiet"))
                     fprintf(pset->queryFout, "%s\n", PQcmdStatus(results));
-                    fflush(pset->queryFout);
-                }
 				break;
 
 			case PGRES_COPY_OUT:
@@ -515,10 +511,11 @@ SendQuery(PsqlSettings *pset, const char *query)
 			case PGRES_BAD_RESPONSE:
 				success = false;
 				fputs(PQerrorMessage(pset->db), pset->queryFout);
-                fflush(pset->queryFout);
 				break;
 		}
 
+        fflush(pset->queryFout);
+
 		if (PQstatus(pset->db) == CONNECTION_BAD)
 		{
 			fputs("The connection to the server was lost. Attempting reset: ", stderr);
@@ -541,6 +538,7 @@ SendQuery(PsqlSettings *pset, const char *query)
 			fprintf(pset->queryFout, "Asynchronous NOTIFY '%s' from backend with pid '%d' received.\n",
 					notify->relname, notify->be_pid);
 			free(notify);
+            fflush(pset->queryFout);
 		}
 
 		if (results)
diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index 31fe4ce7737..250f1233ea6 100644
--- a/src/bin/psql/input.c
+++ b/src/bin/psql/input.c
@@ -32,11 +32,7 @@ gets_interactive(const char *prompt)
 
 #ifdef USE_READLINE
 	if (useReadline)
-	{
 		s = readline(prompt);
-		fputc('\r', stdout);
-		fflush(stdout);
-	}
 	else
 	{
 #endif
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index 067be54e2cc..f85247689b9 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -29,6 +29,8 @@ int
 MainLoop(PsqlSettings *pset, FILE *source)
 {
 	PQExpBuffer query_buf;		/* buffer for query being accumulated */
+    PQExpBuffer previous_buf;   /* if there isn't anything in the new buffer
+                                   yet, use this one for \e, etc. */
 	char	   *line;			/* current line of input */
 	int			len;			/* length of the line */
 	int			successResult = EXIT_SUCCESS;
@@ -63,7 +65,8 @@ MainLoop(PsqlSettings *pset, FILE *source)
 
 
 	query_buf = createPQExpBuffer();
-	if (!query_buf)
+    previous_buf = createPQExpBuffer();
+	if (!query_buf || !previous_buf)
 	{
 		perror("createPQExpBuffer");
 		exit(EXIT_FAILURE);
@@ -80,21 +83,21 @@ MainLoop(PsqlSettings *pset, FILE *source)
 	{
 		if (slashCmdStatus == CMD_NEWEDIT)
 		{
-
 			/*
 			 * just returned from editing the line? then just copy to the
 			 * input buffer
 			 */
-			line = strdup(query_buf->data);
+			line = xstrdup(query_buf->data);
 			resetPQExpBuffer(query_buf);
-			/* reset parsing state since we are rescanning whole query */
+			/* reset parsing state since we are rescanning whole line */
 			xcomment = false;
 			in_quote = 0;
 			paren_level = 0;
+            slashCmdStatus = CMD_UNKNOWN;
 		}
 		else
 		{
-
+            fflush(stdout);
 			/*
 			 * otherwise, set interactive prompt if necessary and get
 			 * another line
@@ -170,8 +173,6 @@ MainLoop(PsqlSettings *pset, FILE *source)
 			puts(line);
 
 
-		slashCmdStatus = CMD_UNKNOWN;
-
 		len = strlen(line);
 		query_start = 0;
 
@@ -275,11 +276,13 @@ MainLoop(PsqlSettings *pset, FILE *source)
 			/* semicolon? then send query */
 			else if (line[i] == ';' && !was_bslash)
 			{
+                /* delete the old query buffer from last time around */
+                if (slashCmdStatus == CMD_SEND)
+
 				line[i] = '\0';
 				/* is there anything else on the line? */
 				if (line[query_start + strspn(line + query_start, " \t")] != '\0')
 				{
-
 					/*
 					 * insert a cosmetic newline, if this is not the first
 					 * line in the buffer
@@ -292,8 +295,11 @@ MainLoop(PsqlSettings *pset, FILE *source)
 
 				/* execute query */
 				success = SendQuery(pset, query_buf->data);
+                slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
 
-				resetPQExpBuffer(query_buf);
+                resetPQExpBuffer(previous_buf);
+                appendPQExpBufferStr(previous_buf, query_buf->data);
+                resetPQExpBuffer(query_buf);
 				query_start = i + thislen;
 			}
 
@@ -316,7 +322,6 @@ MainLoop(PsqlSettings *pset, FILE *source)
 				/* is there anything else on the line? */
 				if (line[query_start + strspn(line + query_start, " \t")] != '\0')
 				{
-
 					/*
 					 * insert a cosmetic newline, if this is not the first
 					 * line in the buffer
@@ -327,17 +332,27 @@ MainLoop(PsqlSettings *pset, FILE *source)
 					appendPQExpBufferStr(query_buf, line + query_start);
 				}
 
-				/* handle backslash command */
-
-				slashCmdStatus = HandleSlashCmds(pset, &line[i], query_buf, &end_of_cmd);
+                /* handle backslash command */
+                slashCmdStatus = HandleSlashCmds(pset, &line[i], 
+                                                 query_buf->len>0 ? query_buf : previous_buf,
+                                                 &end_of_cmd);
 
 				success = slashCmdStatus != CMD_ERROR;
 
+                if ((slashCmdStatus == CMD_SEND || slashCmdStatus == CMD_NEWEDIT) &&
+                    query_buf->len == 0) {
+                    /* copy previous buffer to current for for handling */
+                    appendPQExpBufferStr(query_buf, previous_buf->data);
+                }
+
 				if (slashCmdStatus == CMD_SEND)
 				{
 					success = SendQuery(pset, query_buf->data);
-					resetPQExpBuffer(query_buf);
 					query_start = i + thislen;
+
+                    resetPQExpBuffer(previous_buf);
+                    appendPQExpBufferStr(previous_buf, query_buf->data);
+                    resetPQExpBuffer(query_buf);
 				}
 
 				/* is there anything left after the backslash command? */
@@ -358,13 +373,6 @@ MainLoop(PsqlSettings *pset, FILE *source)
 		} /* for (line) */
 
 
-		if (!success && die_on_error && !pset->cur_cmd_interactive)
-		{
-			successResult = EXIT_USER;
-			break;
-		}
-
-
 		if (slashCmdStatus == CMD_TERMINATE)
 		{
 			successResult = EXIT_SUCCESS;
@@ -387,7 +395,17 @@ MainLoop(PsqlSettings *pset, FILE *source)
 		if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline"))
 		{
 			success = SendQuery(pset, query_buf->data);
-			resetPQExpBuffer(query_buf);
+            slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
+            resetPQExpBuffer(previous_buf);
+            appendPQExpBufferStr(previous_buf, query_buf->data);
+            resetPQExpBuffer(query_buf);
+		}
+
+
+		if (!success && die_on_error && !pset->cur_cmd_interactive)
+		{
+			successResult = EXIT_USER;
+			break;
 		}
 
 
@@ -397,9 +415,10 @@ MainLoop(PsqlSettings *pset, FILE *source)
 			successResult = EXIT_BADCONN;
 			break;
 		}
-	}							/* while */
+	} /* while !EOF */
 
 	destroyPQExpBuffer(query_buf);
+	destroyPQExpBuffer(previous_buf);
 
 	pset->cur_cmd_source = prev_cmd_source;
 	pset->cur_cmd_interactive = prev_cmd_interactive;
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index 481f76f343e..15d40a806a9 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -18,7 +18,7 @@
 #include <libpq-fe.h>
 #include <postgres_ext.h>		/* for Oid type */
 
-#define DEFAULT_PAGER "/bin/more"
+#define DEFAULT_PAGER "more"
 
 
 
@@ -325,6 +325,11 @@ print_aligned_vertical(const char *title, const char * const * headers,
 				dwidth = 0;
 	char	   *divider;
 
+    if (cells[0] == NULL) {
+        puts("(No rows)\n");
+        return;
+    }
+
 	/* count columns and find longest header */
 	for (ptr = headers; *ptr; ptr++)
 	{
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 828dbd40d0f..85cf9dcb7f3 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -13,7 +13,7 @@
 #include "print.h"
 
 #define DEFAULT_FIELD_SEP "|"
-#define DEFAULT_EDITOR	"/bin/vi"
+#define DEFAULT_EDITOR	"vi"
 
 #define DEFAULT_PROMPT1 "%/%R%# "
 #define DEFAULT_PROMPT2 "%/%R%# "
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index f2025b0d26a..2b08ff3f861 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -203,7 +203,7 @@ char ** psql_completion(char *text, int start, int end)
 
     (void)end; /* not used */
 
-    rl_filename_quoting_desired = 1;
+    rl_completion_append_character = ' ';
 
     /* Clear a few things. */
     completion_charp = NULL;
@@ -501,6 +501,11 @@ char ** psql_completion(char *text, int start, int end)
       	COMPLETE_WITH_QUERY(Query_for_list_of_tables);
 
 
+/* ... FROM ... */
+    else if (strcasecmp(prev_wd, "FROM") == 0 )
+        COMPLETE_WITH_QUERY(Query_for_list_of_tables);
+
+
 /* Backslash commands */
     else if (strcmp(prev_wd, "\\connect")==0 || strcmp(prev_wd, "\\c")==0)
         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
@@ -510,7 +515,7 @@ char ** psql_completion(char *text, int start, int end)
         COMPLETE_WITH_LIST(sql_commands);
     else if (strcmp(prev_wd, "\\pset")==0) {
         char * my_list[] = { "format", "border", "expanded", "null", "fieldsep",
-                             "tuples_only", "title", "tableattr", "pager" };
+                             "tuples_only", "title", "tableattr", "pager", NULL };
         COMPLETE_WITH_LIST(my_list);
     }
     else if( strcmp(prev_wd, "\\e")==0 || strcmp(prev_wd, "\\edit")==0 ||
@@ -541,8 +546,8 @@ char ** psql_completion(char *text, int start, int end)
        of default list. If we were to just return NULL, readline automatically
        attempts filename completion, and that's usually no good. */
     if (matches == NULL) {
-        char * my_list[] = { "", "", NULL };
-        COMPLETE_WITH_LIST(my_list);
+        COMPLETE_WITH_CONST("");
+        rl_completion_append_character = '\0';
     }
 	
 
-- 
GitLab