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; } }