</para>
<para>
- The new contents of the query buffer are then re-parsed according to
+ If you edit a file or the previous query, and you quit the editor without
+ modifying the file, the query buffer is cleared.
+ Otherwise, the new contents of the query buffer are re-parsed according to
the normal rules of <application>psql</application>, treating the
whole buffer as a single line. Any complete queries are immediately
executed; that is, if the query buffer contains or ends with a
in the form of a <command>CREATE OR REPLACE FUNCTION</command> or
<command>CREATE OR REPLACE PROCEDURE</command> command.
Editing is done in the same way as for <literal>\edit</literal>.
- After the editor exits, the updated command is executed immediately
+ If you quit the editor without saving, the statement is discarded.
+ If you save and exit the editor, the updated command is executed immediately
if you added a semicolon to it. Otherwise it is redisplayed;
type semicolon or <literal>\g</literal> to send it, or <literal>\r</literal>
to cancel.
This command fetches and edits the definition of the named view,
in the form of a <command>CREATE OR REPLACE VIEW</command> command.
Editing is done in the same way as for <literal>\edit</literal>.
- After the editor exits, the updated command is executed immediately
+ If you quit the editor without saving, the statement is discarded.
+ If you save and exit the editor, the updated command is executed immediately
if you added a semicolon to it. Otherwise it is redisplayed;
type semicolon or <literal>\g</literal> to send it, or <literal>\r</literal>
to cancel.
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,
* 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;
}
}
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;
{
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"));
}
/* 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);
* 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;
}
/*
/*
- * 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)
}
-/* 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;
{
pg_log_error("%s: %m", fname);
error = true;
+ resetPQExpBuffer(query_buf);
}
else if (edited)
{
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)