Skip to content

Commit e97281c

Browse files
committed
Write psql's ~/.psql_history file using history_truncate_file() and
append_history(), if libreadline is new enough to have those functions (they seem to be present at least since 4.2; but libedit may not have them). This gives significantly saner behavior when two or more sessions overlap in their use of the history file; although having two sessions exit at just the same time is still perilous to your history. The behavior of \s remains unchanged, ie, overwrite whatever was there. Per bug #5052 from Marek Wójtowicz.
1 parent eb62398 commit e97281c

File tree

7 files changed

+88
-31
lines changed

7 files changed

+88
-31
lines changed

configure

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19453,7 +19453,8 @@ fi
1945319453
done
1945419454

1945519455

19456-
for ac_func in replace_history_entry
19456+
19457+
for ac_func in append_history history_truncate_file
1945719458
do
1945819459
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
1945919460
{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5

configure.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
dnl Process this file with autoconf to produce a configure script.
2-
dnl $PostgreSQL: pgsql/configure.in,v 1.610 2009/09/08 16:08:26 tgl Exp $
2+
dnl $PostgreSQL: pgsql/configure.in,v 1.611 2009/09/13 22:18:22 tgl Exp $
33
dnl
44
dnl Developers, please strive to achieve this order:
55
dnl
@@ -1316,7 +1316,7 @@ fi
13161316
if test "$with_readline" = yes; then
13171317
PGAC_VAR_RL_COMPLETION_APPEND_CHARACTER
13181318
AC_CHECK_FUNCS([rl_completion_matches rl_filename_completion_function])
1319-
AC_CHECK_FUNCS([replace_history_entry])
1319+
AC_CHECK_FUNCS([append_history history_truncate_file])
13201320
fi
13211321

13221322

src/bin/psql/command.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.206 2009/06/11 14:49:07 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.207 2009/09/13 22:18:22 tgl Exp $
77
*/
88
#include "postgres_fe.h"
99
#include "command.h"
@@ -908,7 +908,7 @@ exec_command(const char *cmd,
908908

909909
expand_tilde(&fname);
910910
/* This scrolls off the screen when using /dev/tty */
911-
success = saveHistory(fname ? fname : DEVTTY, false);
911+
success = saveHistory(fname ? fname : DEVTTY, -1, false, false);
912912
if (success && !pset.quiet && fname)
913913
printf(gettext("Wrote history to file \"%s/%s\".\n"),
914914
pset.dirname ? pset.dirname : ".", fname);

src/bin/psql/input.c

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
*
44
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.66 2009/01/01 17:23:55 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.67 2009/09/13 22:18:22 tgl Exp $
77
*/
88
#include "postgres_fe.h"
99

10+
#ifndef WIN32
11+
#include <unistd.h>
12+
#endif
13+
#include <fcntl.h>
14+
1015
#include "input.h"
1116
#include "settings.h"
1217
#include "tab-complete.h"
@@ -23,7 +28,11 @@
2328
#ifdef USE_READLINE
2429
static bool useReadline;
2530
static bool useHistory;
26-
char *psql_history;
31+
32+
static char *psql_history;
33+
34+
static int history_lines_added;
35+
2736

2837
/*
2938
* Preserve newlines in saved queries by mapping '\n' to NL_IN_HISTORY
@@ -135,6 +144,8 @@ pg_send_history(PQExpBuffer history_buf)
135144
prev_hist = pg_strdup(s);
136145
/* And send it to readline */
137146
add_history(s);
147+
/* Count lines added to history for use later */
148+
history_lines_added++;
138149
}
139150
}
140151

@@ -276,6 +287,7 @@ initializeInput(int flags)
276287

277288
useHistory = true;
278289
using_history();
290+
history_lines_added = 0;
279291

280292
histfile = GetVariable(pset.vars, "HISTFILE");
281293
if (histfile == NULL)
@@ -310,15 +322,22 @@ initializeInput(int flags)
310322

311323

312324
/*
313-
* This function is for saving the readline history when user
314-
* runs \s command or when psql finishes.
325+
* This function saves the readline history when user
326+
* runs \s command or when psql exits.
327+
*
328+
* fname: pathname of history file. (Should really be "const char *",
329+
* but some ancient versions of readline omit the const-decoration.)
330+
*
331+
* max_lines: if >= 0, limit history file to that many entries.
315332
*
316-
* We have an argument named encodeFlag to handle the cases differently.
317-
* In case of call via \s we don't really need to encode \n as \x01,
318-
* but when we save history for Readline we must do that conversion.
333+
* appendFlag: if true, try to append just our new lines to the file.
334+
* If false, write the whole available history.
335+
*
336+
* encodeFlag: whether to encode \n as \x01. For \s calls we don't wish
337+
* to do that, but must do so when saving the final history file.
319338
*/
320339
bool
321-
saveHistory(char *fname, bool encodeFlag)
340+
saveHistory(char *fname, int max_lines, bool appendFlag, bool encodeFlag)
322341
{
323342
#ifdef USE_READLINE
324343

@@ -335,14 +354,54 @@ saveHistory(char *fname, bool encodeFlag)
335354
encode_history();
336355

337356
/*
338-
* return value of write_history is not standardized across GNU
357+
* On newer versions of libreadline, truncate the history file as
358+
* needed and then append what we've added. This avoids overwriting
359+
* history from other concurrent sessions (although there are still
360+
* race conditions when two sessions exit at about the same time).
361+
* If we don't have those functions, fall back to write_history().
362+
*
363+
* Note: return value of write_history is not standardized across GNU
339364
* readline and libedit. Therefore, check for errno becoming set to
340-
* see if the write failed.
365+
* see if the write failed. Similarly for append_history.
341366
*/
342-
errno = 0;
343-
(void) write_history(fname);
344-
if (errno == 0)
345-
return true;
367+
#if defined(HAVE_HISTORY_TRUNCATE_FILE) && defined(HAVE_APPEND_HISTORY)
368+
if (appendFlag)
369+
{
370+
int nlines;
371+
int fd;
372+
373+
/* truncate previous entries if needed */
374+
if (max_lines >= 0)
375+
{
376+
nlines = Max(max_lines - history_lines_added, 0);
377+
(void) history_truncate_file(fname, nlines);
378+
}
379+
/* append_history fails if file doesn't already exist :-( */
380+
fd = open(fname, O_CREAT | O_WRONLY | PG_BINARY, 0600);
381+
if (fd >= 0)
382+
close(fd);
383+
/* append the appropriate number of lines */
384+
if (max_lines >= 0)
385+
nlines = Min(max_lines, history_lines_added);
386+
else
387+
nlines = history_lines_added;
388+
errno = 0;
389+
(void) append_history(nlines, fname);
390+
if (errno == 0)
391+
return true;
392+
}
393+
else
394+
#endif
395+
{
396+
/* truncate what we have ... */
397+
if (max_lines >= 0)
398+
stifle_history(max_lines);
399+
/* ... and overwrite file. Tough luck for concurrent sessions. */
400+
errno = 0;
401+
(void) write_history(fname);
402+
if (errno == 0)
403+
return true;
404+
}
346405

347406
psql_error("could not save history to file \"%s\": %s\n",
348407
fname, strerror(errno));
@@ -369,10 +428,7 @@ finishInput(int exitstatus, void *arg)
369428
int hist_size;
370429

371430
hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
372-
if (hist_size >= 0)
373-
stifle_history(hist_size);
374-
375-
saveHistory(psql_history, true);
431+
saveHistory(psql_history, hist_size, true, true);
376432
free(psql_history);
377433
psql_history = NULL;
378434
}

src/bin/psql/input.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/input.h,v 1.32 2009/08/24 16:18:13 tgl Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/input.h,v 1.33 2009/09/13 22:18:22 tgl Exp $
77
*/
88
#ifndef INPUT_H
99
#define INPUT_H
@@ -45,7 +45,7 @@ char *gets_interactive(const char *prompt);
4545
char *gets_fromFile(FILE *source);
4646

4747
void initializeInput(int flags);
48-
bool saveHistory(char *fname, bool encodeFlag);
48+
bool saveHistory(char *fname, int max_lines, bool appendFlag, bool encodeFlag);
4949

5050
void pg_append_history(const char *s, PQExpBuffer history_buf);
5151
void pg_send_history(PQExpBuffer history_buf);

src/include/pg_config.h.in

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@
7878
# define gettimeofday(a,b) gettimeofday(a)
7979
#endif
8080

81+
/* Define to 1 if you have the `append_history' function. */
82+
#undef HAVE_APPEND_HISTORY
83+
8184
/* Define to 1 if you have the `atexit' function. */
8285
#undef HAVE_ATEXIT
8386

@@ -212,6 +215,9 @@
212215
/* Define to 1 if you have the <history.h> header file. */
213216
#undef HAVE_HISTORY_H
214217

218+
/* Define to 1 if you have the `history_truncate_file' function. */
219+
#undef HAVE_HISTORY_TRUNCATE_FILE
220+
215221
/* Define to 1 if you have the <ieeefp.h> header file. */
216222
#undef HAVE_IEEEFP_H
217223

@@ -378,9 +384,6 @@
378384
/* Define to 1 if you have the `readlink' function. */
379385
#undef HAVE_READLINK
380386

381-
/* Define to 1 if you have the `replace_history_entry' function. */
382-
#undef HAVE_REPLACE_HISTORY_ENTRY
383-
384387
/* Define to 1 if you have the `rint' function. */
385388
#undef HAVE_RINT
386389

src/include/pg_config.h.win32

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,6 @@
306306
/* Define to 1 if you have the `readlink' function. */
307307
/* #undef HAVE_READLINK */
308308

309-
/* Define to 1 if you have the `replace_history_entry' function. */
310-
/* #undef HAVE_REPLACE_HISTORY_ENTRY */
311-
312309
/* Define to 1 if you have the `rint' function. */
313310
/*#define HAVE_RINT 1*/
314311

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy