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-2017, PostgreSQL Global Development Group
11 * src/bin/psql/describe.c
13 #include "postgres_fe.h"
17 #include "catalog/pg_attribute.h"
18 #include "catalog/pg_class.h"
19 #include "catalog/pg_default_acl.h"
20 #include "fe_utils/string_utils.h"
24 #include "fe_utils/mbprint.h"
25 #include "fe_utils/print.h"
27 #include "variables.h"
30 static bool describeOneTableDetails(const char *schemaname,
31 const char *relationname,
34 static void add_tablespace_footer(printTableContent *const cont, char relkind,
35 Oid tablespace, const bool newline);
36 static void add_role_attribute(PQExpBuffer buf, const char *const str);
37 static bool listTSParsersVerbose(const char *pattern);
38 static bool describeOneTSParser(const char *oid, const char *nspname,
40 static bool listTSConfigsVerbose(const char *pattern);
41 static bool describeOneTSConfig(const char *oid, const char *nspname,
43 const char *pnspname, const char *prsname);
44 static void printACLColumn(PQExpBuffer buf, const char *colname);
45 static bool listOneExtensionContents(const char *extname, const char *oid);
49 * Handlers for various slash commands displaying some sort of list
50 * of things in the database.
52 * Note: try to format the queries to look nice in -E output.
58 * Takes an optional regexp to select particular aggregates
61 describeAggregates(const char *pattern, bool verbose, bool showSystem)
65 printQueryOpt myopt = pset.popt;
67 initPQExpBuffer(&buf);
69 printfPQExpBuffer(&buf,
70 "SELECT n.nspname as \"%s\",\n"
71 " p.proname AS \"%s\",\n"
72 " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n",
73 gettext_noop("Schema"),
75 gettext_noop("Result data type"));
77 if (pset.sversion >= 80400)
78 appendPQExpBuffer(&buf,
79 " CASE WHEN p.pronargs = 0\n"
80 " THEN CAST('*' AS pg_catalog.text)\n"
81 " ELSE pg_catalog.pg_get_function_arguments(p.oid)\n"
83 gettext_noop("Argument data types"));
84 else if (pset.sversion >= 80200)
85 appendPQExpBuffer(&buf,
86 " CASE WHEN p.pronargs = 0\n"
87 " THEN CAST('*' AS pg_catalog.text)\n"
89 " pg_catalog.array_to_string(ARRAY(\n"
91 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
93 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
96 gettext_noop("Argument data types"));
98 appendPQExpBuffer(&buf,
99 " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
100 gettext_noop("Argument data types"));
102 appendPQExpBuffer(&buf,
103 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
104 "FROM pg_catalog.pg_proc p\n"
105 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
106 "WHERE p.proisagg\n",
107 gettext_noop("Description"));
109 if (!showSystem && !pattern)
110 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
111 " AND n.nspname <> 'information_schema'\n");
113 processSQLNamePattern(pset.db, &buf, pattern, true, false,
114 "n.nspname", "p.proname", NULL,
115 "pg_catalog.pg_function_is_visible(p.oid)");
117 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
119 res = PSQLexec(buf.data);
120 termPQExpBuffer(&buf);
124 myopt.nullPrint = NULL;
125 myopt.title = _("List of aggregate functions");
126 myopt.translate_header = true;
128 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
135 * Takes an optional regexp to select particular access methods
138 describeAccessMethods(const char *pattern, bool verbose)
142 printQueryOpt myopt = pset.popt;
143 static const bool translate_columns[] = {false, true, false, false};
145 if (pset.sversion < 90600)
149 psql_error("The server (version %s) does not support access methods.\n",
150 formatPGVersionNumber(pset.sversion, false,
151 sverbuf, sizeof(sverbuf)));
155 initPQExpBuffer(&buf);
157 printfPQExpBuffer(&buf,
158 "SELECT amname AS \"%s\",\n"
160 " WHEN 'i' THEN '%s'"
162 gettext_noop("Name"),
163 gettext_noop("Index"),
164 gettext_noop("Type"));
168 appendPQExpBuffer(&buf,
169 ",\n amhandler AS \"%s\",\n"
170 " pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
171 gettext_noop("Handler"),
172 gettext_noop("Description"));
175 appendPQExpBufferStr(&buf,
176 "\nFROM pg_catalog.pg_am\n");
178 processSQLNamePattern(pset.db, &buf, pattern, false, false,
179 NULL, "amname", NULL,
182 appendPQExpBufferStr(&buf, "ORDER BY 1;");
184 res = PSQLexec(buf.data);
185 termPQExpBuffer(&buf);
189 myopt.nullPrint = NULL;
190 myopt.title = _("List of access methods");
191 myopt.translate_header = true;
192 myopt.translate_columns = translate_columns;
193 myopt.n_translate_columns = lengthof(translate_columns);
195 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
202 * Takes an optional regexp to select particular tablespaces
205 describeTablespaces(const char *pattern, bool verbose)
209 printQueryOpt myopt = pset.popt;
211 if (pset.sversion < 80000)
215 psql_error("The server (version %s) does not support tablespaces.\n",
216 formatPGVersionNumber(pset.sversion, false,
217 sverbuf, sizeof(sverbuf)));
221 initPQExpBuffer(&buf);
223 if (pset.sversion >= 90200)
224 printfPQExpBuffer(&buf,
225 "SELECT spcname AS \"%s\",\n"
226 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
227 " pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
228 gettext_noop("Name"),
229 gettext_noop("Owner"),
230 gettext_noop("Location"));
232 printfPQExpBuffer(&buf,
233 "SELECT spcname AS \"%s\",\n"
234 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
235 " spclocation AS \"%s\"",
236 gettext_noop("Name"),
237 gettext_noop("Owner"),
238 gettext_noop("Location"));
242 appendPQExpBufferStr(&buf, ",\n ");
243 printACLColumn(&buf, "spcacl");
246 if (verbose && pset.sversion >= 90000)
247 appendPQExpBuffer(&buf,
248 ",\n spcoptions AS \"%s\"",
249 gettext_noop("Options"));
251 if (verbose && pset.sversion >= 90200)
252 appendPQExpBuffer(&buf,
253 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\"",
254 gettext_noop("Size"));
256 if (verbose && pset.sversion >= 80200)
257 appendPQExpBuffer(&buf,
258 ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
259 gettext_noop("Description"));
261 appendPQExpBufferStr(&buf,
262 "\nFROM pg_catalog.pg_tablespace\n");
264 processSQLNamePattern(pset.db, &buf, pattern, false, false,
265 NULL, "spcname", NULL,
268 appendPQExpBufferStr(&buf, "ORDER BY 1;");
270 res = PSQLexec(buf.data);
271 termPQExpBuffer(&buf);
275 myopt.nullPrint = NULL;
276 myopt.title = _("List of tablespaces");
277 myopt.translate_header = true;
279 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
287 * Takes an optional regexp to select particular functions.
289 * As with \d, you can specify the kinds of functions you want:
296 * and you can mix and match these in any order.
299 describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem)
301 bool showAggregate = strchr(functypes, 'a') != NULL;
302 bool showNormal = strchr(functypes, 'n') != NULL;
303 bool showTrigger = strchr(functypes, 't') != NULL;
304 bool showWindow = strchr(functypes, 'w') != NULL;
308 printQueryOpt myopt = pset.popt;
309 static const bool translate_columns[] = {false, false, false, false, true, true, true, false, true, false, false, false, false};
311 /* No "Parallel" column before 9.6 */
312 static const bool translate_columns_pre_96[] = {false, false, false, false, true, true, false, true, false, false, false, false};
314 if (strlen(functypes) != strspn(functypes, "antwS+"))
316 psql_error("\\df only takes [antwS+] as options\n");
320 if (showWindow && pset.sversion < 80400)
324 psql_error("\\df does not take a \"w\" option with server version %s\n",
325 formatPGVersionNumber(pset.sversion, false,
326 sverbuf, sizeof(sverbuf)));
330 if (!showAggregate && !showNormal && !showTrigger && !showWindow)
332 showAggregate = showNormal = showTrigger = true;
333 if (pset.sversion >= 80400)
337 initPQExpBuffer(&buf);
339 printfPQExpBuffer(&buf,
340 "SELECT n.nspname as \"%s\",\n"
341 " p.proname as \"%s\",\n",
342 gettext_noop("Schema"),
343 gettext_noop("Name"));
345 if (pset.sversion >= 80400)
346 appendPQExpBuffer(&buf,
347 " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
348 " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
350 " WHEN p.proisagg THEN '%s'\n"
351 " WHEN p.proiswindow THEN '%s'\n"
352 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
355 gettext_noop("Result data type"),
356 gettext_noop("Argument data types"),
357 /* translator: "agg" is short for "aggregate" */
359 gettext_noop("window"),
360 gettext_noop("trigger"),
361 gettext_noop("normal"),
362 gettext_noop("Type"));
363 else if (pset.sversion >= 80100)
364 appendPQExpBuffer(&buf,
365 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
366 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
367 " CASE WHEN proallargtypes IS NOT NULL THEN\n"
368 " pg_catalog.array_to_string(ARRAY(\n"
371 " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
372 " WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
373 " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
374 " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
377 " WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
378 " ELSE p.proargnames[s.i] || ' '\n"
380 " pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
382 " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
385 " pg_catalog.array_to_string(ARRAY(\n"
388 " WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
389 " ELSE p.proargnames[s.i+1] || ' '\n"
391 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
393 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
397 " WHEN p.proisagg THEN '%s'\n"
398 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
401 gettext_noop("Result data type"),
402 gettext_noop("Argument data types"),
403 /* translator: "agg" is short for "aggregate" */
405 gettext_noop("trigger"),
406 gettext_noop("normal"),
407 gettext_noop("Type"));
409 appendPQExpBuffer(&buf,
410 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
411 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
412 " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\",\n"
414 " WHEN p.proisagg THEN '%s'\n"
415 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
418 gettext_noop("Result data type"),
419 gettext_noop("Argument data types"),
420 /* translator: "agg" is short for "aggregate" */
422 gettext_noop("trigger"),
423 gettext_noop("normal"),
424 gettext_noop("Type"));
428 appendPQExpBuffer(&buf,
430 " WHEN p.provolatile = 'i' THEN '%s'\n"
431 " WHEN p.provolatile = 's' THEN '%s'\n"
432 " WHEN p.provolatile = 'v' THEN '%s'\n"
434 gettext_noop("immutable"),
435 gettext_noop("stable"),
436 gettext_noop("volatile"),
437 gettext_noop("Volatility"));
438 if (pset.sversion >= 90600)
439 appendPQExpBuffer(&buf,
441 " WHEN p.proparallel = 'r' THEN '%s'\n"
442 " WHEN p.proparallel = 's' THEN '%s'\n"
443 " WHEN p.proparallel = 'u' THEN '%s'\n"
445 gettext_noop("restricted"),
446 gettext_noop("safe"),
447 gettext_noop("unsafe"),
448 gettext_noop("Parallel"));
449 appendPQExpBuffer(&buf,
450 ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\""
451 ",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\"",
452 gettext_noop("Owner"),
453 gettext_noop("definer"),
454 gettext_noop("invoker"),
455 gettext_noop("Security"));
456 appendPQExpBufferStr(&buf, ",\n ");
457 printACLColumn(&buf, "p.proacl");
458 appendPQExpBuffer(&buf,
459 ",\n l.lanname as \"%s\""
460 ",\n p.prosrc as \"%s\""
461 ",\n pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
462 gettext_noop("Language"),
463 gettext_noop("Source code"),
464 gettext_noop("Description"));
467 appendPQExpBufferStr(&buf,
468 "\nFROM pg_catalog.pg_proc p"
469 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
472 appendPQExpBufferStr(&buf,
473 " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
477 /* filter by function type, if requested */
478 if (showNormal && showAggregate && showTrigger && showWindow)
485 appendPQExpBufferStr(&buf, " AND ");
488 appendPQExpBufferStr(&buf, "WHERE ");
491 appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
496 appendPQExpBufferStr(&buf, " AND ");
499 appendPQExpBufferStr(&buf, "WHERE ");
502 appendPQExpBufferStr(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
504 if (!showWindow && pset.sversion >= 80400)
507 appendPQExpBufferStr(&buf, " AND ");
510 appendPQExpBufferStr(&buf, "WHERE ");
513 appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
518 bool needs_or = false;
520 appendPQExpBufferStr(&buf, "WHERE (\n ");
522 /* Note: at least one of these must be true ... */
525 appendPQExpBufferStr(&buf, "p.proisagg\n");
531 appendPQExpBufferStr(&buf, " OR ");
532 appendPQExpBufferStr(&buf,
533 "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n");
539 appendPQExpBufferStr(&buf, " OR ");
540 appendPQExpBufferStr(&buf, "p.proiswindow\n");
543 appendPQExpBufferStr(&buf, " )\n");
546 processSQLNamePattern(pset.db, &buf, pattern, have_where, false,
547 "n.nspname", "p.proname", NULL,
548 "pg_catalog.pg_function_is_visible(p.oid)");
550 if (!showSystem && !pattern)
551 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
552 " AND n.nspname <> 'information_schema'\n");
554 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
556 res = PSQLexec(buf.data);
557 termPQExpBuffer(&buf);
561 myopt.nullPrint = NULL;
562 myopt.title = _("List of functions");
563 myopt.translate_header = true;
564 if (pset.sversion >= 90600)
566 myopt.translate_columns = translate_columns;
567 myopt.n_translate_columns = lengthof(translate_columns);
571 myopt.translate_columns = translate_columns_pre_96;
572 myopt.n_translate_columns = lengthof(translate_columns_pre_96);
575 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
588 describeTypes(const char *pattern, bool verbose, bool showSystem)
592 printQueryOpt myopt = pset.popt;
594 initPQExpBuffer(&buf);
596 printfPQExpBuffer(&buf,
597 "SELECT n.nspname as \"%s\",\n"
598 " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
599 gettext_noop("Schema"),
600 gettext_noop("Name"));
602 appendPQExpBuffer(&buf,
603 " t.typname AS \"%s\",\n"
604 " CASE WHEN t.typrelid != 0\n"
605 " THEN CAST('tuple' AS pg_catalog.text)\n"
606 " WHEN t.typlen < 0\n"
607 " THEN CAST('var' AS pg_catalog.text)\n"
608 " ELSE CAST(t.typlen AS pg_catalog.text)\n"
610 gettext_noop("Internal name"),
611 gettext_noop("Size"));
612 if (verbose && pset.sversion >= 80300)
614 appendPQExpBufferStr(&buf,
615 " pg_catalog.array_to_string(\n"
617 " SELECT e.enumlabel\n"
618 " FROM pg_catalog.pg_enum e\n"
619 " WHERE e.enumtypid = t.oid\n");
621 if (pset.sversion >= 90100)
622 appendPQExpBufferStr(&buf,
623 " ORDER BY e.enumsortorder\n");
625 appendPQExpBufferStr(&buf,
626 " ORDER BY e.oid\n");
628 appendPQExpBuffer(&buf,
632 gettext_noop("Elements"));
636 appendPQExpBuffer(&buf,
637 " pg_catalog.pg_get_userbyid(t.typowner) AS \"%s\",\n",
638 gettext_noop("Owner"));
640 if (verbose && pset.sversion >= 90200)
642 printACLColumn(&buf, "t.typacl");
643 appendPQExpBufferStr(&buf, ",\n ");
646 appendPQExpBuffer(&buf,
647 " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
648 gettext_noop("Description"));
650 appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_type t\n"
651 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
654 * do not include complex types (typrelid!=0) unless they are standalone
657 appendPQExpBufferStr(&buf, "WHERE (t.typrelid = 0 ");
658 appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
659 " FROM pg_catalog.pg_class c "
660 "WHERE c.oid = t.typrelid))\n");
663 * do not include array types (before 8.3 we have to use the assumption
664 * that their names start with underscore)
666 if (pset.sversion >= 80300)
667 appendPQExpBufferStr(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
669 appendPQExpBufferStr(&buf, " AND t.typname !~ '^_'\n");
671 if (!showSystem && !pattern)
672 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
673 " AND n.nspname <> 'information_schema'\n");
675 /* Match name pattern against either internal or external name */
676 processSQLNamePattern(pset.db, &buf, pattern, true, false,
677 "n.nspname", "t.typname",
678 "pg_catalog.format_type(t.oid, NULL)",
679 "pg_catalog.pg_type_is_visible(t.oid)");
681 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
683 res = PSQLexec(buf.data);
684 termPQExpBuffer(&buf);
688 myopt.nullPrint = NULL;
689 myopt.title = _("List of data types");
690 myopt.translate_header = true;
692 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
703 describeOperators(const char *pattern, bool verbose, bool showSystem)
707 printQueryOpt myopt = pset.popt;
709 initPQExpBuffer(&buf);
712 * Note: before Postgres 9.1, we did not assign comments to any built-in
713 * operators, preferring to let the comment on the underlying function
714 * suffice. The coalesce() on the obj_description() calls below supports
715 * this convention by providing a fallback lookup of a comment on the
716 * operator's function. As of 9.1 there is a policy that every built-in
717 * operator should have a comment; so the coalesce() is no longer
718 * necessary so far as built-in operators are concerned. We keep it
719 * anyway, for now, because (1) third-party modules may still be following
720 * the old convention, and (2) we'd need to do it anyway when talking to a
724 printfPQExpBuffer(&buf,
725 "SELECT n.nspname as \"%s\",\n"
726 " o.oprname AS \"%s\",\n"
727 " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
728 " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
729 " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
730 gettext_noop("Schema"),
731 gettext_noop("Name"),
732 gettext_noop("Left arg type"),
733 gettext_noop("Right arg type"),
734 gettext_noop("Result type"));
737 appendPQExpBuffer(&buf,
738 " o.oprcode AS \"%s\",\n",
739 gettext_noop("Function"));
741 appendPQExpBuffer(&buf,
742 " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
743 " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
744 "FROM pg_catalog.pg_operator o\n"
745 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
746 gettext_noop("Description"));
748 if (!showSystem && !pattern)
749 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
750 " AND n.nspname <> 'information_schema'\n");
752 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, true,
753 "n.nspname", "o.oprname", NULL,
754 "pg_catalog.pg_operator_is_visible(o.oid)");
756 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4;");
758 res = PSQLexec(buf.data);
759 termPQExpBuffer(&buf);
763 myopt.nullPrint = NULL;
764 myopt.title = _("List of operators");
765 myopt.translate_header = true;
767 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
777 * for \l, \list, and -l switch
780 listAllDbs(const char *pattern, bool verbose)
784 printQueryOpt myopt = pset.popt;
786 initPQExpBuffer(&buf);
788 printfPQExpBuffer(&buf,
789 "SELECT d.datname as \"%s\",\n"
790 " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
791 " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
792 gettext_noop("Name"),
793 gettext_noop("Owner"),
794 gettext_noop("Encoding"));
795 if (pset.sversion >= 80400)
796 appendPQExpBuffer(&buf,
797 " d.datcollate as \"%s\",\n"
798 " d.datctype as \"%s\",\n",
799 gettext_noop("Collate"),
800 gettext_noop("Ctype"));
801 appendPQExpBufferStr(&buf, " ");
802 printACLColumn(&buf, "d.datacl");
803 if (verbose && pset.sversion >= 80200)
804 appendPQExpBuffer(&buf,
805 ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
806 " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
807 " ELSE 'No Access'\n"
809 gettext_noop("Size"));
810 if (verbose && pset.sversion >= 80000)
811 appendPQExpBuffer(&buf,
812 ",\n t.spcname as \"%s\"",
813 gettext_noop("Tablespace"));
814 if (verbose && pset.sversion >= 80200)
815 appendPQExpBuffer(&buf,
816 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
817 gettext_noop("Description"));
818 appendPQExpBufferStr(&buf,
819 "\nFROM pg_catalog.pg_database d\n");
820 if (verbose && pset.sversion >= 80000)
821 appendPQExpBufferStr(&buf,
822 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
825 processSQLNamePattern(pset.db, &buf, pattern, false, false,
826 NULL, "d.datname", NULL, NULL);
828 appendPQExpBufferStr(&buf, "ORDER BY 1;");
829 res = PSQLexec(buf.data);
830 termPQExpBuffer(&buf);
834 myopt.nullPrint = NULL;
835 myopt.title = _("List of databases");
836 myopt.translate_header = true;
838 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
846 * List Tables' Grant/Revoke Permissions
847 * \z (now also \dp -- perhaps more mnemonic)
850 permissionsList(const char *pattern)
854 printQueryOpt myopt = pset.popt;
855 static const bool translate_columns[] = {false, false, true, false, false, false};
857 initPQExpBuffer(&buf);
860 * we ignore indexes and toast tables since they have no meaningful rights
862 printfPQExpBuffer(&buf,
863 "SELECT n.nspname as \"%s\",\n"
864 " c.relname as \"%s\",\n"
866 " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
867 " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
868 " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
869 " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
870 " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
871 " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
874 gettext_noop("Schema"),
875 gettext_noop("Name"),
876 gettext_noop("table"),
877 gettext_noop("view"),
878 gettext_noop("materialized view"),
879 gettext_noop("sequence"),
880 gettext_noop("foreign table"),
881 gettext_noop("table"), /* partitioned table */
882 gettext_noop("Type"));
884 printACLColumn(&buf, "c.relacl");
886 if (pset.sversion >= 80400)
887 appendPQExpBuffer(&buf,
888 ",\n pg_catalog.array_to_string(ARRAY(\n"
889 " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
890 " FROM pg_catalog.pg_attribute a\n"
891 " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
892 " ), E'\\n') AS \"%s\"",
893 gettext_noop("Column privileges"));
895 if (pset.sversion >= 90500 && pset.sversion < 100000)
896 appendPQExpBuffer(&buf,
897 ",\n pg_catalog.array_to_string(ARRAY(\n"
899 " || CASE WHEN polcmd != '*' THEN\n"
900 " E' (' || polcmd || E'):'\n"
903 " || CASE WHEN polqual IS NOT NULL THEN\n"
904 " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
907 " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
908 " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
911 " || CASE WHEN polroles <> '{0}' THEN\n"
912 " E'\\n to: ' || pg_catalog.array_to_string(\n"
915 " FROM pg_catalog.pg_roles\n"
916 " WHERE oid = ANY (polroles)\n"
921 " FROM pg_catalog.pg_policy pol\n"
922 " WHERE polrelid = c.oid), E'\\n')\n"
924 gettext_noop("Policies"));
926 if (pset.sversion >= 100000)
927 appendPQExpBuffer(&buf,
928 ",\n pg_catalog.array_to_string(ARRAY(\n"
930 " || CASE WHEN NOT polpermissive THEN\n"
931 " E' (RESTRICTIVE)'\n"
933 " || CASE WHEN polcmd != '*' THEN\n"
934 " E' (' || polcmd || E'):'\n"
937 " || CASE WHEN polqual IS NOT NULL THEN\n"
938 " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
941 " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
942 " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
945 " || CASE WHEN polroles <> '{0}' THEN\n"
946 " E'\\n to: ' || pg_catalog.array_to_string(\n"
949 " FROM pg_catalog.pg_roles\n"
950 " WHERE oid = ANY (polroles)\n"
955 " FROM pg_catalog.pg_policy pol\n"
956 " WHERE polrelid = c.oid), E'\\n')\n"
958 gettext_noop("Policies"));
960 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_class c\n"
961 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
962 "WHERE c.relkind IN ("
963 CppAsString2(RELKIND_RELATION) ","
964 CppAsString2(RELKIND_VIEW) ","
965 CppAsString2(RELKIND_MATVIEW) ","
966 CppAsString2(RELKIND_SEQUENCE) ","
967 CppAsString2(RELKIND_FOREIGN_TABLE) ","
968 CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
971 * Unless a schema pattern is specified, we suppress system and temp
972 * tables, since they normally aren't very interesting from a permissions
973 * point of view. You can see 'em by explicit request though, eg with \z
976 processSQLNamePattern(pset.db, &buf, pattern, true, false,
977 "n.nspname", "c.relname", NULL,
978 "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
980 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
982 res = PSQLexec(buf.data);
985 termPQExpBuffer(&buf);
989 myopt.nullPrint = NULL;
990 printfPQExpBuffer(&buf, _("Access privileges"));
991 myopt.title = buf.data;
992 myopt.translate_header = true;
993 myopt.translate_columns = translate_columns;
994 myopt.n_translate_columns = lengthof(translate_columns);
996 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
998 termPQExpBuffer(&buf);
1007 * List Default ACLs. The pattern can match either schema or role name.
1010 listDefaultACLs(const char *pattern)
1012 PQExpBufferData buf;
1014 printQueryOpt myopt = pset.popt;
1015 static const bool translate_columns[] = {false, false, true, false};
1017 if (pset.sversion < 90000)
1021 psql_error("The server (version %s) does not support altering default privileges.\n",
1022 formatPGVersionNumber(pset.sversion, false,
1023 sverbuf, sizeof(sverbuf)));
1027 initPQExpBuffer(&buf);
1029 printfPQExpBuffer(&buf,
1030 "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
1031 " n.nspname AS \"%s\",\n"
1032 " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
1034 gettext_noop("Owner"),
1035 gettext_noop("Schema"),
1037 gettext_noop("table"),
1039 gettext_noop("sequence"),
1041 gettext_noop("function"),
1043 gettext_noop("type"),
1044 DEFACLOBJ_NAMESPACE,
1045 gettext_noop("schema"),
1046 gettext_noop("Type"));
1048 printACLColumn(&buf, "d.defaclacl");
1050 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
1051 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
1053 processSQLNamePattern(pset.db, &buf, pattern, false, false,
1056 "pg_catalog.pg_get_userbyid(d.defaclrole)",
1059 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1061 res = PSQLexec(buf.data);
1064 termPQExpBuffer(&buf);
1068 myopt.nullPrint = NULL;
1069 printfPQExpBuffer(&buf, _("Default access privileges"));
1070 myopt.title = buf.data;
1071 myopt.translate_header = true;
1072 myopt.translate_columns = translate_columns;
1073 myopt.n_translate_columns = lengthof(translate_columns);
1075 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1077 termPQExpBuffer(&buf);
1084 * Get object comments
1088 * Note: This command only lists comments for object types which do not have
1089 * their comments displayed by their own backslash commands. The following
1090 * types of objects will be displayed: constraint, operator class,
1091 * operator family, rule, and trigger.
1095 objectDescription(const char *pattern, bool showSystem)
1097 PQExpBufferData buf;
1099 printQueryOpt myopt = pset.popt;
1100 static const bool translate_columns[] = {false, false, true, false};
1102 initPQExpBuffer(&buf);
1104 appendPQExpBuffer(&buf,
1105 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
1107 gettext_noop("Schema"),
1108 gettext_noop("Name"),
1109 gettext_noop("Object"),
1110 gettext_noop("Description"));
1112 /* Table constraint descriptions */
1113 appendPQExpBuffer(&buf,
1114 " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1115 " n.nspname as nspname,\n"
1116 " CAST(pgc.conname AS pg_catalog.text) as name,"
1117 " CAST('%s' AS pg_catalog.text) as object\n"
1118 " FROM pg_catalog.pg_constraint pgc\n"
1119 " JOIN pg_catalog.pg_class c "
1120 "ON c.oid = pgc.conrelid\n"
1121 " LEFT JOIN pg_catalog.pg_namespace n "
1122 " ON n.oid = c.relnamespace\n",
1123 gettext_noop("table constraint"));
1125 if (!showSystem && !pattern)
1126 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1127 " AND n.nspname <> 'information_schema'\n");
1129 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern,
1130 false, "n.nspname", "pgc.conname", NULL,
1131 "pg_catalog.pg_table_is_visible(c.oid)");
1133 /* Domain constraint descriptions */
1134 appendPQExpBuffer(&buf,
1136 " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1137 " n.nspname as nspname,\n"
1138 " CAST(pgc.conname AS pg_catalog.text) as name,"
1139 " CAST('%s' AS pg_catalog.text) as object\n"
1140 " FROM pg_catalog.pg_constraint pgc\n"
1141 " JOIN pg_catalog.pg_type t "
1142 "ON t.oid = pgc.contypid\n"
1143 " LEFT JOIN pg_catalog.pg_namespace n "
1144 " ON n.oid = t.typnamespace\n",
1145 gettext_noop("domain constraint"));
1147 if (!showSystem && !pattern)
1148 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1149 " AND n.nspname <> 'information_schema'\n");
1151 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern,
1152 false, "n.nspname", "pgc.conname", NULL,
1153 "pg_catalog.pg_type_is_visible(t.oid)");
1157 * pg_opclass.opcmethod only available in 8.3+
1159 if (pset.sversion >= 80300)
1161 /* Operator class descriptions */
1162 appendPQExpBuffer(&buf,
1164 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
1165 " n.nspname as nspname,\n"
1166 " CAST(o.opcname AS pg_catalog.text) as name,\n"
1167 " CAST('%s' AS pg_catalog.text) as object\n"
1168 " FROM pg_catalog.pg_opclass o\n"
1169 " JOIN pg_catalog.pg_am am ON "
1170 "o.opcmethod = am.oid\n"
1171 " JOIN pg_catalog.pg_namespace n ON "
1172 "n.oid = o.opcnamespace\n",
1173 gettext_noop("operator class"));
1175 if (!showSystem && !pattern)
1176 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1177 " AND n.nspname <> 'information_schema'\n");
1179 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1180 "n.nspname", "o.opcname", NULL,
1181 "pg_catalog.pg_opclass_is_visible(o.oid)");
1185 * although operator family comments have been around since 8.3,
1186 * pg_opfamily_is_visible is only available in 9.2+
1188 if (pset.sversion >= 90200)
1190 /* Operator family descriptions */
1191 appendPQExpBuffer(&buf,
1193 " SELECT opf.oid as oid, opf.tableoid as tableoid,\n"
1194 " n.nspname as nspname,\n"
1195 " CAST(opf.opfname AS pg_catalog.text) AS name,\n"
1196 " CAST('%s' AS pg_catalog.text) as object\n"
1197 " FROM pg_catalog.pg_opfamily opf\n"
1198 " JOIN pg_catalog.pg_am am "
1199 "ON opf.opfmethod = am.oid\n"
1200 " JOIN pg_catalog.pg_namespace n "
1201 "ON opf.opfnamespace = n.oid\n",
1202 gettext_noop("operator family"));
1204 if (!showSystem && !pattern)
1205 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1206 " AND n.nspname <> 'information_schema'\n");
1208 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1209 "n.nspname", "opf.opfname", NULL,
1210 "pg_catalog.pg_opfamily_is_visible(opf.oid)");
1213 /* Rule descriptions (ignore rules for views) */
1214 appendPQExpBuffer(&buf,
1216 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
1217 " n.nspname as nspname,\n"
1218 " CAST(r.rulename AS pg_catalog.text) as name,"
1219 " CAST('%s' AS pg_catalog.text) as object\n"
1220 " FROM pg_catalog.pg_rewrite r\n"
1221 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
1222 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
1223 " WHERE r.rulename != '_RETURN'\n",
1224 gettext_noop("rule"));
1226 if (!showSystem && !pattern)
1227 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1228 " AND n.nspname <> 'information_schema'\n");
1230 processSQLNamePattern(pset.db, &buf, pattern, true, false,
1231 "n.nspname", "r.rulename", NULL,
1232 "pg_catalog.pg_table_is_visible(c.oid)");
1234 /* Trigger descriptions */
1235 appendPQExpBuffer(&buf,
1237 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
1238 " n.nspname as nspname,\n"
1239 " CAST(t.tgname AS pg_catalog.text) as name,"
1240 " CAST('%s' AS pg_catalog.text) as object\n"
1241 " FROM pg_catalog.pg_trigger t\n"
1242 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
1243 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
1244 gettext_noop("trigger"));
1246 if (!showSystem && !pattern)
1247 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1248 " AND n.nspname <> 'information_schema'\n");
1250 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
1251 "n.nspname", "t.tgname", NULL,
1252 "pg_catalog.pg_table_is_visible(c.oid)");
1254 appendPQExpBufferStr(&buf,
1256 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
1258 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1260 res = PSQLexec(buf.data);
1261 termPQExpBuffer(&buf);
1265 myopt.nullPrint = NULL;
1266 myopt.title = _("Object descriptions");
1267 myopt.translate_header = true;
1268 myopt.translate_columns = translate_columns;
1269 myopt.n_translate_columns = lengthof(translate_columns);
1271 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1279 * describeTableDetails (for \d)
1281 * This routine finds the tables to be displayed, and calls
1282 * describeOneTableDetails for each one.
1284 * verbose: if true, this is \d+
1287 describeTableDetails(const char *pattern, bool verbose, bool showSystem)
1289 PQExpBufferData buf;
1293 initPQExpBuffer(&buf);
1295 printfPQExpBuffer(&buf,
1299 "FROM pg_catalog.pg_class c\n"
1300 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1302 if (!showSystem && !pattern)
1303 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1304 " AND n.nspname <> 'information_schema'\n");
1306 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
1307 "n.nspname", "c.relname", NULL,
1308 "pg_catalog.pg_table_is_visible(c.oid)");
1310 appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
1312 res = PSQLexec(buf.data);
1313 termPQExpBuffer(&buf);
1317 if (PQntuples(res) == 0)
1320 psql_error("Did not find any relation named \"%s\".\n",
1326 for (i = 0; i < PQntuples(res); i++)
1329 const char *nspname;
1330 const char *relname;
1332 oid = PQgetvalue(res, i, 0);
1333 nspname = PQgetvalue(res, i, 1);
1334 relname = PQgetvalue(res, i, 2);
1336 if (!describeOneTableDetails(nspname, relname, oid, verbose))
1353 * describeOneTableDetails (for \d)
1355 * Unfortunately, the information presented here is so complicated that it
1356 * cannot be done in a single query. So we have to assemble the printed table
1357 * by hand and pass it to the underlying printTable() function.
1360 describeOneTableDetails(const char *schemaname,
1361 const char *relationname,
1365 PQExpBufferData buf;
1366 PGresult *res = NULL;
1367 printTableOpt myopt = pset.popt.topt;
1368 printTableContent cont;
1369 bool printTableInitialized = false;
1371 char *view_def = NULL;
1373 char **seq_values = NULL;
1375 PQExpBufferData title;
1376 PQExpBufferData tmpbuf;
1387 bool forcerowsecurity;
1392 char relpersistence;
1395 bool show_column_details = false;
1400 myopt.default_footer = false;
1401 /* This output looks confusing in expanded mode. */
1402 myopt.expanded = false;
1404 initPQExpBuffer(&buf);
1405 initPQExpBuffer(&title);
1406 initPQExpBuffer(&tmpbuf);
1408 /* Get general table info */
1409 if (pset.sversion >= 90500)
1411 printfPQExpBuffer(&buf,
1412 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1413 "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
1414 "c.relhasoids, %s, c.reltablespace, "
1415 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1416 "c.relpersistence, c.relreplident\n"
1417 "FROM pg_catalog.pg_class c\n "
1418 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1419 "WHERE c.oid = '%s';",
1421 "pg_catalog.array_to_string(c.reloptions || "
1422 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1426 else if (pset.sversion >= 90400)
1428 printfPQExpBuffer(&buf,
1429 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1430 "c.relhastriggers, false, false, c.relhasoids, "
1431 "%s, c.reltablespace, "
1432 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1433 "c.relpersistence, c.relreplident\n"
1434 "FROM pg_catalog.pg_class c\n "
1435 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1436 "WHERE c.oid = '%s';",
1438 "pg_catalog.array_to_string(c.reloptions || "
1439 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1443 else if (pset.sversion >= 90100)
1445 printfPQExpBuffer(&buf,
1446 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1447 "c.relhastriggers, false, false, c.relhasoids, "
1448 "%s, c.reltablespace, "
1449 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1450 "c.relpersistence\n"
1451 "FROM pg_catalog.pg_class c\n "
1452 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1453 "WHERE c.oid = '%s';",
1455 "pg_catalog.array_to_string(c.reloptions || "
1456 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1460 else if (pset.sversion >= 90000)
1462 printfPQExpBuffer(&buf,
1463 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1464 "c.relhastriggers, false, false, c.relhasoids, "
1465 "%s, c.reltablespace, "
1466 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END\n"
1467 "FROM pg_catalog.pg_class c\n "
1468 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1469 "WHERE c.oid = '%s';",
1471 "pg_catalog.array_to_string(c.reloptions || "
1472 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1476 else if (pset.sversion >= 80400)
1478 printfPQExpBuffer(&buf,
1479 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1480 "c.relhastriggers, false, false, c.relhasoids, "
1481 "%s, c.reltablespace\n"
1482 "FROM pg_catalog.pg_class c\n "
1483 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1484 "WHERE c.oid = '%s';",
1486 "pg_catalog.array_to_string(c.reloptions || "
1487 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1491 else if (pset.sversion >= 80200)
1493 printfPQExpBuffer(&buf,
1494 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1495 "reltriggers <> 0, false, false, relhasoids, "
1496 "%s, reltablespace\n"
1497 "FROM pg_catalog.pg_class WHERE oid = '%s';",
1499 "pg_catalog.array_to_string(reloptions, E', ')" : "''"),
1502 else if (pset.sversion >= 80000)
1504 printfPQExpBuffer(&buf,
1505 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1506 "reltriggers <> 0, false, false, relhasoids, "
1507 "'', reltablespace\n"
1508 "FROM pg_catalog.pg_class WHERE oid = '%s';",
1513 printfPQExpBuffer(&buf,
1514 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1515 "reltriggers <> 0, false, false, relhasoids, "
1517 "FROM pg_catalog.pg_class WHERE oid = '%s';",
1521 res = PSQLexec(buf.data);
1525 /* Did we get anything? */
1526 if (PQntuples(res) == 0)
1529 psql_error("Did not find any relation with OID %s.\n", oid);
1533 tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
1534 tableinfo.relkind = *(PQgetvalue(res, 0, 1));
1535 tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
1536 tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
1537 tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
1538 tableinfo.rowsecurity = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
1539 tableinfo.forcerowsecurity = strcmp(PQgetvalue(res, 0, 6), "t") == 0;
1540 tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 7), "t") == 0;
1541 tableinfo.reloptions = (pset.sversion >= 80200) ?
1542 pg_strdup(PQgetvalue(res, 0, 8)) : NULL;
1543 tableinfo.tablespace = (pset.sversion >= 80000) ?
1544 atooid(PQgetvalue(res, 0, 9)) : 0;
1545 tableinfo.reloftype = (pset.sversion >= 90000 &&
1546 strcmp(PQgetvalue(res, 0, 10), "") != 0) ?
1547 pg_strdup(PQgetvalue(res, 0, 10)) : NULL;
1548 tableinfo.relpersistence = (pset.sversion >= 90100) ?
1549 *(PQgetvalue(res, 0, 11)) : 0;
1550 tableinfo.relreplident = (pset.sversion >= 90400) ?
1551 *(PQgetvalue(res, 0, 12)) : 'd';
1556 * If it's a sequence, fetch its values and store into an array that will
1559 if (tableinfo.relkind == RELKIND_SEQUENCE)
1561 printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
1562 /* must be separate because fmtId isn't reentrant */
1563 appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
1565 res = PSQLexec(buf.data);
1569 seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
1571 for (i = 0; i < PQnfields(res); i++)
1572 seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
1573 seq_values[i] = NULL;
1582 * You need to modify value of "firstvcol" which will be defined below if
1583 * you are adding column(s) preceding to verbose-only columns.
1585 printfPQExpBuffer(&buf, "SELECT a.attname,");
1586 appendPQExpBufferStr(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
1587 "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
1588 "\n FROM pg_catalog.pg_attrdef d"
1589 "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
1590 "\n a.attnotnull, a.attnum,");
1591 if (pset.sversion >= 90100)
1592 appendPQExpBufferStr(&buf, "\n (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
1593 " WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
1595 appendPQExpBufferStr(&buf, "\n NULL AS attcollation");
1596 if (pset.sversion >= 100000)
1597 appendPQExpBufferStr(&buf, ", a.attidentity");
1599 appendPQExpBufferStr(&buf, ", ''::\"char\" AS attidentity");
1600 if (tableinfo.relkind == RELKIND_INDEX)
1601 appendPQExpBufferStr(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
1603 appendPQExpBufferStr(&buf, ",\n NULL AS indexdef");
1604 if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
1605 appendPQExpBufferStr(&buf, ",\n CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
1606 " '(' || array_to_string(ARRAY(SELECT quote_ident(option_name) || ' ' || quote_literal(option_value) FROM "
1607 " pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
1609 appendPQExpBufferStr(&buf, ",\n NULL AS attfdwoptions");
1612 appendPQExpBufferStr(&buf, ",\n a.attstorage");
1613 appendPQExpBufferStr(&buf, ",\n CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
1616 * In 9.0+, we have column comments for: relations, views, composite
1617 * types, and foreign tables (c.f. CommentObject() in comment.c).
1619 if (tableinfo.relkind == RELKIND_RELATION ||
1620 tableinfo.relkind == RELKIND_VIEW ||
1621 tableinfo.relkind == RELKIND_MATVIEW ||
1622 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1623 tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
1624 tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1625 appendPQExpBufferStr(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)");
1628 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_attribute a");
1629 appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
1630 appendPQExpBufferStr(&buf, "\nORDER BY a.attnum;");
1632 res = PSQLexec(buf.data);
1635 numrows = PQntuples(res);
1638 switch (tableinfo.relkind)
1640 case RELKIND_RELATION:
1641 if (tableinfo.relpersistence == 'u')
1642 printfPQExpBuffer(&title, _("Unlogged table \"%s.%s\""),
1643 schemaname, relationname);
1645 printfPQExpBuffer(&title, _("Table \"%s.%s\""),
1646 schemaname, relationname);
1649 printfPQExpBuffer(&title, _("View \"%s.%s\""),
1650 schemaname, relationname);
1652 case RELKIND_MATVIEW:
1653 if (tableinfo.relpersistence == 'u')
1654 printfPQExpBuffer(&title, _("Unlogged materialized view \"%s.%s\""),
1655 schemaname, relationname);
1657 printfPQExpBuffer(&title, _("Materialized view \"%s.%s\""),
1658 schemaname, relationname);
1660 case RELKIND_SEQUENCE:
1661 printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
1662 schemaname, relationname);
1665 if (tableinfo.relpersistence == 'u')
1666 printfPQExpBuffer(&title, _("Unlogged index \"%s.%s\""),
1667 schemaname, relationname);
1669 printfPQExpBuffer(&title, _("Index \"%s.%s\""),
1670 schemaname, relationname);
1673 /* not used as of 8.2, but keep it for backwards compatibility */
1674 printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
1675 schemaname, relationname);
1677 case RELKIND_TOASTVALUE:
1678 printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
1679 schemaname, relationname);
1681 case RELKIND_COMPOSITE_TYPE:
1682 printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
1683 schemaname, relationname);
1685 case RELKIND_FOREIGN_TABLE:
1686 printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""),
1687 schemaname, relationname);
1689 case RELKIND_PARTITIONED_TABLE:
1690 if (tableinfo.relpersistence == 'u')
1691 printfPQExpBuffer(&title, _("Unlogged table \"%s.%s\""),
1692 schemaname, relationname);
1694 printfPQExpBuffer(&title, _("Table \"%s.%s\""),
1695 schemaname, relationname);
1698 /* untranslated unknown relkind */
1699 printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
1700 tableinfo.relkind, schemaname, relationname);
1704 /* Set the number of columns, and their names */
1705 headers[0] = gettext_noop("Column");
1706 headers[1] = gettext_noop("Type");
1709 if (tableinfo.relkind == RELKIND_RELATION ||
1710 tableinfo.relkind == RELKIND_VIEW ||
1711 tableinfo.relkind == RELKIND_MATVIEW ||
1712 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1713 tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
1714 tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1716 headers[cols++] = gettext_noop("Collation");
1717 headers[cols++] = gettext_noop("Nullable");
1718 headers[cols++] = gettext_noop("Default");
1719 show_column_details = true;
1722 if (tableinfo.relkind == RELKIND_SEQUENCE)
1723 headers[cols++] = gettext_noop("Value");
1725 if (tableinfo.relkind == RELKIND_INDEX)
1726 headers[cols++] = gettext_noop("Definition");
1728 if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
1729 headers[cols++] = gettext_noop("FDW Options");
1733 headers[cols++] = gettext_noop("Storage");
1734 if (tableinfo.relkind == RELKIND_RELATION ||
1735 tableinfo.relkind == RELKIND_MATVIEW ||
1736 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1737 tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1738 headers[cols++] = gettext_noop("Stats target");
1739 /* Column comments, if the relkind supports this feature. */
1740 if (tableinfo.relkind == RELKIND_RELATION ||
1741 tableinfo.relkind == RELKIND_VIEW ||
1742 tableinfo.relkind == RELKIND_MATVIEW ||
1743 tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
1744 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1745 tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1746 headers[cols++] = gettext_noop("Description");
1749 printTableInit(&cont, &myopt, title.data, cols, numrows);
1750 printTableInitialized = true;
1752 for (i = 0; i < cols; i++)
1753 printTableAddHeader(&cont, headers[i], true, 'l');
1755 /* Get view_def if table is a view or materialized view */
1756 if ((tableinfo.relkind == RELKIND_VIEW ||
1757 tableinfo.relkind == RELKIND_MATVIEW) && verbose)
1761 printfPQExpBuffer(&buf,
1762 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
1764 result = PSQLexec(buf.data);
1768 if (PQntuples(result) > 0)
1769 view_def = pg_strdup(PQgetvalue(result, 0, 0));
1774 /* Generate table cells to be printed */
1775 for (i = 0; i < numrows; i++)
1778 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
1781 printTableAddCell(&cont, PQgetvalue(res, i, 1), false, false);
1783 /* Collation, Nullable, Default */
1784 if (show_column_details)
1787 char *default_str = "";
1789 printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
1791 printTableAddCell(&cont, strcmp(PQgetvalue(res, i, 3), "t") == 0 ? "not null" : "", false, false);
1793 identity = PQgetvalue(res, i, 6);
1796 /* (note: above we cut off the 'default' string at 128) */
1797 default_str = PQgetvalue(res, i, 2);
1798 else if (identity[0] == ATTRIBUTE_IDENTITY_ALWAYS)
1799 default_str = "generated always as identity";
1800 else if (identity[0] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
1801 default_str = "generated by default as identity";
1803 printTableAddCell(&cont, default_str, false, false);
1806 /* Value: for sequences only */
1807 if (tableinfo.relkind == RELKIND_SEQUENCE)
1808 printTableAddCell(&cont, seq_values[i], false, false);
1810 /* Expression for index column */
1811 if (tableinfo.relkind == RELKIND_INDEX)
1812 printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
1814 /* FDW options for foreign table column, only for 9.2 or later */
1815 if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
1816 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
1818 /* Storage and Description */
1822 char *storage = PQgetvalue(res, i, firstvcol);
1824 /* these strings are literal in our syntax, so not translated. */
1825 printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
1826 (storage[0] == 'm' ? "main" :
1827 (storage[0] == 'x' ? "extended" :
1828 (storage[0] == 'e' ? "external" :
1832 /* Statistics target, if the relkind supports this feature */
1833 if (tableinfo.relkind == RELKIND_RELATION ||
1834 tableinfo.relkind == RELKIND_MATVIEW ||
1835 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1836 tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1838 printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
1842 /* Column comments, if the relkind supports this feature. */
1843 if (tableinfo.relkind == RELKIND_RELATION ||
1844 tableinfo.relkind == RELKIND_VIEW ||
1845 tableinfo.relkind == RELKIND_MATVIEW ||
1846 tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
1847 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1848 tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1849 printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 2),
1855 if (pset.sversion >= 100000)
1857 /* Get the partition information */
1861 char *partconstraintdef = NULL;
1863 /* If verbose, also request the partition constraint definition */
1865 printfPQExpBuffer(&buf,
1866 "SELECT inhparent::pg_catalog.regclass,"
1867 " pg_get_expr(c.relpartbound, inhrelid),"
1868 " pg_get_partition_constraintdef(inhrelid)"
1869 " FROM pg_catalog.pg_class c"
1870 " JOIN pg_catalog.pg_inherits"
1871 " ON c.oid = inhrelid"
1872 " WHERE c.oid = '%s' AND c.relispartition;", oid);
1874 printfPQExpBuffer(&buf,
1875 "SELECT inhparent::pg_catalog.regclass,"
1876 " pg_get_expr(c.relpartbound, inhrelid)"
1877 " FROM pg_catalog.pg_class c"
1878 " JOIN pg_catalog.pg_inherits"
1879 " ON c.oid = inhrelid"
1880 " WHERE c.oid = '%s' AND c.relispartition;", oid);
1881 result = PSQLexec(buf.data);
1885 if (PQntuples(result) > 0)
1887 parent_name = PQgetvalue(result, 0, 0);
1888 partdef = PQgetvalue(result, 0, 1);
1890 if (PQnfields(result) == 3)
1891 partconstraintdef = PQgetvalue(result, 0, 2);
1893 printfPQExpBuffer(&tmpbuf, _("Partition of: %s %s"), parent_name,
1895 printTableAddFooter(&cont, tmpbuf.data);
1897 if (partconstraintdef)
1899 printfPQExpBuffer(&tmpbuf, _("Partition constraint: %s"),
1901 printTableAddFooter(&cont, tmpbuf.data);
1908 if (tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1910 /* Get the partition key information */
1914 printfPQExpBuffer(&buf,
1915 "SELECT pg_catalog.pg_get_partkeydef('%s'::pg_catalog.oid);",
1917 result = PSQLexec(buf.data);
1918 if (!result || PQntuples(result) != 1)
1921 partkeydef = PQgetvalue(result, 0, 0);
1922 printfPQExpBuffer(&tmpbuf, _("Partition key: %s"), partkeydef);
1923 printTableAddFooter(&cont, tmpbuf.data);
1927 if (tableinfo.relkind == RELKIND_INDEX)
1929 /* Footer information about an index */
1932 printfPQExpBuffer(&buf,
1933 "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
1934 if (pset.sversion >= 80200)
1935 appendPQExpBufferStr(&buf, "i.indisvalid,\n");
1937 appendPQExpBufferStr(&buf, "true AS indisvalid,\n");
1938 if (pset.sversion >= 90000)
1939 appendPQExpBufferStr(&buf,
1940 " (NOT i.indimmediate) AND "
1941 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1942 "WHERE conrelid = i.indrelid AND "
1943 "conindid = i.indexrelid AND "
1944 "contype IN ('p','u','x') AND "
1945 "condeferrable) AS condeferrable,\n"
1946 " (NOT i.indimmediate) AND "
1947 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1948 "WHERE conrelid = i.indrelid AND "
1949 "conindid = i.indexrelid AND "
1950 "contype IN ('p','u','x') AND "
1951 "condeferred) AS condeferred,\n");
1953 appendPQExpBufferStr(&buf,
1954 " false AS condeferrable, false AS condeferred,\n");
1956 if (pset.sversion >= 90400)
1957 appendPQExpBuffer(&buf, "i.indisreplident,\n");
1959 appendPQExpBuffer(&buf, "false AS indisreplident,\n");
1961 appendPQExpBuffer(&buf, " a.amname, c2.relname, "
1962 "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
1963 "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
1964 "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
1965 "AND i.indrelid = c2.oid;",
1968 result = PSQLexec(buf.data);
1971 else if (PQntuples(result) != 1)
1978 char *indisunique = PQgetvalue(result, 0, 0);
1979 char *indisprimary = PQgetvalue(result, 0, 1);
1980 char *indisclustered = PQgetvalue(result, 0, 2);
1981 char *indisvalid = PQgetvalue(result, 0, 3);
1982 char *deferrable = PQgetvalue(result, 0, 4);
1983 char *deferred = PQgetvalue(result, 0, 5);
1984 char *indisreplident = PQgetvalue(result, 0, 6);
1985 char *indamname = PQgetvalue(result, 0, 7);
1986 char *indtable = PQgetvalue(result, 0, 8);
1987 char *indpred = PQgetvalue(result, 0, 9);
1989 if (strcmp(indisprimary, "t") == 0)
1990 printfPQExpBuffer(&tmpbuf, _("primary key, "));
1991 else if (strcmp(indisunique, "t") == 0)
1992 printfPQExpBuffer(&tmpbuf, _("unique, "));
1994 resetPQExpBuffer(&tmpbuf);
1995 appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
1997 /* we assume here that index and table are in same schema */
1998 appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
1999 schemaname, indtable);
2001 if (strlen(indpred))
2002 appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
2004 if (strcmp(indisclustered, "t") == 0)
2005 appendPQExpBufferStr(&tmpbuf, _(", clustered"));
2007 if (strcmp(indisvalid, "t") != 0)
2008 appendPQExpBufferStr(&tmpbuf, _(", invalid"));
2010 if (strcmp(deferrable, "t") == 0)
2011 appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
2013 if (strcmp(deferred, "t") == 0)
2014 appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
2016 if (strcmp(indisreplident, "t") == 0)
2017 appendPQExpBuffer(&tmpbuf, _(", replica identity"));
2019 printTableAddFooter(&cont, tmpbuf.data);
2020 add_tablespace_footer(&cont, tableinfo.relkind,
2021 tableinfo.tablespace, true);
2026 else if (tableinfo.relkind == RELKIND_SEQUENCE)
2028 /* Footer information about a sequence */
2029 PGresult *result = NULL;
2031 /* Get the column that owns this sequence */
2032 printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
2033 "\n pg_catalog.quote_ident(relname) || '.' ||"
2034 "\n pg_catalog.quote_ident(attname),"
2036 "\nFROM pg_catalog.pg_class c"
2037 "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
2038 "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
2039 "\nINNER JOIN pg_catalog.pg_attribute a ON ("
2040 "\n a.attrelid=c.oid AND"
2041 "\n a.attnum=d.refobjsubid)"
2042 "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
2043 "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
2045 "\n AND d.deptype IN ('a', 'i')",
2048 result = PSQLexec(buf.data);
2051 else if (PQntuples(result) == 1)
2053 switch (PQgetvalue(result, 0, 1)[0])
2056 printfPQExpBuffer(&buf, _("Owned by: %s"),
2057 PQgetvalue(result, 0, 0));
2058 printTableAddFooter(&cont, buf.data);
2061 printfPQExpBuffer(&buf, _("Sequence for identity column: %s"),
2062 PQgetvalue(result, 0, 0));
2063 printTableAddFooter(&cont, buf.data);
2069 * If we get no rows back, don't show anything (obviously). We should
2070 * never get more than one row back, but if we do, just ignore it and
2071 * don't print anything.
2075 else if (tableinfo.relkind == RELKIND_RELATION ||
2076 tableinfo.relkind == RELKIND_MATVIEW ||
2077 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
2078 tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
2080 /* Footer information about a table */
2081 PGresult *result = NULL;
2085 if (tableinfo.hasindex)
2087 printfPQExpBuffer(&buf,
2088 "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
2089 if (pset.sversion >= 80200)
2090 appendPQExpBufferStr(&buf, "i.indisvalid, ");
2092 appendPQExpBufferStr(&buf, "true as indisvalid, ");
2093 appendPQExpBufferStr(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n ");
2094 if (pset.sversion >= 90000)
2095 appendPQExpBufferStr(&buf,
2096 "pg_catalog.pg_get_constraintdef(con.oid, true), "
2097 "contype, condeferrable, condeferred");
2099 appendPQExpBufferStr(&buf,
2100 "null AS constraintdef, null AS contype, "
2101 "false AS condeferrable, false AS condeferred");
2102 if (pset.sversion >= 90400)
2103 appendPQExpBufferStr(&buf, ", i.indisreplident");
2105 appendPQExpBufferStr(&buf, ", false AS indisreplident");
2106 if (pset.sversion >= 80000)
2107 appendPQExpBufferStr(&buf, ", c2.reltablespace");
2108 appendPQExpBufferStr(&buf,
2109 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
2110 if (pset.sversion >= 90000)
2111 appendPQExpBufferStr(&buf,
2112 " LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
2113 appendPQExpBuffer(&buf,
2114 "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
2115 "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname;",
2117 result = PSQLexec(buf.data);
2121 tuples = PQntuples(result);
2125 printTableAddFooter(&cont, _("Indexes:"));
2126 for (i = 0; i < tuples; i++)
2128 /* untranslated index name */
2129 printfPQExpBuffer(&buf, " \"%s\"",
2130 PQgetvalue(result, i, 0));
2132 /* If exclusion constraint, print the constraintdef */
2133 if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
2135 appendPQExpBuffer(&buf, " %s",
2136 PQgetvalue(result, i, 6));
2140 const char *indexdef;
2141 const char *usingpos;
2143 /* Label as primary key or unique (but not both) */
2144 if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
2145 appendPQExpBufferStr(&buf, " PRIMARY KEY,");
2146 else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
2148 if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
2149 appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
2151 appendPQExpBufferStr(&buf, " UNIQUE,");
2154 /* Everything after "USING" is echoed verbatim */
2155 indexdef = PQgetvalue(result, i, 5);
2156 usingpos = strstr(indexdef, " USING ");
2158 indexdef = usingpos + 7;
2159 appendPQExpBuffer(&buf, " %s", indexdef);
2161 /* Need these for deferrable PK/UNIQUE indexes */
2162 if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
2163 appendPQExpBufferStr(&buf, " DEFERRABLE");
2165 if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
2166 appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
2169 /* Add these for all cases */
2170 if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
2171 appendPQExpBufferStr(&buf, " CLUSTER");
2173 if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
2174 appendPQExpBufferStr(&buf, " INVALID");
2176 if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
2177 appendPQExpBuffer(&buf, " REPLICA IDENTITY");
2179 printTableAddFooter(&cont, buf.data);
2181 /* Print tablespace of the index on the same line */
2182 if (pset.sversion >= 80000)
2183 add_tablespace_footer(&cont, RELKIND_INDEX,
2184 atooid(PQgetvalue(result, i, 11)),
2191 /* print table (and column) check constraints */
2192 if (tableinfo.checks)
2194 printfPQExpBuffer(&buf,
2195 "SELECT r.conname, "
2196 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
2197 "FROM pg_catalog.pg_constraint r\n"
2198 "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
2201 result = PSQLexec(buf.data);
2205 tuples = PQntuples(result);
2209 printTableAddFooter(&cont, _("Check constraints:"));
2210 for (i = 0; i < tuples; i++)
2212 /* untranslated constraint name and def */
2213 printfPQExpBuffer(&buf, " \"%s\" %s",
2214 PQgetvalue(result, i, 0),
2215 PQgetvalue(result, i, 1));
2217 printTableAddFooter(&cont, buf.data);
2223 /* print foreign-key constraints (there are none if no triggers) */
2224 if (tableinfo.hastriggers)
2226 printfPQExpBuffer(&buf,
2228 " pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n"
2229 "FROM pg_catalog.pg_constraint r\n"
2230 "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1;",
2232 result = PSQLexec(buf.data);
2236 tuples = PQntuples(result);
2240 printTableAddFooter(&cont, _("Foreign-key constraints:"));
2241 for (i = 0; i < tuples; i++)
2243 /* untranslated constraint name and def */
2244 printfPQExpBuffer(&buf, " \"%s\" %s",
2245 PQgetvalue(result, i, 0),
2246 PQgetvalue(result, i, 1));
2248 printTableAddFooter(&cont, buf.data);
2254 /* print incoming foreign-key references (none if no triggers) */
2255 if (tableinfo.hastriggers)
2257 printfPQExpBuffer(&buf,
2258 "SELECT conname, conrelid::pg_catalog.regclass,\n"
2259 " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
2260 "FROM pg_catalog.pg_constraint c\n"
2261 "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1;",
2263 result = PSQLexec(buf.data);
2267 tuples = PQntuples(result);
2271 printTableAddFooter(&cont, _("Referenced by:"));
2272 for (i = 0; i < tuples; i++)
2274 printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
2275 PQgetvalue(result, i, 1),
2276 PQgetvalue(result, i, 0),
2277 PQgetvalue(result, i, 2));
2279 printTableAddFooter(&cont, buf.data);
2285 /* print any row-level policies */
2286 if (pset.sversion >= 90500)
2288 if (pset.sversion >= 100000)
2289 printfPQExpBuffer(&buf,
2290 "SELECT pol.polname, pol.polpermissive,\n"
2291 "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"
2292 "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
2293 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
2295 "WHEN 'r' THEN 'SELECT'\n"
2296 "WHEN 'a' THEN 'INSERT'\n"
2297 "WHEN 'w' THEN 'UPDATE'\n"
2298 "WHEN 'd' THEN 'DELETE'\n"
2300 "FROM pg_catalog.pg_policy pol\n"
2301 "WHERE pol.polrelid = '%s' ORDER BY 1;",
2304 printfPQExpBuffer(&buf,
2305 "SELECT pol.polname, 't' as polpermissive,\n"
2306 "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"
2307 "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
2308 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
2310 "WHEN 'r' THEN 'SELECT'\n"
2311 "WHEN 'a' THEN 'INSERT'\n"
2312 "WHEN 'w' THEN 'UPDATE'\n"
2313 "WHEN 'd' THEN 'DELETE'\n"
2315 "FROM pg_catalog.pg_policy pol\n"
2316 "WHERE pol.polrelid = '%s' ORDER BY 1;",
2319 result = PSQLexec(buf.data);
2323 tuples = PQntuples(result);
2326 * Handle cases where RLS is enabled and there are policies, or
2327 * there aren't policies, or RLS isn't enabled but there are
2330 if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
2331 printTableAddFooter(&cont, _("Policies:"));
2333 if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
2334 printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
2336 if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
2337 printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
2339 if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
2340 printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
2342 if (!tableinfo.rowsecurity && tuples > 0)
2343 printTableAddFooter(&cont, _("Policies (row security disabled):"));
2345 /* Might be an empty set - that's ok */
2346 for (i = 0; i < tuples; i++)
2348 printfPQExpBuffer(&buf, " POLICY \"%s\"",
2349 PQgetvalue(result, i, 0));
2351 if (*(PQgetvalue(result, i, 1)) == 'f')
2352 appendPQExpBuffer(&buf, " AS RESTRICTIVE");
2354 if (!PQgetisnull(result, i, 5))
2355 appendPQExpBuffer(&buf, " FOR %s",
2356 PQgetvalue(result, i, 5));
2358 if (!PQgetisnull(result, i, 2))
2360 appendPQExpBuffer(&buf, "\n TO %s",
2361 PQgetvalue(result, i, 2));
2364 if (!PQgetisnull(result, i, 3))
2365 appendPQExpBuffer(&buf, "\n USING (%s)",
2366 PQgetvalue(result, i, 3));
2368 if (!PQgetisnull(result, i, 4))
2369 appendPQExpBuffer(&buf, "\n WITH CHECK (%s)",
2370 PQgetvalue(result, i, 4));
2372 printTableAddFooter(&cont, buf.data);
2378 /* print any extended statistics */
2379 if (pset.sversion >= 100000)
2381 printfPQExpBuffer(&buf,
2383 "stxrelid::pg_catalog.regclass, "
2384 "stxnamespace::pg_catalog.regnamespace AS nsp, "
2386 " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(attname),', ')\n"
2387 " FROM pg_catalog.unnest(stxkeys) s(attnum)\n"
2388 " JOIN pg_catalog.pg_attribute a ON (stxrelid = a.attrelid AND\n"
2389 " a.attnum = s.attnum AND NOT attisdropped)) AS columns,\n"
2390 " (stxkind @> '{d}') AS ndist_enabled,\n"
2391 " (stxkind @> '{f}') AS deps_enabled\n"
2392 "FROM pg_catalog.pg_statistic_ext stat "
2393 "WHERE stxrelid = '%s'\n"
2397 result = PSQLexec(buf.data);
2401 tuples = PQntuples(result);
2405 printTableAddFooter(&cont, _("Statistics:"));
2407 for (i = 0; i < tuples; i++)
2409 bool gotone = false;
2411 printfPQExpBuffer(&buf, " ");
2413 /* statistics name (qualified with namespace) */
2414 appendPQExpBuffer(&buf, "\"%s\".\"%s\" (",
2415 PQgetvalue(result, i, 2),
2416 PQgetvalue(result, i, 3));
2419 if (strcmp(PQgetvalue(result, i, 5), "t") == 0)
2421 appendPQExpBufferStr(&buf, "ndistinct");
2425 if (strcmp(PQgetvalue(result, i, 6), "t") == 0)
2427 appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
2430 appendPQExpBuffer(&buf, ") ON %s FROM %s",
2431 PQgetvalue(result, i, 4),
2432 PQgetvalue(result, i, 1));
2434 printTableAddFooter(&cont, buf.data);
2441 if (tableinfo.hasrules && tableinfo.relkind != RELKIND_MATVIEW)
2443 if (pset.sversion >= 80300)
2445 printfPQExpBuffer(&buf,
2446 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
2448 "FROM pg_catalog.pg_rewrite r\n"
2449 "WHERE r.ev_class = '%s' ORDER BY 1;",
2454 printfPQExpBuffer(&buf,
2455 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
2456 "'O'::char AS ev_enabled\n"
2457 "FROM pg_catalog.pg_rewrite r\n"
2458 "WHERE r.ev_class = '%s' ORDER BY 1;",
2461 result = PSQLexec(buf.data);
2465 tuples = PQntuples(result);
2472 for (category = 0; category < 4; category++)
2474 have_heading = false;
2476 for (i = 0; i < tuples; i++)
2478 const char *ruledef;
2479 bool list_rule = false;
2484 if (*PQgetvalue(result, i, 2) == 'O')
2488 if (*PQgetvalue(result, i, 2) == 'D')
2492 if (*PQgetvalue(result, i, 2) == 'A')
2496 if (*PQgetvalue(result, i, 2) == 'R')
2508 printfPQExpBuffer(&buf, _("Rules:"));
2511 printfPQExpBuffer(&buf, _("Disabled rules:"));
2514 printfPQExpBuffer(&buf, _("Rules firing always:"));
2517 printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
2520 printTableAddFooter(&cont, buf.data);
2521 have_heading = true;
2524 /* Everything after "CREATE RULE" is echoed verbatim */
2525 ruledef = PQgetvalue(result, i, 1);
2527 printfPQExpBuffer(&buf, " %s", ruledef);
2528 printTableAddFooter(&cont, buf.data);
2535 /* print any publications */
2536 if (pset.sversion >= 100000)
2538 printfPQExpBuffer(&buf,
2539 "SELECT pub.pubname\n"
2540 " FROM pg_catalog.pg_publication pub\n"
2541 " LEFT JOIN pg_catalog.pg_publication_rel pr\n"
2542 " ON (pr.prpubid = pub.oid)\n"
2543 "WHERE pr.prrelid = '%s' OR pub.puballtables\n"
2547 result = PSQLexec(buf.data);
2551 tuples = PQntuples(result);
2554 printTableAddFooter(&cont, _("Publications:"));
2556 /* Might be an empty set - that's ok */
2557 for (i = 0; i < tuples; i++)
2559 printfPQExpBuffer(&buf, " \"%s\"",
2560 PQgetvalue(result, i, 0));
2562 printTableAddFooter(&cont, buf.data);
2570 PGresult *result = NULL;
2572 /* Footer information about a view */
2573 printTableAddFooter(&cont, _("View definition:"));
2574 printTableAddFooter(&cont, view_def);
2577 if (tableinfo.hasrules)
2579 printfPQExpBuffer(&buf,
2580 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
2581 "FROM pg_catalog.pg_rewrite r\n"
2582 "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1;",
2584 result = PSQLexec(buf.data);
2588 if (PQntuples(result) > 0)
2590 printTableAddFooter(&cont, _("Rules:"));
2591 for (i = 0; i < PQntuples(result); i++)
2593 const char *ruledef;
2595 /* Everything after "CREATE RULE" is echoed verbatim */
2596 ruledef = PQgetvalue(result, i, 1);
2599 printfPQExpBuffer(&buf, " %s", ruledef);
2600 printTableAddFooter(&cont, buf.data);
2608 * Print triggers next, if any (but only user-defined triggers). This
2609 * could apply to either a table or a view.
2611 if (tableinfo.hastriggers)
2616 printfPQExpBuffer(&buf,
2618 "pg_catalog.pg_get_triggerdef(t.oid%s), "
2620 "FROM pg_catalog.pg_trigger t\n"
2621 "WHERE t.tgrelid = '%s' AND ",
2622 (pset.sversion >= 90000 ? ", true" : ""),
2623 (pset.sversion >= 90000 ? "t.tgisinternal" :
2624 pset.sversion >= 80300 ?
2625 "t.tgconstraint <> 0 AS tgisinternal" :
2626 "false AS tgisinternal"), oid);
2627 if (pset.sversion >= 90000)
2628 /* display/warn about disabled internal triggers */
2629 appendPQExpBuffer(&buf, "(NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))");
2630 else if (pset.sversion >= 80300)
2631 appendPQExpBufferStr(&buf, "(t.tgconstraint = 0 OR (t.tgconstraint <> 0 AND t.tgenabled = 'D'))");
2633 appendPQExpBufferStr(&buf,
2634 "(NOT tgisconstraint "
2636 " (SELECT 1 FROM pg_catalog.pg_depend d "
2637 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
2638 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
2639 appendPQExpBufferStr(&buf, "\nORDER BY 1;");
2641 result = PSQLexec(buf.data);
2645 tuples = PQntuples(result);
2653 * split the output into 4 different categories. Enabled triggers,
2654 * disabled triggers and the two special ALWAYS and REPLICA
2657 for (category = 0; category <= 4; category++)
2659 have_heading = false;
2660 for (i = 0; i < tuples; i++)
2664 const char *usingpos;
2665 const char *tgenabled;
2666 const char *tgisinternal;
2669 * Check if this trigger falls into the current category
2671 tgenabled = PQgetvalue(result, i, 2);
2672 tgisinternal = PQgetvalue(result, i, 3);
2673 list_trigger = false;
2677 if (*tgenabled == 'O' || *tgenabled == 't')
2678 list_trigger = true;
2681 if ((*tgenabled == 'D' || *tgenabled == 'f') &&
2682 *tgisinternal == 'f')
2683 list_trigger = true;
2686 if ((*tgenabled == 'D' || *tgenabled == 'f') &&
2687 *tgisinternal == 't')
2688 list_trigger = true;
2691 if (*tgenabled == 'A')
2692 list_trigger = true;
2695 if (*tgenabled == 'R')
2696 list_trigger = true;
2699 if (list_trigger == false)
2702 /* Print the category heading once */
2703 if (have_heading == false)
2708 printfPQExpBuffer(&buf, _("Triggers:"));
2711 if (pset.sversion >= 80300)
2712 printfPQExpBuffer(&buf, _("Disabled user triggers:"));
2714 printfPQExpBuffer(&buf, _("Disabled triggers:"));
2717 printfPQExpBuffer(&buf, _("Disabled internal triggers:"));
2720 printfPQExpBuffer(&buf, _("Triggers firing always:"));
2723 printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
2727 printTableAddFooter(&cont, buf.data);
2728 have_heading = true;
2731 /* Everything after "TRIGGER" is echoed verbatim */
2732 tgdef = PQgetvalue(result, i, 1);
2733 usingpos = strstr(tgdef, " TRIGGER ");
2735 tgdef = usingpos + 9;
2737 printfPQExpBuffer(&buf, " %s", tgdef);
2738 printTableAddFooter(&cont, buf.data);
2746 * Finish printing the footer information about a table.
2748 if (tableinfo.relkind == RELKIND_RELATION ||
2749 tableinfo.relkind == RELKIND_MATVIEW ||
2750 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
2751 tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
2756 /* print foreign server name */
2757 if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
2761 /* Footer information about foreign table */
2762 printfPQExpBuffer(&buf,
2763 "SELECT s.srvname,\n"
2764 " array_to_string(ARRAY(SELECT "
2765 " quote_ident(option_name) || ' ' || "
2766 " quote_literal(option_value) FROM "
2767 " pg_options_to_table(ftoptions)), ', ') "
2768 "FROM pg_catalog.pg_foreign_table f,\n"
2769 " pg_catalog.pg_foreign_server s\n"
2770 "WHERE f.ftrelid = %s AND s.oid = f.ftserver;",
2772 result = PSQLexec(buf.data);
2775 else if (PQntuples(result) != 1)
2781 /* Print server name */
2782 printfPQExpBuffer(&buf, _("Server: %s"),
2783 PQgetvalue(result, 0, 0));
2784 printTableAddFooter(&cont, buf.data);
2786 /* Print per-table FDW options, if any */
2787 ftoptions = PQgetvalue(result, 0, 1);
2788 if (ftoptions && ftoptions[0] != '\0')
2790 printfPQExpBuffer(&buf, _("FDW Options: (%s)"), ftoptions);
2791 printTableAddFooter(&cont, buf.data);
2796 /* print inherited tables (exclude, if parent is a partitioned table) */
2797 printfPQExpBuffer(&buf,
2798 "SELECT c.oid::pg_catalog.regclass"
2799 " FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i"
2800 " WHERE c.oid=i.inhparent AND i.inhrelid = '%s'"
2801 " AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_TABLE)
2802 " ORDER BY inhseqno;", oid);
2804 result = PSQLexec(buf.data);
2809 const char *s = _("Inherits");
2810 int sw = pg_wcswidth(s, strlen(s), pset.encoding);
2812 tuples = PQntuples(result);
2814 for (i = 0; i < tuples; i++)
2817 printfPQExpBuffer(&buf, "%s: %s",
2818 s, PQgetvalue(result, i, 0));
2820 printfPQExpBuffer(&buf, "%*s %s",
2821 sw, "", PQgetvalue(result, i, 0));
2823 appendPQExpBufferChar(&buf, ',');
2825 printTableAddFooter(&cont, buf.data);
2831 /* print child tables (with additional info if partitions) */
2832 if (pset.sversion >= 100000)
2833 printfPQExpBuffer(&buf,
2834 "SELECT c.oid::pg_catalog.regclass, pg_get_expr(c.relpartbound, c.oid)"
2835 " FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i"
2836 " WHERE c.oid=i.inhrelid AND"
2837 " i.inhparent = '%s' AND"
2838 " EXISTS (SELECT 1 FROM pg_class c WHERE c.oid = '%s')"
2839 " ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid, oid);
2840 else if (pset.sversion >= 80300)
2841 printfPQExpBuffer(&buf,
2842 "SELECT c.oid::pg_catalog.regclass"
2843 " FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i"
2844 " WHERE c.oid=i.inhrelid AND"
2845 " i.inhparent = '%s' AND"
2846 " EXISTS (SELECT 1 FROM pg_class c WHERE c.oid = '%s')"
2847 " ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid, oid);
2849 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);
2851 result = PSQLexec(buf.data);
2855 tuples = PQntuples(result);
2859 /* print the number of child tables, if any */
2862 if (tableinfo.relkind != RELKIND_PARTITIONED_TABLE)
2863 printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
2865 printfPQExpBuffer(&buf, _("Number of partitions: %d (Use \\d+ to list them.)"), tuples);
2866 printTableAddFooter(&cont, buf.data);
2871 /* display the list of child tables */
2872 const char *ct = (tableinfo.relkind != RELKIND_PARTITIONED_TABLE) ?
2873 _("Child tables") : _("Partitions");
2874 int ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
2876 for (i = 0; i < tuples; i++)
2878 if (tableinfo.relkind != RELKIND_PARTITIONED_TABLE)
2881 printfPQExpBuffer(&buf, "%s: %s",
2882 ct, PQgetvalue(result, i, 0));
2884 printfPQExpBuffer(&buf, "%*s %s",
2885 ctw, "", PQgetvalue(result, i, 0));
2890 printfPQExpBuffer(&buf, "%s: %s %s",
2891 ct, PQgetvalue(result, i, 0), PQgetvalue(result, i, 1));
2893 printfPQExpBuffer(&buf, "%*s %s %s",
2894 ctw, "", PQgetvalue(result, i, 0), PQgetvalue(result, i, 1));
2897 appendPQExpBufferChar(&buf, ',');
2899 printTableAddFooter(&cont, buf.data);
2905 if (tableinfo.reloftype)
2907 printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
2908 printTableAddFooter(&cont, buf.data);
2912 (tableinfo.relkind == RELKIND_RELATION ||
2913 tableinfo.relkind == RELKIND_MATVIEW) &&
2916 * No need to display default values; we already display a REPLICA
2917 * IDENTITY marker on indexes.
2919 tableinfo.relreplident != 'i' &&
2920 ((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
2921 (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
2923 const char *s = _("Replica Identity");
2925 printfPQExpBuffer(&buf, "%s: %s",
2927 tableinfo.relreplident == 'f' ? "FULL" :
2928 tableinfo.relreplident == 'n' ? "NOTHING" :
2931 printTableAddFooter(&cont, buf.data);
2934 /* OIDs, if verbose and not a materialized view */
2935 if (verbose && tableinfo.relkind != RELKIND_MATVIEW && tableinfo.hasoids)
2936 printTableAddFooter(&cont, _("Has OIDs: yes"));
2938 /* Tablespace info */
2939 add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
2943 /* reloptions, if verbose */
2945 tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
2947 const char *t = _("Options");
2949 printfPQExpBuffer(&buf, "%s: %s", t, tableinfo.reloptions);
2950 printTableAddFooter(&cont, buf.data);
2953 printTable(&cont, pset.queryFout, false, pset.logfile);
2960 if (printTableInitialized)
2961 printTableCleanup(&cont);
2962 termPQExpBuffer(&buf);
2963 termPQExpBuffer(&title);
2964 termPQExpBuffer(&tmpbuf);
2968 for (ptr = seq_values; *ptr; ptr++)
2983 * Add a tablespace description to a footer. If 'newline' is true, it is added
2984 * in a new line; otherwise it's appended to the current value of the last
2988 add_tablespace_footer(printTableContent *const cont, char relkind,
2989 Oid tablespace, const bool newline)
2991 /* relkinds for which we support tablespaces */
2992 if (relkind == RELKIND_RELATION ||
2993 relkind == RELKIND_MATVIEW ||
2994 relkind == RELKIND_INDEX ||
2995 relkind == RELKIND_PARTITIONED_TABLE)
2998 * We ignore the database default tablespace so that users not using
2999 * tablespaces don't need to know about them. This case also covers
3000 * pre-8.0 servers, for which tablespace will always be 0.
3002 if (tablespace != 0)
3004 PGresult *result = NULL;
3005 PQExpBufferData buf;
3007 initPQExpBuffer(&buf);
3008 printfPQExpBuffer(&buf,
3009 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
3010 "WHERE oid = '%u';", tablespace);
3011 result = PSQLexec(buf.data);
3014 /* Should always be the case, but.... */
3015 if (PQntuples(result) > 0)
3019 /* Add the tablespace as a new footer */
3020 printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
3021 PQgetvalue(result, 0, 0));
3022 printTableAddFooter(cont, buf.data);
3026 /* Append the tablespace to the latest footer */
3027 printfPQExpBuffer(&buf, "%s", cont->footer->data);
3030 translator: before this string there's an index description like
3031 '"foo_pkey" PRIMARY KEY, btree (a)' */
3032 appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
3033 PQgetvalue(result, 0, 0));
3034 printTableSetFooter(cont, buf.data);
3038 termPQExpBuffer(&buf);
3046 * Describes roles. Any schema portion of the pattern is ignored.
3049 describeRoles(const char *pattern, bool verbose, bool showSystem)
3051 PQExpBufferData buf;
3053 printTableContent cont;
3054 printTableOpt myopt = pset.popt.topt;
3059 const char align = 'l';
3062 myopt.default_footer = false;
3064 initPQExpBuffer(&buf);
3066 if (pset.sversion >= 80100)
3068 printfPQExpBuffer(&buf,
3069 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
3070 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
3071 " r.rolconnlimit, r.rolvaliduntil,\n"
3072 " ARRAY(SELECT b.rolname\n"
3073 " FROM pg_catalog.pg_auth_members m\n"
3074 " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
3075 " WHERE m.member = r.oid) as memberof");
3077 if (verbose && pset.sversion >= 80200)
3079 appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
3082 if (pset.sversion >= 90100)
3084 appendPQExpBufferStr(&buf, "\n, r.rolreplication");
3087 if (pset.sversion >= 90500)
3089 appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
3092 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
3094 if (!showSystem && !pattern)
3095 appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
3097 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3098 NULL, "r.rolname", NULL, NULL);
3102 printfPQExpBuffer(&buf,
3103 "SELECT u.usename AS rolname,\n"
3104 " u.usesuper AS rolsuper,\n"
3105 " true AS rolinherit, false AS rolcreaterole,\n"
3106 " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
3107 " -1 AS rolconnlimit,"
3108 " u.valuntil as rolvaliduntil,\n"
3109 " ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
3110 "\nFROM pg_catalog.pg_user u\n");
3112 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3113 NULL, "u.usename", NULL, NULL);
3116 appendPQExpBufferStr(&buf, "ORDER BY 1;");
3118 res = PSQLexec(buf.data);
3122 nrows = PQntuples(res);
3123 attr = pg_malloc0((nrows + 1) * sizeof(*attr));
3125 printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
3127 printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
3128 printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
3129 printTableAddHeader(&cont, gettext_noop("Member of"), true, align);
3131 if (verbose && pset.sversion >= 80200)
3132 printTableAddHeader(&cont, gettext_noop("Description"), true, align);
3134 for (i = 0; i < nrows; i++)
3136 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
3138 resetPQExpBuffer(&buf);
3139 if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
3140 add_role_attribute(&buf, _("Superuser"));
3142 if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
3143 add_role_attribute(&buf, _("No inheritance"));
3145 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
3146 add_role_attribute(&buf, _("Create role"));
3148 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
3149 add_role_attribute(&buf, _("Create DB"));
3151 if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
3152 add_role_attribute(&buf, _("Cannot login"));
3154 if (pset.sversion >= 90100)
3155 if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
3156 add_role_attribute(&buf, _("Replication"));
3158 if (pset.sversion >= 90500)
3159 if (strcmp(PQgetvalue(res, i, (verbose ? 11 : 10)), "t") == 0)
3160 add_role_attribute(&buf, _("Bypass RLS"));
3162 conns = atoi(PQgetvalue(res, i, 6));
3166 appendPQExpBufferChar(&buf, '\n');
3169 appendPQExpBufferStr(&buf, _("No connections"));
3171 appendPQExpBuffer(&buf, ngettext("%d connection",
3177 if (strcmp(PQgetvalue(res, i, 7), "") != 0)
3180 appendPQExpBufferStr(&buf, "\n");
3181 appendPQExpBufferStr(&buf, _("Password valid until "));
3182 appendPQExpBufferStr(&buf, PQgetvalue(res, i, 7));
3185 attr[i] = pg_strdup(buf.data);
3187 printTableAddCell(&cont, attr[i], false, false);
3189 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
3191 if (verbose && pset.sversion >= 80200)
3192 printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
3194 termPQExpBuffer(&buf);
3196 printTable(&cont, pset.queryFout, false, pset.logfile);
3197 printTableCleanup(&cont);
3199 for (i = 0; i < nrows; i++)
3208 add_role_attribute(PQExpBuffer buf, const char *const str)
3211 appendPQExpBufferStr(buf, ", ");
3213 appendPQExpBufferStr(buf, str);
3220 listDbRoleSettings(const char *pattern, const char *pattern2)
3222 PQExpBufferData buf;
3224 printQueryOpt myopt = pset.popt;
3226 initPQExpBuffer(&buf);
3228 if (pset.sversion >= 90000)
3232 printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
3233 "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
3234 "FROM pg_db_role_setting AS s\n"
3235 "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n"
3236 "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n",
3237 gettext_noop("Role"),
3238 gettext_noop("Database"),
3239 gettext_noop("Settings"));
3240 havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
3241 NULL, "pg_roles.rolname", NULL, NULL);
3242 processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
3243 NULL, "pg_database.datname", NULL, NULL);
3244 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3248 fprintf(pset.queryFout,
3249 _("No per-database role settings support in this server version.\n"));
3253 res = PSQLexec(buf.data);
3257 if (PQntuples(res) == 0 && !pset.quiet)
3260 fprintf(pset.queryFout, _("No matching settings found.\n"));
3262 fprintf(pset.queryFout, _("No settings found.\n"));
3266 myopt.nullPrint = NULL;
3267 myopt.title = _("List of settings");
3268 myopt.translate_header = true;
3270 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3274 resetPQExpBuffer(&buf);
3282 * handler for \dt, \di, etc.
3284 * tabtypes is an array of characters, specifying what info is desired:
3288 * m - materialized views
3290 * E - foreign table (Note: different from 'f', the relkind value)
3291 * (any order of the above is fine)
3292 * If tabtypes is empty, we default to \dtvsE.
3295 listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
3297 bool showTables = strchr(tabtypes, 't') != NULL;
3298 bool showIndexes = strchr(tabtypes, 'i') != NULL;
3299 bool showViews = strchr(tabtypes, 'v') != NULL;
3300 bool showMatViews = strchr(tabtypes, 'm') != NULL;
3301 bool showSeq = strchr(tabtypes, 's') != NULL;
3302 bool showForeign = strchr(tabtypes, 'E') != NULL;
3304 PQExpBufferData buf;
3306 printQueryOpt myopt = pset.popt;
3307 static const bool translate_columns[] = {false, false, true, false, false, false, false};
3309 if (!(showTables || showIndexes || showViews || showMatViews || showSeq || showForeign))
3310 showTables = showViews = showMatViews = showSeq = showForeign = true;
3312 initPQExpBuffer(&buf);
3315 * Note: as of Pg 8.2, we no longer use relkind 's' (special), but we keep
3316 * it here for backwards compatibility.
3318 printfPQExpBuffer(&buf,
3319 "SELECT n.nspname as \"%s\",\n"
3320 " c.relname as \"%s\",\n"
3322 " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
3323 " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
3324 " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
3325 " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'"
3326 " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
3327 " WHEN 's' THEN '%s'"
3328 " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
3329 " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
3331 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
3332 gettext_noop("Schema"),
3333 gettext_noop("Name"),
3334 gettext_noop("table"),
3335 gettext_noop("view"),
3336 gettext_noop("materialized view"),
3337 gettext_noop("index"),
3338 gettext_noop("sequence"),
3339 gettext_noop("special"),
3340 gettext_noop("foreign table"),
3341 gettext_noop("table"), /* partitioned table */
3342 gettext_noop("Type"),
3343 gettext_noop("Owner"));
3346 appendPQExpBuffer(&buf,
3347 ",\n c2.relname as \"%s\"",
3348 gettext_noop("Table"));
3353 * As of PostgreSQL 9.0, use pg_table_size() to show a more accurate
3354 * size of a table, including FSM, VM and TOAST tables.
3356 if (pset.sversion >= 90000)
3357 appendPQExpBuffer(&buf,
3358 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \"%s\"",
3359 gettext_noop("Size"));
3360 else if (pset.sversion >= 80100)
3361 appendPQExpBuffer(&buf,
3362 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
3363 gettext_noop("Size"));
3365 appendPQExpBuffer(&buf,
3366 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
3367 gettext_noop("Description"));
3370 appendPQExpBufferStr(&buf,
3371 "\nFROM pg_catalog.pg_class c"
3372 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
3374 appendPQExpBufferStr(&buf,
3375 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
3376 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
3378 appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
3380 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_RELATION) ","
3381 CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
3383 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_VIEW) ",");
3385 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_MATVIEW) ",");
3387 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_INDEX) ",");
3389 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_SEQUENCE) ",");
3390 if (showSystem || pattern)
3391 appendPQExpBufferStr(&buf, "'s',"); /* was RELKIND_SPECIAL */
3393 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_FOREIGN_TABLE) ",");
3395 appendPQExpBufferStr(&buf, "''"); /* dummy */
3396 appendPQExpBufferStr(&buf, ")\n");
3398 if (!showSystem && !pattern)
3399 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
3400 " AND n.nspname <> 'information_schema'\n");
3403 * TOAST objects are suppressed unconditionally. Since we don't provide
3404 * any way to select RELKIND_TOASTVALUE above, we would never show toast
3405 * tables in any case; it seems a bit confusing to allow their indexes to
3406 * be shown. Use plain \d if you really need to look at a TOAST
3409 appendPQExpBufferStr(&buf, " AND n.nspname !~ '^pg_toast'\n");
3411 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3412 "n.nspname", "c.relname", NULL,
3413 "pg_catalog.pg_table_is_visible(c.oid)");
3415 appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
3417 res = PSQLexec(buf.data);
3418 termPQExpBuffer(&buf);
3422 if (PQntuples(res) == 0 && !pset.quiet)
3425 fprintf(pset.queryFout, _("No matching relations found.\n"));
3427 fprintf(pset.queryFout, _("No relations found.\n"));
3431 myopt.nullPrint = NULL;
3432 myopt.title = _("List of relations");
3433 myopt.translate_header = true;
3434 myopt.translate_columns = translate_columns;
3435 myopt.n_translate_columns = lengthof(translate_columns);
3437 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3448 * Describes languages.
3451 listLanguages(const char *pattern, bool verbose, bool showSystem)
3453 PQExpBufferData buf;
3455 printQueryOpt myopt = pset.popt;
3457 initPQExpBuffer(&buf);
3459 printfPQExpBuffer(&buf,
3460 "SELECT l.lanname AS \"%s\",\n",
3461 gettext_noop("Name"));
3462 if (pset.sversion >= 80300)
3463 appendPQExpBuffer(&buf,
3464 " pg_catalog.pg_get_userbyid(l.lanowner) as \"%s\",\n",
3465 gettext_noop("Owner"));
3467 appendPQExpBuffer(&buf,
3468 " l.lanpltrusted AS \"%s\"",
3469 gettext_noop("Trusted"));
3473 appendPQExpBuffer(&buf,
3474 ",\n NOT l.lanispl AS \"%s\",\n"
3475 " l.lanplcallfoid::regprocedure AS \"%s\",\n"
3476 " l.lanvalidator::regprocedure AS \"%s\",\n ",
3477 gettext_noop("Internal Language"),
3478 gettext_noop("Call Handler"),
3479 gettext_noop("Validator"));
3480 if (pset.sversion >= 90000)
3481 appendPQExpBuffer(&buf, "l.laninline::regprocedure AS \"%s\",\n ",
3482 gettext_noop("Inline Handler"));
3483 printACLColumn(&buf, "l.lanacl");
3486 appendPQExpBuffer(&buf,
3487 ",\n d.description AS \"%s\""
3488 "\nFROM pg_catalog.pg_language l\n"
3489 "LEFT JOIN pg_catalog.pg_description d\n"
3490 " ON d.classoid = l.tableoid AND d.objoid = l.oid\n"
3491 " AND d.objsubid = 0\n",
3492 gettext_noop("Description"));
3495 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3496 NULL, "l.lanname", NULL, NULL);
3498 if (!showSystem && !pattern)
3499 appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n");
3502 appendPQExpBufferStr(&buf, "ORDER BY 1;");
3504 res = PSQLexec(buf.data);
3505 termPQExpBuffer(&buf);
3509 myopt.nullPrint = NULL;
3510 myopt.title = _("List of languages");
3511 myopt.translate_header = true;
3513 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3523 * Describes domains.
3526 listDomains(const char *pattern, bool verbose, bool showSystem)
3528 PQExpBufferData buf;
3530 printQueryOpt myopt = pset.popt;
3532 initPQExpBuffer(&buf);
3534 printfPQExpBuffer(&buf,
3535 "SELECT n.nspname as \"%s\",\n"
3536 " t.typname as \"%s\",\n"
3537 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n",
3538 gettext_noop("Schema"),
3539 gettext_noop("Name"),
3540 gettext_noop("Type"));
3542 if (pset.sversion >= 90100)
3543 appendPQExpBuffer(&buf,
3544 " (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
3545 " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as \"%s\",\n",
3546 gettext_noop("Collation"));
3547 appendPQExpBuffer(&buf,
3548 " CASE WHEN t.typnotnull THEN 'not null' END as \"%s\",\n"
3549 " t.typdefault as \"%s\",\n"
3550 " pg_catalog.array_to_string(ARRAY(\n"
3551 " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
3552 " ), ' ') as \"%s\"",
3553 gettext_noop("Nullable"),
3554 gettext_noop("Default"),
3555 gettext_noop("Check"));
3559 if (pset.sversion >= 90200)
3561 appendPQExpBufferStr(&buf, ",\n ");
3562 printACLColumn(&buf, "t.typacl");
3564 appendPQExpBuffer(&buf,
3565 ",\n d.description as \"%s\"",
3566 gettext_noop("Description"));
3569 appendPQExpBufferStr(&buf,
3570 "\nFROM pg_catalog.pg_type t\n"
3571 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
3574 appendPQExpBufferStr(&buf,
3575 " LEFT JOIN pg_catalog.pg_description d "
3576 "ON d.classoid = t.tableoid AND d.objoid = t.oid "
3577 "AND d.objsubid = 0\n");
3579 appendPQExpBufferStr(&buf, "WHERE t.typtype = 'd'\n");
3581 if (!showSystem && !pattern)
3582 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
3583 " AND n.nspname <> 'information_schema'\n");
3585 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3586 "n.nspname", "t.typname", NULL,
3587 "pg_catalog.pg_type_is_visible(t.oid)");
3589 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3591 res = PSQLexec(buf.data);
3592 termPQExpBuffer(&buf);
3596 myopt.nullPrint = NULL;
3597 myopt.title = _("List of domains");
3598 myopt.translate_header = true;
3600 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3609 * Describes conversions.
3612 listConversions(const char *pattern, bool verbose, bool showSystem)
3614 PQExpBufferData buf;
3616 printQueryOpt myopt = pset.popt;
3617 static const bool translate_columns[] =
3618 {false, false, false, false, true, false};
3620 initPQExpBuffer(&buf);
3622 printfPQExpBuffer(&buf,
3623 "SELECT n.nspname AS \"%s\",\n"
3624 " c.conname AS \"%s\",\n"
3625 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
3626 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
3627 " CASE WHEN c.condefault THEN '%s'\n"
3628 " ELSE '%s' END AS \"%s\"",
3629 gettext_noop("Schema"),
3630 gettext_noop("Name"),
3631 gettext_noop("Source"),
3632 gettext_noop("Destination"),
3633 gettext_noop("yes"), gettext_noop("no"),
3634 gettext_noop("Default?"));
3637 appendPQExpBuffer(&buf,
3638 ",\n d.description AS \"%s\"",
3639 gettext_noop("Description"));
3641 appendPQExpBufferStr(&buf,
3642 "\nFROM pg_catalog.pg_conversion c\n"
3643 " JOIN pg_catalog.pg_namespace n "
3644 "ON n.oid = c.connamespace\n");
3647 appendPQExpBufferStr(&buf,
3648 "LEFT JOIN pg_catalog.pg_description d "
3649 "ON d.classoid = c.tableoid\n"
3650 " AND d.objoid = c.oid "
3651 "AND d.objsubid = 0\n");
3653 appendPQExpBufferStr(&buf, "WHERE true\n");
3655 if (!showSystem && !pattern)
3656 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
3657 " AND n.nspname <> 'information_schema'\n");
3659 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3660 "n.nspname", "c.conname", NULL,
3661 "pg_catalog.pg_conversion_is_visible(c.oid)");
3663 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3665 res = PSQLexec(buf.data);
3666 termPQExpBuffer(&buf);
3670 myopt.nullPrint = NULL;
3671 myopt.title = _("List of conversions");
3672 myopt.translate_header = true;
3673 myopt.translate_columns = translate_columns;
3674 myopt.n_translate_columns = lengthof(translate_columns);
3676 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3685 * Describes Event Triggers.
3688 listEventTriggers(const char *pattern, bool verbose)
3690 PQExpBufferData buf;
3692 printQueryOpt myopt = pset.popt;
3693 static const bool translate_columns[] =
3694 {false, false, false, true, false, false, false};
3696 initPQExpBuffer(&buf);
3698 printfPQExpBuffer(&buf,
3699 "SELECT evtname as \"%s\", "
3700 "evtevent as \"%s\", "
3701 "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
3702 " case evtenabled when 'O' then '%s'"
3703 " when 'R' then '%s'"
3704 " when 'A' then '%s'"
3705 " when 'D' then '%s' end as \"%s\",\n"
3706 " e.evtfoid::pg_catalog.regproc as \"%s\", "
3707 "pg_catalog.array_to_string(array(select x"
3708 " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
3709 gettext_noop("Name"),
3710 gettext_noop("Event"),
3711 gettext_noop("Owner"),
3712 gettext_noop("enabled"),
3713 gettext_noop("replica"),
3714 gettext_noop("always"),
3715 gettext_noop("disabled"),
3716 gettext_noop("Enabled"),
3717 gettext_noop("Procedure"),
3718 gettext_noop("Tags"));
3720 appendPQExpBuffer(&buf,
3721 ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
3722 gettext_noop("Description"));
3723 appendPQExpBufferStr(&buf,
3724 "\nFROM pg_catalog.pg_event_trigger e ");
3726 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3727 NULL, "evtname", NULL, NULL);
3729 appendPQExpBufferStr(&buf, "ORDER BY 1");
3731 res = PSQLexec(buf.data);
3732 termPQExpBuffer(&buf);
3736 myopt.nullPrint = NULL;
3737 myopt.title = _("List of event triggers");
3738 myopt.translate_header = true;
3739 myopt.translate_columns = translate_columns;
3740 myopt.n_translate_columns = lengthof(translate_columns);
3742 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3754 listCasts(const char *pattern, bool verbose)
3756 PQExpBufferData buf;
3758 printQueryOpt myopt = pset.popt;
3759 static const bool translate_columns[] = {false, false, false, true, false};
3761 initPQExpBuffer(&buf);
3764 * We need a left join to pg_proc for binary casts; the others are just
3765 * paranoia. Also note that we don't attempt to localize '(binary
3766 * coercible)', because there's too much risk of gettext translating a
3767 * function name that happens to match some string in the PO database.
3769 printfPQExpBuffer(&buf,
3770 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
3771 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
3772 " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
3775 " CASE WHEN c.castcontext = 'e' THEN '%s'\n"
3776 " WHEN c.castcontext = 'a' THEN '%s'\n"
3779 gettext_noop("Source type"),
3780 gettext_noop("Target type"),
3781 gettext_noop("Function"),
3783 gettext_noop("in assignment"),
3784 gettext_noop("yes"),
3785 gettext_noop("Implicit?"));
3788 appendPQExpBuffer(&buf,
3789 ",\n d.description AS \"%s\"\n",
3790 gettext_noop("Description"));
3792 appendPQExpBufferStr(&buf,
3793 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
3794 " ON c.castfunc = p.oid\n"
3795 " LEFT JOIN pg_catalog.pg_type ts\n"
3796 " ON c.castsource = ts.oid\n"
3797 " LEFT JOIN pg_catalog.pg_namespace ns\n"
3798 " ON ns.oid = ts.typnamespace\n"
3799 " LEFT JOIN pg_catalog.pg_type tt\n"
3800 " ON c.casttarget = tt.oid\n"
3801 " LEFT JOIN pg_catalog.pg_namespace nt\n"
3802 " ON nt.oid = tt.typnamespace\n");
3805 appendPQExpBufferStr(&buf,
3806 " LEFT JOIN pg_catalog.pg_description d\n"
3807 " ON d.classoid = c.tableoid AND d.objoid = "
3808 "c.oid AND d.objsubid = 0\n");
3810 appendPQExpBufferStr(&buf, "WHERE ( (true");
3813 * Match name pattern against either internal or external name of either
3814 * castsource or casttarget
3816 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3817 "ns.nspname", "ts.typname",
3818 "pg_catalog.format_type(ts.oid, NULL)",
3819 "pg_catalog.pg_type_is_visible(ts.oid)");
3821 appendPQExpBufferStr(&buf, ") OR (true");
3823 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3824 "nt.nspname", "tt.typname",
3825 "pg_catalog.format_type(tt.oid, NULL)",
3826 "pg_catalog.pg_type_is_visible(tt.oid)");
3828 appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
3830 res = PSQLexec(buf.data);
3831 termPQExpBuffer(&buf);
3835 myopt.nullPrint = NULL;
3836 myopt.title = _("List of casts");
3837 myopt.translate_header = true;
3838 myopt.translate_columns = translate_columns;
3839 myopt.n_translate_columns = lengthof(translate_columns);
3841 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3850 * Describes collations.
3853 listCollations(const char *pattern, bool verbose, bool showSystem)
3855 PQExpBufferData buf;
3857 printQueryOpt myopt = pset.popt;
3858 static const bool translate_columns[] = {false, false, false, false, false, false};
3860 if (pset.sversion < 90100)
3864 psql_error("The server (version %s) does not support collations.\n",
3865 formatPGVersionNumber(pset.sversion, false,
3866 sverbuf, sizeof(sverbuf)));
3870 initPQExpBuffer(&buf);
3872 printfPQExpBuffer(&buf,
3873 "SELECT n.nspname AS \"%s\",\n"
3874 " c.collname AS \"%s\",\n"
3875 " c.collcollate AS \"%s\",\n"
3876 " c.collctype AS \"%s\"",
3877 gettext_noop("Schema"),
3878 gettext_noop("Name"),
3879 gettext_noop("Collate"),
3880 gettext_noop("Ctype"));
3882 if (pset.sversion >= 100000)
3883 appendPQExpBuffer(&buf,
3884 ",\n CASE c.collprovider WHEN 'd' THEN 'default' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"%s\"",
3885 gettext_noop("Provider"));
3888 appendPQExpBuffer(&buf,
3889 ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
3890 gettext_noop("Description"));
3892 appendPQExpBufferStr(&buf,
3893 "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
3894 "WHERE n.oid = c.collnamespace\n");
3896 if (!showSystem && !pattern)
3897 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
3898 " AND n.nspname <> 'information_schema'\n");
3901 * Hide collations that aren't usable in the current database's encoding.
3902 * If you think to change this, note that pg_collation_is_visible rejects
3903 * unusable collations, so you will need to hack name pattern processing
3904 * somehow to avoid inconsistent behavior.
3906 appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
3908 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3909 "n.nspname", "c.collname", NULL,
3910 "pg_catalog.pg_collation_is_visible(c.oid)");
3912 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3914 res = PSQLexec(buf.data);
3915 termPQExpBuffer(&buf);
3919 myopt.nullPrint = NULL;
3920 myopt.title = _("List of collations");
3921 myopt.translate_header = true;
3922 myopt.translate_columns = translate_columns;
3923 myopt.n_translate_columns = lengthof(translate_columns);
3925 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3934 * Describes schemas (namespaces)
3937 listSchemas(const char *pattern, bool verbose, bool showSystem)
3939 PQExpBufferData buf;
3941 printQueryOpt myopt = pset.popt;
3943 initPQExpBuffer(&buf);
3944 printfPQExpBuffer(&buf,
3945 "SELECT n.nspname AS \"%s\",\n"
3946 " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
3947 gettext_noop("Name"),
3948 gettext_noop("Owner"));
3952 appendPQExpBufferStr(&buf, ",\n ");
3953 printACLColumn(&buf, "n.nspacl");
3954 appendPQExpBuffer(&buf,
3955 ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
3956 gettext_noop("Description"));
3959 appendPQExpBuffer(&buf,
3960 "\nFROM pg_catalog.pg_namespace n\n");
3962 if (!showSystem && !pattern)
3963 appendPQExpBufferStr(&buf,
3964 "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
3966 processSQLNamePattern(pset.db, &buf, pattern,
3967 !showSystem && !pattern, false,
3968 NULL, "n.nspname", NULL,
3971 appendPQExpBufferStr(&buf, "ORDER BY 1;");
3973 res = PSQLexec(buf.data);
3974 termPQExpBuffer(&buf);
3978 myopt.nullPrint = NULL;
3979 myopt.title = _("List of schemas");
3980 myopt.translate_header = true;
3982 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3991 * list text search parsers
3994 listTSParsers(const char *pattern, bool verbose)
3996 PQExpBufferData buf;
3998 printQueryOpt myopt = pset.popt;
4000 if (pset.sversion < 80300)
4004 psql_error("The server (version %s) does not support full text search.\n",
4005 formatPGVersionNumber(pset.sversion, false,
4006 sverbuf, sizeof(sverbuf)));
4011 return listTSParsersVerbose(pattern);
4013 initPQExpBuffer(&buf);
4015 printfPQExpBuffer(&buf,
4017 " n.nspname as \"%s\",\n"
4018 " p.prsname as \"%s\",\n"
4019 " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
4020 "FROM pg_catalog.pg_ts_parser p\n"
4021 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
4022 gettext_noop("Schema"),
4023 gettext_noop("Name"),
4024 gettext_noop("Description")
4027 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4028 "n.nspname", "p.prsname", NULL,
4029 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
4031 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4033 res = PSQLexec(buf.data);
4034 termPQExpBuffer(&buf);
4038 myopt.nullPrint = NULL;
4039 myopt.title = _("List of text search parsers");
4040 myopt.translate_header = true;
4042 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4049 * full description of parsers
4052 listTSParsersVerbose(const char *pattern)
4054 PQExpBufferData buf;
4058 initPQExpBuffer(&buf);
4060 printfPQExpBuffer(&buf,
4064 "FROM pg_catalog.pg_ts_parser p\n"
4065 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
4068 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4069 "n.nspname", "p.prsname", NULL,
4070 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
4072 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4074 res = PSQLexec(buf.data);
4075 termPQExpBuffer(&buf);
4079 if (PQntuples(res) == 0)
4082 psql_error("Did not find any text search parser named \"%s\".\n",
4088 for (i = 0; i < PQntuples(res); i++)
4091 const char *nspname = NULL;
4092 const char *prsname;
4094 oid = PQgetvalue(res, i, 0);
4095 if (!PQgetisnull(res, i, 1))
4096 nspname = PQgetvalue(res, i, 1);
4097 prsname = PQgetvalue(res, i, 2);
4099 if (!describeOneTSParser(oid, nspname, prsname))
4117 describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
4119 PQExpBufferData buf;
4122 printQueryOpt myopt = pset.popt;
4123 static const bool translate_columns[] = {true, false, false};
4125 initPQExpBuffer(&buf);
4127 printfPQExpBuffer(&buf,
4128 "SELECT '%s' AS \"%s\",\n"
4129 " p.prsstart::pg_catalog.regproc AS \"%s\",\n"
4130 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\"\n"
4131 " FROM pg_catalog.pg_ts_parser p\n"
4132 " WHERE p.oid = '%s'\n"
4135 " p.prstoken::pg_catalog.regproc,\n"
4136 " pg_catalog.obj_description(p.prstoken, 'pg_proc')\n"
4137 " FROM pg_catalog.pg_ts_parser p\n"
4138 " WHERE p.oid = '%s'\n"
4141 " p.prsend::pg_catalog.regproc,\n"
4142 " pg_catalog.obj_description(p.prsend, 'pg_proc')\n"
4143 " FROM pg_catalog.pg_ts_parser p\n"
4144 " WHERE p.oid = '%s'\n"
4147 " p.prsheadline::pg_catalog.regproc,\n"
4148 " pg_catalog.obj_description(p.prsheadline, 'pg_proc')\n"
4149 " FROM pg_catalog.pg_ts_parser p\n"
4150 " WHERE p.oid = '%s'\n"
4153 " p.prslextype::pg_catalog.regproc,\n"
4154 " pg_catalog.obj_description(p.prslextype, 'pg_proc')\n"
4155 " FROM pg_catalog.pg_ts_parser p\n"
4156 " WHERE p.oid = '%s';",
4157 gettext_noop("Start parse"),
4158 gettext_noop("Method"),
4159 gettext_noop("Function"),
4160 gettext_noop("Description"),
4162 gettext_noop("Get next token"),
4164 gettext_noop("End parse"),
4166 gettext_noop("Get headline"),
4168 gettext_noop("Get token types"),
4171 res = PSQLexec(buf.data);
4172 termPQExpBuffer(&buf);
4176 myopt.nullPrint = NULL;
4178 sprintf(title, _("Text search parser \"%s.%s\""), nspname, prsname);
4180 sprintf(title, _("Text search parser \"%s\""), prsname);
4181 myopt.title = title;
4182 myopt.footers = NULL;
4183 myopt.topt.default_footer = false;
4184 myopt.translate_header = true;
4185 myopt.translate_columns = translate_columns;
4186 myopt.n_translate_columns = lengthof(translate_columns);
4188 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4192 initPQExpBuffer(&buf);
4194 printfPQExpBuffer(&buf,
4195 "SELECT t.alias as \"%s\",\n"
4196 " t.description as \"%s\"\n"
4197 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t\n"
4199 gettext_noop("Token name"),
4200 gettext_noop("Description"),
4203 res = PSQLexec(buf.data);
4204 termPQExpBuffer(&buf);
4208 myopt.nullPrint = NULL;
4210 sprintf(title, _("Token types for parser \"%s.%s\""), nspname, prsname);
4212 sprintf(title, _("Token types for parser \"%s\""), prsname);
4213 myopt.title = title;
4214 myopt.footers = NULL;
4215 myopt.topt.default_footer = true;
4216 myopt.translate_header = true;
4217 myopt.translate_columns = NULL;
4218 myopt.n_translate_columns = 0;
4220 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4229 * list text search dictionaries
4232 listTSDictionaries(const char *pattern, bool verbose)
4234 PQExpBufferData buf;
4236 printQueryOpt myopt = pset.popt;
4238 if (pset.sversion < 80300)
4242 psql_error("The server (version %s) does not support full text search.\n",
4243 formatPGVersionNumber(pset.sversion, false,
4244 sverbuf, sizeof(sverbuf)));
4248 initPQExpBuffer(&buf);
4250 printfPQExpBuffer(&buf,
4252 " n.nspname as \"%s\",\n"
4253 " d.dictname as \"%s\",\n",
4254 gettext_noop("Schema"),
4255 gettext_noop("Name"));
4259 appendPQExpBuffer(&buf,
4260 " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM\n"
4261 " pg_catalog.pg_ts_template t\n"
4262 " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace\n"
4263 " WHERE d.dicttemplate = t.oid ) AS \"%s\",\n"
4264 " d.dictinitoption as \"%s\",\n",
4265 gettext_noop("Template"),
4266 gettext_noop("Init options"));
4269 appendPQExpBuffer(&buf,
4270 " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
4271 gettext_noop("Description"));
4273 appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_dict d\n"
4274 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
4276 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4277 "n.nspname", "d.dictname", NULL,
4278 "pg_catalog.pg_ts_dict_is_visible(d.oid)");
4280 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4282 res = PSQLexec(buf.data);
4283 termPQExpBuffer(&buf);
4287 myopt.nullPrint = NULL;
4288 myopt.title = _("List of text search dictionaries");
4289 myopt.translate_header = true;
4291 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4300 * list text search templates
4303 listTSTemplates(const char *pattern, bool verbose)
4305 PQExpBufferData buf;
4307 printQueryOpt myopt = pset.popt;
4309 if (pset.sversion < 80300)
4313 psql_error("The server (version %s) does not support full text search.\n",
4314 formatPGVersionNumber(pset.sversion, false,
4315 sverbuf, sizeof(sverbuf)));
4319 initPQExpBuffer(&buf);
4322 printfPQExpBuffer(&buf,
4324 " n.nspname AS \"%s\",\n"
4325 " t.tmplname AS \"%s\",\n"
4326 " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
4327 " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
4328 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
4329 gettext_noop("Schema"),
4330 gettext_noop("Name"),
4331 gettext_noop("Init"),
4332 gettext_noop("Lexize"),
4333 gettext_noop("Description"));
4335 printfPQExpBuffer(&buf,
4337 " n.nspname AS \"%s\",\n"
4338 " t.tmplname AS \"%s\",\n"
4339 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
4340 gettext_noop("Schema"),
4341 gettext_noop("Name"),
4342 gettext_noop("Description"));
4344 appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_template t\n"
4345 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
4347 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4348 "n.nspname", "t.tmplname", NULL,
4349 "pg_catalog.pg_ts_template_is_visible(t.oid)");
4351 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4353 res = PSQLexec(buf.data);
4354 termPQExpBuffer(&buf);
4358 myopt.nullPrint = NULL;
4359 myopt.title = _("List of text search templates");
4360 myopt.translate_header = true;
4362 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4371 * list text search configurations
4374 listTSConfigs(const char *pattern, bool verbose)
4376 PQExpBufferData buf;
4378 printQueryOpt myopt = pset.popt;
4380 if (pset.sversion < 80300)
4384 psql_error("The server (version %s) does not support full text search.\n",
4385 formatPGVersionNumber(pset.sversion, false,
4386 sverbuf, sizeof(sverbuf)));
4391 return listTSConfigsVerbose(pattern);
4393 initPQExpBuffer(&buf);
4395 printfPQExpBuffer(&buf,
4397 " n.nspname as \"%s\",\n"
4398 " c.cfgname as \"%s\",\n"
4399 " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
4400 "FROM pg_catalog.pg_ts_config c\n"
4401 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace\n",
4402 gettext_noop("Schema"),
4403 gettext_noop("Name"),
4404 gettext_noop("Description")
4407 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4408 "n.nspname", "c.cfgname", NULL,
4409 "pg_catalog.pg_ts_config_is_visible(c.oid)");
4411 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4413 res = PSQLexec(buf.data);
4414 termPQExpBuffer(&buf);
4418 myopt.nullPrint = NULL;
4419 myopt.title = _("List of text search configurations");
4420 myopt.translate_header = true;
4422 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4429 listTSConfigsVerbose(const char *pattern)
4431 PQExpBufferData buf;
4435 initPQExpBuffer(&buf);
4437 printfPQExpBuffer(&buf,
4438 "SELECT c.oid, c.cfgname,\n"
4441 " np.nspname as pnspname\n"
4442 "FROM pg_catalog.pg_ts_config c\n"
4443 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace,\n"
4444 " pg_catalog.pg_ts_parser p\n"
4445 " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace\n"
4446 "WHERE p.oid = c.cfgparser\n"
4449 processSQLNamePattern(pset.db, &buf, pattern, true, false,
4450 "n.nspname", "c.cfgname", NULL,
4451 "pg_catalog.pg_ts_config_is_visible(c.oid)");
4453 appendPQExpBufferStr(&buf, "ORDER BY 3, 2;");
4455 res = PSQLexec(buf.data);
4456 termPQExpBuffer(&buf);
4460 if (PQntuples(res) == 0)
4463 psql_error("Did not find any text search configuration named \"%s\".\n",
4469 for (i = 0; i < PQntuples(res); i++)
4472 const char *cfgname;
4473 const char *nspname = NULL;
4474 const char *prsname;
4475 const char *pnspname = NULL;
4477 oid = PQgetvalue(res, i, 0);
4478 cfgname = PQgetvalue(res, i, 1);
4479 if (!PQgetisnull(res, i, 2))
4480 nspname = PQgetvalue(res, i, 2);
4481 prsname = PQgetvalue(res, i, 3);
4482 if (!PQgetisnull(res, i, 4))
4483 pnspname = PQgetvalue(res, i, 4);
4485 if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname))
4503 describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
4504 const char *pnspname, const char *prsname)
4506 PQExpBufferData buf,
4509 printQueryOpt myopt = pset.popt;
4511 initPQExpBuffer(&buf);
4513 printfPQExpBuffer(&buf,
4515 " ( SELECT t.alias FROM\n"
4516 " pg_catalog.ts_token_type(c.cfgparser) AS t\n"
4517 " WHERE t.tokid = m.maptokentype ) AS \"%s\",\n"
4518 " pg_catalog.btrim(\n"
4519 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary\n"
4520 " FROM pg_catalog.pg_ts_config_map AS mm\n"
4521 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype\n"
4522 " ORDER BY mapcfg, maptokentype, mapseqno\n"
4523 " ) :: pg_catalog.text,\n"
4524 " '{}') AS \"%s\"\n"
4525 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m\n"
4526 "WHERE c.oid = '%s' AND m.mapcfg = c.oid\n"
4527 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser\n"
4529 gettext_noop("Token"),
4530 gettext_noop("Dictionaries"),
4533 res = PSQLexec(buf.data);
4534 termPQExpBuffer(&buf);
4538 initPQExpBuffer(&title);
4541 appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
4544 appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
4548 appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
4551 appendPQExpBuffer(&title, _("\nParser: \"%s\""),
4554 myopt.nullPrint = NULL;
4555 myopt.title = title.data;
4556 myopt.footers = NULL;
4557 myopt.topt.default_footer = false;
4558 myopt.translate_header = true;
4560 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4562 termPQExpBuffer(&title);
4572 * Describes foreign-data wrappers
4575 listForeignDataWrappers(const char *pattern, bool verbose)
4577 PQExpBufferData buf;
4579 printQueryOpt myopt = pset.popt;
4581 if (pset.sversion < 80400)
4585 psql_error("The server (version %s) does not support foreign-data wrappers.\n",
4586 formatPGVersionNumber(pset.sversion, false,
4587 sverbuf, sizeof(sverbuf)));
4591 initPQExpBuffer(&buf);
4592 printfPQExpBuffer(&buf,
4593 "SELECT fdw.fdwname AS \"%s\",\n"
4594 " pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n",
4595 gettext_noop("Name"),
4596 gettext_noop("Owner"));
4597 if (pset.sversion >= 90100)
4598 appendPQExpBuffer(&buf,
4599 " fdw.fdwhandler::pg_catalog.regproc AS \"%s\",\n",
4600 gettext_noop("Handler"));
4601 appendPQExpBuffer(&buf,
4602 " fdw.fdwvalidator::pg_catalog.regproc AS \"%s\"",
4603 gettext_noop("Validator"));
4607 appendPQExpBufferStr(&buf, ",\n ");
4608 printACLColumn(&buf, "fdwacl");
4609 appendPQExpBuffer(&buf,
4610 ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
4611 " '(' || array_to_string(ARRAY(SELECT "
4612 " quote_ident(option_name) || ' ' || "
4613 " quote_literal(option_value) FROM "
4614 " pg_options_to_table(fdwoptions)), ', ') || ')' "
4616 gettext_noop("FDW Options"));
4618 if (pset.sversion >= 90100)
4619 appendPQExpBuffer(&buf,
4620 ",\n d.description AS \"%s\" ",
4621 gettext_noop("Description"));
4624 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
4626 if (verbose && pset.sversion >= 90100)
4627 appendPQExpBufferStr(&buf,
4628 "LEFT JOIN pg_catalog.pg_description d\n"
4629 " ON d.classoid = fdw.tableoid "
4630 "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
4632 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4633 NULL, "fdwname", NULL, NULL);
4635 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4637 res = PSQLexec(buf.data);
4638 termPQExpBuffer(&buf);
4642 myopt.nullPrint = NULL;
4643 myopt.title = _("List of foreign-data wrappers");
4644 myopt.translate_header = true;
4646 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4655 * Describes foreign servers.
4658 listForeignServers(const char *pattern, bool verbose)
4660 PQExpBufferData buf;
4662 printQueryOpt myopt = pset.popt;
4664 if (pset.sversion < 80400)
4668 psql_error("The server (version %s) does not support foreign servers.\n",
4669 formatPGVersionNumber(pset.sversion, false,
4670 sverbuf, sizeof(sverbuf)));
4674 initPQExpBuffer(&buf);
4675 printfPQExpBuffer(&buf,
4676 "SELECT s.srvname AS \"%s\",\n"
4677 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
4678 " f.fdwname AS \"%s\"",
4679 gettext_noop("Name"),
4680 gettext_noop("Owner"),
4681 gettext_noop("Foreign-data wrapper"));
4685 appendPQExpBufferStr(&buf, ",\n ");
4686 printACLColumn(&buf, "s.srvacl");
4687 appendPQExpBuffer(&buf,
4689 " s.srvtype AS \"%s\",\n"
4690 " s.srvversion AS \"%s\",\n"
4691 " CASE WHEN srvoptions IS NULL THEN '' ELSE "
4692 " '(' || array_to_string(ARRAY(SELECT "
4693 " quote_ident(option_name) || ' ' || "
4694 " quote_literal(option_value) FROM "
4695 " pg_options_to_table(srvoptions)), ', ') || ')' "
4697 " d.description AS \"%s\"",
4698 gettext_noop("Type"),
4699 gettext_noop("Version"),
4700 gettext_noop("FDW Options"),
4701 gettext_noop("Description"));
4704 appendPQExpBufferStr(&buf,
4705 "\nFROM pg_catalog.pg_foreign_server s\n"
4706 " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
4709 appendPQExpBufferStr(&buf,
4710 "LEFT JOIN pg_description d\n "
4711 "ON d.classoid = s.tableoid AND d.objoid = s.oid "
4712 "AND d.objsubid = 0\n");
4714 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4715 NULL, "s.srvname", NULL, NULL);
4717 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4719 res = PSQLexec(buf.data);
4720 termPQExpBuffer(&buf);
4724 myopt.nullPrint = NULL;
4725 myopt.title = _("List of foreign servers");
4726 myopt.translate_header = true;
4728 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4737 * Describes user mappings.
4740 listUserMappings(const char *pattern, bool verbose)
4742 PQExpBufferData buf;
4744 printQueryOpt myopt = pset.popt;
4746 if (pset.sversion < 80400)
4750 psql_error("The server (version %s) does not support user mappings.\n",
4751 formatPGVersionNumber(pset.sversion, false,
4752 sverbuf, sizeof(sverbuf)));
4756 initPQExpBuffer(&buf);
4757 printfPQExpBuffer(&buf,
4758 "SELECT um.srvname AS \"%s\",\n"
4759 " um.usename AS \"%s\"",
4760 gettext_noop("Server"),
4761 gettext_noop("User name"));
4764 appendPQExpBuffer(&buf,
4765 ",\n CASE WHEN umoptions IS NULL THEN '' ELSE "
4766 " '(' || array_to_string(ARRAY(SELECT "
4767 " quote_ident(option_name) || ' ' || "
4768 " quote_literal(option_value) FROM "
4769 " pg_options_to_table(umoptions)), ', ') || ')' "
4771 gettext_noop("FDW Options"));
4773 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
4775 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4776 NULL, "um.srvname", "um.usename", NULL);
4778 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4780 res = PSQLexec(buf.data);
4781 termPQExpBuffer(&buf);
4785 myopt.nullPrint = NULL;
4786 myopt.title = _("List of user mappings");
4787 myopt.translate_header = true;
4789 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4798 * Describes foreign tables.
4801 listForeignTables(const char *pattern, bool verbose)
4803 PQExpBufferData buf;
4805 printQueryOpt myopt = pset.popt;
4807 if (pset.sversion < 90100)
4811 psql_error("The server (version %s) does not support foreign tables.\n",
4812 formatPGVersionNumber(pset.sversion, false,
4813 sverbuf, sizeof(sverbuf)));
4817 initPQExpBuffer(&buf);
4818 printfPQExpBuffer(&buf,
4819 "SELECT n.nspname AS \"%s\",\n"
4820 " c.relname AS \"%s\",\n"
4821 " s.srvname AS \"%s\"",
4822 gettext_noop("Schema"),
4823 gettext_noop("Table"),
4824 gettext_noop("Server"));
4827 appendPQExpBuffer(&buf,
4828 ",\n CASE WHEN ftoptions IS NULL THEN '' ELSE "
4829 " '(' || array_to_string(ARRAY(SELECT "
4830 " quote_ident(option_name) || ' ' || "
4831 " quote_literal(option_value) FROM "
4832 " pg_options_to_table(ftoptions)), ', ') || ')' "
4834 " d.description AS \"%s\"",
4835 gettext_noop("FDW Options"),
4836 gettext_noop("Description"));
4838 appendPQExpBufferStr(&buf,
4839 "\nFROM pg_catalog.pg_foreign_table ft\n"
4840 " INNER JOIN pg_catalog.pg_class c"
4841 " ON c.oid = ft.ftrelid\n"
4842 " INNER JOIN pg_catalog.pg_namespace n"
4843 " ON n.oid = c.relnamespace\n"
4844 " INNER JOIN pg_catalog.pg_foreign_server s"
4845 " ON s.oid = ft.ftserver\n");
4847 appendPQExpBufferStr(&buf,
4848 " LEFT JOIN pg_catalog.pg_description d\n"
4849 " ON d.classoid = c.tableoid AND "
4850 "d.objoid = c.oid AND d.objsubid = 0\n");
4852 processSQLNamePattern(pset.db, &buf, pattern, false, false,
4853 "n.nspname", "c.relname", NULL,
4854 "pg_catalog.pg_table_is_visible(c.oid)");
4856 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4858 res = PSQLexec(buf.data);
4859 termPQExpBuffer(&buf);
4863 myopt.nullPrint = NULL;
4864 myopt.title = _("List of foreign tables");
4865 myopt.translate_header = true;
4867 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4876 * Briefly describes installed extensions.
4879 listExtensions(const char *pattern)
4881 PQExpBufferData buf;
4883 printQueryOpt myopt = pset.popt;
4885 if (pset.sversion < 90100)
4889 psql_error("The server (version %s) does not support extensions.\n",
4890 formatPGVersionNumber(pset.sversion, false,
4891 sverbuf, sizeof(sverbuf)));
4895 initPQExpBuffer(&buf);
4896 printfPQExpBuffer(&buf,
4897 "SELECT e.extname AS \"%s\", "
4898 "e.extversion AS \"%s\", n.nspname AS \"%s\", c.description AS \"%s\"\n"
4899 "FROM pg_catalog.pg_extension e "
4900 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
4901 "LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
4902 "AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass\n",
4903 gettext_noop("Name"),
4904 gettext_noop("Version"),
4905 gettext_noop("Schema"),
4906 gettext_noop("Description"));
4908 processSQLNamePattern(pset.db, &buf, pattern,
4910 NULL, "e.extname", NULL,
4913 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4915 res = PSQLexec(buf.data);
4916 termPQExpBuffer(&buf);
4920 myopt.nullPrint = NULL;
4921 myopt.title = _("List of installed extensions");
4922 myopt.translate_header = true;
4924 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4933 * List contents of installed extensions.
4936 listExtensionContents(const char *pattern)
4938 PQExpBufferData buf;
4942 if (pset.sversion < 90100)
4946 psql_error("The server (version %s) does not support extensions.\n",
4947 formatPGVersionNumber(pset.sversion, false,
4948 sverbuf, sizeof(sverbuf)));
4952 initPQExpBuffer(&buf);
4953 printfPQExpBuffer(&buf,
4954 "SELECT e.extname, e.oid\n"
4955 "FROM pg_catalog.pg_extension e\n");
4957 processSQLNamePattern(pset.db, &buf, pattern,
4959 NULL, "e.extname", NULL,
4962 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4964 res = PSQLexec(buf.data);
4965 termPQExpBuffer(&buf);
4969 if (PQntuples(res) == 0)
4974 psql_error("Did not find any extension named \"%s\".\n",
4977 psql_error("Did not find any extensions.\n");
4983 for (i = 0; i < PQntuples(res); i++)
4985 const char *extname;
4988 extname = PQgetvalue(res, i, 0);
4989 oid = PQgetvalue(res, i, 1);
4991 if (!listOneExtensionContents(extname, oid))
5008 listOneExtensionContents(const char *extname, const char *oid)
5010 PQExpBufferData buf;
5013 printQueryOpt myopt = pset.popt;
5015 initPQExpBuffer(&buf);
5016 printfPQExpBuffer(&buf,
5017 "SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS \"%s\"\n"
5018 "FROM pg_catalog.pg_depend\n"
5019 "WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '%s' AND deptype = 'e'\n"
5021 gettext_noop("Object Description"),
5024 res = PSQLexec(buf.data);
5025 termPQExpBuffer(&buf);
5029 myopt.nullPrint = NULL;
5030 snprintf(title, sizeof(title), _("Objects in extension \"%s\""), extname);
5031 myopt.title = title;
5032 myopt.translate_header = true;
5034 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5041 * Lists publications.
5043 * Takes an optional regexp to select particular publications
5046 listPublications(const char *pattern)
5048 PQExpBufferData buf;
5050 printQueryOpt myopt = pset.popt;
5051 static const bool translate_columns[] = {false, false, false, false, false};
5053 if (pset.sversion < 100000)
5056 psql_error("The server (version %s) does not support publications.\n",
5057 formatPGVersionNumber(pset.sversion, false,
5058 sverbuf, sizeof(sverbuf)));
5062 initPQExpBuffer(&buf);
5064 printfPQExpBuffer(&buf,
5065 "SELECT pubname AS \"%s\",\n"
5066 " pg_catalog.pg_get_userbyid(pubowner) AS \"%s\",\n"
5067 " pubinsert AS \"%s\",\n"
5068 " pubupdate AS \"%s\",\n"
5069 " pubdelete AS \"%s\"\n",
5070 gettext_noop("Name"),
5071 gettext_noop("Owner"),
5072 gettext_noop("Inserts"),
5073 gettext_noop("Updates"),
5074 gettext_noop("Deletes"));
5076 appendPQExpBufferStr(&buf,
5077 "\nFROM pg_catalog.pg_publication\n");
5079 processSQLNamePattern(pset.db, &buf, pattern, false, false,
5080 NULL, "pubname", NULL,
5083 appendPQExpBufferStr(&buf, "ORDER BY 1;");
5085 res = PSQLexec(buf.data);
5086 termPQExpBuffer(&buf);
5090 myopt.nullPrint = NULL;
5091 myopt.title = _("List of publications");
5092 myopt.translate_header = true;
5093 myopt.translate_columns = translate_columns;
5094 myopt.n_translate_columns = lengthof(translate_columns);
5096 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5104 * Describes publications including the contents.
5106 * Takes an optional regexp to select particular publications
5109 describePublications(const char *pattern)
5111 PQExpBufferData buf;
5115 if (pset.sversion < 100000)
5118 psql_error("The server (version %s) does not support publications.\n",
5119 formatPGVersionNumber(pset.sversion, false,
5120 sverbuf, sizeof(sverbuf)));
5124 initPQExpBuffer(&buf);
5126 printfPQExpBuffer(&buf,
5127 "SELECT oid, pubname, puballtables, pubinsert,\n"
5128 " pubupdate, pubdelete\n"
5129 "FROM pg_catalog.pg_publication\n");
5131 processSQLNamePattern(pset.db, &buf, pattern, false, false,
5132 NULL, "pubname", NULL,
5135 appendPQExpBufferStr(&buf, "ORDER BY 2;");
5137 res = PSQLexec(buf.data);
5140 termPQExpBuffer(&buf);
5144 for (i = 0; i < PQntuples(res); i++)
5146 const char align = 'l';
5151 char *pubid = PQgetvalue(res, i, 0);
5152 char *pubname = PQgetvalue(res, i, 1);
5153 bool puballtables = strcmp(PQgetvalue(res, i, 2), "t") == 0;
5155 PQExpBufferData title;
5156 printTableOpt myopt = pset.popt.topt;
5157 printTableContent cont;
5159 initPQExpBuffer(&title);
5160 printfPQExpBuffer(&title, _("Publication %s"), pubname);
5161 printTableInit(&cont, &myopt, title.data, ncols, nrows);
5163 printTableAddHeader(&cont, gettext_noop("Inserts"), true, align);
5164 printTableAddHeader(&cont, gettext_noop("Updates"), true, align);
5165 printTableAddHeader(&cont, gettext_noop("Deletes"), true, align);
5167 printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false);
5168 printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false);
5169 printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
5172 printfPQExpBuffer(&buf,
5173 "SELECT n.nspname, c.relname\n"
5174 "FROM pg_catalog.pg_class c,\n"
5175 " pg_catalog.pg_namespace n\n"
5176 "WHERE c.relnamespace = n.oid\n"
5177 " AND c.relkind = " CppAsString2(RELKIND_RELATION) "\n"
5178 " AND n.nspname <> 'pg_catalog'\n"
5179 " AND n.nspname <> 'information_schema'\n"
5182 printfPQExpBuffer(&buf,
5183 "SELECT n.nspname, c.relname\n"
5184 "FROM pg_catalog.pg_class c,\n"
5185 " pg_catalog.pg_namespace n,\n"
5186 " pg_catalog.pg_publication_rel pr\n"
5187 "WHERE c.relnamespace = n.oid\n"
5188 " AND c.oid = pr.prrelid\n"
5189 " AND pr.prpubid = '%s'\n"
5190 "ORDER BY 1,2", pubid);
5192 tabres = PSQLexec(buf.data);
5195 printTableCleanup(&cont);
5197 termPQExpBuffer(&buf);
5198 termPQExpBuffer(&title);
5202 tables = PQntuples(tabres);
5205 printTableAddFooter(&cont, _("Tables:"));
5207 for (j = 0; j < tables; j++)
5209 printfPQExpBuffer(&buf, " \"%s.%s\"",
5210 PQgetvalue(tabres, j, 0),
5211 PQgetvalue(tabres, j, 1));
5213 printTableAddFooter(&cont, buf.data);
5217 printTable(&cont, pset.queryFout, false, pset.logfile);
5218 printTableCleanup(&cont);
5220 termPQExpBuffer(&title);
5223 termPQExpBuffer(&buf);
5230 * Describes subscriptions.
5232 * Takes an optional regexp to select particular subscriptions
5235 describeSubscriptions(const char *pattern, bool verbose)
5237 PQExpBufferData buf;
5239 printQueryOpt myopt = pset.popt;
5240 static const bool translate_columns[] = {false, false, false, false,
5243 if (pset.sversion < 100000)
5246 psql_error("The server (version %s) does not support subscriptions.\n",
5247 formatPGVersionNumber(pset.sversion, false,
5248 sverbuf, sizeof(sverbuf)));
5252 initPQExpBuffer(&buf);
5254 printfPQExpBuffer(&buf,
5255 "SELECT subname AS \"%s\"\n"
5256 ", pg_catalog.pg_get_userbyid(subowner) AS \"%s\"\n"
5257 ", subenabled AS \"%s\"\n"
5258 ", subpublications AS \"%s\"\n",
5259 gettext_noop("Name"),
5260 gettext_noop("Owner"),
5261 gettext_noop("Enabled"),
5262 gettext_noop("Publication"));
5266 appendPQExpBuffer(&buf,
5267 ", subsynccommit AS \"%s\"\n"
5268 ", subconninfo AS \"%s\"\n",
5269 gettext_noop("Synchronous commit"),
5270 gettext_noop("Conninfo"));
5273 /* Only display subscriptions in current database. */
5274 appendPQExpBufferStr(&buf,
5275 "FROM pg_catalog.pg_subscription\n"
5276 "WHERE subdbid = (SELECT oid\n"
5277 " FROM pg_catalog.pg_database\n"
5278 " WHERE datname = current_database())");
5280 processSQLNamePattern(pset.db, &buf, pattern, true, false,
5281 NULL, "subname", NULL,
5284 appendPQExpBufferStr(&buf, "ORDER BY 1;");
5286 res = PSQLexec(buf.data);
5287 termPQExpBuffer(&buf);
5291 myopt.nullPrint = NULL;
5292 myopt.title = _("List of subscriptions");
5293 myopt.translate_header = true;
5294 myopt.translate_columns = translate_columns;
5295 myopt.n_translate_columns = lengthof(translate_columns);
5297 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5306 * Helper function for consistently formatting ACL (privilege) columns.
5307 * The proper targetlist entry is appended to buf. Note lack of any
5308 * whitespace or comma decoration.
5311 printACLColumn(PQExpBuffer buf, const char *colname)
5313 if (pset.sversion >= 80100)
5314 appendPQExpBuffer(buf,
5315 "pg_catalog.array_to_string(%s, E'\\n') AS \"%s\"",
5316 colname, gettext_noop("Access privileges"));
5318 appendPQExpBuffer(buf,
5319 "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"",
5320 colname, gettext_noop("Access privileges"));