2 * psql - the PostgreSQL interactive terminal
4 * Support for the various \d ("describe") commands. Note that the current
5 * expectation is that all functions in this file will succeed when working
6 * with servers of versions 7.4 and up. It's okay to omit irrelevant
7 * information for an old server, but not to fail outright.
9 * Copyright (c) 2000-2016, PostgreSQL Global Development Group
11 * src/bin/psql/describe.c
13 #include "postgres_fe.h"
17 #include "catalog/pg_default_acl.h"
18 #include "fe_utils/string_utils.h"
22 #include "fe_utils/mbprint.h"
23 #include "fe_utils/print.h"
25 #include "variables.h"
28 static bool describeOneTableDetails(const char *schemaname,
29 const char *relationname,
32 static void add_tablespace_footer(printTableContent *const cont, char relkind,
33 Oid tablespace, const bool newline);
34 static void add_role_attribute(PQExpBuffer buf, const char *const str);
35 static bool listTSParsersVerbose(const char *pattern);
36 static bool describeOneTSParser(const char *oid, const char *nspname,
38 static bool listTSConfigsVerbose(const char *pattern);
39 static bool describeOneTSConfig(const char *oid, const char *nspname,
41 const char *pnspname, const char *prsname);
42 static void printACLColumn(PQExpBuffer buf, const char *colname);
43 static bool listOneExtensionContents(const char *extname, const char *oid);
47 * Handlers for various slash commands displaying some sort of list
48 * of things in the database.
50 * Note: try to format the queries to look nice in -E output.
56 * Takes an optional regexp to select particular aggregates
59 describeAggregates(const char *pattern, bool verbose, bool showSystem)
63 printQueryOpt myopt = pset.popt;
65 initPQExpBuffer(&buf);
67 printfPQExpBuffer(&buf,
68 "SELECT n.nspname as \"%s\",\n"
69 " p.proname AS \"%s\",\n"
70 " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n",
71 gettext_noop("Schema"),
73 gettext_noop("Result data type"));
75 if (pset.sversion >= 80400)
76 appendPQExpBuffer(&buf,
77 " CASE WHEN p.pronargs = 0\n"
78 " THEN CAST('*' AS pg_catalog.text)\n"
79 " ELSE pg_catalog.pg_get_function_arguments(p.oid)\n"
81 gettext_noop("Argument data types"));
82 else if (pset.sversion >= 80200)
83 appendPQExpBuffer(&buf,
84 " CASE WHEN p.pronargs = 0\n"
85 " THEN CAST('*' AS pg_catalog.text)\n"
87 " pg_catalog.array_to_string(ARRAY(\n"
89 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
91 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
94 gettext_noop("Argument data types"));
96 appendPQExpBuffer(&buf,
97 " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
98 gettext_noop("Argument data types"));
100 appendPQExpBuffer(&buf,
101 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
102 "FROM pg_catalog.pg_proc p\n"
103 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
104 "WHERE p.proisagg\n",
105 gettext_noop("Description"));
107 if (!showSystem && !pattern)
108 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
109 " AND n.nspname <> 'information_schema'\n");
111 processSQLNamePattern(pset.db, &buf, pattern, true, false,
112 "n.nspname", "p.proname", NULL,
113 "pg_catalog.pg_function_is_visible(p.oid)");
115 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
117 res = PSQLexec(buf.data);
118 termPQExpBuffer(&buf);
122 myopt.nullPrint = NULL;
123 myopt.title = _("List of aggregate functions");
124 myopt.translate_header = true;
126 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
133 * Takes an optional regexp to select particular access methods
136 describeAccessMethods(const char *pattern, bool verbose)
140 printQueryOpt myopt = pset.popt;
141 static const bool translate_columns[] = {false, true, false, false};
143 if (pset.sversion < 90600)
145 psql_error("The server (version %d.%d) does not support access methods.\n",
146 pset.sversion / 10000, (pset.sversion / 100) % 100);
150 initPQExpBuffer(&buf);
152 printfPQExpBuffer(&buf,
153 "SELECT amname AS \"%s\",\n"
155 " WHEN 'i' THEN '%s'"
157 gettext_noop("Name"),
158 gettext_noop("Index"),
159 gettext_noop("Type"));
163 appendPQExpBuffer(&buf,
164 ",\n amhandler AS \"%s\",\n"
165 " pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
166 gettext_noop("Handler"),
167 gettext_noop("Description"));
170 appendPQExpBufferStr(&buf,
171 "\nFROM pg_catalog.pg_am\n");
173 processSQLNamePattern(pset.db, &buf, pattern, false, false,
174 NULL, "amname", NULL,
177 appendPQExpBufferStr(&buf, "ORDER BY 1;");
179 res = PSQLexec(buf.data);
180 termPQExpBuffer(&buf);
184 myopt.nullPrint = NULL;
185 myopt.title = _("List of access methods");
186 myopt.translate_header = true;
187 myopt.translate_columns = translate_columns;
188 myopt.n_translate_columns = lengthof(translate_columns);
190 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
197 * Takes an optional regexp to select particular tablespaces
200 describeTablespaces(const char *pattern, bool verbose)
204 printQueryOpt myopt = pset.popt;
206 if (pset.sversion < 80000)
208 psql_error("The server (version %d.%d) does not support tablespaces.\n",
209 pset.sversion / 10000, (pset.sversion / 100) % 100);
213 initPQExpBuffer(&buf);
215 if (pset.sversion >= 90200)
216 printfPQExpBuffer(&buf,
217 "SELECT spcname AS \"%s\",\n"
218 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
219 " pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
220 gettext_noop("Name"),
221 gettext_noop("Owner"),
222 gettext_noop("Location"));
224 printfPQExpBuffer(&buf,
225 "SELECT spcname AS \"%s\",\n"
226 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
227 " spclocation AS \"%s\"",
228 gettext_noop("Name"),
229 gettext_noop("Owner"),
230 gettext_noop("Location"));
234 appendPQExpBufferStr(&buf, ",\n ");
235 printACLColumn(&buf, "spcacl");
238 if (verbose && pset.sversion >= 90000)
239 appendPQExpBuffer(&buf,
240 ",\n spcoptions AS \"%s\"",
241 gettext_noop("Options"));
243 if (verbose && pset.sversion >= 90200)
244 appendPQExpBuffer(&buf,
245 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\"",
246 gettext_noop("Size"));
248 if (verbose && pset.sversion >= 80200)
249 appendPQExpBuffer(&buf,
250 ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
251 gettext_noop("Description"));
253 appendPQExpBufferStr(&buf,
254 "\nFROM pg_catalog.pg_tablespace\n");
256 processSQLNamePattern(pset.db, &buf, pattern, false, false,
257 NULL, "spcname", NULL,
260 appendPQExpBufferStr(&buf, "ORDER BY 1;");
262 res = PSQLexec(buf.data);
263 termPQExpBuffer(&buf);
267 myopt.nullPrint = NULL;
268 myopt.title = _("List of tablespaces");
269 myopt.translate_header = true;
271 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
279 * Takes an optional regexp to select particular functions.
281 * As with \d, you can specify the kinds of functions you want:
288 * and you can mix and match these in any order.
291 describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem)
293 bool showAggregate = strchr(functypes, 'a') != NULL;
294 bool showNormal = strchr(functypes, 'n') != NULL;
295 bool showTrigger = strchr(functypes, 't') != NULL;
296 bool showWindow = strchr(functypes, 'w') != NULL;
300 printQueryOpt myopt = pset.popt;
301 static const bool translate_columns[] = {false, false, false, false, true, true, true, false, false, false, false};
303 if (strlen(functypes) != strspn(functypes, "antwS+"))
305 psql_error("\\df only takes [antwS+] as options\n");
309 if (showWindow && pset.sversion < 80400)
311 psql_error("\\df does not take a \"w\" option with server version %d.%d\n",
312 pset.sversion / 10000, (pset.sversion / 100) % 100);
316 if (!showAggregate && !showNormal && !showTrigger && !showWindow)
318 showAggregate = showNormal = showTrigger = true;
319 if (pset.sversion >= 80400)
323 initPQExpBuffer(&buf);
325 printfPQExpBuffer(&buf,
326 "SELECT n.nspname as \"%s\",\n"
327 " p.proname as \"%s\",\n",
328 gettext_noop("Schema"),
329 gettext_noop("Name"));
331 if (pset.sversion >= 80400)
332 appendPQExpBuffer(&buf,
333 " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
334 " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
336 " WHEN p.proisagg THEN '%s'\n"
337 " WHEN p.proiswindow THEN '%s'\n"
338 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
341 gettext_noop("Result data type"),
342 gettext_noop("Argument data types"),
343 /* translator: "agg" is short for "aggregate" */
345 gettext_noop("window"),
346 gettext_noop("trigger"),
347 gettext_noop("normal"),
348 gettext_noop("Type"));
349 else if (pset.sversion >= 80100)
350 appendPQExpBuffer(&buf,
351 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
352 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
353 " CASE WHEN proallargtypes IS NOT NULL THEN\n"
354 " pg_catalog.array_to_string(ARRAY(\n"
357 " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
358 " WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
359 " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
360 " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
363 " WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
364 " ELSE p.proargnames[s.i] || ' ' \n"
366 " pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
368 " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
371 " pg_catalog.array_to_string(ARRAY(\n"
374 " WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
375 " ELSE p.proargnames[s.i+1] || ' '\n"
377 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
379 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
383 " WHEN p.proisagg THEN '%s'\n"
384 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
387 gettext_noop("Result data type"),
388 gettext_noop("Argument data types"),
389 /* translator: "agg" is short for "aggregate" */
391 gettext_noop("trigger"),
392 gettext_noop("normal"),
393 gettext_noop("Type"));
395 appendPQExpBuffer(&buf,
396 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
397 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
398 " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\",\n"
400 " WHEN p.proisagg THEN '%s'\n"
401 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
404 gettext_noop("Result data type"),
405 gettext_noop("Argument data types"),
406 /* translator: "agg" is short for "aggregate" */
408 gettext_noop("trigger"),
409 gettext_noop("normal"),
410 gettext_noop("Type"));
413 appendPQExpBuffer(&buf,
414 ",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\""
416 " WHEN p.provolatile = 'i' THEN '%s'\n"
417 " WHEN p.provolatile = 's' THEN '%s'\n"
418 " WHEN p.provolatile = 'v' THEN '%s'\n"
420 ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\",\n"
421 " l.lanname as \"%s\",\n"
422 " p.prosrc as \"%s\",\n"
423 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
424 gettext_noop("definer"),
425 gettext_noop("invoker"),
426 gettext_noop("Security"),
427 gettext_noop("immutable"),
428 gettext_noop("stable"),
429 gettext_noop("volatile"),
430 gettext_noop("Volatility"),
431 gettext_noop("Owner"),
432 gettext_noop("Language"),
433 gettext_noop("Source code"),
434 gettext_noop("Description"));
436 appendPQExpBufferStr(&buf,
437 "\nFROM pg_catalog.pg_proc p"
438 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
441 appendPQExpBufferStr(&buf,
442 " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
446 /* filter by function type, if requested */
447 if (showNormal && showAggregate && showTrigger && showWindow)
454 appendPQExpBufferStr(&buf, " AND ");
457 appendPQExpBufferStr(&buf, "WHERE ");
460 appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
465 appendPQExpBufferStr(&buf, " AND ");
468 appendPQExpBufferStr(&buf, "WHERE ");
471 appendPQExpBufferStr(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
473 if (!showWindow && pset.sversion >= 80400)
476 appendPQExpBufferStr(&buf, " AND ");
479 appendPQExpBufferStr(&buf, "WHERE ");
482 appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
487 bool needs_or = false;
489 appendPQExpBufferStr(&buf, "WHERE (\n ");
491 /* Note: at least one of these must be true ... */
494 appendPQExpBufferStr(&buf, "p.proisagg\n");
500 appendPQExpBufferStr(&buf, " OR ");
501 appendPQExpBufferStr(&buf,
502 "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n");
508 appendPQExpBufferStr(&buf, " OR ");
509 appendPQExpBufferStr(&buf, "p.proiswindow\n");
512 appendPQExpBufferStr(&buf, " )\n");
515 processSQLNamePattern(pset.db, &buf, pattern, have_where, false,
516 "n.nspname", "p.proname", NULL,
517 "pg_catalog.pg_function_is_visible(p.oid)");
519 if (!showSystem && !pattern)
520 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
521 " AND n.nspname <> 'information_schema'\n");
523 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
525 res = PSQLexec(buf.data);
526 termPQExpBuffer(&buf);
530 myopt.nullPrint = NULL;
531 myopt.title = _("List of functions");
532 myopt.translate_header = true;
533 myopt.translate_columns = translate_columns;
534 myopt.n_translate_columns = lengthof(translate_columns);
536 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
549 describeTypes(const char *pattern, bool verbose, bool showSystem)
553 printQueryOpt myopt = pset.popt;
555 initPQExpBuffer(&buf);
557 printfPQExpBuffer(&buf,
558 "SELECT n.nspname as \"%s\",\n"
559 " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
560 gettext_noop("Schema"),
561 gettext_noop("Name"));
563 appendPQExpBuffer(&buf,
564 " t.typname AS \"%s\",\n"
565 " CASE WHEN t.typrelid != 0\n"
566 " THEN CAST('tuple' AS pg_catalog.text)\n"
567 " WHEN t.typlen < 0\n"
568 " THEN CAST('var' AS pg_catalog.text)\n"
569 " ELSE CAST(t.typlen AS pg_catalog.text)\n"
571 gettext_noop("Internal name"),
572 gettext_noop("Size"));
573 if (verbose && pset.sversion >= 80300)
575 appendPQExpBufferStr(&buf,
576 " pg_catalog.array_to_string(\n"
578 " SELECT e.enumlabel\n"
579 " FROM pg_catalog.pg_enum e\n"
580 " WHERE e.enumtypid = t.oid\n");
582 if (pset.sversion >= 90100)
583 appendPQExpBufferStr(&buf,
584 " ORDER BY e.enumsortorder\n");
586 appendPQExpBufferStr(&buf,
587 " ORDER BY e.oid\n");
589 appendPQExpBuffer(&buf,
593 gettext_noop("Elements"));
597 appendPQExpBuffer(&buf,
598 " pg_catalog.pg_get_userbyid(t.typowner) AS \"%s\",\n",
599 gettext_noop("Owner"));
601 if (verbose && pset.sversion >= 90200)
603 printACLColumn(&buf, "t.typacl");
604 appendPQExpBufferStr(&buf, ",\n ");
607 appendPQExpBuffer(&buf,
608 " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
609 gettext_noop("Description"));
611 appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_type t\n"
612 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
615 * do not include complex types (typrelid!=0) unless they are standalone
618 appendPQExpBufferStr(&buf, "WHERE (t.typrelid = 0 ");
619 appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
620 "WHERE c.oid = t.typrelid))\n");
623 * do not include array types (before 8.3 we have to use the assumption
624 * that their names start with underscore)
626 if (pset.sversion >= 80300)
627 appendPQExpBufferStr(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
629 appendPQExpBufferStr(&buf, " AND t.typname !~ '^_'\n");
631 if (!showSystem && !pattern)
632 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
633 " AND n.nspname <> 'information_schema'\n");
635 /* Match name pattern against either internal or external name */
636 processSQLNamePattern(pset.db, &buf, pattern, true, false,
637 "n.nspname", "t.typname",
638 "pg_catalog.format_type(t.oid, NULL)",
639 "pg_catalog.pg_type_is_visible(t.oid)");
641 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
643 res = PSQLexec(buf.data);
644 termPQExpBuffer(&buf);
648 myopt.nullPrint = NULL;
649 myopt.title = _("List of data types");
650 myopt.translate_header = true;
652 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
663 describeOperators(const char *pattern, bool verbose, bool showSystem)
667 printQueryOpt myopt = pset.popt;
669 initPQExpBuffer(&buf);
672 * Note: before Postgres 9.1, we did not assign comments to any built-in
673 * operators, preferring to let the comment on the underlying function
674 * suffice. The coalesce() on the obj_description() calls below supports
675 * this convention by providing a fallback lookup of a comment on the
676 * operator's function. As of 9.1 there is a policy that every built-in
677 * operator should have a comment; so the coalesce() is no longer
678 * necessary so far as built-in operators are concerned. We keep it
679 * anyway, for now, because (1) third-party modules may still be following
680 * the old convention, and (2) we'd need to do it anyway when talking to a
684 printfPQExpBuffer(&buf,
685 "SELECT n.nspname as \"%s\",\n"
686 " o.oprname AS \"%s\",\n"
687 " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
688 " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
689 " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
690 gettext_noop("Schema"),
691 gettext_noop("Name"),
692 gettext_noop("Left arg type"),
693 gettext_noop("Right arg type"),
694 gettext_noop("Result type"));
697 appendPQExpBuffer(&buf,
698 " o.oprcode AS \"%s\",\n",
699 gettext_noop("Function"));
701 appendPQExpBuffer(&buf,
702 " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
703 " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
704 "FROM pg_catalog.pg_operator o\n"
705 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
706 gettext_noop("Description"));
708 if (!showSystem && !pattern)
709 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
710 " AND n.nspname <> 'information_schema'\n");
712 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, true,
713 "n.nspname", "o.oprname", NULL,
714 "pg_catalog.pg_operator_is_visible(o.oid)");
716 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4;");
718 res = PSQLexec(buf.data);
719 termPQExpBuffer(&buf);
723 myopt.nullPrint = NULL;
724 myopt.title = _("List of operators");
725 myopt.translate_header = true;
727 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
737 * for \l, \list, and -l switch
740 listAllDbs(const char *pattern, bool verbose)
744 printQueryOpt myopt = pset.popt;
746 initPQExpBuffer(&buf);
748 printfPQExpBuffer(&buf,
749 "SELECT d.datname as \"%s\",\n"
750 " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
751 " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
752 gettext_noop("Name"),
753 gettext_noop("Owner"),
754 gettext_noop("Encoding"));
755 if (pset.sversion >= 80400)
756 appendPQExpBuffer(&buf,
757 " d.datcollate as \"%s\",\n"
758 " d.datctype as \"%s\",\n",
759 gettext_noop("Collate"),
760 gettext_noop("Ctype"));
761 appendPQExpBufferStr(&buf, " ");
762 printACLColumn(&buf, "d.datacl");
763 if (verbose && pset.sversion >= 80200)
764 appendPQExpBuffer(&buf,
765 ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
766 " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
767 " ELSE 'No Access'\n"
769 gettext_noop("Size"));
770 if (verbose && pset.sversion >= 80000)
771 appendPQExpBuffer(&buf,
772 ",\n t.spcname as \"%s\"",
773 gettext_noop("Tablespace"));
774 if (verbose && pset.sversion >= 80200)
775 appendPQExpBuffer(&buf,
776 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
777 gettext_noop("Description"));
778 appendPQExpBufferStr(&buf,
779 "\nFROM pg_catalog.pg_database d\n");
780 if (verbose && pset.sversion >= 80000)
781 appendPQExpBufferStr(&buf,
782 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
785 processSQLNamePattern(pset.db, &buf, pattern, false, false,
786 NULL, "d.datname", NULL, NULL);
788 appendPQExpBufferStr(&buf, "ORDER BY 1;");
789 res = PSQLexec(buf.data);
790 termPQExpBuffer(&buf);
794 myopt.nullPrint = NULL;
795 myopt.title = _("List of databases");
796 myopt.translate_header = true;
798 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
806 * List Tables' Grant/Revoke Permissions
807 * \z (now also \dp -- perhaps more mnemonic)
810 permissionsList(const char *pattern)
814 printQueryOpt myopt = pset.popt;
815 static const bool translate_columns[] = {false, false, true, false, false, false};
817 initPQExpBuffer(&buf);
820 * we ignore indexes and toast tables since they have no meaningful rights
822 printfPQExpBuffer(&buf,
823 "SELECT n.nspname as \"%s\",\n"
824 " c.relname as \"%s\",\n"
826 " WHEN 'r' THEN '%s'"
827 " WHEN 'v' THEN '%s'"
828 " WHEN 'm' THEN '%s'"
829 " WHEN 'S' THEN '%s'"
830 " WHEN 'f' THEN '%s'"
833 gettext_noop("Schema"),
834 gettext_noop("Name"),
835 gettext_noop("table"),
836 gettext_noop("view"),
837 gettext_noop("materialized view"),
838 gettext_noop("sequence"),
839 gettext_noop("foreign table"),
840 gettext_noop("Type"));
842 printACLColumn(&buf, "c.relacl");
844 if (pset.sversion >= 80400)
845 appendPQExpBuffer(&buf,
846 ",\n pg_catalog.array_to_string(ARRAY(\n"
847 " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
848 " FROM pg_catalog.pg_attribute a\n"
849 " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
850 " ), E'\\n') AS \"%s\"",
851 gettext_noop("Column privileges"));
853 if (pset.sversion >= 90500)
854 appendPQExpBuffer(&buf,
855 ",\n pg_catalog.array_to_string(ARRAY(\n"
857 " || CASE WHEN polcmd != '*' THEN\n"
858 " E' (' || polcmd || E'):'\n"
861 " || CASE WHEN polqual IS NOT NULL THEN\n"
862 " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
865 " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
866 " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
869 " || CASE WHEN polroles <> '{0}' THEN\n"
870 " E'\\n to: ' || pg_catalog.array_to_string(\n"
873 " FROM pg_catalog.pg_roles\n"
874 " WHERE oid = ANY (polroles)\n"
879 " FROM pg_catalog.pg_policy pol\n"
880 " WHERE polrelid = c.oid), E'\\n')\n"
882 gettext_noop("Policies"));
884 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_class c\n"
885 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
886 "WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f')\n");
889 * Unless a schema pattern is specified, we suppress system and temp
890 * tables, since they normally aren't very interesting from a permissions
891 * point of view. You can see 'em by explicit request though, eg with \z
894 processSQLNamePattern(pset.db, &buf, pattern, true, false,
895 "n.nspname", "c.relname", NULL,
896 "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
898 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
900 res = PSQLexec(buf.data);
903 termPQExpBuffer(&buf);
907 myopt.nullPrint = NULL;
908 printfPQExpBuffer(&buf, _("Access privileges"));
909 myopt.title = buf.data;
910 myopt.translate_header = true;
911 myopt.translate_columns = translate_columns;
912 myopt.n_translate_columns = lengthof(translate_columns);
914 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
916 termPQExpBuffer(&buf);
925 * List Default ACLs. The pattern can match either schema or role name.
928 listDefaultACLs(const char *pattern)
932 printQueryOpt myopt = pset.popt;
933 static const bool translate_columns[] = {false, false, true, false};
935 if (pset.sversion < 90000)
937 psql_error("The server (version %d.%d) does not support altering default privileges.\n",
938 pset.sversion / 10000, (pset.sversion / 100) % 100);
942 initPQExpBuffer(&buf);
944 printfPQExpBuffer(&buf,
945 "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
946 " n.nspname AS \"%s\",\n"
947 " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
949 gettext_noop("Owner"),
950 gettext_noop("Schema"),
952 gettext_noop("table"),
954 gettext_noop("sequence"),
956 gettext_noop("function"),
958 gettext_noop("type"),
959 gettext_noop("Type"));
961 printACLColumn(&buf, "d.defaclacl");
963 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
964 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
966 processSQLNamePattern(pset.db, &buf, pattern, false, false,
969 "pg_catalog.pg_get_userbyid(d.defaclrole)",
972 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
974 res = PSQLexec(buf.data);
977 termPQExpBuffer(&buf);
981 myopt.nullPrint = NULL;
982 printfPQExpBuffer(&buf, _("Default access privileges"));
983 myopt.title = buf.data;
984 myopt.translate_header = true;
985 myopt.translate_columns = translate_columns;
986 myopt.n_translate_columns = lengthof(translate_columns);
988 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
990 termPQExpBuffer(&buf);
997 * Get object comments
1001 * Note: This command only lists comments for object types which do not have
1002 * their comments displayed by their own backslash commands. The following
1003 * types of objects will be displayed: constraint, operator class,
1004 * operator family, rule, and trigger.
1008 objectDescription(const char *pattern, bool showSystem)
1010 PQExpBufferData buf;
1012 printQueryOpt myopt = pset.popt;
1013 static const bool translate_columns[] = {false, false, true, false};
1015 initPQExpBuffer(&buf);
1017 appendPQExpBuffer(&buf,
1018 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
1020 gettext_noop("Schema"),
1021 gettext_noop("Name"),
1022 gettext_noop("Object"),
1023 gettext_noop("Description"));
1025 /* Table constraint descriptions */
1026 appendPQExpBuffer(&buf,
1027 " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1028 " n.nspname as nspname,\n"
1029 " CAST(pgc.conname AS pg_catalog.text) as name,"
1030 " CAST('%s' AS pg_catalog.text) as object\n"
1031 " FROM pg_catalog.pg_constraint pgc\n"
1032 " JOIN pg_catalog.pg_class c "
1033 "ON c.oid = pgc.conrelid\n"
1034 " LEFT JOIN pg_catalog.pg_namespace n "
1035 " ON n.oid = c.relnamespace\n",
1036 gettext_noop("table constraint"));
1038 if (!showSystem && !pattern)
1039 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1040 " AND n.nspname <> 'information_schema'\n");
1042 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern,
1043 false, "n.nspname", "pgc.conname", NULL,
1044 "pg_catalog.pg_table_is_visible(c.oid)");
1046 /* Domain constraint descriptions */
1047 appendPQExpBuffer(&buf,
1049 " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1050 " n.nspname as nspname,\n"
1051 " CAST(pgc.conname AS pg_catalog.text) as name,"
1052 " CAST('%s' AS pg_catalog.text) as object\n"
1053 " FROM pg_catalog.pg_constraint pgc\n"
1054 " JOIN pg_catalog.pg_type t "
1055 "ON t.oid = pgc.contypid\n"
1056 " LEFT JOIN pg_catalog.pg_namespace n "
1057 " ON n.oid = t.typnamespace\n",
1058 gettext_noop("domain constraint"));
1060 if (!showSystem && !pattern)
1061 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1062 " AND n.nspname <> 'information_schema'\n");
1064 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern,
1065 false, "n.nspname", "pgc.conname", NULL,
1066 "pg_catalog.pg_type_is_visible(t.oid)");
1070 * pg_opclass.opcmethod only available in 8.3+
1072 if (pset.sversion >= 80300)
1074 /* Operator class descriptions */
1075 appendPQExpBuffer(&buf,
1077 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
1078 " n.nspname as nspname,\n"
1079 " CAST(o.opcname AS pg_catalog.text) as name,\n"
1080 " CAST('%s' AS pg_catalog.text) as object\n"
1081 " FROM pg_catalog.pg_opclass o\n"
1082 " JOIN pg_catalog.pg_am am ON "
1083 "o.opcmethod = am.oid\n"
1084 " JOIN pg_catalog.pg_namespace n ON "
1085 "n.oid = o.opcnamespace\n",
1086 gettext_noop("operator class"));
1088 if (!showSystem && !pattern)
1089 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1090 " AND n.nspname <> 'information_schema'\n");
1092 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1093 "n.nspname", "o.opcname", NULL,
1094 "pg_catalog.pg_opclass_is_visible(o.oid)");
1098 * although operator family comments have been around since 8.3,
1099 * pg_opfamily_is_visible is only available in 9.2+
1101 if (pset.sversion >= 90200)
1103 /* Operator family descriptions */
1104 appendPQExpBuffer(&buf,
1106 " SELECT opf.oid as oid, opf.tableoid as tableoid,\n"
1107 " n.nspname as nspname,\n"
1108 " CAST(opf.opfname AS pg_catalog.text) AS name,\n"
1109 " CAST('%s' AS pg_catalog.text) as object\n"
1110 " FROM pg_catalog.pg_opfamily opf\n"
1111 " JOIN pg_catalog.pg_am am "
1112 "ON opf.opfmethod = am.oid\n"
1113 " JOIN pg_catalog.pg_namespace n "
1114 "ON opf.opfnamespace = n.oid\n",
1115 gettext_noop("operator family"));
1117 if (!showSystem && !pattern)
1118 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1119 " AND n.nspname <> 'information_schema'\n");
1121 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1122 "n.nspname", "opf.opfname", NULL,
1123 "pg_catalog.pg_opfamily_is_visible(opf.oid)");
1126 /* Rule descriptions (ignore rules for views) */
1127 appendPQExpBuffer(&buf,
1129 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
1130 " n.nspname as nspname,\n"
1131 " CAST(r.rulename AS pg_catalog.text) as name,"
1132 " CAST('%s' AS pg_catalog.text) as object\n"
1133 " FROM pg_catalog.pg_rewrite r\n"
1134 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
1135 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
1136 " WHERE r.rulename != '_RETURN'\n",
1137 gettext_noop("rule"));
1139 if (!showSystem && !pattern)
1140 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1141 " AND n.nspname <> 'information_schema'\n");
1143 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1144 "n.nspname", "r.rulename", NULL,
1145 "pg_catalog.pg_table_is_visible(c.oid)");
1147 /* Trigger descriptions */
1148 appendPQExpBuffer(&buf,
1150 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
1151 " n.nspname as nspname,\n"
1152 " CAST(t.tgname AS pg_catalog.text) as name,"
1153 " CAST('%s' AS pg_catalog.text) as object\n"
1154 " FROM pg_catalog.pg_trigger t\n"
1155 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
1156 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
1157 gettext_noop("trigger"));
1159 if (!showSystem && !pattern)
1160 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1161 " AND n.nspname <> 'information_schema'\n");
1163 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
1164 "n.nspname", "t.tgname", NULL,
1165 "pg_catalog.pg_table_is_visible(c.oid)");
1167 appendPQExpBufferStr(&buf,
1169 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
1171 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1173 res = PSQLexec(buf.data);
1174 termPQExpBuffer(&buf);
1178 myopt.nullPrint = NULL;
1179 myopt.title = _("Object descriptions");
1180 myopt.translate_header = true;
1181 myopt.translate_columns = translate_columns;
1182 myopt.n_translate_columns = lengthof(translate_columns);
1184 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1192 * describeTableDetails (for \d)
1194 * This routine finds the tables to be displayed, and calls
1195 * describeOneTableDetails for each one.
1197 * verbose: if true, this is \d+
1200 describeTableDetails(const char *pattern, bool verbose, bool showSystem)
1202 PQExpBufferData buf;
1206 initPQExpBuffer(&buf);
1208 printfPQExpBuffer(&buf,
1212 "FROM pg_catalog.pg_class c\n"
1213 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1215 if (!showSystem && !pattern)
1216 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1217 " AND n.nspname <> 'information_schema'\n");
1219 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
1220 "n.nspname", "c.relname", NULL,
1221 "pg_catalog.pg_table_is_visible(c.oid)");
1223 appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
1225 res = PSQLexec(buf.data);
1226 termPQExpBuffer(&buf);
1230 if (PQntuples(res) == 0)
1233 psql_error("Did not find any relation named \"%s\".\n",
1239 for (i = 0; i < PQntuples(res); i++)
1242 const char *nspname;
1243 const char *relname;
1245 oid = PQgetvalue(res, i, 0);
1246 nspname = PQgetvalue(res, i, 1);
1247 relname = PQgetvalue(res, i, 2);
1249 if (!describeOneTableDetails(nspname, relname, oid, verbose))
1266 * describeOneTableDetails (for \d)
1268 * Unfortunately, the information presented here is so complicated that it
1269 * cannot be done in a single query. So we have to assemble the printed table
1270 * by hand and pass it to the underlying printTable() function.
1273 describeOneTableDetails(const char *schemaname,
1274 const char *relationname,
1278 PQExpBufferData buf;
1279 PGresult *res = NULL;
1280 printTableOpt myopt = pset.popt.topt;
1281 printTableContent cont;
1282 bool printTableInitialized = false;
1284 char *view_def = NULL;
1286 char **seq_values = NULL;
1287 char **modifiers = NULL;
1289 PQExpBufferData title;
1290 PQExpBufferData tmpbuf;
1301 bool forcerowsecurity;
1306 char relpersistence;
1309 bool show_modifiers = false;
1314 myopt.default_footer = false;
1315 /* This output looks confusing in expanded mode. */
1316 myopt.expanded = false;
1318 initPQExpBuffer(&buf);
1319 initPQExpBuffer(&title);
1320 initPQExpBuffer(&tmpbuf);
1322 /* Get general table info */
1323 if (pset.sversion >= 90500)
1325 printfPQExpBuffer(&buf,
1326 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1327 "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
1328 "c.relhasoids, %s, c.reltablespace, "
1329 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1330 "c.relpersistence, c.relreplident\n"
1331 "FROM pg_catalog.pg_class c\n "
1332 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1333 "WHERE c.oid = '%s';",
1335 "pg_catalog.array_to_string(c.reloptions || "
1336 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1340 else if (pset.sversion >= 90400)
1342 printfPQExpBuffer(&buf,
1343 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1344 "c.relhastriggers, false, false, c.relhasoids, "
1345 "%s, c.reltablespace, "
1346 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1347 "c.relpersistence, c.relreplident\n"
1348 "FROM pg_catalog.pg_class c\n "
1349 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1350 "WHERE c.oid = '%s';",
1352 "pg_catalog.array_to_string(c.reloptions || "
1353 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1357 else if (pset.sversion >= 90100)
1359 printfPQExpBuffer(&buf,
1360 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1361 "c.relhastriggers, false, false, c.relhasoids, "
1362 "%s, c.reltablespace, "
1363 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1364 "c.relpersistence\n"
1365 "FROM pg_catalog.pg_class c\n "
1366 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1367 "WHERE c.oid = '%s';",
1369 "pg_catalog.array_to_string(c.reloptions || "
1370 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1374 else if (pset.sversion >= 90000)
1376 printfPQExpBuffer(&buf,
1377 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1378 "c.relhastriggers, false, false, c.relhasoids, "
1379 "%s, c.reltablespace, "
1380 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END\n"
1381 "FROM pg_catalog.pg_class c\n "
1382 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1383 "WHERE c.oid = '%s';",
1385 "pg_catalog.array_to_string(c.reloptions || "
1386 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1390 else if (pset.sversion >= 80400)
1392 printfPQExpBuffer(&buf,
1393 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1394 "c.relhastriggers, false, false, c.relhasoids, "
1395 "%s, c.reltablespace\n"
1396 "FROM pg_catalog.pg_class c\n "
1397 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1398 "WHERE c.oid = '%s';",
1400 "pg_catalog.array_to_string(c.reloptions || "
1401 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1405 else if (pset.sversion >= 80200)
1407 printfPQExpBuffer(&buf,
1408 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1409 "reltriggers <> 0, false, false, relhasoids, "
1410 "%s, reltablespace\n"
1411 "FROM pg_catalog.pg_class WHERE oid = '%s';",
1413 "pg_catalog.array_to_string(reloptions, E', ')" : "''"),
1416 else if (pset.sversion >= 80000)
1418 printfPQExpBuffer(&buf,
1419 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1420 "reltriggers <> 0, false, false, relhasoids, "
1421 "'', reltablespace\n"
1422 "FROM pg_catalog.pg_class WHERE oid = '%s';",
1427 printfPQExpBuffer(&buf,
1428 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1429 "reltriggers <> 0, false, false, relhasoids, "
1431 "FROM pg_catalog.pg_class WHERE oid = '%s';",
1435 res = PSQLexec(buf.data);
1439 /* Did we get anything? */
1440 if (PQntuples(res) == 0)
1443 psql_error("Did not find any relation with OID %s.\n", oid);
1447 tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
1448 tableinfo.relkind = *(PQgetvalue(res, 0, 1));
1449 tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
1450 tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
1451 tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
1452 tableinfo.rowsecurity = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
1453 tableinfo.forcerowsecurity = strcmp(PQgetvalue(res, 0, 6), "t") == 0;
1454 tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 7), "t") == 0;
1455 tableinfo.reloptions = (pset.sversion >= 80200) ?
1456 pg_strdup(PQgetvalue(res, 0, 8)) : NULL;
1457 tableinfo.tablespace = (pset.sversion >= 80000) ?
1458 atooid(PQgetvalue(res, 0, 9)) : 0;
1459 tableinfo.reloftype = (pset.sversion >= 90000 &&
1460 strcmp(PQgetvalue(res, 0, 10), "") != 0) ?
1461 pg_strdup(PQgetvalue(res, 0, 10)) : NULL;
1462 tableinfo.relpersistence = (pset.sversion >= 90100) ?
1463 *(PQgetvalue(res, 0, 11)) : 0;
1464 tableinfo.relreplident = (pset.sversion >= 90400) ?
1465 *(PQgetvalue(res, 0, 12)) : 'd';
1470 * If it's a sequence, fetch its values and store into an array that will
1473 if (tableinfo.relkind == 'S')
1475 printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
1476 /* must be separate because fmtId isn't reentrant */
1477 appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
1479 res = PSQLexec(buf.data);
1483 seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
1485 for (i = 0; i < PQnfields(res); i++)
1486 seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
1487 seq_values[i] = NULL;
1496 * You need to modify value of "firstvcol" which will be defined below if
1497 * you are adding column(s) preceding to verbose-only columns.
1499 printfPQExpBuffer(&buf, "SELECT a.attname,");
1500 appendPQExpBufferStr(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
1501 "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
1502 "\n FROM pg_catalog.pg_attrdef d"
1503 "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
1504 "\n a.attnotnull, a.attnum,");
1505 if (pset.sversion >= 90100)
1506 appendPQExpBufferStr(&buf, "\n (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
1507 " WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
1509 appendPQExpBufferStr(&buf, "\n NULL AS attcollation");
1510 if (tableinfo.relkind == 'i')
1511 appendPQExpBufferStr(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
1513 appendPQExpBufferStr(&buf, ",\n NULL AS indexdef");
1514 if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
1515 appendPQExpBufferStr(&buf, ",\n CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
1516 " '(' || array_to_string(ARRAY(SELECT quote_ident(option_name) || ' ' || quote_literal(option_value) FROM "
1517 " pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
1519 appendPQExpBufferStr(&buf, ",\n NULL AS attfdwoptions");
1522 appendPQExpBufferStr(&buf, ",\n a.attstorage");
1523 appendPQExpBufferStr(&buf, ",\n CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
1526 * In 9.0+, we have column comments for: relations, views, composite
1527 * types, and foreign tables (c.f. CommentObject() in comment.c).
1529 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
1530 tableinfo.relkind == 'm' ||
1531 tableinfo.relkind == 'f' || tableinfo.relkind == 'c')
1532 appendPQExpBufferStr(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)");
1535 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_attribute a");
1536 appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
1537 appendPQExpBufferStr(&buf, "\nORDER BY a.attnum;");
1539 res = PSQLexec(buf.data);
1542 numrows = PQntuples(res);
1545 switch (tableinfo.relkind)
1548 if (tableinfo.relpersistence == 'u')
1549 printfPQExpBuffer(&title, _("Unlogged table \"%s.%s\""),
1550 schemaname, relationname);
1552 printfPQExpBuffer(&title, _("Table \"%s.%s\""),
1553 schemaname, relationname);
1556 printfPQExpBuffer(&title, _("View \"%s.%s\""),
1557 schemaname, relationname);
1560 if (tableinfo.relpersistence == 'u')
1561 printfPQExpBuffer(&title, _("Unlogged materialized view \"%s.%s\""),
1562 schemaname, relationname);
1564 printfPQExpBuffer(&title, _("Materialized view \"%s.%s\""),
1565 schemaname, relationname);
1568 printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
1569 schemaname, relationname);
1572 if (tableinfo.relpersistence == 'u')
1573 printfPQExpBuffer(&title, _("Unlogged index \"%s.%s\""),
1574 schemaname, relationname);
1576 printfPQExpBuffer(&title, _("Index \"%s.%s\""),
1577 schemaname, relationname);
1580 /* not used as of 8.2, but keep it for backwards compatibility */
1581 printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
1582 schemaname, relationname);
1585 printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
1586 schemaname, relationname);
1589 printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
1590 schemaname, relationname);
1593 printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""),
1594 schemaname, relationname);
1597 /* untranslated unknown relkind */
1598 printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
1599 tableinfo.relkind, schemaname, relationname);
1603 /* Set the number of columns, and their names */
1604 headers[0] = gettext_noop("Column");
1605 headers[1] = gettext_noop("Type");
1608 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
1609 tableinfo.relkind == 'm' ||
1610 tableinfo.relkind == 'f' || tableinfo.relkind == 'c')
1612 show_modifiers = true;
1613 headers[cols++] = gettext_noop("Modifiers");
1614 modifiers = pg_malloc0((numrows + 1) * sizeof(*modifiers));
1617 if (tableinfo.relkind == 'S')
1618 headers[cols++] = gettext_noop("Value");
1620 if (tableinfo.relkind == 'i')
1621 headers[cols++] = gettext_noop("Definition");
1623 if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
1624 headers[cols++] = gettext_noop("FDW Options");
1628 headers[cols++] = gettext_noop("Storage");
1629 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
1630 tableinfo.relkind == 'f')
1631 headers[cols++] = gettext_noop("Stats target");
1632 /* Column comments, if the relkind supports this feature. */
1633 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
1634 tableinfo.relkind == 'm' ||
1635 tableinfo.relkind == 'c' || tableinfo.relkind == 'f')
1636 headers[cols++] = gettext_noop("Description");
1639 printTableInit(&cont, &myopt, title.data, cols, numrows);
1640 printTableInitialized = true;
1642 for (i = 0; i < cols; i++)
1643 printTableAddHeader(&cont, headers[i], true, 'l');
1645 /* Check if table is a view or materialized view */
1646 if ((tableinfo.relkind == 'v' || tableinfo.relkind == 'm') && verbose)
1650 printfPQExpBuffer(&buf,
1651 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
1653 result = PSQLexec(buf.data);
1657 if (PQntuples(result) > 0)
1658 view_def = pg_strdup(PQgetvalue(result, 0, 0));
1663 /* Generate table cells to be printed */
1664 for (i = 0; i < numrows; i++)
1667 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
1670 printTableAddCell(&cont, PQgetvalue(res, i, 1), false, false);
1672 /* Modifiers: collate, not null, default */
1675 resetPQExpBuffer(&tmpbuf);
1677 if (!PQgetisnull(res, i, 5))
1680 appendPQExpBufferChar(&tmpbuf, ' ');
1681 appendPQExpBuffer(&tmpbuf, _("collate %s"),
1682 PQgetvalue(res, i, 5));
1685 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
1688 appendPQExpBufferChar(&tmpbuf, ' ');
1689 appendPQExpBufferStr(&tmpbuf, _("not null"));
1692 /* handle "default" here */
1693 /* (note: above we cut off the 'default' string at 128) */
1694 if (strlen(PQgetvalue(res, i, 2)) != 0)
1697 appendPQExpBufferChar(&tmpbuf, ' ');
1698 /* translator: default values of column definitions */
1699 appendPQExpBuffer(&tmpbuf, _("default %s"),
1700 PQgetvalue(res, i, 2));
1703 modifiers[i] = pg_strdup(tmpbuf.data);
1704 printTableAddCell(&cont, modifiers[i], false, false);
1707 /* Value: for sequences only */
1708 if (tableinfo.relkind == 'S')
1709 printTableAddCell(&cont, seq_values[i], false, false);
1711 /* Expression for index column */
1712 if (tableinfo.relkind == 'i')
1713 printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
1715 /* FDW options for foreign table column, only for 9.2 or later */
1716 if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
1717 printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
1719 /* Storage and Description */
1723 char *storage = PQgetvalue(res, i, firstvcol);
1725 /* these strings are literal in our syntax, so not translated. */
1726 printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
1727 (storage[0] == 'm' ? "main" :
1728 (storage[0] == 'x' ? "extended" :
1729 (storage[0] == 'e' ? "external" :
1733 /* Statistics target, if the relkind supports this feature */
1734 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
1735 tableinfo.relkind == 'f')
1737 printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
1741 /* Column comments, if the relkind supports this feature. */
1742 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
1743 tableinfo.relkind == 'm' ||
1744 tableinfo.relkind == 'c' || tableinfo.relkind == 'f')
1745 printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 2),
1751 if (tableinfo.relkind == 'i')
1753 /* Footer information about an index */
1756 printfPQExpBuffer(&buf,
1757 "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
1758 if (pset.sversion >= 80200)
1759 appendPQExpBufferStr(&buf, "i.indisvalid,\n");
1761 appendPQExpBufferStr(&buf, "true AS indisvalid,\n");
1762 if (pset.sversion >= 90000)
1763 appendPQExpBufferStr(&buf,
1764 " (NOT i.indimmediate) AND "
1765 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1766 "WHERE conrelid = i.indrelid AND "
1767 "conindid = i.indexrelid AND "
1768 "contype IN ('p','u','x') AND "
1769 "condeferrable) AS condeferrable,\n"
1770 " (NOT i.indimmediate) AND "
1771 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1772 "WHERE conrelid = i.indrelid AND "
1773 "conindid = i.indexrelid AND "
1774 "contype IN ('p','u','x') AND "
1775 "condeferred) AS condeferred,\n");
1777 appendPQExpBufferStr(&buf,
1778 " false AS condeferrable, false AS condeferred,\n");
1780 if (pset.sversion >= 90400)
1781 appendPQExpBuffer(&buf, "i.indisreplident,\n");
1783 appendPQExpBuffer(&buf, "false AS indisreplident,\n");
1785 appendPQExpBuffer(&buf, " a.amname, c2.relname, "
1786 "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
1787 "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
1788 "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
1789 "AND i.indrelid = c2.oid;",
1792 result = PSQLexec(buf.data);
1795 else if (PQntuples(result) != 1)
1802 char *indisunique = PQgetvalue(result, 0, 0);
1803 char *indisprimary = PQgetvalue(result, 0, 1);
1804 char *indisclustered = PQgetvalue(result, 0, 2);
1805 char *indisvalid = PQgetvalue(result, 0, 3);
1806 char *deferrable = PQgetvalue(result, 0, 4);
1807 char *deferred = PQgetvalue(result, 0, 5);
1808 char *indisreplident = PQgetvalue(result, 0, 6);
1809 char *indamname = PQgetvalue(result, 0, 7);
1810 char *indtable = PQgetvalue(result, 0, 8);
1811 char *indpred = PQgetvalue(result, 0, 9);
1813 if (strcmp(indisprimary, "t") == 0)
1814 printfPQExpBuffer(&tmpbuf, _("primary key, "));
1815 else if (strcmp(indisunique, "t") == 0)
1816 printfPQExpBuffer(&tmpbuf, _("unique, "));
1818 resetPQExpBuffer(&tmpbuf);
1819 appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
1821 /* we assume here that index and table are in same schema */
1822 appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
1823 schemaname, indtable);
1825 if (strlen(indpred))
1826 appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
1828 if (strcmp(indisclustered, "t") == 0)
1829 appendPQExpBufferStr(&tmpbuf, _(", clustered"));
1831 if (strcmp(indisvalid, "t") != 0)
1832 appendPQExpBufferStr(&tmpbuf, _(", invalid"));
1834 if (strcmp(deferrable, "t") == 0)
1835 appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
1837 if (strcmp(deferred, "t") == 0)
1838 appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
1840 if (strcmp(indisreplident, "t") == 0)
1841 appendPQExpBuffer(&tmpbuf, _(", replica identity"));
1843 printTableAddFooter(&cont, tmpbuf.data);
1844 add_tablespace_footer(&cont, tableinfo.relkind,
1845 tableinfo.tablespace, true);
1850 else if (tableinfo.relkind == 'S')
1852 /* Footer information about a sequence */
1853 PGresult *result = NULL;
1855 /* Get the column that owns this sequence */
1856 printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
1857 "\n pg_catalog.quote_ident(relname) || '.' ||"
1858 "\n pg_catalog.quote_ident(attname)"
1859 "\nFROM pg_catalog.pg_class c"
1860 "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
1861 "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
1862 "\nINNER JOIN pg_catalog.pg_attribute a ON ("
1863 "\n a.attrelid=c.oid AND"
1864 "\n a.attnum=d.refobjsubid)"
1865 "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
1866 "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
1868 "\n AND d.deptype='a'",
1871 result = PSQLexec(buf.data);
1874 else if (PQntuples(result) == 1)
1876 printfPQExpBuffer(&buf, _("Owned by: %s"),
1877 PQgetvalue(result, 0, 0));
1878 printTableAddFooter(&cont, buf.data);
1882 * If we get no rows back, don't show anything (obviously). We should
1883 * never get more than one row back, but if we do, just ignore it and
1884 * don't print anything.
1888 else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
1889 tableinfo.relkind == 'f')
1891 /* Footer information about a table */
1892 PGresult *result = NULL;
1896 if (tableinfo.hasindex)
1898 printfPQExpBuffer(&buf,
1899 "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
1900 if (pset.sversion >= 80200)
1901 appendPQExpBufferStr(&buf, "i.indisvalid, ");
1903 appendPQExpBufferStr(&buf, "true as indisvalid, ");
1904 appendPQExpBufferStr(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n ");
1905 if (pset.sversion >= 90000)
1906 appendPQExpBufferStr(&buf,
1907 "pg_catalog.pg_get_constraintdef(con.oid, true), "
1908 "contype, condeferrable, condeferred");
1910 appendPQExpBufferStr(&buf,
1911 "null AS constraintdef, null AS contype, "
1912 "false AS condeferrable, false AS condeferred");
1913 if (pset.sversion >= 90400)
1914 appendPQExpBufferStr(&buf, ", i.indisreplident");
1916 appendPQExpBufferStr(&buf, ", false AS indisreplident");
1917 if (pset.sversion >= 80000)
1918 appendPQExpBufferStr(&buf, ", c2.reltablespace");
1919 appendPQExpBufferStr(&buf,
1920 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
1921 if (pset.sversion >= 90000)
1922 appendPQExpBufferStr(&buf,
1923 " LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
1924 appendPQExpBuffer(&buf,
1925 "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
1926 "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname;",
1928 result = PSQLexec(buf.data);
1932 tuples = PQntuples(result);
1936 printTableAddFooter(&cont, _("Indexes:"));
1937 for (i = 0; i < tuples; i++)
1939 /* untranslated index name */
1940 printfPQExpBuffer(&buf, " \"%s\"",
1941 PQgetvalue(result, i, 0));
1943 /* If exclusion constraint, print the constraintdef */
1944 if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
1946 appendPQExpBuffer(&buf, " %s",
1947 PQgetvalue(result, i, 6));
1951 const char *indexdef;
1952 const char *usingpos;
1954 /* Label as primary key or unique (but not both) */
1955 if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
1956 appendPQExpBufferStr(&buf, " PRIMARY KEY,");
1957 else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
1959 if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
1960 appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
1962 appendPQExpBufferStr(&buf, " UNIQUE,");
1965 /* Everything after "USING" is echoed verbatim */
1966 indexdef = PQgetvalue(result, i, 5);
1967 usingpos = strstr(indexdef, " USING ");
1969 indexdef = usingpos + 7;
1970 appendPQExpBuffer(&buf, " %s", indexdef);
1972 /* Need these for deferrable PK/UNIQUE indexes */
1973 if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
1974 appendPQExpBufferStr(&buf, " DEFERRABLE");
1976 if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
1977 appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
1980 /* Add these for all cases */
1981 if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
1982 appendPQExpBufferStr(&buf, " CLUSTER");
1984 if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
1985 appendPQExpBufferStr(&buf, " INVALID");
1987 if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
1988 appendPQExpBuffer(&buf, " REPLICA IDENTITY");
1990 printTableAddFooter(&cont, buf.data);
1992 /* Print tablespace of the index on the same line */
1993 if (pset.sversion >= 80000)
1994 add_tablespace_footer(&cont, 'i',
1995 atooid(PQgetvalue(result, i, 11)),
2002 /* print table (and column) check constraints */
2003 if (tableinfo.checks)
2005 printfPQExpBuffer(&buf,
2006 "SELECT r.conname, "
2007 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
2008 "FROM pg_catalog.pg_constraint r\n"
2009 "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
2012 result = PSQLexec(buf.data);
2016 tuples = PQntuples(result);
2020 printTableAddFooter(&cont, _("Check constraints:"));
2021 for (i = 0; i < tuples; i++)
2023 /* untranslated contraint name and def */
2024 printfPQExpBuffer(&buf, " \"%s\" %s",
2025 PQgetvalue(result, i, 0),
2026 PQgetvalue(result, i, 1));
2028 printTableAddFooter(&cont, buf.data);
2034 /* print foreign-key constraints (there are none if no triggers) */
2035 if (tableinfo.hastriggers)
2037 printfPQExpBuffer(&buf,
2039 " pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n"
2040 "FROM pg_catalog.pg_constraint r\n"
2041 "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1;",
2043 result = PSQLexec(buf.data);
2047 tuples = PQntuples(result);
2051 printTableAddFooter(&cont, _("Foreign-key constraints:"));
2052 for (i = 0; i < tuples; i++)
2054 /* untranslated constraint name and def */
2055 printfPQExpBuffer(&buf, " \"%s\" %s",
2056 PQgetvalue(result, i, 0),
2057 PQgetvalue(result, i, 1));
2059 printTableAddFooter(&cont, buf.data);
2065 /* print incoming foreign-key references (none if no triggers) */
2066 if (tableinfo.hastriggers)
2068 printfPQExpBuffer(&buf,
2069 "SELECT conname, conrelid::pg_catalog.regclass,\n"
2070 " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
2071 "FROM pg_catalog.pg_constraint c\n"
2072 "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1;",
2074 result = PSQLexec(buf.data);
2078 tuples = PQntuples(result);
2082 printTableAddFooter(&cont, _("Referenced by:"));
2083 for (i = 0; i < tuples; i++)
2085 printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
2086 PQgetvalue(result, i, 1),
2087 PQgetvalue(result, i, 0),
2088 PQgetvalue(result, i, 2));
2090 printTableAddFooter(&cont, buf.data);
2096 /* print any row-level policies */
2097 if (pset.sversion >= 90500)
2099 printfPQExpBuffer(&buf,
2100 "SELECT pol.polname,\n"
2101 "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
2102 "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
2103 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
2104 "CASE pol.polcmd \n"
2105 "WHEN 'r' THEN 'SELECT'\n"
2106 "WHEN 'a' THEN 'INSERT'\n"
2107 "WHEN 'w' THEN 'UPDATE'\n"
2108 "WHEN 'd' THEN 'DELETE'\n"
2109 "WHEN '*' THEN 'ALL'\n"
2111 "FROM pg_catalog.pg_policy pol\n"
2112 "WHERE pol.polrelid = '%s' ORDER BY 1;",
2115 result = PSQLexec(buf.data);
2119 tuples = PQntuples(result);
2122 * Handle cases where RLS is enabled and there are policies, or
2123 * there aren't policies, or RLS isn't enabled but there are
2126 if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
2127 printTableAddFooter(&cont, _("Policies:"));
2129 if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
2130 printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
2132 if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
2133 printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
2135 if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
2136 printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
2138 if (!tableinfo.rowsecurity && tuples > 0)
2139 printTableAddFooter(&cont, _("Policies (row security disabled):"));
2141 /* Might be an empty set - that's ok */
2142 for (i = 0; i < tuples; i++)
2144 printfPQExpBuffer(&buf, " POLICY \"%s\"",
2145 PQgetvalue(result, i, 0));
2147 if (!PQgetisnull(result, i, 4))
2148 appendPQExpBuffer(&buf, " FOR %s",
2149 PQgetvalue(result, i, 4));
2151 if (!PQgetisnull(result, i, 1))
2153 appendPQExpBuffer(&buf, "\n TO %s",
2154 PQgetvalue(result, i, 1));
2157 if (!PQgetisnull(result, i, 2))
2158 appendPQExpBuffer(&buf, "\n USING (%s)",
2159 PQgetvalue(result, i, 2));
2161 if (!PQgetisnull(result, i, 3))
2162 appendPQExpBuffer(&buf, "\n WITH CHECK (%s)",
2163 PQgetvalue(result, i, 3));
2165 printTableAddFooter(&cont, buf.data);
2172 if (tableinfo.hasrules && tableinfo.relkind != 'm')
2174 if (pset.sversion >= 80300)
2176 printfPQExpBuffer(&buf,
2177 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
2179 "FROM pg_catalog.pg_rewrite r\n"
2180 "WHERE r.ev_class = '%s' ORDER BY 1;",
2185 printfPQExpBuffer(&buf,
2186 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
2187 "'O'::char AS ev_enabled\n"
2188 "FROM pg_catalog.pg_rewrite r\n"
2189 "WHERE r.ev_class = '%s' ORDER BY 1;",
2192 result = PSQLexec(buf.data);
2196 tuples = PQntuples(result);
2203 for (category = 0; category < 4; category++)
2205 have_heading = false;
2207 for (i = 0; i < tuples; i++)
2209 const char *ruledef;
2210 bool list_rule = false;
2215 if (*PQgetvalue(result, i, 2) == 'O')
2219 if (*PQgetvalue(result, i, 2) == 'D')
2223 if (*PQgetvalue(result, i, 2) == 'A')
2227 if (*PQgetvalue(result, i, 2) == 'R')
2239 printfPQExpBuffer(&buf, _("Rules:"));
2242 printfPQExpBuffer(&buf, _("Disabled rules:"));
2245 printfPQExpBuffer(&buf, _("Rules firing always:"));
2248 printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
2251 printTableAddFooter(&cont, buf.data);
2252 have_heading = true;
2255 /* Everything after "CREATE RULE" is echoed verbatim */
2256 ruledef = PQgetvalue(result, i, 1);
2258 printfPQExpBuffer(&buf, " %s", ruledef);
2259 printTableAddFooter(&cont, buf.data);
2269 PGresult *result = NULL;
2271 /* Footer information about a view */
2272 printTableAddFooter(&cont, _("View definition:"));
2273 printTableAddFooter(&cont, view_def);
2276 if (tableinfo.hasrules)
2278 printfPQExpBuffer(&buf,
2279 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
2280 "FROM pg_catalog.pg_rewrite r\n"
2281 "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1;",
2283 result = PSQLexec(buf.data);
2287 if (PQntuples(result) > 0)
2289 printTableAddFooter(&cont, _("Rules:"));
2290 for (i = 0; i < PQntuples(result); i++)
2292 const char *ruledef;
2294 /* Everything after "CREATE RULE" is echoed verbatim */
2295 ruledef = PQgetvalue(result, i, 1);
2298 printfPQExpBuffer(&buf, " %s", ruledef);
2299 printTableAddFooter(&cont, buf.data);
2307 * Print triggers next, if any (but only user-defined triggers). This
2308 * could apply to either a table or a view.
2310 if (tableinfo.hastriggers)
2315 printfPQExpBuffer(&buf,
2317 "pg_catalog.pg_get_triggerdef(t.oid%s), "
2319 "FROM pg_catalog.pg_trigger t\n"
2320 "WHERE t.tgrelid = '%s' AND ",
2321 (pset.sversion >= 90000 ? ", true" : ""),
2322 (pset.sversion >= 90000 ? "t.tgisinternal" :
2323 pset.sversion >= 80300 ?
2324 "t.tgconstraint <> 0 AS tgisinternal" :
2325 "false AS tgisinternal"), oid);
2326 if (pset.sversion >= 90000)
2327 /* display/warn about disabled internal triggers */
2328 appendPQExpBuffer(&buf, "(NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))");
2329 else if (pset.sversion >= 80300)
2330 appendPQExpBufferStr(&buf, "(t.tgconstraint = 0 OR (t.tgconstraint <> 0 AND t.tgenabled = 'D'))");
2332 appendPQExpBufferStr(&buf,
2333 "(NOT tgisconstraint "
2335 " (SELECT 1 FROM pg_catalog.pg_depend d "
2336 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
2337 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
2338 appendPQExpBufferStr(&buf, "\nORDER BY 1;");
2340 result = PSQLexec(buf.data);
2344 tuples = PQntuples(result);
2352 * split the output into 4 different categories. Enabled triggers,
2353 * disabled triggers and the two special ALWAYS and REPLICA
2356 for (category = 0; category <= 4; category++)
2358 have_heading = false;
2359 for (i = 0; i < tuples; i++)
2363 const char *usingpos;
2364 const char *tgenabled;
2365 const char *tgisinternal;
2368 * Check if this trigger falls into the current category
2370 tgenabled = PQgetvalue(result, i, 2);
2371 tgisinternal = PQgetvalue(result, i, 3);
2372 list_trigger = false;
2376 if (*tgenabled == 'O' || *tgenabled == 't')
2377 list_trigger = true;
2380 if ((*tgenabled == 'D' || *tgenabled == 'f') &&
2381 *tgisinternal == 'f')
2382 list_trigger = true;
2385 if ((*tgenabled == 'D' || *tgenabled == 'f') &&
2386 *tgisinternal == 't')
2387 list_trigger = true;
2390 if (*tgenabled == 'A')
2391 list_trigger = true;
2394 if (*tgenabled == 'R')
2395 list_trigger = true;
2398 if (list_trigger == false)
2401 /* Print the category heading once */
2402 if (have_heading == false)
2407 printfPQExpBuffer(&buf, _("Triggers:"));
2410 if (pset.sversion >= 80300)
2411 printfPQExpBuffer(&buf, _("Disabled user triggers:"));
2413 printfPQExpBuffer(&buf, _("Disabled triggers:"));
2416 printfPQExpBuffer(&buf, _("Disabled internal triggers:"));
2419 printfPQExpBuffer(&buf, _("Triggers firing always:"));
2422 printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
2426 printTableAddFooter(&cont, buf.data);
2427 have_heading = true;
2430 /* Everything after "TRIGGER" is echoed verbatim */
2431 tgdef = PQgetvalue(result, i, 1);
2432 usingpos = strstr(tgdef, " TRIGGER ");
2434 tgdef = usingpos + 9;
2436 printfPQExpBuffer(&buf, " %s", tgdef);
2437 printTableAddFooter(&cont, buf.data);
2445 * Finish printing the footer information about a table.
2447 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
2448 tableinfo.relkind == 'f')
2453 /* print foreign server name */
2454 if (tableinfo.relkind == 'f')
2458 /* Footer information about foreign table */
2459 printfPQExpBuffer(&buf,
2460 "SELECT s.srvname,\n"
2461 " array_to_string(ARRAY(SELECT "
2462 " quote_ident(option_name) || ' ' || "
2463 " quote_literal(option_value) FROM "
2464 " pg_options_to_table(ftoptions)), ', ') "
2465 "FROM pg_catalog.pg_foreign_table f,\n"
2466 " pg_catalog.pg_foreign_server s\n"
2467 "WHERE f.ftrelid = %s AND s.oid = f.ftserver;",
2469 result = PSQLexec(buf.data);
2472 else if (PQntuples(result) != 1)
2478 /* Print server name */
2479 printfPQExpBuffer(&buf, "Server: %s",
2480 PQgetvalue(result, 0, 0));
2481 printTableAddFooter(&cont, buf.data);
2483 /* Print per-table FDW options, if any */
2484 ftoptions = PQgetvalue(result, 0, 1);
2485 if (ftoptions && ftoptions[0] != '\0')
2487 printfPQExpBuffer(&buf, "FDW Options: (%s)", ftoptions);
2488 printTableAddFooter(&cont, buf.data);
2493 /* print inherited tables */
2494 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);
2496 result = PSQLexec(buf.data);
2501 const char *s = _("Inherits");
2502 int sw = pg_wcswidth(s, strlen(s), pset.encoding);
2504 tuples = PQntuples(result);
2506 for (i = 0; i < tuples; i++)
2509 printfPQExpBuffer(&buf, "%s: %s",
2510 s, PQgetvalue(result, i, 0));
2512 printfPQExpBuffer(&buf, "%*s %s",
2513 sw, "", PQgetvalue(result, i, 0));
2515 appendPQExpBufferChar(&buf, ',');
2517 printTableAddFooter(&cont, buf.data);
2523 /* print child tables */
2524 if (pset.sversion >= 80300)
2525 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);
2527 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);
2529 result = PSQLexec(buf.data);
2533 tuples = PQntuples(result);
2537 /* print the number of child tables, if any */
2540 printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
2541 printTableAddFooter(&cont, buf.data);
2546 /* display the list of child tables */
2547 const char *ct = _("Child tables");
2548 int ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
2550 for (i = 0; i < tuples; i++)
2553 printfPQExpBuffer(&buf, "%s: %s",
2554 ct, PQgetvalue(result, i, 0));
2556 printfPQExpBuffer(&buf, "%*s %s",
2557 ctw, "", PQgetvalue(result, i, 0));
2559 appendPQExpBufferChar(&buf, ',');
2561 printTableAddFooter(&cont, buf.data);
2567 if (tableinfo.reloftype)
2569 printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
2570 printTableAddFooter(&cont, buf.data);
2573 if (verbose && (tableinfo.relkind == 'r' || tableinfo.relkind == 'm') &&
2576 * No need to display default values; we already display a REPLICA
2577 * IDENTITY marker on indexes.
2579 tableinfo.relreplident != 'i' &&
2580 ((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
2581 (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
2583 const char *s = _("Replica Identity");
2585 printfPQExpBuffer(&buf, "%s: %s",
2587 tableinfo.relreplident == 'f' ? "FULL" :
2588 tableinfo.relreplident == 'n' ? "NOTHING" :
2591 printTableAddFooter(&cont, buf.data);
2594 /* OIDs, if verbose and not a materialized view */
2595 if (verbose && tableinfo.relkind != 'm' && tableinfo.hasoids)
2596 printTableAddFooter(&cont, _("Has OIDs: yes"));
2598 /* Tablespace info */
2599 add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
2603 /* reloptions, if verbose */
2605 tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
2607 const char *t = _("Options");
2609 printfPQExpBuffer(&buf, "%s: %s", t, tableinfo.reloptions);
2610 printTableAddFooter(&cont, buf.data);
2613 printTable(&cont, pset.queryFout, false, pset.logfile);
2620 if (printTableInitialized)
2621 printTableCleanup(&cont);
2622 termPQExpBuffer(&buf);
2623 termPQExpBuffer(&title);
2624 termPQExpBuffer(&tmpbuf);
2628 for (ptr = seq_values; *ptr; ptr++)
2635 for (ptr = modifiers; *ptr; ptr++)
2650 * Add a tablespace description to a footer. If 'newline' is true, it is added
2651 * in a new line; otherwise it's appended to the current value of the last
2655 add_tablespace_footer(printTableContent *const cont, char relkind,
2656 Oid tablespace, const bool newline)
2658 /* relkinds for which we support tablespaces */
2659 if (relkind == 'r' || relkind == 'm' || relkind == 'i')
2662 * We ignore the database default tablespace so that users not using
2663 * tablespaces don't need to know about them. This case also covers
2664 * pre-8.0 servers, for which tablespace will always be 0.
2666 if (tablespace != 0)
2668 PGresult *result = NULL;
2669 PQExpBufferData buf;
2671 initPQExpBuffer(&buf);
2672 printfPQExpBuffer(&buf,
2673 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
2674 "WHERE oid = '%u';", tablespace);
2675 result = PSQLexec(buf.data);
2678 /* Should always be the case, but.... */
2679 if (PQntuples(result) > 0)
2683 /* Add the tablespace as a new footer */
2684 printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
2685 PQgetvalue(result, 0, 0));
2686 printTableAddFooter(cont, buf.data);
2690 /* Append the tablespace to the latest footer */
2691 printfPQExpBuffer(&buf, "%s", cont->footer->data);
2694 translator: before this string there's an index description like
2695 '"foo_pkey" PRIMARY KEY, btree (a)' */
2696 appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
2697 PQgetvalue(result, 0, 0));
2698 printTableSetFooter(cont, buf.data);
2702 termPQExpBuffer(&buf);
2710 * Describes roles. Any schema portion of the pattern is ignored.
2713 describeRoles(const char *pattern, bool verbose, bool showSystem)
2715 PQExpBufferData buf;
2717 printTableContent cont;
2718 printTableOpt myopt = pset.popt.topt;
2723 const char align = 'l';
2726 myopt.default_footer = false;
2728 initPQExpBuffer(&buf);
2730 if (pset.sversion >= 80100)
2732 printfPQExpBuffer(&buf,
2733 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
2734 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
2735 " r.rolconnlimit, r.rolvaliduntil,\n"
2736 " ARRAY(SELECT b.rolname\n"
2737 " FROM pg_catalog.pg_auth_members m\n"
2738 " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
2739 " WHERE m.member = r.oid) as memberof");
2741 if (verbose && pset.sversion >= 80200)
2743 appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
2746 if (pset.sversion >= 90100)
2748 appendPQExpBufferStr(&buf, "\n, r.rolreplication");
2751 if (pset.sversion >= 90500)
2753 appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
2756 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
2758 if (!showSystem && !pattern)
2759 appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
2761 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2762 NULL, "r.rolname", NULL, NULL);
2766 printfPQExpBuffer(&buf,
2767 "SELECT u.usename AS rolname,\n"
2768 " u.usesuper AS rolsuper,\n"
2769 " true AS rolinherit, false AS rolcreaterole,\n"
2770 " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
2771 " -1 AS rolconnlimit,"
2772 " u.valuntil as rolvaliduntil,\n"
2773 " ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
2774 "\nFROM pg_catalog.pg_user u\n");
2776 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2777 NULL, "u.usename", NULL, NULL);
2780 appendPQExpBufferStr(&buf, "ORDER BY 1;");
2782 res = PSQLexec(buf.data);
2786 nrows = PQntuples(res);
2787 attr = pg_malloc0((nrows + 1) * sizeof(*attr));
2789 printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
2791 printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
2792 printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
2793 printTableAddHeader(&cont, gettext_noop("Member of"), true, align);
2795 if (verbose && pset.sversion >= 80200)
2796 printTableAddHeader(&cont, gettext_noop("Description"), true, align);
2798 for (i = 0; i < nrows; i++)
2800 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
2802 resetPQExpBuffer(&buf);
2803 if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
2804 add_role_attribute(&buf, _("Superuser"));
2806 if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
2807 add_role_attribute(&buf, _("No inheritance"));
2809 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
2810 add_role_attribute(&buf, _("Create role"));
2812 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
2813 add_role_attribute(&buf, _("Create DB"));
2815 if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
2816 add_role_attribute(&buf, _("Cannot login"));
2818 if (pset.sversion >= 90100)
2819 if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
2820 add_role_attribute(&buf, _("Replication"));
2822 if (pset.sversion >= 90500)
2823 if (strcmp(PQgetvalue(res, i, (verbose ? 11 : 10)), "t") == 0)
2824 add_role_attribute(&buf, _("Bypass RLS"));
2826 conns = atoi(PQgetvalue(res, i, 6));
2830 appendPQExpBufferChar(&buf, '\n');
2833 appendPQExpBufferStr(&buf, _("No connections"));
2835 appendPQExpBuffer(&buf, ngettext("%d connection",
2841 if (strcmp(PQgetvalue(res, i, 7), "") != 0)
2844 appendPQExpBufferStr(&buf, "\n");
2845 appendPQExpBufferStr(&buf, _("Password valid until "));
2846 appendPQExpBufferStr(&buf, PQgetvalue(res, i, 7));
2849 attr[i] = pg_strdup(buf.data);
2851 printTableAddCell(&cont, attr[i], false, false);
2853 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
2855 if (verbose && pset.sversion >= 80200)
2856 printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
2858 termPQExpBuffer(&buf);
2860 printTable(&cont, pset.queryFout, false, pset.logfile);
2861 printTableCleanup(&cont);
2863 for (i = 0; i < nrows; i++)
2872 add_role_attribute(PQExpBuffer buf, const char *const str)
2875 appendPQExpBufferStr(buf, ", ");
2877 appendPQExpBufferStr(buf, str);
2884 listDbRoleSettings(const char *pattern, const char *pattern2)
2886 PQExpBufferData buf;
2888 printQueryOpt myopt = pset.popt;
2890 initPQExpBuffer(&buf);
2892 if (pset.sversion >= 90000)
2896 printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
2897 "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
2898 "FROM pg_db_role_setting AS s\n"
2899 "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n"
2900 "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n",
2901 gettext_noop("Role"),
2902 gettext_noop("Database"),
2903 gettext_noop("Settings"));
2904 havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
2905 NULL, "pg_roles.rolname", NULL, NULL);
2906 processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
2907 NULL, "pg_database.datname", NULL, NULL);
2908 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
2912 fprintf(pset.queryFout,
2913 _("No per-database role settings support in this server version.\n"));
2917 res = PSQLexec(buf.data);
2921 if (PQntuples(res) == 0 && !pset.quiet)
2924 fprintf(pset.queryFout, _("No matching settings found.\n"));
2926 fprintf(pset.queryFout, _("No settings found.\n"));
2930 myopt.nullPrint = NULL;
2931 myopt.title = _("List of settings");
2932 myopt.translate_header = true;
2934 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
2938 resetPQExpBuffer(&buf);
2946 * handler for \dt, \di, etc.
2948 * tabtypes is an array of characters, specifying what info is desired:
2952 * m - materialized views
2954 * E - foreign table (Note: different from 'f', the relkind value)
2955 * (any order of the above is fine)
2956 * If tabtypes is empty, we default to \dtvsE.
2959 listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
2961 bool showTables = strchr(tabtypes, 't') != NULL;
2962 bool showIndexes = strchr(tabtypes, 'i') != NULL;
2963 bool showViews = strchr(tabtypes, 'v') != NULL;
2964 bool showMatViews = strchr(tabtypes, 'm') != NULL;
2965 bool showSeq = strchr(tabtypes, 's') != NULL;
2966 bool showForeign = strchr(tabtypes, 'E') != NULL;
2968 PQExpBufferData buf;
2970 printQueryOpt myopt = pset.popt;
2971 static const bool translate_columns[] = {false, false, true, false, false, false, false};
2973 if (!(showTables || showIndexes || showViews || showMatViews || showSeq || showForeign))
2974 showTables = showViews = showMatViews = showSeq = showForeign = true;
2976 initPQExpBuffer(&buf);
2979 * Note: as of Pg 8.2, we no longer use relkind 's', but we keep it here
2980 * for backwards compatibility.
2982 printfPQExpBuffer(&buf,
2983 "SELECT n.nspname as \"%s\",\n"
2984 " c.relname as \"%s\",\n"
2986 " WHEN 'r' THEN '%s'"
2987 " WHEN 'v' THEN '%s'"
2988 " WHEN 'm' THEN '%s'"
2989 " WHEN 'i' THEN '%s'"
2990 " WHEN 'S' THEN '%s'"
2991 " WHEN 's' THEN '%s'"
2992 " WHEN 'f' THEN '%s'"
2994 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
2995 gettext_noop("Schema"),
2996 gettext_noop("Name"),
2997 gettext_noop("table"),
2998 gettext_noop("view"),
2999 gettext_noop("materialized view"),
3000 gettext_noop("index"),
3001 gettext_noop("sequence"),
3002 gettext_noop("special"),
3003 gettext_noop("foreign table"),
3004 gettext_noop("Type"),
3005 gettext_noop("Owner"));
3008 appendPQExpBuffer(&buf,
3009 ",\n c2.relname as \"%s\"",
3010 gettext_noop("Table"));
3015 * As of PostgreSQL 9.0, use pg_table_size() to show a more acurate
3016 * size of a table, including FSM, VM and TOAST tables.
3018 if (pset.sversion >= 90000)
3019 appendPQExpBuffer(&buf,
3020 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \"%s\"",
3021 gettext_noop("Size"));
3022 else if (pset.sversion >= 80100)
3023 appendPQExpBuffer(&buf,
3024 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
3025 gettext_noop("Size"));
3027 appendPQExpBuffer(&buf,
3028 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
3029 gettext_noop("Description"));
3032 appendPQExpBufferStr(&buf,
3033 "\nFROM pg_catalog.pg_class c"
3034 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
3036 appendPQExpBufferStr(&buf,
3037 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
3038 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
3040 appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
3042 appendPQExpBufferStr(&buf, "'r',");
3044 appendPQExpBufferStr(&buf, "'v',");
3046 appendPQExpBufferStr(&buf, "'m',");
3048 appendPQExpBufferStr(&buf, "'i',");
3050 appendPQExpBufferStr(&buf, "'S',");
3051 if (showSystem || pattern)
3052 appendPQExpBufferStr(&buf, "'s',"); /* was RELKIND_SPECIAL in <=
3055 appendPQExpBufferStr(&buf, "'f',");
3057 appendPQExpBufferStr(&buf, "''"); /* dummy */
3058 appendPQExpBufferStr(&buf, ")\n");
3060 if (!showSystem && !pattern)
3061 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
3062 " AND n.nspname <> 'information_schema'\n");
3065 * TOAST objects are suppressed unconditionally. Since we don't provide
3066 * any way to select relkind 't' above, we would never show toast tables
3067 * in any case; it seems a bit confusing to allow their indexes to be
3068 * shown. Use plain \d if you really need to look at a TOAST table/index.
3070 appendPQExpBufferStr(&buf, " AND n.nspname !~ '^pg_toast'\n");
3072 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3073 "n.nspname", "c.relname", NULL,
3074 "pg_catalog.pg_table_is_visible(c.oid)");
3076 appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
3078 res = PSQLexec(buf.data);
3079 termPQExpBuffer(&buf);
3083 if (PQntuples(res) == 0 && !pset.quiet)
3086 fprintf(pset.queryFout, _("No matching relations found.\n"));
3088 fprintf(pset.queryFout, _("No relations found.\n"));
3092 myopt.nullPrint = NULL;
3093 myopt.title = _("List of relations");
3094 myopt.translate_header = true;
3095 myopt.translate_columns = translate_columns;
3096 myopt.n_translate_columns = lengthof(translate_columns);
3098 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3109 * Describes languages.
3112 listLanguages(const char *pattern, bool verbose, bool showSystem)
3114 PQExpBufferData buf;
3116 printQueryOpt myopt = pset.popt;
3118 initPQExpBuffer(&buf);
3120 printfPQExpBuffer(&buf,
3121 "SELECT l.lanname AS \"%s\",\n",
3122 gettext_noop("Name"));
3123 if (pset.sversion >= 80300)
3124 appendPQExpBuffer(&buf,
3125 " pg_catalog.pg_get_userbyid(l.lanowner) as \"%s\",\n",
3126 gettext_noop("Owner"));
3128 appendPQExpBuffer(&buf,
3129 " l.lanpltrusted AS \"%s\"",
3130 gettext_noop("Trusted"));
3134 appendPQExpBuffer(&buf,
3135 ",\n NOT l.lanispl AS \"%s\",\n"
3136 " l.lanplcallfoid::regprocedure AS \"%s\",\n"
3137 " l.lanvalidator::regprocedure AS \"%s\",\n ",
3138 gettext_noop("Internal Language"),
3139 gettext_noop("Call Handler"),
3140 gettext_noop("Validator"));
3141 if (pset.sversion >= 90000)
3142 appendPQExpBuffer(&buf, "l.laninline::regprocedure AS \"%s\",\n ",
3143 gettext_noop("Inline Handler"));
3144 printACLColumn(&buf, "l.lanacl");
3147 appendPQExpBuffer(&buf,
3148 ",\n d.description AS \"%s\""
3149 "\nFROM pg_catalog.pg_language l\n"
3150 "LEFT JOIN pg_catalog.pg_description d\n"
3151 " ON d.classoid = l.tableoid AND d.objoid = l.oid\n"
3152 " AND d.objsubid = 0\n",
3153 gettext_noop("Description"));
3156 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3157 NULL, "l.lanname", NULL, NULL);
3159 if (!showSystem && !pattern)
3160 appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n");
3163 appendPQExpBufferStr(&buf, "ORDER BY 1;");
3165 res = PSQLexec(buf.data);
3166 termPQExpBuffer(&buf);
3170 myopt.nullPrint = NULL;
3171 myopt.title = _("List of languages");
3172 myopt.translate_header = true;
3174 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3184 * Describes domains.
3187 listDomains(const char *pattern, bool verbose, bool showSystem)
3189 PQExpBufferData buf;
3191 printQueryOpt myopt = pset.popt;
3193 initPQExpBuffer(&buf);
3195 printfPQExpBuffer(&buf,
3196 "SELECT n.nspname as \"%s\",\n"
3197 " t.typname as \"%s\",\n"
3198 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
3200 gettext_noop("Schema"),
3201 gettext_noop("Name"),
3202 gettext_noop("Type"));
3204 if (pset.sversion >= 90100)
3205 appendPQExpBufferStr(&buf,
3206 " COALESCE((SELECT ' collate ' || c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
3207 " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation), '') ||\n");
3208 appendPQExpBuffer(&buf,
3209 " CASE WHEN t.typnotnull THEN ' not null' ELSE '' END ||\n"
3210 " CASE WHEN t.typdefault IS NOT NULL THEN ' default ' || t.typdefault ELSE '' END\n"
3212 " pg_catalog.array_to_string(ARRAY(\n"
3213 " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
3214 " ), ' ') as \"%s\"",
3215 gettext_noop("Modifier"),
3216 gettext_noop("Check"));
3220 if (pset.sversion >= 90200)
3222 appendPQExpBufferStr(&buf, ",\n ");
3223 printACLColumn(&buf, "t.typacl");
3225 appendPQExpBuffer(&buf,
3226 ",\n d.description as \"%s\"",
3227 gettext_noop("Description"));
3230 appendPQExpBufferStr(&buf,
3231 "\nFROM pg_catalog.pg_type t\n"
3232 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
3235 appendPQExpBufferStr(&buf,
3236 " LEFT JOIN pg_catalog.pg_description d "
3237 "ON d.classoid = t.tableoid AND d.objoid = t.oid "
3238 "AND d.objsubid = 0\n");
3240 appendPQExpBufferStr(&buf, "WHERE t.typtype = 'd'\n");
3242 if (!showSystem && !pattern)
3243 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
3244 " AND n.nspname <> 'information_schema'\n");
3246 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3247 "n.nspname", "t.typname", NULL,
3248 "pg_catalog.pg_type_is_visible(t.oid)");
3250 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3252 res = PSQLexec(buf.data);
3253 termPQExpBuffer(&buf);
3257 myopt.nullPrint = NULL;
3258 myopt.title = _("List of domains");
3259 myopt.translate_header = true;
3261 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3270 * Describes conversions.
3273 listConversions(const char *pattern, bool verbose, bool showSystem)
3275 PQExpBufferData buf;
3277 printQueryOpt myopt = pset.popt;
3278 static const bool translate_columns[] =
3279 {false, false, false, false, true, false};
3281 initPQExpBuffer(&buf);
3283 printfPQExpBuffer(&buf,
3284 "SELECT n.nspname AS \"%s\",\n"
3285 " c.conname AS \"%s\",\n"
3286 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
3287 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
3288 " CASE WHEN c.condefault THEN '%s'\n"
3289 " ELSE '%s' END AS \"%s\"",
3290 gettext_noop("Schema"),
3291 gettext_noop("Name"),
3292 gettext_noop("Source"),
3293 gettext_noop("Destination"),
3294 gettext_noop("yes"), gettext_noop("no"),
3295 gettext_noop("Default?"));
3298 appendPQExpBuffer(&buf,
3299 ",\n d.description AS \"%s\"",
3300 gettext_noop("Description"));
3302 appendPQExpBufferStr(&buf,
3303 "\nFROM pg_catalog.pg_conversion c\n"
3304 " JOIN pg_catalog.pg_namespace n "
3305 "ON n.oid = c.connamespace\n");
3308 appendPQExpBufferStr(&buf,
3309 "LEFT JOIN pg_catalog.pg_description d "
3310 "ON d.classoid = c.tableoid\n"
3311 " AND d.objoid = c.oid "
3312 "AND d.objsubid = 0\n");
3314 appendPQExpBufferStr(&buf, "WHERE true\n");
3316 if (!showSystem && !pattern)
3317 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
3318 " AND n.nspname <> 'information_schema'\n");
3320 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3321 "n.nspname", "c.conname", NULL,
3322 "pg_catalog.pg_conversion_is_visible(c.oid)");
3324 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3326 res = PSQLexec(buf.data);
3327 termPQExpBuffer(&buf);
3331 myopt.nullPrint = NULL;
3332 myopt.title = _("List of conversions");
3333 myopt.translate_header = true;
3334 myopt.translate_columns = translate_columns;
3335 myopt.n_translate_columns = lengthof(translate_columns);
3337 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3346 * Describes Event Triggers.
3349 listEventTriggers(const char *pattern, bool verbose)
3351 PQExpBufferData buf;
3353 printQueryOpt myopt = pset.popt;
3354 static const bool translate_columns[] =
3355 {false, false, false, true, false, false, false};
3357 initPQExpBuffer(&buf);
3359 printfPQExpBuffer(&buf,
3360 "SELECT evtname as \"%s\", "
3361 "evtevent as \"%s\", "
3362 "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
3363 " case evtenabled when 'O' then '%s'"
3364 " when 'R' then '%s'"
3365 " when 'A' then '%s'"
3366 " when 'D' then '%s' end as \"%s\",\n"
3367 " e.evtfoid::pg_catalog.regproc as \"%s\", "
3368 "pg_catalog.array_to_string(array(select x"
3369 " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
3370 gettext_noop("Name"),
3371 gettext_noop("Event"),
3372 gettext_noop("Owner"),
3373 gettext_noop("enabled"),
3374 gettext_noop("replica"),
3375 gettext_noop("always"),
3376 gettext_noop("disabled"),
3377 gettext_noop("Enabled"),
3378 gettext_noop("Procedure"),
3379 gettext_noop("Tags"));
3381 appendPQExpBuffer(&buf,
3382 ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
3383 gettext_noop("Description"));
3384 appendPQExpBufferStr(&buf,
3385 "\nFROM pg_catalog.pg_event_trigger e ");
3387 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3388 NULL, "evtname", NULL, NULL);
3390 appendPQExpBufferStr(&buf, "ORDER BY 1");
3392 res = PSQLexec(buf.data);
3393 termPQExpBuffer(&buf);
3397 myopt.nullPrint = NULL;
3398 myopt.title = _("List of event triggers");
3399 myopt.translate_header = true;
3400 myopt.translate_columns = translate_columns;
3401 myopt.n_translate_columns = lengthof(translate_columns);
3403 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3415 listCasts(const char *pattern, bool verbose)
3417 PQExpBufferData buf;
3419 printQueryOpt myopt = pset.popt;
3420 static const bool translate_columns[] = {false, false, false, true, false};
3422 initPQExpBuffer(&buf);
3425 * We need a left join to pg_proc for binary casts; the others are just
3426 * paranoia. Also note that we don't attempt to localize '(binary
3427 * coercible)', because there's too much risk of gettext translating a
3428 * function name that happens to match some string in the PO database.
3430 printfPQExpBuffer(&buf,
3431 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
3432 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
3433 " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
3436 " CASE WHEN c.castcontext = 'e' THEN '%s'\n"
3437 " WHEN c.castcontext = 'a' THEN '%s'\n"
3440 gettext_noop("Source type"),
3441 gettext_noop("Target type"),
3442 gettext_noop("Function"),
3444 gettext_noop("in assignment"),
3445 gettext_noop("yes"),
3446 gettext_noop("Implicit?"));
3449 appendPQExpBuffer(&buf,
3450 ",\n d.description AS \"%s\"\n",
3451 gettext_noop("Description"));
3453 appendPQExpBufferStr(&buf,
3454 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
3455 " ON c.castfunc = p.oid\n"
3456 " LEFT JOIN pg_catalog.pg_type ts\n"
3457 " ON c.castsource = ts.oid\n"
3458 " LEFT JOIN pg_catalog.pg_namespace ns\n"
3459 " ON ns.oid = ts.typnamespace\n"
3460 " LEFT JOIN pg_catalog.pg_type tt\n"
3461 " ON c.casttarget = tt.oid\n"
3462 " LEFT JOIN pg_catalog.pg_namespace nt\n"
3463 " ON nt.oid = tt.typnamespace\n");
3466 appendPQExpBufferStr(&buf,
3467 " LEFT JOIN pg_catalog.pg_description d\n"
3468 " ON d.classoid = c.tableoid AND d.objoid = "
3469 "c.oid AND d.objsubid = 0\n");
3471 appendPQExpBufferStr(&buf, "WHERE ( (true");
3474 * Match name pattern against either internal or external name of either
3475 * castsource or casttarget
3477 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3478 "ns.nspname", "ts.typname",
3479 "pg_catalog.format_type(ts.oid, NULL)",
3480 "pg_catalog.pg_type_is_visible(ts.oid)");
3482 appendPQExpBufferStr(&buf, ") OR (true");
3484 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3485 "nt.nspname", "tt.typname",
3486 "pg_catalog.format_type(tt.oid, NULL)",
3487 "pg_catalog.pg_type_is_visible(tt.oid)");
3489 appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
3491 res = PSQLexec(buf.data);
3492 termPQExpBuffer(&buf);
3496 myopt.nullPrint = NULL;
3497 myopt.title = _("List of casts");
3498 myopt.translate_header = true;
3499 myopt.translate_columns = translate_columns;
3500 myopt.n_translate_columns = lengthof(translate_columns);
3502 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3511 * Describes collations.
3514 listCollations(const char *pattern, bool verbose, bool showSystem)
3516 PQExpBufferData buf;
3518 printQueryOpt myopt = pset.popt;
3519 static const bool translate_columns[] = {false, false, false, false, false};
3521 if (pset.sversion < 90100)
3523 psql_error("The server (version %d.%d) does not support collations.\n",
3524 pset.sversion / 10000, (pset.sversion / 100) % 100);
3528 initPQExpBuffer(&buf);
3530 printfPQExpBuffer(&buf,
3531 "SELECT n.nspname AS \"%s\",\n"
3532 " c.collname AS \"%s\",\n"
3533 " c.collcollate AS \"%s\",\n"
3534 " c.collctype AS \"%s\"",
3535 gettext_noop("Schema"),
3536 gettext_noop("Name"),
3537 gettext_noop("Collate"),
3538 gettext_noop("Ctype"));
3541 appendPQExpBuffer(&buf,
3542 ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
3543 gettext_noop("Description"));
3545 appendPQExpBufferStr(&buf,
3546 "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
3547 "WHERE n.oid = c.collnamespace\n");
3549 if (!showSystem && !pattern)
3550 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
3551 " AND n.nspname <> 'information_schema'\n");
3554 * Hide collations that aren't usable in the current database's encoding.
3555 * If you think to change this, note that pg_collation_is_visible rejects
3556 * unusable collations, so you will need to hack name pattern processing
3557 * somehow to avoid inconsistent behavior.
3559 appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
3561 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3562 "n.nspname", "c.collname", NULL,
3563 "pg_catalog.pg_collation_is_visible(c.oid)");
3565 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3567 res = PSQLexec(buf.data);
3568 termPQExpBuffer(&buf);
3572 myopt.nullPrint = NULL;
3573 myopt.title = _("List of collations");
3574 myopt.translate_header = true;
3575 myopt.translate_columns = translate_columns;
3576 myopt.n_translate_columns = lengthof(translate_columns);
3578 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3587 * Describes schemas (namespaces)
3590 listSchemas(const char *pattern, bool verbose, bool showSystem)
3592 PQExpBufferData buf;
3594 printQueryOpt myopt = pset.popt;
3596 initPQExpBuffer(&buf);
3597 printfPQExpBuffer(&buf,
3598 "SELECT n.nspname AS \"%s\",\n"
3599 " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
3600 gettext_noop("Name"),
3601 gettext_noop("Owner"));
3605 appendPQExpBufferStr(&buf, ",\n ");
3606 printACLColumn(&buf, "n.nspacl");
3607 appendPQExpBuffer(&buf,
3608 ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
3609 gettext_noop("Description"));
3612 appendPQExpBuffer(&buf,
3613 "\nFROM pg_catalog.pg_namespace n\n");
3615 if (!showSystem && !pattern)
3616 appendPQExpBufferStr(&buf,
3617 "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
3619 processSQLNamePattern(pset.db, &buf, pattern,
3620 !showSystem && !pattern, false,
3621 NULL, "n.nspname", NULL,
3624 appendPQExpBufferStr(&buf, "ORDER BY 1;");
3626 res = PSQLexec(buf.data);
3627 termPQExpBuffer(&buf);
3631 myopt.nullPrint = NULL;
3632 myopt.title = _("List of schemas");
3633 myopt.translate_header = true;
3635 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3644 * list text search parsers
3647 listTSParsers(const char *pattern, bool verbose)
3649 PQExpBufferData buf;
3651 printQueryOpt myopt = pset.popt;
3653 if (pset.sversion < 80300)
3655 psql_error("The server (version %d.%d) does not support full text search.\n",
3656 pset.sversion / 10000, (pset.sversion / 100) % 100);
3661 return listTSParsersVerbose(pattern);
3663 initPQExpBuffer(&buf);
3665 printfPQExpBuffer(&buf,
3667 " n.nspname as \"%s\",\n"
3668 " p.prsname as \"%s\",\n"
3669 " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
3670 "FROM pg_catalog.pg_ts_parser p \n"
3671 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
3672 gettext_noop("Schema"),
3673 gettext_noop("Name"),
3674 gettext_noop("Description")
3677 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3678 "n.nspname", "p.prsname", NULL,
3679 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
3681 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3683 res = PSQLexec(buf.data);
3684 termPQExpBuffer(&buf);
3688 myopt.nullPrint = NULL;
3689 myopt.title = _("List of text search parsers");
3690 myopt.translate_header = true;
3692 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3699 * full description of parsers
3702 listTSParsersVerbose(const char *pattern)
3704 PQExpBufferData buf;
3708 initPQExpBuffer(&buf);
3710 printfPQExpBuffer(&buf,
3714 "FROM pg_catalog.pg_ts_parser p\n"
3715 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
3718 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3719 "n.nspname", "p.prsname", NULL,
3720 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
3722 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3724 res = PSQLexec(buf.data);
3725 termPQExpBuffer(&buf);
3729 if (PQntuples(res) == 0)
3732 psql_error("Did not find any text search parser named \"%s\".\n",
3738 for (i = 0; i < PQntuples(res); i++)
3741 const char *nspname = NULL;
3742 const char *prsname;
3744 oid = PQgetvalue(res, i, 0);
3745 if (!PQgetisnull(res, i, 1))
3746 nspname = PQgetvalue(res, i, 1);
3747 prsname = PQgetvalue(res, i, 2);
3749 if (!describeOneTSParser(oid, nspname, prsname))
3767 describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
3769 PQExpBufferData buf;
3772 printQueryOpt myopt = pset.popt;
3773 static const bool translate_columns[] = {true, false, false};
3775 initPQExpBuffer(&buf);
3777 printfPQExpBuffer(&buf,
3778 "SELECT '%s' AS \"%s\", \n"
3779 " p.prsstart::pg_catalog.regproc AS \"%s\", \n"
3780 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\" \n"
3781 " FROM pg_catalog.pg_ts_parser p \n"
3782 " WHERE p.oid = '%s' \n"
3785 " p.prstoken::pg_catalog.regproc, \n"
3786 " pg_catalog.obj_description(p.prstoken, 'pg_proc') \n"
3787 " FROM pg_catalog.pg_ts_parser p \n"
3788 " WHERE p.oid = '%s' \n"
3791 " p.prsend::pg_catalog.regproc, \n"
3792 " pg_catalog.obj_description(p.prsend, 'pg_proc') \n"
3793 " FROM pg_catalog.pg_ts_parser p \n"
3794 " WHERE p.oid = '%s' \n"
3797 " p.prsheadline::pg_catalog.regproc, \n"
3798 " pg_catalog.obj_description(p.prsheadline, 'pg_proc') \n"
3799 " FROM pg_catalog.pg_ts_parser p \n"
3800 " WHERE p.oid = '%s' \n"
3803 " p.prslextype::pg_catalog.regproc, \n"
3804 " pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
3805 " FROM pg_catalog.pg_ts_parser p \n"
3806 " WHERE p.oid = '%s';",
3807 gettext_noop("Start parse"),
3808 gettext_noop("Method"),
3809 gettext_noop("Function"),
3810 gettext_noop("Description"),
3812 gettext_noop("Get next token"),
3814 gettext_noop("End parse"),
3816 gettext_noop("Get headline"),
3818 gettext_noop("Get token types"),
3821 res = PSQLexec(buf.data);
3822 termPQExpBuffer(&buf);
3826 myopt.nullPrint = NULL;
3828 sprintf(title, _("Text search parser \"%s.%s\""), nspname, prsname);
3830 sprintf(title, _("Text search parser \"%s\""), prsname);
3831 myopt.title = title;
3832 myopt.footers = NULL;
3833 myopt.topt.default_footer = false;
3834 myopt.translate_header = true;
3835 myopt.translate_columns = translate_columns;
3836 myopt.n_translate_columns = lengthof(translate_columns);
3838 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3842 initPQExpBuffer(&buf);
3844 printfPQExpBuffer(&buf,
3845 "SELECT t.alias as \"%s\", \n"
3846 " t.description as \"%s\" \n"
3847 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
3849 gettext_noop("Token name"),
3850 gettext_noop("Description"),
3853 res = PSQLexec(buf.data);
3854 termPQExpBuffer(&buf);
3858 myopt.nullPrint = NULL;
3860 sprintf(title, _("Token types for parser \"%s.%s\""), nspname, prsname);
3862 sprintf(title, _("Token types for parser \"%s\""), prsname);
3863 myopt.title = title;
3864 myopt.footers = NULL;
3865 myopt.topt.default_footer = true;
3866 myopt.translate_header = true;
3867 myopt.translate_columns = NULL;
3868 myopt.n_translate_columns = 0;
3870 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3879 * list text search dictionaries
3882 listTSDictionaries(const char *pattern, bool verbose)
3884 PQExpBufferData buf;
3886 printQueryOpt myopt = pset.popt;
3888 if (pset.sversion < 80300)
3890 psql_error("The server (version %d.%d) does not support full text search.\n",
3891 pset.sversion / 10000, (pset.sversion / 100) % 100);
3895 initPQExpBuffer(&buf);
3897 printfPQExpBuffer(&buf,
3899 " n.nspname as \"%s\",\n"
3900 " d.dictname as \"%s\",\n",
3901 gettext_noop("Schema"),
3902 gettext_noop("Name"));
3906 appendPQExpBuffer(&buf,
3907 " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM \n"
3908 " pg_catalog.pg_ts_template t \n"
3909 " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
3910 " WHERE d.dicttemplate = t.oid ) AS \"%s\", \n"
3911 " d.dictinitoption as \"%s\", \n",
3912 gettext_noop("Template"),
3913 gettext_noop("Init options"));
3916 appendPQExpBuffer(&buf,
3917 " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
3918 gettext_noop("Description"));
3920 appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_dict d\n"
3921 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
3923 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3924 "n.nspname", "d.dictname", NULL,
3925 "pg_catalog.pg_ts_dict_is_visible(d.oid)");
3927 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3929 res = PSQLexec(buf.data);
3930 termPQExpBuffer(&buf);
3934 myopt.nullPrint = NULL;
3935 myopt.title = _("List of text search dictionaries");
3936 myopt.translate_header = true;
3938 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3947 * list text search templates
3950 listTSTemplates(const char *pattern, bool verbose)
3952 PQExpBufferData buf;
3954 printQueryOpt myopt = pset.popt;
3956 if (pset.sversion < 80300)
3958 psql_error("The server (version %d.%d) does not support full text search.\n",
3959 pset.sversion / 10000, (pset.sversion / 100) % 100);
3963 initPQExpBuffer(&buf);
3966 printfPQExpBuffer(&buf,
3968 " n.nspname AS \"%s\",\n"
3969 " t.tmplname AS \"%s\",\n"
3970 " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
3971 " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
3972 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
3973 gettext_noop("Schema"),
3974 gettext_noop("Name"),
3975 gettext_noop("Init"),
3976 gettext_noop("Lexize"),
3977 gettext_noop("Description"));
3979 printfPQExpBuffer(&buf,
3981 " n.nspname AS \"%s\",\n"
3982 " t.tmplname AS \"%s\",\n"
3983 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
3984 gettext_noop("Schema"),
3985 gettext_noop("Name"),
3986 gettext_noop("Description"));
3988 appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_template t\n"
3989 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
3991 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3992 "n.nspname", "t.tmplname", NULL,
3993 "pg_catalog.pg_ts_template_is_visible(t.oid)");
3995 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3997 res = PSQLexec(buf.data);
3998 termPQExpBuffer(&buf);
4002 myopt.nullPrint = NULL;
4003 myopt.title = _("List of text search templates");
4004 myopt.translate_header = true;
4006 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4015 * list text search configurations
4018 listTSConfigs(const char *pattern, bool verbose)
4020 PQExpBufferData buf;
4022 printQueryOpt myopt = pset.popt;
4024 if (pset.sversion < 80300)
4026 psql_error("The server (version %d.%d) does not support full text search.\n",
4027 pset.sversion / 10000, (pset.sversion / 100) % 100);
4032 return listTSConfigsVerbose(pattern);
4034 initPQExpBuffer(&buf);
4036 printfPQExpBuffer(&buf,
4038 " n.nspname as \"%s\",\n"
4039 " c.cfgname as \"%s\",\n"
4040 " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
4041 "FROM pg_catalog.pg_ts_config c\n"
4042 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
4043 gettext_noop("Schema"),
4044 gettext_noop("Name"),
4045 gettext_noop("Description")
4048 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4049 "n.nspname", "c.cfgname", NULL,
4050 "pg_catalog.pg_ts_config_is_visible(c.oid)");
4052 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4054 res = PSQLexec(buf.data);
4055 termPQExpBuffer(&buf);
4059 myopt.nullPrint = NULL;
4060 myopt.title = _("List of text search configurations");
4061 myopt.translate_header = true;
4063 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4070 listTSConfigsVerbose(const char *pattern)
4072 PQExpBufferData buf;
4076 initPQExpBuffer(&buf);
4078 printfPQExpBuffer(&buf,
4079 "SELECT c.oid, c.cfgname,\n"
4082 " np.nspname as pnspname \n"
4083 "FROM pg_catalog.pg_ts_config c \n"
4084 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace, \n"
4085 " pg_catalog.pg_ts_parser p \n"
4086 " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace \n"
4087 "WHERE p.oid = c.cfgparser\n"
4090 processSQLNamePattern(pset.db, &buf, pattern, true, false,
4091 "n.nspname", "c.cfgname", NULL,
4092 "pg_catalog.pg_ts_config_is_visible(c.oid)");
4094 appendPQExpBufferStr(&buf, "ORDER BY 3, 2;");
4096 res = PSQLexec(buf.data);
4097 termPQExpBuffer(&buf);
4101 if (PQntuples(res) == 0)
4104 psql_error("Did not find any text search configuration named \"%s\".\n",
4110 for (i = 0; i < PQntuples(res); i++)
4113 const char *cfgname;
4114 const char *nspname = NULL;
4115 const char *prsname;
4116 const char *pnspname = NULL;
4118 oid = PQgetvalue(res, i, 0);
4119 cfgname = PQgetvalue(res, i, 1);
4120 if (!PQgetisnull(res, i, 2))
4121 nspname = PQgetvalue(res, i, 2);
4122 prsname = PQgetvalue(res, i, 3);
4123 if (!PQgetisnull(res, i, 4))
4124 pnspname = PQgetvalue(res, i, 4);
4126 if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname))
4144 describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
4145 const char *pnspname, const char *prsname)
4147 PQExpBufferData buf,
4150 printQueryOpt myopt = pset.popt;
4152 initPQExpBuffer(&buf);
4154 printfPQExpBuffer(&buf,
4156 " ( SELECT t.alias FROM \n"
4157 " pg_catalog.ts_token_type(c.cfgparser) AS t \n"
4158 " WHERE t.tokid = m.maptokentype ) AS \"%s\", \n"
4159 " pg_catalog.btrim( \n"
4160 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary \n"
4161 " FROM pg_catalog.pg_ts_config_map AS mm \n"
4162 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype \n"
4163 " ORDER BY mapcfg, maptokentype, mapseqno \n"
4164 " ) :: pg_catalog.text , \n"
4165 " '{}') AS \"%s\" \n"
4166 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n"
4167 "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
4168 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
4170 gettext_noop("Token"),
4171 gettext_noop("Dictionaries"),
4174 res = PSQLexec(buf.data);
4175 termPQExpBuffer(&buf);
4179 initPQExpBuffer(&title);
4182 appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
4185 appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
4189 appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
4192 appendPQExpBuffer(&title, _("\nParser: \"%s\""),
4195 myopt.nullPrint = NULL;
4196 myopt.title = title.data;
4197 myopt.footers = NULL;
4198 myopt.topt.default_footer = false;
4199 myopt.translate_header = true;
4201 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4203 termPQExpBuffer(&title);
4213 * Describes foreign-data wrappers
4216 listForeignDataWrappers(const char *pattern, bool verbose)
4218 PQExpBufferData buf;
4220 printQueryOpt myopt = pset.popt;
4222 if (pset.sversion < 80400)
4224 psql_error("The server (version %d.%d) does not support foreign-data wrappers.\n",
4225 pset.sversion / 10000, (pset.sversion / 100) % 100);
4229 initPQExpBuffer(&buf);
4230 printfPQExpBuffer(&buf,
4231 "SELECT fdw.fdwname AS \"%s\",\n"
4232 " pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n",
4233 gettext_noop("Name"),
4234 gettext_noop("Owner"));
4235 if (pset.sversion >= 90100)
4236 appendPQExpBuffer(&buf,
4237 " fdw.fdwhandler::pg_catalog.regproc AS \"%s\",\n",
4238 gettext_noop("Handler"));
4239 appendPQExpBuffer(&buf,
4240 " fdw.fdwvalidator::pg_catalog.regproc AS \"%s\"",
4241 gettext_noop("Validator"));
4245 appendPQExpBufferStr(&buf, ",\n ");
4246 printACLColumn(&buf, "fdwacl");
4247 appendPQExpBuffer(&buf,
4248 ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
4249 " '(' || array_to_string(ARRAY(SELECT "
4250 " quote_ident(option_name) || ' ' || "
4251 " quote_literal(option_value) FROM "
4252 " pg_options_to_table(fdwoptions)), ', ') || ')' "
4254 gettext_noop("FDW Options"));
4256 if (pset.sversion >= 90100)
4257 appendPQExpBuffer(&buf,
4258 ",\n d.description AS \"%s\" ",
4259 gettext_noop("Description"));
4262 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
4264 if (verbose && pset.sversion >= 90100)
4265 appendPQExpBufferStr(&buf,
4266 "LEFT JOIN pg_catalog.pg_description d\n"
4267 " ON d.classoid = fdw.tableoid "
4268 "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
4270 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4271 NULL, "fdwname", NULL, NULL);
4273 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4275 res = PSQLexec(buf.data);
4276 termPQExpBuffer(&buf);
4280 myopt.nullPrint = NULL;
4281 myopt.title = _("List of foreign-data wrappers");
4282 myopt.translate_header = true;
4284 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4293 * Describes foreign servers.
4296 listForeignServers(const char *pattern, bool verbose)
4298 PQExpBufferData buf;
4300 printQueryOpt myopt = pset.popt;
4302 if (pset.sversion < 80400)
4304 psql_error("The server (version %d.%d) does not support foreign servers.\n",
4305 pset.sversion / 10000, (pset.sversion / 100) % 100);
4309 initPQExpBuffer(&buf);
4310 printfPQExpBuffer(&buf,
4311 "SELECT s.srvname AS \"%s\",\n"
4312 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
4313 " f.fdwname AS \"%s\"",
4314 gettext_noop("Name"),
4315 gettext_noop("Owner"),
4316 gettext_noop("Foreign-data wrapper"));
4320 appendPQExpBufferStr(&buf, ",\n ");
4321 printACLColumn(&buf, "s.srvacl");
4322 appendPQExpBuffer(&buf,
4324 " s.srvtype AS \"%s\",\n"
4325 " s.srvversion AS \"%s\",\n"
4326 " CASE WHEN srvoptions IS NULL THEN '' ELSE "
4327 " '(' || array_to_string(ARRAY(SELECT "
4328 " quote_ident(option_name) || ' ' || "
4329 " quote_literal(option_value) FROM "
4330 " pg_options_to_table(srvoptions)), ', ') || ')' "
4332 " d.description AS \"%s\"",
4333 gettext_noop("Type"),
4334 gettext_noop("Version"),
4335 gettext_noop("FDW Options"),
4336 gettext_noop("Description"));
4339 appendPQExpBufferStr(&buf,
4340 "\nFROM pg_catalog.pg_foreign_server s\n"
4341 " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
4344 appendPQExpBufferStr(&buf,
4345 "LEFT JOIN pg_description d\n "
4346 "ON d.classoid = s.tableoid AND d.objoid = s.oid "
4347 "AND d.objsubid = 0\n");
4349 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4350 NULL, "s.srvname", NULL, NULL);
4352 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4354 res = PSQLexec(buf.data);
4355 termPQExpBuffer(&buf);
4359 myopt.nullPrint = NULL;
4360 myopt.title = _("List of foreign servers");
4361 myopt.translate_header = true;
4363 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4372 * Describes user mappings.
4375 listUserMappings(const char *pattern, bool verbose)
4377 PQExpBufferData buf;
4379 printQueryOpt myopt = pset.popt;
4381 if (pset.sversion < 80400)
4383 psql_error("The server (version %d.%d) does not support user mappings.\n",
4384 pset.sversion / 10000, (pset.sversion / 100) % 100);
4388 initPQExpBuffer(&buf);
4389 printfPQExpBuffer(&buf,
4390 "SELECT um.srvname AS \"%s\",\n"
4391 " um.usename AS \"%s\"",
4392 gettext_noop("Server"),
4393 gettext_noop("User name"));
4396 appendPQExpBuffer(&buf,
4397 ",\n CASE WHEN umoptions IS NULL THEN '' ELSE "
4398 " '(' || array_to_string(ARRAY(SELECT "
4399 " quote_ident(option_name) || ' ' || "
4400 " quote_literal(option_value) FROM "
4401 " pg_options_to_table(umoptions)), ', ') || ')' "
4403 gettext_noop("FDW Options"));
4405 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
4407 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4408 NULL, "um.srvname", "um.usename", NULL);
4410 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4412 res = PSQLexec(buf.data);
4413 termPQExpBuffer(&buf);
4417 myopt.nullPrint = NULL;
4418 myopt.title = _("List of user mappings");
4419 myopt.translate_header = true;
4421 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4430 * Describes foreign tables.
4433 listForeignTables(const char *pattern, bool verbose)
4435 PQExpBufferData buf;
4437 printQueryOpt myopt = pset.popt;
4439 if (pset.sversion < 90100)
4441 psql_error("The server (version %d.%d) does not support foreign tables.\n",
4442 pset.sversion / 10000, (pset.sversion / 100) % 100);
4446 initPQExpBuffer(&buf);
4447 printfPQExpBuffer(&buf,
4448 "SELECT n.nspname AS \"%s\",\n"
4449 " c.relname AS \"%s\",\n"
4450 " s.srvname AS \"%s\"",
4451 gettext_noop("Schema"),
4452 gettext_noop("Table"),
4453 gettext_noop("Server"));
4456 appendPQExpBuffer(&buf,
4457 ",\n CASE WHEN ftoptions IS NULL THEN '' ELSE "
4458 " '(' || array_to_string(ARRAY(SELECT "
4459 " quote_ident(option_name) || ' ' || "
4460 " quote_literal(option_value) FROM "
4461 " pg_options_to_table(ftoptions)), ', ') || ')' "
4463 " d.description AS \"%s\"",
4464 gettext_noop("FDW Options"),
4465 gettext_noop("Description"));
4467 appendPQExpBufferStr(&buf,
4468 "\nFROM pg_catalog.pg_foreign_table ft\n"
4469 " INNER JOIN pg_catalog.pg_class c"
4470 " ON c.oid = ft.ftrelid\n"
4471 " INNER JOIN pg_catalog.pg_namespace n"
4472 " ON n.oid = c.relnamespace\n"
4473 " INNER JOIN pg_catalog.pg_foreign_server s"
4474 " ON s.oid = ft.ftserver\n");
4476 appendPQExpBufferStr(&buf,
4477 " LEFT JOIN pg_catalog.pg_description d\n"
4478 " ON d.classoid = c.tableoid AND "
4479 "d.objoid = c.oid AND d.objsubid = 0\n");
4481 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4482 "n.nspname", "c.relname", NULL,
4483 "pg_catalog.pg_table_is_visible(c.oid)");
4485 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4487 res = PSQLexec(buf.data);
4488 termPQExpBuffer(&buf);
4492 myopt.nullPrint = NULL;
4493 myopt.title = _("List of foreign tables");
4494 myopt.translate_header = true;
4496 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4505 * Briefly describes installed extensions.
4508 listExtensions(const char *pattern)
4510 PQExpBufferData buf;
4512 printQueryOpt myopt = pset.popt;
4514 if (pset.sversion < 90100)
4516 psql_error("The server (version %d.%d) does not support extensions.\n",
4517 pset.sversion / 10000, (pset.sversion / 100) % 100);
4521 initPQExpBuffer(&buf);
4522 printfPQExpBuffer(&buf,
4523 "SELECT e.extname AS \"%s\", "
4524 "e.extversion AS \"%s\", n.nspname AS \"%s\", c.description AS \"%s\"\n"
4525 "FROM pg_catalog.pg_extension e "
4526 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
4527 "LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
4528 "AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass\n",
4529 gettext_noop("Name"),
4530 gettext_noop("Version"),
4531 gettext_noop("Schema"),
4532 gettext_noop("Description"));
4534 processSQLNamePattern(pset.db, &buf, pattern,
4536 NULL, "e.extname", NULL,
4539 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4541 res = PSQLexec(buf.data);
4542 termPQExpBuffer(&buf);
4546 myopt.nullPrint = NULL;
4547 myopt.title = _("List of installed extensions");
4548 myopt.translate_header = true;
4550 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4559 * List contents of installed extensions.
4562 listExtensionContents(const char *pattern)
4564 PQExpBufferData buf;
4568 if (pset.sversion < 90100)
4570 psql_error("The server (version %d.%d) does not support extensions.\n",
4571 pset.sversion / 10000, (pset.sversion / 100) % 100);
4575 initPQExpBuffer(&buf);
4576 printfPQExpBuffer(&buf,
4577 "SELECT e.extname, e.oid\n"
4578 "FROM pg_catalog.pg_extension e\n");
4580 processSQLNamePattern(pset.db, &buf, pattern,
4582 NULL, "e.extname", NULL,
4585 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4587 res = PSQLexec(buf.data);
4588 termPQExpBuffer(&buf);
4592 if (PQntuples(res) == 0)
4597 psql_error("Did not find any extension named \"%s\".\n",
4600 psql_error("Did not find any extensions.\n");
4606 for (i = 0; i < PQntuples(res); i++)
4608 const char *extname;
4611 extname = PQgetvalue(res, i, 0);
4612 oid = PQgetvalue(res, i, 1);
4614 if (!listOneExtensionContents(extname, oid))
4631 listOneExtensionContents(const char *extname, const char *oid)
4633 PQExpBufferData buf;
4636 printQueryOpt myopt = pset.popt;
4638 initPQExpBuffer(&buf);
4639 printfPQExpBuffer(&buf,
4640 "SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS \"%s\"\n"
4641 "FROM pg_catalog.pg_depend\n"
4642 "WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '%s' AND deptype = 'e'\n"
4644 gettext_noop("Object Description"),
4647 res = PSQLexec(buf.data);
4648 termPQExpBuffer(&buf);
4652 myopt.nullPrint = NULL;
4653 snprintf(title, sizeof(title), _("Objects in extension \"%s\""), extname);
4654 myopt.title = title;
4655 myopt.translate_header = true;
4657 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4666 * Helper function for consistently formatting ACL (privilege) columns.
4667 * The proper targetlist entry is appended to buf. Note lack of any
4668 * whitespace or comma decoration.
4671 printACLColumn(PQExpBuffer buf, const char *colname)
4673 if (pset.sversion >= 80100)
4674 appendPQExpBuffer(buf,
4675 "pg_catalog.array_to_string(%s, E'\\n') AS \"%s\"",
4676 colname, gettext_noop("Access privileges"));
4678 appendPQExpBuffer(buf,
4679 "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"",
4680 colname, gettext_noop("Access privileges"));