Commit 92459e7a authored by Tom Lane's avatar Tom Lane

Fix translatability markings in psql, and add defenses against future bugs.

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 89368676
(added prosecdef to \df+), c9ac00e6 (added description to \dc+) and
3b17efdf (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
parent 5858cf8a
...@@ -224,7 +224,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool ...@@ -224,7 +224,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
PQExpBufferData buf; PQExpBufferData buf;
PGresult *res; PGresult *res;
printQueryOpt myopt = pset.popt; 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+")) if (strlen(functypes) != strspn(functypes, "antwS+"))
{ {
...@@ -457,6 +457,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool ...@@ -457,6 +457,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
myopt.title = _("List of functions"); myopt.title = _("List of functions");
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -789,6 +790,7 @@ permissionsList(const char *pattern) ...@@ -789,6 +790,7 @@ permissionsList(const char *pattern)
myopt.title = buf.data; myopt.title = buf.data;
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -862,6 +864,7 @@ listDefaultACLs(const char *pattern) ...@@ -862,6 +864,7 @@ listDefaultACLs(const char *pattern)
myopt.title = buf.data; myopt.title = buf.data;
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -1034,6 +1037,7 @@ objectDescription(const char *pattern, bool showSystem) ...@@ -1034,6 +1037,7 @@ objectDescription(const char *pattern, bool showSystem)
myopt.title = _("Object descriptions"); myopt.title = _("Object descriptions");
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -2818,6 +2822,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys ...@@ -2818,6 +2822,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
myopt.title = _("List of relations"); myopt.title = _("List of relations");
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
} }
...@@ -2999,7 +3004,8 @@ listConversions(const char *pattern, bool verbose, bool showSystem) ...@@ -2999,7 +3004,8 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
PQExpBufferData buf; PQExpBufferData buf;
PGresult *res; PGresult *res;
printQueryOpt myopt = pset.popt; 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); initPQExpBuffer(&buf);
...@@ -3055,6 +3061,7 @@ listConversions(const char *pattern, bool verbose, bool showSystem) ...@@ -3055,6 +3061,7 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
myopt.title = _("List of conversions"); myopt.title = _("List of conversions");
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -3079,19 +3086,23 @@ listEventTriggers(const char *pattern, bool verbose) ...@@ -3079,19 +3086,23 @@ listEventTriggers(const char *pattern, bool verbose)
initPQExpBuffer(&buf); initPQExpBuffer(&buf);
printfPQExpBuffer(&buf, printfPQExpBuffer(&buf,
"select evtname as \"%s\", " "SELECT evtname as \"%s\", "
"evtevent as \"%s\", " "evtevent as \"%s\", "
"pg_catalog.pg_get_userbyid(e.evtowner) AS \"%s\", " "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
"case evtenabled when 'O' then 'enabled' " " case evtenabled when 'O' then '%s'"
" when 'R' then 'replica' " " when 'R' then '%s'"
" when 'A' then 'always' " " when 'A' then '%s'"
" when 'D' then 'disabled' end as \"%s\", " " when 'D' then '%s' end as \"%s\",\n"
"e.evtfoid::regproc as \"%s\", " " e.evtfoid::pg_catalog.regproc as \"%s\", "
"array_to_string(array(select x " "pg_catalog.array_to_string(array(select x"
" from unnest(evttags) as t(x)), ', ') as \"%s\" ", " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
gettext_noop("Name"), gettext_noop("Name"),
gettext_noop("Event"), gettext_noop("Event"),
gettext_noop("Owner"), gettext_noop("Owner"),
gettext_noop("enabled"),
gettext_noop("replica"),
gettext_noop("always"),
gettext_noop("disabled"),
gettext_noop("Enabled"), gettext_noop("Enabled"),
gettext_noop("Procedure"), gettext_noop("Procedure"),
gettext_noop("Tags")); gettext_noop("Tags"));
...@@ -3100,7 +3111,7 @@ listEventTriggers(const char *pattern, bool verbose) ...@@ -3100,7 +3111,7 @@ listEventTriggers(const char *pattern, bool verbose)
",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"", ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
gettext_noop("Description")); gettext_noop("Description"));
appendPQExpBufferStr(&buf, appendPQExpBufferStr(&buf,
"\nFROM pg_event_trigger e "); "\nFROM pg_catalog.pg_event_trigger e ");
processSQLNamePattern(pset.db, &buf, pattern, false, false, processSQLNamePattern(pset.db, &buf, pattern, false, false,
NULL, "evtname", NULL, NULL); NULL, "evtname", NULL, NULL);
...@@ -3116,6 +3127,7 @@ listEventTriggers(const char *pattern, bool verbose) ...@@ -3116,6 +3127,7 @@ listEventTriggers(const char *pattern, bool verbose)
myopt.title = _("List of event triggers"); myopt.title = _("List of event triggers");
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -3134,7 +3146,7 @@ listCasts(const char *pattern, bool verbose) ...@@ -3134,7 +3146,7 @@ listCasts(const char *pattern, bool verbose)
PQExpBufferData buf; PQExpBufferData buf;
PGresult *res; PGresult *res;
printQueryOpt myopt = pset.popt; 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); initPQExpBuffer(&buf);
...@@ -3214,6 +3226,7 @@ listCasts(const char *pattern, bool verbose) ...@@ -3214,6 +3226,7 @@ listCasts(const char *pattern, bool verbose)
myopt.title = _("List of casts"); myopt.title = _("List of casts");
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -3289,6 +3302,7 @@ listCollations(const char *pattern, bool verbose, bool showSystem) ...@@ -3289,6 +3302,7 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
myopt.title = _("List of collations"); myopt.title = _("List of collations");
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -3548,6 +3562,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname) ...@@ -3548,6 +3562,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
myopt.topt.default_footer = false; myopt.topt.default_footer = false;
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = translate_columns; myopt.translate_columns = translate_columns;
myopt.n_translate_columns = lengthof(translate_columns);
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
...@@ -3579,6 +3594,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname) ...@@ -3579,6 +3594,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
myopt.topt.default_footer = true; myopt.topt.default_footer = true;
myopt.translate_header = true; myopt.translate_header = true;
myopt.translate_columns = NULL; myopt.translate_columns = NULL;
myopt.n_translate_columns = 0;
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
......
...@@ -2596,6 +2596,10 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f ...@@ -2596,6 +2596,10 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
printTableInit(&cont, &opt->topt, opt->title, printTableInit(&cont, &opt->topt, opt->title,
PQnfields(result), PQntuples(result)); 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++) for (i = 0; i < cont.ncolumns; i++)
{ {
char align; char align;
......
...@@ -146,6 +146,7 @@ typedef struct printQueryOpt ...@@ -146,6 +146,7 @@ typedef struct printQueryOpt
bool translate_header; /* do gettext on column headers */ bool translate_header; /* do gettext on column headers */
const bool *translate_columns; /* translate_columns[i-1] => do const bool *translate_columns; /* translate_columns[i-1] => do
* gettext on col i */ * gettext on col i */
int n_translate_columns; /* length of translate_columns[] */
} printQueryOpt; } printQueryOpt;
......
...@@ -160,6 +160,8 @@ main(int argc, char *argv[]) ...@@ -160,6 +160,8 @@ main(int argc, char *argv[])
popt.title = _("Procedural Languages"); popt.title = _("Procedural Languages");
popt.translate_header = true; popt.translate_header = true;
popt.translate_columns = translate_columns; popt.translate_columns = translate_columns;
popt.n_translate_columns = lengthof(translate_columns);
printQuery(result, &popt, stdout, NULL); printQuery(result, &popt, stdout, NULL);
PQfinish(conn); PQfinish(conn);
......
...@@ -159,6 +159,8 @@ main(int argc, char *argv[]) ...@@ -159,6 +159,8 @@ main(int argc, char *argv[])
popt.title = _("Procedural Languages"); popt.title = _("Procedural Languages");
popt.translate_header = true; popt.translate_header = true;
popt.translate_columns = translate_columns; popt.translate_columns = translate_columns;
popt.n_translate_columns = lengthof(translate_columns);
printQuery(result, &popt, stdout, NULL); printQuery(result, &popt, stdout, NULL);
PQfinish(conn); PQfinish(conn);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment