* 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-2009, PostgreSQL Global Development Group
+ * Copyright (c) 2000-2011, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.198 2009/01/22 20:16:08 tgl Exp $
+ * src/bin/psql/describe.c
*/
#include "postgres_fe.h"
const char *oid,
bool verbose);
static void add_tablespace_footer(printTableContent *const cont, char relkind,
- Oid tablespace, const bool newline);
+ Oid tablespace, const bool newline);
static void add_role_attribute(PQExpBuffer buf, const char *const str);
static bool listTSParsersVerbose(const char *pattern);
static bool describeOneTSParser(const char *oid, const char *nspname,
const char *cfgname,
const char *pnspname, const char *prsname);
static void printACLColumn(PQExpBuffer buf, const char *colname);
+static bool listOneExtensionContents(const char *extname, const char *oid);
/*----------------
printfPQExpBuffer(&buf,
"SELECT n.nspname as \"%s\",\n"
" p.proname AS \"%s\",\n"
- " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n",
+ " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n",
gettext_noop("Schema"),
gettext_noop("Name"),
gettext_noop("Result data type"));
if (pset.sversion >= 80200)
- appendPQExpBuffer(&buf,
- " CASE WHEN p.pronargs = 0\n"
- " THEN CAST('*' AS pg_catalog.text)\n"
- " ELSE\n"
- " pg_catalog.array_to_string(ARRAY(\n"
- " SELECT\n"
- " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
- " FROM\n"
- " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
- " ), ', ')\n"
- " END AS \"%s\",\n",
- gettext_noop("Argument data types"));
+ appendPQExpBuffer(&buf,
+ " CASE WHEN p.pronargs = 0\n"
+ " THEN CAST('*' AS pg_catalog.text)\n"
+ " ELSE\n"
+ " pg_catalog.array_to_string(ARRAY(\n"
+ " SELECT\n"
+ " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
+ " FROM\n"
+ " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
+ " ), ', ')\n"
+ " END AS \"%s\",\n",
+ gettext_noop("Argument data types"));
else
- appendPQExpBuffer(&buf,
- " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
- gettext_noop("Argument data types"));
+ appendPQExpBuffer(&buf,
+ " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
+ gettext_noop("Argument data types"));
appendPQExpBuffer(&buf,
" pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
"WHERE p.proisagg\n",
gettext_noop("Description"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&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,
if (verbose && pset.sversion >= 80200)
appendPQExpBuffer(&buf,
- ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
+ ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
gettext_noop("Description"));
appendPQExpBuffer(&buf,
/* \df
- * Takes an optional regexp to select particular functions
+ * Takes an optional regexp to select particular functions.
+ *
+ * As with \d, you can specify the kinds of functions you want:
+ *
+ * a for aggregates
+ * n for normal
+ * t for trigger
+ * w for window
+ *
+ * and you can mix and match these in any order.
*/
bool
-describeFunctions(const char *pattern, bool verbose, bool showSystem)
+describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem)
{
+ bool showAggregate = strchr(functypes, 'a') != NULL;
+ bool showNormal = strchr(functypes, 'n') != NULL;
+ bool showTrigger = strchr(functypes, 't') != NULL;
+ bool showWindow = strchr(functypes, 'w') != NULL;
+ bool have_where;
PQExpBufferData buf;
PGresult *res;
printQueryOpt myopt = pset.popt;
+ static const bool translate_columns[] = {false, false, false, false, true, true, false, false, false, false};
+
+ if (strlen(functypes) != strspn(functypes, "antwS+"))
+ {
+ fprintf(stderr, _("\\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);
+ return true;
+ }
+
+ if (!showAggregate && !showNormal && !showTrigger && !showWindow)
+ {
+ showAggregate = showNormal = showTrigger = true;
+ if (pset.sversion >= 80400)
+ showWindow = true;
+ }
initPQExpBuffer(&buf);
gettext_noop("Schema"),
gettext_noop("Name"));
- if (pset.sversion >= 80400)
+ if (pset.sversion >= 80400)
appendPQExpBuffer(&buf,
- " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
- " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\"",
+ " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
+ " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
+ " CASE\n"
+ " WHEN p.proisagg THEN '%s'\n"
+ " WHEN p.proiswindow THEN '%s'\n"
+ " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
+ " ELSE '%s'\n"
+ "END as \"%s\"",
gettext_noop("Result data type"),
- gettext_noop("Argument data types"));
- else if (pset.sversion >= 80100)
+ gettext_noop("Argument data types"),
+ /* translator: "agg" is short for "aggregate" */
+ gettext_noop("agg"),
+ gettext_noop("window"),
+ gettext_noop("trigger"),
+ gettext_noop("normal"),
+ gettext_noop("Type"));
+ else if (pset.sversion >= 80100)
appendPQExpBuffer(&buf,
- " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
+ " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
" pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
- " CASE WHEN proallargtypes IS NOT NULL THEN\n"
- " pg_catalog.array_to_string(ARRAY(\n"
- " SELECT\n"
- " CASE\n"
- " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
+ " CASE WHEN proallargtypes IS NOT NULL THEN\n"
+ " pg_catalog.array_to_string(ARRAY(\n"
+ " SELECT\n"
+ " CASE\n"
+ " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
" WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
- " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
- " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
- " END ||\n"
- " CASE\n"
+ " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
+ " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
+ " END ||\n"
+ " CASE\n"
" WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
- " ELSE p.proargnames[s.i] || ' ' \n"
- " END ||\n"
+ " ELSE p.proargnames[s.i] || ' ' \n"
+ " END ||\n"
" pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
- " FROM\n"
- " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
- " ), ', ')\n"
- " ELSE\n"
- " pg_catalog.array_to_string(ARRAY(\n"
- " SELECT\n"
- " CASE\n"
+ " FROM\n"
+ " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
+ " ), ', ')\n"
+ " ELSE\n"
+ " pg_catalog.array_to_string(ARRAY(\n"
+ " SELECT\n"
+ " CASE\n"
" WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
- " ELSE p.proargnames[s.i+1] || ' '\n"
- " END ||\n"
+ " ELSE p.proargnames[s.i+1] || ' '\n"
+ " END ||\n"
" pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
- " FROM\n"
- " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
- " ), ', ')\n"
- " END AS \"%s\"",
+ " FROM\n"
+ " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
+ " ), ', ')\n"
+ " END AS \"%s\",\n"
+ " CASE\n"
+ " WHEN p.proisagg THEN '%s'\n"
+ " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
+ " ELSE '%s'\n"
+ " END AS \"%s\"",
gettext_noop("Result data type"),
- gettext_noop("Argument data types"));
+ gettext_noop("Argument data types"),
+ /* translator: "agg" is short for "aggregate" */
+ gettext_noop("agg"),
+ gettext_noop("trigger"),
+ gettext_noop("normal"),
+ gettext_noop("Type"));
else
appendPQExpBuffer(&buf,
- " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
+ " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
" pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
- " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\"",
+ " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\",\n"
+ " CASE\n"
+ " WHEN p.proisagg THEN '%s'\n"
+ " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
+ " ELSE '%s'\n"
+ " END AS \"%s\"",
gettext_noop("Result data type"),
- gettext_noop("Argument data types"));
+ gettext_noop("Argument data types"),
+ /* translator: "agg" is short for "aggregate" */
+ gettext_noop("agg"),
+ gettext_noop("trigger"),
+ gettext_noop("normal"),
+ gettext_noop("Type"));
if (verbose)
appendPQExpBuffer(&buf,
",\n CASE\n"
- " WHEN p.provolatile = 'i' THEN 'immutable'\n"
- " WHEN p.provolatile = 's' THEN 'stable'\n"
- " WHEN p.provolatile = 'v' THEN 'volatile'\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\""
- ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\",\n"
+ ",\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("immutable"),
+ gettext_noop("stable"),
+ gettext_noop("volatile"),
gettext_noop("Volatility"),
gettext_noop("Owner"),
gettext_noop("Language"),
appendPQExpBuffer(&buf,
"\nFROM pg_catalog.pg_proc p"
- "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
+ "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
if (verbose)
appendPQExpBuffer(&buf,
- " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
+ " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
- /*
- * we skip in/out funcs by excluding functions that take or return cstring
- */
- appendPQExpBuffer(&buf,
- "WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n"
- " AND p.proargtypes[0] IS DISTINCT FROM 'pg_catalog.cstring'::pg_catalog.regtype\n"
- " AND NOT p.proisagg\n");
+ have_where = false;
+
+ /* filter by function type, if requested */
+ if (showNormal && showAggregate && showTrigger && showWindow)
+ /* Do nothing */ ;
+ else if (showNormal)
+ {
+ if (!showAggregate)
+ {
+ if (have_where)
+ appendPQExpBuffer(&buf, " AND ");
+ else
+ {
+ appendPQExpBuffer(&buf, "WHERE ");
+ have_where = true;
+ }
+ appendPQExpBuffer(&buf, "NOT p.proisagg\n");
+ }
+ if (!showTrigger)
+ {
+ if (have_where)
+ appendPQExpBuffer(&buf, " AND ");
+ else
+ {
+ appendPQExpBuffer(&buf, "WHERE ");
+ have_where = true;
+ }
+ appendPQExpBuffer(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
+ }
+ if (!showWindow && pset.sversion >= 80400)
+ {
+ if (have_where)
+ appendPQExpBuffer(&buf, " AND ");
+ else
+ {
+ appendPQExpBuffer(&buf, "WHERE ");
+ have_where = true;
+ }
+ appendPQExpBuffer(&buf, "NOT p.proiswindow\n");
+ }
+ }
+ else
+ {
+ bool needs_or = false;
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ appendPQExpBuffer(&buf, "WHERE (\n ");
+ have_where = true;
+ /* Note: at least one of these must be true ... */
+ if (showAggregate)
+ {
+ appendPQExpBuffer(&buf, "p.proisagg\n");
+ needs_or = true;
+ }
+ if (showTrigger)
+ {
+ if (needs_or)
+ appendPQExpBuffer(&buf, " OR ");
+ appendPQExpBuffer(&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");
+ needs_or = true;
+ }
+ appendPQExpBuffer(&buf, " )\n");
+ }
- processSQLNamePattern(pset.db, &buf, pattern, true, false,
+ processSQLNamePattern(pset.db, &buf, pattern, have_where, false,
"n.nspname", "p.proname", NULL,
"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");
+
appendPQExpBuffer(&buf, "ORDER BY 1, 2, 4;");
res = PSQLexec(buf.data, false);
myopt.nullPrint = NULL;
myopt.title = _("List of functions");
myopt.translate_header = true;
+ myopt.translate_columns = translate_columns;
printQuery(res, &myopt, pset.queryFout, pset.logfile);
gettext_noop("Internal name"),
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"
- " ORDER BY e.oid\n"
+ " WHERE e.enumtypid = t.oid\n");
+
+ if (pset.sversion >= 90100)
+ appendPQExpBuffer(&buf,
+ " ORDER BY e.enumsortorder\n");
+ else
+ appendPQExpBuffer(&buf,
+ " ORDER BY e.oid\n");
+
+ appendPQExpBuffer(&buf,
" ),\n"
" E'\\n'\n"
" ) AS \"%s\",\n",
gettext_noop("Elements"));
+ }
appendPQExpBuffer(&buf,
- " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
+ " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
gettext_noop("Description"));
appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n"
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");
+
/*
* do not include array types (before 8.3 we have to use the assumption
* that their names start with underscore)
else
appendPQExpBuffer(&buf, " AND t.typname !~ '^_'\n");
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&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,
initPQExpBuffer(&buf);
+ /*
+ * Note: before Postgres 9.1, we did not assign comments to any built-in
+ * operators, preferring to let the comment on the underlying function
+ * suffice. The coalesce() on the obj_description() calls below supports
+ * this convention by providing a fallback lookup of a comment on the
+ * operator's function. As of 9.1 there is a policy that every built-in
+ * operator should have a comment; so the coalesce() is no longer
+ * necessary so far as built-in operators are concerned. We keep it
+ * anyway, for now, because (1) third-party modules may still be following
+ * the old convention, and (2) we'd need to do it anyway when talking to a
+ * pre-9.1 server.
+ */
+
printfPQExpBuffer(&buf,
"SELECT n.nspname as \"%s\",\n"
" o.oprname AS \"%s\",\n"
gettext_noop("Result type"),
gettext_noop("Description"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " WHERE n.nspname <> 'pg_catalog'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+ " AND n.nspname <> 'information_schema'\n");
- processSQLNamePattern(pset.db, &buf, pattern, !showSystem, true,
+ processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, true,
"n.nspname", "o.oprname", NULL,
"pg_catalog.pg_operator_is_visible(o.oid)");
printfPQExpBuffer(&buf,
"SELECT d.datname as \"%s\",\n"
- " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
- " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
+ " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
+ " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
gettext_noop("Name"),
gettext_noop("Owner"),
gettext_noop("Encoding"));
appendPQExpBuffer(&buf,
" d.datcollate as \"%s\",\n"
" d.datctype as \"%s\",\n",
- gettext_noop("Collation"),
+ gettext_noop("Collate"),
gettext_noop("Ctype"));
appendPQExpBuffer(&buf, " ");
printACLColumn(&buf, "d.datacl");
",\n t.spcname as \"%s\"",
gettext_noop("Tablespace"));
if (verbose && pset.sversion >= 80200)
- appendPQExpBuffer(&buf,
+ appendPQExpBuffer(&buf,
",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
gettext_noop("Description"));
appendPQExpBuffer(&buf,
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' END 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"
" ",
gettext_noop("Schema"),
gettext_noop("Name"),
- gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
+ gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
+ gettext_noop("foreign table"),
gettext_noop("Type"));
printACLColumn(&buf, "c.relacl");
appendPQExpBuffer(&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')\n");
+ "WHERE c.relkind IN ('r', 'v', 'S', 'f')\n");
/*
* Unless a schema pattern is specified, we suppress system and temp
}
+/*
+ * \ddp
+ *
+ * List DefaultACLs. The pattern can match either schema or role name.
+ */
+bool
+listDefaultACLs(const char *pattern)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+ static const bool translate_columns[] = {false, false, true, false};
+
+ 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);
+ return true;
+ }
+
+ initPQExpBuffer(&buf);
+
+ 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"
+ " ",
+ gettext_noop("Owner"),
+ gettext_noop("Schema"),
+ gettext_noop("table"),
+ gettext_noop("sequence"),
+ gettext_noop("function"),
+ 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");
+
+ processSQLNamePattern(pset.db, &buf, pattern, false, false,
+ NULL,
+ "n.nspname",
+ "pg_catalog.pg_get_userbyid(d.defaclrole)",
+ NULL);
+
+ appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
+
+ res = PSQLexec(buf.data, false);
+ if (!res)
+ {
+ termPQExpBuffer(&buf);
+ return false;
+ }
+
+ myopt.nullPrint = NULL;
+ printfPQExpBuffer(&buf, _("Default access privileges"));
+ myopt.title = buf.data;
+ myopt.translate_header = true;
+ myopt.translate_columns = translate_columns;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ termPQExpBuffer(&buf);
+ PQclear(res);
+ return true;
+}
+
/*
* Get object comments
" WHERE p.proisagg\n",
gettext_noop("aggregate"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&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)");
- /* Function descriptions (except in/outs for datatypes) */
+ /* Function descriptions */
appendPQExpBuffer(&buf,
"UNION ALL\n"
" SELECT p.oid as oid, p.tableoid as tableoid,\n"
" CAST('%s' AS pg_catalog.text) as object\n"
" FROM pg_catalog.pg_proc p\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
-
- " WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n"
- " AND (p.proargtypes[0] IS NULL\n"
- " OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n"
- " AND NOT p.proisagg\n",
+ " WHERE NOT p.proisagg\n",
gettext_noop("function"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&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)");
- /* Operator descriptions (only if operator has its own comment) */
+ /* Operator descriptions */
appendPQExpBuffer(&buf,
"UNION ALL\n"
" SELECT o.oid as oid, o.tableoid as tableoid,\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
gettext_noop("operator"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " WHERE n.nspname <> 'pg_catalog'\n");
-
- processSQLNamePattern(pset.db, &buf, pattern, !showSystem, false,
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+ " AND n.nspname <> 'information_schema'\n");
+
+ processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
"n.nspname", "o.oprname", NULL,
"pg_catalog.pg_operator_is_visible(o.oid)");
- /* Type description */
+ /* Type descriptions */
appendPQExpBuffer(&buf,
"UNION ALL\n"
" SELECT t.oid as oid, t.tableoid as tableoid,\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
gettext_noop("data type"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " WHERE n.nspname <> 'pg_catalog'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+ " AND n.nspname <> 'information_schema'\n");
- processSQLNamePattern(pset.db, &buf, pattern, !showSystem, false,
+ processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
"n.nspname", "pg_catalog.format_type(t.oid, NULL)",
NULL,
"pg_catalog.pg_type_is_visible(t.oid)");
" n.nspname as nspname,\n"
" CAST(c.relname AS pg_catalog.text) as name,\n"
" CAST(\n"
- " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END"
+ " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END"
" AS pg_catalog.text) as object\n"
" FROM pg_catalog.pg_class c\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
- " WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
+ " WHERE c.relkind IN ('r', 'v', 'i', 'S', 'f')\n",
gettext_noop("table"),
gettext_noop("view"),
gettext_noop("index"),
- gettext_noop("sequence"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ gettext_noop("sequence"),
+ gettext_noop("foreign table"));
+
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
+ " AND n.nspname <> 'information_schema'\n");
processSQLNamePattern(pset.db, &buf, pattern, true, false,
"n.nspname", "c.relname", NULL,
"pg_catalog.pg_table_is_visible(c.oid)");
- /* Rule description (ignore rules for views) */
+ /* Rule descriptions (ignore rules for views) */
appendPQExpBuffer(&buf,
"UNION ALL\n"
" SELECT r.oid as oid, r.tableoid as tableoid,\n"
" WHERE r.rulename != '_RETURN'\n",
gettext_noop("rule"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
+ " AND n.nspname <> 'information_schema'\n");
/* XXX not sure what to do about visibility rule here? */
processSQLNamePattern(pset.db, &buf, pattern, true, false,
"n.nspname", "r.rulename", NULL,
"pg_catalog.pg_table_is_visible(c.oid)");
- /* Trigger description */
+ /* Trigger descriptions */
appendPQExpBuffer(&buf,
"UNION ALL\n"
" SELECT t.oid as oid, t.tableoid as tableoid,\n"
" JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
gettext_noop("trigger"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " WHERE n.nspname <> 'pg_catalog'\n");
+
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+ " AND n.nspname <> 'information_schema'\n");
/* XXX not sure what to do about visibility rule here? */
- processSQLNamePattern(pset.db, &buf, pattern, !showSystem, false,
+ processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
"n.nspname", "t.tgname", NULL,
"pg_catalog.pg_table_is_visible(c.oid)");
"FROM pg_catalog.pg_class c\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
- if (!showSystem)
- appendPQExpBuffer(&buf, " WHERE n.nspname <> 'pg_catalog'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
+ " AND n.nspname <> 'information_schema'\n");
- processSQLNamePattern(pset.db, &buf, pattern, !showSystem, false,
+ processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
"n.nspname", "c.relname", NULL,
"pg_catalog.pg_table_is_visible(c.oid)");
PGresult *res = NULL;
printTableOpt myopt = pset.popt.topt;
printTableContent cont;
- bool printTableInitialized = false;
+ bool printTableInitialized = false;
int i;
char *view_def = NULL;
char *headers[6];
char **ptr;
PQExpBufferData title;
PQExpBufferData tmpbuf;
- int cols = 0;
+ int cols;
int numrows = 0;
struct
{
bool hasoids;
Oid tablespace;
char *reloptions;
+ char *reloftype;
+ char relpersistence;
} tableinfo;
bool show_modifiers = false;
bool retval;
initPQExpBuffer(&tmpbuf);
/* Get general table info */
- printfPQExpBuffer(&buf,
- "SELECT relchecks, relkind, relhasindex, relhasrules, %s, "
- "relhasoids"
- "%s%s\n"
- "FROM pg_catalog.pg_class WHERE oid = '%s'",
- (pset.sversion >= 80400 ? "relhastriggers" : "reltriggers <> 0"),
- (pset.sversion >= 80200 && verbose ?
- ", pg_catalog.array_to_string(reloptions, E', ')" : ",''"),
- (pset.sversion >= 80000 ? ", reltablespace" : ""),
- oid);
+ if (pset.sversion >= 90100)
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
+ "c.relhastriggers, c.relhasoids, "
+ "%s, c.reltablespace, "
+ "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
+ "c.relpersistence\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 >= 90000)
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
+ "c.relhastriggers, 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 "
+ "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 >= 80400)
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
+ "c.relhastriggers, 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"
+ "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 >= 80200)
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT relchecks, relkind, relhasindex, relhasrules, "
+ "reltriggers <> 0, relhasoids, "
+ "%s, reltablespace\n"
+ "FROM pg_catalog.pg_class WHERE oid = '%s';",
+ (verbose ?
+ "pg_catalog.array_to_string(reloptions, E', ')" : "''"),
+ oid);
+ }
+ else if (pset.sversion >= 80000)
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT relchecks, relkind, relhasindex, relhasrules, "
+ "reltriggers <> 0, relhasoids, "
+ "'', reltablespace\n"
+ "FROM pg_catalog.pg_class WHERE oid = '%s';",
+ oid);
+ }
+ else
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT relchecks, relkind, relhasindex, relhasrules, "
+ "reltriggers <> 0, relhasoids, "
+ "'', ''\n"
+ "FROM pg_catalog.pg_class WHERE oid = '%s';",
+ oid);
+ }
+
res = PSQLexec(buf.data, false);
if (!res)
goto error_return;
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.reloptions = pset.sversion >= 80200 ?
- strdup(PQgetvalue(res, 0, 6)) : 0;
+ tableinfo.reloptions = (pset.sversion >= 80200) ?
+ strdup(PQgetvalue(res, 0, 6)) : 0;
tableinfo.tablespace = (pset.sversion >= 80000) ?
- atooid(PQgetvalue(res, 0, 7)) : 0;
+ 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;
PQclear(res);
res = NULL;
-
+
/*
- * If it's a sequence, fetch its values and store into an
- * array that will be used later.
+ * If it's a sequence, fetch its values and store into an array that will
+ * be used later.
*/
if (tableinfo.relkind == 'S')
{
- PGresult *result;
-
-#define SEQ_NUM_COLS 10
- printfPQExpBuffer(&buf,
- "SELECT sequence_name, last_value,\n"
- " start_value, increment_by,\n"
- " max_value, min_value, cache_value,\n"
- " log_cnt, is_cycled, is_called\n"
- "FROM %s",
- fmtId(schemaname));
+ printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
/* must be separate because fmtId isn't reentrant */
- appendPQExpBuffer(&buf, ".%s", fmtId(relationname));
-
- result = PSQLexec(buf.data, false);
- if (!result)
+ appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
+
+ res = PSQLexec(buf.data, false);
+ if (!res)
goto error_return;
-
- seq_values = pg_malloc_zero((SEQ_NUM_COLS+1) * sizeof(*seq_values));
-
- for (i = 0; i < SEQ_NUM_COLS; i++)
- seq_values[i] = pg_strdup(PQgetvalue(result, 0, i));
-
- PQclear(result);
+
+ seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
+
+ for (i = 0; i < PQnfields(res); i++)
+ seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
+ seq_values[i] = NULL;
+
+ PQclear(res);
+ res = NULL;
}
- /* Get column info (index requires additional checks) */
+ /*
+ * Get column info
+ *
+ * You need to modify value of "firstvcol" which willbe defined below if
+ * 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");
+ "\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");
+ else
+ appendPQExpBuffer(&buf, "\n NULL AS attcollation");
+ if (tableinfo.relkind == 'i')
+ appendPQExpBuffer(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
+ else
+ appendPQExpBuffer(&buf, ",\n NULL AS indexdef");
+ if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
+ appendPQExpBuffer(&buf, ",\n a.attfdwoptions");
+ else
+ appendPQExpBuffer(&buf, ",\n NULL AS attfdwoptions");
if (verbose)
- appendPQExpBuffer(&buf, ", a.attstorage, pg_catalog.col_description(a.attrelid, a.attnum)");
+ {
+ appendPQExpBuffer(&buf, ",\n a.attstorage");
+ /*
+ * 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 == 'f' || tableinfo.relkind == 'c')
+ appendPQExpBuffer(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)");
+ }
+
appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_attribute a");
- if (tableinfo.relkind == 'i')
- appendPQExpBuffer(&buf, ", pg_catalog.pg_index i");
appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
- if (tableinfo.relkind == 'i')
- appendPQExpBuffer(&buf, " AND a.attrelid = i.indexrelid");
- appendPQExpBuffer(&buf, "\nORDER BY a.attnum");
+ appendPQExpBuffer(&buf, "\nORDER BY a.attnum;");
res = PSQLexec(buf.data, false);
if (!res)
switch (tableinfo.relkind)
{
case 'r':
- printfPQExpBuffer(&title, _("Table \"%s.%s\""),
- schemaname, relationname);
+ if (tableinfo.relpersistence == 'u')
+ printfPQExpBuffer(&title, _("Unlogged table \"%s.%s\""),
+ schemaname, relationname);
+ else
+ printfPQExpBuffer(&title, _("Table \"%s.%s\""),
+ schemaname, relationname);
break;
case 'v':
printfPQExpBuffer(&title, _("View \"%s.%s\""),
schemaname, relationname);
break;
case 'i':
- printfPQExpBuffer(&title, _("Index \"%s.%s\""),
- schemaname, relationname);
+ if (tableinfo.relpersistence == 'u')
+ printfPQExpBuffer(&title, _("Unlogged index \"%s.%s\""),
+ schemaname, relationname);
+ else
+ printfPQExpBuffer(&title, _("Index \"%s.%s\""),
+ schemaname, relationname);
break;
case 's':
/* not used as of 8.2, but keep it for backwards compatibility */
printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
schemaname, relationname);
break;
+ case 'f':
+ printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""),
+ schemaname, relationname);
+ break;
default:
/* untranslated unknown relkind */
printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
}
/* Set the number of columns, and their names */
- cols += 2;
headers[0] = gettext_noop("Column");
headers[1] = gettext_noop("Type");
+ cols = 2;
- if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
+ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
+ tableinfo.relkind == 'f' || tableinfo.relkind == 'c')
{
show_modifiers = true;
headers[cols++] = gettext_noop("Modifiers");
if (tableinfo.relkind == 'S')
headers[cols++] = gettext_noop("Value");
-
+
+ if (tableinfo.relkind == 'i')
+ headers[cols++] = gettext_noop("Definition");
+
+ if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
+ headers[cols++] = gettext_noop("Options");
+
if (verbose)
{
headers[cols++] = gettext_noop("Storage");
- headers[cols++] = gettext_noop("Description");
+ /* Column comments, if the relkind supports this feature. */
+ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
+ tableinfo.relkind == 'c' || tableinfo.relkind == 'f')
+ headers[cols++] = gettext_noop("Description");
}
-
+
printTableInit(&cont, &myopt, title.data, cols, numrows);
printTableInitialized = true;
printTableAddHeader(&cont, headers[i], true, 'l');
/* Check if table is a view */
- if (tableinfo.relkind == 'v')
+ if (tableinfo.relkind == 'v' && 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);
if (!result)
for (i = 0; i < numrows; i++)
{
/* Column */
- printTableAddCell(&cont, PQgetvalue(res, i, 0), false);
+ printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
/* Type */
- printTableAddCell(&cont, PQgetvalue(res, i, 1), false);
+ printTableAddCell(&cont, PQgetvalue(res, i, 1), false, false);
- /* Modifiers: not null and default */
+ /* Modifiers: collate, not null, default */
if (show_modifiers)
{
resetPQExpBuffer(&tmpbuf);
+
+ if (!PQgetisnull(res, i, 5))
+ {
+ if (tmpbuf.len > 0)
+ appendPQExpBufferStr(&tmpbuf, " ");
+ appendPQExpBuffer(&tmpbuf, _("collate %s"),
+ PQgetvalue(res, i, 5));
+ }
+
if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
+ {
+ if (tmpbuf.len > 0)
+ appendPQExpBufferStr(&tmpbuf, " ");
appendPQExpBufferStr(&tmpbuf, _("not null"));
+ }
/* handle "default" here */
/* (note: above we cut off the 'default' string at 128) */
}
modifiers[i] = pg_strdup(tmpbuf.data);
- printTableAddCell(&cont, modifiers[i], false);
+ printTableAddCell(&cont, modifiers[i], false, false);
}
/* Value: for sequences only */
if (tableinfo.relkind == 'S')
- printTableAddCell(&cont, seq_values[i], false);
+ printTableAddCell(&cont, seq_values[i], false, false);
+
+ /* Expression for index column */
+ if (tableinfo.relkind == 'i')
+ printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
+
+ /* FDW options for foreign table column, only for 9.2 or later */
+ if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
+ printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
/* Storage and Description */
if (verbose)
{
- char *storage = PQgetvalue(res, i, 5);
+ int firstvcol = 8;
+ char *storage = PQgetvalue(res, i, firstvcol);
/* these strings are literal in our syntax, so not translated. */
- printTableAddCell(&cont, (storage[0]=='p' ? "plain" :
- (storage[0]=='m' ? "main" :
- (storage[0]=='x' ? "extended" :
- (storage[0]=='e' ? "external" :
+ printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
+ (storage[0] == 'm' ? "main" :
+ (storage[0] == 'x' ? "extended" :
+ (storage[0] == 'e' ? "external" :
"???")))),
- false);
- printTableAddCell(&cont, PQgetvalue(res, i, 6), false);
+ false, false);
+ /* Column comments, if the relkind supports this feature. */
+ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
+ tableinfo.relkind == 'c' || tableinfo.relkind == 'f')
+ printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
+ false, false);
}
}
PGresult *result;
printfPQExpBuffer(&buf,
- "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
+ "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
if (pset.sversion >= 80200)
- appendPQExpBuffer(&buf, "i.indisvalid, ");
+ appendPQExpBuffer(&buf, "i.indisvalid,\n");
else
- appendPQExpBuffer(&buf, "true as indisvalid, ");
- appendPQExpBuffer(&buf, "a.amname, c2.relname,\n"
- " pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
+ appendPQExpBuffer(&buf, "true AS indisvalid,\n");
+ if (pset.sversion >= 90000)
+ appendPQExpBuffer(&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 "
+ "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");
+ else
+ appendPQExpBuffer(&buf,
+ " false AS condeferrable, false AS condeferred,\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"
"WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
- "AND i.indrelid = c2.oid",
+ "AND i.indrelid = c2.oid;",
oid);
result = PSQLexec(buf.data, false);
char *indisprimary = PQgetvalue(result, 0, 1);
char *indisclustered = PQgetvalue(result, 0, 2);
char *indisvalid = PQgetvalue(result, 0, 3);
- char *indamname = PQgetvalue(result, 0, 4);
- char *indtable = PQgetvalue(result, 0, 5);
- char *indpred = PQgetvalue(result, 0, 6);
+ 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);
if (strcmp(indisprimary, "t") == 0)
printfPQExpBuffer(&tmpbuf, _("primary key, "));
if (strcmp(indisvalid, "t") != 0)
appendPQExpBuffer(&tmpbuf, _(", invalid"));
+ if (strcmp(deferrable, "t") == 0)
+ appendPQExpBuffer(&tmpbuf, _(", deferrable"));
+
+ if (strcmp(deferred, "t") == 0)
+ appendPQExpBuffer(&tmpbuf, _(", initially deferred"));
+
printTableAddFooter(&cont, tmpbuf.data);
add_tablespace_footer(&cont, tableinfo.relkind,
tableinfo.tablespace, true);
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",
+ "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1;",
oid);
result = PSQLexec(buf.data, false);
if (!result)
PQclear(result);
}
}
- else if (tableinfo.relkind == 'r')
+ else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'f')
{
/* Footer information about a table */
PGresult *result = NULL;
{
printfPQExpBuffer(&buf,
"SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
- if (pset.sversion >= 80200)
+ if (pset.sversion >= 80200)
appendPQExpBuffer(&buf, "i.indisvalid, ");
- else
+ else
appendPQExpBuffer(&buf, "true as indisvalid, ");
- appendPQExpBuffer(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)");
- if (pset.sversion >= 80000)
+ appendPQExpBuffer(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n ");
+ if (pset.sversion >= 90000)
+ appendPQExpBuffer(&buf,
+ "pg_catalog.pg_get_constraintdef(con.oid, true), "
+ "contype, condeferrable, condeferred");
+ else
+ appendPQExpBuffer(&buf,
+ "null AS constraintdef, null AS contype, "
+ "false AS condeferrable, false AS condeferred");
+ 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"
+ "\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");
+ 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);
if (!result)
printTableAddFooter(&cont, _("Indexes:"));
for (i = 0; i < tuples; i++)
{
- const char *indexdef;
- const char *usingpos;
-
/* untranslated index name */
printfPQExpBuffer(&buf, " \"%s\"",
PQgetvalue(result, i, 0));
- /* Label as primary key or unique (but not both) */
- appendPQExpBuffer(&buf,
- strcmp(PQgetvalue(result, i, 1), "t") == 0
- ? " PRIMARY KEY," :
- (strcmp(PQgetvalue(result, i, 2), "t") == 0
- ? " UNIQUE,"
- : ""));
- /* Everything after "USING" is echoed verbatim */
- indexdef = PQgetvalue(result, i, 5);
- usingpos = strstr(indexdef, " USING ");
- if (usingpos)
- indexdef = usingpos + 7;
+ /* If exclusion constraint, print the constraintdef */
+ if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
+ {
+ appendPQExpBuffer(&buf, " %s",
+ PQgetvalue(result, i, 6));
+ }
+ else
+ {
+ const char *indexdef;
+ const char *usingpos;
+
+ /* Label as primary key or unique (but not both) */
+ if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
+ appendPQExpBuffer(&buf, " PRIMARY KEY,");
+ else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
+ {
+ if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
+ appendPQExpBuffer(&buf, " UNIQUE CONSTRAINT,");
+ else
+ appendPQExpBuffer(&buf, " UNIQUE,");
+ }
+
+ /* Everything after "USING" is echoed verbatim */
+ indexdef = PQgetvalue(result, i, 5);
+ usingpos = strstr(indexdef, " USING ");
+ if (usingpos)
+ indexdef = usingpos + 7;
+ appendPQExpBuffer(&buf, " %s", indexdef);
- appendPQExpBuffer(&buf, " %s", indexdef);
+ /* Need these for deferrable PK/UNIQUE indexes */
+ if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
+ appendPQExpBuffer(&buf, " DEFERRABLE");
+ if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
+ appendPQExpBuffer(&buf, " INITIALLY DEFERRED");
+ }
+
+ /* Add these for all cases */
if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
appendPQExpBuffer(&buf, " CLUSTER");
/* Print tablespace of the index on the same line */
if (pset.sversion >= 80000)
- add_tablespace_footer(&cont, 'i',
- atooid(PQgetvalue(result, i, 6)),
+ add_tablespace_footer(&cont, 'i',
+ atooid(PQgetvalue(result, i, 10)),
false);
}
}
"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'\nORDER BY 1;",
oid);
result = PSQLexec(buf.data, false);
if (!result)
{
printfPQExpBuffer(&buf,
"SELECT conname,\n"
- " pg_catalog.pg_get_constraintdef(r.oid, true) as condef\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);
if (!result)
if (tableinfo.hastriggers)
{
printfPQExpBuffer(&buf,
- "SELECT conname, conrelid::pg_catalog.regclass,\n"
- " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
+ "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);
if (!result)
printTableAddFooter(&cont, _("Referenced by:"));
for (i = 0; i < tuples; i++)
{
- /* translator: the first %s is a FK name, the following are
- * a table name and the FK definition */
- printfPQExpBuffer(&buf, _(" \"%s\" IN %s %s"),
- PQgetvalue(result, i, 0),
+ printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
PQgetvalue(result, i, 1),
+ PQgetvalue(result, i, 0),
PQgetvalue(result, i, 2));
printTableAddFooter(&cont, buf.data);
"SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
"ev_enabled\n"
"FROM pg_catalog.pg_rewrite r\n"
- "WHERE r.ev_class = '%s' ORDER BY 1",
+ "WHERE r.ev_class = '%s' ORDER BY 1;",
oid);
}
else
"SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
"'O'::char AS ev_enabled\n"
"FROM pg_catalog.pg_rewrite r\n"
- "WHERE r.ev_class = '%s' ORDER BY 1",
+ "WHERE r.ev_class = '%s' ORDER BY 1;",
oid);
}
result = PSQLexec(buf.data, false);
}
PQclear(result);
}
+ }
- /* print triggers (but ignore foreign-key triggers) */
- if (tableinfo.hastriggers)
- {
- printfPQExpBuffer(&buf,
- "SELECT t.tgname, "
- "pg_catalog.pg_get_triggerdef(t.oid), "
- "t.tgenabled\n"
- "FROM pg_catalog.pg_trigger t\n"
- "WHERE t.tgrelid = '%s' AND ",
- oid);
- if (pset.sversion >= 80300)
- appendPQExpBuffer(&buf, "t.tgconstraint = 0");
- 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");
+ /*
+ * Print triggers next, if any (but only user-defined triggers). This
+ * could apply to either a table or a view.
+ */
+ if (tableinfo.hastriggers)
+ {
+ PGresult *result;
+ int tuples;
- result = PSQLexec(buf.data, false);
- if (!result)
- goto error_return;
- else
- tuples = PQntuples(result);
+ printfPQExpBuffer(&buf,
+ "SELECT t.tgname, "
+ "pg_catalog.pg_get_triggerdef(t.oid%s), "
+ "t.tgenabled\n"
+ "FROM pg_catalog.pg_trigger t\n"
+ "WHERE t.tgrelid = '%s' AND ",
+ (pset.sversion >= 90000 ? ", true" : ""),
+ oid);
+ if (pset.sversion >= 90000)
+ appendPQExpBuffer(&buf, "NOT t.tgisinternal");
+ else if (pset.sversion >= 80300)
+ appendPQExpBuffer(&buf, "t.tgconstraint = 0");
+ 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;");
- if (tuples > 0)
- {
- bool have_heading;
- int category;
+ result = PSQLexec(buf.data, false);
+ if (!result)
+ goto error_return;
+ else
+ tuples = PQntuples(result);
- /*
- * split the output into 4 different categories. Enabled triggers,
- * disabled triggers and the two special ALWAYS and REPLICA
- * configurations.
- */
- for (category = 0; category < 4; category++)
+ if (tuples > 0)
+ {
+ bool have_heading;
+ int category;
+
+ /*
+ * split the output into 4 different categories. Enabled triggers,
+ * disabled triggers and the two special ALWAYS and REPLICA
+ * configurations.
+ */
+ for (category = 0; category < 4; category++)
+ {
+ have_heading = false;
+ for (i = 0; i < tuples; i++)
{
- have_heading = false;
- for (i = 0; i < tuples; i++)
+ bool list_trigger;
+ const char *tgdef;
+ const char *usingpos;
+ const char *tgenabled;
+
+ /*
+ * Check if this trigger falls into the current category
+ */
+ tgenabled = PQgetvalue(result, i, 2);
+ list_trigger = false;
+ switch (category)
{
- bool list_trigger;
- const char *tgdef;
- const char *usingpos;
- const char *tgenabled;
+ case 0:
+ if (*tgenabled == 'O' || *tgenabled == 't')
+ list_trigger = true;
+ break;
+ case 1:
+ if (*tgenabled == 'D' || *tgenabled == 'f')
+ list_trigger = true;
+ break;
+ case 2:
+ if (*tgenabled == 'A')
+ list_trigger = true;
+ break;
+ case 3:
+ if (*tgenabled == 'R')
+ list_trigger = true;
+ break;
+ }
+ if (list_trigger == false)
+ continue;
- /* Check if this trigger falls into the current category */
- tgenabled = PQgetvalue(result, i, 2);
- list_trigger = false;
+ /* Print the category heading once */
+ if (have_heading == false)
+ {
switch (category)
{
case 0:
- if (*tgenabled == 'O' || *tgenabled == 't')
- list_trigger = true;
+ printfPQExpBuffer(&buf, _("Triggers:"));
break;
case 1:
- if (*tgenabled == 'D' || *tgenabled == 'f')
- list_trigger = true;
+ printfPQExpBuffer(&buf, _("Disabled triggers:"));
break;
case 2:
- if (*tgenabled == 'A')
- list_trigger = true;
+ printfPQExpBuffer(&buf, _("Triggers firing always:"));
break;
case 3:
- if (*tgenabled == 'R')
- list_trigger = true;
+ printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
break;
- }
- if (list_trigger == false)
- continue;
-
- /* Print the category heading once */
- if (have_heading == false)
- {
- switch (category)
- {
- case 0:
- printfPQExpBuffer(&buf, _("Triggers:"));
- break;
- case 1:
- printfPQExpBuffer(&buf, _("Disabled triggers:"));
- break;
- case 2:
- printfPQExpBuffer(&buf, _("Triggers firing always:"));
- break;
- case 3:
- printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
- break;
- }
- printTableAddFooter(&cont, buf.data);
- have_heading = true;
}
-
- /* Everything after "TRIGGER" is echoed verbatim */
- tgdef = PQgetvalue(result, i, 1);
- usingpos = strstr(tgdef, " TRIGGER ");
- if (usingpos)
- tgdef = usingpos + 9;
-
- printfPQExpBuffer(&buf, " %s", tgdef);
printTableAddFooter(&cont, buf.data);
+ have_heading = true;
}
+
+ /* Everything after "TRIGGER" is echoed verbatim */
+ tgdef = PQgetvalue(result, i, 1);
+ usingpos = strstr(tgdef, " TRIGGER ");
+ if (usingpos)
+ tgdef = usingpos + 9;
+
+ printfPQExpBuffer(&buf, " %s", tgdef);
+ printTableAddFooter(&cont, buf.data);
}
}
+ }
+ PQclear(result);
+ }
+
+ /*
+ * Finish printing the footer information about a table.
+ */
+ if (tableinfo.relkind == 'r' || tableinfo.relkind == 'f')
+ {
+ PGresult *result;
+ int tuples;
+
+ /* print foreign server name */
+ if (tableinfo.relkind == 'f')
+ {
+ /* Footer information about foreign table */
+ printfPQExpBuffer(&buf,
+ "SELECT s.srvname\n"
+ "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);
+ if (!result)
+ goto error_return;
+ else if (PQntuples(result) != 1)
+ {
+ PQclear(result);
+ goto error_return;
+ }
+
+ printfPQExpBuffer(&buf, "Server: %s",
+ PQgetvalue(result, 0, 0));
+ printTableAddFooter(&cont, buf.data);
PQclear(result);
}
/* 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);
+ 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);
if (!result)
}
PQclear(result);
+ /* print child tables */
+ if (pset.sversion >= 80300)
+ 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.oid::pg_catalog.regclass::pg_catalog.text;", oid);
+ 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);
+ if (!result)
+ goto error_return;
+ else
+ tuples = PQntuples(result);
+
+ if (!verbose)
+ {
+ /* print the number of child tables, if any */
+ if (tuples > 0)
+ {
+ printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
+ printTableAddFooter(&cont, buf.data);
+ }
+ }
+ else
+ {
+ /* display the list of child tables */
+ const char *ct = _("Child tables");
+
+ for (i = 0; i < tuples; i++)
+ {
+ if (i == 0)
+ printfPQExpBuffer(&buf, "%s: %s",
+ ct, PQgetvalue(result, i, 0));
+ else
+ printfPQExpBuffer(&buf, "%*s %s",
+ (int) strlen(ct), "",
+ PQgetvalue(result, i, 0));
+ if (i < tuples - 1)
+ appendPQExpBuffer(&buf, ",");
+
+ printTableAddFooter(&cont, buf.data);
+ }
+ }
+ PQclear(result);
+
+ /* Table type */
+ if (tableinfo.reloftype)
+ {
+ printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
+ printTableAddFooter(&cont, buf.data);
+ }
+
+ /* OIDs and options */
if (verbose)
{
const char *s = _("Has OIDs");
termPQExpBuffer(&buf);
termPQExpBuffer(&title);
termPQExpBuffer(&tmpbuf);
-
+
if (seq_values)
{
for (ptr = seq_values; *ptr; ptr++)
free(*ptr);
free(seq_values);
}
-
+
if (modifiers)
{
for (ptr = modifiers; *ptr; ptr++)
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf,
"SELECT spcname FROM pg_catalog.pg_tablespace\n"
- "WHERE oid = '%u'", tablespace);
+ "WHERE oid = '%u';", tablespace);
result = PSQLexec(buf.data, false);
if (!result)
return;
{
/* 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);
if (pset.sversion >= 80100)
{
printfPQExpBuffer(&buf,
- "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
- " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
- " r.rolconnlimit,\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"
- " WHERE m.member = r.oid) as memberof");
+ "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
+ " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
+ " r.rolconnlimit,\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"
+ " WHERE m.member = r.oid) as memberof");
if (verbose && pset.sversion >= 80200)
{
appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
ncols++;
}
+ if (pset.sversion >= 90100)
+ {
+ appendPQExpBufferStr(&buf, "\n, r.rolreplication");
+ }
appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
processSQLNamePattern(pset.db, &buf, pattern, false, false,
NULL, "r.rolname", NULL, NULL);
- }
- else
- {
- printfPQExpBuffer(&buf,
- "SELECT u.usename AS rolname,\n"
- " u.usesuper AS rolsuper,\n"
- " true AS rolinherit, false AS rolcreaterole,\n"
- " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
- " -1 AS rolconnlimit,\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");
+ }
+ else
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT u.usename AS rolname,\n"
+ " u.usesuper AS rolsuper,\n"
+ " true AS rolinherit, false AS rolcreaterole,\n"
+ " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
+ " -1 AS rolconnlimit,\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");
processSQLNamePattern(pset.db, &buf, pattern, false, false,
NULL, "u.usename", NULL, NULL);
- }
+ }
appendPQExpBuffer(&buf, "ORDER BY 1;");
for (i = 0; i < nrows; i++)
{
- printTableAddCell(&cont, PQgetvalue(res, i, 0), false);
+ printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
resetPQExpBuffer(&buf);
if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
add_role_attribute(&buf, _("Cannot login"));
+ if (pset.sversion >= 90100)
+ if (strcmp(PQgetvalue(res, i, (verbose ? 9 : 8)), "t") == 0)
+ add_role_attribute(&buf, _("Replication"));
+
conns = atoi(PQgetvalue(res, i, 6));
if (conns >= 0)
{
if (conns == 0)
appendPQExpBuffer(&buf, _("No connections"));
- else if (conns == 1)
- appendPQExpBuffer(&buf, _("1 connection"));
else
- appendPQExpBuffer(&buf, _("%d connections"), conns);
+ appendPQExpBuffer(&buf, ngettext("%d connection",
+ "%d connections",
+ conns),
+ conns);
}
attr[i] = pg_strdup(buf.data);
- printTableAddCell(&cont, attr[i], false);
+ printTableAddCell(&cont, attr[i], false, false);
- printTableAddCell(&cont, PQgetvalue(res, i, 7), false);
+ printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
if (verbose && pset.sversion >= 80200)
- printTableAddCell(&cont, PQgetvalue(res, i, 8), false);
+ printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
}
termPQExpBuffer(&buf);
return true;
}
-void
+static void
add_role_attribute(PQExpBuffer buf, const char *const str)
{
if (buf->len > 0)
- appendPQExpBufferStr(buf, "\n");
+ appendPQExpBufferStr(buf, ", ");
appendPQExpBufferStr(buf, str);
}
+/*
+ * \drds
+ */
+bool
+listDbRoleSettings(const char *pattern, const char *pattern2)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ initPQExpBuffer(&buf);
+
+ if (pset.sversion >= 90000)
+ {
+ bool havewhere;
+
+ printfPQExpBuffer(&buf, "SELECT rolname AS role, datname AS database,\n"
+ "pg_catalog.array_to_string(setconfig, E'\\n') AS settings\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");
+ 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;");
+ }
+ else
+ {
+ fprintf(pset.queryFout,
+ _("No per-database role settings support in this server version.\n"));
+ return false;
+ }
+
+ res = PSQLexec(buf.data, false);
+ if (!res)
+ return false;
+
+ if (PQntuples(res) == 0 && !pset.quiet)
+ {
+ if (pattern)
+ fprintf(pset.queryFout, _("No matching settings found.\n"));
+ else
+ fprintf(pset.queryFout, _("No settings found.\n"));
+ }
+ else
+ {
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of settings");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+ }
+
+ PQclear(res);
+ resetPQExpBuffer(&buf);
+ return true;
+}
+
/*
* listTables()
*
- * handler for \d, \dt, etc.
+ * handler for \dt, \di, etc.
*
* tabtypes is an array of characters, specifying what info is desired:
* t - tables
* i - indexes
* v - views
* s - sequences
- * S - system tables (pg_catalog)
+ * E - foreign table (Note: different from 'f', the relkind value)
* (any order of the above is fine)
+ * If tabtypes is empty, we default to \dtvsE.
*/
bool
listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
bool showIndexes = strchr(tabtypes, 'i') != NULL;
bool showViews = strchr(tabtypes, 'v') != NULL;
bool showSeq = strchr(tabtypes, 's') != NULL;
+ bool showForeign = strchr(tabtypes, 'E') != NULL;
PQExpBufferData buf;
PGresult *res;
printQueryOpt myopt = pset.popt;
static const bool translate_columns[] = {false, false, true, false, false, false, false};
- if (!(showTables || showIndexes || showViews || showSeq))
- showTables = showViews = showSeq = true;
+ if (!(showTables || showIndexes || showViews || showSeq || showForeign))
+ showTables = showViews = showSeq = showForeign = true;
initPQExpBuffer(&buf);
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' END 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"
" pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
gettext_noop("Schema"),
gettext_noop("Name"),
gettext_noop("index"),
gettext_noop("sequence"),
gettext_noop("special"),
+ gettext_noop("foreign table"),
gettext_noop("Type"),
gettext_noop("Owner"));
",\n c2.relname as \"%s\"",
gettext_noop("Table"));
- if (verbose && pset.sversion >= 80100)
- appendPQExpBuffer(&buf,
- ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
- gettext_noop("Size"));
if (verbose)
+ {
+ /*
+ * As of PostgreSQL 9.0, use pg_table_size() to show a more acurate
+ * size of a table, including FSM, VM and TOAST tables.
+ */
+ if (pset.sversion >= 90000)
+ appendPQExpBuffer(&buf,
+ ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \"%s\"",
+ gettext_noop("Size"));
+ else if (pset.sversion >= 80100)
+ appendPQExpBuffer(&buf,
+ ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
+ gettext_noop("Size"));
+
appendPQExpBuffer(&buf,
",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
gettext_noop("Description"));
+ }
appendPQExpBuffer(&buf,
"\nFROM pg_catalog.pg_class c"
appendPQExpBuffer(&buf, "'i',");
if (showSeq)
appendPQExpBuffer(&buf, "'S',");
- if (showSystem)
- appendPQExpBuffer(&buf, "'s',"); /* was RELKIND_SPECIAL in <= 8.1 */
+ if (showSystem || pattern)
+ appendPQExpBuffer(&buf, "'s',"); /* was RELKIND_SPECIAL in <=
+ * 8.1 */
+ if (showForeign)
+ appendPQExpBuffer(&buf, "'f',");
+
appendPQExpBuffer(&buf, "''"); /* dummy */
appendPQExpBuffer(&buf, ")\n");
- if (!showSystem)
- /* Exclude system and pg_toast objects, but show temp tables */
- appendPQExpBuffer(&buf,
- " AND n.nspname <> 'pg_catalog'\n"
- " AND n.nspname !~ '^pg_toast'\n");
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
+ " AND n.nspname <> 'information_schema'\n");
+
+ /*
+ * TOAST objects are suppressed unconditionally. Since we don't provide
+ * any way to select relkind 't' above, we would never show toast tables
+ * 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");
processSQLNamePattern(pset.db, &buf, pattern, true, false,
"n.nspname", "c.relname", NULL,
}
+/*
+ * \dL
+ *
+ * Describes languages.
+ */
+bool
+listLanguages(const char *pattern, bool verbose, bool showSystem)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ initPQExpBuffer(&buf);
+
+ printfPQExpBuffer(&buf,
+ "SELECT l.lanname AS \"%s\",\n",
+ gettext_noop("Name"));
+ if (pset.sversion >= 80300)
+ appendPQExpBuffer(&buf,
+ " pg_catalog.pg_get_userbyid(l.lanowner) as \"%s\",\n",
+ gettext_noop("Owner"));
+
+ appendPQExpBuffer(&buf,
+ " l.lanpltrusted AS \"%s\"",
+ gettext_noop("Trusted"));
+
+ if (verbose)
+ {
+ appendPQExpBuffer(&buf,
+ ",\n NOT l.lanispl AS \"%s\",\n"
+ " l.lanplcallfoid::regprocedure AS \"%s\",\n"
+ " l.lanvalidator::regprocedure AS \"%s\",\n ",
+ gettext_noop("Internal Language"),
+ gettext_noop("Call Handler"),
+ gettext_noop("Validator"));
+ if (pset.sversion >= 90000)
+ appendPQExpBuffer(&buf, "l.laninline::regprocedure AS \"%s\",\n ",
+ gettext_noop("Inline Handler"));
+ printACLColumn(&buf, "l.lanacl");
+ }
+
+ appendPQExpBuffer(&buf,
+ ",\n d.description AS \"%s\""
+ "\nFROM pg_catalog.pg_language l\n"
+ "LEFT JOIN pg_catalog.pg_description d\n"
+ " ON d.classoid = l.tableoid AND d.objoid = l.oid\n"
+ " AND d.objsubid = 0\n",
+ gettext_noop("Description"));
+
+ if (pattern)
+ processSQLNamePattern(pset.db, &buf, pattern, false, false,
+ NULL, "l.lanname", NULL, NULL);
+
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf, "WHERE l.lanplcallfoid != 0\n");
+
+
+ appendPQExpBuffer(&buf, "ORDER BY 1;");
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of languages");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
+
+
/*
* \dD
*
* Describes domains.
*/
bool
-listDomains(const char *pattern, bool showSystem)
+listDomains(const char *pattern, bool verbose, bool showSystem)
{
PQExpBufferData buf;
PGresult *res;
"SELECT n.nspname as \"%s\",\n"
" t.typname as \"%s\",\n"
" pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
- " CASE WHEN t.typnotnull AND t.typdefault IS NOT NULL THEN 'not null default '||t.typdefault\n"
- " WHEN t.typnotnull AND t.typdefault IS NULL THEN 'not null'\n"
- " WHEN NOT t.typnotnull AND t.typdefault IS NOT NULL THEN 'default '||t.typdefault\n"
- " ELSE ''\n"
- " END as \"%s\",\n"
- " pg_catalog.pg_get_constraintdef(r.oid, true) as \"%s\"\n"
- "FROM pg_catalog.pg_type t\n"
- " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
- " LEFT JOIN pg_catalog.pg_constraint r ON t.oid = r.contypid\n"
- "WHERE t.typtype = 'd'\n",
+ " TRIM(LEADING\n",
gettext_noop("Schema"),
gettext_noop("Name"),
- gettext_noop("Type"),
+ 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");
+ 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"
+ " ) as \"%s\",\n"
+ " pg_catalog.array_to_string(ARRAY(\n"
+ " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
+ " ), ' ') as \"%s\"",
gettext_noop("Modifier"),
gettext_noop("Check"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ if (verbose)
+ 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");
+
+ 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");
+
+ appendPQExpBuffer(&buf, "WHERE t.typtype = 'd'\n");
+
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&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,
* Describes conversions.
*/
bool
-listConversions(const char *pattern, bool showSystem)
+listConversions(const char *pattern, bool verbose, bool showSystem)
{
PQExpBufferData buf;
PGresult *res;
" pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
" pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
" CASE WHEN c.condefault THEN '%s'\n"
- " ELSE '%s' END AS \"%s\"\n"
- "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
- "WHERE n.oid = c.connamespace\n",
+ " ELSE '%s' END AS \"%s\"",
gettext_noop("Schema"),
gettext_noop("Name"),
gettext_noop("Source"),
gettext_noop("yes"), gettext_noop("no"),
gettext_noop("Default?"));
- if (!showSystem)
- appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n");
+ if (verbose)
+ appendPQExpBuffer(&buf,
+ ",\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");
+
+ 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");
+
+ appendPQExpBuffer(&buf, "WHERE true\n");
+
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&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,
* Describes casts.
*/
bool
-listCasts(const char *pattern)
+listCasts(const char *pattern, bool verbose)
{
PQExpBufferData buf;
PGresult *res;
static const bool translate_columns[] = {false, false, false, true};
initPQExpBuffer(&buf);
+
/*
* We need a left join to pg_proc for binary casts; the others are just
* paranoia. Also note that we don't attempt to localize '(binary
printfPQExpBuffer(&buf,
"SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
" pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
- " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
+ " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
" ELSE p.proname\n"
" END as \"%s\",\n"
" CASE WHEN c.castcontext = 'e' THEN '%s'\n"
" WHEN c.castcontext = 'a' THEN '%s'\n"
" ELSE '%s'\n"
- " END as \"%s\"\n"
+ " END as \"%s\"",
+ gettext_noop("Source type"),
+ gettext_noop("Target type"),
+ gettext_noop("Function"),
+ gettext_noop("no"),
+ gettext_noop("in assignment"),
+ gettext_noop("yes"),
+ gettext_noop("Implicit?"));
+
+ if (verbose)
+ appendPQExpBuffer(&buf,
+ ",\n d.description AS \"%s\"\n",
+ gettext_noop("Description"));
+
+ appendPQExpBuffer(&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"
" 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"
- "WHERE (true",
- gettext_noop("Source type"),
- gettext_noop("Target type"),
- gettext_noop("Function"),
- gettext_noop("no"), gettext_noop("in assignment"), gettext_noop("yes"),
- gettext_noop("Implicit?"));
+ " 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");
+
+ appendPQExpBuffer(&buf, "WHERE ( (true");
/*
* Match name pattern against either internal or external name of either
"pg_catalog.format_type(tt.oid, NULL)",
"pg_catalog.pg_type_is_visible(tt.oid)");
- appendPQExpBuffer(&buf, ")\nORDER BY 1, 2;");
+ appendPQExpBuffer(&buf, ") )\nORDER BY 1, 2;");
res = PSQLexec(buf.data, false);
termPQExpBuffer(&buf);
return true;
}
+/*
+ * \dO
+ *
+ * Describes collations.
+ */
+bool
+listCollations(const char *pattern, bool verbose, bool showSystem)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+ static const bool translate_columns[] = {false, false, false, false, false};
+
+ initPQExpBuffer(&buf);
+
+ printfPQExpBuffer(&buf,
+ "SELECT n.nspname AS \"%s\",\n"
+ " c.collname AS \"%s\",\n"
+ " c.collcollate AS \"%s\",\n"
+ " c.collctype AS \"%s\"",
+ gettext_noop("Schema"),
+ gettext_noop("Name"),
+ gettext_noop("Collate"),
+ gettext_noop("Ctype"));
+
+ if (verbose)
+ appendPQExpBuffer(&buf,
+ ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
+ gettext_noop("Description"));
+
+ appendPQExpBuffer(&buf,
+ "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
+ "WHERE n.oid = c.collnamespace\n");
+
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&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.
+ * If you think to change this, note that pg_collation_is_visible rejects
+ * 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");
+
+ 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;");
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of collations");
+ myopt.translate_header = true;
+ myopt.translate_columns = translate_columns;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
+
/*
* \dn
*
* Describes schemas (namespaces)
*/
bool
-listSchemas(const char *pattern, bool verbose)
+listSchemas(const char *pattern, bool verbose, bool showSystem)
{
PQExpBufferData buf;
PGresult *res;
appendPQExpBuffer(&buf, ",\n ");
printACLColumn(&buf, "n.nspacl");
appendPQExpBuffer(&buf,
- ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
+ ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
gettext_noop("Description"));
}
appendPQExpBuffer(&buf,
- "\nFROM pg_catalog.pg_namespace n\n"
- "WHERE (n.nspname !~ '^pg_temp_' OR\n"
- " n.nspname = (pg_catalog.current_schemas(true))[1])\n"); /* temp schema is first */
+ "\nFROM pg_catalog.pg_namespace n\n");
- processSQLNamePattern(pset.db, &buf, pattern, true, false,
+ if (!showSystem && !pattern)
+ appendPQExpBuffer(&buf,
+ "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
+
+ processSQLNamePattern(pset.db, &buf, pattern,
+ !showSystem && !pattern, false,
NULL, "n.nspname", NULL,
NULL);
" p.prslextype::pg_catalog.regproc, \n"
" pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
" FROM pg_catalog.pg_ts_parser p \n"
- " WHERE p.oid = '%s' \n",
+ " WHERE p.oid = '%s';",
gettext_noop("Start parse"),
gettext_noop("Method"),
gettext_noop("Function"),
"FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n"
"WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
"GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
- "ORDER BY 1",
+ "ORDER BY 1;",
gettext_noop("Token"),
gettext_noop("Dictionaries"),
oid);
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf,
"SELECT fdwname AS \"%s\",\n"
- " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n"
- " fdwlibrary AS \"%s\"",
+ " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n",
gettext_noop("Name"),
- gettext_noop("Owner"),
- gettext_noop("Library"));
+ gettext_noop("Owner"));
+ if (pset.sversion >= 90100)
+ appendPQExpBuffer(&buf,
+ " fdwhandler::pg_catalog.regproc AS \"%s\",\n",
+ gettext_noop("Handler"));
+ appendPQExpBuffer(&buf,
+ " fdwvalidator::pg_catalog.regproc AS \"%s\"",
+ gettext_noop("Validator"));
if (verbose)
{
/*
* \des
*
- * Describes foreign-data servers.
+ * Describes foreign servers.
*/
bool
listForeignServers(const char *pattern, bool verbose)
if (pset.sversion < 80400)
{
- fprintf(stderr, _("The server (version %d.%d) does not support foreign-data servers.\n"),
+ fprintf(stderr, _("The server (version %d.%d) does not support foreign servers.\n"),
pset.sversion / 10000, (pset.sversion / 100) % 100);
return true;
}
}
appendPQExpBuffer(&buf,
- "\nFROM pg_catalog.pg_foreign_server s\n"
- " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
+ "\nFROM pg_catalog.pg_foreign_server s\n"
+ " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
processSQLNamePattern(pset.db, &buf, pattern, false, false,
NULL, "s.srvname", NULL, NULL);
if (pset.sversion < 80400)
{
- fprintf(stderr, _("The server (version %d.%d) does not support foreign-data user mappings.\n"),
+ fprintf(stderr, _("The server (version %d.%d) does not support user mappings.\n"),
pset.sversion / 10000, (pset.sversion / 100) % 100);
return true;
}
"SELECT um.srvname AS \"%s\",\n"
" um.usename AS \"%s\"",
gettext_noop("Server"),
- gettext_noop("Username"));
+ gettext_noop("User name"));
if (verbose)
appendPQExpBuffer(&buf,
return true;
}
+/*
+ * \det
+ *
+ * Describes foreign tables.
+ */
+bool
+listForeignTables(const char *pattern, bool verbose)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ if (pset.sversion < 90100)
+ {
+ fprintf(stderr, _("The server (version %d.%d) does not support foreign tables.\n"),
+ pset.sversion / 10000, (pset.sversion / 100) % 100);
+ return true;
+ }
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT n.nspname AS \"%s\",\n"
+ " c.relname AS \"%s\",\n"
+ " s.srvname AS \"%s\"",
+ gettext_noop("Schema"),
+ gettext_noop("Table"),
+ gettext_noop("Server"));
+
+ if (verbose)
+ appendPQExpBuffer(&buf,
+ ",\n ft.ftoptions AS \"%s\"",
+ gettext_noop("Options"));
+
+ appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_foreign_table ft,");
+ appendPQExpBuffer(&buf, "\n pg_catalog.pg_class c,");
+ appendPQExpBuffer(&buf, "\n pg_catalog.pg_namespace n,");
+ appendPQExpBuffer(&buf, "\n pg_catalog.pg_foreign_server s\n");
+ appendPQExpBuffer(&buf, "\nWHERE c.oid = ft.ftrelid");
+ appendPQExpBuffer(&buf, "\nAND s.oid = ft.ftserver\n");
+ appendPQExpBuffer(&buf, "\nAND n.oid = c.relnamespace\n");
+
+ processSQLNamePattern(pset.db, &buf, pattern, true, false,
+ NULL, "n.nspname", "c.relname", NULL);
+
+ appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of foreign tables");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
+
+/*
+ * \dx
+ *
+ * Briefly describes installed extensions.
+ */
+bool
+listExtensions(const char *pattern)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ if (pset.sversion < 90100)
+ {
+ fprintf(stderr, _("The server (version %d.%d) does not support extensions.\n"),
+ pset.sversion / 10000, (pset.sversion / 100) % 100);
+ return true;
+ }
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT e.extname AS \"%s\", "
+ "e.extversion AS \"%s\", n.nspname AS \"%s\", c.description AS \"%s\"\n"
+ "FROM pg_catalog.pg_extension e "
+ "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
+ "LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
+ "AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass\n",
+ gettext_noop("Name"),
+ gettext_noop("Version"),
+ gettext_noop("Schema"),
+ gettext_noop("Description"));
+
+ processSQLNamePattern(pset.db, &buf, pattern,
+ false, false,
+ NULL, "e.extname", NULL,
+ NULL);
+
+ appendPQExpBuffer(&buf, "ORDER BY 1;");
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of installed extensions");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
+
+/*
+ * \dx+
+ *
+ * List contents of installed extensions.
+ */
+bool
+listExtensionContents(const char *pattern)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ int i;
+
+ if (pset.sversion < 90100)
+ {
+ fprintf(stderr, _("The server (version %d.%d) does not support extensions.\n"),
+ pset.sversion / 10000, (pset.sversion / 100) % 100);
+ return true;
+ }
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT e.extname, e.oid\n"
+ "FROM pg_catalog.pg_extension e\n");
+
+ processSQLNamePattern(pset.db, &buf, pattern,
+ false, false,
+ NULL, "e.extname", NULL,
+ NULL);
+
+ appendPQExpBuffer(&buf, "ORDER BY 1;");
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ if (PQntuples(res) == 0)
+ {
+ if (!pset.quiet)
+ {
+ if (pattern)
+ fprintf(stderr, _("Did not find any extension named \"%s\".\n"),
+ pattern);
+ else
+ fprintf(stderr, _("Did not find any extensions.\n"));
+ }
+ PQclear(res);
+ return false;
+ }
+
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ const char *extname;
+ const char *oid;
+
+ extname = PQgetvalue(res, i, 0);
+ oid = PQgetvalue(res, i, 1);
+
+ if (!listOneExtensionContents(extname, oid))
+ {
+ PQclear(res);
+ return false;
+ }
+ if (cancel_pressed)
+ {
+ PQclear(res);
+ return false;
+ }
+ }
+
+ PQclear(res);
+ return true;
+}
+
+static bool
+listOneExtensionContents(const char *extname, const char *oid)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ char title[1024];
+ printQueryOpt myopt = pset.popt;
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS \"%s\"\n"
+ "FROM pg_catalog.pg_depend\n"
+ "WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '%s' AND deptype = 'e'\n"
+ "ORDER BY 1;",
+ gettext_noop("Object Description"),
+ oid);
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ snprintf(title, sizeof(title), _("Objects in extension \"%s\""), extname);
+ myopt.title = title;
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
+
/*
* 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