summaryrefslogtreecommitdiff
path: root/src/bin/psql/describe.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/psql/describe.c')
-rw-r--r--src/bin/psql/describe.c1138
1 files changed, 0 insertions, 1138 deletions
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
deleted file mode 100644
index 297875e0bec..00000000000
--- a/src/bin/psql/describe.c
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*
- * psql - the PostgreSQL interactive terminal
- *
- * Copyright 2000 by PostgreSQL Global Development Group
- *
- * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.54 2002/05/13 17:45:30 tgl Exp $
- */
-#include "postgres_fe.h"
-#include "describe.h"
-
-#include "libpq-fe.h"
-#include "pqexpbuffer.h"
-
-#include "common.h"
-#include "settings.h"
-#include "print.h"
-#include "variables.h"
-
-#define _(x) gettext((x))
-
-
-/*----------------
- * Handlers for various slash commands displaying some sort of list
- * of things in the database.
- *
- * If you add something here, try to format the query to look nice in -E output.
- *----------------
- */
-
-
-/* \da
- * takes an optional regexp to match specific aggregates by name
- */
-bool
-describeAggregates(const char *name)
-{
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- /*
- * There are two kinds of aggregates: ones that work on particular
- * types and ones that work on all (denoted by input type = 0)
- */
- printfPQExpBuffer(&buf,
- "SELECT p.proname AS \"%s\",\n"
- " CASE p.proargtypes[0]\n"
- " WHEN 0 THEN CAST('%s' AS text)\n"
- " ELSE format_type(p.proargtypes[0], NULL)\n"
- " END AS \"%s\",\n"
- " obj_description(p.oid, 'pg_proc') as \"%s\"\n"
- "FROM pg_proc p\n"
- "WHERE p.proisagg\n",
- _("Name"), _("(all types)"),
- _("Data type"), _("Description"));
-
- if (name)
- appendPQExpBuffer(&buf, " AND p.proname ~ '^%s'\n", name);
-
- appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- myopt.nullPrint = NULL;
- myopt.title = _("List of aggregate functions");
-
- printQuery(res, &myopt, pset.queryFout);
-
- PQclear(res);
- return true;
-}
-
-
-/* \df
- * Takes an optional regexp to narrow down the function name
- */
-bool
-describeFunctions(const char *name, bool verbose)
-{
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- /*
- * we skip in/out funcs by excluding functions that take some
- * arguments, but have no types defined for those arguments
- */
- printfPQExpBuffer(&buf,
- "SELECT format_type(p.prorettype, NULL) as \"%s\",\n"
- " p.proname as \"%s\",\n"
- " oidvectortypes(p.proargtypes) as \"%s\"",
- _("Result data type"), _("Name"),
- _("Argument data types"));
-
- if (verbose)
- appendPQExpBuffer(&buf,
- ",\n u.usename as \"%s\",\n"
- " l.lanname as \"%s\",\n"
- " p.prosrc as \"%s\",\n"
- " obj_description(p.oid, 'pg_proc') as \"%s\"",
- _("Owner"), _("Language"),
- _("Source code"), _("Description"));
-
- if (!verbose)
- appendPQExpBuffer(&buf,
- "\nFROM pg_proc p\n"
- "WHERE p.prorettype <> 0 AND (pronargs = 0 OR oidvectortypes(p.proargtypes) <> '') AND NOT p.proisagg\n");
- else
- appendPQExpBuffer(&buf,
- "\nFROM pg_proc p, pg_language l, pg_user u\n"
- "WHERE p.prolang = l.oid AND p.proowner = u.usesysid\n"
- " AND p.prorettype <> 0 AND (pronargs = 0 OR oidvectortypes(p.proargtypes) <> '') AND NOT p.proisagg\n");
-
- if (name)
- appendPQExpBuffer(&buf, " AND p.proname ~ '^%s'\n", name);
- appendPQExpBuffer(&buf, "ORDER BY 2, 1, 3;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- myopt.nullPrint = NULL;
- myopt.title = _("List of functions");
-
- printQuery(res, &myopt, pset.queryFout);
-
- PQclear(res);
- return true;
-}
-
-
-
-/*
- * \dT
- * describe types
- */
-bool
-describeTypes(const char *name, bool verbose)
-{
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- printfPQExpBuffer(&buf,
- "SELECT format_type(t.oid, NULL) AS \"%s\",\n",
- _("Name"));
- if (verbose)
- appendPQExpBuffer(&buf,
- " t.typname AS \"%s\",\n"
- " CASE WHEN t.typlen = -1\n"
- " THEN CAST('var' AS text)\n"
- " ELSE CAST(t.typlen AS text)\n"
- " END AS \"%s\",\n",
- _("Internal name"), _("Size"));
- appendPQExpBuffer(&buf,
- " obj_description(t.oid, 'pg_type') as \"%s\"\n",
- _("Description"));
-
- /*
- * do not include array types (start with underscore), do not include
- * user relations (typrelid!=0)
- */
- appendPQExpBuffer(&buf, "FROM pg_type t\nWHERE t.typrelid = 0 AND t.typname !~ '^_.*'\n");
-
- if (name)
- /* accept either internal or external type name */
- appendPQExpBuffer(&buf, " AND (format_type(t.oid, NULL) ~ '^%s' OR t.typname ~ '^%s')\n", name, name);
-
- appendPQExpBuffer(&buf, "ORDER BY 1;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- myopt.nullPrint = NULL;
- myopt.title = _("List of data types");
-
- printQuery(res, &myopt, pset.queryFout);
-
- PQclear(res);
- return true;
-}
-
-
-
-/* \do
- */
-bool
-describeOperators(const char *name)
-{
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- printfPQExpBuffer(&buf,
- "SELECT o.oprname AS \"%s\",\n"
- " CASE WHEN o.oprkind='l' THEN NULL ELSE format_type(o.oprleft, NULL) END AS \"%s\",\n"
- " CASE WHEN o.oprkind='r' THEN NULL ELSE format_type(o.oprright, NULL) END AS \"%s\",\n"
- " format_type(o.oprresult, NULL) AS \"%s\",\n"
- " coalesce(obj_description(o.oid, 'pg_operator'),"
- " obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
- "FROM pg_operator o\n",
- _("Name"), _("Left arg type"), _("Right arg type"),
- _("Result type"), _("Description"));
- if (name)
- appendPQExpBuffer(&buf, "WHERE o.oprname = '%s'\n", name);
-
- appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- myopt.nullPrint = NULL;
- myopt.title = _("List of operators");
-
- printQuery(res, &myopt, pset.queryFout);
-
- PQclear(res);
- return true;
-}
-
-
-/*
- * listAllDbs
- *
- * for \l, \list, and -l switch
- */
-bool
-listAllDbs(bool desc)
-{
- PGresult *res;
- PQExpBufferData buf;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- printfPQExpBuffer(&buf,
- "SELECT d.datname as \"%s\",\n"
- " u.usename as \"%s\"",
- _("Name"), _("Owner"));
-#ifdef MULTIBYTE
- appendPQExpBuffer(&buf,
- ",\n pg_encoding_to_char(d.encoding) as \"%s\"",
- _("Encoding"));
-#endif
- if (desc)
- appendPQExpBuffer(&buf,
- ",\n obj_description(d.oid, 'pg_database') as \"%s\"",
- _("Description"));
- appendPQExpBuffer(&buf,
- "\nFROM pg_database d LEFT JOIN pg_user u ON d.datdba = u.usesysid\n"
- "ORDER BY 1;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- myopt.nullPrint = NULL;
- myopt.title = _("List of databases");
-
- printQuery(res, &myopt, pset.queryFout);
-
- PQclear(res);
- return true;
-}
-
-
-/*
- * List Tables Grant/Revoke Permissions
- * \z (now also \dp -- perhaps more mnemonic)
- */
-bool
-permissionsList(const char *name)
-{
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- /* Currently, we ignore indexes since they have no meaningful rights */
- printfPQExpBuffer(&buf,
- "SELECT relname as \"%s\",\n"
- " relacl as \"%s\"\n"
- "FROM pg_class\n"
- "WHERE relkind in ('r', 'v', 'S') AND\n"
- " relname NOT LIKE 'pg$_%%' ESCAPE '$'\n",
- _("Table"), _("Access privileges"));
- if (name)
- appendPQExpBuffer(&buf, " AND relname ~ '^%s'\n", name);
- appendPQExpBuffer(&buf, "ORDER BY 1;");
-
- res = PSQLexec(buf.data);
- if (!res)
- {
- termPQExpBuffer(&buf);
- return false;
- }
-
- myopt.nullPrint = NULL;
- printfPQExpBuffer(&buf, _("Access privileges for database \"%s\""), PQdb(pset.db));
- myopt.title = buf.data;
-
- printQuery(res, &myopt, pset.queryFout);
-
- termPQExpBuffer(&buf);
- PQclear(res);
- return true;
-}
-
-
-
-/*
- * Get object comments
- *
- * \dd [foo]
- *
- * Note: This only lists things that actually have a description. For complete
- * lists of things, there are other \d? commands.
- */
-bool
-objectDescription(const char *object)
-{
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- printfPQExpBuffer(&buf,
- "SELECT DISTINCT tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
- "FROM (\n"
-
- /* Aggregate descriptions */
- " SELECT p.oid as oid, p.tableoid as tableoid,\n"
- " CAST(p.proname AS text) as name, CAST('%s' AS text) as object\n"
- " FROM pg_proc p\n"
- " WHERE p.proisagg\n"
-
- /* Function descriptions (except in/outs for datatypes) */
- "UNION ALL\n"
- " SELECT p.oid as oid, p.tableoid as tableoid,\n"
- " CAST(p.proname AS text) as name, CAST('%s' AS text) as object\n"
- " FROM pg_proc p\n"
- " WHERE (p.pronargs = 0 or oidvectortypes(p.proargtypes) <> '') AND NOT p.proisagg\n"
-
- /* Operator descriptions (only if operator has its own comment) */
- "UNION ALL\n"
- " SELECT o.oid as oid, o.tableoid as tableoid,\n"
- " CAST(o.oprname AS text) as name, CAST('%s' AS text) as object\n"
- " FROM pg_operator o\n"
-
- /* Type description */
- "UNION ALL\n"
- " SELECT t.oid as oid, t.tableoid as tableoid,\n"
- " format_type(t.oid, NULL) as name, CAST('%s' AS text) as object\n"
- " FROM pg_type t\n"
-
- /* Relation (tables, views, indexes, sequences) descriptions */
- "UNION ALL\n"
- " SELECT c.oid as oid, c.tableoid as tableoid,\n"
- " CAST(c.relname AS 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"
- " AS text) as object\n"
- " FROM pg_class c\n"
-
- /* Rule description (ignore rules for views) */
- "UNION ALL\n"
- " SELECT r.oid as oid, r.tableoid as tableoid,\n"
- " CAST(r.rulename AS text) as name, CAST('%s' AS text) as object\n"
- " FROM pg_rewrite r\n"
- " WHERE r.rulename != '_RETURN'\n"
-
- /* Trigger description */
- "UNION ALL\n"
- " SELECT t.oid as oid, t.tableoid as tableoid,\n"
- " CAST(t.tgname AS text) as name, CAST('%s' AS text) as object\n"
- " FROM pg_trigger t\n"
-
- ") AS tt,\n"
- "pg_description d\n"
- "WHERE tt.oid = d.objoid and tt.tableoid = d.classoid and d.objsubid = 0\n",
-
- _("Name"), _("Object"), _("Description"),
- _("aggregate"), _("function"), _("operator"),
- _("data type"), _("table"), _("view"),
- _("index"), _("sequence"), _("rule"),
- _("trigger")
- );
-
- if (object)
- appendPQExpBuffer(&buf, " AND tt.name ~ '^%s'\n", object);
- appendPQExpBuffer(&buf, "ORDER BY 1;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- myopt.nullPrint = NULL;
- myopt.title = _("Object descriptions");
-
- printQuery(res, &myopt, pset.queryFout);
-
- PQclear(res);
- return true;
-}
-
-
-
-/*
- * describeTableDetails (for \d)
- *
- * Unfortunately, the information presented here is so complicated that it cannot
- * be done in a single query. So we have to assemble the printed table by hand
- * and pass it to the underlying printTable() function.
- *
- */
-
-static void *
-xmalloc(size_t size)
-{
- void *tmp;
-
- tmp = malloc(size);
- if (!tmp)
- {
- psql_error("out of memory\n");
- exit(EXIT_FAILURE);
- }
- return tmp;
-}
-
-
-bool
-describeTableDetails(const char *name, bool desc)
-{
- PQExpBufferData buf;
- PGresult *res = NULL;
- printTableOpt myopt = pset.popt.topt;
- int i;
- const char *view_def = NULL;
- const char *headers[5];
- char **cells = NULL;
- char **footers = NULL;
- char **ptr;
- PQExpBufferData title;
- unsigned int cols = 0;
- struct
- {
- bool hasindex;
- char relkind;
- int16 checks;
- int16 triggers;
- bool hasrules;
- } tableinfo;
- bool retval;
-
- retval = false;
-
- initPQExpBuffer(&buf);
- initPQExpBuffer(&title);
-
- /* Get general table info */
- printfPQExpBuffer(&buf,
- "SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules\n"
- "FROM pg_class WHERE relname='%s'",
- name);
- res = PSQLexec(buf.data);
- if (!res)
- goto error_return;
-
- /* Did we get anything? */
- if (PQntuples(res) == 0)
- {
- if (!QUIET())
- fprintf(stderr, _("Did not find any relation named \"%s\".\n"), name);
- PQclear(res);
- res = NULL;
- goto error_return;
- }
-
- /* FIXME: check for null pointers here? */
- tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 0), "t") == 0;
- tableinfo.relkind = *(PQgetvalue(res, 0, 1));
- tableinfo.checks = atoi(PQgetvalue(res, 0, 2));
- tableinfo.triggers = atoi(PQgetvalue(res, 0, 3));
- tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
- PQclear(res);
-
-
- headers[0] = _("Column");
- headers[1] = _("Type");
- cols = 2;
-
- if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
- {
- cols++;
- headers[cols - 1] = _("Modifiers");
- }
-
- if (desc)
- {
- cols++;
- headers[cols - 1] = _("Description");
- }
-
- headers[cols] = NULL;
-
-
- /* Get column info (index requires additional checks) */
- if (tableinfo.relkind == 'i')
- printfPQExpBuffer(&buf, "SELECT\n CASE i.indproc WHEN ('-'::regproc) THEN a.attname\n ELSE SUBSTR(pg_get_indexdef(attrelid),\n POSITION('(' in pg_get_indexdef(attrelid)))\n END, ");
- else
- printfPQExpBuffer(&buf, "SELECT a.attname, ");
- appendPQExpBuffer(&buf, "format_type(a.atttypid, a.atttypmod), a.attnotnull, a.atthasdef, a.attnum");
- if (desc)
- appendPQExpBuffer(&buf, ", col_description(a.attrelid, a.attnum)");
- appendPQExpBuffer(&buf, "\nFROM pg_class c, pg_attribute a");
- if (tableinfo.relkind == 'i')
- appendPQExpBuffer(&buf, ", pg_index i");
- appendPQExpBuffer(&buf, "\nWHERE c.relname = '%s'\n AND a.attnum > 0 AND a.attrelid = c.oid", name);
- if (tableinfo.relkind == 'i')
- appendPQExpBuffer(&buf, " AND a.attrelid = i.indexrelid");
- appendPQExpBuffer(&buf, "\nORDER BY a.attnum");
-
- res = PSQLexec(buf.data);
- if (!res)
- goto error_return;
-
- /* Check if table is a view */
- if (tableinfo.hasrules)
- {
- PGresult *result;
-
- printfPQExpBuffer(&buf, "SELECT definition FROM pg_views WHERE viewname = '%s'", name);
- result = PSQLexec(buf.data);
- if (!result)
- {
- PQclear(res);
- PQclear(result);
- goto error_return;
- }
-
- if (PQntuples(result) > 0)
- view_def = xstrdup(PQgetvalue(result, 0, 0));
- PQclear(result);
- }
-
-
- /* Generate table cells to be printed */
- cells = xmalloc((PQntuples(res) * cols + 1) * sizeof(*cells));
- cells[PQntuples(res) * cols] = NULL; /* end of list */
-
- for (i = 0; i < PQntuples(res); i++)
- {
- /* Name */
- cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this
- * afterwards */
- /* Type */
- cells[i * cols + 1] = PQgetvalue(res, i, 1); /* don't free this
- * either */
-
- /* Extra: not null and default */
- /* (I'm cutting off the 'default' string at 128) */
- if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
- {
- cells[i * cols + 2] = xmalloc(128 + 128);
- cells[i * cols + 2][0] = '\0';
- if (strcmp(PQgetvalue(res, i, 2), "t") == 0)
- strcat(cells[i * cols + 2], "not null");
-
- /* handle "default" here */
- if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
- {
- PGresult *result;
-
- printfPQExpBuffer(&buf,
- "SELECT substring(d.adsrc for 128) FROM pg_attrdef d, pg_class c\n"
- "WHERE c.relname = '%s' AND c.oid = d.adrelid AND d.adnum = %s",
- name, PQgetvalue(res, i, 4));
-
- result = PSQLexec(buf.data);
-
- if (cells[i * cols + 2][0])
- strcat(cells[i * cols + 2], " ");
- strcat(cells[i * cols + 2], "default ");
- strcat(cells[i * cols + 2], result ? PQgetvalue(result, 0, 0) : "?");
-
- PQclear(result);
- }
- }
-
- /* Description */
- if (desc)
- cells[i * cols + cols - 1] = PQgetvalue(res, i, 5);
- }
-
- /* Make title */
- switch (tableinfo.relkind)
- {
- case 'r':
- printfPQExpBuffer(&title, _("Table \"%s\""), name);
- break;
- case 'v':
- printfPQExpBuffer(&title, _("View \"%s\""), name);
- break;
- case 'S':
- printfPQExpBuffer(&title, _("Sequence \"%s\""), name);
- break;
- case 'i':
- printfPQExpBuffer(&title, _("Index \"%s\""), name);
- break;
- case 's':
- printfPQExpBuffer(&title, _("Special relation \"%s\""), name);
- break;
- case 't':
- printfPQExpBuffer(&title, _("TOAST table \"%s\""), name);
- break;
- default:
- printfPQExpBuffer(&title, _("?%c? \"%s\""), tableinfo.relkind, name);
- break;
- }
-
- /* Make footers */
- if (tableinfo.relkind == 'i')
- {
- /* Footer information about an index */
- PGresult *result;
- printfPQExpBuffer(&buf,
- "SELECT i.indisunique, i.indisprimary, a.amname, c2.relname,\n"
- "pg_get_expr(i.indpred,i.indrelid)\n"
- "FROM pg_index i, pg_class c, pg_class c2, pg_am a\n"
- "WHERE i.indexrelid = c.oid AND c.relname = '%s' AND c.relam = a.oid\n"
- "AND i.indrelid = c2.oid",
- name);
-
- result = PSQLexec(buf.data);
- if (!result)
- goto error_return;
- else if (PQntuples(result) != 1)
- {
- PQclear(result);
- goto error_return;
- }
- else
- {
- PQExpBufferData tmpbuf;
- char *indisunique = PQgetvalue(result, 0, 0);
- char *indisprimary = PQgetvalue(result, 0, 1);
- char *indamname = PQgetvalue(result, 0, 2);
- char *indtable = PQgetvalue(result, 0, 3);
- char *indpred = PQgetvalue(result, 0, 4);
-
- initPQExpBuffer(&tmpbuf);
-
- if (strcmp(indisprimary, "t") == 0)
- printfPQExpBuffer(&tmpbuf, _("primary key, "));
- else if (strcmp(indisunique, "t") == 0)
- printfPQExpBuffer(&tmpbuf, _("unique, "));
- else
- resetPQExpBuffer(&tmpbuf);
- appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
-
- appendPQExpBuffer(&tmpbuf, _("for table \"%s\""), indtable);
- if (strlen(indpred))
- appendPQExpBuffer(&tmpbuf, ", predicate %s", indpred);
-
- footers = xmalloc(2 * sizeof(*footers));
- footers[0] = xstrdup(tmpbuf.data);
- footers[1] = NULL;
- termPQExpBuffer(&tmpbuf);
- }
-
- PQclear(result);
- }
- else if (view_def)
- {
- PGresult *result = NULL;
- int rule_count = 0;
- int count_footers = 0;
-
- /* count rules */
- if (tableinfo.hasrules)
- {
- printfPQExpBuffer(&buf,
- "SELECT r.rulename\n"
- "FROM pg_rewrite r, pg_class c\n"
- "WHERE c.relname = '%s' AND c.oid = r.ev_class\n"
- "AND r.rulename != '_RETURN'",
- name);
- result = PSQLexec(buf.data);
- if (!result)
- goto error_return;
- else
- rule_count = PQntuples(result);
- }
-
- /* Footer information about a view */
- footers = xmalloc((rule_count + 2) * sizeof(*footers));
- footers[count_footers] = xmalloc(64 + strlen(view_def));
- snprintf(footers[count_footers], 64 + strlen(view_def),
- _("View definition: %s"), view_def);
- count_footers++;
-
- /* print rules */
- for (i = 0; i < rule_count; i++)
- {
- char *s = _("Rules");
-
- 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 < rule_count - 1)
- appendPQExpBuffer(&buf, ",");
-
- footers[count_footers++] = xstrdup(buf.data);
- }
- PQclear(result);
-
- footers[count_footers] = NULL;
-
- }
- else if (tableinfo.relkind == 'r')
- {
- /* Footer information about a table */
- PGresult *result1 = NULL,
- *result2 = NULL,
- *result3 = NULL,
- *result4 = NULL;
- int index_count = 0,
- constr_count = 0,
- rule_count = 0,
- trigger_count = 0;
- int count_footers = 0;
-
- /* count indexes */
- if (tableinfo.hasindex)
- {
- printfPQExpBuffer(&buf,
- "SELECT c2.relname, i.indisprimary, i.indisunique,\n"
- "SUBSTR(pg_get_indexdef(i.indexrelid),\n"
- "POSITION('USING ' IN pg_get_indexdef(i.indexrelid))+5)\n"
- "FROM pg_class c, pg_class c2, pg_index i\n"
- "WHERE c.relname = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
- "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
- name);
- result1 = PSQLexec(buf.data);
- if (!result1)
- goto error_return;
- else
- index_count = PQntuples(result1);
- }
-
- /* count table (and column) constraints */
- if (tableinfo.checks)
- {
- printfPQExpBuffer(&buf,
- "SELECT rcsrc, rcname\n"
- "FROM pg_relcheck r, pg_class c\n"
- "WHERE c.relname='%s' AND c.oid = r.rcrelid",
- name);
- result2 = PSQLexec(buf.data);
- if (!result2)
- goto error_return;
- else
- constr_count = PQntuples(result2);
- }
-
- /* count rules */
- if (tableinfo.hasrules)
- {
- printfPQExpBuffer(&buf,
- "SELECT r.rulename\n"
- "FROM pg_rewrite r, pg_class c\n"
- "WHERE c.relname='%s' AND c.oid = r.ev_class",
- name);
- result3 = PSQLexec(buf.data);
- if (!result3)
- goto error_return;
- else
- rule_count = PQntuples(result3);
- }
-
- /* count triggers */
- if (tableinfo.triggers)
- {
- printfPQExpBuffer(&buf,
- "SELECT t.tgname\n"
- "FROM pg_trigger t, pg_class c\n"
- "WHERE c.relname='%s' AND c.oid = t.tgrelid",
- name);
- result4 = PSQLexec(buf.data);
- if (!result4)
- goto error_return;
- else
- trigger_count = PQntuples(result4);
- }
-
- footers = xmalloc((index_count + constr_count + rule_count + trigger_count + 1)
- * sizeof(*footers));
-
- /* print indexes */
- for (i = 0; i < index_count; i++)
- {
- char *s = _("Indexes");
-
- if (i == 0)
- printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result1, i, 0));
- else
- printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result1, i, 0));
-
- /* Label as primary key or unique (but not both) */
- appendPQExpBuffer(&buf,
- strcmp(PQgetvalue(result1,i,1),"t") == 0
- ? _(" primary key") :
- (strcmp(PQgetvalue(result1,i,2),"t") == 0
- ? _(" unique")
- : ""));
-
- /* Everything after "USING" is echoed verbatim */
- appendPQExpBuffer(&buf, "%s", PQgetvalue(result1,i,3));
-
- if (i < index_count - 1)
- appendPQExpBuffer(&buf, ",");
-
- footers[count_footers++] = xstrdup(buf.data);
- }
-
-
- /* print constraints */
- for (i = 0; i < constr_count; i++)
- {
- char *s = _("Check constraints");
-
- if (i == 0)
- printfPQExpBuffer(&buf, _("%s: \"%s\" %s"),
- s,
- PQgetvalue(result2, i, 1),
- PQgetvalue(result2, i, 0));
- else
- printfPQExpBuffer(&buf, _("%*s \"%s\" %s"),
- (int) strlen(s), "",
- PQgetvalue(result2, i, 1),
- PQgetvalue(result2, i, 0));
- footers[count_footers++] = xstrdup(buf.data);
- }
-
- /* print rules */
- for (i = 0; i < rule_count; i++)
- {
- char *s = _("Rules");
-
- if (i == 0)
- printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result3, i, 0));
- else
- printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result3, i, 0));
- if (i < rule_count - 1)
- appendPQExpBuffer(&buf, ",");
-
- footers[count_footers++] = xstrdup(buf.data);
- }
-
- /* print triggers */
- for (i = 0; i < trigger_count; i++)
- {
- char *s = _("Triggers");
-
- if (i == 0)
- printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result4, i, 0));
- else
- printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result4, i, 0));
- if (i < trigger_count - 1)
- appendPQExpBuffer(&buf, ",");
-
- footers[count_footers++] = xstrdup(buf.data);
- }
-
- /* end of list marker */
- footers[count_footers] = NULL;
-
- PQclear(result1);
- PQclear(result2);
- PQclear(result3);
- PQclear(result4);
- }
-
- printTable(title.data, headers,
- (const char **) cells, (const char **) footers,
- "llll", &myopt, pset.queryFout);
-
- retval = true;
-
-error_return:
-
- /* clean up */
- termPQExpBuffer(&buf);
- termPQExpBuffer(&title);
-
- if (cells)
- {
- for (i = 0; i < PQntuples(res); i++)
- if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
- free(cells[i * cols + 2]);
- free(cells);
- }
-
- if (footers)
- {
- for (ptr = footers; *ptr; ptr++)
- free(*ptr);
- free(footers);
- }
-
- if (res)
- PQclear(res);
-
- return retval;
-}
-
-
-/*
- * \du [user]
- *
- * Describes users, possibly based on a simplistic prefix search on the
- * argument.
- */
-bool
-describeUsers(const char *name)
-{
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- printfPQExpBuffer(&buf,
- "SELECT u.usename AS \"%s\",\n"
- " u.usesysid AS \"%s\",\n"
- " CASE WHEN u.usesuper AND u.usecreatedb THEN CAST('%s' AS text)\n"
- " WHEN u.usesuper THEN CAST('%s' AS text)\n"
- " WHEN u.usecreatedb THEN CAST('%s' AS text)\n"
- " ELSE CAST('' AS text)\n"
- " END AS \"%s\"\n"
- "FROM pg_user u\n",
- _("User name"), _("User ID"),
- _("superuser, create database"),
- _("superuser"), _("create database"),
- _("Attributes"));
- if (name)
- appendPQExpBuffer(&buf, "WHERE u.usename ~ '^%s'\n", name);
- appendPQExpBuffer(&buf, "ORDER BY 1;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- myopt.nullPrint = NULL;
- myopt.title = _("List of database users");
-
- printQuery(res, &myopt, pset.queryFout);
-
- PQclear(res);
- return true;
-}
-
-
-/*
- * listTables()
- *
- * handler for \d, \dt, etc.
- *
- * The infotype is an array of characters, specifying what info is desired:
- * t - tables
- * i - indexes
- * v - views
- * s - sequences
- * S - systems tables (~ '^pg_')
- * (any order of the above is fine)
- *
- * Note: For some reason it always happens to people that their tables have owners
- * that are no longer in pg_user; consequently they wouldn't show up here. The code
- * tries to fix this the painful way, hopefully outer joins will be done sometime.
- */
-bool
-listTables(const char *infotype, const char *name, bool desc)
-{
- bool showTables = strchr(infotype, 't') != NULL;
- bool showIndexes = strchr(infotype, 'i') != NULL;
- bool showViews = strchr(infotype, 'v') != NULL;
- bool showSeq = strchr(infotype, 's') != NULL;
- bool showSystem = strchr(infotype, 'S') != NULL;
-
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- if (showSystem && !(showSeq || showIndexes || showViews || showTables))
- showTables = showViews = showSeq = true;
-
- initPQExpBuffer(&buf);
-
- printfPQExpBuffer(&buf,
- "SELECT 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"
- " u.usename as \"%s\"",
- _("Name"), _("table"), _("view"), _("index"), _("sequence"),
- _("special"), _("Type"), _("Owner"));
-
- if (desc)
- appendPQExpBuffer(&buf,
- ",\n obj_description(c.oid, 'pg_class') as \"%s\"",
- _("Description"));
- if (showIndexes)
- appendPQExpBuffer(&buf,
- ",\n c2.relname as \"%s\""
- "\nFROM pg_class c, pg_class c2, pg_index i, pg_user u\n"
- "WHERE c.relowner = u.usesysid\n"
- "AND i.indrelid = c2.oid AND i.indexrelid = c.oid\n",
- _("Table"));
- else
- appendPQExpBuffer(&buf,
- "\nFROM pg_class c, pg_user u\n"
- "WHERE c.relowner = u.usesysid\n");
-
- appendPQExpBuffer(&buf, "AND c.relkind IN (");
- if (showTables)
- appendPQExpBuffer(&buf, "'r',");
- if (showViews)
- appendPQExpBuffer(&buf, "'v',");
- if (showIndexes)
- appendPQExpBuffer(&buf, "'i',");
- if (showSeq)
- appendPQExpBuffer(&buf, "'S',");
- if (showSystem && showTables)
- appendPQExpBuffer(&buf, "'s',");
- appendPQExpBuffer(&buf, "''"); /* dummy */
- appendPQExpBuffer(&buf, ")\n");
-
- if (showSystem)
- appendPQExpBuffer(&buf, " AND c.relname ~ '^pg_'\n");
- else
- appendPQExpBuffer(&buf, " AND c.relname !~ '^pg_'\n");
-
- if (name)
- appendPQExpBuffer(&buf, " AND c.relname ~ '^%s'\n", name);
-
- appendPQExpBuffer(&buf, "ORDER BY 1;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- if (PQntuples(res) == 0 && !QUIET())
- {
- if (name)
- fprintf(pset.queryFout, _("No matching relations found.\n"));
- else
- fprintf(pset.queryFout, _("No relations found.\n"));
- }
- else
- {
- myopt.nullPrint = NULL;
- myopt.title = _("List of relations");
-
- printQuery(res, &myopt, pset.queryFout);
- }
-
- PQclear(res);
- return true;
-}
-
-
-/*
- * \dD [domain]
- *
- * Describes domains, possibly based on a simplistic prefix search on the
- * argument.
- */
-bool
-listDomains(const char *name)
-{
- PQExpBufferData buf;
- PGresult *res;
- printQueryOpt myopt = pset.popt;
-
- initPQExpBuffer(&buf);
-
- printfPQExpBuffer(&buf,
- "SELECT t.typname as \"%s\",\n"
- " 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"
- "FROM pg_type t\n"
- "WHERE t.typtype = 'd'\n",
- _("Name"),
- _("Type"),
- _("Modifier"));
- if (name)
- appendPQExpBuffer(&buf, "AND t.typname ~ '^%s'\n", name);
- appendPQExpBuffer(&buf, "ORDER BY 1;");
-
- res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
- if (!res)
- return false;
-
- myopt.nullPrint = NULL;
- myopt.title = _("List of domains");
-
- printQuery(res, &myopt, pset.queryFout);
-
- PQclear(res);
- return true;
-}