mirror of
https://github.com/postgres/postgres.git
synced 2025-06-01 00:01:20 -04:00
Code review for psql multiline history patch(es). Fix memory leak,
failure to enter commands in history if canceled by control-C, other infelicities.
This commit is contained in:
parent
bf64a37909
commit
e2e2a9db4c
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.169 2006/06/07 22:24:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.170 2006/06/11 23:06:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
@ -1361,7 +1361,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* read file back in */
|
/* read file back into query_buf */
|
||||||
char line[1024];
|
char line[1024];
|
||||||
|
|
||||||
resetPQExpBuffer(query_buf);
|
resetPQExpBuffer(query_buf);
|
||||||
@ -1374,14 +1374,6 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf)
|
|||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_READLINE
|
|
||||||
#ifdef HAVE_REPLACE_HISTORY_ENTRY
|
|
||||||
|
|
||||||
replace_history_entry(where_history(), query_buf->data, NULL);
|
|
||||||
#else
|
|
||||||
add_history(query_buf->data);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
fclose(stream);
|
fclose(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,10 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.110 2006/03/05 15:58:51 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.111 2006/06/11 23:06:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "pqexpbuffer.h"
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.53 2006/03/21 13:38:12 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.54 2006/06/11 23:06:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
#include "pqexpbuffer.h"
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "pqexpbuffer.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "tab-complete.h"
|
#include "tab-complete.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@ -78,9 +78,23 @@ GetHistControlConfig(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static char *
|
/*
|
||||||
gets_basic(const char prompt[])
|
* gets_interactive()
|
||||||
|
*
|
||||||
|
* Gets a line of interactive input, using readline if desired.
|
||||||
|
* The result is malloc'ed.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
gets_interactive(const char *prompt)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_READLINE
|
||||||
|
if (useReadline)
|
||||||
|
{
|
||||||
|
/* On some platforms, readline is declared as readline(char *) */
|
||||||
|
return readline((char *) prompt);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
fputs(prompt, stdout);
|
fputs(prompt, stdout);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
return gets_fromFile(stdin);
|
return gets_fromFile(stdin);
|
||||||
@ -88,100 +102,65 @@ gets_basic(const char prompt[])
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gets_interactive()
|
* Append the line to the history buffer, making sure there is a trailing '\n'
|
||||||
*
|
|
||||||
* Gets a line of interactive input, using readline of desired.
|
|
||||||
* The result is malloc'ed.
|
|
||||||
*/
|
*/
|
||||||
char *
|
|
||||||
gets_interactive(const char *prompt)
|
|
||||||
{
|
|
||||||
#ifdef USE_READLINE
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
if (useReadline)
|
|
||||||
/* On some platforms, readline is declared as readline(char *) */
|
|
||||||
s = readline((char *) prompt);
|
|
||||||
else
|
|
||||||
s = gets_basic(prompt);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
#else
|
|
||||||
return gets_basic(prompt);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Put the line in the history buffer and also add the trailing \n */
|
|
||||||
void
|
void
|
||||||
pg_append_history(char *s, PQExpBuffer history_buf)
|
pg_append_history(const char *s, PQExpBuffer history_buf)
|
||||||
{
|
{
|
||||||
#ifdef USE_READLINE
|
#ifdef USE_READLINE
|
||||||
|
if (useHistory && s && s[0])
|
||||||
int slen;
|
|
||||||
if (useReadline && useHistory && s && s[0])
|
|
||||||
{
|
{
|
||||||
slen = strlen(s);
|
appendPQExpBufferStr(history_buf, s);
|
||||||
if (s[slen-1] == '\n')
|
if (s[strlen(s) - 1] != '\n')
|
||||||
appendPQExpBufferStr(history_buf, s);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(history_buf, s);
|
|
||||||
appendPQExpBufferChar(history_buf, '\n');
|
appendPQExpBufferChar(history_buf, '\n');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Feed the string to readline
|
* 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
|
void
|
||||||
pg_write_history(char *s)
|
pg_send_history(PQExpBuffer history_buf)
|
||||||
{
|
{
|
||||||
#ifdef USE_READLINE
|
#ifdef USE_READLINE
|
||||||
static char *prev_hist;
|
static char *prev_hist = NULL;
|
||||||
int slen, i;
|
|
||||||
|
char *s = history_buf->data;
|
||||||
if (useReadline && useHistory )
|
|
||||||
|
if (useHistory && s[0])
|
||||||
{
|
{
|
||||||
enum histcontrol HC;
|
enum histcontrol HC = GetHistControlConfig();
|
||||||
|
|
||||||
/* Flushing of empty buffer should do nothing */
|
|
||||||
if (*s == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
prev_hist = NULL;
|
|
||||||
|
|
||||||
HC = GetHistControlConfig();
|
|
||||||
|
|
||||||
if (((HC & hctl_ignorespace) && s[0] == ' ') ||
|
if (((HC & hctl_ignorespace) && s[0] == ' ') ||
|
||||||
((HC & hctl_ignoredups) && prev_hist && strcmp(s, prev_hist) == 0))
|
((HC & hctl_ignoredups) && prev_hist && strcmp(s, prev_hist) == 0))
|
||||||
{
|
{
|
||||||
/* Ignore this line as far as history is concerned */
|
/* Ignore this line as far as history is concerned */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free(prev_hist);
|
int i;
|
||||||
slen = strlen(s);
|
|
||||||
/* Trim the trailing \n's */
|
/* Trim any trailing \n's (OK to scribble on history_buf) */
|
||||||
for (i = slen-1; i >= 0 && s[i] == '\n'; i--)
|
for (i = strlen(s)-1; i >= 0 && s[i] == '\n'; i--)
|
||||||
;
|
;
|
||||||
s[i + 1] = '\0';
|
s[i + 1] = '\0';
|
||||||
|
/* Save each previous line for ignoredups processing */
|
||||||
|
if (prev_hist)
|
||||||
|
free(prev_hist);
|
||||||
prev_hist = pg_strdup(s);
|
prev_hist = pg_strdup(s);
|
||||||
|
/* And send it to readline */
|
||||||
add_history(s);
|
add_history(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
resetPQExpBuffer(history_buf);
|
||||||
pg_clear_history(PQExpBuffer history_buf)
|
|
||||||
{
|
|
||||||
#ifdef USE_READLINE
|
|
||||||
if (useReadline && useHistory)
|
|
||||||
resetPQExpBuffer(history_buf);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +198,9 @@ gets_fromFile(FILE *source)
|
|||||||
|
|
||||||
|
|
||||||
#ifdef USE_READLINE
|
#ifdef USE_READLINE
|
||||||
|
/*
|
||||||
|
* Convert newlines to NL_IN_HISTORY for safe saving in readline history file
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
encode_history(void)
|
encode_history(void)
|
||||||
{
|
{
|
||||||
@ -232,6 +214,9 @@ encode_history(void)
|
|||||||
*cur_ptr = NL_IN_HISTORY;
|
*cur_ptr = NL_IN_HISTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reverse the above encoding
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
decode_history(void)
|
decode_history(void)
|
||||||
{
|
{
|
||||||
@ -285,9 +270,10 @@ initializeInput(int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (psql_history)
|
if (psql_history)
|
||||||
|
{
|
||||||
read_history(psql_history);
|
read_history(psql_history);
|
||||||
|
decode_history();
|
||||||
decode_history();
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -299,11 +285,13 @@ initializeInput(int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This function is designed for saving the readline history when user
|
/*
|
||||||
* run \s command or when psql finishes.
|
* This function is for saving the readline history when user
|
||||||
* We have an argument named encodeFlag to handle those cases differently
|
* runs \s command or when psql finishes.
|
||||||
* In that case of call via \s we don't really need to encode \n as \x01,
|
*
|
||||||
* but when we save history for Readline we must do that conversion
|
* We have an argument named encodeFlag to handle the cases differently.
|
||||||
|
* In case of call via \s we don't really need to encode \n as \x01,
|
||||||
|
* but when we save history for Readline we must do that conversion.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
saveHistory(char *fname, bool encodeFlag)
|
saveHistory(char *fname, bool encodeFlag)
|
||||||
@ -316,7 +304,8 @@ saveHistory(char *fname, bool encodeFlag)
|
|||||||
if (write_history(fname) == 0)
|
if (write_history(fname) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
psql_error("could not save history to file \"%s\": %s\n", fname, strerror(errno));
|
psql_error("could not save history to file \"%s\": %s\n",
|
||||||
|
fname, strerror(errno));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
psql_error("history is not supported by this installation\n");
|
psql_error("history is not supported by this installation\n");
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/input.h,v 1.27 2006/03/21 13:38:12 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/input.h,v 1.28 2006/06/11 23:06:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef INPUT_H
|
#ifndef INPUT_H
|
||||||
#define INPUT_H
|
#define INPUT_H
|
||||||
@ -32,6 +32,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "pqexpbuffer.h"
|
||||||
|
|
||||||
|
|
||||||
char *gets_interactive(const char *prompt);
|
char *gets_interactive(const char *prompt);
|
||||||
char *gets_fromFile(FILE *source);
|
char *gets_fromFile(FILE *source);
|
||||||
@ -39,9 +41,7 @@ char *gets_fromFile(FILE *source);
|
|||||||
void initializeInput(int flags);
|
void initializeInput(int flags);
|
||||||
bool saveHistory(char *fname, bool encodeFlag);
|
bool saveHistory(char *fname, bool encodeFlag);
|
||||||
|
|
||||||
void pg_append_history(char *s, PQExpBuffer history_buf);
|
void pg_append_history(const char *s, PQExpBuffer history_buf);
|
||||||
void pg_clear_history(PQExpBuffer history_buf);
|
void pg_send_history(PQExpBuffer history_buf);
|
||||||
void pg_write_history(char *s);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INPUT_H */
|
#endif /* INPUT_H */
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.78 2006/06/07 13:18:37 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.79 2006/06/11 23:06:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "mainloop.h"
|
#include "mainloop.h"
|
||||||
@ -37,12 +37,12 @@ MainLoop(FILE *source)
|
|||||||
PQExpBuffer query_buf; /* buffer for query being accumulated */
|
PQExpBuffer query_buf; /* buffer for query being accumulated */
|
||||||
PQExpBuffer previous_buf; /* if there isn't anything in the new buffer
|
PQExpBuffer previous_buf; /* if there isn't anything in the new buffer
|
||||||
* yet, use this one for \e, etc. */
|
* yet, use this one for \e, etc. */
|
||||||
PQExpBuffer history_buf;
|
PQExpBuffer history_buf; /* earlier lines of a multi-line command,
|
||||||
|
* not yet saved to readline history */
|
||||||
char *line; /* current line of input */
|
char *line; /* current line of input */
|
||||||
int added_nl_pos;
|
int added_nl_pos;
|
||||||
bool success;
|
bool success;
|
||||||
|
bool line_saved_in_history;
|
||||||
volatile bool line_saved_in_history;
|
|
||||||
volatile int successResult = EXIT_SUCCESS;
|
volatile int successResult = EXIT_SUCCESS;
|
||||||
volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
|
volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
|
||||||
volatile promptStatus_t prompt_status = PROMPT_READY;
|
volatile promptStatus_t prompt_status = PROMPT_READY;
|
||||||
@ -70,7 +70,6 @@ MainLoop(FILE *source)
|
|||||||
query_buf = createPQExpBuffer();
|
query_buf = createPQExpBuffer();
|
||||||
previous_buf = createPQExpBuffer();
|
previous_buf = createPQExpBuffer();
|
||||||
history_buf = createPQExpBuffer();
|
history_buf = createPQExpBuffer();
|
||||||
|
|
||||||
if (!query_buf || !previous_buf || !history_buf)
|
if (!query_buf || !previous_buf || !history_buf)
|
||||||
{
|
{
|
||||||
psql_error("out of memory\n");
|
psql_error("out of memory\n");
|
||||||
@ -80,8 +79,6 @@ MainLoop(FILE *source)
|
|||||||
/* main loop to get queries and execute them */
|
/* main loop to get queries and execute them */
|
||||||
while (successResult == EXIT_SUCCESS)
|
while (successResult == EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
line_saved_in_history = false;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Welcome code for Control-C
|
* Welcome code for Control-C
|
||||||
*/
|
*/
|
||||||
@ -97,7 +94,7 @@ MainLoop(FILE *source)
|
|||||||
successResult = EXIT_USER;
|
successResult = EXIT_USER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pg_clear_history(history_buf);
|
|
||||||
cancel_pressed = false;
|
cancel_pressed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,8 +110,6 @@ MainLoop(FILE *source)
|
|||||||
count_eof = 0;
|
count_eof = 0;
|
||||||
slashCmdStatus = PSQL_CMD_UNKNOWN;
|
slashCmdStatus = PSQL_CMD_UNKNOWN;
|
||||||
prompt_status = PROMPT_READY;
|
prompt_status = PROMPT_READY;
|
||||||
if (pset.cur_cmd_interactive)
|
|
||||||
pg_write_history(history_buf->data);
|
|
||||||
|
|
||||||
if (pset.cur_cmd_interactive)
|
if (pset.cur_cmd_interactive)
|
||||||
putc('\n', stdout);
|
putc('\n', stdout);
|
||||||
@ -135,33 +130,10 @@ MainLoop(FILE *source)
|
|||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
if (slashCmdStatus == PSQL_CMD_NEWEDIT)
|
/*
|
||||||
{
|
* get another line
|
||||||
/*
|
*/
|
||||||
* just returned from editing the line? then just copy to the
|
if (pset.cur_cmd_interactive)
|
||||||
* input buffer
|
|
||||||
*/
|
|
||||||
line = pg_strdup(query_buf->data);
|
|
||||||
/* reset parsing state since we are rescanning whole line */
|
|
||||||
resetPQExpBuffer(query_buf);
|
|
||||||
psql_scan_reset(scan_state);
|
|
||||||
slashCmdStatus = PSQL_CMD_UNKNOWN;
|
|
||||||
prompt_status = PROMPT_READY;
|
|
||||||
|
|
||||||
if (pset.cur_cmd_interactive)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Pass all the contents of history_buf to readline
|
|
||||||
* and free the history buffer.
|
|
||||||
*/
|
|
||||||
pg_write_history(history_buf->data);
|
|
||||||
pg_clear_history(history_buf);
|
|
||||||
pg_write_history(line);
|
|
||||||
line_saved_in_history = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* otherwise, get another line */
|
|
||||||
else if (pset.cur_cmd_interactive)
|
|
||||||
{
|
{
|
||||||
/* May need to reset prompt, eg after \r command */
|
/* May need to reset prompt, eg after \r command */
|
||||||
if (query_buf->len == 0)
|
if (query_buf->len == 0)
|
||||||
@ -230,7 +202,8 @@ MainLoop(FILE *source)
|
|||||||
*/
|
*/
|
||||||
psql_scan_setup(scan_state, line, strlen(line));
|
psql_scan_setup(scan_state, line, strlen(line));
|
||||||
success = true;
|
success = true;
|
||||||
|
line_saved_in_history = false;
|
||||||
|
|
||||||
while (success || !die_on_error)
|
while (success || !die_on_error)
|
||||||
{
|
{
|
||||||
PsqlScanResult scan_result;
|
PsqlScanResult scan_result;
|
||||||
@ -247,6 +220,17 @@ MainLoop(FILE *source)
|
|||||||
(scan_result == PSCAN_EOL &&
|
(scan_result == PSCAN_EOL &&
|
||||||
GetVariableBool(pset.vars, "SINGLELINE")))
|
GetVariableBool(pset.vars, "SINGLELINE")))
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Save query in history. We use history_buf to accumulate
|
||||||
|
* multi-line queries into a single history entry.
|
||||||
|
*/
|
||||||
|
if (pset.cur_cmd_interactive && !line_saved_in_history)
|
||||||
|
{
|
||||||
|
pg_append_history(line, history_buf);
|
||||||
|
pg_send_history(history_buf);
|
||||||
|
line_saved_in_history = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* execute query */
|
/* execute query */
|
||||||
success = SendQuery(query_buf->data);
|
success = SendQuery(query_buf->data);
|
||||||
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
|
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
|
||||||
@ -265,12 +249,27 @@ MainLoop(FILE *source)
|
|||||||
* If we added a newline to query_buf, and nothing else has
|
* If we added a newline to query_buf, and nothing else has
|
||||||
* been inserted in query_buf by the lexer, then strip off the
|
* been inserted in query_buf by the lexer, then strip off the
|
||||||
* newline again. This avoids any change to query_buf when a
|
* newline again. This avoids any change to query_buf when a
|
||||||
* line contains only a backslash command.
|
* line contains only a backslash command. Also, in this
|
||||||
|
* situation we force out any previous lines as a separate
|
||||||
|
* history entry; we don't want SQL and backslash commands
|
||||||
|
* intermixed in history if at all possible.
|
||||||
*/
|
*/
|
||||||
if (query_buf->len == added_nl_pos)
|
if (query_buf->len == added_nl_pos)
|
||||||
|
{
|
||||||
query_buf->data[--query_buf->len] = '\0';
|
query_buf->data[--query_buf->len] = '\0';
|
||||||
|
pg_send_history(history_buf);
|
||||||
|
}
|
||||||
added_nl_pos = -1;
|
added_nl_pos = -1;
|
||||||
|
|
||||||
|
/* save backslash command in history */
|
||||||
|
if (pset.cur_cmd_interactive && !line_saved_in_history)
|
||||||
|
{
|
||||||
|
pg_append_history(line, history_buf);
|
||||||
|
pg_send_history(history_buf);
|
||||||
|
line_saved_in_history = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* execute backslash command */
|
||||||
slashCmdStatus = HandleSlashCmds(scan_state,
|
slashCmdStatus = HandleSlashCmds(scan_state,
|
||||||
query_buf->len > 0 ?
|
query_buf->len > 0 ?
|
||||||
query_buf : previous_buf);
|
query_buf : previous_buf);
|
||||||
@ -295,44 +294,32 @@ MainLoop(FILE *source)
|
|||||||
/* flush any paren nesting info after forced send */
|
/* flush any paren nesting info after forced send */
|
||||||
psql_scan_reset(scan_state);
|
psql_scan_reset(scan_state);
|
||||||
}
|
}
|
||||||
|
else if (slashCmdStatus == PSQL_CMD_NEWEDIT)
|
||||||
|
{
|
||||||
|
/* rescan query_buf as new input */
|
||||||
|
psql_scan_finish(scan_state);
|
||||||
|
free(line);
|
||||||
|
line = pg_strdup(query_buf->data);
|
||||||
|
resetPQExpBuffer(query_buf);
|
||||||
|
/* reset parsing state since we are rescanning whole line */
|
||||||
|
psql_scan_reset(scan_state);
|
||||||
|
psql_scan_setup(scan_state, line, strlen(line));
|
||||||
|
line_saved_in_history = false;
|
||||||
|
prompt_status = PROMPT_READY;
|
||||||
|
}
|
||||||
|
else if (slashCmdStatus == PSQL_CMD_TERMINATE)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* fall out of loop if lexer reached EOL */
|
||||||
* If we append to history a backslash command that is inside
|
if (scan_result == PSCAN_INCOMPLETE ||
|
||||||
* a multi-line query, then when we recall the history, the
|
|
||||||
* backslash command will make the query invalid, so we write
|
|
||||||
* backslash commands immediately rather than keeping them
|
|
||||||
* as part of the current multi-line query. We do the test
|
|
||||||
* down here so we can check for \g and other 'execute'
|
|
||||||
* backslash commands, which should be appended.
|
|
||||||
*/
|
|
||||||
if (!line_saved_in_history && pset.cur_cmd_interactive)
|
|
||||||
{
|
|
||||||
/* Sending a command (PSQL_CMD_SEND) zeros the length */
|
|
||||||
if (scan_result == PSCAN_BACKSLASH)
|
|
||||||
pg_write_history(line);
|
|
||||||
else
|
|
||||||
pg_append_history(line, history_buf);
|
|
||||||
line_saved_in_history = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fall out of loop on \q or if lexer reached EOL */
|
|
||||||
if (slashCmdStatus == PSQL_CMD_TERMINATE ||
|
|
||||||
scan_result == PSCAN_INCOMPLETE ||
|
|
||||||
scan_result == PSCAN_EOL)
|
scan_result == PSCAN_EOL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pset.cur_cmd_interactive && prompt_status == PROMPT_READY) ||
|
/* Add line to pending history if we didn't execute anything yet */
|
||||||
(GetVariableBool(pset.vars, "SINGLELINE") && prompt_status == PROMPT_CONTINUE))
|
if (pset.cur_cmd_interactive && !line_saved_in_history)
|
||||||
{
|
pg_append_history(line, history_buf);
|
||||||
/*
|
|
||||||
* Pass all the contents of history_buf to readline
|
|
||||||
* and free the history buffer.
|
|
||||||
*/
|
|
||||||
pg_write_history(history_buf->data);
|
|
||||||
pg_clear_history(history_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
psql_scan_finish(scan_state);
|
psql_scan_finish(scan_state);
|
||||||
free(line);
|
free(line);
|
||||||
@ -359,6 +346,11 @@ MainLoop(FILE *source)
|
|||||||
if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
|
if (query_buf->len > 0 && !pset.cur_cmd_interactive &&
|
||||||
successResult == EXIT_SUCCESS)
|
successResult == EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
|
/* save query in history */
|
||||||
|
if (pset.cur_cmd_interactive)
|
||||||
|
pg_send_history(history_buf);
|
||||||
|
|
||||||
|
/* execute query */
|
||||||
success = SendQuery(query_buf->data);
|
success = SendQuery(query_buf->data);
|
||||||
|
|
||||||
if (!success && die_on_error)
|
if (!success && die_on_error)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/prompt.c,v 1.44 2006/04/19 16:02:17 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/prompt.c,v 1.45 2006/06/11 23:06:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "pqexpbuffer.h"
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.152 2006/05/28 02:27:08 alvherre Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.153 2006/06/11 23:06:00 tgl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*----------------------------------------------------------------------
|
/*----------------------------------------------------------------------
|
||||||
@ -43,7 +43,6 @@
|
|||||||
|
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "tab-complete.h"
|
#include "tab-complete.h"
|
||||||
#include "pqexpbuffer.h"
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
/* If we don't have this, we might as well forget about the whole thing: */
|
/* If we don't have this, we might as well forget about the whole thing: */
|
||||||
@ -51,6 +50,7 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "libpq-fe.h"
|
#include "libpq-fe.h"
|
||||||
|
#include "pqexpbuffer.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user