Commit df4271fe authored by Tom Lane's avatar Tom Lane

Improve the method of localizing column names and other fixed strings in

psql's \d commands and other uses of printQuery().  Previously we would pass
these strings through gettext() and then send them to the server as literals
in the SQL query.  But the code was not set up to handle doubling of quotes in
the strings, causing failure if a translation attempted to use the wrong kind
of quote marks, as indeed is now the case for (at least) the French
translation of \dFp.  Another hazard was that gettext() would translate to
whatever encoding was implied by the client's LC_CTYPE setting, which might be
different from the client_encoding setting, which would probably cause the
server to reject the query as mis-encoded.  The new arrangement is to send the
untranslated ASCII strings to the server, and do the translations inside
printQuery() after the query results come back.  Per report from Guillaume
Lelarge and subsequent discussion.
parent 286049db
This diff is collapsed.
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2007, PostgreSQL Global Development Group * Copyright (c) 2000-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.48 2007/01/20 16:57:31 neilc Exp $ * $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.49 2007/12/12 21:41:47 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "large_obj.h" #include "large_obj.h"
...@@ -279,11 +279,12 @@ do_lo_list(void) ...@@ -279,11 +279,12 @@ do_lo_list(void)
printQueryOpt myopt = pset.popt; printQueryOpt myopt = pset.popt;
snprintf(buf, sizeof(buf), snprintf(buf, sizeof(buf),
"SELECT loid as \"ID\",\n" "SELECT loid as \"%s\",\n"
" pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n" " pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
"FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n" "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
"ORDER BY 1", "ORDER BY 1",
_("Description")); gettext_noop("ID"),
gettext_noop("Description"));
res = PSQLexec(buf, false); res = PSQLexec(buf, false);
if (!res) if (!res)
...@@ -292,6 +293,7 @@ do_lo_list(void) ...@@ -292,6 +293,7 @@ do_lo_list(void)
myopt.topt.tuples_only = false; myopt.topt.tuples_only = false;
myopt.nullPrint = NULL; myopt.nullPrint = NULL;
myopt.title = _("Large objects"); myopt.title = _("Large objects");
myopt.trans_headers = true;
printQuery(res, &myopt, pset.queryFout, pset.logfile); printQuery(res, &myopt, pset.queryFout, pset.logfile);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2007, PostgreSQL Global Development Group * Copyright (c) 2000-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.94 2007/11/22 17:51:39 momjian Exp $ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.95 2007/12/12 21:41:47 tgl Exp $
* *
* Note: we include postgres.h not postgres_fe.h so that we can include * Note: we include postgres.h not postgres_fe.h so that we can include
* catalog/pg_type.h, and thereby have access to INT4OID and similar macros. * catalog/pg_type.h, and thereby have access to INT4OID and similar macros.
...@@ -1926,38 +1926,59 @@ printTable(const char *title, ...@@ -1926,38 +1926,59 @@ printTable(const char *title,
void void
printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog) printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog)
{ {
int ntuples;
int nfields; int nfields;
int ncells; int ncells;
const char **headers; const char **headers;
const char **cells; const char **cells;
char **footers; char **footers;
char *align; char *align;
int i; int i,
r,
c;
if (cancel_pressed) if (cancel_pressed)
return; return;
/* extract headers */ /* extract headers */
ntuples = PQntuples(result);
nfields = PQnfields(result); nfields = PQnfields(result);
headers = pg_local_calloc(nfields + 1, sizeof(*headers)); headers = pg_local_calloc(nfields + 1, sizeof(*headers));
for (i = 0; i < nfields; i++) for (i = 0; i < nfields; i++)
{
headers[i] = (char *) mbvalidate((unsigned char *) PQfname(result, i), headers[i] = (char *) mbvalidate((unsigned char *) PQfname(result, i),
opt->topt.encoding); opt->topt.encoding);
#ifdef ENABLE_NLS
if (opt->trans_headers)
headers[i] = _(headers[i]);
#endif
}
/* set cells */ /* set cells */
ncells = PQntuples(result) * nfields; ncells = ntuples * nfields;
cells = pg_local_calloc(ncells + 1, sizeof(*cells)); cells = pg_local_calloc(ncells + 1, sizeof(*cells));
for (i = 0; i < ncells; i++) i = 0;
for (r = 0; r < ntuples; r++)
{ {
if (PQgetisnull(result, i / nfields, i % nfields)) for (c = 0; c < nfields; c++)
cells[i] = opt->nullPrint ? opt->nullPrint : ""; {
else if (PQgetisnull(result, r, c))
cells[i] = (char *) cells[i] = opt->nullPrint ? opt->nullPrint : "";
mbvalidate((unsigned char *) PQgetvalue(result, i / nfields, i % nfields), else
opt->topt.encoding); {
cells[i] = (char *)
mbvalidate((unsigned char *) PQgetvalue(result, r, c),
opt->topt.encoding);
#ifdef ENABLE_NLS
if (opt->trans_columns && opt->trans_columns[c])
cells[i] = _(cells[i]);
#endif
}
i++;
}
} }
/* set footers */ /* set footers */
...@@ -1970,7 +1991,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f ...@@ -1970,7 +1991,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
footers = pg_local_calloc(2, sizeof(*footers)); footers = pg_local_calloc(2, sizeof(*footers));
footers[0] = pg_local_malloc(100); footers[0] = pg_local_malloc(100);
total_records = opt->topt.prior_records + PQntuples(result); total_records = opt->topt.prior_records + ntuples;
if (total_records == 1) if (total_records == 1)
snprintf(footers[0], 100, _("(1 row)")); snprintf(footers[0], 100, _("(1 row)"));
else else
...@@ -2013,7 +2034,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f ...@@ -2013,7 +2034,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
free(headers); free(headers);
free(cells); free(cells);
if (footers) if (footers && !opt->footers)
{ {
free(footers[0]); free(footers[0]);
free(footers); free(footers);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2007, PostgreSQL Global Development Group * Copyright (c) 2000-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.33 2007/01/05 22:19:49 momjian Exp $ * $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.34 2007/12/12 21:41:47 tgl Exp $
*/ */
#ifndef PRINT_H #ifndef PRINT_H
#define PRINT_H #define PRINT_H
...@@ -67,7 +67,6 @@ void printTable(const char *title, const char *const * headers, ...@@ -67,7 +67,6 @@ void printTable(const char *title, const char *const * headers,
const printTableOpt *opt, FILE *fout, FILE *flog); const printTableOpt *opt, FILE *fout, FILE *flog);
typedef struct _printQueryOpt typedef struct _printQueryOpt
{ {
printTableOpt topt; /* the options above */ printTableOpt topt; /* the options above */
...@@ -76,6 +75,8 @@ typedef struct _printQueryOpt ...@@ -76,6 +75,8 @@ typedef struct _printQueryOpt
char *title; /* override title */ char *title; /* override title */
char **footers; /* override footer (default is "(xx rows)") */ char **footers; /* override footer (default is "(xx rows)") */
bool default_footer; /* print default footer if footers==NULL */ bool default_footer; /* print default footer if footers==NULL */
bool trans_headers; /* do gettext on column headers */
const bool *trans_columns; /* trans_columns[i-1] => do gettext on col i */
} printQueryOpt; } printQueryOpt;
/* /*
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2007, PostgreSQL Global Development Group * Copyright (c) 2000-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.144 2007/12/11 19:01:06 tgl Exp $ * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.145 2007/12/12 21:41:47 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
...@@ -140,6 +140,7 @@ main(int argc, char *argv[]) ...@@ -140,6 +140,7 @@ main(int argc, char *argv[])
pset.cur_cmd_source = stdin; pset.cur_cmd_source = stdin;
pset.cur_cmd_interactive = false; pset.cur_cmd_interactive = false;
/* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
pset.popt.topt.format = PRINT_ALIGNED; pset.popt.topt.format = PRINT_ALIGNED;
pset.popt.topt.border = 1; pset.popt.topt.border = 1;
pset.popt.topt.pager = 1; pset.popt.topt.pager = 1;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/scripts/createlang.c,v 1.27 2007/12/11 19:57:32 tgl Exp $ * $PostgreSQL: pgsql/src/bin/scripts/createlang.c,v 1.28 2007/12/12 21:41:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -125,6 +125,7 @@ main(int argc, char *argv[]) ...@@ -125,6 +125,7 @@ main(int argc, char *argv[])
if (listlangs) if (listlangs)
{ {
printQueryOpt popt; printQueryOpt popt;
static const bool trans_columns[] = {false, true};
conn = connectDatabase(dbname, host, port, username, password, conn = connectDatabase(dbname, host, port, username, password,
progname); progname);
...@@ -132,7 +133,9 @@ main(int argc, char *argv[]) ...@@ -132,7 +133,9 @@ main(int argc, char *argv[])
printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", " printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" " "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
"FROM pg_catalog.pg_language WHERE lanispl;", "FROM pg_catalog.pg_language WHERE lanispl;",
_("Name"), _("yes"), _("no"), _("Trusted?")); gettext_noop("Name"),
gettext_noop("yes"), gettext_noop("no"),
gettext_noop("Trusted?"));
result = executeQuery(conn, sql.data, progname, echo); result = executeQuery(conn, sql.data, progname, echo);
memset(&popt, 0, sizeof(popt)); memset(&popt, 0, sizeof(popt));
...@@ -142,6 +145,8 @@ main(int argc, char *argv[]) ...@@ -142,6 +145,8 @@ main(int argc, char *argv[])
popt.topt.stop_table = true; popt.topt.stop_table = true;
popt.topt.encoding = PQclientEncoding(conn); popt.topt.encoding = PQclientEncoding(conn);
popt.title = _("Procedural Languages"); popt.title = _("Procedural Languages");
popt.trans_headers = true;
popt.trans_columns = trans_columns;
printQuery(result, &popt, stdout, NULL); printQuery(result, &popt, stdout, NULL);
PQfinish(conn); PQfinish(conn);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.24 2007/12/11 19:57:32 tgl Exp $ * $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.25 2007/12/12 21:41:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -136,6 +136,7 @@ main(int argc, char *argv[]) ...@@ -136,6 +136,7 @@ main(int argc, char *argv[])
if (listlangs) if (listlangs)
{ {
printQueryOpt popt; printQueryOpt popt;
static const bool trans_columns[] = {false, true};
conn = connectDatabase(dbname, host, port, username, password, conn = connectDatabase(dbname, host, port, username, password,
progname); progname);
...@@ -143,7 +144,9 @@ main(int argc, char *argv[]) ...@@ -143,7 +144,9 @@ main(int argc, char *argv[])
printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", " printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" " "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
"FROM pg_catalog.pg_language WHERE lanispl;", "FROM pg_catalog.pg_language WHERE lanispl;",
_("Name"), _("yes"), _("no"), _("Trusted?")); gettext_noop("Name"),
gettext_noop("yes"), gettext_noop("no"),
gettext_noop("Trusted?"));
result = executeQuery(conn, sql.data, progname, echo); result = executeQuery(conn, sql.data, progname, echo);
memset(&popt, 0, sizeof(popt)); memset(&popt, 0, sizeof(popt));
...@@ -153,6 +156,8 @@ main(int argc, char *argv[]) ...@@ -153,6 +156,8 @@ main(int argc, char *argv[])
popt.topt.stop_table = true; popt.topt.stop_table = true;
popt.topt.encoding = PQclientEncoding(conn); popt.topt.encoding = PQclientEncoding(conn);
popt.title = _("Procedural Languages"); popt.title = _("Procedural Languages");
popt.trans_headers = true;
popt.trans_columns = trans_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