From 0155a5573e7ff9a187f788c0e12096fe9a7d8ac7 Mon Sep 17 00:00:00 2001
From: Greg Nancarrow <gregn4422@gmail.com>
Date: Mon, 6 Sep 2021 23:10:35 +1000
Subject: [PATCH] Correct handling of blank/commented lines in PSQL
 interactive-mode history.

Improve PSQL interactive-mode history, for lines that are not part of a line
continuation, by storing them in the history as separate entries if they only
contain whitespace or an SQL comment.
(Note that lines starting with a space don't get saved in the history if
HISTCONTROL=ignorespace is in effect)
Currently, such blank or commented lines are prepended to the history entry for
the next command entered. Worse, if HISTCONTROL=ignorespace is in effect, and
the line starts with a space and the rest is whitespace or an SQL comment, it
prevents the next command entered from being saved in the history.
---
 src/bin/psql/mainloop.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index e49ed02293..cf8b0076c0 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -47,6 +47,7 @@ MainLoop(FILE *source)
 	volatile int successResult = EXIT_SUCCESS;
 	volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
 	volatile promptStatus_t prompt_status = PROMPT_READY;
+	volatile PsqlScanResult scan_result = PSCAN_INCOMPLETE;
 	volatile bool need_redisplay = false;
 	volatile int count_eof = 0;
 	volatile bool die_on_error = false;
@@ -119,6 +120,7 @@ MainLoop(FILE *source)
 			count_eof = 0;
 			slashCmdStatus = PSQL_CMD_UNKNOWN;
 			prompt_status = PROMPT_READY;
+			scan_result = PSCAN_INCOMPLETE;
 			need_redisplay = false;
 			pset.stmt_lineno = 1;
 			cancel_pressed = false;
@@ -388,7 +390,6 @@ MainLoop(FILE *source)
 
 		while (success || !die_on_error)
 		{
-			PsqlScanResult scan_result;
 			promptStatus_t prompt_tmp = prompt_status;
 			size_t		pos_in_query;
 			char	   *tmp_line;
@@ -564,9 +565,25 @@ MainLoop(FILE *source)
 				break;
 		}
 
-		/* Add line to pending history if we didn't execute anything yet */
+		/*
+		 * If we didn't execute anything yet, then depending on the scan and
+		 * prompt state, either save the line to the history or just add the
+		 * line to the pending history.
+		 */
 		if (pset.cur_cmd_interactive && !line_saved_in_history)
+		{
 			pg_append_history(line, history_buf);
+			if (scan_result == PSCAN_INCOMPLETE && prompt_status == PROMPT_READY)
+			{
+				/*
+				 * In this case, it's not a line continuation, and the line
+				 * contains only whitespace or a single-line SQL comment, so
+				 * save it to the history.
+				 */
+				pg_send_history(history_buf);
+				line_saved_in_history = true;
+			}
+		}
 
 		psql_scan_finish(scan_state);
 		free(line);
-- 
2.27.0

