|
|
|
/*
|
|
|
|
* psql - the PostgreSQL interactive terminal
|
|
|
|
*
|
|
|
|
* Copyright (c) 2000-2015, PostgreSQL Global Development Group
|
|
|
|
*
|
|
|
|
* src/bin/psql/input.c
|
|
|
|
*/
|
|
|
|
#include "postgres_fe.h"
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
#include "input.h"
|
* Includes tab completion. It's not magic, but it's very cool. At any
rate
it's better than what used to be there.
* Does proper SQL "host variable" substitution as pointed out by Andreas
Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
and ';' are treated (escape with \ to send to backend). This does
_not_
affect the '::' cast operator, but perhaps others that contain : or ;
(but there are none right now).
* To show description with a <something> listing, append '?' to command
name, e.g., \df?. This seemed to be the convenient and logical
solution.
Or append a '+' to see more useless information, e.g., \df+.
* Fixed fflush()'ing bug pointed out by Jan during the regression test
discussion.
* Added LastOid variable. This ought to take care of TODO item "Add a
function to return the last inserted oid, for use in psql scripts"
(under CLIENTS)
E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid
* \d command shows constraints, rules, and triggers defined on the table
(in addition to indices)
* Various fixes, optimizations, corrections
* Documentation update as well
Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.
Enjoy.
--
Peter Eisentraut Sernanders väg 10:115
26 years ago
|
|
|
#include "settings.h"
|
|
|
|
#include "tab-complete.h"
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
#define PSQLHISTORY ".psql_history"
|
|
|
|
#else
|
|
|
|
#define PSQLHISTORY "psql_history"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Runtime options for turning off readline and history */
|
|
|
|
/* (of course there is no runtime command for doing that :) */
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
static bool useReadline;
|
|
|
|
static bool useHistory;
|
|
|
|
|
|
|
|
static char *psql_history;
|
|
|
|
|
|
|
|
static int history_lines_added;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Preserve newlines in saved queries by mapping '\n' to NL_IN_HISTORY
|
|
|
|
*
|
|
|
|
* It is assumed NL_IN_HISTORY will never be entered by the user
|
|
|
|
* nor appear inside a multi-byte string. 0x00 is not properly
|
|
|
|
* handled by the readline routines so it can not be used
|
|
|
|
* for this purpose.
|
|
|
|
*/
|
|
|
|
#define NL_IN_HISTORY 0x01
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void finishInput(void);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* gets_interactive()
|
|
|
|
*
|
|
|
|
* Gets a line of interactive input, using readline if desired.
|
|
|
|
* The result is a malloc'd string.
|
|
|
|
*
|
|
|
|
* Caller *must* have set up sigint_interrupt_jmp before calling.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gets_interactive(const char *prompt)
|
|
|
|
{
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
if (useReadline)
|
|
|
|
{
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
/* Enable SIGINT to longjmp to sigint_interrupt_jmp */
|
|
|
|
sigint_interrupt_enabled = true;
|
|
|
|
|
|
|
|
/* On some platforms, readline is declared as readline(char *) */
|
|
|
|
result = readline((char *) prompt);
|
|
|
|
|
|
|
|
/* Disable SIGINT again */
|
|
|
|
sigint_interrupt_enabled = false;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fputs(prompt, stdout);
|
|
|
|
fflush(stdout);
|
|
|
|
return gets_fromFile(stdin);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Append the line to the history buffer, making sure there is a trailing '\n'
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pg_append_history(const char *s, PQExpBuffer history_buf)
|
|
|
|
{
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
if (useHistory && s)
|
|
|
|
{
|
|
|
|
appendPQExpBufferStr(history_buf, s);
|
|
|
|
if (!s[0] || s[strlen(s) - 1] != '\n')
|
|
|
|
appendPQExpBufferChar(history_buf, '\n');
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Emit accumulated history entry to readline's history mechanism,
|
|
|
|
* then reset the buffer to empty.
|
|
|
|
*
|
|
|
|
* Note: we write nothing if history_buf is empty, so extra calls to this
|
|
|
|
* function don't hurt. There must have been at least one line added by
|
|
|
|
* pg_append_history before we'll do anything.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pg_send_history(PQExpBuffer history_buf)
|
|
|
|
{
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
static char *prev_hist = NULL;
|
|
|
|
|
|
|
|
char *s = history_buf->data;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Trim any trailing \n's (OK to scribble on history_buf) */
|
|
|
|
for (i = strlen(s) - 1; i >= 0 && s[i] == '\n'; i--)
|
|
|
|
;
|
|
|
|
s[i + 1] = '\0';
|
|
|
|
|
|
|
|
if (useHistory && s[0])
|
|
|
|
{
|
|
|
|
if (((pset.histcontrol & hctl_ignorespace) &&
|
|
|
|
s[0] == ' ') ||
|
|
|
|
((pset.histcontrol & hctl_ignoredups) &&
|
|
|
|
prev_hist && strcmp(s, prev_hist) == 0))
|
|
|
|
{
|
|
|
|
/* Ignore this line as far as history is concerned */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Save each previous line for ignoredups processing */
|
|
|
|
if (prev_hist)
|
|
|
|
free(prev_hist);
|
|
|
|
prev_hist = pg_strdup(s);
|
|
|
|
/* And send it to readline */
|
|
|
|
add_history(s);
|
|
|
|
/* Count lines added to history for use later */
|
|
|
|
history_lines_added++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resetPQExpBuffer(history_buf);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* gets_fromFile
|
|
|
|
*
|
|
|
|
* Gets a line of noninteractive input from a file (which could be stdin).
|
|
|
|
* The result is a malloc'd string, or NULL on EOF or input error.
|
|
|
|
*
|
|
|
|
* Caller *must* have set up sigint_interrupt_jmp before calling.
|
|
|
|
*
|
|
|
|
* Note: we re-use a static PQExpBuffer for each call. This is to avoid
|
|
|
|
* leaking memory if interrupted by SIGINT.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
gets_fromFile(FILE *source)
|
|
|
|
{
|
|
|
|
static PQExpBuffer buffer = NULL;
|
|
|
|
|
|
|
|
char line[1024];
|
|
|
|
|
|
|
|
if (buffer == NULL) /* first time through? */
|
|
|
|
buffer = createPQExpBuffer();
|
|
|
|
else
|
|
|
|
resetPQExpBuffer(buffer);
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
/* Enable SIGINT to longjmp to sigint_interrupt_jmp */
|
|
|
|
sigint_interrupt_enabled = true;
|
|
|
|
|
|
|
|
/* Get some data */
|
|
|
|
result = fgets(line, sizeof(line), source);
|
|
|
|
|
|
|
|
/* Disable SIGINT again */
|
|
|
|
sigint_interrupt_enabled = false;
|
|
|
|
|
|
|
|
/* EOF or error? */
|
|
|
|
if (result == NULL)
|
|
|
|
{
|
|
|
|
if (ferror(source))
|
|
|
|
{
|
|
|
|
psql_error("could not read from input file: %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
appendPQExpBufferStr(buffer, line);
|
|
|
|
|
|
|
|
if (PQExpBufferBroken(buffer))
|
|
|
|
{
|
|
|
|
psql_error("out of memory\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* EOL? */
|
|
|
|
if (buffer->data[buffer->len - 1] == '\n')
|
|
|
|
{
|
|
|
|
buffer->data[buffer->len - 1] = '\0';
|
|
|
|
return pg_strdup(buffer->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffer->len > 0) /* EOF after reading some bufferload(s) */
|
|
|
|
return pg_strdup(buffer->data);
|
|
|
|
|
|
|
|
/* EOF, so return null */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef USE_READLINE
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
|
|
|
|
/*
|
|
|
|
* Macros to iterate over each element of the history list in order
|
|
|
|
*
|
|
|
|
* You would think this would be simple enough, but in its inimitable fashion
|
|
|
|
* libedit has managed to break it: in libreadline we must use next_history()
|
|
|
|
* to go from oldest to newest, but in libedit we must use previous_history().
|
|
|
|
* To detect what to do, we make a trial call of previous_history(): if it
|
|
|
|
* fails, then either next_history() is what to use, or there's zero or one
|
|
|
|
* history entry so that it doesn't matter which direction we go.
|
|
|
|
*
|
|
|
|
* In case that wasn't disgusting enough: the code below is not as obvious as
|
|
|
|
* it might appear. In some libedit releases history_set_pos(0) fails until
|
|
|
|
* at least one add_history() call has been done. This is not an issue for
|
|
|
|
* printHistory() or encode_history(), which cannot be invoked before that has
|
|
|
|
* happened. In decode_history(), that's not so, and what actually happens is
|
|
|
|
* that we are sitting on the newest entry to start with, previous_history()
|
|
|
|
* fails, and we iterate over all the entries using next_history(). So the
|
|
|
|
* decode_history() loop iterates over the entries in the wrong order when
|
|
|
|
* using such a libedit release, and if there were another attempt to use
|
|
|
|
* BEGIN_ITERATE_HISTORY() before some add_history() call had happened, it
|
|
|
|
* wouldn't work. Fortunately we don't care about either of those things.
|
|
|
|
*
|
|
|
|
* Usage pattern is:
|
|
|
|
*
|
|
|
|
* BEGIN_ITERATE_HISTORY(varname);
|
|
|
|
* {
|
|
|
|
* loop body referencing varname->line;
|
|
|
|
* }
|
|
|
|
* END_ITERATE_HISTORY();
|
|
|
|
*/
|
|
|
|
#define BEGIN_ITERATE_HISTORY(VARNAME) \
|
|
|
|
do { \
|
|
|
|
HIST_ENTRY *VARNAME; \
|
|
|
|
bool use_prev_; \
|
|
|
|
\
|
|
|
|
history_set_pos(0); \
|
|
|
|
use_prev_ = (previous_history() != NULL); \
|
|
|
|
history_set_pos(0); \
|
|
|
|
for (VARNAME = current_history(); VARNAME != NULL; \
|
|
|
|
VARNAME = use_prev_ ? previous_history() : next_history()) \
|
|
|
|
{ \
|
|
|
|
(void) 0
|
|
|
|
|
|
|
|
#define END_ITERATE_HISTORY() \
|
|
|
|
} \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert newlines to NL_IN_HISTORY for safe saving in readline history file
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
encode_history(void)
|
|
|
|
{
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
BEGIN_ITERATE_HISTORY(cur_hist);
|
|
|
|
{
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
char *cur_ptr;
|
|
|
|
|
|
|
|
/* some platforms declare HIST_ENTRY.line as const char * */
|
|
|
|
for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
{
|
|
|
|
if (*cur_ptr == '\n')
|
|
|
|
*cur_ptr = NL_IN_HISTORY;
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
}
|
|
|
|
}
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
END_ITERATE_HISTORY();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reverse the above encoding
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
decode_history(void)
|
|
|
|
{
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
BEGIN_ITERATE_HISTORY(cur_hist);
|
|
|
|
{
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
char *cur_ptr;
|
|
|
|
|
|
|
|
/* some platforms declare HIST_ENTRY.line as const char * */
|
|
|
|
for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
{
|
|
|
|
if (*cur_ptr == NL_IN_HISTORY)
|
|
|
|
*cur_ptr = '\n';
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
}
|
|
|
|
}
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
END_ITERATE_HISTORY();
|
|
|
|
}
|
|
|
|
#endif /* USE_READLINE */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put any startup stuff related to input in here. It's good to maintain
|
|
|
|
* abstraction this way.
|
|
|
|
*
|
|
|
|
* The only "flag" right now is 1 for use readline & history.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
initializeInput(int flags)
|
|
|
|
{
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
if (flags & 1)
|
|
|
|
{
|
|
|
|
const char *histfile;
|
|
|
|
char home[MAXPGPATH];
|
|
|
|
|
|
|
|
useReadline = true;
|
|
|
|
initialize_readline();
|
|
|
|
|
|
|
|
useHistory = true;
|
|
|
|
using_history();
|
|
|
|
history_lines_added = 0;
|
|
|
|
|
|
|
|
histfile = GetVariable(pset.vars, "HISTFILE");
|
|
|
|
|
|
|
|
if (histfile == NULL)
|
|
|
|
{
|
|
|
|
char *envhist;
|
|
|
|
|
|
|
|
envhist = getenv("PSQL_HISTORY");
|
|
|
|
if (envhist != NULL && strlen(envhist) > 0)
|
|
|
|
histfile = envhist;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (histfile == NULL)
|
|
|
|
{
|
|
|
|
if (get_home_path(home))
|
|
|
|
psql_history = psprintf("%s/%s", home, PSQLHISTORY);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
psql_history = pg_strdup(histfile);
|
|
|
|
expand_tilde(&psql_history);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (psql_history)
|
|
|
|
{
|
|
|
|
read_history(psql_history);
|
|
|
|
decode_history();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
atexit(finishInput);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
* This function saves the readline history when psql exits.
|
|
|
|
*
|
|
|
|
* fname: pathname of history file. (Should really be "const char *",
|
|
|
|
* but some ancient versions of readline omit the const-decoration.)
|
|
|
|
*
|
|
|
|
* max_lines: if >= 0, limit history file to that many entries.
|
|
|
|
*/
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
static bool
|
|
|
|
saveHistory(char *fname, int max_lines)
|
|
|
|
{
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Suppressing the write attempt when HISTFILE is set to /dev/null may
|
|
|
|
* look like a negligible optimization, but it's necessary on e.g. Darwin,
|
|
|
|
* where write_history will fail because it tries to chmod the target
|
|
|
|
* file.
|
|
|
|
*/
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
if (strcmp(fname, DEVNULL) != 0)
|
|
|
|
{
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
/*
|
|
|
|
* Encode \n, since otherwise readline will reload multiline history
|
|
|
|
* entries as separate lines. (libedit doesn't really need this, but
|
|
|
|
* we do it anyway since it's too hard to tell which implementation we
|
|
|
|
* are using.)
|
|
|
|
*/
|
|
|
|
encode_history();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On newer versions of libreadline, truncate the history file as
|
|
|
|
* needed and then append what we've added. This avoids overwriting
|
|
|
|
* history from other concurrent sessions (although there are still
|
|
|
|
* race conditions when two sessions exit at about the same time). If
|
|
|
|
* we don't have those functions, fall back to write_history().
|
|
|
|
*
|
|
|
|
* Note: return value of write_history is not standardized across GNU
|
|
|
|
* readline and libedit. Therefore, check for errno becoming set to
|
|
|
|
* see if the write failed. Similarly for append_history.
|
|
|
|
*/
|
|
|
|
#if defined(HAVE_HISTORY_TRUNCATE_FILE) && defined(HAVE_APPEND_HISTORY)
|
|
|
|
{
|
|
|
|
int nlines;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
/* truncate previous entries if needed */
|
|
|
|
if (max_lines >= 0)
|
|
|
|
{
|
|
|
|
nlines = Max(max_lines - history_lines_added, 0);
|
|
|
|
(void) history_truncate_file(fname, nlines);
|
|
|
|
}
|
|
|
|
/* append_history fails if file doesn't already exist :-( */
|
|
|
|
fd = open(fname, O_CREAT | O_WRONLY | PG_BINARY, 0600);
|
|
|
|
if (fd >= 0)
|
|
|
|
close(fd);
|
|
|
|
/* append the appropriate number of lines */
|
|
|
|
if (max_lines >= 0)
|
|
|
|
nlines = Min(max_lines, history_lines_added);
|
|
|
|
else
|
|
|
|
nlines = history_lines_added;
|
|
|
|
errno = 0;
|
|
|
|
(void) append_history(nlines, fname);
|
|
|
|
if (errno == 0)
|
|
|
|
return true;
|
|
|
|
}
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
#else /* don't have append support */
|
|
|
|
{
|
|
|
|
/* truncate what we have ... */
|
|
|
|
if (max_lines >= 0)
|
|
|
|
stifle_history(max_lines);
|
|
|
|
/* ... and overwrite file. Tough luck for concurrent sessions. */
|
|
|
|
errno = 0;
|
|
|
|
(void) write_history(fname);
|
|
|
|
if (errno == 0)
|
|
|
|
return true;
|
|
|
|
}
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
#endif
|
|
|
|
|
|
|
|
psql_error("could not save history to file \"%s\": %s\n",
|
|
|
|
fname, strerror(errno));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
/*
|
|
|
|
* Print history to the specified file, or to the console if fname is NULL
|
|
|
|
* (psql \s command)
|
|
|
|
*
|
|
|
|
* We used to use saveHistory() for this purpose, but that doesn't permit
|
|
|
|
* use of a pager; moreover libedit's implementation behaves incompatibly
|
|
|
|
* (preferring to encode its output) and may fail outright when the target
|
|
|
|
* file is specified as /dev/tty.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
printHistory(const char *fname, unsigned short int pager)
|
|
|
|
{
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
FILE *output;
|
|
|
|
bool is_pager;
|
|
|
|
|
|
|
|
if (!useHistory)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (fname == NULL)
|
|
|
|
{
|
|
|
|
/* use pager, if enabled, when printing to console */
|
|
|
|
output = PageOutput(INT_MAX, pager);
|
|
|
|
is_pager = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
output = fopen(fname, "w");
|
|
|
|
if (output == NULL)
|
|
|
|
{
|
|
|
|
psql_error("could not save history to file \"%s\": %s\n",
|
|
|
|
fname, strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
is_pager = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
BEGIN_ITERATE_HISTORY(cur_hist);
|
|
|
|
{
|
|
|
|
fprintf(output, "%s\n", cur_hist->line);
|
|
|
|
}
|
|
|
|
END_ITERATE_HISTORY();
|
|
|
|
|
|
|
|
if (is_pager)
|
|
|
|
ClosePager(output);
|
|
|
|
else
|
|
|
|
fclose(output);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
psql_error("history is not supported by this installation\n");
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
finishInput(void)
|
|
|
|
{
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
if (useHistory && psql_history)
|
|
|
|
{
|
|
|
|
int hist_size;
|
|
|
|
|
|
|
|
hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
|
Fix psql \s to work with recent libedit, and add pager support.
psql's \s (print command history) doesn't work at all with recent libedit
versions when printing to the terminal, because libedit tries to do an
fchmod() on the target file which will fail if the target is /dev/tty.
(We'd already noted this in the context of the target being /dev/null.)
Even before that, it didn't work pleasantly, because libedit likes to
encode the command history file (to ensure successful reloading), which
renders it nigh unreadable, not to mention significantly different-looking
depending on exactly which libedit version you have. So let's forget using
write_history() for this purpose, and instead print the data ourselves,
using logic similar to that used to iterate over the history for newline
encoding/decoding purposes.
While we're at it, insert the ability to use the pager when \s is printing
to the terminal. This has been an acknowledged shortcoming of \s for many
years, so while you could argue it's not exactly a back-patchable bug fix
it still seems like a good improvement. Anyone who's seriously annoyed
at this can use "\s /dev/tty" or local equivalent to get the old behavior.
Experimentation with this showed that the history iteration logic was
actually rather broken when used with libedit. It turns out that with
libedit you have to use previous_history() not next_history() to advance
to more recent history entries. The easiest and most robust fix for this
seems to be to make a run-time test to verify which function to call.
We had not noticed this because libedit doesn't really need the newline
encoding logic: its own encoding ensures that command entries containing
newlines are reloaded correctly (unlike libreadline). So the effective
behavior with recent libedits was that only the oldest history entry got
newline-encoded or newline-decoded. However, because of yet other bugs in
history_set_pos(), some old versions of libedit allowed the existing loop
logic to reach entries besides the oldest, which means there may be libedit
~/.psql_history files out there containing encoded newlines in more than
just the oldest entry. To ensure we can reload such files, it seems
appropriate to back-patch this fix, even though that will result in some
incompatibility with older psql versions (ie, multiline history entries
written by a psql with this fix will look corrupted to a psql without it,
if its libedit is reasonably up to date).
Stepan Rutz and Tom Lane
11 years ago
|
|
|
(void) saveHistory(psql_history, hist_size);
|
|
|
|
free(psql_history);
|
|
|
|
psql_history = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|