]> granicus.if.org Git - postgresql/blobdiff - src/bin/psql/describe.c
Add missing translate_columns array entry
[postgresql] / src / bin / psql / describe.c
index 8ec240d09ebd4f9c9442926015b71ce94f979bbd..2cdc5acf30264355c2d5784eca1c8bd9529e3141 100644 (file)
@@ -6,7 +6,7 @@
  * with servers of versions 7.4 and up.  It's okay to omit irrelevant
  * information for an old server, but not to fail outright.
  *
- * Copyright (c) 2000-2011, PostgreSQL Global Development Group
+ * Copyright (c) 2000-2016, PostgreSQL Global Development Group
  *
  * src/bin/psql/describe.c
  */
 
 #include <ctype.h>
 
+#include "catalog/pg_default_acl.h"
+#include "fe_utils/string_utils.h"
+
 #include "common.h"
 #include "describe.h"
-#include "dumputils.h"
-#include "mbprint.h"
-#include "print.h"
+#include "fe_utils/mbprint.h"
+#include "fe_utils/print.h"
 #include "settings.h"
 #include "variables.h"
 
@@ -70,7 +72,14 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem)
                                          gettext_noop("Name"),
                                          gettext_noop("Result data type"));
 
-       if (pset.sversion >= 80200)
+       if (pset.sversion >= 80400)
+               appendPQExpBuffer(&buf,
+                                                 "  CASE WHEN p.pronargs = 0\n"
+                                                 "    THEN CAST('*' AS pg_catalog.text)\n"
+                                        "    ELSE pg_catalog.pg_get_function_arguments(p.oid)\n"
+                                                 "  END AS \"%s\",\n",
+                                                 gettext_noop("Argument data types"));
+       else if (pset.sversion >= 80200)
                appendPQExpBuffer(&buf,
                                                  "  CASE WHEN p.pronargs = 0\n"
                                                  "    THEN CAST('*' AS pg_catalog.text)\n"
@@ -96,16 +105,16 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem)
                                          gettext_noop("Description"));
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                  "n.nspname", "p.proname", NULL,
                                                  "pg_catalog.pg_function_is_visible(p.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2, 4;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -114,7 +123,71 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem)
        myopt.title = _("List of aggregate functions");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+       PQclear(res);
+       return true;
+}
+
+/* \dA
+ * Takes an optional regexp to select particular access methods
+ */
+bool
+describeAccessMethods(const char *pattern, bool verbose)
+{
+       PQExpBufferData buf;
+       PGresult   *res;
+       printQueryOpt myopt = pset.popt;
+       static const bool translate_columns[] = {false, true, false, false};
+
+       if (pset.sversion < 90600)
+       {
+               psql_error("The server (version %d.%d) does not support access methods.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
+               return true;
+       }
+
+       initPQExpBuffer(&buf);
+
+       printfPQExpBuffer(&buf,
+                                         "SELECT amname AS \"%s\",\n"
+                                         "  CASE amtype"
+                                         " WHEN 'i' THEN '%s'"
+                                         " END AS \"%s\"",
+                                         gettext_noop("Name"),
+                                         gettext_noop("Index"),
+                                         gettext_noop("Type"));
+
+       if (verbose)
+       {
+               appendPQExpBuffer(&buf,
+                                                 ",\n  amhandler AS \"%s\",\n"
+                                         "  pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
+                                                 gettext_noop("Handler"),
+                                                 gettext_noop("Description"));
+       }
+
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_am\n");
+
+       processSQLNamePattern(pset.db, &buf, pattern, false, false,
+                                                 NULL, "amname", NULL,
+                                                 NULL);
+
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
+
+       res = PSQLexec(buf.data);
+       termPQExpBuffer(&buf);
+       if (!res)
+               return false;
+
+       myopt.nullPrint = NULL;
+       myopt.title = _("List of access methods");
+       myopt.translate_header = true;
+       myopt.translate_columns = translate_columns;
+       myopt.n_translate_columns = lengthof(translate_columns);
+
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -132,42 +205,61 @@ describeTablespaces(const char *pattern, bool verbose)
 
        if (pset.sversion < 80000)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support tablespaces.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support tablespaces.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
        initPQExpBuffer(&buf);
 
-       printfPQExpBuffer(&buf,
-                                         "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 (pset.sversion >= 90200)
+               printfPQExpBuffer(&buf,
+                                                 "SELECT spcname AS \"%s\",\n"
+                                               "  pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
+                                               "  pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
+                                                 gettext_noop("Name"),
+                                                 gettext_noop("Owner"),
+                                                 gettext_noop("Location"));
+       else
+               printfPQExpBuffer(&buf,
+                                                 "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  ");
+               appendPQExpBufferStr(&buf, ",\n  ");
                printACLColumn(&buf, "spcacl");
        }
 
+       if (verbose && pset.sversion >= 90000)
+               appendPQExpBuffer(&buf,
+                                                 ",\n  spcoptions AS \"%s\"",
+                                                 gettext_noop("Options"));
+
+       if (verbose && pset.sversion >= 90200)
+               appendPQExpBuffer(&buf,
+                                                 ",\n  pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\"",
+                                                 gettext_noop("Size"));
+
        if (verbose && pset.sversion >= 80200)
                appendPQExpBuffer(&buf,
                 ",\n  pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
                                                  gettext_noop("Description"));
 
-       appendPQExpBuffer(&buf,
-                                         "\nFROM pg_catalog.pg_tablespace\n");
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_tablespace\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                  NULL, "spcname", NULL,
                                                  NULL);
 
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -176,7 +268,7 @@ describeTablespaces(const char *pattern, bool verbose)
        myopt.title = _("List of tablespaces");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -206,18 +298,18 @@ 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+"))
        {
-               fprintf(stderr, _("\\df only takes [antwS+] as options\n"));
+               psql_error("\\df only takes [antwS+] as options\n");
                return true;
        }
 
        if (showWindow && pset.sversion < 80400)
        {
-               fprintf(stderr, _("\\df does not take a \"w\" option with server version %d.%d\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("\\df does not take a \"w\" option with server version %d.%d\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -245,7 +337,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
                                                  "  WHEN p.proiswindow THEN '%s'\n"
                                                  "  WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
                                                  "  ELSE '%s'\n"
-                                                 "END as \"%s\"",
+                                                 " END as \"%s\"",
                                                  gettext_noop("Result data type"),
                                                  gettext_noop("Argument data types"),
                /* translator: "agg" is short for "aggregate" */
@@ -319,15 +411,19 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
 
        if (verbose)
                appendPQExpBuffer(&buf,
+                                 ",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\""
                                                  ",\n CASE\n"
                                                  "  WHEN p.provolatile = 'i' THEN '%s'\n"
                                                  "  WHEN p.provolatile = 's' THEN '%s'\n"
                                                  "  WHEN p.provolatile = 'v' THEN '%s'\n"
-                                                 "END as \"%s\""
+                                                 " END as \"%s\""
                                   ",\n  pg_catalog.pg_get_userbyid(p.proowner) as \"%s\",\n"
                                                  "  l.lanname as \"%s\",\n"
                                                  "  p.prosrc as \"%s\",\n"
                                  "  pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
+                                                 gettext_noop("definer"),
+                                                 gettext_noop("invoker"),
+                                                 gettext_noop("Security"),
                                                  gettext_noop("immutable"),
                                                  gettext_noop("stable"),
                                                  gettext_noop("volatile"),
@@ -337,12 +433,12 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
                                                  gettext_noop("Source code"),
                                                  gettext_noop("Description"));
 
-       appendPQExpBuffer(&buf,
-                                         "\nFROM pg_catalog.pg_proc p"
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_proc p"
        "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
 
        if (verbose)
-               appendPQExpBuffer(&buf,
+               appendPQExpBufferStr(&buf,
                   "     LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
 
        have_where = false;
@@ -355,65 +451,65 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
                if (!showAggregate)
                {
                        if (have_where)
-                               appendPQExpBuffer(&buf, "      AND ");
+                               appendPQExpBufferStr(&buf, "      AND ");
                        else
                        {
-                               appendPQExpBuffer(&buf, "WHERE ");
+                               appendPQExpBufferStr(&buf, "WHERE ");
                                have_where = true;
                        }
-                       appendPQExpBuffer(&buf, "NOT p.proisagg\n");
+                       appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
                }
                if (!showTrigger)
                {
                        if (have_where)
-                               appendPQExpBuffer(&buf, "      AND ");
+                               appendPQExpBufferStr(&buf, "      AND ");
                        else
                        {
-                               appendPQExpBuffer(&buf, "WHERE ");
+                               appendPQExpBufferStr(&buf, "WHERE ");
                                have_where = true;
                        }
-                       appendPQExpBuffer(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
+                       appendPQExpBufferStr(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
                }
                if (!showWindow && pset.sversion >= 80400)
                {
                        if (have_where)
-                               appendPQExpBuffer(&buf, "      AND ");
+                               appendPQExpBufferStr(&buf, "      AND ");
                        else
                        {
-                               appendPQExpBuffer(&buf, "WHERE ");
+                               appendPQExpBufferStr(&buf, "WHERE ");
                                have_where = true;
                        }
-                       appendPQExpBuffer(&buf, "NOT p.proiswindow\n");
+                       appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
                }
        }
        else
        {
                bool            needs_or = false;
 
-               appendPQExpBuffer(&buf, "WHERE (\n       ");
+               appendPQExpBufferStr(&buf, "WHERE (\n       ");
                have_where = true;
                /* Note: at least one of these must be true ... */
                if (showAggregate)
                {
-                       appendPQExpBuffer(&buf, "p.proisagg\n");
+                       appendPQExpBufferStr(&buf, "p.proisagg\n");
                        needs_or = true;
                }
                if (showTrigger)
                {
                        if (needs_or)
-                               appendPQExpBuffer(&buf, "       OR ");
-                       appendPQExpBuffer(&buf,
+                               appendPQExpBufferStr(&buf, "       OR ");
+                       appendPQExpBufferStr(&buf,
                                "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n");
                        needs_or = true;
                }
                if (showWindow)
                {
                        if (needs_or)
-                               appendPQExpBuffer(&buf, "       OR ");
-                       appendPQExpBuffer(&buf, "p.proiswindow\n");
+                               appendPQExpBufferStr(&buf, "       OR ");
+                       appendPQExpBufferStr(&buf, "p.proiswindow\n");
                        needs_or = true;
                }
-               appendPQExpBuffer(&buf, "      )\n");
+               appendPQExpBufferStr(&buf, "      )\n");
        }
 
        processSQLNamePattern(pset.db, &buf, pattern, have_where, false,
@@ -421,12 +517,12 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
                                                  "pg_catalog.pg_function_is_visible(p.oid)");
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2, 4;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -435,8 +531,9 @@ 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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -475,19 +572,19 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
                                                  gettext_noop("Size"));
        if (verbose && pset.sversion >= 80300)
        {
-               appendPQExpBuffer(&buf,
-                                                 "  pg_catalog.array_to_string(\n"
-                                                 "      ARRAY(\n"
-                                                 "                  SELECT e.enumlabel\n"
-                                                 "          FROM pg_catalog.pg_enum e\n"
-                                                 "          WHERE e.enumtypid = t.oid\n");
+               appendPQExpBufferStr(&buf,
+                                                        "  pg_catalog.array_to_string(\n"
+                                                        "      ARRAY(\n"
+                                                        "                   SELECT e.enumlabel\n"
+                                                        "          FROM pg_catalog.pg_enum e\n"
+                                                        "          WHERE e.enumtypid = t.oid\n");
 
                if (pset.sversion >= 90100)
-                       appendPQExpBuffer(&buf,
-                                                         "          ORDER BY e.enumsortorder\n");
+                       appendPQExpBufferStr(&buf,
+                                                                "          ORDER BY e.enumsortorder\n");
                else
-                       appendPQExpBuffer(&buf,
-                                                         "          ORDER BY e.oid\n");
+                       appendPQExpBufferStr(&buf,
+                                                                "          ORDER BY e.oid\n");
 
                appendPQExpBuffer(&buf,
                                                  "      ),\n"
@@ -495,34 +592,45 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
                                                  "  ) AS \"%s\",\n",
                                                  gettext_noop("Elements"));
        }
+       if (verbose)
+       {
+               appendPQExpBuffer(&buf,
+                                        "  pg_catalog.pg_get_userbyid(t.typowner) AS \"%s\",\n",
+                                                 gettext_noop("Owner"));
+       }
+       if (verbose && pset.sversion >= 90200)
+       {
+               printACLColumn(&buf, "t.typacl");
+               appendPQExpBufferStr(&buf, ",\n  ");
+       }
 
        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"
+       appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_type t\n"
         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
 
        /*
         * do not include complex types (typrelid!=0) unless they are standalone
         * composite types
         */
-       appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 ");
-       appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
-                                         "WHERE c.oid = t.typrelid))\n");
+       appendPQExpBufferStr(&buf, "WHERE (t.typrelid = 0 ");
+       appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
+                                                "WHERE c.oid = t.typrelid))\n");
 
        /*
         * do not include array types (before 8.3 we have to use the assumption
         * that their names start with underscore)
         */
        if (pset.sversion >= 80300)
-               appendPQExpBuffer(&buf, "  AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
+               appendPQExpBufferStr(&buf, "  AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
        else
-               appendPQExpBuffer(&buf, "  AND t.typname !~ '^_'\n");
+               appendPQExpBufferStr(&buf, "  AND t.typname !~ '^_'\n");
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        /* Match name pattern against either internal or external name */
        processSQLNamePattern(pset.db, &buf, pattern, true, false,
@@ -530,9 +638,9 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
                                                  "pg_catalog.format_type(t.oid, NULL)",
                                                  "pg_catalog.pg_type_is_visible(t.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -541,7 +649,7 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
        myopt.title = _("List of data types");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -549,9 +657,10 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
 
 
 /* \do
+ * Describe operators
  */
 bool
-describeOperators(const char *pattern, bool showSystem)
+describeOperators(const char *pattern, bool verbose, bool showSystem)
 {
        PQExpBufferData buf;
        PGresult   *res;
@@ -577,29 +686,36 @@ describeOperators(const char *pattern, bool showSystem)
                                          "  o.oprname AS \"%s\",\n"
                                          "  CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
                                          "  CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
-                                  "  pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n"
-                        "  coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
-       "           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",
+                                 "  pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
                                          gettext_noop("Schema"),
                                          gettext_noop("Name"),
                                          gettext_noop("Left arg type"),
                                          gettext_noop("Right arg type"),
-                                         gettext_noop("Result type"),
+                                         gettext_noop("Result type"));
+
+       if (verbose)
+               appendPQExpBuffer(&buf,
+                                                 "  o.oprcode AS \"%s\",\n",
+                                                 gettext_noop("Function"));
+
+       appendPQExpBuffer(&buf,
+                        "  coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
+       "           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("Description"));
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, true,
                                                  "n.nspname", "o.oprname", NULL,
                                                  "pg_catalog.pg_operator_is_visible(o.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -608,7 +724,7 @@ describeOperators(const char *pattern, bool showSystem)
        myopt.title = _("List of operators");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -621,7 +737,7 @@ describeOperators(const char *pattern, bool showSystem)
  * for \l, \list, and -l switch
  */
 bool
-listAllDbs(bool verbose)
+listAllDbs(const char *pattern, bool verbose)
 {
        PGresult   *res;
        PQExpBufferData buf;
@@ -642,7 +758,7 @@ listAllDbs(bool verbose)
                                                  "       d.datctype as \"%s\",\n",
                                                  gettext_noop("Collate"),
                                                  gettext_noop("Ctype"));
-       appendPQExpBuffer(&buf, "       ");
+       appendPQExpBufferStr(&buf, "       ");
        printACLColumn(&buf, "d.datacl");
        if (verbose && pset.sversion >= 80200)
                appendPQExpBuffer(&buf,
@@ -659,13 +775,18 @@ listAllDbs(bool verbose)
                appendPQExpBuffer(&buf,
                                                  ",\n       pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
                                                  gettext_noop("Description"));
-       appendPQExpBuffer(&buf,
-                                         "\nFROM pg_catalog.pg_database d\n");
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_database d\n");
        if (verbose && pset.sversion >= 80000)
-               appendPQExpBuffer(&buf,
+               appendPQExpBufferStr(&buf,
                   "  JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
-       res = PSQLexec(buf.data, false);
+
+       if (pattern)
+               processSQLNamePattern(pset.db, &buf, pattern, false, false,
+                                                         NULL, "d.datname", NULL, NULL);
+
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -674,7 +795,7 @@ listAllDbs(bool verbose)
        myopt.title = _("List of databases");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -691,7 +812,7 @@ permissionsList(const char *pattern)
        PQExpBufferData buf;
        PGresult   *res;
        printQueryOpt myopt = pset.popt;
-       static const bool translate_columns[] = {false, false, true, false, false};
+       static const bool translate_columns[] = {false, false, true, false, false, false};
 
        initPQExpBuffer(&buf);
 
@@ -701,11 +822,20 @@ permissionsList(const char *pattern)
        printfPQExpBuffer(&buf,
                                          "SELECT n.nspname as \"%s\",\n"
                                          "  c.relname as \"%s\",\n"
-                                         "  CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END as \"%s\",\n"
+                                         "  CASE c.relkind"
+                                         " WHEN 'r' THEN '%s'"
+                                         " WHEN 'v' THEN '%s'"
+                                         " WHEN 'm' THEN '%s'"
+                                         " WHEN 'S' THEN '%s'"
+                                         " WHEN 'f' THEN '%s'"
+                                         " END as \"%s\",\n"
                                          "  ",
                                          gettext_noop("Schema"),
                                          gettext_noop("Name"),
-          gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
+                                         gettext_noop("table"),
+                                         gettext_noop("view"),
+                                         gettext_noop("materialized view"),
+                                         gettext_noop("sequence"),
                                          gettext_noop("foreign table"),
                                          gettext_noop("Type"));
 
@@ -718,11 +848,42 @@ permissionsList(const char *pattern)
                                                  "    FROM pg_catalog.pg_attribute a\n"
                                                  "    WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
                                                  "  ), E'\\n') AS \"%s\"",
-                                                 gettext_noop("Column access privileges"));
+                                                 gettext_noop("Column privileges"));
 
-       appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_class c\n"
+       if (pset.sversion >= 90500)
+               appendPQExpBuffer(&buf,
+                                                 ",\n  pg_catalog.array_to_string(ARRAY(\n"
+                                                 "    SELECT polname\n"
+                                                 "    || CASE WHEN polcmd != '*' THEN\n"
+                                                 "           E' (' || polcmd || E'):'\n"
+                                                 "       ELSE E':' \n"
+                                                 "       END\n"
+                                                 "    || CASE WHEN polqual IS NOT NULL THEN\n"
+                                                 "           E'\\n  (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
+                                                 "       ELSE E''\n"
+                                                 "       END\n"
+                                                 "    || CASE WHEN polwithcheck IS NOT NULL THEN\n"
+                                                 "           E'\\n  (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
+                                                 "       ELSE E''\n"
+                                                 "       END"
+                                                 "    || CASE WHEN polroles <> '{0}' THEN\n"
+                                  "           E'\\n  to: ' || pg_catalog.array_to_string(\n"
+                                                 "               ARRAY(\n"
+                                                 "                   SELECT rolname\n"
+                                                 "                   FROM pg_catalog.pg_roles\n"
+                                                 "                   WHERE oid = ANY (polroles)\n"
+                                                 "                   ORDER BY 1\n"
+                                                 "               ), E', ')\n"
+                                                 "       ELSE E''\n"
+                                                 "       END\n"
+                                                 "    FROM pg_catalog.pg_policy pol\n"
+                                                 "    WHERE polrelid = c.oid), E'\\n')\n"
+                                                 "    AS \"%s\"",
+                                                 gettext_noop("Policies"));
+
+       appendPQExpBufferStr(&buf, "\nFROM 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', 'f')\n");
+                                                "WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f')\n");
 
        /*
         * Unless a schema pattern is specified, we suppress system and temp
@@ -734,9 +895,9 @@ permissionsList(const char *pattern)
                                                  "n.nspname", "c.relname", NULL,
                        "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        if (!res)
        {
                termPQExpBuffer(&buf);
@@ -748,8 +909,9 @@ 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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        termPQExpBuffer(&buf);
        PQclear(res);
@@ -760,7 +922,7 @@ permissionsList(const char *pattern)
 /*
  * \ddp
  *
- * List DefaultACLs.  The pattern can match either schema or role name.
+ * List Default ACLs.  The pattern can match either schema or role name.
  */
 bool
 listDefaultACLs(const char *pattern)
@@ -772,8 +934,8 @@ listDefaultACLs(const char *pattern)
 
        if (pset.sversion < 90000)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support altering default privileges.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support altering default privileges.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -782,19 +944,24 @@ listDefaultACLs(const char *pattern)
        printfPQExpBuffer(&buf,
                           "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
                                          "  n.nspname AS \"%s\",\n"
-                                         "  CASE d.defaclobjtype WHEN 'r' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END AS \"%s\",\n"
+                                         "  CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
                                          "  ",
                                          gettext_noop("Owner"),
                                          gettext_noop("Schema"),
+                                         DEFACLOBJ_RELATION,
                                          gettext_noop("table"),
+                                         DEFACLOBJ_SEQUENCE,
                                          gettext_noop("sequence"),
+                                         DEFACLOBJ_FUNCTION,
                                          gettext_noop("function"),
+                                         DEFACLOBJ_TYPE,
+                                         gettext_noop("type"),
                                          gettext_noop("Type"));
 
        printACLColumn(&buf, "d.defaclacl");
 
-       appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
-                                         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
+       appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
+                                                "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                  NULL,
@@ -802,9 +969,9 @@ listDefaultACLs(const char *pattern)
                                                  "pg_catalog.pg_get_userbyid(d.defaclrole)",
                                                  NULL);
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        if (!res)
        {
                termPQExpBuffer(&buf);
@@ -816,8 +983,9 @@ 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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        termPQExpBuffer(&buf);
        PQclear(res);
@@ -854,7 +1022,7 @@ objectDescription(const char *pattern, bool showSystem)
                                          gettext_noop("Object"),
                                          gettext_noop("Description"));
 
-       /* Constraint descriptions */
+       /* Table constraint descriptions */
        appendPQExpBuffer(&buf,
                                          "  SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
                                          "  n.nspname as nspname,\n"
@@ -865,19 +1033,41 @@ objectDescription(const char *pattern, bool showSystem)
                                          "ON c.oid = pgc.conrelid\n"
                                          "    LEFT JOIN pg_catalog.pg_namespace n "
                                          "    ON n.oid = c.relnamespace\n",
-                                         gettext_noop("constraint"));
+                                         gettext_noop("table constraint"));
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern,
                                                  false, "n.nspname", "pgc.conname", NULL,
                                                  "pg_catalog.pg_table_is_visible(c.oid)");
 
+       /* Domain constraint descriptions */
+       appendPQExpBuffer(&buf,
+                                         "UNION ALL\n"
+                                         "  SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
+                                         "  n.nspname as nspname,\n"
+                                         "  CAST(pgc.conname AS pg_catalog.text) as name,"
+                                         "  CAST('%s' AS pg_catalog.text) as object\n"
+                                         "  FROM pg_catalog.pg_constraint pgc\n"
+                                         "    JOIN pg_catalog.pg_type t "
+                                         "ON t.oid = pgc.contypid\n"
+                                         "    LEFT JOIN pg_catalog.pg_namespace n "
+                                         "    ON n.oid = t.typnamespace\n",
+                                         gettext_noop("domain constraint"));
+
+       if (!showSystem && !pattern)
+               appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
+
+       processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern,
+                                                 false, "n.nspname", "pgc.conname", NULL,
+                                                 "pg_catalog.pg_type_is_visible(t.oid)");
+
+
        /*
-        * pg_opclass.opcmethod only available in 8.3+, and comment on operator
-        * family only available in 8.3+
+        * pg_opclass.opcmethod only available in 8.3+
         */
        if (pset.sversion >= 80300)
        {
@@ -896,17 +1086,24 @@ objectDescription(const char *pattern, bool showSystem)
                                                  gettext_noop("operator class"));
 
                if (!showSystem && !pattern)
-                       appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                         "      AND n.nspname <> 'information_schema'\n");
+                       appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                       "      AND n.nspname <> 'information_schema'\n");
 
                processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                          "n.nspname", "o.opcname", NULL,
                                                          "pg_catalog.pg_opclass_is_visible(o.oid)");
+       }
 
+       /*
+        * although operator family comments have been around since 8.3,
+        * pg_opfamily_is_visible is only available in 9.2+
+        */
+       if (pset.sversion >= 90200)
+       {
                /* Operator family descriptions */
                appendPQExpBuffer(&buf,
                                                  "UNION ALL\n"
-                                                 "  SELECT opf.oid as oid, opf.tableoid as tableoid,\n"
+                                          "  SELECT opf.oid as oid, opf.tableoid as tableoid,\n"
                                                  "  n.nspname as nspname,\n"
                                                  "  CAST(opf.opfname AS pg_catalog.text) AS name,\n"
                                                  "  CAST('%s' AS pg_catalog.text) as object\n"
@@ -918,8 +1115,8 @@ objectDescription(const char *pattern, bool showSystem)
                                                  gettext_noop("operator family"));
 
                if (!showSystem && !pattern)
-                       appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                         "      AND n.nspname <> 'information_schema'\n");
+                       appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                       "      AND n.nspname <> 'information_schema'\n");
 
                processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                          "n.nspname", "opf.opfname", NULL,
@@ -940,8 +1137,8 @@ objectDescription(const char *pattern, bool showSystem)
                                          gettext_noop("rule"));
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                  "n.nspname", "r.rulename", NULL,
@@ -960,20 +1157,20 @@ objectDescription(const char *pattern, bool showSystem)
                                          gettext_noop("trigger"));
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
                                                  "n.nspname", "t.tgname", NULL,
                                                  "pg_catalog.pg_table_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf,
-                                         ") AS tt\n"
-                                         "  JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
+       appendPQExpBufferStr(&buf,
+                                                ") AS tt\n"
+                                                "  JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -982,8 +1179,9 @@ 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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -1015,16 +1213,16 @@ describeTableDetails(const char *pattern, bool verbose, bool showSystem)
         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
                                                  "n.nspname", "c.relname", NULL,
                                                  "pg_catalog.pg_table_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 2, 3;");
+       appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -1032,8 +1230,8 @@ describeTableDetails(const char *pattern, bool verbose, bool showSystem)
        if (PQntuples(res) == 0)
        {
                if (!pset.quiet)
-                       fprintf(stderr, _("Did not find any relation named \"%s\".\n"),
-                                       pattern);
+                       psql_error("Did not find any relation named \"%s\".\n",
+                                          pattern);
                PQclear(res);
                return false;
        }
@@ -1084,7 +1282,7 @@ describeOneTableDetails(const char *schemaname,
        bool            printTableInitialized = false;
        int                     i;
        char       *view_def = NULL;
-       char       *headers[6];
+       char       *headers[9];
        char      **seq_values = NULL;
        char      **modifiers = NULL;
        char      **ptr;
@@ -1099,17 +1297,21 @@ describeOneTableDetails(const char *schemaname,
                bool            hasindex;
                bool            hasrules;
                bool            hastriggers;
+               bool            rowsecurity;
+               bool            forcerowsecurity;
                bool            hasoids;
                Oid                     tablespace;
                char       *reloptions;
                char       *reloftype;
                char            relpersistence;
+               char            relreplident;
        }                       tableinfo;
        bool            show_modifiers = false;
        bool            retval;
 
        retval = false;
 
+       myopt.default_footer = false;
        /* This output looks confusing in expanded mode. */
        myopt.expanded = false;
 
@@ -1118,11 +1320,45 @@ describeOneTableDetails(const char *schemaname,
        initPQExpBuffer(&tmpbuf);
 
        /* Get general table info */
-       if (pset.sversion >= 90100)
+       if (pset.sversion >= 90500)
        {
                printfPQExpBuffer(&buf,
                          "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
-                                                 "c.relhastriggers, c.relhasoids, "
+                               "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
+                                                 "c.relhasoids, %s, c.reltablespace, "
+                                                 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
+                                                 "c.relpersistence, c.relreplident\n"
+                                                 "FROM pg_catalog.pg_class c\n "
+                  "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
+                                                 "WHERE c.oid = '%s';",
+                                                 (verbose ?
+                                                  "pg_catalog.array_to_string(c.reloptions || "
+                                                  "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
+                                                  : "''"),
+                                                 oid);
+       }
+       else if (pset.sversion >= 90400)
+       {
+               printfPQExpBuffer(&buf,
+                         "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
+                                                 "c.relhastriggers, false, false, c.relhasoids, "
+                                                 "%s, c.reltablespace, "
+                                                 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
+                                                 "c.relpersistence, c.relreplident\n"
+                                                 "FROM pg_catalog.pg_class c\n "
+                  "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
+                                                 "WHERE c.oid = '%s';",
+                                                 (verbose ?
+                                                  "pg_catalog.array_to_string(c.reloptions || "
+                                                  "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
+                                                  : "''"),
+                                                 oid);
+       }
+       else if (pset.sversion >= 90100)
+       {
+               printfPQExpBuffer(&buf,
+                         "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
+                                                 "c.relhastriggers, false, false, c.relhasoids, "
                                                  "%s, c.reltablespace, "
                                                  "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
                                                  "c.relpersistence\n"
@@ -1139,7 +1375,7 @@ describeOneTableDetails(const char *schemaname,
        {
                printfPQExpBuffer(&buf,
                          "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
-                                                 "c.relhastriggers, c.relhasoids, "
+                                                 "c.relhastriggers, false, false, c.relhasoids, "
                                                  "%s, c.reltablespace, "
                                                  "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END\n"
                                                  "FROM pg_catalog.pg_class c\n "
@@ -1155,7 +1391,7 @@ describeOneTableDetails(const char *schemaname,
        {
                printfPQExpBuffer(&buf,
                          "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
-                                                 "c.relhastriggers, c.relhasoids, "
+                                                 "c.relhastriggers, false, false, c.relhasoids, "
                                                  "%s, c.reltablespace\n"
                                                  "FROM pg_catalog.pg_class c\n "
                   "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
@@ -1170,7 +1406,7 @@ describeOneTableDetails(const char *schemaname,
        {
                printfPQExpBuffer(&buf,
                                          "SELECT relchecks, relkind, relhasindex, relhasrules, "
-                                                 "reltriggers <> 0, relhasoids, "
+                                                 "reltriggers <> 0, false, false, relhasoids, "
                                                  "%s, reltablespace\n"
                                                  "FROM pg_catalog.pg_class WHERE oid = '%s';",
                                                  (verbose ?
@@ -1181,7 +1417,7 @@ describeOneTableDetails(const char *schemaname,
        {
                printfPQExpBuffer(&buf,
                                          "SELECT relchecks, relkind, relhasindex, relhasrules, "
-                                                 "reltriggers <> 0, relhasoids, "
+                                                 "reltriggers <> 0, false, false, relhasoids, "
                                                  "'', reltablespace\n"
                                                  "FROM pg_catalog.pg_class WHERE oid = '%s';",
                                                  oid);
@@ -1190,13 +1426,13 @@ describeOneTableDetails(const char *schemaname,
        {
                printfPQExpBuffer(&buf,
                                          "SELECT relchecks, relkind, relhasindex, relhasrules, "
-                                                 "reltriggers <> 0, relhasoids, "
+                                                 "reltriggers <> 0, false, false, relhasoids, "
                                                  "'', ''\n"
                                                  "FROM pg_catalog.pg_class WHERE oid = '%s';",
                                                  oid);
        }
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        if (!res)
                goto error_return;
 
@@ -1204,8 +1440,7 @@ describeOneTableDetails(const char *schemaname,
        if (PQntuples(res) == 0)
        {
                if (!pset.quiet)
-                       fprintf(stderr, _("Did not find any relation with OID %s.\n"),
-                                       oid);
+                       psql_error("Did not find any relation with OID %s.\n", oid);
                goto error_return;
        }
 
@@ -1214,15 +1449,20 @@ describeOneTableDetails(const char *schemaname,
        tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
        tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
        tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
-       tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
+       tableinfo.rowsecurity = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
+       tableinfo.forcerowsecurity = strcmp(PQgetvalue(res, 0, 6), "t") == 0;
+       tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 7), "t") == 0;
        tableinfo.reloptions = (pset.sversion >= 80200) ?
-               strdup(PQgetvalue(res, 0, 6)) : 0;
+               pg_strdup(PQgetvalue(res, 0, 8)) : NULL;
        tableinfo.tablespace = (pset.sversion >= 80000) ?
-               atooid(PQgetvalue(res, 0, 7)) : 0;
-       tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 8), "") != 0) ?
-               strdup(PQgetvalue(res, 0, 8)) : 0;
-       tableinfo.relpersistence = (pset.sversion >= 90100 && strcmp(PQgetvalue(res, 0, 9), "") != 0) ?
-               PQgetvalue(res, 0, 9)[0] : 0;
+               atooid(PQgetvalue(res, 0, 9)) : 0;
+       tableinfo.reloftype = (pset.sversion >= 90000 &&
+                                                  strcmp(PQgetvalue(res, 0, 10), "") != 0) ?
+               pg_strdup(PQgetvalue(res, 0, 10)) : NULL;
+       tableinfo.relpersistence = (pset.sversion >= 90100) ?
+               *(PQgetvalue(res, 0, 11)) : 0;
+       tableinfo.relreplident = (pset.sversion >= 90400) ?
+               *(PQgetvalue(res, 0, 12)) : 'd';
        PQclear(res);
        res = NULL;
 
@@ -1236,7 +1476,7 @@ describeOneTableDetails(const char *schemaname,
                /* must be separate because fmtId isn't reentrant */
                appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
 
-               res = PSQLexec(buf.data, false);
+               res = PSQLexec(buf.data);
                if (!res)
                        goto error_return;
 
@@ -1257,43 +1497,46 @@ describeOneTableDetails(const char *schemaname,
         * you are adding column(s) preceding to verbose-only columns.
         */
        printfPQExpBuffer(&buf, "SELECT a.attname,");
-       appendPQExpBuffer(&buf, "\n  pg_catalog.format_type(a.atttypid, a.atttypmod),"
-                                         "\n  (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
-                                         "\n   FROM pg_catalog.pg_attrdef d"
-                                         "\n   WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
-                                         "\n  a.attnotnull, a.attnum,");
+       appendPQExpBufferStr(&buf, "\n  pg_catalog.format_type(a.atttypid, a.atttypmod),"
+                                                "\n  (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
+                                                "\n   FROM pg_catalog.pg_attrdef d"
+                                                "\n   WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
+                                                "\n  a.attnotnull, a.attnum,");
        if (pset.sversion >= 90100)
-               appendPQExpBuffer(&buf, "\n  (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
-                                                 "   WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
+               appendPQExpBufferStr(&buf, "\n  (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
+                                                        "   WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
        else
-               appendPQExpBuffer(&buf, "\n  NULL AS attcollation");
+               appendPQExpBufferStr(&buf, "\n  NULL AS attcollation");
        if (tableinfo.relkind == 'i')
-               appendPQExpBuffer(&buf, ",\n  pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
+               appendPQExpBufferStr(&buf, ",\n  pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
        else
-               appendPQExpBuffer(&buf, ",\n  NULL AS indexdef");
+               appendPQExpBufferStr(&buf, ",\n  NULL AS indexdef");
        if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
-               appendPQExpBuffer(&buf, ",\n  CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
-                                                               "  '(' || array_to_string(ARRAY(SELECT quote_ident(option_name) ||  ' ' || quote_literal(option_value)  FROM "
-                                                               "  pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
+               appendPQExpBufferStr(&buf, ",\n  CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
+                                                        "  '(' || array_to_string(ARRAY(SELECT quote_ident(option_name) ||  ' ' || quote_literal(option_value)  FROM "
+                                                        "  pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
        else
-               appendPQExpBuffer(&buf, ",\n  NULL AS attfdwoptions");
+               appendPQExpBufferStr(&buf, ",\n  NULL AS attfdwoptions");
        if (verbose)
        {
-               appendPQExpBuffer(&buf, ",\n  a.attstorage");
+               appendPQExpBufferStr(&buf, ",\n  a.attstorage");
+               appendPQExpBufferStr(&buf, ",\n  CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
+
                /*
                 * In 9.0+, we have column comments for: relations, views, composite
                 * types, and foreign tables (c.f. CommentObject() in comment.c).
                 */
                if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
+                       tableinfo.relkind == 'm' ||
                        tableinfo.relkind == 'f' || tableinfo.relkind == 'c')
-                       appendPQExpBuffer(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)");
+                       appendPQExpBufferStr(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)");
        }
 
-       appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_attribute a");
+       appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_attribute a");
        appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
-       appendPQExpBuffer(&buf, "\nORDER BY a.attnum;");
+       appendPQExpBufferStr(&buf, "\nORDER BY a.attnum;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        if (!res)
                goto error_return;
        numrows = PQntuples(res);
@@ -1313,6 +1556,14 @@ describeOneTableDetails(const char *schemaname,
                        printfPQExpBuffer(&title, _("View \"%s.%s\""),
                                                          schemaname, relationname);
                        break;
+               case 'm':
+                       if (tableinfo.relpersistence == 'u')
+                               printfPQExpBuffer(&title, _("Unlogged materialized view \"%s.%s\""),
+                                                                 schemaname, relationname);
+                       else
+                               printfPQExpBuffer(&title, _("Materialized view \"%s.%s\""),
+                                                                 schemaname, relationname);
+                       break;
                case 'S':
                        printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
                                                          schemaname, relationname);
@@ -1355,11 +1606,12 @@ describeOneTableDetails(const char *schemaname,
        cols = 2;
 
        if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
+               tableinfo.relkind == 'm' ||
                tableinfo.relkind == 'f' || tableinfo.relkind == 'c')
        {
                show_modifiers = true;
                headers[cols++] = gettext_noop("Modifiers");
-               modifiers = pg_malloc_zero((numrows + 1) * sizeof(*modifiers));
+               modifiers = pg_malloc0((numrows + 1) * sizeof(*modifiers));
        }
 
        if (tableinfo.relkind == 'S')
@@ -1374,8 +1626,12 @@ describeOneTableDetails(const char *schemaname,
        if (verbose)
        {
                headers[cols++] = gettext_noop("Storage");
+               if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
+                       tableinfo.relkind == 'f')
+                       headers[cols++] = gettext_noop("Stats target");
                /* Column comments, if the relkind supports this feature. */
                if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
+                       tableinfo.relkind == 'm' ||
                        tableinfo.relkind == 'c' || tableinfo.relkind == 'f')
                        headers[cols++] = gettext_noop("Description");
        }
@@ -1386,15 +1642,15 @@ describeOneTableDetails(const char *schemaname,
        for (i = 0; i < cols; i++)
                printTableAddHeader(&cont, headers[i], true, 'l');
 
-       /* Check if table is a view */
-       if (tableinfo.relkind == 'v' && verbose)
+       /* Check if table is a view or materialized view */
+       if ((tableinfo.relkind == 'v' || tableinfo.relkind == 'm') && verbose)
        {
                PGresult   *result;
 
                printfPQExpBuffer(&buf,
-                         "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
+                        "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
                                                  oid);
-               result = PSQLexec(buf.data, false);
+               result = PSQLexec(buf.data);
                if (!result)
                        goto error_return;
 
@@ -1421,7 +1677,7 @@ describeOneTableDetails(const char *schemaname,
                        if (!PQgetisnull(res, i, 5))
                        {
                                if (tmpbuf.len > 0)
-                                       appendPQExpBufferStr(&tmpbuf, " ");
+                                       appendPQExpBufferChar(&tmpbuf, ' ');
                                appendPQExpBuffer(&tmpbuf, _("collate %s"),
                                                                  PQgetvalue(res, i, 5));
                        }
@@ -1429,7 +1685,7 @@ describeOneTableDetails(const char *schemaname,
                        if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
                        {
                                if (tmpbuf.len > 0)
-                                       appendPQExpBufferStr(&tmpbuf, " ");
+                                       appendPQExpBufferChar(&tmpbuf, ' ');
                                appendPQExpBufferStr(&tmpbuf, _("not null"));
                        }
 
@@ -1438,7 +1694,7 @@ describeOneTableDetails(const char *schemaname,
                        if (strlen(PQgetvalue(res, i, 2)) != 0)
                        {
                                if (tmpbuf.len > 0)
-                                       appendPQExpBufferStr(&tmpbuf, " ");
+                                       appendPQExpBufferChar(&tmpbuf, ' ');
                                /* translator: default values of column definitions */
                                appendPQExpBuffer(&tmpbuf, _("default %s"),
                                                                  PQgetvalue(res, i, 2));
@@ -1473,10 +1729,20 @@ describeOneTableDetails(const char *schemaname,
                                                                                (storage[0] == 'e' ? "external" :
                                                                                 "???")))),
                                                          false, false);
+
+                       /* Statistics target, if the relkind supports this feature */
+                       if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
+                               tableinfo.relkind == 'f')
+                       {
+                               printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
+                                                                 false, false);
+                       }
+
                        /* Column comments, if the relkind supports this feature. */
                        if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
+                               tableinfo.relkind == 'm' ||
                                tableinfo.relkind == 'c' || tableinfo.relkind == 'f')
-                               printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
+                               printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 2),
                                                                  false, false);
                }
        }
@@ -1490,26 +1756,32 @@ describeOneTableDetails(const char *schemaname,
                printfPQExpBuffer(&buf,
                                 "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
                if (pset.sversion >= 80200)
-                       appendPQExpBuffer(&buf, "i.indisvalid,\n");
+                       appendPQExpBufferStr(&buf, "i.indisvalid,\n");
                else
-                       appendPQExpBuffer(&buf, "true AS indisvalid,\n");
+                       appendPQExpBufferStr(&buf, "true AS indisvalid,\n");
                if (pset.sversion >= 90000)
-                       appendPQExpBuffer(&buf,
-                                                         "  (NOT i.indimmediate) AND "
+                       appendPQExpBufferStr(&buf,
+                                                                "  (NOT i.indimmediate) AND "
                                                        "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
-                                                         "WHERE conrelid = i.indrelid AND "
-                                                         "conindid = i.indexrelid AND "
-                                                         "contype IN ('p','u','x') AND "
-                                                         "condeferrable) AS condeferrable,\n"
-                                                         "  (NOT i.indimmediate) AND "
+                                                                "WHERE conrelid = i.indrelid AND "
+                                                                "conindid = i.indexrelid AND "
+                                                                "contype IN ('p','u','x') AND "
+                                                                "condeferrable) AS condeferrable,\n"
+                                                                "  (NOT i.indimmediate) AND "
                                                        "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
-                                                         "WHERE conrelid = i.indrelid AND "
-                                                         "conindid = i.indexrelid AND "
-                                                         "contype IN ('p','u','x') AND "
-                                                         "condeferred) AS condeferred,\n");
+                                                                "WHERE conrelid = i.indrelid AND "
+                                                                "conindid = i.indexrelid AND "
+                                                                "contype IN ('p','u','x') AND "
+                                                                "condeferred) AS condeferred,\n");
                else
-                       appendPQExpBuffer(&buf,
+                       appendPQExpBufferStr(&buf,
                                                "  false AS condeferrable, false AS condeferred,\n");
+
+               if (pset.sversion >= 90400)
+                       appendPQExpBuffer(&buf, "i.indisreplident,\n");
+               else
+                       appendPQExpBuffer(&buf, "false AS indisreplident,\n");
+
                appendPQExpBuffer(&buf, "  a.amname, c2.relname, "
                                          "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
                                                  "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
@@ -1517,7 +1789,7 @@ describeOneTableDetails(const char *schemaname,
                                                  "AND i.indrelid = c2.oid;",
                                                  oid);
 
-               result = PSQLexec(buf.data, false);
+               result = PSQLexec(buf.data);
                if (!result)
                        goto error_return;
                else if (PQntuples(result) != 1)
@@ -1533,9 +1805,10 @@ describeOneTableDetails(const char *schemaname,
                        char       *indisvalid = PQgetvalue(result, 0, 3);
                        char       *deferrable = PQgetvalue(result, 0, 4);
                        char       *deferred = PQgetvalue(result, 0, 5);
-                       char       *indamname = PQgetvalue(result, 0, 6);
-                       char       *indtable = PQgetvalue(result, 0, 7);
-                       char       *indpred = PQgetvalue(result, 0, 8);
+                       char       *indisreplident = PQgetvalue(result, 0, 6);
+                       char       *indamname = PQgetvalue(result, 0, 7);
+                       char       *indtable = PQgetvalue(result, 0, 8);
+                       char       *indpred = PQgetvalue(result, 0, 9);
 
                        if (strcmp(indisprimary, "t") == 0)
                                printfPQExpBuffer(&tmpbuf, _("primary key, "));
@@ -1553,16 +1826,19 @@ describeOneTableDetails(const char *schemaname,
                                appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
 
                        if (strcmp(indisclustered, "t") == 0)
-                               appendPQExpBuffer(&tmpbuf, _(", clustered"));
+                               appendPQExpBufferStr(&tmpbuf, _(", clustered"));
 
                        if (strcmp(indisvalid, "t") != 0)
-                               appendPQExpBuffer(&tmpbuf, _(", invalid"));
+                               appendPQExpBufferStr(&tmpbuf, _(", invalid"));
 
                        if (strcmp(deferrable, "t") == 0)
-                               appendPQExpBuffer(&tmpbuf, _(", deferrable"));
+                               appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
 
                        if (strcmp(deferred, "t") == 0)
-                               appendPQExpBuffer(&tmpbuf, _(", initially deferred"));
+                               appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
+
+                       if (strcmp(indisreplident, "t") == 0)
+                               appendPQExpBuffer(&tmpbuf, _(", replica identity"));
 
                        printTableAddFooter(&cont, tmpbuf.data);
                        add_tablespace_footer(&cont, tableinfo.relkind,
@@ -1571,44 +1847,6 @@ describeOneTableDetails(const char *schemaname,
 
                PQclear(result);
        }
-       else if (view_def)
-       {
-               PGresult   *result = NULL;
-
-               /* Footer information about a view */
-               printTableAddFooter(&cont, _("View definition:"));
-               printTableAddFooter(&cont, view_def);
-
-               /* print rules */
-               if (tableinfo.hasrules)
-               {
-                       printfPQExpBuffer(&buf,
-                                                         "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
-                                                         "FROM pg_catalog.pg_rewrite r\n"
-                       "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1;",
-                                                         oid);
-                       result = PSQLexec(buf.data, false);
-                       if (!result)
-                               goto error_return;
-
-                       if (PQntuples(result) > 0)
-                       {
-                               printTableAddFooter(&cont, _("Rules:"));
-                               for (i = 0; i < PQntuples(result); i++)
-                               {
-                                       const char *ruledef;
-
-                                       /* Everything after "CREATE RULE" is echoed verbatim */
-                                       ruledef = PQgetvalue(result, i, 1);
-                                       ruledef += 12;
-
-                                       printfPQExpBuffer(&buf, " %s", ruledef);
-                                       printTableAddFooter(&cont, buf.data);
-                               }
-                       }
-                       PQclear(result);
-               }
-       }
        else if (tableinfo.relkind == 'S')
        {
                /* Footer information about a sequence */
@@ -1619,18 +1857,18 @@ describeOneTableDetails(const char *schemaname,
                                                  "\n   pg_catalog.quote_ident(relname) || '.' ||"
                                                  "\n   pg_catalog.quote_ident(attname)"
                                                  "\nFROM pg_catalog.pg_class c"
-                                                 "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
-                                                 "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
+                                       "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
+                        "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
                                                  "\nINNER JOIN pg_catalog.pg_attribute a ON ("
                                                  "\n a.attrelid=c.oid AND"
                                                  "\n a.attnum=d.refobjsubid)"
-                                                 "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
-                                                 "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
+                          "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
+                        "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
                                                  "\n AND d.objid=%s"
                                                  "\n AND d.deptype='a'",
                                                  oid);
 
-               result = PSQLexec(buf.data, false);
+               result = PSQLexec(buf.data);
                if (!result)
                        goto error_return;
                else if (PQntuples(result) == 1)
@@ -1639,14 +1877,16 @@ describeOneTableDetails(const char *schemaname,
                                                          PQgetvalue(result, 0, 0));
                        printTableAddFooter(&cont, buf.data);
                }
+
                /*
-                * If we get no rows back, don't show anything (obviously).
-                * We should never get more than one row back, but if we do,
-                * just ignore it and don't print anything.
+                * If we get no rows back, don't show anything (obviously). We should
+                * never get more than one row back, but if we do, just ignore it and
+                * don't print anything.
                 */
                PQclear(result);
        }
-       else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'f')
+       else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
+                        tableinfo.relkind == 'f')
        {
                /* Footer information about a table */
                PGresult   *result = NULL;
@@ -1658,30 +1898,34 @@ describeOneTableDetails(const char *schemaname,
                        printfPQExpBuffer(&buf,
                                                          "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
                        if (pset.sversion >= 80200)
-                               appendPQExpBuffer(&buf, "i.indisvalid, ");
+                               appendPQExpBufferStr(&buf, "i.indisvalid, ");
                        else
-                               appendPQExpBuffer(&buf, "true as indisvalid, ");
-                       appendPQExpBuffer(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n  ");
+                               appendPQExpBufferStr(&buf, "true as indisvalid, ");
+                       appendPQExpBufferStr(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n  ");
                        if (pset.sversion >= 90000)
-                               appendPQExpBuffer(&buf,
+                               appendPQExpBufferStr(&buf,
                                                   "pg_catalog.pg_get_constraintdef(con.oid, true), "
-                                                                 "contype, condeferrable, condeferred");
+                                                                        "contype, condeferrable, condeferred");
                        else
-                               appendPQExpBuffer(&buf,
-                                                                 "null AS constraintdef, null AS contype, "
+                               appendPQExpBufferStr(&buf,
+                                                                  "null AS constraintdef, null AS contype, "
                                                         "false AS condeferrable, false AS condeferred");
+                       if (pset.sversion >= 90400)
+                               appendPQExpBufferStr(&buf, ", i.indisreplident");
+                       else
+                               appendPQExpBufferStr(&buf, ", false AS indisreplident");
                        if (pset.sversion >= 80000)
-                               appendPQExpBuffer(&buf, ", c2.reltablespace");
-                       appendPQExpBuffer(&buf,
-                                                         "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
+                               appendPQExpBufferStr(&buf, ", c2.reltablespace");
+                       appendPQExpBufferStr(&buf,
+                                                                "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
                        if (pset.sversion >= 90000)
-                               appendPQExpBuffer(&buf,
-                                                                 "  LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
+                               appendPQExpBufferStr(&buf,
+                                                                        "  LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
                        appendPQExpBuffer(&buf,
                                                          "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
-                         "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname;",
+                        "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname;",
                                                          oid);
-                       result = PSQLexec(buf.data, false);
+                       result = PSQLexec(buf.data);
                        if (!result)
                                goto error_return;
                        else
@@ -1709,13 +1953,13 @@ describeOneTableDetails(const char *schemaname,
 
                                                /* Label as primary key or unique (but not both) */
                                                if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
-                                                       appendPQExpBuffer(&buf, " PRIMARY KEY,");
+                                                       appendPQExpBufferStr(&buf, " PRIMARY KEY,");
                                                else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
                                                {
                                                        if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
-                                                               appendPQExpBuffer(&buf, " UNIQUE CONSTRAINT,");
+                                                               appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
                                                        else
-                                                               appendPQExpBuffer(&buf, " UNIQUE,");
+                                                               appendPQExpBufferStr(&buf, " UNIQUE,");
                                                }
 
                                                /* Everything after "USING" is echoed verbatim */
@@ -1727,25 +1971,28 @@ describeOneTableDetails(const char *schemaname,
 
                                                /* Need these for deferrable PK/UNIQUE indexes */
                                                if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
-                                                       appendPQExpBuffer(&buf, " DEFERRABLE");
+                                                       appendPQExpBufferStr(&buf, " DEFERRABLE");
 
                                                if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
-                                                       appendPQExpBuffer(&buf, " INITIALLY DEFERRED");
+                                                       appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
                                        }
 
                                        /* Add these for all cases */
                                        if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
-                                               appendPQExpBuffer(&buf, " CLUSTER");
+                                               appendPQExpBufferStr(&buf, " CLUSTER");
 
                                        if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
-                                               appendPQExpBuffer(&buf, " INVALID");
+                                               appendPQExpBufferStr(&buf, " INVALID");
+
+                                       if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
+                                               appendPQExpBuffer(&buf, " REPLICA IDENTITY");
 
                                        printTableAddFooter(&cont, buf.data);
 
                                        /* Print tablespace of the index on the same line */
                                        if (pset.sversion >= 80000)
                                                add_tablespace_footer(&cont, 'i',
-                                                                                  atooid(PQgetvalue(result, i, 10)),
+                                                                                  atooid(PQgetvalue(result, i, 11)),
                                                                                          false);
                                }
                        }
@@ -1759,9 +2006,10 @@ describeOneTableDetails(const char *schemaname,
                                                          "SELECT r.conname, "
                                                          "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
                                                          "FROM pg_catalog.pg_constraint r\n"
-                                  "WHERE r.conrelid = '%s' AND r.contype = 'c'\nORDER BY 1;",
+                                                         "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
+                                                         "ORDER BY 1;",
                                                          oid);
-                       result = PSQLexec(buf.data, false);
+                       result = PSQLexec(buf.data);
                        if (!result)
                                goto error_return;
                        else
@@ -1790,9 +2038,9 @@ describeOneTableDetails(const char *schemaname,
                                                          "SELECT conname,\n"
                                 "  pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n"
                                                          "FROM pg_catalog.pg_constraint r\n"
-                                       "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1;",
+                                  "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1;",
                                                          oid);
-                       result = PSQLexec(buf.data, false);
+                       result = PSQLexec(buf.data);
                        if (!result)
                                goto error_return;
                        else
@@ -1821,9 +2069,9 @@ describeOneTableDetails(const char *schemaname,
                                                   "SELECT conname, conrelid::pg_catalog.regclass,\n"
                                 "  pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
                                                          "FROM pg_catalog.pg_constraint c\n"
-                                  "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1;",
+                                 "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1;",
                                                          oid);
-                       result = PSQLexec(buf.data, false);
+                       result = PSQLexec(buf.data);
                        if (!result)
                                goto error_return;
                        else
@@ -1845,8 +2093,83 @@ describeOneTableDetails(const char *schemaname,
                        PQclear(result);
                }
 
+               /* print any row-level policies */
+               if (pset.sversion >= 90500)
+               {
+                       printfPQExpBuffer(&buf,
+                                                         "SELECT pol.polname,\n"
+                                                         "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
+                                          "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
+                                 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
+                                                         "CASE pol.polcmd \n"
+                                                         "WHEN 'r' THEN 'SELECT'\n"
+                                                         "WHEN 'a' THEN 'INSERT'\n"
+                                                         "WHEN 'w' THEN 'UPDATE'\n"
+                                                         "WHEN 'd' THEN 'DELETE'\n"
+                                                         "WHEN '*' THEN 'ALL'\n"
+                                                         "END AS cmd\n"
+                                                         "FROM pg_catalog.pg_policy pol\n"
+                                                         "WHERE pol.polrelid = '%s' ORDER BY 1;",
+                                                         oid);
+
+                       result = PSQLexec(buf.data);
+                       if (!result)
+                               goto error_return;
+                       else
+                               tuples = PQntuples(result);
+
+                       /*
+                        * Handle cases where RLS is enabled and there are policies, or
+                        * there aren't policies, or RLS isn't enabled but there are
+                        * policies
+                        */
+                       if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
+                               printTableAddFooter(&cont, _("Policies:"));
+
+                       if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
+                               printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
+
+                       if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
+                               printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
+
+                       if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
+                               printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
+
+                       if (!tableinfo.rowsecurity && tuples > 0)
+                               printTableAddFooter(&cont, _("Policies (row security disabled):"));
+
+                       /* Might be an empty set - that's ok */
+                       for (i = 0; i < tuples; i++)
+                       {
+                               printfPQExpBuffer(&buf, "    POLICY \"%s\"",
+                                                                 PQgetvalue(result, i, 0));
+
+                               if (!PQgetisnull(result, i, 4))
+                                       appendPQExpBuffer(&buf, " FOR %s",
+                                                                         PQgetvalue(result, i, 4));
+
+                               if (!PQgetisnull(result, i, 1))
+                               {
+                                       appendPQExpBuffer(&buf, "\n      TO %s",
+                                                                         PQgetvalue(result, i, 1));
+                               }
+
+                               if (!PQgetisnull(result, i, 2))
+                                       appendPQExpBuffer(&buf, "\n      USING (%s)",
+                                                                         PQgetvalue(result, i, 2));
+
+                               if (!PQgetisnull(result, i, 3))
+                                       appendPQExpBuffer(&buf, "\n      WITH CHECK (%s)",
+                                                                         PQgetvalue(result, i, 3));
+
+                               printTableAddFooter(&cont, buf.data);
+
+                       }
+                       PQclear(result);
+               }
+
                /* print rules */
-               if (tableinfo.hasrules)
+               if (tableinfo.hasrules && tableinfo.relkind != 'm')
                {
                        if (pset.sversion >= 80300)
                        {
@@ -1866,7 +2189,7 @@ describeOneTableDetails(const char *schemaname,
                                                                  "WHERE r.ev_class = '%s' ORDER BY 1;",
                                                                  oid);
                        }
-                       result = PSQLexec(buf.data, false);
+                       result = PSQLexec(buf.data);
                        if (!result)
                                goto error_return;
                        else
@@ -1941,6 +2264,45 @@ describeOneTableDetails(const char *schemaname,
                }
        }
 
+       if (view_def)
+       {
+               PGresult   *result = NULL;
+
+               /* Footer information about a view */
+               printTableAddFooter(&cont, _("View definition:"));
+               printTableAddFooter(&cont, view_def);
+
+               /* print rules */
+               if (tableinfo.hasrules)
+               {
+                       printfPQExpBuffer(&buf,
+                                                         "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
+                                                         "FROM pg_catalog.pg_rewrite r\n"
+                       "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1;",
+                                                         oid);
+                       result = PSQLexec(buf.data);
+                       if (!result)
+                               goto error_return;
+
+                       if (PQntuples(result) > 0)
+                       {
+                               printTableAddFooter(&cont, _("Rules:"));
+                               for (i = 0; i < PQntuples(result); i++)
+                               {
+                                       const char *ruledef;
+
+                                       /* Everything after "CREATE RULE" is echoed verbatim */
+                                       ruledef = PQgetvalue(result, i, 1);
+                                       ruledef += 12;
+
+                                       printfPQExpBuffer(&buf, " %s", ruledef);
+                                       printTableAddFooter(&cont, buf.data);
+                               }
+                       }
+                       PQclear(result);
+               }
+       }
+
        /*
         * Print triggers next, if any (but only user-defined triggers).  This
         * could apply to either a table or a view.
@@ -1953,25 +2315,29 @@ describeOneTableDetails(const char *schemaname,
                printfPQExpBuffer(&buf,
                                                  "SELECT t.tgname, "
                                                  "pg_catalog.pg_get_triggerdef(t.oid%s), "
-                                                 "t.tgenabled\n"
+                                                 "t.tgenabled, %s\n"
                                                  "FROM pg_catalog.pg_trigger t\n"
                                                  "WHERE t.tgrelid = '%s' AND ",
                                                  (pset.sversion >= 90000 ? ", true" : ""),
-                                                 oid);
+                                                 (pset.sversion >= 90000 ? "t.tgisinternal" :
+                                                  pset.sversion >= 80300 ?
+                                                  "t.tgconstraint <> 0 AS tgisinternal" :
+                                                  "false AS tgisinternal"), oid);
                if (pset.sversion >= 90000)
-                       appendPQExpBuffer(&buf, "NOT t.tgisinternal");
+                       /* display/warn about disabled internal triggers */
+                       appendPQExpBuffer(&buf, "(NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))");
                else if (pset.sversion >= 80300)
-                       appendPQExpBuffer(&buf, "t.tgconstraint = 0");
+                       appendPQExpBufferStr(&buf, "(t.tgconstraint = 0 OR (t.tgconstraint <> 0 AND t.tgenabled = 'D'))");
                else
-                       appendPQExpBuffer(&buf,
-                                                         "(NOT tgisconstraint "
-                                                         " OR NOT EXISTS"
-                                                         "  (SELECT 1 FROM pg_catalog.pg_depend d "
-                                                         "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
-                                                         "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
-               appendPQExpBuffer(&buf, "\nORDER BY 1;");
-
-               result = PSQLexec(buf.data, false);
+                       appendPQExpBufferStr(&buf,
+                                                                "(NOT tgisconstraint "
+                                                                " OR NOT EXISTS"
+                                                                "  (SELECT 1 FROM pg_catalog.pg_depend d "
+                                                                "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
+                                                                "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
+               appendPQExpBufferStr(&buf, "\nORDER BY 1;");
+
+               result = PSQLexec(buf.data);
                if (!result)
                        goto error_return;
                else
@@ -1987,7 +2353,7 @@ describeOneTableDetails(const char *schemaname,
                         * disabled triggers and the two special ALWAYS and REPLICA
                         * configurations.
                         */
-                       for (category = 0; category < 4; category++)
+                       for (category = 0; category <= 4; category++)
                        {
                                have_heading = false;
                                for (i = 0; i < tuples; i++)
@@ -1996,11 +2362,13 @@ describeOneTableDetails(const char *schemaname,
                                        const char *tgdef;
                                        const char *usingpos;
                                        const char *tgenabled;
+                                       const char *tgisinternal;
 
                                        /*
                                         * Check if this trigger falls into the current category
                                         */
                                        tgenabled = PQgetvalue(result, i, 2);
+                                       tgisinternal = PQgetvalue(result, i, 3);
                                        list_trigger = false;
                                        switch (category)
                                        {
@@ -2009,14 +2377,20 @@ describeOneTableDetails(const char *schemaname,
                                                                list_trigger = true;
                                                        break;
                                                case 1:
-                                                       if (*tgenabled == 'D' || *tgenabled == 'f')
+                                                       if ((*tgenabled == 'D' || *tgenabled == 'f') &&
+                                                               *tgisinternal == 'f')
                                                                list_trigger = true;
                                                        break;
                                                case 2:
-                                                       if (*tgenabled == 'A')
+                                                       if ((*tgenabled == 'D' || *tgenabled == 'f') &&
+                                                               *tgisinternal == 't')
                                                                list_trigger = true;
                                                        break;
                                                case 3:
+                                                       if (*tgenabled == 'A')
+                                                               list_trigger = true;
+                                                       break;
+                                               case 4:
                                                        if (*tgenabled == 'R')
                                                                list_trigger = true;
                                                        break;
@@ -2033,12 +2407,18 @@ describeOneTableDetails(const char *schemaname,
                                                                printfPQExpBuffer(&buf, _("Triggers:"));
                                                                break;
                                                        case 1:
-                                                               printfPQExpBuffer(&buf, _("Disabled triggers:"));
+                                                               if (pset.sversion >= 80300)
+                                                                       printfPQExpBuffer(&buf, _("Disabled user triggers:"));
+                                                               else
+                                                                       printfPQExpBuffer(&buf, _("Disabled triggers:"));
                                                                break;
                                                        case 2:
-                                                               printfPQExpBuffer(&buf, _("Triggers firing always:"));
+                                                               printfPQExpBuffer(&buf, _("Disabled internal triggers:"));
                                                                break;
                                                        case 3:
+                                                               printfPQExpBuffer(&buf, _("Triggers firing always:"));
+                                                               break;
+                                                       case 4:
                                                                printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
                                                                break;
 
@@ -2064,7 +2444,8 @@ describeOneTableDetails(const char *schemaname,
        /*
         * Finish printing the footer information about a table.
         */
-       if (tableinfo.relkind == 'r' || tableinfo.relkind == 'f')
+       if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
+               tableinfo.relkind == 'f')
        {
                PGresult   *result;
                int                     tuples;
@@ -2072,7 +2453,7 @@ describeOneTableDetails(const char *schemaname,
                /* print foreign server name */
                if (tableinfo.relkind == 'f')
                {
-                       char *ftoptions;
+                       char       *ftoptions;
 
                        /* Footer information about foreign table */
                        printfPQExpBuffer(&buf,
@@ -2080,12 +2461,12 @@ describeOneTableDetails(const char *schemaname,
                                                          "       array_to_string(ARRAY(SELECT "
                                                          "       quote_ident(option_name) ||  ' ' || "
                                                          "       quote_literal(option_value)  FROM "
-                                                         "       pg_options_to_table(ftoptions)),  ', ') "
+                                                       "       pg_options_to_table(ftoptions)),  ', ') "
                                                          "FROM pg_catalog.pg_foreign_table f,\n"
                                                          "     pg_catalog.pg_foreign_server s\n"
                                                          "WHERE f.ftrelid = %s AND s.oid = f.ftserver;",
                                                          oid);
-                       result = PSQLexec(buf.data, false);
+                       result = PSQLexec(buf.data);
                        if (!result)
                                goto error_return;
                        else if (PQntuples(result) != 1)
@@ -2112,26 +2493,32 @@ describeOneTableDetails(const char *schemaname,
                /* print inherited tables */
                printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhparent AND i.inhrelid = '%s' ORDER BY inhseqno;", oid);
 
-               result = PSQLexec(buf.data, false);
+               result = PSQLexec(buf.data);
                if (!result)
                        goto error_return;
                else
-                       tuples = PQntuples(result);
-
-               for (i = 0; i < tuples; i++)
                {
                        const char *s = _("Inherits");
+                       int                     sw = pg_wcswidth(s, strlen(s), pset.encoding);
 
-                       if (i == 0)
-                               printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result, i, 0));
-                       else
-                               printfPQExpBuffer(&buf, "%*s  %s", (int) strlen(s), "", PQgetvalue(result, i, 0));
-                       if (i < tuples - 1)
-                               appendPQExpBuffer(&buf, ",");
+                       tuples = PQntuples(result);
 
-                       printTableAddFooter(&cont, buf.data);
+                       for (i = 0; i < tuples; i++)
+                       {
+                               if (i == 0)
+                                       printfPQExpBuffer(&buf, "%s: %s",
+                                                                         s, PQgetvalue(result, i, 0));
+                               else
+                                       printfPQExpBuffer(&buf, "%*s  %s",
+                                                                         sw, "", PQgetvalue(result, i, 0));
+                               if (i < tuples - 1)
+                                       appendPQExpBufferChar(&buf, ',');
+
+                               printTableAddFooter(&cont, buf.data);
+                       }
+
+                       PQclear(result);
                }
-               PQclear(result);
 
                /* print child tables */
                if (pset.sversion >= 80300)
@@ -2139,7 +2526,7 @@ describeOneTableDetails(const char *schemaname,
                else
                        printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.relname;", oid);
 
-               result = PSQLexec(buf.data, false);
+               result = PSQLexec(buf.data);
                if (!result)
                        goto error_return;
                else
@@ -2158,6 +2545,7 @@ describeOneTableDetails(const char *schemaname,
                {
                        /* display the list of child tables */
                        const char *ct = _("Child tables");
+                       int                     ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
 
                        for (i = 0; i < tuples; i++)
                        {
@@ -2166,10 +2554,9 @@ describeOneTableDetails(const char *schemaname,
                                                                          ct, PQgetvalue(result, i, 0));
                                else
                                        printfPQExpBuffer(&buf, "%*s  %s",
-                                                                         (int) strlen(ct), "",
-                                                                         PQgetvalue(result, i, 0));
+                                                                         ctw, "", PQgetvalue(result, i, 0));
                                if (i < tuples - 1)
-                                       appendPQExpBuffer(&buf, ",");
+                                       appendPQExpBufferChar(&buf, ',');
 
                                printTableAddFooter(&cont, buf.data);
                        }
@@ -2183,35 +2570,47 @@ describeOneTableDetails(const char *schemaname,
                        printTableAddFooter(&cont, buf.data);
                }
 
-               /* OIDs and options */
-               if (verbose)
-               {
-                       const char *s = _("Has OIDs");
+               if (verbose && (tableinfo.relkind == 'r' || tableinfo.relkind == 'm') &&
 
-                       printfPQExpBuffer(&buf, "%s: %s", s,
-                                                         (tableinfo.hasoids ? _("yes") : _("no")));
-                       printTableAddFooter(&cont, buf.data);
+               /*
+                * No need to display default values;  we already display a REPLICA
+                * IDENTITY marker on indexes.
+                */
+                       tableinfo.relreplident != 'i' &&
+                       ((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
+                        (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
+               {
+                       const char *s = _("Replica Identity");
 
-                       /* print reloptions */
-                       if (pset.sversion >= 80200)
-                       {
-                               if (tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
-                               {
-                                       const char *t = _("Options");
+                       printfPQExpBuffer(&buf, "%s: %s",
+                                                         s,
+                                                         tableinfo.relreplident == 'f' ? "FULL" :
+                                                         tableinfo.relreplident == 'n' ? "NOTHING" :
+                                                         "???");
 
-                                       printfPQExpBuffer(&buf, "%s: %s", t,
-                                                                         tableinfo.reloptions);
-                                       printTableAddFooter(&cont, buf.data);
-                               }
-                       }
+                       printTableAddFooter(&cont, buf.data);
                }
 
+               /* OIDs, if verbose and not a materialized view */
+               if (verbose && tableinfo.relkind != 'm' && tableinfo.hasoids)
+                       printTableAddFooter(&cont, _("Has OIDs: yes"));
+
+               /* Tablespace info */
                add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
                                                          true);
        }
 
-       printTable(&cont, pset.queryFout, pset.logfile);
-       printTableCleanup(&cont);
+       /* reloptions, if verbose */
+       if (verbose &&
+               tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
+       {
+               const char *t = _("Options");
+
+               printfPQExpBuffer(&buf, "%s: %s", t, tableinfo.reloptions);
+               printTableAddFooter(&cont, buf.data);
+       }
+
+       printTable(&cont, pset.queryFout, false, pset.logfile);
 
        retval = true;
 
@@ -2257,7 +2656,7 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
                                          Oid tablespace, const bool newline)
 {
        /* relkinds for which we support tablespaces */
-       if (relkind == 'r' || relkind == 'i')
+       if (relkind == 'r' || relkind == 'm' || relkind == 'i')
        {
                /*
                 * We ignore the database default tablespace so that users not using
@@ -2273,7 +2672,7 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
                        printfPQExpBuffer(&buf,
                                                          "SELECT spcname FROM pg_catalog.pg_tablespace\n"
                                                          "WHERE oid = '%u';", tablespace);
-                       result = PSQLexec(buf.data, false);
+                       result = PSQLexec(buf.data);
                        if (!result)
                                return;
                        /* Should always be the case, but.... */
@@ -2291,10 +2690,9 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
                                        /* Append the tablespace to the latest footer */
                                        printfPQExpBuffer(&buf, "%s", cont->footer->data);
 
-                                       /*
-                                        * translator: before this string there's an index
-                                        * description like '"foo_pkey" PRIMARY KEY, btree (a)'
-                                        */
+                                       /*-------
+                                          translator: before this string there's an index description like
+                                          '"foo_pkey" PRIMARY KEY, btree (a)' */
                                        appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
                                                                          PQgetvalue(result, 0, 0));
                                        printTableSetFooter(cont, buf.data);
@@ -2312,7 +2710,7 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
  * Describes roles.  Any schema portion of the pattern is ignored.
  */
 bool
-describeRoles(const char *pattern, bool verbose)
+describeRoles(const char *pattern, bool verbose, bool showSystem)
 {
        PQExpBufferData buf;
        PGresult   *res;
@@ -2325,6 +2723,8 @@ describeRoles(const char *pattern, bool verbose)
        const char      align = 'l';
        char      **attr;
 
+       myopt.default_footer = false;
+
        initPQExpBuffer(&buf);
 
        if (pset.sversion >= 80100)
@@ -2332,7 +2732,7 @@ describeRoles(const char *pattern, bool verbose)
                printfPQExpBuffer(&buf,
                                                  "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
                                                  "  r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
-                                                 "  r.rolconnlimit,\n"
+                                                 "  r.rolconnlimit, r.rolvaliduntil,\n"
                                                  "  ARRAY(SELECT b.rolname\n"
                                                  "        FROM pg_catalog.pg_auth_members m\n"
                                 "        JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
@@ -2348,8 +2748,16 @@ describeRoles(const char *pattern, bool verbose)
                        appendPQExpBufferStr(&buf, "\n, r.rolreplication");
                }
 
+               if (pset.sversion >= 90500)
+               {
+                       appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
+               }
+
                appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
 
+               if (!showSystem && !pattern)
+                       appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
+
                processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                          NULL, "r.rolname", NULL, NULL);
        }
@@ -2360,7 +2768,8 @@ describeRoles(const char *pattern, bool verbose)
                                                  "  u.usesuper AS rolsuper,\n"
                                                  "  true AS rolinherit, false AS rolcreaterole,\n"
                                         "  u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
-                                                 "  -1 AS rolconnlimit,\n"
+                                                 "  -1 AS rolconnlimit,"
+                                                 "  u.valuntil as rolvaliduntil,\n"
                                                  "  ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
                                                  "\nFROM pg_catalog.pg_user u\n");
 
@@ -2368,14 +2777,14 @@ describeRoles(const char *pattern, bool verbose)
                                                          NULL, "u.usename", NULL, NULL);
        }
 
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        if (!res)
                return false;
 
        nrows = PQntuples(res);
-       attr = pg_malloc_zero((nrows + 1) * sizeof(*attr));
+       attr = pg_malloc0((nrows + 1) * sizeof(*attr));
 
        printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
 
@@ -2407,17 +2816,21 @@ describeRoles(const char *pattern, bool verbose)
                        add_role_attribute(&buf, _("Cannot login"));
 
                if (pset.sversion >= 90100)
-                       if (strcmp(PQgetvalue(res, i, (verbose ? 9 : 8)), "t") == 0)
+                       if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
                                add_role_attribute(&buf, _("Replication"));
 
+               if (pset.sversion >= 90500)
+                       if (strcmp(PQgetvalue(res, i, (verbose ? 11 : 10)), "t") == 0)
+                               add_role_attribute(&buf, _("Bypass RLS"));
+
                conns = atoi(PQgetvalue(res, i, 6));
                if (conns >= 0)
                {
                        if (buf.len > 0)
-                               appendPQExpBufferStr(&buf, "\n");
+                               appendPQExpBufferChar(&buf, '\n');
 
                        if (conns == 0)
-                               appendPQExpBuffer(&buf, _("No connections"));
+                               appendPQExpBufferStr(&buf, _("No connections"));
                        else
                                appendPQExpBuffer(&buf, ngettext("%d connection",
                                                                                                 "%d connections",
@@ -2425,18 +2838,26 @@ describeRoles(const char *pattern, bool verbose)
                                                                  conns);
                }
 
+               if (strcmp(PQgetvalue(res, i, 7), "") != 0)
+               {
+                       if (buf.len > 0)
+                               appendPQExpBufferStr(&buf, "\n");
+                       appendPQExpBufferStr(&buf, _("Password valid until "));
+                       appendPQExpBufferStr(&buf, PQgetvalue(res, i, 7));
+               }
+
                attr[i] = pg_strdup(buf.data);
 
                printTableAddCell(&cont, attr[i], false, false);
 
-               printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
+               printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
 
                if (verbose && pset.sversion >= 80200)
-                       printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
+                       printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
        }
        termPQExpBuffer(&buf);
 
-       printTable(&cont, pset.queryFout, pset.logfile);
+       printTable(&cont, pset.queryFout, false, pset.logfile);
        printTableCleanup(&cont);
 
        for (i = 0; i < nrows; i++)
@@ -2472,16 +2893,19 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
        {
                bool            havewhere;
 
-               printfPQExpBuffer(&buf, "SELECT rolname AS role, datname AS database,\n"
-                               "pg_catalog.array_to_string(setconfig, E'\\n') AS settings\n"
+               printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
+                                 "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
                                                  "FROM pg_db_role_setting AS s\n"
                                   "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n"
-                                                 "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n");
+                                                 "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n",
+                                                 gettext_noop("Role"),
+                                                 gettext_noop("Database"),
+                                                 gettext_noop("Settings"));
                havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                                           NULL, "pg_roles.rolname", NULL, NULL);
                processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
                                                          NULL, "pg_database.datname", NULL, NULL);
-               appendPQExpBufferStr(&buf, "ORDER BY role, database;");
+               appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
        }
        else
        {
@@ -2490,7 +2914,7 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
                return false;
        }
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        if (!res)
                return false;
 
@@ -2507,7 +2931,7 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
                myopt.title = _("List of settings");
                myopt.translate_header = true;
 
-               printQuery(res, &myopt, pset.queryFout, pset.logfile);
+               printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
        }
 
        PQclear(res);
@@ -2525,6 +2949,7 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
  * t - tables
  * i - indexes
  * v - views
+ * m - materialized views
  * s - sequences
  * E - foreign table (Note: different from 'f', the relkind value)
  * (any order of the above is fine)
@@ -2536,6 +2961,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
        bool            showTables = strchr(tabtypes, 't') != NULL;
        bool            showIndexes = strchr(tabtypes, 'i') != NULL;
        bool            showViews = strchr(tabtypes, 'v') != NULL;
+       bool            showMatViews = strchr(tabtypes, 'm') != NULL;
        bool            showSeq = strchr(tabtypes, 's') != NULL;
        bool            showForeign = strchr(tabtypes, 'E') != NULL;
 
@@ -2544,8 +2970,8 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
        printQueryOpt myopt = pset.popt;
        static const bool translate_columns[] = {false, false, true, false, false, false, false};
 
-       if (!(showTables || showIndexes || showViews || showSeq || showForeign))
-               showTables = showViews = showSeq = showForeign = true;
+       if (!(showTables || showIndexes || showViews || showMatViews || showSeq || showForeign))
+               showTables = showViews = showMatViews = showSeq = showForeign = true;
 
        initPQExpBuffer(&buf);
 
@@ -2556,12 +2982,21 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
        printfPQExpBuffer(&buf,
                                          "SELECT n.nspname as \"%s\",\n"
                                          "  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' WHEN 'f' THEN '%s' END as \"%s\",\n"
+                                         "  CASE c.relkind"
+                                         " WHEN 'r' THEN '%s'"
+                                         " WHEN 'v' THEN '%s'"
+                                         " WHEN 'm' THEN '%s'"
+                                         " WHEN 'i' THEN '%s'"
+                                         " WHEN 'S' THEN '%s'"
+                                         " WHEN 's' THEN '%s'"
+                                         " WHEN 'f' THEN '%s'"
+                                         " END as \"%s\",\n"
                                          "  pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
                                          gettext_noop("Schema"),
                                          gettext_noop("Name"),
                                          gettext_noop("table"),
                                          gettext_noop("view"),
+                                         gettext_noop("materialized view"),
                                          gettext_noop("index"),
                                          gettext_noop("sequence"),
                                          gettext_noop("special"),
@@ -2594,35 +3029,37 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
                                                  gettext_noop("Description"));
        }
 
-       appendPQExpBuffer(&buf,
-                                         "\nFROM pg_catalog.pg_class c"
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_class c"
         "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
        if (showIndexes)
-               appendPQExpBuffer(&buf,
+               appendPQExpBufferStr(&buf,
                         "\n     LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
                   "\n     LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
 
-       appendPQExpBuffer(&buf, "\nWHERE c.relkind IN (");
+       appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
        if (showTables)
-               appendPQExpBuffer(&buf, "'r',");
+               appendPQExpBufferStr(&buf, "'r',");
        if (showViews)
-               appendPQExpBuffer(&buf, "'v',");
+               appendPQExpBufferStr(&buf, "'v',");
+       if (showMatViews)
+               appendPQExpBufferStr(&buf, "'m',");
        if (showIndexes)
-               appendPQExpBuffer(&buf, "'i',");
+               appendPQExpBufferStr(&buf, "'i',");
        if (showSeq)
-               appendPQExpBuffer(&buf, "'S',");
+               appendPQExpBufferStr(&buf, "'S',");
        if (showSystem || pattern)
-               appendPQExpBuffer(&buf, "'s',");                /* was RELKIND_SPECIAL in <=
+               appendPQExpBufferStr(&buf, "'s',");             /* was RELKIND_SPECIAL in <=
                                                                                                 * 8.1 */
        if (showForeign)
-               appendPQExpBuffer(&buf, "'f',");
+               appendPQExpBufferStr(&buf, "'f',");
 
-       appendPQExpBuffer(&buf, "''");          /* dummy */
-       appendPQExpBuffer(&buf, ")\n");
+       appendPQExpBufferStr(&buf, "''");       /* dummy */
+       appendPQExpBufferStr(&buf, ")\n");
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        /*
         * TOAST objects are suppressed unconditionally.  Since we don't provide
@@ -2630,15 +3067,15 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
         * in any case; it seems a bit confusing to allow their indexes to be
         * shown. Use plain \d if you really need to look at a TOAST table/index.
         */
-       appendPQExpBuffer(&buf, "      AND n.nspname !~ '^pg_toast'\n");
+       appendPQExpBufferStr(&buf, "      AND n.nspname !~ '^pg_toast'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                  "n.nspname", "c.relname", NULL,
                                                  "pg_catalog.pg_table_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1,2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -2656,8 +3093,9 @@ 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);
+               printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
        }
 
        PQclear(res);
@@ -2719,12 +3157,12 @@ listLanguages(const char *pattern, bool verbose, bool showSystem)
                                                          NULL, "l.lanname", NULL, NULL);
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "WHERE l.lanplcallfoid != 0\n");
+               appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n");
 
 
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -2733,7 +3171,7 @@ listLanguages(const char *pattern, bool verbose, bool showSystem)
        myopt.title = _("List of languages");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -2764,9 +3202,9 @@ listDomains(const char *pattern, bool verbose, bool showSystem)
                                          gettext_noop("Type"));
 
        if (pset.sversion >= 90100)
-               appendPQExpBuffer(&buf,
-                                                 "            COALESCE((SELECT ' collate ' || c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
-                                                 "                      WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation), '') ||\n");
+               appendPQExpBufferStr(&buf,
+                                                        "            COALESCE((SELECT ' collate ' || c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
+                                                        "                      WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation), '') ||\n");
        appendPQExpBuffer(&buf,
           "            CASE WHEN t.typnotnull THEN ' not null' ELSE '' END ||\n"
                                          "            CASE WHEN t.typdefault IS NOT NULL THEN ' default ' || t.typdefault ELSE '' END\n"
@@ -2778,33 +3216,40 @@ listDomains(const char *pattern, bool verbose, bool showSystem)
                                          gettext_noop("Check"));
 
        if (verbose)
+       {
+               if (pset.sversion >= 90200)
+               {
+                       appendPQExpBufferStr(&buf, ",\n  ");
+                       printACLColumn(&buf, "t.typacl");
+               }
                appendPQExpBuffer(&buf,
                                                  ",\n       d.description as \"%s\"",
                                                  gettext_noop("Description"));
+       }
 
-       appendPQExpBuffer(&buf,
-                                         "\nFROM pg_catalog.pg_type t\n"
-          "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_type t\n"
+        "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
 
        if (verbose)
-               appendPQExpBuffer(&buf,
-                                                 "     LEFT JOIN pg_catalog.pg_description d "
-                                                 "ON d.classoid = t.tableoid AND d.objoid = t.oid "
-                                                 "AND d.objsubid = 0\n");
+               appendPQExpBufferStr(&buf,
+                                                        "     LEFT JOIN pg_catalog.pg_description d "
+                                                  "ON d.classoid = t.tableoid AND d.objoid = t.oid "
+                                                        "AND d.objsubid = 0\n");
 
-       appendPQExpBuffer(&buf, "WHERE t.typtype = 'd'\n");
+       appendPQExpBufferStr(&buf, "WHERE t.typtype = 'd'\n");
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                  "n.nspname", "t.typname", NULL,
                                                  "pg_catalog.pg_type_is_visible(t.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -2813,7 +3258,7 @@ listDomains(const char *pattern, bool verbose, bool showSystem)
        myopt.title = _("List of domains");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -2830,7 +3275,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);
 
@@ -2853,31 +3299,31 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
                                                  ",\n       d.description AS \"%s\"",
                                                  gettext_noop("Description"));
 
-       appendPQExpBuffer(&buf,
-                                         "\nFROM pg_catalog.pg_conversion c\n"
-                                         "     JOIN pg_catalog.pg_namespace n "
-                                         "ON n.oid = c.connamespace\n");
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_conversion c\n"
+                                                "     JOIN pg_catalog.pg_namespace n "
+                                                "ON n.oid = c.connamespace\n");
 
        if (verbose)
-               appendPQExpBuffer(&buf,
-                                                 "LEFT JOIN pg_catalog.pg_description d "
-                                                 "ON d.classoid = c.tableoid\n"
-                                                 "          AND d.objoid = c.oid "
-                                                 "AND d.objsubid = 0\n");
+               appendPQExpBufferStr(&buf,
+                                                        "LEFT JOIN pg_catalog.pg_description d "
+                                                        "ON d.classoid = c.tableoid\n"
+                                                        "          AND d.objoid = c.oid "
+                                                        "AND d.objsubid = 0\n");
 
-       appendPQExpBuffer(&buf, "WHERE true\n");
+       appendPQExpBufferStr(&buf, "WHERE true\n");
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "  AND n.nspname <> 'pg_catalog'\n"
-                                                 "  AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "  AND n.nspname <> 'pg_catalog'\n"
+                                                        "  AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                  "n.nspname", "c.conname", NULL,
                                                  "pg_catalog.pg_conversion_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -2886,8 +3332,75 @@ 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, false, pset.logfile);
+
+       PQclear(res);
+       return true;
+}
+
+/*
+ * \dy
+ *
+ * Describes Event Triggers.
+ */
+bool
+listEventTriggers(const char *pattern, bool verbose)
+{
+       PQExpBufferData buf;
+       PGresult   *res;
+       printQueryOpt myopt = pset.popt;
+       static const bool translate_columns[] =
+       {false, false, false, true, false, false, false};
+
+       initPQExpBuffer(&buf);
+
+       printfPQExpBuffer(&buf,
+                                         "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"));
+       if (verbose)
+               appendPQExpBuffer(&buf,
+               ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
+                                                 gettext_noop("Description"));
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_event_trigger e ");
+
+       processSQLNamePattern(pset.db, &buf, pattern, false, false,
+                                                 NULL, "evtname", NULL, NULL);
+
+       appendPQExpBufferStr(&buf, "ORDER BY 1");
+
+       res = PSQLexec(buf.data);
+       termPQExpBuffer(&buf);
+       if (!res)
+               return false;
+
+       myopt.nullPrint = NULL;
+       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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -2904,7 +3417,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);
 
@@ -2937,25 +3450,25 @@ listCasts(const char *pattern, bool verbose)
                                                  ",\n       d.description AS \"%s\"\n",
                                                  gettext_noop("Description"));
 
-       appendPQExpBuffer(&buf,
+       appendPQExpBufferStr(&buf,
                                 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
-                                         "     ON c.castfunc = p.oid\n"
-                                         "     LEFT JOIN pg_catalog.pg_type ts\n"
-                                         "     ON c.castsource = ts.oid\n"
-                                         "     LEFT JOIN pg_catalog.pg_namespace ns\n"
-                                         "     ON ns.oid = ts.typnamespace\n"
-                                         "     LEFT JOIN pg_catalog.pg_type tt\n"
-                                         "     ON c.casttarget = tt.oid\n"
-                                         "     LEFT JOIN pg_catalog.pg_namespace nt\n"
-                                         "     ON nt.oid = tt.typnamespace\n");
+                                                "     ON c.castfunc = p.oid\n"
+                                                "     LEFT JOIN pg_catalog.pg_type ts\n"
+                                                "     ON c.castsource = ts.oid\n"
+                                                "     LEFT JOIN pg_catalog.pg_namespace ns\n"
+                                                "     ON ns.oid = ts.typnamespace\n"
+                                                "     LEFT JOIN pg_catalog.pg_type tt\n"
+                                                "     ON c.casttarget = tt.oid\n"
+                                                "     LEFT JOIN pg_catalog.pg_namespace nt\n"
+                                                "     ON nt.oid = tt.typnamespace\n");
 
        if (verbose)
-               appendPQExpBuffer(&buf,
-                                                 "     LEFT JOIN pg_catalog.pg_description d\n"
-                                                 "     ON d.classoid = c.tableoid AND d.objoid = "
-                                                 "c.oid AND d.objsubid = 0\n");
+               appendPQExpBufferStr(&buf,
+                                                        "     LEFT JOIN pg_catalog.pg_description d\n"
+                                                        "     ON d.classoid = c.tableoid AND d.objoid = "
+                                                        "c.oid AND d.objsubid = 0\n");
 
-       appendPQExpBuffer(&buf, "WHERE ( (true");
+       appendPQExpBufferStr(&buf, "WHERE ( (true");
 
        /*
         * Match name pattern against either internal or external name of either
@@ -2966,16 +3479,16 @@ listCasts(const char *pattern, bool verbose)
                                                  "pg_catalog.format_type(ts.oid, NULL)",
                                                  "pg_catalog.pg_type_is_visible(ts.oid)");
 
-       appendPQExpBuffer(&buf, ") OR (true");
+       appendPQExpBufferStr(&buf, ") OR (true");
 
        processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                  "nt.nspname", "tt.typname",
                                                  "pg_catalog.format_type(tt.oid, NULL)",
                                                  "pg_catalog.pg_type_is_visible(tt.oid)");
 
-       appendPQExpBuffer(&buf, ") )\nORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -2984,8 +3497,9 @@ 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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3004,6 +3518,13 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
        printQueryOpt myopt = pset.popt;
        static const bool translate_columns[] = {false, false, false, false, false};
 
+       if (pset.sversion < 90100)
+       {
+               psql_error("The server (version %d.%d) does not support collations.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
+               return true;
+       }
+
        initPQExpBuffer(&buf);
 
        printfPQExpBuffer(&buf,
@@ -3021,13 +3542,13 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
                                                  ",\n       pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
                                                  gettext_noop("Description"));
 
-       appendPQExpBuffer(&buf,
+       appendPQExpBufferStr(&buf,
                          "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
-                                         "WHERE n.oid = c.collnamespace\n");
+                                                "WHERE n.oid = c.collnamespace\n");
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf, "      AND n.nspname <> 'pg_catalog'\n"
-                                                 "      AND n.nspname <> 'information_schema'\n");
+               appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+                                                        "      AND n.nspname <> 'information_schema'\n");
 
        /*
         * Hide collations that aren't usable in the current database's encoding.
@@ -3035,15 +3556,15 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
         * unusable collations, so you will need to hack name pattern processing
         * somehow to avoid inconsistent behavior.
         */
-       appendPQExpBuffer(&buf, "      AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
+       appendPQExpBufferStr(&buf, "      AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, true, false,
                                                  "n.nspname", "c.collname", NULL,
                                                  "pg_catalog.pg_collation_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3052,8 +3573,9 @@ 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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3080,7 +3602,7 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
 
        if (verbose)
        {
-               appendPQExpBuffer(&buf, ",\n  ");
+               appendPQExpBufferStr(&buf, ",\n  ");
                printACLColumn(&buf, "n.nspacl");
                appendPQExpBuffer(&buf,
                  ",\n  pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
@@ -3091,7 +3613,7 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
                                          "\nFROM pg_catalog.pg_namespace n\n");
 
        if (!showSystem && !pattern)
-               appendPQExpBuffer(&buf,
+               appendPQExpBufferStr(&buf,
                "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
 
        processSQLNamePattern(pset.db, &buf, pattern,
@@ -3099,9 +3621,9 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
                                                  NULL, "n.nspname", NULL,
                                                  NULL);
 
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3110,7 +3632,7 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
        myopt.title = _("List of schemas");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3130,8 +3652,8 @@ listTSParsers(const char *pattern, bool verbose)
 
        if (pset.sversion < 80300)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support full text search.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -3156,9 +3678,9 @@ listTSParsers(const char *pattern, bool verbose)
                                                  "n.nspname", "p.prsname", NULL,
                                                  "pg_catalog.pg_ts_parser_is_visible(p.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3167,7 +3689,7 @@ listTSParsers(const char *pattern, bool verbose)
        myopt.title = _("List of text search parsers");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3197,9 +3719,9 @@ listTSParsersVerbose(const char *pattern)
                                                  "n.nspname", "p.prsname", NULL,
                                                  "pg_catalog.pg_ts_parser_is_visible(p.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3207,8 +3729,8 @@ listTSParsersVerbose(const char *pattern)
        if (PQntuples(res) == 0)
        {
                if (!pset.quiet)
-                       fprintf(stderr, _("Did not find any text search parser named \"%s\".\n"),
-                                       pattern);
+                       psql_error("Did not find any text search parser named \"%s\".\n",
+                                          pattern);
                PQclear(res);
                return false;
        }
@@ -3296,7 +3818,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
                                          gettext_noop("Get token types"),
                                          oid);
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3308,11 +3830,12 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
                sprintf(title, _("Text search parser \"%s\""), prsname);
        myopt.title = title;
        myopt.footers = NULL;
-       myopt.default_footer = false;
+       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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
 
@@ -3327,7 +3850,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
                                          gettext_noop("Description"),
                                          oid);
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3339,11 +3862,12 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
                sprintf(title, _("Token types for parser \"%s\""), prsname);
        myopt.title = title;
        myopt.footers = NULL;
-       myopt.default_footer = true;
+       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);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3363,8 +3887,8 @@ listTSDictionaries(const char *pattern, bool verbose)
 
        if (pset.sversion < 80300)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support full text search.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -3393,16 +3917,16 @@ listTSDictionaries(const char *pattern, bool verbose)
                         "  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"
+       appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_dict d\n"
                 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                  "n.nspname", "d.dictname", NULL,
                                                  "pg_catalog.pg_ts_dict_is_visible(d.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3411,7 +3935,7 @@ listTSDictionaries(const char *pattern, bool verbose)
        myopt.title = _("List of text search dictionaries");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3431,8 +3955,8 @@ listTSTemplates(const char *pattern, bool verbose)
 
        if (pset.sversion < 80300)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support full text search.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -3461,16 +3985,16 @@ listTSTemplates(const char *pattern, bool verbose)
                                                  gettext_noop("Name"),
                                                  gettext_noop("Description"));
 
-       appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_template t\n"
+       appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_template t\n"
                 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                  "n.nspname", "t.tmplname", NULL,
                                                  "pg_catalog.pg_ts_template_is_visible(t.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3479,7 +4003,7 @@ listTSTemplates(const char *pattern, bool verbose)
        myopt.title = _("List of text search templates");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3499,8 +4023,8 @@ listTSConfigs(const char *pattern, bool verbose)
 
        if (pset.sversion < 80300)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support full text search.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -3525,9 +4049,9 @@ listTSConfigs(const char *pattern, bool verbose)
                                                  "n.nspname", "c.cfgname", NULL,
                                                  "pg_catalog.pg_ts_config_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3536,7 +4060,7 @@ listTSConfigs(const char *pattern, bool verbose)
        myopt.title = _("List of text search configurations");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3567,9 +4091,9 @@ listTSConfigsVerbose(const char *pattern)
                                                  "n.nspname", "c.cfgname", NULL,
                                                  "pg_catalog.pg_ts_config_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 3, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 3, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3577,8 +4101,8 @@ listTSConfigsVerbose(const char *pattern)
        if (PQntuples(res) == 0)
        {
                if (!pset.quiet)
-                       fprintf(stderr, _("Did not find any text search configuration named \"%s\".\n"),
-                                       pattern);
+                       psql_error("Did not find any text search configuration named \"%s\".\n",
+                                          pattern);
                PQclear(res);
                return false;
        }
@@ -3647,7 +4171,7 @@ describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
                                          gettext_noop("Dictionaries"),
                                          oid);
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3671,10 +4195,10 @@ describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
        myopt.nullPrint = NULL;
        myopt.title = title.data;
        myopt.footers = NULL;
-       myopt.default_footer = false;
+       myopt.topt.default_footer = false;
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        termPQExpBuffer(&title);
 
@@ -3697,15 +4221,15 @@ listForeignDataWrappers(const char *pattern, bool verbose)
 
        if (pset.sversion < 80400)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support foreign-data wrappers.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support foreign-data wrappers.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
        initPQExpBuffer(&buf);
        printfPQExpBuffer(&buf,
                                          "SELECT fdw.fdwname AS \"%s\",\n"
-                                         "  pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n",
+                                  "  pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n",
                                          gettext_noop("Name"),
                                          gettext_noop("Owner"));
        if (pset.sversion >= 90100)
@@ -3718,7 +4242,7 @@ listForeignDataWrappers(const char *pattern, bool verbose)
 
        if (verbose)
        {
-               appendPQExpBuffer(&buf, ",\n  ");
+               appendPQExpBufferStr(&buf, ",\n  ");
                printACLColumn(&buf, "fdwacl");
                appendPQExpBuffer(&buf,
                                                  ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
@@ -3735,20 +4259,20 @@ listForeignDataWrappers(const char *pattern, bool verbose)
                                                          gettext_noop("Description"));
        }
 
-       appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
+       appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
 
        if (verbose && pset.sversion >= 90100)
-               appendPQExpBuffer(&buf,
-                                                 "LEFT JOIN pg_catalog.pg_description d\n"
-                                                 "       ON d.classoid = fdw.tableoid "
-                                                 "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
+               appendPQExpBufferStr(&buf,
+                                                        "LEFT JOIN pg_catalog.pg_description d\n"
+                                                        "       ON d.classoid = fdw.tableoid "
+                                                        "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                  NULL, "fdwname", NULL, NULL);
 
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3757,7 +4281,7 @@ listForeignDataWrappers(const char *pattern, bool verbose)
        myopt.title = _("List of foreign-data wrappers");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3777,8 +4301,8 @@ listForeignServers(const char *pattern, bool verbose)
 
        if (pset.sversion < 80400)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support foreign servers.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support foreign servers.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -3793,7 +4317,7 @@ listForeignServers(const char *pattern, bool verbose)
 
        if (verbose)
        {
-               appendPQExpBuffer(&buf, ",\n  ");
+               appendPQExpBufferStr(&buf, ",\n  ");
                printACLColumn(&buf, "s.srvacl");
                appendPQExpBuffer(&buf,
                                                  ",\n"
@@ -3812,22 +4336,22 @@ listForeignServers(const char *pattern, bool verbose)
                                                  gettext_noop("Description"));
        }
 
-       appendPQExpBuffer(&buf,
-                                         "\nFROM pg_catalog.pg_foreign_server s\n"
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_foreign_server s\n"
           "     JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
 
        if (verbose)
-               appendPQExpBuffer(&buf,
-                                                 "LEFT JOIN pg_description d\n       "
-                                                 "ON d.classoid = s.tableoid AND d.objoid = s.oid "
-                                                 "AND d.objsubid = 0\n");
+               appendPQExpBufferStr(&buf,
+                                                        "LEFT JOIN pg_description d\n       "
+                                                  "ON d.classoid = s.tableoid AND d.objoid = s.oid "
+                                                        "AND d.objsubid = 0\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                  NULL, "s.srvname", NULL, NULL);
 
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3836,7 +4360,7 @@ listForeignServers(const char *pattern, bool verbose)
        myopt.title = _("List of foreign servers");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3856,8 +4380,8 @@ listUserMappings(const char *pattern, bool verbose)
 
        if (pset.sversion < 80400)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support user mappings.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support user mappings.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -3878,14 +4402,14 @@ listUserMappings(const char *pattern, bool verbose)
                                                  "  END AS \"%s\"",
                                                  gettext_noop("FDW Options"));
 
-       appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
+       appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
                                                  NULL, "um.srvname", "um.usename", NULL);
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3894,7 +4418,7 @@ listUserMappings(const char *pattern, bool verbose)
        myopt.title = _("List of user mappings");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3914,8 +4438,8 @@ listForeignTables(const char *pattern, bool verbose)
 
        if (pset.sversion < 90100)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support foreign tables.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support foreign tables.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -3940,26 +4464,27 @@ listForeignTables(const char *pattern, bool verbose)
                                                  gettext_noop("FDW Options"),
                                                  gettext_noop("Description"));
 
-       appendPQExpBuffer(&buf,
-                                         "\nFROM pg_catalog.pg_foreign_table ft\n"
-                                         "  INNER JOIN pg_catalog.pg_class c"
-                                         " ON c.oid = ft.ftrelid\n"
-                                         "  INNER JOIN pg_catalog.pg_namespace n"
-                                         " ON n.oid = c.relnamespace\n"
-                                         "  INNER JOIN pg_catalog.pg_foreign_server s"
-                                         " ON s.oid = ft.ftserver\n");
+       appendPQExpBufferStr(&buf,
+                                                "\nFROM pg_catalog.pg_foreign_table ft\n"
+                                                "  INNER JOIN pg_catalog.pg_class c"
+                                                " ON c.oid = ft.ftrelid\n"
+                                                "  INNER JOIN pg_catalog.pg_namespace n"
+                                                " ON n.oid = c.relnamespace\n"
+                                                "  INNER JOIN pg_catalog.pg_foreign_server s"
+                                                " ON s.oid = ft.ftserver\n");
        if (verbose)
-               appendPQExpBuffer(&buf,
-                                                 "   LEFT JOIN pg_catalog.pg_description d\n"
-                                                 "          ON d.classoid = c.tableoid AND "
-                                                 "d.objoid = c.oid AND d.objsubid = 0\n");
+               appendPQExpBufferStr(&buf,
+                                                        "   LEFT JOIN pg_catalog.pg_description d\n"
+                                                        "          ON d.classoid = c.tableoid AND "
+                                                        "d.objoid = c.oid AND d.objsubid = 0\n");
 
        processSQLNamePattern(pset.db, &buf, pattern, false, false,
-                                                 NULL, "n.nspname", "c.relname", NULL);
+                                                 "n.nspname", "c.relname", NULL,
+                                                 "pg_catalog.pg_table_is_visible(c.oid)");
 
-       appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -3968,7 +4493,7 @@ listForeignTables(const char *pattern, bool verbose)
        myopt.title = _("List of foreign tables");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -3988,8 +4513,8 @@ listExtensions(const char *pattern)
 
        if (pset.sversion < 90100)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support extensions.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support extensions.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -4011,9 +4536,9 @@ listExtensions(const char *pattern)
                                                  NULL, "e.extname", NULL,
                                                  NULL);
 
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -4022,7 +4547,7 @@ listExtensions(const char *pattern)
        myopt.title = _("List of installed extensions");
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -4042,8 +4567,8 @@ listExtensionContents(const char *pattern)
 
        if (pset.sversion < 90100)
        {
-               fprintf(stderr, _("The server (version %d.%d) does not support extensions.\n"),
-                               pset.sversion / 10000, (pset.sversion / 100) % 100);
+               psql_error("The server (version %d.%d) does not support extensions.\n",
+                                  pset.sversion / 10000, (pset.sversion / 100) % 100);
                return true;
        }
 
@@ -4057,9 +4582,9 @@ listExtensionContents(const char *pattern)
                                                  NULL, "e.extname", NULL,
                                                  NULL);
 
-       appendPQExpBuffer(&buf, "ORDER BY 1;");
+       appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -4069,10 +4594,10 @@ listExtensionContents(const char *pattern)
                if (!pset.quiet)
                {
                        if (pattern)
-                               fprintf(stderr, _("Did not find any extension named \"%s\".\n"),
-                                               pattern);
+                               psql_error("Did not find any extension named \"%s\".\n",
+                                                  pattern);
                        else
-                               fprintf(stderr, _("Did not find any extensions.\n"));
+                               psql_error("Did not find any extensions.\n");
                }
                PQclear(res);
                return false;
@@ -4119,7 +4644,7 @@ listOneExtensionContents(const char *extname, const char *oid)
                                          gettext_noop("Object Description"),
                                          oid);
 
-       res = PSQLexec(buf.data, false);
+       res = PSQLexec(buf.data);
        termPQExpBuffer(&buf);
        if (!res)
                return false;
@@ -4129,7 +4654,7 @@ listOneExtensionContents(const char *extname, const char *oid)
        myopt.title = title;
        myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout, pset.logfile);
+       printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
        PQclear(res);
        return true;
@@ -4139,7 +4664,7 @@ listOneExtensionContents(const char *extname, const char *oid)
  * printACLColumn
  *
  * Helper function for consistently formatting ACL (privilege) columns.
- * The proper targetlist entry is appended to buf.     Note lack of any
+ * The proper targetlist entry is appended to buf.  Note lack of any
  * whitespace or comma decoration.
  */
 static void