Skip to content

Commit 4cb27fe

Browse files
committed
o Improve psql's handling of multi-line statements
Currently, while \e saves a single statement as one entry, interactive statements are saved one line at a time. Ideally all statements would be saved like \e does. Sergey E. Koposov
1 parent fbb1dae commit 4cb27fe

File tree

6 files changed

+125
-23
lines changed

6 files changed

+125
-23
lines changed

src/bin/psql/help.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
*
44
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.106 2005/10/15 02:49:40 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.107 2006/02/11 21:55:35 momjian Exp $
77
*/
88
#include "postgres_fe.h"
99
#include "common.h"
10+
#include "pqexpbuffer.h"
1011
#include "input.h"
1112
#include "print.h"
1213
#include "help.h"

src/bin/psql/input.c

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
*
44
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.46 2005/10/15 02:49:40 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.47 2006/02/11 21:55:35 momjian Exp $
77
*/
88
#include "postgres_fe.h"
99

10-
#include "input.h"
1110
#include "pqexpbuffer.h"
11+
#include "input.h"
1212
#include "settings.h"
1313
#include "tab-complete.h"
1414
#include "common.h"
@@ -90,18 +90,55 @@ gets_interactive(const char *prompt)
9090
#ifdef USE_READLINE
9191
char *s;
9292

93-
static char *prev_hist = NULL;
94-
9593
if (useReadline)
9694
/* On some platforms, readline is declared as readline(char *) */
9795
s = readline((char *) prompt);
9896
else
9997
s = gets_basic(prompt);
10098

101-
if (useHistory && s && s[0])
99+
return s;
100+
#else
101+
return gets_basic(prompt);
102+
#endif
103+
}
104+
105+
106+
/* Put the line in the history buffer and also add the trailing \n */
107+
void pgadd_history(char *s, PQExpBuffer history_buf)
108+
{
109+
#ifdef USE_READLINE
110+
111+
int slen;
112+
if (useReadline && useHistory && s && s[0])
102113
{
103-
enum histcontrol HC;
114+
slen = strlen(s);
115+
if (s[slen-1] == '\n')
116+
appendPQExpBufferStr(history_buf, s);
117+
else
118+
{
119+
appendPQExpBufferStr(history_buf, s);
120+
appendPQExpBufferChar(history_buf, '\n');
121+
}
122+
}
123+
#endif
124+
}
104125

126+
127+
/* Feed the contents of the history buffer to readline */
128+
void pgflush_history(PQExpBuffer history_buf)
129+
{
130+
#ifdef USE_READLINE
131+
char *s;
132+
static char *prev_hist;
133+
int slen, i;
134+
135+
if (useReadline && useHistory )
136+
{
137+
enum histcontrol HC;
138+
139+
s = history_buf->data;
140+
prev_hist = NULL;
141+
105142
HC = GetHistControlConfig();
106143

107144
if (((HC & hctl_ignorespace) && s[0] == ' ') ||
@@ -112,17 +149,27 @@ gets_interactive(const char *prompt)
112149
else
113150
{
114151
free(prev_hist);
152+
slen = strlen(s);
153+
/* Trim the trailing \n's */
154+
for (i = slen-1; i >= 0 && s[i] == '\n'; i--)
155+
;
156+
s[i + 1] = '\0';
115157
prev_hist = pg_strdup(s);
116158
add_history(s);
117159
}
160+
161+
resetPQExpBuffer(history_buf);
118162
}
119-
120-
return s;
121-
#else
122-
return gets_basic(prompt);
123163
#endif
124164
}
125165

166+
void pgclear_history(PQExpBuffer history_buf)
167+
{
168+
#ifdef USE_READLINE
169+
if (useReadline && useHistory)
170+
resetPQExpBuffer(history_buf);
171+
#endif
172+
}
126173

127174

128175
/*
@@ -157,6 +204,30 @@ gets_fromFile(FILE *source)
157204
}
158205

159206

207+
static void encode_history()
208+
{
209+
HIST_ENTRY *cur_hist;
210+
char *cur_ptr;
211+
212+
for (history_set_pos(0), cur_hist = current_history();
213+
cur_hist; cur_hist = next_history())
214+
for (cur_ptr = cur_hist->line; *cur_ptr; cur_ptr++)
215+
if (*cur_ptr == '\n')
216+
*cur_ptr = '\0';
217+
}
218+
219+
static void decode_history()
220+
{
221+
HIST_ENTRY *cur_hist;
222+
char *cur_ptr;
223+
224+
for (history_set_pos(0), cur_hist = current_history();
225+
cur_hist; cur_hist = next_history())
226+
for (cur_ptr = cur_hist->line; *cur_ptr; cur_ptr++)
227+
if (*cur_ptr == '\0')
228+
*cur_ptr = '\n';
229+
}
230+
160231

161232
/*
162233
* Put any startup stuff related to input in here. It's good to maintain
@@ -197,6 +268,8 @@ initializeInput(int flags)
197268

198269
if (psql_history)
199270
read_history(psql_history);
271+
272+
decode_history();
200273
}
201274
#endif
202275

@@ -215,6 +288,7 @@ saveHistory(char *fname)
215288
#ifdef USE_READLINE
216289
if (useHistory && fname)
217290
{
291+
encode_history();
218292
if (write_history(fname) == 0)
219293
return true;
220294

src/bin/psql/input.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/input.h,v 1.23 2005/01/01 05:43:08 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/input.h,v 1.24 2006/02/11 21:55:35 momjian Exp $
77
*/
88
#ifndef INPUT_H
99
#define INPUT_H
@@ -39,4 +39,9 @@ char *gets_fromFile(FILE *source);
3939
void initializeInput(int flags);
4040
bool saveHistory(char *fname);
4141

42+
void pgadd_history(char *s, PQExpBuffer history_buf);
43+
void pgclear_history(PQExpBuffer history_buf);
44+
void pgflush_history(PQExpBuffer history_buf);
45+
46+
4247
#endif /* INPUT_H */

src/bin/psql/mainloop.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.69 2005/12/18 02:17:16 petere Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.70 2006/02/11 21:55:35 momjian Exp $
77
*/
88
#include "postgres_fe.h"
99
#include "mainloop.h"
@@ -37,6 +37,7 @@ MainLoop(FILE *source)
3737
PQExpBuffer query_buf; /* buffer for query being accumulated */
3838
PQExpBuffer previous_buf; /* if there isn't anything in the new buffer
3939
* yet, use this one for \e, etc. */
40+
PQExpBuffer history_buf;
4041
char *line; /* current line of input */
4142
int added_nl_pos;
4243
bool success;
@@ -66,7 +67,9 @@ MainLoop(FILE *source)
6667

6768
query_buf = createPQExpBuffer();
6869
previous_buf = createPQExpBuffer();
69-
if (!query_buf || !previous_buf)
70+
history_buf = createPQExpBuffer();
71+
72+
if (!query_buf || !previous_buf || !history_buf)
7073
{
7174
psql_error("out of memory\n");
7275
exit(EXIT_FAILURE);
@@ -90,7 +93,7 @@ MainLoop(FILE *source)
9093
successResult = EXIT_USER;
9194
break;
9295
}
93-
96+
pgclear_history(history_buf);
9497
cancel_pressed = false;
9598
}
9699

@@ -106,6 +109,8 @@ MainLoop(FILE *source)
106109
count_eof = 0;
107110
slashCmdStatus = PSQL_CMD_UNKNOWN;
108111
prompt_status = PROMPT_READY;
112+
if (pset.cur_cmd_interactive)
113+
pgclear_history(history_buf);
109114

110115
if (pset.cur_cmd_interactive)
111116
putc('\n', stdout);
@@ -138,11 +143,15 @@ MainLoop(FILE *source)
138143
psql_scan_reset(scan_state);
139144
slashCmdStatus = PSQL_CMD_UNKNOWN;
140145
prompt_status = PROMPT_READY;
146+
147+
if (pset.cur_cmd_interactive)
148+
/*
149+
* Pass all the contents of history_buf to readline
150+
* and free the history buffer.
151+
*/
152+
pgflush_history(history_buf);
141153
}
142-
143-
/*
144-
* otherwise, get another line
145-
*/
154+
/* otherwise, get another line */
146155
else if (pset.cur_cmd_interactive)
147156
{
148157
/* May need to reset prompt, eg after \r command */
@@ -212,7 +221,11 @@ MainLoop(FILE *source)
212221
*/
213222
psql_scan_setup(scan_state, line, strlen(line));
214223
success = true;
215-
224+
225+
if (pset.cur_cmd_interactive)
226+
/* Put current line in the history buffer */
227+
pgadd_history(line, history_buf);
228+
216229
while (success || !die_on_error)
217230
{
218231
PsqlScanResult scan_result;
@@ -287,6 +300,13 @@ MainLoop(FILE *source)
287300
scan_result == PSCAN_EOL)
288301
break;
289302
}
303+
304+
if (pset.cur_cmd_interactive && prompt_status != PROMPT_CONTINUE)
305+
/*
306+
* Pass all the contents of history_buf to readline
307+
* and free the history buffer.
308+
*/
309+
pgflush_history(history_buf);
290310

291311
psql_scan_finish(scan_state);
292312
free(line);
@@ -333,6 +353,7 @@ MainLoop(FILE *source)
333353

334354
destroyPQExpBuffer(query_buf);
335355
destroyPQExpBuffer(previous_buf);
356+
destroyPQExpBuffer(history_buf);
336357

337358
psql_scan_destroy(scan_state);
338359

src/bin/psql/prompt.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/prompt.c,v 1.41 2006/01/03 23:32:30 tgl Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/prompt.c,v 1.42 2006/02/11 21:55:35 momjian Exp $
77
*/
88
#include "postgres_fe.h"
99
#include "prompt.h"
@@ -12,6 +12,7 @@
1212

1313
#include "settings.h"
1414
#include "common.h"
15+
#include "pqexpbuffer.h"
1516
#include "input.h"
1617
#include "variables.h"
1718

src/bin/psql/tab-complete.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.144 2006/01/11 08:43:12 neilc Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.145 2006/02/11 21:55:35 momjian Exp $
77
*/
88

99
/*----------------------------------------------------------------------
@@ -43,14 +43,14 @@
4343

4444
#include "postgres_fe.h"
4545
#include "tab-complete.h"
46+
#include "pqexpbuffer.h"
4647
#include "input.h"
4748

4849
/* If we don't have this, we might as well forget about the whole thing: */
4950
#ifdef USE_READLINE
5051

5152
#include <ctype.h>
5253
#include "libpq-fe.h"
53-
#include "pqexpbuffer.h"
5454
#include "common.h"
5555
#include "settings.h"
5656

0 commit comments

Comments
 (0)