Hello,

On Thu, 17 Aug 2017, Pavel Stehule wrote:

> 2017-08-17 9:23 GMT+02:00 Vesa-Matti J Kari <vmk...@cc.helsinki.fi>:
>
>       Bash has HISTIGNORE feature that allows you to exclude certain commands
>       from the command history (e.g. shutdown, reboot, rm *).
>
>       Would it make any sense to add such a feature to psql (e.g. to ignore
>       DROP, DELETE commands)?
>
>
> It is not bad idea.

A quick patch is attached. Not sure about the quality, hacked this
together in about four hours, trying to figure out how to do it correctly
the PostgreSQL way.

Based on a few tests, the patch seems to work.

I do not know how the Bash implementation works, but I chose to disallow
forms such as:

:
:a
a:
a::b

So specifying empty strings seems like a syntax error to me. But I do
not know how to report failures for those, the current patch disallows
them and HISTIGNORE simply does not work with invalid syntax.

Regards,
vmk
-- 
************************************************************************
               Tietotekniikkakeskus / Helsingin yliopisto
                 IT department / University of Helsinki
************************************************************************
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index b3dbb5946e..1a28a21f26 100644
*** a/src/bin/psql/help.c
--- b/src/bin/psql/help.c
***************
*** 357,362 **** helpVariables(unsigned short int pager)
--- 357,363 ----
                                          "                     (default: 
0=unlimited)\n"));
        fprintf(output, _("  HISTCONTROL        controls command history 
[ignorespace, ignoredups, ignoreboth]\n"));
        fprintf(output, _("  HISTFILE           file name used to store the 
command history\n"));
+       fprintf(output, _("  HISTIGNORE         controls command history, 
ignores colon separated commands\n"));
        fprintf(output, _("  HISTSIZE           max number of commands to store 
in the command history\n"));
        fprintf(output, _("  HOST               the currently connected 
database server host\n"));
        fprintf(output, _("  IGNOREEOF          number of EOFs needed to 
terminate an interactive session\n"));
diff --git a/src/bin/psql/index 62f5f77383..ffaee397cf 100644
*** a/src/bin/psql/input.c
--- b/src/bin/psql/input.c
***************
*** 147,152 **** pg_send_history(PQExpBuffer history_buf)
--- 147,162 ----
  
        if (useHistory && s[0])
        {
+               if (pset.histignore)
+               {
+                       for (i = 0; i < histignore.nstr; i++) {
+                               if (pg_strncasecmp(s, histignore.str[i], 
strlen(histignore.str[i])) == 0) {
+                                       resetPQExpBuffer(history_buf);
+                                       return;
+                               }
+                       }
+               }
+ 
                if (((pset.histcontrol & hctl_ignorespace) &&
                         s[0] == ' ') ||
                        ((pset.histcontrol & hctl_ignoredups) &&
diff --git a/src/bin/psql/sindex b78f151acd..9c436eeb88 100644
*** a/src/bin/psql/settings.h
--- b/src/bin/psql/settings.h
***************
*** 77,82 **** enum trivalue
--- 77,89 ----
        TRI_YES
  };
  
+ typedef struct HistIgnore
+ {
+       char **str;
+       int nstr;
+ 
+ } HistIgnore;
+ 
  typedef struct _psqlSettings
  {
        PGconn     *db;                         /* connection to backend */
***************
*** 133,138 **** typedef struct _psqlSettings
--- 140,146 ----
        PSQL_ERROR_ROLLBACK on_error_rollback;
        PSQL_COMP_CASE comp_case;
        HistControl histcontrol;
+       char            *histignore;
        const char *prompt1;
        const char *prompt2;
        const char *prompt3;
***************
*** 141,146 **** typedef struct _psqlSettings
--- 149,155 ----
  } PsqlSettings;
  
  extern PsqlSettings pset;
+ extern HistIgnore histignore;
  
  
  #ifndef EXIT_SUCCESS
diff --git a/src/bin/psql/starindex 7f767976a5..b14ce2699e 100644
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
***************
*** 31,36 ****
--- 31,37 ----
   * Global psql options
   */
  PsqlSettings pset;
+ HistIgnore histignore;
  
  #ifndef WIN32
  #define SYSPSQLRC     "psqlrc"
***************
*** 667,672 **** parse_psql_options(int argc, char *argv[], struct adhoc_opts 
*options)
--- 668,726 ----
  }
  
  
+ static bool
+ parse_histignore(const char *val)
+ {
+       const char *p;
+       char *tokbuf;
+       char *tok;
+       int i;
+       int len;
+       int ncolons;
+ 
+       len = strlen(val);
+ 
+       if (len == 0) {
+               histignore.str = NULL;
+               histignore.nstr = 0;
+               return true;
+       }
+ 
+       /* Validate syntax first. */
+       if (val[0] == ':' || val[len-1] == ':')
+               return false;
+ 
+       i = 0;
+       while (val[i] && val[i+1]) {
+               if (val[i] == ':' && val[i+1] == ':')
+                       return false;
+               i++;
+       }
+ 
+       p = val;
+       ncolons = 0;
+       while (*p++)
+               if (*p == ':')
+                       ncolons++;
+ 
+       histignore.nstr = ncolons + 1;
+       histignore.str = pg_malloc(histignore.nstr * sizeof(char *));
+ 
+ 
+       i = 0;
+       tokbuf = pg_strdup(val);
+ 
+       tok = strtok(tokbuf, ":");
+       while (tok != NULL) {
+               histignore.str[i] = pg_strdup(tok);
+               tok = strtok(NULL, ":");
+               i++;
+       }
+ 
+       return true;
+ }
+ 
+ 
  /*
   * Append a new item to the end of the SimpleActionList.
   * Note that "val" is copied if it's not NULL.
***************
*** 1024,1029 **** histcontrol_hook(const char *newval)
--- 1078,1101 ----
        return true;
  }
  
+ static char *
+ histignore_substitute_hook(char *newval)
+ {
+       if (newval == NULL)
+               newval = pg_strdup("");
+       return newval;
+ }
+ 
+ static bool
+ histignore_hook(const char *newval)
+ {
+       Assert(newval != NULL);
+       if (parse_histignore(newval) == false)
+               return false;
+       pset.histignore = pg_strdup(newval);
+       return true;
+ }
+ 
  static bool
  prompt1_hook(const char *newval)
  {
***************
*** 1151,1156 **** EstablishVariableSpace(void)
--- 1223,1231 ----
        SetVariableHooks(pset.vars, "HISTCONTROL",
                                         histcontrol_substitute_hook,
                                         histcontrol_hook);
+       SetVariableHooks(pset.vars, "HISTIGNORE",
+                                        histignore_substitute_hook,
+                                        histignore_hook);
        SetVariableHooks(pset.vars, "PROMPT1",
                                         NULL,
                                         prompt1_hook);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to