Proposed patch to avoid translation risks in psql's \d commands - Mailing list pgsql-patches

From Tom Lane
Subject Proposed patch to avoid translation risks in psql's \d commands
Date
Msg-id 10693.1197427944@sss.pgh.pa.us
Whole thread Raw
Responses Re: Proposed patch to avoid translation risks in psql's \d commands
List pgsql-patches
I proposed here:
http://archives.postgresql.org/pgsql-hackers/2007-12/msg00436.php
that we change the way that psql deals with localization of column
names and other fixed strings in the output of \d and related commands
(basically, anything that calls printQuery()).  Specifically, we should
avoid shipping already-translated strings to the server, because they
might not be in the expected encoding and also might contain quote
marks, which the existing code doesn't guard against.  We can instead
apply the gettext() conversion when the query results come back from
the server.

The attached patch does this, and seems to resolve Guillaume Lelarge's
original complaint.

I found just one place where the proposed new method doesn't work quite
as nicely as the old.  In \dC (describe casts), the Function column
contains either a function name or '(binary compatible)' to indicate
a cast WITHOUT FUNCTION.  The existing code is able to localize '(binary
compatible)', but this patch does not, because applying gettext to every
value in the column seems to pose an unacceptably high risk of
"translating" some function name that happens to match a string in
psql's .PO database.

I'm inclined to just live with that, since it seems a relatively minor
deficiency, but I wonder if anyone has a better idea how to do it?

            regards, tom lane

Index: src/bin/psql/describe.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.162
diff -c -r1.162 describe.c
*** src/bin/psql/describe.c    15 Nov 2007 21:14:42 -0000    1.162
--- src/bin/psql/describe.c    12 Dec 2007 02:36:43 -0000
***************
*** 85,92 ****
                        "FROM pg_catalog.pg_proc p\n"
         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
                        "WHERE p.proisagg\n",
!                       _("Schema"), _("Name"), _("Result data type"),
!                       _("Argument data types"), _("Description"));

      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "p.proname", NULL,
--- 85,95 ----
                        "FROM pg_catalog.pg_proc p\n"
         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
                        "WHERE p.proisagg\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("Result data type"),
!                       gettext_noop("Argument data types"),
!                       gettext_noop("Description"));

      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "p.proname", NULL,
***************
*** 101,106 ****
--- 104,110 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of aggregate functions");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 131,143 ****
                        "SELECT spcname AS \"%s\",\n"
                        "  pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
                        "  spclocation AS \"%s\"",
!                       _("Name"), _("Owner"), _("Location"));

      if (verbose)
          appendPQExpBuffer(&buf,
!                           ",\n  spcacl as \"%s\""
           ",\n  pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
!                           _("Access privileges"), _("Description"));

      appendPQExpBuffer(&buf,
                        "\nFROM pg_catalog.pg_tablespace\n");
--- 135,150 ----
                        "SELECT spcname AS \"%s\",\n"
                        "  pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
                        "  spclocation AS \"%s\"",
!                       gettext_noop("Name"),
!                       gettext_noop("Owner"),
!                       gettext_noop("Location"));

      if (verbose)
          appendPQExpBuffer(&buf,
!                           ",\n  spcacl AS \"%s\""
           ",\n  pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
!                           gettext_noop("Access privileges"),
!                           gettext_noop("Description"));

      appendPQExpBuffer(&buf,
                        "\nFROM pg_catalog.pg_tablespace\n");
***************
*** 155,160 ****
--- 162,168 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of tablespaces");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 208,215 ****
                        "        pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
                        "    ), ', ')\n"
                        "  END AS \"%s\"",
!                       _("Schema"), _("Name"), _("Result data type"),
!                       _("Argument data types"));

      if (verbose)
          appendPQExpBuffer(&buf,
--- 216,225 ----
                        "        pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
                        "    ), ', ')\n"
                        "  END AS \"%s\"",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("Result data type"),
!                       gettext_noop("Argument data types"));

      if (verbose)
          appendPQExpBuffer(&buf,
***************
*** 222,229 ****
                            "  l.lanname as \"%s\",\n"
                            "  p.prosrc as \"%s\",\n"
                    "  pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
!                           _("Volatility"), _("Owner"), _("Language"),
!                           _("Source code"), _("Description"));

      if (!verbose)
          appendPQExpBuffer(&buf,
--- 232,242 ----
                            "  l.lanname as \"%s\",\n"
                            "  p.prosrc as \"%s\",\n"
                    "  pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
!                           gettext_noop("Volatility"),
!                           gettext_noop("Owner"),
!                           gettext_noop("Language"),
!                           gettext_noop("Source code"),
!                           gettext_noop("Description"));

      if (!verbose)
          appendPQExpBuffer(&buf,
***************
*** 258,263 ****
--- 271,277 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of functions");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 283,289 ****
      printfPQExpBuffer(&buf,
                        "SELECT n.nspname as \"%s\",\n"
                        "  pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
!                       _("Schema"), _("Name"));
      if (verbose)
          appendPQExpBuffer(&buf,
                            "  t.typname AS \"%s\",\n"
--- 297,304 ----
      printfPQExpBuffer(&buf,
                        "SELECT n.nspname as \"%s\",\n"
                        "  pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"));
      if (verbose)
          appendPQExpBuffer(&buf,
                            "  t.typname AS \"%s\",\n"
***************
*** 293,302 ****
                            "      THEN CAST('var' AS pg_catalog.text)\n"
                            "    ELSE CAST(t.typlen AS pg_catalog.text)\n"
                            "  END AS \"%s\",\n",
!                           _("Internal name"), _("Size"));
      appendPQExpBuffer(&buf,
                  "  pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
!                       _("Description"));

      appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n"
       "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
--- 308,318 ----
                            "      THEN CAST('var' AS pg_catalog.text)\n"
                            "    ELSE CAST(t.typlen AS pg_catalog.text)\n"
                            "  END AS \"%s\",\n",
!                           gettext_noop("Internal name"),
!                           gettext_noop("Size"));
      appendPQExpBuffer(&buf,
                  "  pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
!                       gettext_noop("Description"));

      appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n"
       "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
***************
*** 325,330 ****
--- 341,347 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of data types");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 354,362 ****
      "           pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
                        "FROM pg_catalog.pg_operator o\n"
        "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
!                       _("Schema"), _("Name"),
!                       _("Left arg type"), _("Right arg type"),
!                       _("Result type"), _("Description"));

      processSQLNamePattern(pset.db, &buf, pattern, false, true,
                            "n.nspname", "o.oprname", NULL,
--- 371,382 ----
      "           pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
                        "FROM pg_catalog.pg_operator o\n"
        "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("Left arg type"),
!                       gettext_noop("Right arg type"),
!                       gettext_noop("Result type"),
!                       gettext_noop("Description"));

      processSQLNamePattern(pset.db, &buf, pattern, false, true,
                            "n.nspname", "o.oprname", NULL,
***************
*** 371,376 ****
--- 391,397 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of operators");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 395,413 ****

      printfPQExpBuffer(&buf,
                        "SELECT d.datname as \"%s\",\n"
!                       "       r.rolname as \"%s\"",
!                       _("Name"), _("Owner"));
!     appendPQExpBuffer(&buf,
!             ",\n       pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\"",
!                       _("Encoding"));
      if (verbose)
      {
          appendPQExpBuffer(&buf,
                            ",\n       t.spcname as \"%s\"",
!                           _("Tablespace"));
          appendPQExpBuffer(&buf,
                            ",\n       pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
!                           _("Description"));
      }
      appendPQExpBuffer(&buf,
                        "\nFROM pg_catalog.pg_database d"
--- 416,434 ----

      printfPQExpBuffer(&buf,
                        "SELECT d.datname as \"%s\",\n"
!                       "       r.rolname as \"%s\",\n"
!                       "       pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\"",
!                       gettext_noop("Name"),
!                       gettext_noop("Owner"),
!                       gettext_noop("Encoding"));
      if (verbose)
      {
          appendPQExpBuffer(&buf,
                            ",\n       t.spcname as \"%s\"",
!                           gettext_noop("Tablespace"));
          appendPQExpBuffer(&buf,
                            ",\n       pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
!                           gettext_noop("Description"));
      }
      appendPQExpBuffer(&buf,
                        "\nFROM pg_catalog.pg_database d"
***************
*** 423,428 ****
--- 444,450 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of databases");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 441,446 ****
--- 463,469 ----
      PQExpBufferData buf;
      PGresult   *res;
      printQueryOpt myopt = pset.popt;
+     static const bool trans_columns[] = {false, false, true, false};

      initPQExpBuffer(&buf);

***************
*** 455,461 ****
                        "FROM pg_catalog.pg_class c\n"
         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
                        "WHERE c.relkind IN ('r', 'v', 'S')\n",
!                       _("Schema"), _("Name"), _("table"), _("view"), _("sequence"), _("Type"), _("Access
privileges"));

      /*
       * Unless a schema pattern is specified, we suppress system and temp
--- 478,488 ----
                        "FROM pg_catalog.pg_class c\n"
         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
                        "WHERE c.relkind IN ('r', 'v', 'S')\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
!                       gettext_noop("Type"),
!                       gettext_noop("Access privileges"));

      /*
       * Unless a schema pattern is specified, we suppress system and temp
***************
*** 477,484 ****
      }

      myopt.nullPrint = NULL;
!     printfPQExpBuffer(&buf, _("Access privileges for database \"%s\""), PQdb(pset.db));
      myopt.title = buf.data;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

--- 504,514 ----
      }

      myopt.nullPrint = NULL;
!     printfPQExpBuffer(&buf, _("Access privileges for database \"%s\""),
!                       PQdb(pset.db));
      myopt.title = buf.data;
+     myopt.trans_headers = true;
+     myopt.trans_columns = trans_columns;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 503,515 ****
      PQExpBufferData buf;
      PGresult   *res;
      printQueryOpt myopt = pset.popt;

      initPQExpBuffer(&buf);

      appendPQExpBuffer(&buf,
                        "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS
\"%s\"\n"
                        "FROM (\n",
!                       _("Schema"), _("Name"), _("Object"), _("Description"));

      /* Aggregate descriptions */
      appendPQExpBuffer(&buf,
--- 533,549 ----
      PQExpBufferData buf;
      PGresult   *res;
      printQueryOpt myopt = pset.popt;
+     static const bool trans_columns[] = {false, false, true, false};

      initPQExpBuffer(&buf);

      appendPQExpBuffer(&buf,
                        "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS
\"%s\"\n"
                        "FROM (\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("Object"),
!                       gettext_noop("Description"));

      /* Aggregate descriptions */
      appendPQExpBuffer(&buf,
***************
*** 520,526 ****
                        "  FROM pg_catalog.pg_proc p\n"
       "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
                        "  WHERE p.proisagg\n",
!                       _("aggregate"));
      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "p.proname", NULL,
                            "pg_catalog.pg_function_is_visible(p.oid)");
--- 554,560 ----
                        "  FROM pg_catalog.pg_proc p\n"
       "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
                        "  WHERE p.proisagg\n",
!                       gettext_noop("aggregate"));
      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "p.proname", NULL,
                            "pg_catalog.pg_function_is_visible(p.oid)");
***************
*** 539,545 ****
                        "      AND (p.proargtypes[0] IS NULL\n"
                        "      OR   p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n"
                        "      AND NOT p.proisagg\n",
!                       _("function"));
      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "p.proname", NULL,
                            "pg_catalog.pg_function_is_visible(p.oid)");
--- 573,579 ----
                        "      AND (p.proargtypes[0] IS NULL\n"
                        "      OR   p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n"
                        "      AND NOT p.proisagg\n",
!                       gettext_noop("function"));
      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "p.proname", NULL,
                            "pg_catalog.pg_function_is_visible(p.oid)");
***************
*** 553,559 ****
                        "  CAST('%s' AS pg_catalog.text) as object\n"
                        "  FROM pg_catalog.pg_operator o\n"
      "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
!                       _("operator"));
      processSQLNamePattern(pset.db, &buf, pattern, false, false,
                            "n.nspname", "o.oprname", NULL,
                            "pg_catalog.pg_operator_is_visible(o.oid)");
--- 587,593 ----
                        "  CAST('%s' AS pg_catalog.text) as object\n"
                        "  FROM pg_catalog.pg_operator o\n"
      "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
!                       gettext_noop("operator"));
      processSQLNamePattern(pset.db, &buf, pattern, false, false,
                            "n.nspname", "o.oprname", NULL,
                            "pg_catalog.pg_operator_is_visible(o.oid)");
***************
*** 567,573 ****
                        "  CAST('%s' AS pg_catalog.text) as object\n"
                        "  FROM pg_catalog.pg_type t\n"
      "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
!                       _("data type"));
      processSQLNamePattern(pset.db, &buf, pattern, false, false,
                            "n.nspname", "pg_catalog.format_type(t.oid, NULL)",
                            NULL,
--- 601,607 ----
                        "  CAST('%s' AS pg_catalog.text) as object\n"
                        "  FROM pg_catalog.pg_type t\n"
      "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
!                       gettext_noop("data type"));
      processSQLNamePattern(pset.db, &buf, pattern, false, false,
                            "n.nspname", "pg_catalog.format_type(t.oid, NULL)",
                            NULL,
***************
*** 585,591 ****
                        "  FROM pg_catalog.pg_class c\n"
       "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
                        "  WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
!                       _("table"), _("view"), _("index"), _("sequence"));
      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "c.relname", NULL,
                            "pg_catalog.pg_table_is_visible(c.oid)");
--- 619,628 ----
                        "  FROM pg_catalog.pg_class c\n"
       "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
                        "  WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
!                       gettext_noop("table"),
!                       gettext_noop("view"),
!                       gettext_noop("index"),
!                       gettext_noop("sequence"));
      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "c.relname", NULL,
                            "pg_catalog.pg_table_is_visible(c.oid)");
***************
*** 601,607 ****
                    "       JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
       "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
                        "  WHERE r.rulename != '_RETURN'\n",
!                       _("rule"));
      /* XXX not sure what to do about visibility rule here? */
      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "r.rulename", NULL,
--- 638,644 ----
                    "       JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
       "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
                        "  WHERE r.rulename != '_RETURN'\n",
!                       gettext_noop("rule"));
      /* XXX not sure what to do about visibility rule here? */
      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "r.rulename", NULL,
***************
*** 617,623 ****
                        "  FROM pg_catalog.pg_trigger t\n"
                     "       JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
      "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
!                       _("trigger"));
      /* XXX not sure what to do about visibility rule here? */
      processSQLNamePattern(pset.db, &buf, pattern, false, false,
                            "n.nspname", "t.tgname", NULL,
--- 654,660 ----
                        "  FROM pg_catalog.pg_trigger t\n"
                     "       JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
      "       LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
!                       gettext_noop("trigger"));
      /* XXX not sure what to do about visibility rule here? */
      processSQLNamePattern(pset.db, &buf, pattern, false, false,
                            "n.nspname", "t.tgname", NULL,
***************
*** 636,641 ****
--- 673,680 ----

      myopt.nullPrint = NULL;
      myopt.title = _("Object descriptions");
+     myopt.trans_headers = true;
+     myopt.trans_columns = trans_columns;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 1572,1577 ****
--- 1611,1617 ----
      PQExpBufferData buf;
      PGresult   *res;
      printQueryOpt myopt = pset.popt;
+     static const bool trans_columns[] = {false, true, true, true, true, false, false};

      initPQExpBuffer(&buf);

***************
*** 1584,1599 ****
                        "       ELSE CAST(r.rolconnlimit AS pg_catalog.text)\n"
                        "  END AS \"%s\", \n"
                        "  ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON
(m.roleid= b.oid) WHERE m.member = r.oid) as \"%s\"", 
!                       _("Role name"),
!                       _("yes"), _("no"), _("Superuser"),
!                       _("yes"), _("no"), _("Create role"),
!                       _("yes"), _("no"), _("Create DB"),
!                       _("no limit"), _("Connections"),
!                       _("Member of"));

      if (verbose)
          appendPQExpBuffer(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS \"%s\"",
!                           _("Description"));

      appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_roles r\n");

--- 1624,1643 ----
                        "       ELSE CAST(r.rolconnlimit AS pg_catalog.text)\n"
                        "  END AS \"%s\", \n"
                        "  ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON
(m.roleid= b.oid) WHERE m.member = r.oid) as \"%s\"", 
!                       gettext_noop("Role name"),
!                       gettext_noop("yes"), gettext_noop("no"),
!                       gettext_noop("Superuser"),
!                       gettext_noop("yes"), gettext_noop("no"),
!                       gettext_noop("Create role"),
!                       gettext_noop("yes"), gettext_noop("no"),
!                       gettext_noop("Create DB"),
!                       gettext_noop("no limit"),
!                       gettext_noop("Connections"),
!                       gettext_noop("Member of"));

      if (verbose)
          appendPQExpBuffer(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS \"%s\"",
!                           gettext_noop("Description"));

      appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_roles r\n");

***************
*** 1609,1614 ****
--- 1653,1660 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of roles");
+     myopt.trans_headers = true;
+     myopt.trans_columns = trans_columns;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 1642,1647 ****
--- 1688,1694 ----
      PQExpBufferData buf;
      PGresult   *res;
      printQueryOpt myopt = pset.popt;
+     static const bool trans_columns[] = {false, false, true, false, false, false};

      if (!(showTables || showIndexes || showViews || showSeq))
          showTables = showViews = showSeq = true;
***************
*** 1657,1675 ****
                        "  c.relname as \"%s\",\n"
                        "  CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s'
WHEN's' THEN '%s' END as \"%s\",\n" 
                        "  r.rolname as \"%s\"",
!                       _("Schema"), _("Name"),
!                       _("table"), _("view"), _("index"), _("sequence"),
!                       _("special"), _("Type"), _("Owner"));

      if (showIndexes)
          appendPQExpBuffer(&buf,
                            ",\n c2.relname as \"%s\"",
!                           _("Table"));

      if (verbose)
          appendPQExpBuffer(&buf,
                ",\n  pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
!                           _("Description"));

      appendPQExpBuffer(&buf,
                        "\nFROM pg_catalog.pg_class c"
--- 1704,1724 ----
                        "  c.relname as \"%s\",\n"
                        "  CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s'
WHEN's' THEN '%s' END as \"%s\",\n" 
                        "  r.rolname as \"%s\"",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("table"), gettext_noop("view"), gettext_noop("index"), gettext_noop("sequence"),
gettext_noop("special"),
!                       gettext_noop("Type"),
!                       gettext_noop("Owner"));

      if (showIndexes)
          appendPQExpBuffer(&buf,
                            ",\n c2.relname as \"%s\"",
!                           gettext_noop("Table"));

      if (verbose)
          appendPQExpBuffer(&buf,
                ",\n  pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
!                           gettext_noop("Description"));

      appendPQExpBuffer(&buf,
                        "\nFROM pg_catalog.pg_class c"
***************
*** 1729,1734 ****
--- 1778,1785 ----
      {
          myopt.nullPrint = NULL;
          myopt.title = _("List of relations");
+         myopt.trans_headers = true;
+         myopt.trans_columns = trans_columns;

          printQuery(res, &myopt, pset.queryFout, pset.logfile);
      }
***************
*** 1766,1776 ****
         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
            "     LEFT JOIN pg_catalog.pg_constraint r ON t.oid = r.contypid\n"
                        "WHERE t.typtype = 'd'\n",
!                       _("Schema"),
!                       _("Name"),
!                       _("Type"),
!                       _("Modifier"),
!                       _("Check"));

      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "t.typname", NULL,
--- 1817,1827 ----
         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
            "     LEFT JOIN pg_catalog.pg_constraint r ON t.oid = r.contypid\n"
                        "WHERE t.typtype = 'd'\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("Type"),
!                       gettext_noop("Modifier"),
!                       gettext_noop("Check"));

      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "t.typname", NULL,
***************
*** 1785,1790 ****
--- 1836,1842 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of domains");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 1803,1808 ****
--- 1855,1861 ----
      PQExpBufferData buf;
      PGresult   *res;
      printQueryOpt myopt = pset.popt;
+     static const bool trans_columns[] = {false, false, false, false, true};

      initPQExpBuffer(&buf);

***************
*** 1815,1827 ****
                        "       ELSE '%s' END AS \"%s\"\n"
                 "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
                        "WHERE n.oid = c.connamespace\n",
!                       _("Schema"),
!                       _("Name"),
!                       _("Source"),
!                       _("Destination"),
!                       _("yes"),
!                       _("no"),
!                       _("Default?"));

      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "c.conname", NULL,
--- 1868,1879 ----
                        "       ELSE '%s' END AS \"%s\"\n"
                 "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
                        "WHERE n.oid = c.connamespace\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("Source"),
!                       gettext_noop("Destination"),
!                       gettext_noop("yes"), gettext_noop("no"),
!                       gettext_noop("Default?"));

      processSQLNamePattern(pset.db, &buf, pattern, true, false,
                            "n.nspname", "c.conname", NULL,
***************
*** 1836,1841 ****
--- 1888,1895 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of conversions");
+     myopt.trans_headers = true;
+     myopt.trans_columns = trans_columns;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 1854,1866 ****
      PQExpBufferData buf;
      PGresult   *res;
      printQueryOpt myopt = pset.popt;

      initPQExpBuffer(&buf);
! /* NEED LEFT JOIN FOR BINARY CASTS */
      printfPQExpBuffer(&buf,
                 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
                 "       pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
!                       "       CASE WHEN castfunc = 0 THEN '%s'\n"
                        "            ELSE p.proname\n"
                        "       END as \"%s\",\n"
                        "       CASE WHEN c.castcontext = 'e' THEN '%s'\n"
--- 1908,1926 ----
      PQExpBufferData buf;
      PGresult   *res;
      printQueryOpt myopt = pset.popt;
+     static const bool trans_columns[] = {false, false, false, true};

      initPQExpBuffer(&buf);
!     /*
!      * We need left join here for binary casts.  Also note that we don't
!      * attempt to localize '(binary compatible)', because there's too much
!      * risk of gettext translating a function name that happens to match
!      * some string in the PO database.
!      */
      printfPQExpBuffer(&buf,
                 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
                 "       pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
!                       "       CASE WHEN castfunc = 0 THEN '(binary compatible)'\n"
                        "            ELSE p.proname\n"
                        "       END as \"%s\",\n"
                        "       CASE WHEN c.castcontext = 'e' THEN '%s'\n"
***************
*** 1870,1883 ****
                   "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
                        "     ON c.castfunc = p.oid\n"
                        "ORDER BY 1, 2",
!                       _("Source type"),
!                       _("Target type"),
!                       _("(binary compatible)"),
!                       _("Function"),
!                       _("no"),
!                       _("in assignment"),
!                       _("yes"),
!                       _("Implicit?"));

      res = PSQLexec(buf.data, false);
      termPQExpBuffer(&buf);
--- 1930,1940 ----
                   "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
                        "     ON c.castfunc = p.oid\n"
                        "ORDER BY 1, 2",
!                       gettext_noop("Source type"),
!                       gettext_noop("Target type"),
!                       gettext_noop("Function"),
!                       gettext_noop("no"), gettext_noop("in assignment"), gettext_noop("yes"),
!                       gettext_noop("Implicit?"));

      res = PSQLexec(buf.data, false);
      termPQExpBuffer(&buf);
***************
*** 1886,1891 ****
--- 1943,1950 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of casts");
+     myopt.trans_headers = true;
+     myopt.trans_columns = trans_columns;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 1909,1921 ****
      printfPQExpBuffer(&buf,
                        "SELECT n.nspname AS \"%s\",\n"
                        "       r.rolname AS \"%s\"",
!                       _("Name"), _("Owner"));

      if (verbose)
          appendPQExpBuffer(&buf,
                            ",\n  n.nspacl as \"%s\","
               "  pg_catalog.obj_description(n.oid, 'pg_namespace') as \"%s\"",
!                           _("Access privileges"), _("Description"));

      appendPQExpBuffer(&buf,
                "\nFROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_roles r\n"
--- 1968,1982 ----
      printfPQExpBuffer(&buf,
                        "SELECT n.nspname AS \"%s\",\n"
                        "       r.rolname AS \"%s\"",
!                       gettext_noop("Name"),
!                       gettext_noop("Owner"));

      if (verbose)
          appendPQExpBuffer(&buf,
                            ",\n  n.nspacl as \"%s\","
               "  pg_catalog.obj_description(n.oid, 'pg_namespace') as \"%s\"",
!                           gettext_noop("Access privileges"),
!                           gettext_noop("Description"));

      appendPQExpBuffer(&buf,
                "\nFROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_roles r\n"
***************
*** 1936,1941 ****
--- 1997,2003 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of schemas");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 1967,1975 ****
              "  pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
                        "FROM pg_catalog.pg_ts_parser p \n"
             "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
!                       _("Schema"),
!                       _("Name"),
!                       _("Description")
          );

      processSQLNamePattern(pset.db, &buf, pattern, false, false,
--- 2029,2037 ----
              "  pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
                        "FROM pg_catalog.pg_ts_parser p \n"
             "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("Description")
          );

      processSQLNamePattern(pset.db, &buf, pattern, false, false,
***************
*** 1985,1990 ****
--- 2047,2053 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of text search parsers");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 2067,2072 ****
--- 2130,2136 ----
      PGresult   *res;
      char        title[1024];
      printQueryOpt myopt = pset.popt;
+     static const bool trans_columns[] = {true, false, false};

      initPQExpBuffer(&buf);

***************
*** 2100,2113 ****
                    "   pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
                        " FROM pg_catalog.pg_ts_parser p \n"
                        " WHERE p.oid = '%s' \n",
!                       _("Start parse"),
!                       _("Method"), _("Function"), _("Description"),
                        oid,
!                       _("Get next token"), oid,
!                       _("End parse"), oid,
!                       _("Get headline"), oid,
!                       _("Get token types"), oid
!         );

      res = PSQLexec(buf.data, false);
      termPQExpBuffer(&buf);
--- 2164,2182 ----
                    "   pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
                        " FROM pg_catalog.pg_ts_parser p \n"
                        " WHERE p.oid = '%s' \n",
!                       gettext_noop("Start parse"),
!                       gettext_noop("Method"),
!                       gettext_noop("Function"),
!                       gettext_noop("Description"),
                        oid,
!                       gettext_noop("Get next token"),
!                       oid,
!                       gettext_noop("End parse"),
!                       oid,
!                       gettext_noop("Get headline"),
!                       oid,
!                       gettext_noop("Get token types"),
!                       oid);

      res = PSQLexec(buf.data, false);
      termPQExpBuffer(&buf);
***************
*** 2122,2127 ****
--- 2191,2198 ----
      myopt.title = title;
      myopt.footers = NULL;
      myopt.default_footer = false;
+     myopt.trans_headers = true;
+     myopt.trans_columns = trans_columns;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 2134,2141 ****
                        "  t.description as \"%s\" \n"
                "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
                        "ORDER BY 1;",
!                       _("Token name"),
!                       _("Description"),
                        oid);

      res = PSQLexec(buf.data, false);
--- 2205,2212 ----
                        "  t.description as \"%s\" \n"
                "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
                        "ORDER BY 1;",
!                       gettext_noop("Token name"),
!                       gettext_noop("Description"),
                        oid);

      res = PSQLexec(buf.data, false);
***************
*** 2151,2156 ****
--- 2222,2229 ----
      myopt.title = title;
      myopt.footers = NULL;
      myopt.default_footer = true;
+     myopt.trans_headers = true;
+     myopt.trans_columns = NULL;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 2176,2183 ****
                        "SELECT \n"
                        "  n.nspname as \"%s\",\n"
                        "  d.dictname as \"%s\",\n",
!                       _("Schema"),
!                       _("Name"));

      if (verbose)
      {
--- 2249,2256 ----
                        "SELECT \n"
                        "  n.nspname as \"%s\",\n"
                        "  d.dictname as \"%s\",\n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"));

      if (verbose)
      {
***************
*** 2187,2199 ****
                            "             LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
                            "             WHERE d.dicttemplate = t.oid ) AS  \"%s\", \n"
                            "  d.dictinitoption as \"%s\", \n",
!                           _("Template"),
!                           _("Init options"));
      }

      appendPQExpBuffer(&buf,
               "  pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
!                       _("Description"));

      appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_dict d\n"
           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
--- 2260,2272 ----
                            "             LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
                            "             WHERE d.dicttemplate = t.oid ) AS  \"%s\", \n"
                            "  d.dictinitoption as \"%s\", \n",
!                           gettext_noop("Template"),
!                           gettext_noop("Init options"));
      }

      appendPQExpBuffer(&buf,
               "  pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
!                       gettext_noop("Description"));

      appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_dict d\n"
           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
***************
*** 2211,2216 ****
--- 2284,2290 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of text search dictionaries");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 2240,2259 ****
                            "  t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
                            "  t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
           "  pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
!                           _("Schema"),
!                           _("Name"),
!                           _("Init"),
!                           _("Lexize"),
!                           _("Description"));
      else
          printfPQExpBuffer(&buf,
                            "SELECT \n"
                            "  n.nspname AS \"%s\",\n"
                            "  t.tmplname AS \"%s\",\n"
           "  pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
!                           _("Schema"),
!                           _("Name"),
!                           _("Description"));

      appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_template t\n"
           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
--- 2314,2333 ----
                            "  t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
                            "  t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
           "  pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
!                           gettext_noop("Schema"),
!                           gettext_noop("Name"),
!                           gettext_noop("Init"),
!                           gettext_noop("Lexize"),
!                           gettext_noop("Description"));
      else
          printfPQExpBuffer(&buf,
                            "SELECT \n"
                            "  n.nspname AS \"%s\",\n"
                            "  t.tmplname AS \"%s\",\n"
           "  pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
!                           gettext_noop("Schema"),
!                           gettext_noop("Name"),
!                           gettext_noop("Description"));

      appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_template t\n"
           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
***************
*** 2271,2276 ****
--- 2345,2351 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of text search templates");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 2302,2310 ****
             "   pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
                        "FROM pg_catalog.pg_ts_config c\n"
            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
!                       _("Schema"),
!                       _("Name"),
!                       _("Description")
          );

      processSQLNamePattern(pset.db, &buf, pattern, false, false,
--- 2377,2385 ----
             "   pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
                        "FROM pg_catalog.pg_ts_config c\n"
            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
!                       gettext_noop("Schema"),
!                       gettext_noop("Name"),
!                       gettext_noop("Description")
          );

      processSQLNamePattern(pset.db, &buf, pattern, false, false,
***************
*** 2320,2325 ****
--- 2395,2401 ----

      myopt.nullPrint = NULL;
      myopt.title = _("List of text search configurations");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

***************
*** 2428,2435 ****
                        "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
                        "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
                        "ORDER BY 1",
!                       _("Token"),
!                       _("Dictionaries"),
                        oid);

      res = PSQLexec(buf.data, false);
--- 2504,2511 ----
                        "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
                        "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
                        "ORDER BY 1",
!                       gettext_noop("Token"),
!                       gettext_noop("Dictionaries"),
                        oid);

      res = PSQLexec(buf.data, false);
***************
*** 2440,2458 ****
      initPQExpBuffer(&title);

      if (nspname)
!         appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""), nspname, cfgname);
      else
!         appendPQExpBuffer(&title, _("Text search configuration \"%s\""), cfgname);

      if (pnspname)
!         appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""), pnspname, prsname);
      else
!         appendPQExpBuffer(&title, _("\nParser: \"%s\""), prsname);

      myopt.nullPrint = NULL;
      myopt.title = title.data;
      myopt.footers = NULL;
      myopt.default_footer = false;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

--- 2516,2539 ----
      initPQExpBuffer(&title);

      if (nspname)
!         appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
!                           nspname, cfgname);
      else
!         appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
!                           cfgname);

      if (pnspname)
!         appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
!                           pnspname, prsname);
      else
!         appendPQExpBuffer(&title, _("\nParser: \"%s\""),
!                           prsname);

      myopt.nullPrint = NULL;
      myopt.title = title.data;
      myopt.footers = NULL;
      myopt.default_footer = false;
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

Index: src/bin/psql/large_obj.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/large_obj.c,v
retrieving revision 1.48
diff -c -r1.48 large_obj.c
*** src/bin/psql/large_obj.c    20 Jan 2007 16:57:31 -0000    1.48
--- src/bin/psql/large_obj.c    12 Dec 2007 02:36:43 -0000
***************
*** 279,289 ****
      printQueryOpt myopt = pset.popt;

      snprintf(buf, sizeof(buf),
!              "SELECT loid as \"ID\",\n"
             "  pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
               "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
               "ORDER BY 1",
!              _("Description"));

      res = PSQLexec(buf, false);
      if (!res)
--- 279,290 ----
      printQueryOpt myopt = pset.popt;

      snprintf(buf, sizeof(buf),
!              "SELECT loid as \"%s\",\n"
             "  pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
               "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
               "ORDER BY 1",
!              gettext_noop("ID"),
!              gettext_noop("Description"));

      res = PSQLexec(buf, false);
      if (!res)
***************
*** 292,297 ****
--- 293,299 ----
      myopt.topt.tuples_only = false;
      myopt.nullPrint = NULL;
      myopt.title = _("Large objects");
+     myopt.trans_headers = true;

      printQuery(res, &myopt, pset.queryFout, pset.logfile);

Index: src/bin/psql/print.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.94
diff -c -r1.94 print.c
*** src/bin/psql/print.c    22 Nov 2007 17:51:39 -0000    1.94
--- src/bin/psql/print.c    12 Dec 2007 02:36:43 -0000
***************
*** 1926,1963 ****
  void
  printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog)
  {
      int            nfields;
      int            ncells;
      const char **headers;
      const char **cells;
      char      **footers;
      char       *align;
!     int            i;

      if (cancel_pressed)
          return;

      /* extract headers */
      nfields = PQnfields(result);

      headers = pg_local_calloc(nfields + 1, sizeof(*headers));

      for (i = 0; i < nfields; i++)
          headers[i] = (char *) mbvalidate((unsigned char *) PQfname(result, i),
                                           opt->topt.encoding);

      /* set cells */
!     ncells = PQntuples(result) * nfields;
      cells = pg_local_calloc(ncells + 1, sizeof(*cells));

!     for (i = 0; i < ncells; i++)
      {
!         if (PQgetisnull(result, i / nfields, i % nfields))
!             cells[i] = opt->nullPrint ? opt->nullPrint : "";
!         else
!             cells[i] = (char *)
!                 mbvalidate((unsigned char *) PQgetvalue(result, i / nfields, i % nfields),
!                            opt->topt.encoding);
      }

      /* set footers */
--- 1926,1984 ----
  void
  printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog)
  {
+     int            ntuples;
      int            nfields;
      int            ncells;
      const char **headers;
      const char **cells;
      char      **footers;
      char       *align;
!     int            i,
!                 r,
!                 c;

      if (cancel_pressed)
          return;

      /* extract headers */
+     ntuples = PQntuples(result);
      nfields = PQnfields(result);

      headers = pg_local_calloc(nfields + 1, sizeof(*headers));

      for (i = 0; i < nfields; i++)
+     {
          headers[i] = (char *) mbvalidate((unsigned char *) PQfname(result, i),
                                           opt->topt.encoding);
+ #ifdef ENABLE_NLS
+         if (opt->trans_headers)
+             headers[i] = _(headers[i]);
+ #endif
+     }

      /* set cells */
!     ncells = ntuples * nfields;
      cells = pg_local_calloc(ncells + 1, sizeof(*cells));

!     i = 0;
!     for (r = 0; r < ntuples; r++)
      {
!         for (c = 0; c < nfields; c++)
!         {
!             if (PQgetisnull(result, r, c))
!                 cells[i] = opt->nullPrint ? opt->nullPrint : "";
!             else
!             {
!                 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 */
***************
*** 1970,1976 ****

          footers = pg_local_calloc(2, sizeof(*footers));
          footers[0] = pg_local_malloc(100);
!         total_records = opt->topt.prior_records + PQntuples(result);
          if (total_records == 1)
              snprintf(footers[0], 100, _("(1 row)"));
          else
--- 1991,1997 ----

          footers = pg_local_calloc(2, sizeof(*footers));
          footers[0] = pg_local_malloc(100);
!         total_records = opt->topt.prior_records + ntuples;
          if (total_records == 1)
              snprintf(footers[0], 100, _("(1 row)"));
          else
***************
*** 2013,2019 ****

      free(headers);
      free(cells);
!     if (footers)
      {
          free(footers[0]);
          free(footers);
--- 2034,2040 ----

      free(headers);
      free(cells);
!     if (footers && !opt->footers)
      {
          free(footers[0]);
          free(footers);
Index: src/bin/psql/print.h
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.h,v
retrieving revision 1.33
diff -c -r1.33 print.h
*** src/bin/psql/print.h    5 Jan 2007 22:19:49 -0000    1.33
--- src/bin/psql/print.h    12 Dec 2007 02:36:43 -0000
***************
*** 67,73 ****
             const printTableOpt *opt, FILE *fout, FILE *flog);


-
  typedef struct _printQueryOpt
  {
      printTableOpt topt;            /* the options above */
--- 67,72 ----
***************
*** 76,81 ****
--- 75,82 ----
      char       *title;            /* override title */
      char      **footers;        /* override footer (default is "(xx rows)") */
      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;

  /*
Index: src/bin/psql/startup.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/startup.c,v
retrieving revision 1.144
diff -c -r1.144 startup.c
*** src/bin/psql/startup.c    11 Dec 2007 19:01:06 -0000    1.144
--- src/bin/psql/startup.c    12 Dec 2007 02:36:43 -0000
***************
*** 140,145 ****
--- 140,146 ----
      pset.cur_cmd_source = stdin;
      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.border = 1;
      pset.popt.topt.pager = 1;
Index: src/bin/scripts/createlang.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/scripts/createlang.c,v
retrieving revision 1.27
diff -c -r1.27 createlang.c
*** src/bin/scripts/createlang.c    11 Dec 2007 19:57:32 -0000    1.27
--- src/bin/scripts/createlang.c    12 Dec 2007 02:36:43 -0000
***************
*** 125,130 ****
--- 125,131 ----
      if (listlangs)
      {
          printQueryOpt popt;
+         static const bool trans_columns[] = {false, true};

          conn = connectDatabase(dbname, host, port, username, password,
                                 progname);
***************
*** 132,138 ****
          printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
                  "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
                            "FROM pg_catalog.pg_language WHERE lanispl;",
!                           _("Name"), _("yes"), _("no"), _("Trusted?"));
          result = executeQuery(conn, sql.data, progname, echo);

          memset(&popt, 0, sizeof(popt));
--- 133,141 ----
          printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
                  "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
                            "FROM pg_catalog.pg_language WHERE lanispl;",
!                           gettext_noop("Name"),
!                           gettext_noop("yes"), gettext_noop("no"),
!                           gettext_noop("Trusted?"));
          result = executeQuery(conn, sql.data, progname, echo);

          memset(&popt, 0, sizeof(popt));
***************
*** 142,147 ****
--- 145,152 ----
          popt.topt.stop_table = true;
          popt.topt.encoding = PQclientEncoding(conn);
          popt.title = _("Procedural Languages");
+         popt.trans_headers = true;
+         popt.trans_columns = trans_columns;
          printQuery(result, &popt, stdout, NULL);

          PQfinish(conn);
Index: src/bin/scripts/droplang.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/scripts/droplang.c,v
retrieving revision 1.24
diff -c -r1.24 droplang.c
*** src/bin/scripts/droplang.c    11 Dec 2007 19:57:32 -0000    1.24
--- src/bin/scripts/droplang.c    12 Dec 2007 02:36:43 -0000
***************
*** 136,141 ****
--- 136,142 ----
      if (listlangs)
      {
          printQueryOpt popt;
+         static const bool trans_columns[] = {false, true};

          conn = connectDatabase(dbname, host, port, username, password,
                                 progname);
***************
*** 143,149 ****
          printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
                  "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
                            "FROM pg_catalog.pg_language WHERE lanispl;",
!                           _("Name"), _("yes"), _("no"), _("Trusted?"));
          result = executeQuery(conn, sql.data, progname, echo);

          memset(&popt, 0, sizeof(popt));
--- 144,152 ----
          printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
                  "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
                            "FROM pg_catalog.pg_language WHERE lanispl;",
!                           gettext_noop("Name"),
!                           gettext_noop("yes"), gettext_noop("no"),
!                           gettext_noop("Trusted?"));
          result = executeQuery(conn, sql.data, progname, echo);

          memset(&popt, 0, sizeof(popt));
***************
*** 153,158 ****
--- 156,163 ----
          popt.topt.stop_table = true;
          popt.topt.encoding = PQclientEncoding(conn);
          popt.title = _("Procedural Languages");
+         popt.trans_headers = true;
+         popt.trans_columns = trans_columns;
          printQuery(result, &popt, stdout, NULL);

          PQfinish(conn);

pgsql-patches by date:

Previous
From: Magnus Hagander
Date:
Subject: Re: [HACKERS] Problem with ControlFileData structure being ABI depe ndent
Next
From: Heikki Linnakangas
Date:
Subject: DDL in EDB-SPL