aboutsummaryrefslogtreecommitdiff
path: root/src/bin/psql/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/psql/command.c')
-rw-r--r--src/bin/psql/command.c74
1 files changed, 59 insertions, 15 deletions
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index e42be914d22..e04ccc5b628 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -148,11 +148,11 @@ static void save_query_text_state(PsqlScanState scan_state, ConditionalStack cst
PQExpBuffer query_buf);
static void discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
PQExpBuffer query_buf);
-static void copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf);
+static bool copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf);
static bool do_connect(enum trivalue reuse_previous_specification,
char *dbname, char *user, char *host, char *port);
static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
- int lineno, bool *edited);
+ int lineno, bool discard_on_quit, bool *edited);
static bool do_shell(const char *command);
static bool do_watch(PQExpBuffer query_buf, double sleep);
static bool lookup_object_oid(EditableObjectType obj_type, const char *desc,
@@ -418,7 +418,7 @@ exec_command(const char *cmd,
* the individual command subroutines.
*/
if (status == PSQL_CMD_SEND)
- copy_previous_query(query_buf, previous_buf);
+ (void) copy_previous_query(query_buf, previous_buf);
return status;
}
@@ -1004,14 +1004,27 @@ exec_command_edit(PsqlScanState scan_state, bool active_branch,
}
if (status != PSQL_CMD_ERROR)
{
+ bool discard_on_quit;
+
expand_tilde(&fname);
if (fname)
+ {
canonicalize_path(fname);
+ /* Always clear buffer if the file isn't modified */
+ discard_on_quit = true;
+ }
+ else
+ {
+ /*
+ * If query_buf is empty, recall previous query for
+ * editing. But in that case, the query buffer should be
+ * emptied if editing doesn't modify the file.
+ */
+ discard_on_quit = copy_previous_query(query_buf,
+ previous_buf);
+ }
- /* If query_buf is empty, recall previous query for editing */
- copy_previous_query(query_buf, previous_buf);
-
- if (do_edit(fname, query_buf, lineno, NULL))
+ if (do_edit(fname, query_buf, lineno, discard_on_quit, NULL))
status = PSQL_CMD_NEWEDIT;
else
status = PSQL_CMD_ERROR;
@@ -1134,7 +1147,7 @@ exec_command_ef_ev(PsqlScanState scan_state, bool active_branch,
{
bool edited = false;
- if (!do_edit(NULL, query_buf, lineno, &edited))
+ if (!do_edit(NULL, query_buf, lineno, true, &edited))
status = PSQL_CMD_ERROR;
else if (!edited)
puts(_("No changes"));
@@ -2637,7 +2650,7 @@ exec_command_watch(PsqlScanState scan_state, bool active_branch,
}
/* If query_buf is empty, recall and execute previous query */
- copy_previous_query(query_buf, previous_buf);
+ (void) copy_previous_query(query_buf, previous_buf);
success = do_watch(query_buf, sleep);
@@ -2961,12 +2974,19 @@ discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
* This is used by various slash commands for which re-execution of a
* previous query is a common usage. For convenience, we allow the
* case of query_buf == NULL (and do nothing).
+ *
+ * Returns "true" if the previous query was copied into the query
+ * buffer, else "false".
*/
-static void
+static bool
copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf)
{
if (query_buf && query_buf->len == 0)
+ {
appendPQExpBufferStr(query_buf, previous_buf->data);
+ return true;
+ }
+ return false;
}
/*
@@ -3647,10 +3667,11 @@ UnsyncVariables(void)
/*
- * do_edit -- handler for \e
+ * helper for do_edit(): actually invoke the editor
*
- * If you do not specify a filename, the current query buffer will be copied
- * into a temporary one.
+ * Returns true on success, false if we failed to invoke the editor or
+ * it returned nonzero status. (An error message is printed for failed-
+ * to-invoke cases, but not if the editor returns nonzero status.)
*/
static bool
editFile(const char *fname, int lineno)
@@ -3719,10 +3740,23 @@ editFile(const char *fname, int lineno)
}
-/* call this one */
+/*
+ * do_edit -- handler for \e
+ *
+ * If you do not specify a filename, the current query buffer will be copied
+ * into a temporary file.
+ *
+ * After this function is done, the resulting file will be copied back into the
+ * query buffer. As an exception to this, the query buffer will be emptied
+ * if the file was not modified (or the editor failed) and the caller passes
+ * "discard_on_quit" = true.
+ *
+ * If "edited" isn't NULL, *edited will be set to true if the query buffer
+ * is successfully replaced.
+ */
static bool
do_edit(const char *filename_arg, PQExpBuffer query_buf,
- int lineno, bool *edited)
+ int lineno, bool discard_on_quit, bool *edited)
{
char fnametmp[MAXPGPATH];
FILE *stream = NULL;
@@ -3870,6 +3904,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
{
pg_log_error("%s: %m", fname);
error = true;
+ resetPQExpBuffer(query_buf);
}
else if (edited)
{
@@ -3879,6 +3914,15 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
fclose(stream);
}
}
+ else
+ {
+ /*
+ * If the file was not modified, and the caller requested it, discard
+ * the query buffer.
+ */
+ if (discard_on_quit)
+ resetPQExpBuffer(query_buf);
+ }
/* remove temp file */
if (!filename_arg)