Tom Lane wrote:

> > but "one letter is enough" is not true since 9.3 that added
> > "latex-longtable" sharing the same start as "latex", and then 
> > 9.5 added "asciidoc" with the same first letter as "aligned".
> 
> Yeah, that text has clearly outstayed its welcome.
> 
> > When a non-unique abbreviation is used, psql uses the first
> > match in an arbitrary order defined in do_pset() by
> > a cascade of pg_strncasecmp().
> 
> Ugh.  Should we not fix the code so that it complains if there's
> not a unique match?  I would bet that the code was also written
> on the assumption that any abbrevation must be unique.

Here's a patch making "\pset format" reject ambiguous abbreviations.


Best regards,
-- 
Daniel Vérité
PostgreSQL-powered mailer: http://www.manitou-mail.org
Twitter: @DanielVerite
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index a1ca940..6e6d0f4 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -2589,8 +2589,7 @@ lo_import 152801
           <literal>latex</literal> (uses <literal>tabular</literal>),
           <literal>latex-longtable</literal>, <literal>troff-ms</literal>,
           <literal>unaligned</literal>, or <literal>wrapped</literal>.
-          Unique abbreviations are allowed.  (That would mean one letter
-          is enough.)
+          Unique abbreviations are allowed.
           </para>
 
           <para><literal>unaligned</literal> format writes all columns of a 
row on one
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 0dea54d..1f23aaf 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -3637,28 +3637,52 @@ do_pset(const char *param, const char *value, 
printQueryOpt *popt, bool quiet)
        /* set format */
        if (strcmp(param, "format") == 0)
        {
+               static const struct fmt
+               {
+                       const char *name;
+                       enum printFormat number;
+               }                       formats[] =
+               {
+                       {"aligned", PRINT_ALIGNED},
+                       {"asciidoc", PRINT_ASCIIDOC},
+                       {"html", PRINT_HTML},
+                       {"latex", PRINT_LATEX},
+                       {"latex-longtable", PRINT_LATEX_LONGTABLE},
+                       {"troff-ms", PRINT_TROFF_MS},
+                       {"unaligned", PRINT_UNALIGNED},
+                       {"wrapped", PRINT_WRAPPED}
+               };
+
                if (!value)
                        ;
-               else if (pg_strncasecmp("aligned", value, vallen) == 0)
-                       popt->topt.format = PRINT_ALIGNED;
-               else if (pg_strncasecmp("asciidoc", value, vallen) == 0)
-                       popt->topt.format = PRINT_ASCIIDOC;
-               else if (pg_strncasecmp("html", value, vallen) == 0)
-                       popt->topt.format = PRINT_HTML;
-               else if (pg_strncasecmp("latex", value, vallen) == 0)
-                       popt->topt.format = PRINT_LATEX;
-               else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
-                       popt->topt.format = PRINT_LATEX_LONGTABLE;
-               else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
-                       popt->topt.format = PRINT_TROFF_MS;
-               else if (pg_strncasecmp("unaligned", value, vallen) == 0)
-                       popt->topt.format = PRINT_UNALIGNED;
-               else if (pg_strncasecmp("wrapped", value, vallen) == 0)
-                       popt->topt.format = PRINT_WRAPPED;
                else
                {
-                       psql_error("\\pset: allowed formats are aligned, 
asciidoc, html, latex, latex-longtable, troff-ms, unaligned, wrapped\n");
-                       return false;
+                       int                     match_count = 0;
+                       int                     first_match = 0;
+
+                       /*
+                        * Count the number of left-anchored matches. Exactly 
one match
+                        * must be found, otherwise error out.
+                        */
+                       for (int i = 0; i < lengthof(formats); i++)
+                       {
+                               if (pg_strncasecmp(formats[i].name, value, 
vallen) == 0)
+                               {
+                                       if (++match_count > 1)
+                                       {
+                                               psql_error("\\pset: ambiguous 
abbreviation: \"%s\"\n", value);
+                                               return false;
+                                       }
+                                       first_match = i;
+                               }
+                       }
+                       if (match_count == 0)
+                       {
+                               psql_error("\\pset: allowed formats are 
aligned, asciidoc, html, latex, latex-longtable, troff-ms, unaligned, 
wrapped\n");
+                               return false;
+                       }
+                       else
+                               popt->topt.format = formats[first_match].number;
                }
        }
 

Reply via email to