2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2007, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.149 2007/01/05 22:19:49 momjian Exp $
8 #include "postgres_fe.h"
11 #include "dumputils.h"
16 #include "variables.h"
22 * mbvalidate() is used in function describeOneTableDetails() to make sure
23 * all characters of the cells will be printed to the DOS console in a
30 static bool describeOneTableDetails(const char *schemaname,
31 const char *relationname,
34 static bool add_tablespace_footer(char relkind, Oid tablespace, char **footers,
35 int *count, PQExpBufferData buf, bool newline);
38 * Handlers for various slash commands displaying some sort of list
39 * of things in the database.
41 * If you add something here, try to format the query to look nice in -E output.
47 * Takes an optional regexp to select particular aggregates
50 describeAggregates(const char *pattern, bool verbose)
54 printQueryOpt myopt = pset.popt;
56 initPQExpBuffer(&buf);
59 * There are two kinds of aggregates: ones that work on particular types
60 * and ones that work on all (denoted by input type = "any")
62 printfPQExpBuffer(&buf,
63 "SELECT n.nspname as \"%s\",\n"
64 " p.proname AS \"%s\",\n"
65 " CASE WHEN p.pronargs = 0\n"
66 " THEN CAST('*' AS pg_catalog.text)\n"
68 " pg_catalog.array_to_string(ARRAY(\n"
70 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
72 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
75 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
76 "FROM pg_catalog.pg_proc p\n"
77 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
79 _("Schema"), _("Name"),
80 _("Argument data types"), _("Description"));
82 processSQLNamePattern(pset.db, &buf, pattern, true, false,
83 "n.nspname", "p.proname", NULL,
84 "pg_catalog.pg_function_is_visible(p.oid)");
86 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
88 res = PSQLexec(buf.data, false);
89 termPQExpBuffer(&buf);
93 myopt.nullPrint = NULL;
94 myopt.title = _("List of aggregate functions");
96 printQuery(res, &myopt, pset.queryFout, pset.logfile);
103 * Takes an optional regexp to select particular tablespaces
106 describeTablespaces(const char *pattern, bool verbose)
110 printQueryOpt myopt = pset.popt;
112 if (pset.sversion < 80000)
114 fprintf(stderr, _("The server version (%d) does not support tablespaces.\n"),
119 initPQExpBuffer(&buf);
121 printfPQExpBuffer(&buf,
122 "SELECT spcname AS \"%s\",\n"
123 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
124 " spclocation AS \"%s\"",
125 _("Name"), _("Owner"), _("Location"));
128 appendPQExpBuffer(&buf,
129 ",\n spcacl as \"%s\""
130 ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
131 _("Access privileges"), _("Description"));
133 appendPQExpBuffer(&buf,
134 "\nFROM pg_catalog.pg_tablespace\n");
136 processSQLNamePattern(pset.db, &buf, pattern, false, false,
137 NULL, "spcname", NULL,
140 appendPQExpBuffer(&buf, "ORDER BY 1;");
142 res = PSQLexec(buf.data, false);
143 termPQExpBuffer(&buf);
147 myopt.nullPrint = NULL;
148 myopt.title = _("List of tablespaces");
150 printQuery(res, &myopt, pset.queryFout, pset.logfile);
158 * Takes an optional regexp to select particular functions
161 describeFunctions(const char *pattern, bool verbose)
165 printQueryOpt myopt = pset.popt;
167 initPQExpBuffer(&buf);
169 printfPQExpBuffer(&buf,
170 "SELECT n.nspname as \"%s\",\n"
171 " p.proname as \"%s\",\n"
172 " CASE WHEN p.proretset THEN 'setof ' ELSE '' END ||\n"
173 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
174 " CASE WHEN proallargtypes IS NOT NULL THEN\n"
175 " pg_catalog.array_to_string(ARRAY(\n"
178 " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
179 " WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
180 " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
183 " WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
184 " ELSE p.proargnames[s.i] || ' ' \n"
186 " pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
188 " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
191 " pg_catalog.array_to_string(ARRAY(\n"
194 " WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
195 " ELSE p.proargnames[s.i+1] || ' '\n"
197 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
199 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
202 _("Schema"), _("Name"), _("Result data type"),
203 _("Argument data types"));
206 appendPQExpBuffer(&buf,
207 ",\n r.rolname as \"%s\",\n"
208 " l.lanname as \"%s\",\n"
209 " p.prosrc as \"%s\",\n"
210 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
211 _("Owner"), _("Language"),
212 _("Source code"), _("Description"));
215 appendPQExpBuffer(&buf,
216 "\nFROM pg_catalog.pg_proc p"
217 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
219 appendPQExpBuffer(&buf,
220 "\nFROM pg_catalog.pg_proc p"
221 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace"
222 "\n LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang"
223 "\n JOIN pg_catalog.pg_roles r ON r.oid = p.proowner\n");
226 * we skip in/out funcs by excluding functions that take or return cstring
228 appendPQExpBuffer(&buf,
229 "WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n"
230 " AND (p.proargtypes[0] IS NULL\n"
231 " OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n"
232 " AND NOT p.proisagg\n");
234 processSQLNamePattern(pset.db, &buf, pattern, true, false,
235 "n.nspname", "p.proname", NULL,
236 "pg_catalog.pg_function_is_visible(p.oid)");
238 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;");
240 res = PSQLexec(buf.data, false);
241 termPQExpBuffer(&buf);
245 myopt.nullPrint = NULL;
246 myopt.title = _("List of functions");
248 printQuery(res, &myopt, pset.queryFout, pset.logfile);
261 describeTypes(const char *pattern, bool verbose)
265 printQueryOpt myopt = pset.popt;
267 initPQExpBuffer(&buf);
269 printfPQExpBuffer(&buf,
270 "SELECT n.nspname as \"%s\",\n"
271 " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
272 _("Schema"), _("Name"));
274 appendPQExpBuffer(&buf,
275 " t.typname AS \"%s\",\n"
276 " CASE WHEN t.typrelid != 0\n"
277 " THEN CAST('tuple' AS pg_catalog.text)\n"
278 " WHEN t.typlen < 0\n"
279 " THEN CAST('var' AS pg_catalog.text)\n"
280 " ELSE CAST(t.typlen AS pg_catalog.text)\n"
282 _("Internal name"), _("Size"));
283 appendPQExpBuffer(&buf,
284 " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
287 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n"
288 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
291 * do not include array types (start with underscore); do not include
292 * complex types (typrelid!=0) unless they are standalone composite types
294 appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 ");
295 appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
296 "WHERE c.oid = t.typrelid)) ");
297 appendPQExpBuffer(&buf, "AND t.typname !~ '^_'\n");
299 /* Match name pattern against either internal or external name */
300 processSQLNamePattern(pset.db, &buf, pattern, true, false,
301 "n.nspname", "t.typname",
302 "pg_catalog.format_type(t.oid, NULL)",
303 "pg_catalog.pg_type_is_visible(t.oid)");
305 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
307 res = PSQLexec(buf.data, false);
308 termPQExpBuffer(&buf);
312 myopt.nullPrint = NULL;
313 myopt.title = _("List of data types");
315 printQuery(res, &myopt, pset.queryFout, pset.logfile);
326 describeOperators(const char *pattern)
330 printQueryOpt myopt = pset.popt;
332 initPQExpBuffer(&buf);
334 printfPQExpBuffer(&buf,
335 "SELECT n.nspname as \"%s\",\n"
336 " o.oprname AS \"%s\",\n"
337 " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
338 " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
339 " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n"
340 " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
341 " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
342 "FROM pg_catalog.pg_operator o\n"
343 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
344 _("Schema"), _("Name"),
345 _("Left arg type"), _("Right arg type"),
346 _("Result type"), _("Description"));
348 processSQLNamePattern(pset.db, &buf, pattern, false, true,
349 "n.nspname", "o.oprname", NULL,
350 "pg_catalog.pg_operator_is_visible(o.oid)");
352 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;");
354 res = PSQLexec(buf.data, false);
355 termPQExpBuffer(&buf);
359 myopt.nullPrint = NULL;
360 myopt.title = _("List of operators");
362 printQuery(res, &myopt, pset.queryFout, pset.logfile);
372 * for \l, \list, and -l switch
375 listAllDbs(bool verbose)
379 printQueryOpt myopt = pset.popt;
381 initPQExpBuffer(&buf);
383 printfPQExpBuffer(&buf,
384 "SELECT d.datname as \"%s\",\n"
385 " r.rolname as \"%s\"",
386 _("Name"), _("Owner"));
387 appendPQExpBuffer(&buf,
388 ",\n pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\"",
392 appendPQExpBuffer(&buf,
393 ",\n t.spcname as \"%s\"",
395 appendPQExpBuffer(&buf,
396 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
399 appendPQExpBuffer(&buf,
400 "\nFROM pg_catalog.pg_database d"
401 "\n JOIN pg_catalog.pg_roles r ON d.datdba = r.oid\n");
403 appendPQExpBuffer(&buf,
404 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
405 appendPQExpBuffer(&buf, "ORDER BY 1;");
406 res = PSQLexec(buf.data, false);
407 termPQExpBuffer(&buf);
411 myopt.nullPrint = NULL;
412 myopt.title = _("List of databases");
414 printQuery(res, &myopt, pset.queryFout, pset.logfile);
422 * List Tables Grant/Revoke Permissions
423 * \z (now also \dp -- perhaps more mnemonic)
426 permissionsList(const char *pattern)
430 printQueryOpt myopt = pset.popt;
432 initPQExpBuffer(&buf);
435 * we ignore indexes and toast tables since they have no meaningful rights
437 printfPQExpBuffer(&buf,
438 "SELECT n.nspname as \"%s\",\n"
439 " c.relname as \"%s\",\n"
440 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \"%s\",\n"
441 " c.relacl as \"%s\"\n"
442 "FROM pg_catalog.pg_class c\n"
443 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
444 "WHERE c.relkind IN ('r', 'v', 'S')\n",
445 _("Schema"), _("Name"), _("table"), _("view"), _("sequence"), _("Type"), _("Access privileges"));
448 * Unless a schema pattern is specified, we suppress system and temp
449 * tables, since they normally aren't very interesting from a permissions
450 * point of view. You can see 'em by explicit request though, eg with \z
453 processSQLNamePattern(pset.db, &buf, pattern, true, false,
454 "n.nspname", "c.relname", NULL,
455 "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
457 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
459 res = PSQLexec(buf.data, false);
462 termPQExpBuffer(&buf);
466 myopt.nullPrint = NULL;
467 printfPQExpBuffer(&buf, _("Access privileges for database \"%s\""), PQdb(pset.db));
468 myopt.title = buf.data;
470 printQuery(res, &myopt, pset.queryFout, pset.logfile);
472 termPQExpBuffer(&buf);
480 * Get object comments
484 * Note: This only lists things that actually have a description. For complete
485 * lists of things, there are other \d? commands.
488 objectDescription(const char *pattern)
492 printQueryOpt myopt = pset.popt;
494 initPQExpBuffer(&buf);
496 appendPQExpBuffer(&buf,
497 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
499 _("Schema"), _("Name"), _("Object"), _("Description"));
501 /* Aggregate descriptions */
502 appendPQExpBuffer(&buf,
503 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
504 " n.nspname as nspname,\n"
505 " CAST(p.proname AS pg_catalog.text) as name,"
506 " CAST('%s' AS pg_catalog.text) as object\n"
507 " FROM pg_catalog.pg_proc p\n"
508 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
509 " WHERE p.proisagg\n",
511 processSQLNamePattern(pset.db, &buf, pattern, true, false,
512 "n.nspname", "p.proname", NULL,
513 "pg_catalog.pg_function_is_visible(p.oid)");
515 /* Function descriptions (except in/outs for datatypes) */
516 appendPQExpBuffer(&buf,
518 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
519 " n.nspname as nspname,\n"
520 " CAST(p.proname AS pg_catalog.text) as name,"
521 " CAST('%s' AS pg_catalog.text) as object\n"
522 " FROM pg_catalog.pg_proc p\n"
523 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
525 " WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n"
526 " AND (p.proargtypes[0] IS NULL\n"
527 " OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n"
528 " AND NOT p.proisagg\n",
530 processSQLNamePattern(pset.db, &buf, pattern, true, false,
531 "n.nspname", "p.proname", NULL,
532 "pg_catalog.pg_function_is_visible(p.oid)");
534 /* Operator descriptions (only if operator has its own comment) */
535 appendPQExpBuffer(&buf,
537 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
538 " n.nspname as nspname,\n"
539 " CAST(o.oprname AS pg_catalog.text) as name,"
540 " CAST('%s' AS pg_catalog.text) as object\n"
541 " FROM pg_catalog.pg_operator o\n"
542 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
544 processSQLNamePattern(pset.db, &buf, pattern, false, false,
545 "n.nspname", "o.oprname", NULL,
546 "pg_catalog.pg_operator_is_visible(o.oid)");
548 /* Type description */
549 appendPQExpBuffer(&buf,
551 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
552 " n.nspname as nspname,\n"
553 " pg_catalog.format_type(t.oid, NULL) as name,"
554 " CAST('%s' AS pg_catalog.text) as object\n"
555 " FROM pg_catalog.pg_type t\n"
556 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
558 processSQLNamePattern(pset.db, &buf, pattern, false, false,
559 "n.nspname", "pg_catalog.format_type(t.oid, NULL)",
561 "pg_catalog.pg_type_is_visible(t.oid)");
563 /* Relation (tables, views, indexes, sequences) descriptions */
564 appendPQExpBuffer(&buf,
566 " SELECT c.oid as oid, c.tableoid as tableoid,\n"
567 " n.nspname as nspname,\n"
568 " CAST(c.relname AS pg_catalog.text) as name,\n"
570 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END"
571 " AS pg_catalog.text) as object\n"
572 " FROM pg_catalog.pg_class c\n"
573 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
574 " WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
575 _("table"), _("view"), _("index"), _("sequence"));
576 processSQLNamePattern(pset.db, &buf, pattern, true, false,
577 "n.nspname", "c.relname", NULL,
578 "pg_catalog.pg_table_is_visible(c.oid)");
580 /* Rule description (ignore rules for views) */
581 appendPQExpBuffer(&buf,
583 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
584 " n.nspname as nspname,\n"
585 " CAST(r.rulename AS pg_catalog.text) as name,"
586 " CAST('%s' AS pg_catalog.text) as object\n"
587 " FROM pg_catalog.pg_rewrite r\n"
588 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
589 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
590 " WHERE r.rulename != '_RETURN'\n",
592 /* XXX not sure what to do about visibility rule here? */
593 processSQLNamePattern(pset.db, &buf, pattern, true, false,
594 "n.nspname", "r.rulename", NULL,
595 "pg_catalog.pg_table_is_visible(c.oid)");
597 /* Trigger description */
598 appendPQExpBuffer(&buf,
600 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
601 " n.nspname as nspname,\n"
602 " CAST(t.tgname AS pg_catalog.text) as name,"
603 " CAST('%s' AS pg_catalog.text) as object\n"
604 " FROM pg_catalog.pg_trigger t\n"
605 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
606 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
608 /* XXX not sure what to do about visibility rule here? */
609 processSQLNamePattern(pset.db, &buf, pattern, false, false,
610 "n.nspname", "t.tgname", NULL,
611 "pg_catalog.pg_table_is_visible(c.oid)");
613 appendPQExpBuffer(&buf,
615 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
617 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
619 res = PSQLexec(buf.data, false);
620 termPQExpBuffer(&buf);
624 myopt.nullPrint = NULL;
625 myopt.title = _("Object descriptions");
627 printQuery(res, &myopt, pset.queryFout, pset.logfile);
636 * describeTableDetails (for \d)
638 * This routine finds the tables to be displayed, and calls
639 * describeOneTableDetails for each one.
641 * verbose: if true, this is \d+
644 describeTableDetails(const char *pattern, bool verbose)
650 initPQExpBuffer(&buf);
652 printfPQExpBuffer(&buf,
656 "FROM pg_catalog.pg_class c\n"
657 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
659 processSQLNamePattern(pset.db, &buf, pattern, false, false,
660 "n.nspname", "c.relname", NULL,
661 "pg_catalog.pg_table_is_visible(c.oid)");
663 appendPQExpBuffer(&buf, "ORDER BY 2, 3;");
665 res = PSQLexec(buf.data, false);
666 termPQExpBuffer(&buf);
670 if (PQntuples(res) == 0)
673 fprintf(stderr, _("Did not find any relation named \"%s\".\n"),
679 for (i = 0; i < PQntuples(res); i++)
685 oid = PQgetvalue(res, i, 0);
686 nspname = PQgetvalue(res, i, 1);
687 relname = PQgetvalue(res, i, 2);
689 if (!describeOneTableDetails(nspname, relname, oid, verbose))
706 * describeOneTableDetails (for \d)
708 * Unfortunately, the information presented here is so complicated that it
709 * cannot be done in a single query. So we have to assemble the printed table
710 * by hand and pass it to the underlying printTable() function.
713 describeOneTableDetails(const char *schemaname,
714 const char *relationname,
719 PGresult *res = NULL;
720 printTableOpt myopt = pset.popt.topt;
722 char *view_def = NULL;
723 const char *headers[5];
725 char **footers = NULL;
727 PQExpBufferData title;
728 PQExpBufferData tmpbuf;
741 bool show_modifiers = false;
746 /* This output looks confusing in expanded mode. */
747 myopt.expanded = false;
749 initPQExpBuffer(&buf);
750 initPQExpBuffer(&title);
751 initPQExpBuffer(&tmpbuf);
753 /* Get general table info */
754 printfPQExpBuffer(&buf,
755 "SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules, \n"
757 "FROM pg_catalog.pg_class WHERE oid = '%s'",
758 pset.sversion >= 80000 ? ", reltablespace" : "",
760 res = PSQLexec(buf.data, false);
764 /* Did we get anything? */
765 if (PQntuples(res) == 0)
768 fprintf(stderr, _("Did not find any relation with OID %s.\n"),
773 /* FIXME: check for null pointers here? */
774 tableinfo.checks = atoi(PQgetvalue(res, 0, 2));
775 tableinfo.triggers = atoi(PQgetvalue(res, 0, 3));
776 tableinfo.relkind = *(PQgetvalue(res, 0, 1));
777 tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 0), "t") == 0;
778 tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
779 tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
780 tableinfo.tablespace = (pset.sversion >= 80000) ?
781 atooid(PQgetvalue(res, 0, 6)) : 0;
784 headers[0] = _("Column");
785 headers[1] = _("Type");
788 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
790 show_modifiers = true;
792 headers[cols - 1] = _("Modifiers");
798 headers[cols - 1] = _("Description");
801 headers[cols] = NULL;
803 /* Get column info (index requires additional checks) */
804 printfPQExpBuffer(&buf, "SELECT a.attname,");
805 appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
806 "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
807 "\n FROM pg_catalog.pg_attrdef d"
808 "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
809 "\n a.attnotnull, a.attnum");
811 appendPQExpBuffer(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)");
812 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_attribute a");
813 if (tableinfo.relkind == 'i')
814 appendPQExpBuffer(&buf, ", pg_catalog.pg_index i");
815 appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
816 if (tableinfo.relkind == 'i')
817 appendPQExpBuffer(&buf, " AND a.attrelid = i.indexrelid");
818 appendPQExpBuffer(&buf, "\nORDER BY a.attnum");
820 res = PSQLexec(buf.data, false);
823 numrows = PQntuples(res);
825 /* Check if table is a view */
826 if (tableinfo.relkind == 'v')
830 printfPQExpBuffer(&buf, "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true)", oid);
831 result = PSQLexec(buf.data, false);
835 if (PQntuples(result) > 0)
836 view_def = pg_strdup(PQgetvalue(result, 0, 0));
841 /* Generate table cells to be printed */
842 /* note: initialize all cells[] to NULL in case of error exit */
843 cells = pg_malloc_zero((numrows * cols + 1) * sizeof(*cells));
845 for (i = 0; i < numrows; i++)
849 cells[i * cols + 0] = mbvalidate(PQgetvalue(res, i, 0), myopt.encoding);
851 cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this
857 cells[i * cols + 1] = mbvalidate(PQgetvalue(res, i, 1), myopt.encoding);
859 cells[i * cols + 1] = PQgetvalue(res, i, 1); /* don't free this
863 /* Extra: not null and default */
866 resetPQExpBuffer(&tmpbuf);
867 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
868 appendPQExpBufferStr(&tmpbuf, "not null");
870 /* handle "default" here */
871 /* (note: above we cut off the 'default' string at 128) */
872 if (strlen(PQgetvalue(res, i, 2)) != 0)
875 appendPQExpBufferStr(&tmpbuf, " ");
876 appendPQExpBuffer(&tmpbuf, "default %s",
877 PQgetvalue(res, i, 2));
881 cells[i * cols + 2] = pg_strdup(mbvalidate(tmpbuf.data, myopt.encoding));
883 cells[i * cols + 2] = pg_strdup(tmpbuf.data);
890 cells[i * cols + cols - 1] = mbvalidate(PQgetvalue(res, i, 5), myopt.encoding);
892 cells[i * cols + cols - 1] = PQgetvalue(res, i, 5);
897 switch (tableinfo.relkind)
900 printfPQExpBuffer(&title, _("Table \"%s.%s\""),
901 schemaname, relationname);
904 printfPQExpBuffer(&title, _("View \"%s.%s\""),
905 schemaname, relationname);
908 printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
909 schemaname, relationname);
912 printfPQExpBuffer(&title, _("Index \"%s.%s\""),
913 schemaname, relationname);
916 /* not used as of 8.2, but keep it for backwards compatibility */
917 printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
918 schemaname, relationname);
921 printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
922 schemaname, relationname);
925 printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
926 schemaname, relationname);
929 printfPQExpBuffer(&title, _("?%c? \"%s.%s\""),
930 tableinfo.relkind, schemaname, relationname);
935 if (tableinfo.relkind == 'i')
937 /* Footer information about an index */
940 printfPQExpBuffer(&buf,
941 "SELECT i.indisunique, i.indisprimary, i.indisclustered, i.indisvalid, a.amname, c2.relname,\n"
942 " pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
943 "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
944 "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
945 "AND i.indrelid = c2.oid",
948 result = PSQLexec(buf.data, false);
951 else if (PQntuples(result) != 1)
958 char *indisunique = PQgetvalue(result, 0, 0);
959 char *indisprimary = PQgetvalue(result, 0, 1);
960 char *indisclustered = PQgetvalue(result, 0, 2);
961 char *indisvalid = PQgetvalue(result, 0, 3);
962 char *indamname = PQgetvalue(result, 0, 4);
963 char *indtable = PQgetvalue(result, 0, 5);
964 char *indpred = PQgetvalue(result, 0, 6);
965 int count_footers = 0;
967 if (strcmp(indisprimary, "t") == 0)
968 printfPQExpBuffer(&tmpbuf, _("primary key, "));
969 else if (strcmp(indisunique, "t") == 0)
970 printfPQExpBuffer(&tmpbuf, _("unique, "));
972 resetPQExpBuffer(&tmpbuf);
973 appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
975 /* we assume here that index and table are in same schema */
976 appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
977 schemaname, indtable);
980 appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
982 if (strcmp(indisclustered, "t") == 0)
983 appendPQExpBuffer(&tmpbuf, _(", clustered"));
985 if (strcmp(indisvalid, "t") != 0)
986 appendPQExpBuffer(&tmpbuf, _(", invalid"));
988 footers = pg_malloc_zero(4 * sizeof(*footers));
989 footers[count_footers++] = pg_strdup(tmpbuf.data);
990 add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
991 footers, &count_footers, tmpbuf, true);
992 footers[count_footers] = NULL;
1000 PGresult *result = NULL;
1002 int count_footers = 0;
1004 /* count rules other than the view rule */
1005 if (tableinfo.hasrules)
1007 printfPQExpBuffer(&buf,
1008 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
1009 "FROM pg_catalog.pg_rewrite r\n"
1010 "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1",
1012 result = PSQLexec(buf.data, false);
1016 rule_count = PQntuples(result);
1019 /* Footer information about a view */
1020 footers = pg_malloc_zero((rule_count + 3) * sizeof(*footers));
1021 footers[count_footers] = pg_malloc(64 + strlen(view_def));
1022 snprintf(footers[count_footers], 64 + strlen(view_def),
1023 _("View definition:\n%s"), view_def);
1029 printfPQExpBuffer(&buf, _("Rules:"));
1030 footers[count_footers++] = pg_strdup(buf.data);
1031 for (i = 0; i < rule_count; i++)
1033 const char *ruledef;
1035 /* Everything after "CREATE RULE" is echoed verbatim */
1036 ruledef = PQgetvalue(result, i, 1);
1039 printfPQExpBuffer(&buf, " %s", ruledef);
1041 footers[count_footers++] = pg_strdup(buf.data);
1046 footers[count_footers] = NULL;
1049 else if (tableinfo.relkind == 'r')
1051 /* Footer information about a table */
1052 PGresult *result1 = NULL,
1058 int check_count = 0,
1060 foreignkey_count = 0,
1064 int count_footers = 0;
1067 if (tableinfo.hasindex)
1069 printfPQExpBuffer(&buf,
1070 "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, i.indisvalid, "
1071 "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true), c2.reltablespace\n"
1072 "FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
1073 "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
1074 "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
1076 result1 = PSQLexec(buf.data, false);
1080 index_count = PQntuples(result1);
1083 /* count table (and column) check constraints */
1084 if (tableinfo.checks)
1086 printfPQExpBuffer(&buf,
1087 "SELECT r.conname, "
1088 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
1089 "FROM pg_catalog.pg_constraint r\n"
1090 "WHERE r.conrelid = '%s' AND r.contype = 'c' ORDER BY 1",
1092 result2 = PSQLexec(buf.data, false);
1099 check_count = PQntuples(result2);
1103 if (tableinfo.hasrules)
1105 printfPQExpBuffer(&buf,
1106 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
1107 "FROM pg_catalog.pg_rewrite r\n"
1108 "WHERE r.ev_class = '%s' ORDER BY 1",
1110 result3 = PSQLexec(buf.data, false);
1118 rule_count = PQntuples(result3);
1121 /* count triggers (but ignore foreign-key triggers) */
1122 if (tableinfo.triggers)
1124 printfPQExpBuffer(&buf,
1125 "SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid)\n"
1126 "FROM pg_catalog.pg_trigger t\n"
1127 "WHERE t.tgrelid = '%s' "
1128 "AND (not tgisconstraint "
1130 " (SELECT 1 FROM pg_catalog.pg_depend d "
1131 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
1132 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))"
1135 result4 = PSQLexec(buf.data, false);
1144 trigger_count = PQntuples(result4);
1147 /* count foreign-key constraints (there are none if no triggers) */
1148 if (tableinfo.triggers)
1150 printfPQExpBuffer(&buf,
1152 " pg_catalog.pg_get_constraintdef(oid, true) as condef\n"
1153 "FROM pg_catalog.pg_constraint r\n"
1154 "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1",
1156 result5 = PSQLexec(buf.data, false);
1166 foreignkey_count = PQntuples(result5);
1169 /* count inherited tables */
1170 printfPQExpBuffer(&buf, "SELECT c.relname FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhparent AND i.inhrelid = '%s' ORDER BY inhseqno ASC", oid);
1172 result6 = PSQLexec(buf.data, false);
1183 inherits_count = PQntuples(result6);
1185 footers = pg_malloc_zero((index_count + check_count + rule_count + trigger_count + foreignkey_count + inherits_count + 7 + 1)
1186 * sizeof(*footers));
1189 if (index_count > 0)
1191 printfPQExpBuffer(&buf, _("Indexes:"));
1192 footers[count_footers++] = pg_strdup(buf.data);
1193 for (i = 0; i < index_count; i++)
1195 const char *indexdef;
1196 const char *usingpos;
1197 PQExpBufferData tmpbuf;
1199 /* Output index name */
1200 printfPQExpBuffer(&buf, _(" \"%s\""),
1201 PQgetvalue(result1, i, 0));
1203 /* Label as primary key or unique (but not both) */
1204 appendPQExpBuffer(&buf,
1205 strcmp(PQgetvalue(result1, i, 1), "t") == 0
1207 (strcmp(PQgetvalue(result1, i, 2), "t") == 0
1210 /* Everything after "USING" is echoed verbatim */
1211 indexdef = PQgetvalue(result1, i, 5);
1212 usingpos = strstr(indexdef, " USING ");
1214 indexdef = usingpos + 7;
1216 appendPQExpBuffer(&buf, " %s", indexdef);
1218 if (strcmp(PQgetvalue(result1, i, 3), "t") == 0)
1219 appendPQExpBuffer(&buf, " CLUSTER");
1221 if (strcmp(PQgetvalue(result1, i, 4), "t") != 0)
1222 appendPQExpBuffer(&buf, " INVALID");
1224 /* Print tablespace of the index on the same line */
1226 initPQExpBuffer(&tmpbuf);
1227 if (add_tablespace_footer('i',
1228 atooid(PQgetvalue(result1, i, 6)),
1229 footers, &count_footers, tmpbuf, false))
1231 appendPQExpBuffer(&buf, ", ");
1232 appendPQExpBuffer(&buf, tmpbuf.data);
1238 termPQExpBuffer(&tmpbuf);
1240 footers[count_footers++] = pg_strdup(buf.data);
1244 /* print check constraints */
1245 if (check_count > 0)
1247 printfPQExpBuffer(&buf, _("Check constraints:"));
1248 footers[count_footers++] = pg_strdup(buf.data);
1249 for (i = 0; i < check_count; i++)
1251 printfPQExpBuffer(&buf, _(" \"%s\" %s"),
1252 PQgetvalue(result2, i, 0),
1253 PQgetvalue(result2, i, 1));
1255 footers[count_footers++] = pg_strdup(buf.data);
1259 /* print foreign key constraints */
1260 if (foreignkey_count > 0)
1262 printfPQExpBuffer(&buf, _("Foreign-key constraints:"));
1263 footers[count_footers++] = pg_strdup(buf.data);
1264 for (i = 0; i < foreignkey_count; i++)
1266 printfPQExpBuffer(&buf, _(" \"%s\" %s"),
1267 PQgetvalue(result5, i, 0),
1268 PQgetvalue(result5, i, 1));
1270 footers[count_footers++] = pg_strdup(buf.data);
1277 printfPQExpBuffer(&buf, _("Rules:"));
1278 footers[count_footers++] = pg_strdup(buf.data);
1279 for (i = 0; i < rule_count; i++)
1281 const char *ruledef;
1283 /* Everything after "CREATE RULE" is echoed verbatim */
1284 ruledef = PQgetvalue(result3, i, 1);
1287 printfPQExpBuffer(&buf, " %s", ruledef);
1289 footers[count_footers++] = pg_strdup(buf.data);
1293 /* print triggers */
1294 if (trigger_count > 0)
1296 printfPQExpBuffer(&buf, _("Triggers:"));
1297 footers[count_footers++] = pg_strdup(buf.data);
1298 for (i = 0; i < trigger_count; i++)
1301 const char *usingpos;
1303 /* Everything after "TRIGGER" is echoed verbatim */
1304 tgdef = PQgetvalue(result4, i, 1);
1305 usingpos = strstr(tgdef, " TRIGGER ");
1307 tgdef = usingpos + 9;
1309 printfPQExpBuffer(&buf, " %s", tgdef);
1311 footers[count_footers++] = pg_strdup(buf.data);
1315 /* print inherits */
1316 for (i = 0; i < inherits_count; i++)
1318 char *s = _("Inherits");
1321 printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result6, i, 0));
1323 printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result6, i, 0));
1324 if (i < inherits_count - 1)
1325 appendPQExpBuffer(&buf, ",");
1327 footers[count_footers++] = pg_strdup(buf.data);
1332 char *s = _("Has OIDs");
1334 printfPQExpBuffer(&buf, "%s: %s", s,
1335 (tableinfo.hasoids ? _("yes") : _("no")));
1336 footers[count_footers++] = pg_strdup(buf.data);
1339 add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
1340 footers, &count_footers, buf, true);
1341 /* end of list marker */
1342 footers[count_footers] = NULL;
1352 printTable(title.data, headers,
1353 (const char **) cells, (const char **) footers,
1354 "llll", &myopt, pset.queryFout, pset.logfile);
1361 termPQExpBuffer(&buf);
1362 termPQExpBuffer(&title);
1363 termPQExpBuffer(&tmpbuf);
1367 for (i = 0; i < numrows; i++)
1370 free(cells[i * cols + 2]);
1377 for (ptr = footers; *ptr; ptr++)
1393 * Return true if the relation uses non default tablespace;
1394 * otherwise return false
1397 add_tablespace_footer(char relkind, Oid tablespace, char **footers,
1398 int *count, PQExpBufferData buf, bool newline)
1400 /* relkinds for which we support tablespaces */
1401 if (relkind == 'r' || relkind == 'i')
1404 * We ignore the database default tablespace so that users not using
1405 * tablespaces don't need to know about them.
1407 if (tablespace != 0)
1409 PGresult *result1 = NULL;
1411 printfPQExpBuffer(&buf, "SELECT spcname FROM pg_tablespace \n"
1412 "WHERE oid = '%u';", tablespace);
1413 result1 = PSQLexec(buf.data, false);
1416 /* Should always be the case, but.... */
1417 if (PQntuples(result1) > 0)
1419 printfPQExpBuffer(&buf,
1420 newline ? _("Tablespace: \"%s\"") : _("tablespace \"%s\""),
1421 PQgetvalue(result1, 0, 0));
1423 footers[(*count)++] = pg_strdup(buf.data);
1437 * Describes roles. Any schema portion of the pattern is ignored.
1440 describeRoles(const char *pattern, bool verbose)
1442 PQExpBufferData buf;
1444 printQueryOpt myopt = pset.popt;
1446 initPQExpBuffer(&buf);
1448 printfPQExpBuffer(&buf,
1449 "SELECT r.rolname AS \"%s\",\n"
1450 " CASE WHEN r.rolsuper THEN '%s' ELSE '%s' END AS \"%s\",\n"
1451 " CASE WHEN r.rolcreaterole THEN '%s' ELSE '%s' END AS \"%s\",\n"
1452 " CASE WHEN r.rolcreatedb THEN '%s' ELSE '%s' END AS \"%s\",\n"
1453 " CASE WHEN r.rolconnlimit < 0 THEN CAST('%s' AS pg_catalog.text)\n"
1454 " ELSE CAST(r.rolconnlimit AS pg_catalog.text)\n"
1455 " END AS \"%s\", \n"
1456 " ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) WHERE m.member = r.oid) as \"%s\"",
1458 _("yes"), _("no"), _("Superuser"),
1459 _("yes"), _("no"), _("Create role"),
1460 _("yes"), _("no"), _("Create DB"),
1461 _("no limit"), _("Connections"),
1465 appendPQExpBuffer(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS \"%s\"",
1468 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_roles r\n");
1470 processSQLNamePattern(pset.db, &buf, pattern, false, false,
1471 NULL, "r.rolname", NULL, NULL);
1473 appendPQExpBuffer(&buf, "ORDER BY 1;");
1475 res = PSQLexec(buf.data, false);
1476 termPQExpBuffer(&buf);
1480 myopt.nullPrint = NULL;
1481 myopt.title = _("List of roles");
1483 printQuery(res, &myopt, pset.queryFout, pset.logfile);
1493 * handler for \d, \dt, etc.
1495 * tabtypes is an array of characters, specifying what info is desired:
1500 * S - system tables (pg_catalog)
1501 * (any order of the above is fine)
1504 listTables(const char *tabtypes, const char *pattern, bool verbose)
1506 bool showTables = strchr(tabtypes, 't') != NULL;
1507 bool showIndexes = strchr(tabtypes, 'i') != NULL;
1508 bool showViews = strchr(tabtypes, 'v') != NULL;
1509 bool showSeq = strchr(tabtypes, 's') != NULL;
1510 bool showSystem = strchr(tabtypes, 'S') != NULL;
1512 PQExpBufferData buf;
1514 printQueryOpt myopt = pset.popt;
1516 if (!(showTables || showIndexes || showViews || showSeq))
1517 showTables = showViews = showSeq = true;
1519 initPQExpBuffer(&buf);
1522 * Note: as of Pg 8.2, we no longer use relkind 's', but we keep it here
1523 * for backwards compatibility.
1525 printfPQExpBuffer(&buf,
1526 "SELECT n.nspname as \"%s\",\n"
1527 " c.relname as \"%s\",\n"
1528 " 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"
1529 " r.rolname as \"%s\"",
1530 _("Schema"), _("Name"),
1531 _("table"), _("view"), _("index"), _("sequence"),
1532 _("special"), _("Type"), _("Owner"));
1535 appendPQExpBuffer(&buf,
1536 ",\n c2.relname as \"%s\"",
1540 appendPQExpBuffer(&buf,
1541 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
1544 appendPQExpBuffer(&buf,
1545 "\nFROM pg_catalog.pg_class c"
1546 "\n JOIN pg_catalog.pg_roles r ON r.oid = c.relowner"
1547 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
1549 appendPQExpBuffer(&buf,
1550 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
1551 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
1553 appendPQExpBuffer(&buf, "\nWHERE c.relkind IN (");
1555 appendPQExpBuffer(&buf, "'r',");
1557 appendPQExpBuffer(&buf, "'v',");
1559 appendPQExpBuffer(&buf, "'i',");
1561 appendPQExpBuffer(&buf, "'S',");
1562 if (showSystem && showTables)
1563 appendPQExpBuffer(&buf, "'s',");
1564 appendPQExpBuffer(&buf, "''"); /* dummy */
1565 appendPQExpBuffer(&buf, ")\n");
1568 * If showSystem is specified, show only system objects (those in
1569 * pg_catalog). Otherwise, suppress system objects, including those in
1570 * pg_catalog and pg_toast. (We don't want to hide temp tables though.)
1573 appendPQExpBuffer(&buf, " AND n.nspname = 'pg_catalog'\n");
1575 appendPQExpBuffer(&buf, " AND n.nspname NOT IN ('pg_catalog', 'pg_toast')\n");
1577 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1578 "n.nspname", "c.relname", NULL,
1579 "pg_catalog.pg_table_is_visible(c.oid)");
1581 appendPQExpBuffer(&buf, "ORDER BY 1,2;");
1583 res = PSQLexec(buf.data, false);
1584 termPQExpBuffer(&buf);
1588 if (PQntuples(res) == 0 && !pset.quiet)
1591 fprintf(pset.queryFout, _("No matching relations found.\n"));
1593 fprintf(pset.queryFout, _("No relations found.\n"));
1597 myopt.nullPrint = NULL;
1598 myopt.title = _("List of relations");
1600 printQuery(res, &myopt, pset.queryFout, pset.logfile);
1611 * Describes domains.
1614 listDomains(const char *pattern)
1616 PQExpBufferData buf;
1618 printQueryOpt myopt = pset.popt;
1620 initPQExpBuffer(&buf);
1622 printfPQExpBuffer(&buf,
1623 "SELECT n.nspname as \"%s\",\n"
1624 " t.typname as \"%s\",\n"
1625 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
1626 " CASE WHEN t.typnotnull AND t.typdefault IS NOT NULL THEN 'not null default '||t.typdefault\n"
1627 " WHEN t.typnotnull AND t.typdefault IS NULL THEN 'not null'\n"
1628 " WHEN NOT t.typnotnull AND t.typdefault IS NOT NULL THEN 'default '||t.typdefault\n"
1631 " pg_catalog.pg_get_constraintdef(r.oid, true) as \"%s\"\n"
1632 "FROM pg_catalog.pg_type t\n"
1633 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
1634 " LEFT JOIN pg_catalog.pg_constraint r ON t.oid = r.contypid\n"
1635 "WHERE t.typtype = 'd'\n",
1642 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1643 "n.nspname", "t.typname", NULL,
1644 "pg_catalog.pg_type_is_visible(t.oid)");
1646 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
1648 res = PSQLexec(buf.data, false);
1649 termPQExpBuffer(&buf);
1653 myopt.nullPrint = NULL;
1654 myopt.title = _("List of domains");
1656 printQuery(res, &myopt, pset.queryFout, pset.logfile);
1665 * Describes conversions.
1668 listConversions(const char *pattern)
1670 PQExpBufferData buf;
1672 printQueryOpt myopt = pset.popt;
1674 initPQExpBuffer(&buf);
1676 printfPQExpBuffer(&buf,
1677 "SELECT n.nspname AS \"%s\",\n"
1678 " c.conname AS \"%s\",\n"
1679 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
1680 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
1681 " CASE WHEN c.condefault THEN '%s'\n"
1682 " ELSE '%s' END AS \"%s\"\n"
1683 "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
1684 "WHERE n.oid = c.connamespace\n",
1693 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1694 "n.nspname", "c.conname", NULL,
1695 "pg_catalog.pg_conversion_is_visible(c.oid)");
1697 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
1699 res = PSQLexec(buf.data, false);
1700 termPQExpBuffer(&buf);
1704 myopt.nullPrint = NULL;
1705 myopt.title = _("List of conversions");
1707 printQuery(res, &myopt, pset.queryFout, pset.logfile);
1719 listCasts(const char *pattern)
1721 PQExpBufferData buf;
1723 printQueryOpt myopt = pset.popt;
1725 initPQExpBuffer(&buf);
1726 /* NEED LEFT JOIN FOR BINARY CASTS */
1727 printfPQExpBuffer(&buf,
1728 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
1729 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
1730 " CASE WHEN castfunc = 0 THEN '%s'\n"
1733 " CASE WHEN c.castcontext = 'e' THEN '%s'\n"
1734 " WHEN c.castcontext = 'a' THEN '%s'\n"
1737 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
1738 " ON c.castfunc = p.oid\n"
1742 _("(binary compatible)"),
1749 res = PSQLexec(buf.data, false);
1750 termPQExpBuffer(&buf);
1754 myopt.nullPrint = NULL;
1755 myopt.title = _("List of casts");
1757 printQuery(res, &myopt, pset.queryFout, pset.logfile);
1766 * Describes schemas (namespaces)
1769 listSchemas(const char *pattern, bool verbose)
1771 PQExpBufferData buf;
1773 printQueryOpt myopt = pset.popt;
1775 initPQExpBuffer(&buf);
1776 printfPQExpBuffer(&buf,
1777 "SELECT n.nspname AS \"%s\",\n"
1778 " r.rolname AS \"%s\"",
1779 _("Name"), _("Owner"));
1782 appendPQExpBuffer(&buf,
1783 ",\n n.nspacl as \"%s\","
1784 " pg_catalog.obj_description(n.oid, 'pg_namespace') as \"%s\"",
1785 _("Access privileges"), _("Description"));
1787 appendPQExpBuffer(&buf,
1788 "\nFROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_roles r\n"
1789 " ON n.nspowner=r.oid\n"
1790 "WHERE (n.nspname !~ '^pg_temp_' OR\n"
1791 " n.nspname = (pg_catalog.current_schemas(true))[1])\n"); /* temp schema is first */
1793 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1794 NULL, "n.nspname", NULL,
1797 appendPQExpBuffer(&buf, "ORDER BY 1;");
1799 res = PSQLexec(buf.data, false);
1800 termPQExpBuffer(&buf);
1804 myopt.nullPrint = NULL;
1805 myopt.title = _("List of schemas");
1807 printQuery(res, &myopt, pset.queryFout, pset.logfile);