]> granicus.if.org Git - postgresql/commitdiff
Fix translatability markings in psql, and add defenses against future bugs.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 4 Jan 2014 21:05:16 +0000 (16:05 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 4 Jan 2014 21:05:16 +0000 (16:05 -0500)
Several previous commits have added columns to various \d queries without
updating their translate_columns[] arrays, leading to potentially incorrect
translations in NLS-enabled builds.  Offenders include commit 893686762
(added prosecdef to \df+), c9ac00e6e (added description to \dc+) and
3b17efdfd (added description to \dC+).  Fix those cases back to 9.3 or
9.2 as appropriate.

Since this is evidently more easily missed than one would like, in HEAD
also add an Assert that the supplied array is long enough.  This requires
an API change for printQuery(), so it seems inappropriate for back
branches, but presumably all future changes will be tested in HEAD anyway.

In HEAD and 9.3, also clean up a whole lot of sloppiness in the emitted
SQL for \dy (event triggers): lack of translatability due to failing to
pass words-to-be-translated through gettext_noop(), inadequate schema
qualification, and sloppy formatting resulting in unnecessarily ugly
-E output.

Peter Eisentraut and Tom Lane, per bug #8702 from Sergey Burladyan

src/bin/psql/describe.c
src/bin/psql/print.c
src/bin/psql/print.h
src/bin/scripts/createlang.c
src/bin/scripts/droplang.c

index 96322ca85b8f058e40ad2646c7b99ea64c137da2..d6d9c605cc07449c41cda481f74f12e8b5f07758 100644 (file)
@@ -224,7 +224,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
        PQExpBufferData buf;
        PGresult   *res;
        printQueryOpt myopt = pset.popt;
-       static const bool translate_columns[] = {false, false, false, false, true, true, false, false, false, false};
+       static const bool translate_columns[] = {false, false, false, false, true, true, true, false, false, false, false};
 
        if (strlen(functypes) != strspn(functypes, "antwS+"))
        {
@@ -457,6 +457,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
        myopt.title = _("List of functions");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -789,6 +790,7 @@ permissionsList(const char *pattern)
        myopt.title = buf.data;
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -862,6 +864,7 @@ listDefaultACLs(const char *pattern)
        myopt.title = buf.data;
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -1034,6 +1037,7 @@ objectDescription(const char *pattern, bool showSystem)
        myopt.title = _("Object descriptions");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -2818,6 +2822,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
                myopt.title = _("List of relations");
                myopt.translate_header = true;
                myopt.translate_columns = translate_columns;
+               myopt.n_translate_columns = lengthof(translate_columns);
 
                printQuery(res, &myopt, pset.queryFout, pset.logfile);
        }
@@ -2999,7 +3004,8 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
        PQExpBufferData buf;
        PGresult   *res;
        printQueryOpt myopt = pset.popt;
-       static const bool translate_columns[] = {false, false, false, false, true};
+       static const bool translate_columns[] =
+               {false, false, false, false, true, false};
 
        initPQExpBuffer(&buf);
 
@@ -3055,6 +3061,7 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
        myopt.title = _("List of conversions");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -3079,19 +3086,23 @@ listEventTriggers(const char *pattern, bool verbose)
        initPQExpBuffer(&buf);
 
        printfPQExpBuffer(&buf,
-                                         "select evtname as \"%s\", "
-                                         "evtevent as  \"%s\", "
-                                         "pg_catalog.pg_get_userbyid(e.evtowner) AS \"%s\", "
-                                         "case evtenabled when 'O' then 'enabled' "
-                                         "  when 'R' then 'replica' "
-                                         "  when 'A' then 'always' "
-                                         "  when 'D' then 'disabled' end as  \"%s\", "
-                                         "e.evtfoid::regproc as \"%s\", "
-                                         "array_to_string(array(select x "
-                                       "      from unnest(evttags) as t(x)), ', ') as  \"%s\" ",
+                                         "SELECT evtname as \"%s\", "
+                                         "evtevent as \"%s\", "
+                                         "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
+                                         " case evtenabled when 'O' then '%s'"
+                                         "  when 'R' then '%s'"
+                                         "  when 'A' then '%s'"
+                                         "  when 'D' then '%s' end as \"%s\",\n"
+                                         " e.evtfoid::pg_catalog.regproc as \"%s\", "
+                                         "pg_catalog.array_to_string(array(select x"
+                                         " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
                                          gettext_noop("Name"),
                                          gettext_noop("Event"),
                                          gettext_noop("Owner"),
+                                         gettext_noop("enabled"),
+                                         gettext_noop("replica"),
+                                         gettext_noop("always"),
+                                         gettext_noop("disabled"),
                                          gettext_noop("Enabled"),
                                          gettext_noop("Procedure"),
                                          gettext_noop("Tags"));
@@ -3100,7 +3111,7 @@ listEventTriggers(const char *pattern, bool verbose)
                ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
                                                  gettext_noop("Description"));
        appendPQExpBufferStr(&buf,
-                                                "\nFROM pg_event_trigger e ");
+                                                "\nFROM pg_catalog.pg_event_trigger e ");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                  NULL, "evtname", NULL, NULL);
@@ -3116,6 +3127,7 @@ listEventTriggers(const char *pattern, bool verbose)
        myopt.title = _("List of event triggers");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -3134,7 +3146,7 @@ listCasts(const char *pattern, bool verbose)
        PQExpBufferData buf;
        PGresult   *res;
        printQueryOpt myopt = pset.popt;
-       static const bool translate_columns[] = {false, false, false, true};
+       static const bool translate_columns[] = {false, false, false, true, false};
 
        initPQExpBuffer(&buf);
 
@@ -3214,6 +3226,7 @@ listCasts(const char *pattern, bool verbose)
        myopt.title = _("List of casts");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -3289,6 +3302,7 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
        myopt.title = _("List of collations");
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -3548,6 +3562,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
        myopt.topt.default_footer = false;
        myopt.translate_header = true;
        myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
@@ -3579,6 +3594,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
        myopt.topt.default_footer = true;
        myopt.translate_header = true;
        myopt.translate_columns = NULL;
+       myopt.n_translate_columns = 0;
 
        printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
index 736225c629ef29f0188dc8b23f37961d7bb1e1e6..fdf4dcc22e7120912cc317636dc0348318afd10f 100644 (file)
@@ -2596,6 +2596,10 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
        printTableInit(&cont, &opt->topt, opt->title,
                                   PQnfields(result), PQntuples(result));
 
+       /* Assert caller supplied enough translate_columns[] entries */
+       Assert(opt->translate_columns == NULL ||
+                  opt->n_translate_columns >= cont.ncolumns);
+
        for (i = 0; i < cont.ncolumns; i++)
        {
                char            align;
index 9cfa3b6a4171a160e188b56012715bf65893b58a..41ba7989858ffdce03b17d303a757ac486c15f4e 100644 (file)
@@ -146,6 +146,7 @@ typedef struct printQueryOpt
        bool            translate_header;               /* do gettext on column headers */
        const bool *translate_columns;          /* translate_columns[i-1] => do
                                                                                 * gettext on col i */
+       int                     n_translate_columns;    /* length of translate_columns[] */
 } printQueryOpt;
 
 
index 5cfba8e3d5a679dda4261aa00e4ac7191759e73b..92ab97540f73e057ca95c781e406e116269a3cfc 100644 (file)
@@ -160,6 +160,8 @@ main(int argc, char *argv[])
                popt.title = _("Procedural Languages");
                popt.translate_header = true;
                popt.translate_columns = translate_columns;
+               popt.n_translate_columns = lengthof(translate_columns);
+
                printQuery(result, &popt, stdout, NULL);
 
                PQfinish(conn);
index b9664a918500015f75e78284536f46192444ca6c..3650096f735962c59976dc379268bffd9cb800c4 100644 (file)
@@ -159,6 +159,8 @@ main(int argc, char *argv[])
                popt.title = _("Procedural Languages");
                popt.translate_header = true;
                popt.translate_columns = translate_columns;
+               popt.n_translate_columns = lengthof(translate_columns);
+
                printQuery(result, &popt, stdout, NULL);
 
                PQfinish(conn);