From ca8f27998a789af126bbd938c10b160b052a57a7 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Mon, 6 Mar 2006 04:45:21 +0000
Subject: [PATCH] In psql, save history of backslash commands used in
 multi-line statements before the multi-line statement, rather than inside the
 multi-line statement.

---
 src/bin/psql/input.c    | 18 ++++++++----------
 src/bin/psql/input.h    |  8 ++++----
 src/bin/psql/mainloop.c | 40 +++++++++++++++++++++++++++++++---------
 3 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index 241c5d356bb..fdf0bbecdd6 100644
--- a/src/bin/psql/input.c
+++ b/src/bin/psql/input.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.51 2006/03/05 15:58:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.52 2006/03/06 04:45:21 momjian Exp $
  */
 #include "postgres_fe.h"
 
@@ -114,7 +114,7 @@ gets_interactive(const char *prompt)
 
 /* Put the line in the history buffer and also add the trailing \n */
 void
-pgadd_history(char *s, PQExpBuffer history_buf)
+pg_append_history(char *s, PQExpBuffer history_buf)
 {
 #ifdef USE_READLINE
 
@@ -134,12 +134,13 @@ pgadd_history(char *s, PQExpBuffer history_buf)
 }
 
 
-/* Feed the contents of the history buffer to readline */
+/*
+ *	Feed the string to readline
+ */
 void
-pgflush_history(PQExpBuffer history_buf)
+pg_write_history(char *s)
 {
-#ifdef USE_READLINE	
-	char *s;
+#ifdef USE_READLINE
 	static char *prev_hist;
 	int slen, i;
 	
@@ -147,7 +148,6 @@ pgflush_history(PQExpBuffer history_buf)
 	{
 		enum histcontrol HC;
 		
-		s = history_buf->data;
 		prev_hist = NULL;
 			
 		HC = GetHistControlConfig();
@@ -168,14 +168,12 @@ pgflush_history(PQExpBuffer history_buf)
 			prev_hist = pg_strdup(s);
 			add_history(s);
 		}
-		
-		resetPQExpBuffer(history_buf);
 	}
 #endif
 }
 
 void
-pgclear_history(PQExpBuffer history_buf)
+pg_clear_history(PQExpBuffer history_buf)
 {
 #ifdef USE_READLINE	
 	if (useReadline && useHistory)
diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h
index 89c18386d0f..3b85d416705 100644
--- a/src/bin/psql/input.h
+++ b/src/bin/psql/input.h
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/input.h,v 1.25 2006/03/05 15:58:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/input.h,v 1.26 2006/03/06 04:45:21 momjian Exp $
  */
 #ifndef INPUT_H
 #define INPUT_H
@@ -39,9 +39,9 @@ char	   *gets_fromFile(FILE *source);
 void		initializeInput(int flags);
 bool		saveHistory(char *fname);
 
-void pgadd_history(char *s, PQExpBuffer history_buf);
-void pgclear_history(PQExpBuffer history_buf);
-void pgflush_history(PQExpBuffer history_buf);
+void pg_append_history(char *s, PQExpBuffer history_buf);
+void pg_clear_history(PQExpBuffer history_buf);
+void pg_write_history(char *s);
 
 
 #endif   /* INPUT_H */
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index 9e85093c67d..6cdbb9f482a 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.71 2006/03/05 15:58:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.72 2006/03/06 04:45:21 momjian Exp $
  */
 #include "postgres_fe.h"
 #include "mainloop.h"
@@ -41,6 +41,8 @@ MainLoop(FILE *source)
 	char	   *line;			/* current line of input */
 	int			added_nl_pos;
 	bool		success;
+	bool		first_query_scan;
+	
 	volatile int successResult = EXIT_SUCCESS;
 	volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
 	volatile promptStatus_t prompt_status = PROMPT_READY;
@@ -93,7 +95,7 @@ MainLoop(FILE *source)
 				successResult = EXIT_USER;
 				break;
 			}
-			pgclear_history(history_buf);			
+			pg_clear_history(history_buf);			
 			cancel_pressed = false;
 		}
 
@@ -110,7 +112,7 @@ MainLoop(FILE *source)
 			slashCmdStatus = PSQL_CMD_UNKNOWN;
 			prompt_status = PROMPT_READY;
 			if (pset.cur_cmd_interactive)
-				pgclear_history(history_buf);			
+				pg_clear_history(history_buf);			
 
 			if (pset.cur_cmd_interactive)
 				putc('\n', stdout);
@@ -145,11 +147,14 @@ MainLoop(FILE *source)
 			prompt_status = PROMPT_READY;
 			
 			if (pset.cur_cmd_interactive)
+			{
 				/*
 				 *	Pass all the contents of history_buf to readline
 				 *	and free the history buffer.
 				 */
-				pgflush_history(history_buf);
+				pg_write_history(history_buf->data);
+				pg_clear_history(history_buf);
+			}
 		}
 		/* otherwise, get another line */
 		else if (pset.cur_cmd_interactive)
@@ -221,10 +226,7 @@ MainLoop(FILE *source)
 		 */
 		psql_scan_setup(scan_state, line, strlen(line));
 		success = true;
-		
-		if (pset.cur_cmd_interactive)
-			/* Put current line in the history buffer */
-			pgadd_history(line, history_buf);
+		first_query_scan = true;
 		
 		while (success || !die_on_error)
 		{
@@ -234,6 +236,23 @@ MainLoop(FILE *source)
 			scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
 			prompt_status = prompt_tmp;
 
+			/*
+			 *	If we append to history a backslash command that is inside
+			 *	a multi-line query, then when we recall the history, the
+			 *	backslash command will make the query invalid, so we write
+			 *	backslash commands immediately rather than keeping them
+			 *	as part of the current multi-line query.
+			 */
+			if (first_query_scan && pset.cur_cmd_interactive)
+			{
+				if (scan_result == PSCAN_BACKSLASH && query_buf->len != 0)
+					pg_write_history(line);
+				else
+					pg_append_history(line, history_buf);
+			}
+				
+			first_query_scan = false;
+			
 			/*
 			 * Send command if semicolon found, or if end of line and we're in
 			 * single-line mode.
@@ -302,11 +321,14 @@ MainLoop(FILE *source)
 		}
 		
 		if (pset.cur_cmd_interactive && prompt_status != PROMPT_CONTINUE)
+		{
 			/*
 			 *	Pass all the contents of history_buf to readline
 			 *	and free the history buffer.
 			 */
-			pgflush_history(history_buf);
+			pg_write_history(history_buf->data);
+			pg_clear_history(history_buf);
+		}
 
 		psql_scan_finish(scan_state);
 		free(line);
-- 
GitLab