Re: Patch for psql History Display on MacOSX - Mailing list pgsql-hackers

From Tom Lane
Subject Re: Patch for psql History Display on MacOSX
Date
Msg-id 15982.1409601784@sss.pgh.pa.us
Whole thread Raw
In response to Re: Patch for psql History Display on MacOSX  (Stepan Rutz <stepan.rutz@gmx.de>)
Responses Re: Patch for psql History Display on MacOSX
List pgsql-hackers
Stepan Rutz <stepan.rutz@gmx.de> writes:
> Anyway, I am sure the iteration used in encode_history and decode_history in input.c does not work on libedit.

Yeah, I noticed your comment about that.  That seems odd; a look at the
Apple libedit sources suggests it should work.  I was just about to trace
through the logic and try to see what's happening.

The reason nobody noticed is possibly that libedit doesn't actually need
the newline-encoding hack.  However, we should probably fix the loops if
they aren't working as expected on libedit, just in case somebody tries
to copy the logic for some other purpose.

Meanwhile, attached is a draft patch that uses the history_get loop for
all \s operations, and simplifies saveHistory in consequence.

            regards, tom lane

diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index e16b4d5..e1949d8 100644
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
*************** exec_command(const char *cmd,
*** 1088,1107 ****
          char       *fname = psql_scan_slash_option(scan_state,
                                                     OT_NORMAL, NULL, true);

- #if defined(WIN32) && !defined(__CYGWIN__)
-
-         /*
-          * XXX This does not work for all terminal environments or for output
-          * containing non-ASCII characters; see comments in simple_prompt().
-          */
- #define DEVTTY    "con"
- #else
- #define DEVTTY    "/dev/tty"
- #endif
-
          expand_tilde(&fname);
!         /* This scrolls off the screen when using /dev/tty */
!         success = saveHistory(fname ? fname : DEVTTY, -1, false, false);
          if (success && !pset.quiet && fname)
              printf(_("Wrote history to file \"%s\".\n"), fname);
          if (!fname)
--- 1088,1095 ----
          char       *fname = psql_scan_slash_option(scan_state,
                                                     OT_NORMAL, NULL, true);

          expand_tilde(&fname);
!         success = printHistory(fname, pset.popt.topt.pager);
          if (success && !pset.quiet && fname)
              printf(_("Wrote history to file \"%s\".\n"), fname);
          if (!fname)
diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index aa32a3f..f43e4a2 100644
*** a/src/bin/psql/input.c
--- b/src/bin/psql/input.c
*************** initializeInput(int flags)
*** 319,340 ****


  /*
!  * This function saves the readline history when user
!  * runs \s command or 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.
-  *
-  * appendFlag: if true, try to append just our new lines to the file.
-  * If false, write the whole available history.
-  *
-  * encodeFlag: whether to encode \n as \x01.  For \s calls we don't wish
-  * to do that, but must do so when saving the final history file.
   */
! bool
! saveHistory(char *fname, int max_lines, bool appendFlag, bool encodeFlag)
  {
  #ifdef USE_READLINE

--- 319,333 ----


  /*
!  * 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.
   */
! static bool
! saveHistory(char *fname, int max_lines)
  {
  #ifdef USE_READLINE

*************** saveHistory(char *fname, int max_lines,
*** 344,354 ****
       * where write_history will fail because it tries to chmod the target
       * file.
       */
!     if (useHistory && fname &&
!         strcmp(fname, DEVNULL) != 0)
      {
!         if (encodeFlag)
!             encode_history();

          /*
           * On newer versions of libreadline, truncate the history file as
--- 337,351 ----
       * where write_history will fail because it tries to chmod the target
       * file.
       */
!     if (strcmp(fname, DEVNULL) != 0)
      {
!         /*
!          * 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
*************** saveHistory(char *fname, int max_lines,
*** 362,368 ****
           * see if the write failed.  Similarly for append_history.
           */
  #if defined(HAVE_HISTORY_TRUNCATE_FILE) && defined(HAVE_APPEND_HISTORY)
-         if (appendFlag)
          {
              int            nlines;
              int            fd;
--- 359,364 ----
*************** saveHistory(char *fname, int max_lines,
*** 387,394 ****
              if (errno == 0)
                  return true;
          }
!         else
! #endif
          {
              /* truncate what we have ... */
              if (max_lines >= 0)
--- 383,389 ----
              if (errno == 0)
                  return true;
          }
! #else                            /* don't have append support */
          {
              /* truncate what we have ... */
              if (max_lines >= 0)
*************** saveHistory(char *fname, int max_lines,
*** 399,417 ****
              if (errno == 0)
                  return true;
          }

          psql_error("could not save history to file \"%s\": %s\n",
                     fname, strerror(errno));
      }
- #else
-     /* only get here in \s case, so complain */
-     psql_error("history is not supported by this installation\n");
  #endif

      return false;
  }


  static void
  finishInput(void)
  {
--- 394,467 ----
              if (errno == 0)
                  return true;
          }
+ #endif

          psql_error("could not save history to file \"%s\": %s\n",
                     fname, strerror(errno));
      }
  #endif

      return false;
  }


+ /*
+  * 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;
+     int            i;
+     HIST_ENTRY *curr;
+
+     if (!useHistory)
+         return false;
+
+     if (fname == NULL)
+     {
+         /* use pager if appropriate when printing to console */
+         output = PageOutput(history_length, 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;
+     }
+
+     for (i = history_base; (curr = history_get(i)) != NULL; i++)
+     {
+         fprintf(output, "%s\n", curr->line);
+     }
+
+     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)
  {
*************** finishInput(void)
*** 421,427 ****
          int            hist_size;

          hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
!         saveHistory(psql_history, hist_size, true, true);
          free(psql_history);
          psql_history = NULL;
      }
--- 471,477 ----
          int            hist_size;

          hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
!         (void) saveHistory(psql_history, hist_size);
          free(psql_history);
          psql_history = NULL;
      }
diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h
index 1d10a22..1b22399 100644
*** a/src/bin/psql/input.h
--- b/src/bin/psql/input.h
*************** char       *gets_interactive(const char *pr
*** 42,48 ****
  char       *gets_fromFile(FILE *source);

  void        initializeInput(int flags);
! bool        saveHistory(char *fname, int max_lines, bool appendFlag, bool encodeFlag);

  void        pg_append_history(const char *s, PQExpBuffer history_buf);
  void        pg_send_history(PQExpBuffer history_buf);
--- 42,49 ----
  char       *gets_fromFile(FILE *source);

  void        initializeInput(int flags);
!
! bool        printHistory(const char *fname, unsigned short int pager);

  void        pg_append_history(const char *s, PQExpBuffer history_buf);
  void        pg_send_history(PQExpBuffer history_buf);

pgsql-hackers by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Re: [BUGS] Re: BUG #9555: pg_dump for tables with inheritance recreates the table with the wrong order of columns
Next
From: Tom Lane
Date:
Subject: Re: Re: [BUGS] Re: BUG #9555: pg_dump for tables with inheritance recreates the table with the wrong order of columns