diff options
Diffstat (limited to 'src/bin/psql/command.c')
-rw-r--r-- | src/bin/psql/command.c | 74 |
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) |