3
3
*
4
4
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
5
5
*
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 $
7
7
*/
8
8
#include "postgres_fe.h"
9
9
10
+ #ifndef WIN32
11
+ #include <unistd.h>
12
+ #endif
13
+ #include <fcntl.h>
14
+
10
15
#include "input.h"
11
16
#include "settings.h"
12
17
#include "tab-complete.h"
23
28
#ifdef USE_READLINE
24
29
static bool useReadline ;
25
30
static bool useHistory ;
26
- char * psql_history ;
31
+
32
+ static char * psql_history ;
33
+
34
+ static int history_lines_added ;
35
+
27
36
28
37
/*
29
38
* Preserve newlines in saved queries by mapping '\n' to NL_IN_HISTORY
@@ -135,6 +144,8 @@ pg_send_history(PQExpBuffer history_buf)
135
144
prev_hist = pg_strdup (s );
136
145
/* And send it to readline */
137
146
add_history (s );
147
+ /* Count lines added to history for use later */
148
+ history_lines_added ++ ;
138
149
}
139
150
}
140
151
@@ -276,6 +287,7 @@ initializeInput(int flags)
276
287
277
288
useHistory = true;
278
289
using_history ();
290
+ history_lines_added = 0 ;
279
291
280
292
histfile = GetVariable (pset .vars , "HISTFILE" );
281
293
if (histfile == NULL )
@@ -310,15 +322,22 @@ initializeInput(int flags)
310
322
311
323
312
324
/*
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.
315
332
*
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.
319
338
*/
320
339
bool
321
- saveHistory (char * fname , bool encodeFlag )
340
+ saveHistory (char * fname , int max_lines , bool appendFlag , bool encodeFlag )
322
341
{
323
342
#ifdef USE_READLINE
324
343
@@ -335,14 +354,54 @@ saveHistory(char *fname, bool encodeFlag)
335
354
encode_history ();
336
355
337
356
/*
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
339
364
* 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.
341
366
*/
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
+ }
346
405
347
406
psql_error ("could not save history to file \"%s\": %s\n" ,
348
407
fname , strerror (errno ));
@@ -369,10 +428,7 @@ finishInput(int exitstatus, void *arg)
369
428
int hist_size ;
370
429
371
430
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);
376
432
free (psql_history );
377
433
psql_history = NULL ;
378
434
}
0 commit comments