Thread: Trailing semicolons in psql patch

Trailing semicolons in psql patch

From
greg@turnstep.com
Date:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

How about a patch to strip semicolons in psql? I *know*
some of you have done this before:

\d mytable;

(Did not find any relation named "mytable;")

Since there is no reason to have a table named "mytable;"
why not just have psql do the smart thing and silently
strip the trailing semicolons? The attached patch only addresses
a few backslash commands as a proof of concept, but some others
could probably use it without harm. The patch affects:

\C
\c
\d
\e
\i
\o
\s
\z

Greg Sabino Mullane
greg@turnstep.com
PGP Key: 0x14964AC8 200109271811

P.S. Re: microtiming: EXPLAIN ANALYZE sounds interesting, and as
soon as cvs is fixed so that anoncvs/postgresql works, I'll take
a look at it. :)


-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iQA/AwUBO7OkzrybkGcUlkrIEQIPrgCgurQBAqZLt6m5JvbKOJyVIOx3ZQAAn0Wg
KD097oaniENYAeikbSM7LdZg
=erHC
-----END PGP SIGNATURE-----
*** ./src/bin/psql/command.c.orig    Tue Sep 25 13:21:50 2001
--- ./src/bin/psql/command.c    Tue Sep 25 18:06:37 2001
***************
*** 55,61 ****
  {
      OT_NORMAL, OT_SQLID, OT_FILEPIPE
  };
! static char *scan_option(char **string, enum option_type type, char *quote);
  static char *unescape(const unsigned char *source, size_t len);

  static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
--- 55,61 ----
  {
      OT_NORMAL, OT_SQLID, OT_FILEPIPE
  };
! static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon);
  static char *unescape(const unsigned char *source, size_t len);

  static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
***************
*** 216,222 ****
      /* \C -- override table title (formerly change HTML caption) */
      else if (strcmp(cmd, "C") == 0)
      {
!         char       *opt = scan_option(&string, OT_NORMAL, NULL);

          success = do_pset("title", opt, &pset.popt, quiet);
          free(opt);
--- 216,222 ----
      /* \C -- override table title (formerly change HTML caption) */
      else if (strcmp(cmd, "C") == 0)
      {
!         char       *opt = scan_option(&string, OT_NORMAL, NULL, 1);

          success = do_pset("title", opt, &pset.popt, quiet);
          free(opt);
***************
*** 238,245 ****
          char        opt1q,
                      opt2q;

!         opt1 = scan_option(&string, OT_NORMAL, &opt1q);
!         opt2 = scan_option(&string, OT_NORMAL, &opt2q);

          if (opt2)
              /* gave username */
--- 238,245 ----
          char        opt1q,
                      opt2q;

!         opt1 = scan_option(&string, OT_NORMAL, &opt1q, 1);
!         opt2 = scan_option(&string, OT_NORMAL, &opt2q, 1);

          if (opt2)
              /* gave username */
***************
*** 273,280 ****
      {
          char       *name;
          bool        show_verbose;

-         name = scan_option(&string, OT_SQLID, NULL);
          show_verbose = strchr(cmd, '+') ? true : false;

          switch (cmd[1])
--- 273,280 ----
      {
          char       *name;
          bool        show_verbose;
+         name = scan_option(&string, OT_SQLID, NULL, 1);

          show_verbose = strchr(cmd, '+') ? true : false;

          switch (cmd[1])
***************
*** 337,343 ****
          }
          else
          {
!             fname = scan_option(&string, OT_NORMAL, NULL);
              status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
              free(fname);
          }
--- 337,343 ----
          }
          else
          {
!             fname = scan_option(&string, OT_NORMAL, NULL, 1);
              status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
              free(fname);
          }
***************
*** 356,363 ****
              fout = pset.queryFout;
          else
              fout = stdout;
!
!         while ((value = scan_option(&string, OT_NORMAL, "ed)))
          {
              if (!quoted && strcmp(value, "-n") == 0)
                  no_newline = true;
--- 356,363 ----
              fout = pset.queryFout;
          else
              fout = stdout;
!
!         while ((value = scan_option(&string, OT_NORMAL, "ed, 0)))
          {
              if (!quoted && strcmp(value, "-n") == 0)
                  no_newline = true;
***************
*** 378,384 ****
      /* \encoding -- set/show client side encoding */
      else if (strcmp(cmd, "encoding") == 0)
      {
!         char       *encoding = scan_option(&string, OT_NORMAL, NULL);

          if (!encoding)
              /* show encoding */
--- 378,384 ----
      /* \encoding -- set/show client side encoding */
      else if (strcmp(cmd, "encoding") == 0)
      {
!         char       *encoding = scan_option(&string, OT_NORMAL, NULL, 0);

          if (!encoding)
              /* show encoding */
***************
*** 406,412 ****
      /* \f -- change field separator */
      else if (strcmp(cmd, "f") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL);

          success = do_pset("fieldsep", fname, &pset.popt, quiet);
          free(fname);
--- 406,412 ----
      /* \f -- change field separator */
      else if (strcmp(cmd, "f") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL, 0);

          success = do_pset("fieldsep", fname, &pset.popt, quiet);
          free(fname);
***************
*** 415,421 ****
      /* \g means send query */
      else if (strcmp(cmd, "g") == 0)
      {
!         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);

          if (!fname)
              pset.gfname = NULL;
--- 415,421 ----
      /* \g means send query */
      else if (strcmp(cmd, "g") == 0)
      {
!         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, 0);

          if (!fname)
              pset.gfname = NULL;
***************
*** 447,453 ****
      /* \i is include file */
      else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL);

          if (!fname)
          {
--- 447,453 ----
      /* \i is include file */
      else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL, 1);

          if (!fname)
          {
***************
*** 475,482 ****
          char       *opt1,
                     *opt2;

!         opt1 = scan_option(&string, OT_NORMAL, NULL);
!         opt2 = scan_option(&string, OT_NORMAL, NULL);

          if (strcmp(cmd + 3, "export") == 0)
          {
--- 475,482 ----
          char       *opt1,
                     *opt2;

!         opt1 = scan_option(&string, OT_NORMAL, NULL, 1);
!         opt2 = scan_option(&string, OT_NORMAL, NULL, 1);

          if (strcmp(cmd + 3, "export") == 0)
          {
***************
*** 528,534 ****
      /* \o -- set query output */
      else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
      {
!         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);

          success = setQFout(fname);
          free(fname);
--- 528,534 ----
      /* \o -- set query output */
      else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
      {
!         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, 1);

          success = setQFout(fname);
          free(fname);
***************
*** 547,554 ****
      /* \pset -- set printing parameters */
      else if (strcmp(cmd, "pset") == 0)
      {
!         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);
!         char       *opt1 = scan_option(&string, OT_NORMAL, NULL);

          if (!opt0)
          {
--- 547,554 ----
      /* \pset -- set printing parameters */
      else if (strcmp(cmd, "pset") == 0)
      {
!         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, 0);
!         char       *opt1 = scan_option(&string, OT_NORMAL, NULL, 0);

          if (!opt0)
          {
***************
*** 577,583 ****
      /* \s save history in a file or show it on the screen */
      else if (strcmp(cmd, "s") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL);

          success = saveHistory(fname ? fname : "/dev/tty");

--- 577,583 ----
      /* \s save history in a file or show it on the screen */
      else if (strcmp(cmd, "s") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL, 1);

          success = saveHistory(fname ? fname : "/dev/tty");

***************
*** 589,595 ****
      /* \set -- generalized set variable/option command */
      else if (strcmp(cmd, "set") == 0)
      {
!         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);

          if (!opt0)
          {
--- 589,595 ----
      /* \set -- generalized set variable/option command */
      else if (strcmp(cmd, "set") == 0)
      {
!         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, 0);

          if (!opt0)
          {
***************
*** 614,624 ****
              char       *newval = NULL;
              char       *opt;

!             opt = scan_option(&string, OT_NORMAL, NULL);
              newval = xstrdup(opt ? opt : "");
              free(opt);

!             while ((opt = scan_option(&string, OT_NORMAL, NULL)))
              {
                  newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
                  if (!newval)
--- 614,624 ----
              char       *newval = NULL;
              char       *opt;

!             opt = scan_option(&string, OT_NORMAL, NULL, 0);
              newval = xstrdup(opt ? opt : "");
              free(opt);

!             while ((opt = scan_option(&string, OT_NORMAL, NULL, 0)))
              {
                  newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
                  if (!newval)
***************
*** 648,654 ****
      /* \T -- define html <table ...> attributes */
      else if (strcmp(cmd, "T") == 0)
      {
!         char       *value = scan_option(&string, OT_NORMAL, NULL);

          success = do_pset("tableattr", value, &pset.popt, quiet);
          free(value);
--- 648,654 ----
      /* \T -- define html <table ...> attributes */
      else if (strcmp(cmd, "T") == 0)
      {
!         char       *value = scan_option(&string, OT_NORMAL, NULL, 0);

          success = do_pset("tableattr", value, &pset.popt, quiet);
          free(value);
***************
*** 657,663 ****
      /* \unset */
      else if (strcmp(cmd, "unset") == 0)
      {
!         char       *opt = scan_option(&string, OT_NORMAL, NULL);

          if (!opt)
          {
--- 657,663 ----
      /* \unset */
      else if (strcmp(cmd, "unset") == 0)
      {
!         char       *opt = scan_option(&string, OT_NORMAL, NULL, 0);

          if (!opt)
          {
***************
*** 686,692 ****
          }
          else
          {
!             fname = scan_option(&string, OT_FILEPIPE, NULL);

              if (!fname)
              {
--- 686,692 ----
          }
          else
          {
!             fname = scan_option(&string, OT_FILEPIPE, NULL, 1);

              if (!fname)
              {
***************
*** 741,747 ****
      /* \z -- list table rights (grant/revoke) */
      else if (strcmp(cmd, "z") == 0)
      {
!         char       *opt = scan_option(&string, OT_SQLID, NULL);

          success = permissionsList(opt);
          free(opt);
--- 741,747 ----
      /* \z -- list table rights (grant/revoke) */
      else if (strcmp(cmd, "z") == 0)
      {
!         char       *opt = scan_option(&string, OT_SQLID, NULL, 1);

          success = permissionsList(opt);
          free(opt);
***************
*** 772,778 ****
          char       *value;

          fprintf(stderr, "+ optstr = |%s|\n", options_string);
!         while ((value = scan_option(&string, OT_NORMAL, NULL)))
          {
              fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
              free(value);
--- 772,778 ----
          char       *value;

          fprintf(stderr, "+ optstr = |%s|\n", options_string);
!         while ((value = scan_option(&string, OT_NORMAL, NULL, 1)))
          {
              fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
              free(value);
***************
*** 787,793 ****
          status = CMD_ERROR;

      /* eat the rest of the options string */
!     while ((val = scan_option(&string, OT_NORMAL, NULL)))
      {
          if (status != CMD_UNKNOWN)
              psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
--- 787,793 ----
          status = CMD_ERROR;

      /* eat the rest of the options string */
!     while ((val = scan_option(&string, OT_NORMAL, NULL, 0)))
      {
          if (status != CMD_UNKNOWN)
              psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
***************
*** 806,812 ****
   * scan_option()
   */
  static char *
! scan_option(char **string, enum option_type type, char *quote)
  {
      unsigned int pos = 0;
      char       *options_string;
--- 806,812 ----
   * scan_option()
   */
  static char *
! scan_option(char **string, enum option_type type, char *quote, bool semicolon)
  {
      unsigned int pos = 0;
      char       *options_string;
***************
*** 822,827 ****
--- 822,835 ----
      /* skip leading whitespace */
      pos += strspn(options_string + pos, " \t\n\r");

+
+     /* Strip any trailing semi-colons for some types */
+     if (semicolon) {
+         int i;
+         for (i = strlen(options_string)-1; i && options_string[i]==';'; i--);
+         if (i<strlen(options_string)-1) options_string[i+1]='\0';
+     }
+
      switch (options_string[pos])
      {

***************
*** 863,868 ****
--- 871,877 ----
                   * If this is expected to be an SQL identifier like option
                   * then we strip out the double quotes
                   */
+
                  if (type == OT_SQLID)
                  {
                      unsigned int k,
***************
*** 894,900 ****
                  *string = options_string + jj + 1;
                  if (quote)
                      *quote = '"';
!
                  return return_val;
              }

--- 903,909 ----
                  *string = options_string + jj + 1;
                  if (quote)
                      *quote = '"';
!
                  return return_val;
              }


Re: Trailing semicolons in psql patch

From
Bruce Momjian
Date:
I like it.  Several people have complained because they forget and add
the semicolon.  I like that you made it per-command so commands that
need to see the semicolon see it.  I will change it slightly to use
true/false rather than 0/1.

Your patch has been added to the PostgreSQL unapplied patches list at:

    http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> How about a patch to strip semicolons in psql? I *know*
> some of you have done this before:
>
> \d mytable;
>
> (Did not find any relation named "mytable;")
>
> Since there is no reason to have a table named "mytable;"
> why not just have psql do the smart thing and silently
> strip the trailing semicolons? The attached patch only addresses
> a few backslash commands as a proof of concept, but some others
> could probably use it without harm. The patch affects:
>
> \C
> \c
> \d
> \e
> \i
> \o
> \s
> \z
>
> Greg Sabino Mullane
> greg@turnstep.com
> PGP Key: 0x14964AC8 200109271811
>
> P.S. Re: microtiming: EXPLAIN ANALYZE sounds interesting, and as
> soon as cvs is fixed so that anoncvs/postgresql works, I'll take
> a look at it. :)
>
>
> -----BEGIN PGP SIGNATURE-----
> Comment: http://www.turnstep.com/pgp.html
>
> iQA/AwUBO7OkzrybkGcUlkrIEQIPrgCgurQBAqZLt6m5JvbKOJyVIOx3ZQAAn0Wg
> KD097oaniENYAeikbSM7LdZg
> =erHC
> -----END PGP SIGNATURE-----

> *** ./src/bin/psql/command.c.orig    Tue Sep 25 13:21:50 2001
> --- ./src/bin/psql/command.c    Tue Sep 25 18:06:37 2001
> ***************
> *** 55,61 ****
>   {
>       OT_NORMAL, OT_SQLID, OT_FILEPIPE
>   };
> ! static char *scan_option(char **string, enum option_type type, char *quote);
>   static char *unescape(const unsigned char *source, size_t len);
>
>   static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
> --- 55,61 ----
>   {
>       OT_NORMAL, OT_SQLID, OT_FILEPIPE
>   };
> ! static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon);
>   static char *unescape(const unsigned char *source, size_t len);
>
>   static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
> ***************
> *** 216,222 ****
>       /* \C -- override table title (formerly change HTML caption) */
>       else if (strcmp(cmd, "C") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("title", opt, &pset.popt, quiet);
>           free(opt);
> --- 216,222 ----
>       /* \C -- override table title (formerly change HTML caption) */
>       else if (strcmp(cmd, "C") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL, 1);
>
>           success = do_pset("title", opt, &pset.popt, quiet);
>           free(opt);
> ***************
> *** 238,245 ****
>           char        opt1q,
>                       opt2q;
>
> !         opt1 = scan_option(&string, OT_NORMAL, &opt1q);
> !         opt2 = scan_option(&string, OT_NORMAL, &opt2q);
>
>           if (opt2)
>               /* gave username */
> --- 238,245 ----
>           char        opt1q,
>                       opt2q;
>
> !         opt1 = scan_option(&string, OT_NORMAL, &opt1q, 1);
> !         opt2 = scan_option(&string, OT_NORMAL, &opt2q, 1);
>
>           if (opt2)
>               /* gave username */
> ***************
> *** 273,280 ****
>       {
>           char       *name;
>           bool        show_verbose;
>
> -         name = scan_option(&string, OT_SQLID, NULL);
>           show_verbose = strchr(cmd, '+') ? true : false;
>
>           switch (cmd[1])
> --- 273,280 ----
>       {
>           char       *name;
>           bool        show_verbose;
> +         name = scan_option(&string, OT_SQLID, NULL, 1);
>
>           show_verbose = strchr(cmd, '+') ? true : false;
>
>           switch (cmd[1])
> ***************
> *** 337,343 ****
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_NORMAL, NULL);
>               status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
>               free(fname);
>           }
> --- 337,343 ----
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_NORMAL, NULL, 1);
>               status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
>               free(fname);
>           }
> ***************
> *** 356,363 ****
>               fout = pset.queryFout;
>           else
>               fout = stdout;
> !
> !         while ((value = scan_option(&string, OT_NORMAL, "ed)))
>           {
>               if (!quoted && strcmp(value, "-n") == 0)
>                   no_newline = true;
> --- 356,363 ----
>               fout = pset.queryFout;
>           else
>               fout = stdout;
> !
> !         while ((value = scan_option(&string, OT_NORMAL, "ed, 0)))
>           {
>               if (!quoted && strcmp(value, "-n") == 0)
>                   no_newline = true;
> ***************
> *** 378,384 ****
>       /* \encoding -- set/show client side encoding */
>       else if (strcmp(cmd, "encoding") == 0)
>       {
> !         char       *encoding = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!encoding)
>               /* show encoding */
> --- 378,384 ----
>       /* \encoding -- set/show client side encoding */
>       else if (strcmp(cmd, "encoding") == 0)
>       {
> !         char       *encoding = scan_option(&string, OT_NORMAL, NULL, 0);
>
>           if (!encoding)
>               /* show encoding */
> ***************
> *** 406,412 ****
>       /* \f -- change field separator */
>       else if (strcmp(cmd, "f") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("fieldsep", fname, &pset.popt, quiet);
>           free(fname);
> --- 406,412 ----
>       /* \f -- change field separator */
>       else if (strcmp(cmd, "f") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, 0);
>
>           success = do_pset("fieldsep", fname, &pset.popt, quiet);
>           free(fname);
> ***************
> *** 415,421 ****
>       /* \g means send query */
>       else if (strcmp(cmd, "g") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>           if (!fname)
>               pset.gfname = NULL;
> --- 415,421 ----
>       /* \g means send query */
>       else if (strcmp(cmd, "g") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, 0);
>
>           if (!fname)
>               pset.gfname = NULL;
> ***************
> *** 447,453 ****
>       /* \i is include file */
>       else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!fname)
>           {
> --- 447,453 ----
>       /* \i is include file */
>       else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, 1);
>
>           if (!fname)
>           {
> ***************
> *** 475,482 ****
>           char       *opt1,
>                      *opt2;
>
> !         opt1 = scan_option(&string, OT_NORMAL, NULL);
> !         opt2 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (strcmp(cmd + 3, "export") == 0)
>           {
> --- 475,482 ----
>           char       *opt1,
>                      *opt2;
>
> !         opt1 = scan_option(&string, OT_NORMAL, NULL, 1);
> !         opt2 = scan_option(&string, OT_NORMAL, NULL, 1);
>
>           if (strcmp(cmd + 3, "export") == 0)
>           {
> ***************
> *** 528,534 ****
>       /* \o -- set query output */
>       else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>           success = setQFout(fname);
>           free(fname);
> --- 528,534 ----
>       /* \o -- set query output */
>       else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, 1);
>
>           success = setQFout(fname);
>           free(fname);
> ***************
> *** 547,554 ****
>       /* \pset -- set printing parameters */
>       else if (strcmp(cmd, "pset") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);
> !         char       *opt1 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt0)
>           {
> --- 547,554 ----
>       /* \pset -- set printing parameters */
>       else if (strcmp(cmd, "pset") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, 0);
> !         char       *opt1 = scan_option(&string, OT_NORMAL, NULL, 0);
>
>           if (!opt0)
>           {
> ***************
> *** 577,583 ****
>       /* \s save history in a file or show it on the screen */
>       else if (strcmp(cmd, "s") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           success = saveHistory(fname ? fname : "/dev/tty");
>
> --- 577,583 ----
>       /* \s save history in a file or show it on the screen */
>       else if (strcmp(cmd, "s") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, 1);
>
>           success = saveHistory(fname ? fname : "/dev/tty");
>
> ***************
> *** 589,595 ****
>       /* \set -- generalized set variable/option command */
>       else if (strcmp(cmd, "set") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt0)
>           {
> --- 589,595 ----
>       /* \set -- generalized set variable/option command */
>       else if (strcmp(cmd, "set") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, 0);
>
>           if (!opt0)
>           {
> ***************
> *** 614,624 ****
>               char       *newval = NULL;
>               char       *opt;
>
> !             opt = scan_option(&string, OT_NORMAL, NULL);
>               newval = xstrdup(opt ? opt : "");
>               free(opt);
>
> !             while ((opt = scan_option(&string, OT_NORMAL, NULL)))
>               {
>                   newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
>                   if (!newval)
> --- 614,624 ----
>               char       *newval = NULL;
>               char       *opt;
>
> !             opt = scan_option(&string, OT_NORMAL, NULL, 0);
>               newval = xstrdup(opt ? opt : "");
>               free(opt);
>
> !             while ((opt = scan_option(&string, OT_NORMAL, NULL, 0)))
>               {
>                   newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
>                   if (!newval)
> ***************
> *** 648,654 ****
>       /* \T -- define html <table ...> attributes */
>       else if (strcmp(cmd, "T") == 0)
>       {
> !         char       *value = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("tableattr", value, &pset.popt, quiet);
>           free(value);
> --- 648,654 ----
>       /* \T -- define html <table ...> attributes */
>       else if (strcmp(cmd, "T") == 0)
>       {
> !         char       *value = scan_option(&string, OT_NORMAL, NULL, 0);
>
>           success = do_pset("tableattr", value, &pset.popt, quiet);
>           free(value);
> ***************
> *** 657,663 ****
>       /* \unset */
>       else if (strcmp(cmd, "unset") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt)
>           {
> --- 657,663 ----
>       /* \unset */
>       else if (strcmp(cmd, "unset") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL, 0);
>
>           if (!opt)
>           {
> ***************
> *** 686,692 ****
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>               if (!fname)
>               {
> --- 686,692 ----
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_FILEPIPE, NULL, 1);
>
>               if (!fname)
>               {
> ***************
> *** 741,747 ****
>       /* \z -- list table rights (grant/revoke) */
>       else if (strcmp(cmd, "z") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_SQLID, NULL);
>
>           success = permissionsList(opt);
>           free(opt);
> --- 741,747 ----
>       /* \z -- list table rights (grant/revoke) */
>       else if (strcmp(cmd, "z") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_SQLID, NULL, 1);
>
>           success = permissionsList(opt);
>           free(opt);
> ***************
> *** 772,778 ****
>           char       *value;
>
>           fprintf(stderr, "+ optstr = |%s|\n", options_string);
> !         while ((value = scan_option(&string, OT_NORMAL, NULL)))
>           {
>               fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
>               free(value);
> --- 772,778 ----
>           char       *value;
>
>           fprintf(stderr, "+ optstr = |%s|\n", options_string);
> !         while ((value = scan_option(&string, OT_NORMAL, NULL, 1)))
>           {
>               fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
>               free(value);
> ***************
> *** 787,793 ****
>           status = CMD_ERROR;
>
>       /* eat the rest of the options string */
> !     while ((val = scan_option(&string, OT_NORMAL, NULL)))
>       {
>           if (status != CMD_UNKNOWN)
>               psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
> --- 787,793 ----
>           status = CMD_ERROR;
>
>       /* eat the rest of the options string */
> !     while ((val = scan_option(&string, OT_NORMAL, NULL, 0)))
>       {
>           if (status != CMD_UNKNOWN)
>               psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
> ***************
> *** 806,812 ****
>    * scan_option()
>    */
>   static char *
> ! scan_option(char **string, enum option_type type, char *quote)
>   {
>       unsigned int pos = 0;
>       char       *options_string;
> --- 806,812 ----
>    * scan_option()
>    */
>   static char *
> ! scan_option(char **string, enum option_type type, char *quote, bool semicolon)
>   {
>       unsigned int pos = 0;
>       char       *options_string;
> ***************
> *** 822,827 ****
> --- 822,835 ----
>       /* skip leading whitespace */
>       pos += strspn(options_string + pos, " \t\n\r");
>
> +
> +     /* Strip any trailing semi-colons for some types */
> +     if (semicolon) {
> +         int i;
> +         for (i = strlen(options_string)-1; i && options_string[i]==';'; i--);
> +         if (i<strlen(options_string)-1) options_string[i+1]='\0';
> +     }
> +
>       switch (options_string[pos])
>       {
>
> ***************
> *** 863,868 ****
> --- 871,877 ----
>                    * If this is expected to be an SQL identifier like option
>                    * then we strip out the double quotes
>                    */
> +
>                   if (type == OT_SQLID)
>                   {
>                       unsigned int k,
> ***************
> *** 894,900 ****
>                   *string = options_string + jj + 1;
>                   if (quote)
>                       *quote = '"';
> !
>                   return return_val;
>               }
>
> --- 903,909 ----
>                   *string = options_string + jj + 1;
>                   if (quote)
>                       *quote = '"';
> !
>                   return return_val;
>               }
>

>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Trailing semicolons in psql patch

From
Peter Eisentraut
Date:
greg@turnstep.com writes:

> Since there is no reason to have a table named "mytable;"
> why not just have psql do the smart thing and silently
> strip the trailing semicolons?

"Stripping" semicolons is one thing, accepting semicolons as command
separators is another.  Your patch seems to handle the case of

\d mytable;

but it doesn't handle any of

\d mytable; \d yourtable
\d mytable;<space>
\d mytable; select * from mytable;

Anything short of that plus...

> The attached patch only addresses
> a few backslash commands as a proof of concept,

...is just going to create some other confusion in place of the current
one.

--
Peter Eisentraut   peter_e@gmx.net   http://funkturm.homeip.net/~peter



Re: Trailing semicolons in psql patch

From
Bruce Momjian
Date:
> greg@turnstep.com writes:
>
> > Since there is no reason to have a table named "mytable;"
> > why not just have psql do the smart thing and silently
> > strip the trailing semicolons?
>
> "Stripping" semicolons is one thing, accepting semicolons as command
> separators is another.  Your patch seems to handle the case of
>
> \d mytable;
>
> but it doesn't handle any of
>
> \d mytable; \d yourtable
> \d mytable;<space>
> \d mytable; select * from mytable;
>
> Anything short of that plus...
>
> > The attached patch only addresses
> > a few backslash commands as a proof of concept,
>
> ...is just going to create some other confusion in place of the current
> one.

My assumption is that the semicolons used with backslash commands are
just knee-jerk adding of semicolons to the end, not attempts to actually
string backslash commands togeter.   His patch does catch those cases.
The basic issue is that I think we can conclude that any trailing
semicolon on a line with a backslash command can be dropped.  In fact, I
wouldn't want to catch any of the items you listed above.  Let them fail.

We all do this by accident, don't we?  I know I do.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Trailing semicolons in psql patch

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> The basic issue is that I think we can conclude that any trailing
> semicolon on a line with a backslash command can be dropped.

I agree with this premise ... but stated that way, the patch does
entirely the wrong thing, because it's stripping trailing semis at
the word level not the line level.  I think it's a lot more surprising
to drop the semi in

        \x foo; bar

than when it's actually at the end of the line.

How about stripping trailing semis (perhaps whitespace too?) before
the line is broken into words?

            regards, tom lane

Re: Trailing semicolons in psql patch

From
greg@turnstep.com
Date:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

> I agree with this premise ... but stated that way, the patch does
> entirely the wrong thing, because it's stripping trailing semis at
> the word level not the line level.  I think it's a lot more surprising
> to drop the semi in
>
>         \x foo; bar
>
> than when it's actually at the end of the line.

Ah...so what we want then is for all of these cases to work:

\d foo \d bar
\d foo; \d bar
\d foo; \d bar;
\d foo; \d bar

Makes sense...I never combine backslash commands on the same line,
but it is possible. In that case, how about just moving this section:

  if (semicolon) {
    int i;
    for (i = strlen(options_string)-1; i && options_string[i]==';'; i--);
     if (i<strlen(options_string)-1) options_string[i+1]='\0';
  }

to right after here, where we find a "normal word"?

  strncpy(return_val, &options_string[pos], token_end);
  return_val[token_end] = 0;

(and changing options_string to return_val)

that should allow us to catch all the cases above, if I am
understanding the objection above correctly.

Greg Sabino Mullane
greg@turnstep.com PGP Key: 0x14964AC8 200110011738

-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iQA/AwUBO7jijLybkGcUlkrIEQIMWwCfYDNNqC/UYKKKaqj5MYrEcg2bGhcAoPUP
cqeF4yXAuPedUpQPLVFsw1lO
=4dGu
-----END PGP SIGNATURE-----


Re: Trailing semicolons in psql patch

From
Bruce Momjian
Date:
OK, any chance of getting an updated patch.  Your patch email is at:

    http://candle.pha.pa.us/cgi-bin/pgpatches


> > I agree with this premise ... but stated that way, the patch does
> > entirely the wrong thing, because it's stripping trailing semis at
> > the word level not the line level.  I think it's a lot more surprising
> > to drop the semi in
> >
> >         \x foo; bar
> >
> > than when it's actually at the end of the line.
>
> Ah...so what we want then is for all of these cases to work:
>
> \d foo \d bar
> \d foo; \d bar
> \d foo; \d bar;
> \d foo; \d bar
>
> Makes sense...I never combine backslash commands on the same line,
> but it is possible. In that case, how about just moving this section:
>
>   if (semicolon) {
>     int i;
>     for (i = strlen(options_string)-1; i && options_string[i]==';'; i--);
>      if (i<strlen(options_string)-1) options_string[i+1]='\0';
>   }
>
> to right after here, where we find a "normal word"?
>
>   strncpy(return_val, &options_string[pos], token_end);
>   return_val[token_end] = 0;
>
> (and changing options_string to return_val)
>
> that should allow us to catch all the cases above, if I am
> understanding the objection above correctly.
>
> Greg Sabino Mullane
> greg@turnstep.com PGP Key: 0x14964AC8 200110011738
-- End of PGP signed section.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Trailing semicolons in psql patch

From
"Greg Sabino Mullane"
Date:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Attached is the updated version of the patch, which matches
on words as opposed to lines, which means that all of the
following work in psql:

\d foo \d bar
\d foo; \d bar
\d foo \d bar;;
\d foo; <space>


This one also uses "true and false" and strips semicolons
for the following backslash commands: \C \c \d \e \i \o \s \z

Thanks to Bruce Momjian, Peter Eisentraut, and Tom Lane for
the suggestions.

Greg Sabino Mullane
greg@turnstep.com
PGP Key: 0x14964AC8 200110040743

-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iQA+AwUBO7xNp7ybkGcUlkrIEQKzwgCXcaQGh16cXELnjKDs7lpg7BP7twCg1jHW
lDE1BVxPTrLXQZeQRn+ieu4=
=PK53
-----END PGP SIGNATURE-----
*** ./src/bin/psql/command.c.orig    Thu Oct  4 07:26:30 2001
--- ./src/bin/psql/command.c    Thu Oct  4 07:30:37 2001
***************
*** 55,61 ****
  {
      OT_NORMAL, OT_SQLID, OT_FILEPIPE
  };
! static char *scan_option(char **string, enum option_type type, char *quote);
  static char *unescape(const unsigned char *source, size_t len);

  static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
--- 55,61 ----
  {
      OT_NORMAL, OT_SQLID, OT_FILEPIPE
  };
! static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon);
  static char *unescape(const unsigned char *source, size_t len);

  static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
***************
*** 216,222 ****
      /* \C -- override table title (formerly change HTML caption) */
      else if (strcmp(cmd, "C") == 0)
      {
!         char       *opt = scan_option(&string, OT_NORMAL, NULL);

          success = do_pset("title", opt, &pset.popt, quiet);
          free(opt);
--- 216,222 ----
      /* \C -- override table title (formerly change HTML caption) */
      else if (strcmp(cmd, "C") == 0)
      {
!         char       *opt = scan_option(&string, OT_NORMAL, NULL, true);

          success = do_pset("title", opt, &pset.popt, quiet);
          free(opt);
***************
*** 238,245 ****
          char        opt1q,
                      opt2q;

!         opt1 = scan_option(&string, OT_NORMAL, &opt1q);
!         opt2 = scan_option(&string, OT_NORMAL, &opt2q);

          if (opt2)
              /* gave username */
--- 238,245 ----
          char        opt1q,
                      opt2q;

!         opt1 = scan_option(&string, OT_NORMAL, &opt1q, true);
!         opt2 = scan_option(&string, OT_NORMAL, &opt2q, true);

          if (opt2)
              /* gave username */
***************
*** 273,280 ****
      {
          char       *name;
          bool        show_verbose;

-         name = scan_option(&string, OT_SQLID, NULL);
          show_verbose = strchr(cmd, '+') ? true : false;

          switch (cmd[1])
--- 273,280 ----
      {
          char       *name;
          bool        show_verbose;
+         name = scan_option(&string, OT_SQLID, NULL, true);

          show_verbose = strchr(cmd, '+') ? true : false;

          switch (cmd[1])
***************
*** 337,343 ****
          }
          else
          {
!             fname = scan_option(&string, OT_NORMAL, NULL);
              status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
              free(fname);
          }
--- 337,343 ----
          }
          else
          {
!             fname = scan_option(&string, OT_NORMAL, NULL, true);
              status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
              free(fname);
          }
***************
*** 356,363 ****
              fout = pset.queryFout;
          else
              fout = stdout;
!
!         while ((value = scan_option(&string, OT_NORMAL, "ed)))
          {
              if (!quoted && strcmp(value, "-n") == 0)
                  no_newline = true;
--- 356,363 ----
              fout = pset.queryFout;
          else
              fout = stdout;
!
!         while ((value = scan_option(&string, OT_NORMAL, "ed, false)))
          {
              if (!quoted && strcmp(value, "-n") == 0)
                  no_newline = true;
***************
*** 378,384 ****
      /* \encoding -- set/show client side encoding */
      else if (strcmp(cmd, "encoding") == 0)
      {
!         char       *encoding = scan_option(&string, OT_NORMAL, NULL);

          if (!encoding)
              /* show encoding */
--- 378,384 ----
      /* \encoding -- set/show client side encoding */
      else if (strcmp(cmd, "encoding") == 0)
      {
!         char       *encoding = scan_option(&string, OT_NORMAL, NULL, false);

          if (!encoding)
              /* show encoding */
***************
*** 406,412 ****
      /* \f -- change field separator */
      else if (strcmp(cmd, "f") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL);

          success = do_pset("fieldsep", fname, &pset.popt, quiet);
          free(fname);
--- 406,412 ----
      /* \f -- change field separator */
      else if (strcmp(cmd, "f") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL, false);

          success = do_pset("fieldsep", fname, &pset.popt, quiet);
          free(fname);
***************
*** 415,421 ****
      /* \g means send query */
      else if (strcmp(cmd, "g") == 0)
      {
!         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);

          if (!fname)
              pset.gfname = NULL;
--- 415,421 ----
      /* \g means send query */
      else if (strcmp(cmd, "g") == 0)
      {
!         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, false);

          if (!fname)
              pset.gfname = NULL;
***************
*** 447,453 ****
      /* \i is include file */
      else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL);

          if (!fname)
          {
--- 447,453 ----
      /* \i is include file */
      else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL, true);

          if (!fname)
          {
***************
*** 475,482 ****
          char       *opt1,
                     *opt2;

!         opt1 = scan_option(&string, OT_NORMAL, NULL);
!         opt2 = scan_option(&string, OT_NORMAL, NULL);

          if (strcmp(cmd + 3, "export") == 0)
          {
--- 475,482 ----
          char       *opt1,
                     *opt2;

!         opt1 = scan_option(&string, OT_NORMAL, NULL, true);
!         opt2 = scan_option(&string, OT_NORMAL, NULL, true);

          if (strcmp(cmd + 3, "export") == 0)
          {
***************
*** 525,531 ****
      /* \o -- set query output */
      else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
      {
!         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);

          success = setQFout(fname);
          free(fname);
--- 525,531 ----
      /* \o -- set query output */
      else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
      {
!         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, true);

          success = setQFout(fname);
          free(fname);
***************
*** 544,551 ****
      /* \pset -- set printing parameters */
      else if (strcmp(cmd, "pset") == 0)
      {
!         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);
!         char       *opt1 = scan_option(&string, OT_NORMAL, NULL);

          if (!opt0)
          {
--- 544,551 ----
      /* \pset -- set printing parameters */
      else if (strcmp(cmd, "pset") == 0)
      {
!         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
!         char       *opt1 = scan_option(&string, OT_NORMAL, NULL, false);

          if (!opt0)
          {
***************
*** 574,580 ****
      /* \s save history in a file or show it on the screen */
      else if (strcmp(cmd, "s") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL);

          success = saveHistory(fname ? fname : "/dev/tty");

--- 574,580 ----
      /* \s save history in a file or show it on the screen */
      else if (strcmp(cmd, "s") == 0)
      {
!         char       *fname = scan_option(&string, OT_NORMAL, NULL, true);

          success = saveHistory(fname ? fname : "/dev/tty");

***************
*** 586,592 ****
      /* \set -- generalized set variable/option command */
      else if (strcmp(cmd, "set") == 0)
      {
!         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);

          if (!opt0)
          {
--- 586,592 ----
      /* \set -- generalized set variable/option command */
      else if (strcmp(cmd, "set") == 0)
      {
!         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);

          if (!opt0)
          {
***************
*** 611,621 ****
              char       *newval = NULL;
              char       *opt;

!             opt = scan_option(&string, OT_NORMAL, NULL);
              newval = xstrdup(opt ? opt : "");
              free(opt);

!             while ((opt = scan_option(&string, OT_NORMAL, NULL)))
              {
                  newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
                  if (!newval)
--- 611,621 ----
              char       *newval = NULL;
              char       *opt;

!             opt = scan_option(&string, OT_NORMAL, NULL, false);
              newval = xstrdup(opt ? opt : "");
              free(opt);

!             while ((opt = scan_option(&string, OT_NORMAL, NULL, false)))
              {
                  newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
                  if (!newval)
***************
*** 645,651 ****
      /* \T -- define html <table ...> attributes */
      else if (strcmp(cmd, "T") == 0)
      {
!         char       *value = scan_option(&string, OT_NORMAL, NULL);

          success = do_pset("tableattr", value, &pset.popt, quiet);
          free(value);
--- 645,651 ----
      /* \T -- define html <table ...> attributes */
      else if (strcmp(cmd, "T") == 0)
      {
!         char       *value = scan_option(&string, OT_NORMAL, NULL, false);

          success = do_pset("tableattr", value, &pset.popt, quiet);
          free(value);
***************
*** 654,660 ****
      /* \unset */
      else if (strcmp(cmd, "unset") == 0)
      {
!         char       *opt = scan_option(&string, OT_NORMAL, NULL);

          if (!opt)
          {
--- 654,660 ----
      /* \unset */
      else if (strcmp(cmd, "unset") == 0)
      {
!         char       *opt = scan_option(&string, OT_NORMAL, NULL, false);

          if (!opt)
          {
***************
*** 683,689 ****
          }
          else
          {
!             fname = scan_option(&string, OT_FILEPIPE, NULL);

              if (!fname)
              {
--- 683,689 ----
          }
          else
          {
!             fname = scan_option(&string, OT_FILEPIPE, NULL, true);

              if (!fname)
              {
***************
*** 738,744 ****
      /* \z -- list table rights (grant/revoke) */
      else if (strcmp(cmd, "z") == 0)
      {
!         char       *opt = scan_option(&string, OT_SQLID, NULL);

          success = permissionsList(opt);
          free(opt);
--- 738,744 ----
      /* \z -- list table rights (grant/revoke) */
      else if (strcmp(cmd, "z") == 0)
      {
!         char       *opt = scan_option(&string, OT_SQLID, NULL, true);

          success = permissionsList(opt);
          free(opt);
***************
*** 769,775 ****
          char       *value;

          fprintf(stderr, "+ optstr = |%s|\n", options_string);
!         while ((value = scan_option(&string, OT_NORMAL, NULL)))
          {
              fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
              free(value);
--- 769,775 ----
          char       *value;

          fprintf(stderr, "+ optstr = |%s|\n", options_string);
!         while ((value = scan_option(&string, OT_NORMAL, NULL, true)))
          {
              fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
              free(value);
***************
*** 784,790 ****
          status = CMD_ERROR;

      /* eat the rest of the options string */
!     while ((val = scan_option(&string, OT_NORMAL, NULL)))
      {
          if (status != CMD_UNKNOWN)
              psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
--- 784,790 ----
          status = CMD_ERROR;

      /* eat the rest of the options string */
!     while ((val = scan_option(&string, OT_NORMAL, NULL, false)))
      {
          if (status != CMD_UNKNOWN)
              psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
***************
*** 803,809 ****
   * scan_option()
   */
  static char *
! scan_option(char **string, enum option_type type, char *quote)
  {
      unsigned int pos = 0;
      char       *options_string;
--- 803,809 ----
   * scan_option()
   */
  static char *
! scan_option(char **string, enum option_type type, char *quote, bool semicolon)
  {
      unsigned int pos = 0;
      char       *options_string;
***************
*** 860,865 ****
--- 860,866 ----
                   * If this is expected to be an SQL identifier like option
                   * then we strip out the double quotes
                   */
+
                  if (type == OT_SQLID)
                  {
                      unsigned int k,
***************
*** 891,897 ****
                  *string = options_string + jj + 1;
                  if (quote)
                      *quote = '"';
!
                  return return_val;
              }

--- 892,898 ----
                  *string = options_string + jj + 1;
                  if (quote)
                      *quote = '"';
!
                  return return_val;
              }

***************
*** 1071,1076 ****
--- 1072,1084 ----
                  }
                  strncpy(return_val, &options_string[pos], token_end);
                  return_val[token_end] = 0;
+
+                 /* Strip any trailing semi-colons for some types */
+                 if (semicolon) {
+                     int i;
+                     for (i = strlen(return_val)-1; i && return_val[i]==';'; i--);
+                     if (i<strlen(return_val)-1) return_val[i+1]='\0';
+                 }

                  if (type == OT_SQLID)
                      for (cp = return_val; *cp; cp += PQmblen(cp, pset.encoding))

Re: Trailing semicolons in psql patch

From
Bruce Momjian
Date:
Your patch has been added to the PostgreSQL unapplied patches list at:

    http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Attached is the updated version of the patch, which matches
> on words as opposed to lines, which means that all of the
> following work in psql:
>
> \d foo \d bar
> \d foo; \d bar
> \d foo \d bar;;
> \d foo; <space>
>
>
> This one also uses "true and false" and strips semicolons
> for the following backslash commands: \C \c \d \e \i \o \s \z
>
> Thanks to Bruce Momjian, Peter Eisentraut, and Tom Lane for
> the suggestions.
>
> Greg Sabino Mullane
> greg@turnstep.com
> PGP Key: 0x14964AC8 200110040743
>
> -----BEGIN PGP SIGNATURE-----
> Comment: http://www.turnstep.com/pgp.html
>
> iQA+AwUBO7xNp7ybkGcUlkrIEQKzwgCXcaQGh16cXELnjKDs7lpg7BP7twCg1jHW
> lDE1BVxPTrLXQZeQRn+ieu4=
> =PK53
> -----END PGP SIGNATURE-----

> *** ./src/bin/psql/command.c.orig    Thu Oct  4 07:26:30 2001
> --- ./src/bin/psql/command.c    Thu Oct  4 07:30:37 2001
> ***************
> *** 55,61 ****
>   {
>       OT_NORMAL, OT_SQLID, OT_FILEPIPE
>   };
> ! static char *scan_option(char **string, enum option_type type, char *quote);
>   static char *unescape(const unsigned char *source, size_t len);
>
>   static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
> --- 55,61 ----
>   {
>       OT_NORMAL, OT_SQLID, OT_FILEPIPE
>   };
> ! static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon);
>   static char *unescape(const unsigned char *source, size_t len);
>
>   static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
> ***************
> *** 216,222 ****
>       /* \C -- override table title (formerly change HTML caption) */
>       else if (strcmp(cmd, "C") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("title", opt, &pset.popt, quiet);
>           free(opt);
> --- 216,222 ----
>       /* \C -- override table title (formerly change HTML caption) */
>       else if (strcmp(cmd, "C") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL, true);
>
>           success = do_pset("title", opt, &pset.popt, quiet);
>           free(opt);
> ***************
> *** 238,245 ****
>           char        opt1q,
>                       opt2q;
>
> !         opt1 = scan_option(&string, OT_NORMAL, &opt1q);
> !         opt2 = scan_option(&string, OT_NORMAL, &opt2q);
>
>           if (opt2)
>               /* gave username */
> --- 238,245 ----
>           char        opt1q,
>                       opt2q;
>
> !         opt1 = scan_option(&string, OT_NORMAL, &opt1q, true);
> !         opt2 = scan_option(&string, OT_NORMAL, &opt2q, true);
>
>           if (opt2)
>               /* gave username */
> ***************
> *** 273,280 ****
>       {
>           char       *name;
>           bool        show_verbose;
>
> -         name = scan_option(&string, OT_SQLID, NULL);
>           show_verbose = strchr(cmd, '+') ? true : false;
>
>           switch (cmd[1])
> --- 273,280 ----
>       {
>           char       *name;
>           bool        show_verbose;
> +         name = scan_option(&string, OT_SQLID, NULL, true);
>
>           show_verbose = strchr(cmd, '+') ? true : false;
>
>           switch (cmd[1])
> ***************
> *** 337,343 ****
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_NORMAL, NULL);
>               status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
>               free(fname);
>           }
> --- 337,343 ----
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_NORMAL, NULL, true);
>               status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
>               free(fname);
>           }
> ***************
> *** 356,363 ****
>               fout = pset.queryFout;
>           else
>               fout = stdout;
> !
> !         while ((value = scan_option(&string, OT_NORMAL, "ed)))
>           {
>               if (!quoted && strcmp(value, "-n") == 0)
>                   no_newline = true;
> --- 356,363 ----
>               fout = pset.queryFout;
>           else
>               fout = stdout;
> !
> !         while ((value = scan_option(&string, OT_NORMAL, "ed, false)))
>           {
>               if (!quoted && strcmp(value, "-n") == 0)
>                   no_newline = true;
> ***************
> *** 378,384 ****
>       /* \encoding -- set/show client side encoding */
>       else if (strcmp(cmd, "encoding") == 0)
>       {
> !         char       *encoding = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!encoding)
>               /* show encoding */
> --- 378,384 ----
>       /* \encoding -- set/show client side encoding */
>       else if (strcmp(cmd, "encoding") == 0)
>       {
> !         char       *encoding = scan_option(&string, OT_NORMAL, NULL, false);
>
>           if (!encoding)
>               /* show encoding */
> ***************
> *** 406,412 ****
>       /* \f -- change field separator */
>       else if (strcmp(cmd, "f") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("fieldsep", fname, &pset.popt, quiet);
>           free(fname);
> --- 406,412 ----
>       /* \f -- change field separator */
>       else if (strcmp(cmd, "f") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, false);
>
>           success = do_pset("fieldsep", fname, &pset.popt, quiet);
>           free(fname);
> ***************
> *** 415,421 ****
>       /* \g means send query */
>       else if (strcmp(cmd, "g") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>           if (!fname)
>               pset.gfname = NULL;
> --- 415,421 ----
>       /* \g means send query */
>       else if (strcmp(cmd, "g") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, false);
>
>           if (!fname)
>               pset.gfname = NULL;
> ***************
> *** 447,453 ****
>       /* \i is include file */
>       else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!fname)
>           {
> --- 447,453 ----
>       /* \i is include file */
>       else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
>
>           if (!fname)
>           {
> ***************
> *** 475,482 ****
>           char       *opt1,
>                      *opt2;
>
> !         opt1 = scan_option(&string, OT_NORMAL, NULL);
> !         opt2 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (strcmp(cmd + 3, "export") == 0)
>           {
> --- 475,482 ----
>           char       *opt1,
>                      *opt2;
>
> !         opt1 = scan_option(&string, OT_NORMAL, NULL, true);
> !         opt2 = scan_option(&string, OT_NORMAL, NULL, true);
>
>           if (strcmp(cmd + 3, "export") == 0)
>           {
> ***************
> *** 525,531 ****
>       /* \o -- set query output */
>       else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>           success = setQFout(fname);
>           free(fname);
> --- 525,531 ----
>       /* \o -- set query output */
>       else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, true);
>
>           success = setQFout(fname);
>           free(fname);
> ***************
> *** 544,551 ****
>       /* \pset -- set printing parameters */
>       else if (strcmp(cmd, "pset") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);
> !         char       *opt1 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt0)
>           {
> --- 544,551 ----
>       /* \pset -- set printing parameters */
>       else if (strcmp(cmd, "pset") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
> !         char       *opt1 = scan_option(&string, OT_NORMAL, NULL, false);
>
>           if (!opt0)
>           {
> ***************
> *** 574,580 ****
>       /* \s save history in a file or show it on the screen */
>       else if (strcmp(cmd, "s") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           success = saveHistory(fname ? fname : "/dev/tty");
>
> --- 574,580 ----
>       /* \s save history in a file or show it on the screen */
>       else if (strcmp(cmd, "s") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
>
>           success = saveHistory(fname ? fname : "/dev/tty");
>
> ***************
> *** 586,592 ****
>       /* \set -- generalized set variable/option command */
>       else if (strcmp(cmd, "set") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt0)
>           {
> --- 586,592 ----
>       /* \set -- generalized set variable/option command */
>       else if (strcmp(cmd, "set") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
>
>           if (!opt0)
>           {
> ***************
> *** 611,621 ****
>               char       *newval = NULL;
>               char       *opt;
>
> !             opt = scan_option(&string, OT_NORMAL, NULL);
>               newval = xstrdup(opt ? opt : "");
>               free(opt);
>
> !             while ((opt = scan_option(&string, OT_NORMAL, NULL)))
>               {
>                   newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
>                   if (!newval)
> --- 611,621 ----
>               char       *newval = NULL;
>               char       *opt;
>
> !             opt = scan_option(&string, OT_NORMAL, NULL, false);
>               newval = xstrdup(opt ? opt : "");
>               free(opt);
>
> !             while ((opt = scan_option(&string, OT_NORMAL, NULL, false)))
>               {
>                   newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
>                   if (!newval)
> ***************
> *** 645,651 ****
>       /* \T -- define html <table ...> attributes */
>       else if (strcmp(cmd, "T") == 0)
>       {
> !         char       *value = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("tableattr", value, &pset.popt, quiet);
>           free(value);
> --- 645,651 ----
>       /* \T -- define html <table ...> attributes */
>       else if (strcmp(cmd, "T") == 0)
>       {
> !         char       *value = scan_option(&string, OT_NORMAL, NULL, false);
>
>           success = do_pset("tableattr", value, &pset.popt, quiet);
>           free(value);
> ***************
> *** 654,660 ****
>       /* \unset */
>       else if (strcmp(cmd, "unset") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt)
>           {
> --- 654,660 ----
>       /* \unset */
>       else if (strcmp(cmd, "unset") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL, false);
>
>           if (!opt)
>           {
> ***************
> *** 683,689 ****
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>               if (!fname)
>               {
> --- 683,689 ----
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_FILEPIPE, NULL, true);
>
>               if (!fname)
>               {
> ***************
> *** 738,744 ****
>       /* \z -- list table rights (grant/revoke) */
>       else if (strcmp(cmd, "z") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_SQLID, NULL);
>
>           success = permissionsList(opt);
>           free(opt);
> --- 738,744 ----
>       /* \z -- list table rights (grant/revoke) */
>       else if (strcmp(cmd, "z") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_SQLID, NULL, true);
>
>           success = permissionsList(opt);
>           free(opt);
> ***************
> *** 769,775 ****
>           char       *value;
>
>           fprintf(stderr, "+ optstr = |%s|\n", options_string);
> !         while ((value = scan_option(&string, OT_NORMAL, NULL)))
>           {
>               fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
>               free(value);
> --- 769,775 ----
>           char       *value;
>
>           fprintf(stderr, "+ optstr = |%s|\n", options_string);
> !         while ((value = scan_option(&string, OT_NORMAL, NULL, true)))
>           {
>               fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
>               free(value);
> ***************
> *** 784,790 ****
>           status = CMD_ERROR;
>
>       /* eat the rest of the options string */
> !     while ((val = scan_option(&string, OT_NORMAL, NULL)))
>       {
>           if (status != CMD_UNKNOWN)
>               psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
> --- 784,790 ----
>           status = CMD_ERROR;
>
>       /* eat the rest of the options string */
> !     while ((val = scan_option(&string, OT_NORMAL, NULL, false)))
>       {
>           if (status != CMD_UNKNOWN)
>               psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
> ***************
> *** 803,809 ****
>    * scan_option()
>    */
>   static char *
> ! scan_option(char **string, enum option_type type, char *quote)
>   {
>       unsigned int pos = 0;
>       char       *options_string;
> --- 803,809 ----
>    * scan_option()
>    */
>   static char *
> ! scan_option(char **string, enum option_type type, char *quote, bool semicolon)
>   {
>       unsigned int pos = 0;
>       char       *options_string;
> ***************
> *** 860,865 ****
> --- 860,866 ----
>                    * If this is expected to be an SQL identifier like option
>                    * then we strip out the double quotes
>                    */
> +
>                   if (type == OT_SQLID)
>                   {
>                       unsigned int k,
> ***************
> *** 891,897 ****
>                   *string = options_string + jj + 1;
>                   if (quote)
>                       *quote = '"';
> !
>                   return return_val;
>               }
>
> --- 892,898 ----
>                   *string = options_string + jj + 1;
>                   if (quote)
>                       *quote = '"';
> !
>                   return return_val;
>               }
>
> ***************
> *** 1071,1076 ****
> --- 1072,1084 ----
>                   }
>                   strncpy(return_val, &options_string[pos], token_end);
>                   return_val[token_end] = 0;
> +
> +                 /* Strip any trailing semi-colons for some types */
> +                 if (semicolon) {
> +                     int i;
> +                     for (i = strlen(return_val)-1; i && return_val[i]==';'; i--);
> +                     if (i<strlen(return_val)-1) return_val[i+1]='\0';
> +                 }
>
>                   if (type == OT_SQLID)
>                       for (cp = return_val; *cp; cp += PQmblen(cp, pset.encoding))

>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Trailing semicolons in psql patch

From
Bruce Momjian
Date:
Patch applied.  Thanks.

Also, seems there is now a \cd command.  I assume the param for that
would be 'true'.


>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Attached is the updated version of the patch, which matches
> on words as opposed to lines, which means that all of the
> following work in psql:
>
> \d foo \d bar
> \d foo; \d bar
> \d foo \d bar;;
> \d foo; <space>
>
>
> This one also uses "true and false" and strips semicolons
> for the following backslash commands: \C \c \d \e \i \o \s \z
>
> Thanks to Bruce Momjian, Peter Eisentraut, and Tom Lane for
> the suggestions.
>
> Greg Sabino Mullane
> greg@turnstep.com
> PGP Key: 0x14964AC8 200110040743
>
> -----BEGIN PGP SIGNATURE-----
> Comment: http://www.turnstep.com/pgp.html
>
> iQA+AwUBO7xNp7ybkGcUlkrIEQKzwgCXcaQGh16cXELnjKDs7lpg7BP7twCg1jHW
> lDE1BVxPTrLXQZeQRn+ieu4=
> =PK53
> -----END PGP SIGNATURE-----

> *** ./src/bin/psql/command.c.orig    Thu Oct  4 07:26:30 2001
> --- ./src/bin/psql/command.c    Thu Oct  4 07:30:37 2001
> ***************
> *** 55,61 ****
>   {
>       OT_NORMAL, OT_SQLID, OT_FILEPIPE
>   };
> ! static char *scan_option(char **string, enum option_type type, char *quote);
>   static char *unescape(const unsigned char *source, size_t len);
>
>   static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
> --- 55,61 ----
>   {
>       OT_NORMAL, OT_SQLID, OT_FILEPIPE
>   };
> ! static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon);
>   static char *unescape(const unsigned char *source, size_t len);
>
>   static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
> ***************
> *** 216,222 ****
>       /* \C -- override table title (formerly change HTML caption) */
>       else if (strcmp(cmd, "C") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("title", opt, &pset.popt, quiet);
>           free(opt);
> --- 216,222 ----
>       /* \C -- override table title (formerly change HTML caption) */
>       else if (strcmp(cmd, "C") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL, true);
>
>           success = do_pset("title", opt, &pset.popt, quiet);
>           free(opt);
> ***************
> *** 238,245 ****
>           char        opt1q,
>                       opt2q;
>
> !         opt1 = scan_option(&string, OT_NORMAL, &opt1q);
> !         opt2 = scan_option(&string, OT_NORMAL, &opt2q);
>
>           if (opt2)
>               /* gave username */
> --- 238,245 ----
>           char        opt1q,
>                       opt2q;
>
> !         opt1 = scan_option(&string, OT_NORMAL, &opt1q, true);
> !         opt2 = scan_option(&string, OT_NORMAL, &opt2q, true);
>
>           if (opt2)
>               /* gave username */
> ***************
> *** 273,280 ****
>       {
>           char       *name;
>           bool        show_verbose;
>
> -         name = scan_option(&string, OT_SQLID, NULL);
>           show_verbose = strchr(cmd, '+') ? true : false;
>
>           switch (cmd[1])
> --- 273,280 ----
>       {
>           char       *name;
>           bool        show_verbose;
> +         name = scan_option(&string, OT_SQLID, NULL, true);
>
>           show_verbose = strchr(cmd, '+') ? true : false;
>
>           switch (cmd[1])
> ***************
> *** 337,343 ****
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_NORMAL, NULL);
>               status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
>               free(fname);
>           }
> --- 337,343 ----
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_NORMAL, NULL, true);
>               status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
>               free(fname);
>           }
> ***************
> *** 356,363 ****
>               fout = pset.queryFout;
>           else
>               fout = stdout;
> !
> !         while ((value = scan_option(&string, OT_NORMAL, "ed)))
>           {
>               if (!quoted && strcmp(value, "-n") == 0)
>                   no_newline = true;
> --- 356,363 ----
>               fout = pset.queryFout;
>           else
>               fout = stdout;
> !
> !         while ((value = scan_option(&string, OT_NORMAL, "ed, false)))
>           {
>               if (!quoted && strcmp(value, "-n") == 0)
>                   no_newline = true;
> ***************
> *** 378,384 ****
>       /* \encoding -- set/show client side encoding */
>       else if (strcmp(cmd, "encoding") == 0)
>       {
> !         char       *encoding = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!encoding)
>               /* show encoding */
> --- 378,384 ----
>       /* \encoding -- set/show client side encoding */
>       else if (strcmp(cmd, "encoding") == 0)
>       {
> !         char       *encoding = scan_option(&string, OT_NORMAL, NULL, false);
>
>           if (!encoding)
>               /* show encoding */
> ***************
> *** 406,412 ****
>       /* \f -- change field separator */
>       else if (strcmp(cmd, "f") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("fieldsep", fname, &pset.popt, quiet);
>           free(fname);
> --- 406,412 ----
>       /* \f -- change field separator */
>       else if (strcmp(cmd, "f") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, false);
>
>           success = do_pset("fieldsep", fname, &pset.popt, quiet);
>           free(fname);
> ***************
> *** 415,421 ****
>       /* \g means send query */
>       else if (strcmp(cmd, "g") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>           if (!fname)
>               pset.gfname = NULL;
> --- 415,421 ----
>       /* \g means send query */
>       else if (strcmp(cmd, "g") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, false);
>
>           if (!fname)
>               pset.gfname = NULL;
> ***************
> *** 447,453 ****
>       /* \i is include file */
>       else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!fname)
>           {
> --- 447,453 ----
>       /* \i is include file */
>       else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
>
>           if (!fname)
>           {
> ***************
> *** 475,482 ****
>           char       *opt1,
>                      *opt2;
>
> !         opt1 = scan_option(&string, OT_NORMAL, NULL);
> !         opt2 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (strcmp(cmd + 3, "export") == 0)
>           {
> --- 475,482 ----
>           char       *opt1,
>                      *opt2;
>
> !         opt1 = scan_option(&string, OT_NORMAL, NULL, true);
> !         opt2 = scan_option(&string, OT_NORMAL, NULL, true);
>
>           if (strcmp(cmd + 3, "export") == 0)
>           {
> ***************
> *** 525,531 ****
>       /* \o -- set query output */
>       else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>           success = setQFout(fname);
>           free(fname);
> --- 525,531 ----
>       /* \o -- set query output */
>       else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_FILEPIPE, NULL, true);
>
>           success = setQFout(fname);
>           free(fname);
> ***************
> *** 544,551 ****
>       /* \pset -- set printing parameters */
>       else if (strcmp(cmd, "pset") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);
> !         char       *opt1 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt0)
>           {
> --- 544,551 ----
>       /* \pset -- set printing parameters */
>       else if (strcmp(cmd, "pset") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
> !         char       *opt1 = scan_option(&string, OT_NORMAL, NULL, false);
>
>           if (!opt0)
>           {
> ***************
> *** 574,580 ****
>       /* \s save history in a file or show it on the screen */
>       else if (strcmp(cmd, "s") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL);
>
>           success = saveHistory(fname ? fname : "/dev/tty");
>
> --- 574,580 ----
>       /* \s save history in a file or show it on the screen */
>       else if (strcmp(cmd, "s") == 0)
>       {
> !         char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
>
>           success = saveHistory(fname ? fname : "/dev/tty");
>
> ***************
> *** 586,592 ****
>       /* \set -- generalized set variable/option command */
>       else if (strcmp(cmd, "set") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt0)
>           {
> --- 586,592 ----
>       /* \set -- generalized set variable/option command */
>       else if (strcmp(cmd, "set") == 0)
>       {
> !         char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
>
>           if (!opt0)
>           {
> ***************
> *** 611,621 ****
>               char       *newval = NULL;
>               char       *opt;
>
> !             opt = scan_option(&string, OT_NORMAL, NULL);
>               newval = xstrdup(opt ? opt : "");
>               free(opt);
>
> !             while ((opt = scan_option(&string, OT_NORMAL, NULL)))
>               {
>                   newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
>                   if (!newval)
> --- 611,621 ----
>               char       *newval = NULL;
>               char       *opt;
>
> !             opt = scan_option(&string, OT_NORMAL, NULL, false);
>               newval = xstrdup(opt ? opt : "");
>               free(opt);
>
> !             while ((opt = scan_option(&string, OT_NORMAL, NULL, false)))
>               {
>                   newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
>                   if (!newval)
> ***************
> *** 645,651 ****
>       /* \T -- define html <table ...> attributes */
>       else if (strcmp(cmd, "T") == 0)
>       {
> !         char       *value = scan_option(&string, OT_NORMAL, NULL);
>
>           success = do_pset("tableattr", value, &pset.popt, quiet);
>           free(value);
> --- 645,651 ----
>       /* \T -- define html <table ...> attributes */
>       else if (strcmp(cmd, "T") == 0)
>       {
> !         char       *value = scan_option(&string, OT_NORMAL, NULL, false);
>
>           success = do_pset("tableattr", value, &pset.popt, quiet);
>           free(value);
> ***************
> *** 654,660 ****
>       /* \unset */
>       else if (strcmp(cmd, "unset") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL);
>
>           if (!opt)
>           {
> --- 654,660 ----
>       /* \unset */
>       else if (strcmp(cmd, "unset") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_NORMAL, NULL, false);
>
>           if (!opt)
>           {
> ***************
> *** 683,689 ****
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_FILEPIPE, NULL);
>
>               if (!fname)
>               {
> --- 683,689 ----
>           }
>           else
>           {
> !             fname = scan_option(&string, OT_FILEPIPE, NULL, true);
>
>               if (!fname)
>               {
> ***************
> *** 738,744 ****
>       /* \z -- list table rights (grant/revoke) */
>       else if (strcmp(cmd, "z") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_SQLID, NULL);
>
>           success = permissionsList(opt);
>           free(opt);
> --- 738,744 ----
>       /* \z -- list table rights (grant/revoke) */
>       else if (strcmp(cmd, "z") == 0)
>       {
> !         char       *opt = scan_option(&string, OT_SQLID, NULL, true);
>
>           success = permissionsList(opt);
>           free(opt);
> ***************
> *** 769,775 ****
>           char       *value;
>
>           fprintf(stderr, "+ optstr = |%s|\n", options_string);
> !         while ((value = scan_option(&string, OT_NORMAL, NULL)))
>           {
>               fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
>               free(value);
> --- 769,775 ----
>           char       *value;
>
>           fprintf(stderr, "+ optstr = |%s|\n", options_string);
> !         while ((value = scan_option(&string, OT_NORMAL, NULL, true)))
>           {
>               fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
>               free(value);
> ***************
> *** 784,790 ****
>           status = CMD_ERROR;
>
>       /* eat the rest of the options string */
> !     while ((val = scan_option(&string, OT_NORMAL, NULL)))
>       {
>           if (status != CMD_UNKNOWN)
>               psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
> --- 784,790 ----
>           status = CMD_ERROR;
>
>       /* eat the rest of the options string */
> !     while ((val = scan_option(&string, OT_NORMAL, NULL, false)))
>       {
>           if (status != CMD_UNKNOWN)
>               psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
> ***************
> *** 803,809 ****
>    * scan_option()
>    */
>   static char *
> ! scan_option(char **string, enum option_type type, char *quote)
>   {
>       unsigned int pos = 0;
>       char       *options_string;
> --- 803,809 ----
>    * scan_option()
>    */
>   static char *
> ! scan_option(char **string, enum option_type type, char *quote, bool semicolon)
>   {
>       unsigned int pos = 0;
>       char       *options_string;
> ***************
> *** 860,865 ****
> --- 860,866 ----
>                    * If this is expected to be an SQL identifier like option
>                    * then we strip out the double quotes
>                    */
> +
>                   if (type == OT_SQLID)
>                   {
>                       unsigned int k,
> ***************
> *** 891,897 ****
>                   *string = options_string + jj + 1;
>                   if (quote)
>                       *quote = '"';
> !
>                   return return_val;
>               }
>
> --- 892,898 ----
>                   *string = options_string + jj + 1;
>                   if (quote)
>                       *quote = '"';
> !
>                   return return_val;
>               }
>
> ***************
> *** 1071,1076 ****
> --- 1072,1084 ----
>                   }
>                   strncpy(return_val, &options_string[pos], token_end);
>                   return_val[token_end] = 0;
> +
> +                 /* Strip any trailing semi-colons for some types */
> +                 if (semicolon) {
> +                     int i;
> +                     for (i = strlen(return_val)-1; i && return_val[i]==';'; i--);
> +                     if (i<strlen(return_val)-1) return_val[i+1]='\0';
> +                 }
>
>                   if (type == OT_SQLID)
>                       for (cp = return_val; *cp; cp += PQmblen(cp, pset.encoding))

>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026