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-2011, PostgreSQL Global Development Group
11 * src/bin/psql/describe.c
13 #include "postgres_fe.h"
19 #include "dumputils.h"
23 #include "variables.h"
26 static bool describeOneTableDetails(const char *schemaname,
27 const char *relationname,
30 static void add_tablespace_footer(printTableContent *const cont, char relkind,
31 Oid tablespace, const bool newline);
32 static void add_role_attribute(PQExpBuffer buf, const char *const str);
33 static bool listTSParsersVerbose(const char *pattern);
34 static bool describeOneTSParser(const char *oid, const char *nspname,
36 static bool listTSConfigsVerbose(const char *pattern);
37 static bool describeOneTSConfig(const char *oid, const char *nspname,
39 const char *pnspname, const char *prsname);
40 static void printACLColumn(PQExpBuffer buf, const char *colname);
44 * Handlers for various slash commands displaying some sort of list
45 * of things in the database.
47 * Note: try to format the queries to look nice in -E output.
53 * Takes an optional regexp to select particular aggregates
56 describeAggregates(const char *pattern, bool verbose, bool showSystem)
60 printQueryOpt myopt = pset.popt;
62 initPQExpBuffer(&buf);
64 printfPQExpBuffer(&buf,
65 "SELECT n.nspname as \"%s\",\n"
66 " p.proname AS \"%s\",\n"
67 " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n",
68 gettext_noop("Schema"),
70 gettext_noop("Result data type"));
72 if (pset.sversion >= 80200)
73 appendPQExpBuffer(&buf,
74 " CASE WHEN p.pronargs = 0\n"
75 " THEN CAST('*' AS pg_catalog.text)\n"
77 " pg_catalog.array_to_string(ARRAY(\n"
79 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
81 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
84 gettext_noop("Argument data types"));
86 appendPQExpBuffer(&buf,
87 " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
88 gettext_noop("Argument data types"));
90 appendPQExpBuffer(&buf,
91 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
92 "FROM pg_catalog.pg_proc p\n"
93 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
95 gettext_noop("Description"));
97 if (!showSystem && !pattern)
98 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
99 " AND n.nspname <> 'information_schema'\n");
101 processSQLNamePattern(pset.db, &buf, pattern, true, false,
102 "n.nspname", "p.proname", NULL,
103 "pg_catalog.pg_function_is_visible(p.oid)");
105 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 4;");
107 res = PSQLexec(buf.data, false);
108 termPQExpBuffer(&buf);
112 myopt.nullPrint = NULL;
113 myopt.title = _("List of aggregate functions");
114 myopt.translate_header = true;
116 printQuery(res, &myopt, pset.queryFout, pset.logfile);
123 * Takes an optional regexp to select particular tablespaces
126 describeTablespaces(const char *pattern, bool verbose)
130 printQueryOpt myopt = pset.popt;
132 if (pset.sversion < 80000)
134 fprintf(stderr, _("The server (version %d.%d) does not support tablespaces.\n"),
135 pset.sversion / 10000, (pset.sversion / 100) % 100);
139 initPQExpBuffer(&buf);
141 printfPQExpBuffer(&buf,
142 "SELECT spcname AS \"%s\",\n"
143 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
144 " spclocation AS \"%s\"",
145 gettext_noop("Name"),
146 gettext_noop("Owner"),
147 gettext_noop("Location"));
151 appendPQExpBuffer(&buf, ",\n ");
152 printACLColumn(&buf, "spcacl");
155 if (verbose && pset.sversion >= 80200)
156 appendPQExpBuffer(&buf,
157 ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
158 gettext_noop("Description"));
160 appendPQExpBuffer(&buf,
161 "\nFROM pg_catalog.pg_tablespace\n");
163 processSQLNamePattern(pset.db, &buf, pattern, false, false,
164 NULL, "spcname", NULL,
167 appendPQExpBuffer(&buf, "ORDER BY 1;");
169 res = PSQLexec(buf.data, false);
170 termPQExpBuffer(&buf);
174 myopt.nullPrint = NULL;
175 myopt.title = _("List of tablespaces");
176 myopt.translate_header = true;
178 printQuery(res, &myopt, pset.queryFout, pset.logfile);
186 * Takes an optional regexp to select particular functions.
188 * As with \d, you can specify the kinds of functions you want:
195 * and you can mix and match these in any order.
198 describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem)
200 bool showAggregate = strchr(functypes, 'a') != NULL;
201 bool showNormal = strchr(functypes, 'n') != NULL;
202 bool showTrigger = strchr(functypes, 't') != NULL;
203 bool showWindow = strchr(functypes, 'w') != NULL;
207 printQueryOpt myopt = pset.popt;
208 static const bool translate_columns[] = {false, false, false, false, true, true, false, false, false, false};
210 if (strlen(functypes) != strspn(functypes, "antwS+"))
212 fprintf(stderr, _("\\df only takes [antwS+] as options\n"));
216 if (showWindow && pset.sversion < 80400)
218 fprintf(stderr, _("\\df does not take a \"w\" option with server version %d.%d\n"),
219 pset.sversion / 10000, (pset.sversion / 100) % 100);
223 if (!showAggregate && !showNormal && !showTrigger && !showWindow)
225 showAggregate = showNormal = showTrigger = true;
226 if (pset.sversion >= 80400)
230 initPQExpBuffer(&buf);
232 printfPQExpBuffer(&buf,
233 "SELECT n.nspname as \"%s\",\n"
234 " p.proname as \"%s\",\n",
235 gettext_noop("Schema"),
236 gettext_noop("Name"));
238 if (pset.sversion >= 80400)
239 appendPQExpBuffer(&buf,
240 " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
241 " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
243 " WHEN p.proisagg THEN '%s'\n"
244 " WHEN p.proiswindow THEN '%s'\n"
245 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
248 gettext_noop("Result data type"),
249 gettext_noop("Argument data types"),
250 /* translator: "agg" is short for "aggregate" */
252 gettext_noop("window"),
253 gettext_noop("trigger"),
254 gettext_noop("normal"),
255 gettext_noop("Type"));
256 else if (pset.sversion >= 80100)
257 appendPQExpBuffer(&buf,
258 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
259 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
260 " CASE WHEN proallargtypes IS NOT NULL THEN\n"
261 " pg_catalog.array_to_string(ARRAY(\n"
264 " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
265 " WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
266 " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
267 " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
270 " WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
271 " ELSE p.proargnames[s.i] || ' ' \n"
273 " pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
275 " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
278 " pg_catalog.array_to_string(ARRAY(\n"
281 " WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
282 " ELSE p.proargnames[s.i+1] || ' '\n"
284 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
286 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
290 " WHEN p.proisagg THEN '%s'\n"
291 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
294 gettext_noop("Result data type"),
295 gettext_noop("Argument data types"),
296 /* translator: "agg" is short for "aggregate" */
298 gettext_noop("trigger"),
299 gettext_noop("normal"),
300 gettext_noop("Type"));
302 appendPQExpBuffer(&buf,
303 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
304 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
305 " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\",\n"
307 " WHEN p.proisagg THEN '%s'\n"
308 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
311 gettext_noop("Result data type"),
312 gettext_noop("Argument data types"),
313 /* translator: "agg" is short for "aggregate" */
315 gettext_noop("trigger"),
316 gettext_noop("normal"),
317 gettext_noop("Type"));
320 appendPQExpBuffer(&buf,
322 " WHEN p.provolatile = 'i' THEN '%s'\n"
323 " WHEN p.provolatile = 's' THEN '%s'\n"
324 " WHEN p.provolatile = 'v' THEN '%s'\n"
326 ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\",\n"
327 " l.lanname as \"%s\",\n"
328 " p.prosrc as \"%s\",\n"
329 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
330 gettext_noop("immutable"),
331 gettext_noop("stable"),
332 gettext_noop("volatile"),
333 gettext_noop("Volatility"),
334 gettext_noop("Owner"),
335 gettext_noop("Language"),
336 gettext_noop("Source code"),
337 gettext_noop("Description"));
339 appendPQExpBuffer(&buf,
340 "\nFROM pg_catalog.pg_proc p"
341 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
344 appendPQExpBuffer(&buf,
345 " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
349 /* filter by function type, if requested */
350 if (showNormal && showAggregate && showTrigger && showWindow)
357 appendPQExpBuffer(&buf, " AND ");
360 appendPQExpBuffer(&buf, "WHERE ");
363 appendPQExpBuffer(&buf, "NOT p.proisagg\n");
368 appendPQExpBuffer(&buf, " AND ");
371 appendPQExpBuffer(&buf, "WHERE ");
374 appendPQExpBuffer(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
376 if (!showWindow && pset.sversion >= 80400)
379 appendPQExpBuffer(&buf, " AND ");
382 appendPQExpBuffer(&buf, "WHERE ");
385 appendPQExpBuffer(&buf, "NOT p.proiswindow\n");
390 bool needs_or = false;
392 appendPQExpBuffer(&buf, "WHERE (\n ");
394 /* Note: at least one of these must be true ... */
397 appendPQExpBuffer(&buf, "p.proisagg\n");
403 appendPQExpBuffer(&buf, " OR ");
404 appendPQExpBuffer(&buf,
405 "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n");
411 appendPQExpBuffer(&buf, " OR ");
412 appendPQExpBuffer(&buf, "p.proiswindow\n");
415 appendPQExpBuffer(&buf, " )\n");
418 processSQLNamePattern(pset.db, &buf, pattern, have_where, false,
419 "n.nspname", "p.proname", NULL,
420 "pg_catalog.pg_function_is_visible(p.oid)");
422 if (!showSystem && !pattern)
423 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
424 " AND n.nspname <> 'information_schema'\n");
426 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 4;");
428 res = PSQLexec(buf.data, false);
429 termPQExpBuffer(&buf);
433 myopt.nullPrint = NULL;
434 myopt.title = _("List of functions");
435 myopt.translate_header = true;
436 myopt.translate_columns = translate_columns;
438 printQuery(res, &myopt, pset.queryFout, pset.logfile);
451 describeTypes(const char *pattern, bool verbose, bool showSystem)
455 printQueryOpt myopt = pset.popt;
457 initPQExpBuffer(&buf);
459 printfPQExpBuffer(&buf,
460 "SELECT n.nspname as \"%s\",\n"
461 " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
462 gettext_noop("Schema"),
463 gettext_noop("Name"));
465 appendPQExpBuffer(&buf,
466 " t.typname AS \"%s\",\n"
467 " CASE WHEN t.typrelid != 0\n"
468 " THEN CAST('tuple' AS pg_catalog.text)\n"
469 " WHEN t.typlen < 0\n"
470 " THEN CAST('var' AS pg_catalog.text)\n"
471 " ELSE CAST(t.typlen AS pg_catalog.text)\n"
473 gettext_noop("Internal name"),
474 gettext_noop("Size"));
475 if (verbose && pset.sversion >= 80300)
477 appendPQExpBuffer(&buf,
478 " pg_catalog.array_to_string(\n"
480 " SELECT e.enumlabel\n"
481 " FROM pg_catalog.pg_enum e\n"
482 " WHERE e.enumtypid = t.oid\n");
484 if (pset.sversion >= 90100)
485 appendPQExpBuffer(&buf,
486 " ORDER BY e.enumsortorder\n");
488 appendPQExpBuffer(&buf,
489 " ORDER BY e.oid\n");
491 appendPQExpBuffer(&buf,
495 gettext_noop("Elements"));
498 appendPQExpBuffer(&buf,
499 " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
500 gettext_noop("Description"));
502 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n"
503 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
506 * do not include complex types (typrelid!=0) unless they are standalone
509 appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 ");
510 appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
511 "WHERE c.oid = t.typrelid))\n");
514 * do not include array types (before 8.3 we have to use the assumption
515 * that their names start with underscore)
517 if (pset.sversion >= 80300)
518 appendPQExpBuffer(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
520 appendPQExpBuffer(&buf, " AND t.typname !~ '^_'\n");
522 if (!showSystem && !pattern)
523 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
524 " AND n.nspname <> 'information_schema'\n");
526 /* Match name pattern against either internal or external name */
527 processSQLNamePattern(pset.db, &buf, pattern, true, false,
528 "n.nspname", "t.typname",
529 "pg_catalog.format_type(t.oid, NULL)",
530 "pg_catalog.pg_type_is_visible(t.oid)");
532 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
534 res = PSQLexec(buf.data, false);
535 termPQExpBuffer(&buf);
539 myopt.nullPrint = NULL;
540 myopt.title = _("List of data types");
541 myopt.translate_header = true;
543 printQuery(res, &myopt, pset.queryFout, pset.logfile);
553 describeOperators(const char *pattern, bool showSystem)
557 printQueryOpt myopt = pset.popt;
559 initPQExpBuffer(&buf);
561 printfPQExpBuffer(&buf,
562 "SELECT n.nspname as \"%s\",\n"
563 " o.oprname AS \"%s\",\n"
564 " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
565 " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
566 " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n"
567 " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
568 " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
569 "FROM pg_catalog.pg_operator o\n"
570 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
571 gettext_noop("Schema"),
572 gettext_noop("Name"),
573 gettext_noop("Left arg type"),
574 gettext_noop("Right arg type"),
575 gettext_noop("Result type"),
576 gettext_noop("Description"));
578 if (!showSystem && !pattern)
579 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
580 " AND n.nspname <> 'information_schema'\n");
582 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, true,
583 "n.nspname", "o.oprname", NULL,
584 "pg_catalog.pg_operator_is_visible(o.oid)");
586 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;");
588 res = PSQLexec(buf.data, false);
589 termPQExpBuffer(&buf);
593 myopt.nullPrint = NULL;
594 myopt.title = _("List of operators");
595 myopt.translate_header = true;
597 printQuery(res, &myopt, pset.queryFout, pset.logfile);
607 * for \l, \list, and -l switch
610 listAllDbs(bool verbose)
614 printQueryOpt myopt = pset.popt;
616 initPQExpBuffer(&buf);
618 printfPQExpBuffer(&buf,
619 "SELECT d.datname as \"%s\",\n"
620 " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
621 " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
622 gettext_noop("Name"),
623 gettext_noop("Owner"),
624 gettext_noop("Encoding"));
625 if (pset.sversion >= 80400)
626 appendPQExpBuffer(&buf,
627 " d.datcollate as \"%s\",\n"
628 " d.datctype as \"%s\",\n",
629 gettext_noop("Collation"),
630 gettext_noop("Ctype"));
631 appendPQExpBuffer(&buf, " ");
632 printACLColumn(&buf, "d.datacl");
633 if (verbose && pset.sversion >= 80200)
634 appendPQExpBuffer(&buf,
635 ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
636 " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
637 " ELSE 'No Access'\n"
639 gettext_noop("Size"));
640 if (verbose && pset.sversion >= 80000)
641 appendPQExpBuffer(&buf,
642 ",\n t.spcname as \"%s\"",
643 gettext_noop("Tablespace"));
644 if (verbose && pset.sversion >= 80200)
645 appendPQExpBuffer(&buf,
646 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
647 gettext_noop("Description"));
648 appendPQExpBuffer(&buf,
649 "\nFROM pg_catalog.pg_database d\n");
650 if (verbose && pset.sversion >= 80000)
651 appendPQExpBuffer(&buf,
652 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
653 appendPQExpBuffer(&buf, "ORDER BY 1;");
654 res = PSQLexec(buf.data, false);
655 termPQExpBuffer(&buf);
659 myopt.nullPrint = NULL;
660 myopt.title = _("List of databases");
661 myopt.translate_header = true;
663 printQuery(res, &myopt, pset.queryFout, pset.logfile);
671 * List Tables' Grant/Revoke Permissions
672 * \z (now also \dp -- perhaps more mnemonic)
675 permissionsList(const char *pattern)
679 printQueryOpt myopt = pset.popt;
680 static const bool translate_columns[] = {false, false, true, false, false};
682 initPQExpBuffer(&buf);
685 * we ignore indexes and toast tables since they have no meaningful rights
687 printfPQExpBuffer(&buf,
688 "SELECT n.nspname as \"%s\",\n"
689 " c.relname as \"%s\",\n"
690 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END as \"%s\",\n"
692 gettext_noop("Schema"),
693 gettext_noop("Name"),
694 gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
695 gettext_noop("foreign table"),
696 gettext_noop("Type"));
698 printACLColumn(&buf, "c.relacl");
700 if (pset.sversion >= 80400)
701 appendPQExpBuffer(&buf,
702 ",\n pg_catalog.array_to_string(ARRAY(\n"
703 " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
704 " FROM pg_catalog.pg_attribute a\n"
705 " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
706 " ), E'\\n') AS \"%s\"",
707 gettext_noop("Column access privileges"));
709 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_class c\n"
710 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
711 "WHERE c.relkind IN ('r', 'v', 'S', 'f')\n");
714 * Unless a schema pattern is specified, we suppress system and temp
715 * tables, since they normally aren't very interesting from a permissions
716 * point of view. You can see 'em by explicit request though, eg with \z
719 processSQLNamePattern(pset.db, &buf, pattern, true, false,
720 "n.nspname", "c.relname", NULL,
721 "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
723 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
725 res = PSQLexec(buf.data, false);
728 termPQExpBuffer(&buf);
732 myopt.nullPrint = NULL;
733 printfPQExpBuffer(&buf, _("Access privileges"));
734 myopt.title = buf.data;
735 myopt.translate_header = true;
736 myopt.translate_columns = translate_columns;
738 printQuery(res, &myopt, pset.queryFout, pset.logfile);
740 termPQExpBuffer(&buf);
749 * List DefaultACLs. The pattern can match either schema or role name.
752 listDefaultACLs(const char *pattern)
756 printQueryOpt myopt = pset.popt;
757 static const bool translate_columns[] = {false, false, true, false};
759 if (pset.sversion < 90000)
761 fprintf(stderr, _("The server (version %d.%d) does not support altering default privileges.\n"),
762 pset.sversion / 10000, (pset.sversion / 100) % 100);
766 initPQExpBuffer(&buf);
768 printfPQExpBuffer(&buf,
769 "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
770 " n.nspname AS \"%s\",\n"
771 " CASE d.defaclobjtype WHEN 'r' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END AS \"%s\",\n"
773 gettext_noop("Owner"),
774 gettext_noop("Schema"),
775 gettext_noop("table"),
776 gettext_noop("sequence"),
777 gettext_noop("function"),
778 gettext_noop("Type"));
780 printACLColumn(&buf, "d.defaclacl");
782 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
783 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
785 processSQLNamePattern(pset.db, &buf, pattern, false, false,
788 "pg_catalog.pg_get_userbyid(d.defaclrole)",
791 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
793 res = PSQLexec(buf.data, false);
796 termPQExpBuffer(&buf);
800 myopt.nullPrint = NULL;
801 printfPQExpBuffer(&buf, _("Default access privileges"));
802 myopt.title = buf.data;
803 myopt.translate_header = true;
804 myopt.translate_columns = translate_columns;
806 printQuery(res, &myopt, pset.queryFout, pset.logfile);
808 termPQExpBuffer(&buf);
815 * Get object comments
819 * Note: This only lists things that actually have a description. For complete
820 * lists of things, there are other \d? commands.
823 objectDescription(const char *pattern, bool showSystem)
827 printQueryOpt myopt = pset.popt;
828 static const bool translate_columns[] = {false, false, true, false};
830 initPQExpBuffer(&buf);
832 appendPQExpBuffer(&buf,
833 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
835 gettext_noop("Schema"),
836 gettext_noop("Name"),
837 gettext_noop("Object"),
838 gettext_noop("Description"));
840 /* Aggregate descriptions */
841 appendPQExpBuffer(&buf,
842 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
843 " n.nspname as nspname,\n"
844 " CAST(p.proname AS pg_catalog.text) as name,"
845 " CAST('%s' AS pg_catalog.text) as object\n"
846 " FROM pg_catalog.pg_proc p\n"
847 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
848 " WHERE p.proisagg\n",
849 gettext_noop("aggregate"));
851 if (!showSystem && !pattern)
852 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
853 " AND n.nspname <> 'information_schema'\n");
855 processSQLNamePattern(pset.db, &buf, pattern, true, false,
856 "n.nspname", "p.proname", NULL,
857 "pg_catalog.pg_function_is_visible(p.oid)");
859 /* Function descriptions */
860 appendPQExpBuffer(&buf,
862 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
863 " n.nspname as nspname,\n"
864 " CAST(p.proname AS pg_catalog.text) as name,"
865 " CAST('%s' AS pg_catalog.text) as object\n"
866 " FROM pg_catalog.pg_proc p\n"
867 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
868 " WHERE NOT p.proisagg\n",
869 gettext_noop("function"));
871 if (!showSystem && !pattern)
872 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
873 " AND n.nspname <> 'information_schema'\n");
875 processSQLNamePattern(pset.db, &buf, pattern, true, false,
876 "n.nspname", "p.proname", NULL,
877 "pg_catalog.pg_function_is_visible(p.oid)");
879 /* Operator descriptions (only if operator has its own comment) */
880 appendPQExpBuffer(&buf,
882 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
883 " n.nspname as nspname,\n"
884 " CAST(o.oprname AS pg_catalog.text) as name,"
885 " CAST('%s' AS pg_catalog.text) as object\n"
886 " FROM pg_catalog.pg_operator o\n"
887 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
888 gettext_noop("operator"));
890 if (!showSystem && !pattern)
891 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
892 " AND n.nspname <> 'information_schema'\n");
894 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
895 "n.nspname", "o.oprname", NULL,
896 "pg_catalog.pg_operator_is_visible(o.oid)");
898 /* Type description */
899 appendPQExpBuffer(&buf,
901 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
902 " n.nspname as nspname,\n"
903 " pg_catalog.format_type(t.oid, NULL) as name,"
904 " CAST('%s' AS pg_catalog.text) as object\n"
905 " FROM pg_catalog.pg_type t\n"
906 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
907 gettext_noop("data type"));
909 if (!showSystem && !pattern)
910 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
911 " AND n.nspname <> 'information_schema'\n");
913 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
914 "n.nspname", "pg_catalog.format_type(t.oid, NULL)",
916 "pg_catalog.pg_type_is_visible(t.oid)");
918 /* Relation (tables, views, indexes, sequences) descriptions */
919 appendPQExpBuffer(&buf,
921 " SELECT c.oid as oid, c.tableoid as tableoid,\n"
922 " n.nspname as nspname,\n"
923 " CAST(c.relname AS pg_catalog.text) as name,\n"
925 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END"
926 " AS pg_catalog.text) as object\n"
927 " FROM pg_catalog.pg_class c\n"
928 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
929 " WHERE c.relkind IN ('r', 'v', 'i', 'S', 'f')\n",
930 gettext_noop("table"),
931 gettext_noop("view"),
932 gettext_noop("index"),
933 gettext_noop("sequence"),
934 gettext_noop("foreign table"));
936 if (!showSystem && !pattern)
937 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
938 " AND n.nspname <> 'information_schema'\n");
940 processSQLNamePattern(pset.db, &buf, pattern, true, false,
941 "n.nspname", "c.relname", NULL,
942 "pg_catalog.pg_table_is_visible(c.oid)");
944 /* Rule description (ignore rules for views) */
945 appendPQExpBuffer(&buf,
947 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
948 " n.nspname as nspname,\n"
949 " CAST(r.rulename AS pg_catalog.text) as name,"
950 " CAST('%s' AS pg_catalog.text) as object\n"
951 " FROM pg_catalog.pg_rewrite r\n"
952 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
953 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
954 " WHERE r.rulename != '_RETURN'\n",
955 gettext_noop("rule"));
957 if (!showSystem && !pattern)
958 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
959 " AND n.nspname <> 'information_schema'\n");
961 /* XXX not sure what to do about visibility rule here? */
962 processSQLNamePattern(pset.db, &buf, pattern, true, false,
963 "n.nspname", "r.rulename", NULL,
964 "pg_catalog.pg_table_is_visible(c.oid)");
966 /* Trigger description */
967 appendPQExpBuffer(&buf,
969 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
970 " n.nspname as nspname,\n"
971 " CAST(t.tgname AS pg_catalog.text) as name,"
972 " CAST('%s' AS pg_catalog.text) as object\n"
973 " FROM pg_catalog.pg_trigger t\n"
974 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
975 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
976 gettext_noop("trigger"));
978 if (!showSystem && !pattern)
979 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
980 " AND n.nspname <> 'information_schema'\n");
982 /* XXX not sure what to do about visibility rule here? */
983 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
984 "n.nspname", "t.tgname", NULL,
985 "pg_catalog.pg_table_is_visible(c.oid)");
987 appendPQExpBuffer(&buf,
989 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
991 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
993 res = PSQLexec(buf.data, false);
994 termPQExpBuffer(&buf);
998 myopt.nullPrint = NULL;
999 myopt.title = _("Object descriptions");
1000 myopt.translate_header = true;
1001 myopt.translate_columns = translate_columns;
1003 printQuery(res, &myopt, pset.queryFout, pset.logfile);
1011 * describeTableDetails (for \d)
1013 * This routine finds the tables to be displayed, and calls
1014 * describeOneTableDetails for each one.
1016 * verbose: if true, this is \d+
1019 describeTableDetails(const char *pattern, bool verbose, bool showSystem)
1021 PQExpBufferData buf;
1025 initPQExpBuffer(&buf);
1027 printfPQExpBuffer(&buf,
1031 "FROM pg_catalog.pg_class c\n"
1032 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1034 if (!showSystem && !pattern)
1035 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1036 " AND n.nspname <> 'information_schema'\n");
1038 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
1039 "n.nspname", "c.relname", NULL,
1040 "pg_catalog.pg_table_is_visible(c.oid)");
1042 appendPQExpBuffer(&buf, "ORDER BY 2, 3;");
1044 res = PSQLexec(buf.data, false);
1045 termPQExpBuffer(&buf);
1049 if (PQntuples(res) == 0)
1052 fprintf(stderr, _("Did not find any relation named \"%s\".\n"),
1058 for (i = 0; i < PQntuples(res); i++)
1061 const char *nspname;
1062 const char *relname;
1064 oid = PQgetvalue(res, i, 0);
1065 nspname = PQgetvalue(res, i, 1);
1066 relname = PQgetvalue(res, i, 2);
1068 if (!describeOneTableDetails(nspname, relname, oid, verbose))
1085 * describeOneTableDetails (for \d)
1087 * Unfortunately, the information presented here is so complicated that it
1088 * cannot be done in a single query. So we have to assemble the printed table
1089 * by hand and pass it to the underlying printTable() function.
1092 describeOneTableDetails(const char *schemaname,
1093 const char *relationname,
1097 PQExpBufferData buf;
1098 PGresult *res = NULL;
1099 printTableOpt myopt = pset.popt.topt;
1100 printTableContent cont;
1101 bool printTableInitialized = false;
1103 char *view_def = NULL;
1105 char **seq_values = NULL;
1106 char **modifiers = NULL;
1108 PQExpBufferData title;
1109 PQExpBufferData tmpbuf;
1123 char relpersistence;
1125 bool show_modifiers = false;
1130 /* This output looks confusing in expanded mode. */
1131 myopt.expanded = false;
1133 initPQExpBuffer(&buf);
1134 initPQExpBuffer(&title);
1135 initPQExpBuffer(&tmpbuf);
1137 /* Get general table info */
1138 if (pset.sversion >= 90000)
1140 printfPQExpBuffer(&buf,
1141 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1142 "c.relhastriggers, c.relhasoids, "
1143 "%s, c.reltablespace, "
1144 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1145 "c.relpersistence\n"
1146 "FROM pg_catalog.pg_class c\n "
1147 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1148 "WHERE c.oid = '%s'\n",
1150 "pg_catalog.array_to_string(c.reloptions || "
1151 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1155 else if (pset.sversion >= 90000)
1157 printfPQExpBuffer(&buf,
1158 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1159 "c.relhastriggers, c.relhasoids, "
1160 "%s, c.reltablespace, "
1161 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END\n"
1162 "FROM pg_catalog.pg_class c\n "
1163 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1164 "WHERE c.oid = '%s'\n",
1166 "pg_catalog.array_to_string(c.reloptions || "
1167 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1171 else if (pset.sversion >= 80400)
1173 printfPQExpBuffer(&buf,
1174 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1175 "c.relhastriggers, c.relhasoids, "
1176 "%s, c.reltablespace\n"
1177 "FROM pg_catalog.pg_class c\n "
1178 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1179 "WHERE c.oid = '%s'\n",
1181 "pg_catalog.array_to_string(c.reloptions || "
1182 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1186 else if (pset.sversion >= 80200)
1188 printfPQExpBuffer(&buf,
1189 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1190 "reltriggers <> 0, relhasoids, "
1191 "%s, reltablespace\n"
1192 "FROM pg_catalog.pg_class WHERE oid = '%s'",
1194 "pg_catalog.array_to_string(reloptions, E', ')" : "''"),
1197 else if (pset.sversion >= 80000)
1199 printfPQExpBuffer(&buf,
1200 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1201 "reltriggers <> 0, relhasoids, "
1202 "'', reltablespace\n"
1203 "FROM pg_catalog.pg_class WHERE oid = '%s'",
1208 printfPQExpBuffer(&buf,
1209 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1210 "reltriggers <> 0, relhasoids, "
1212 "FROM pg_catalog.pg_class WHERE oid = '%s'",
1216 res = PSQLexec(buf.data, false);
1220 /* Did we get anything? */
1221 if (PQntuples(res) == 0)
1224 fprintf(stderr, _("Did not find any relation with OID %s.\n"),
1229 tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
1230 tableinfo.relkind = *(PQgetvalue(res, 0, 1));
1231 tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
1232 tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
1233 tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
1234 tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
1235 tableinfo.reloptions = (pset.sversion >= 80200) ?
1236 strdup(PQgetvalue(res, 0, 6)) : 0;
1237 tableinfo.tablespace = (pset.sversion >= 80000) ?
1238 atooid(PQgetvalue(res, 0, 7)) : 0;
1239 tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 8), "") != 0) ?
1240 strdup(PQgetvalue(res, 0, 8)) : 0;
1241 tableinfo.relpersistence = (pset.sversion >= 90100 && strcmp(PQgetvalue(res, 0, 9), "") != 0) ?
1242 PQgetvalue(res, 0, 9)[0] : 0;
1247 * If it's a sequence, fetch its values and store into an array that will
1250 if (tableinfo.relkind == 'S')
1252 printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
1253 /* must be separate because fmtId isn't reentrant */
1254 appendPQExpBuffer(&buf, ".%s", fmtId(relationname));
1256 res = PSQLexec(buf.data, false);
1260 seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
1262 for (i = 0; i < PQnfields(res); i++)
1263 seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
1264 seq_values[i] = NULL;
1270 /* Get column info */
1271 printfPQExpBuffer(&buf, "SELECT a.attname,");
1272 appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
1273 "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
1274 "\n FROM pg_catalog.pg_attrdef d"
1275 "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
1276 "\n a.attnotnull, a.attnum");
1277 if (tableinfo.relkind == 'i')
1278 appendPQExpBuffer(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
1280 appendPQExpBuffer(&buf, ",\n a.attstorage, pg_catalog.col_description(a.attrelid, a.attnum)");
1281 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_attribute a");
1282 appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
1283 appendPQExpBuffer(&buf, "\nORDER BY a.attnum");
1285 res = PSQLexec(buf.data, false);
1288 numrows = PQntuples(res);
1291 switch (tableinfo.relkind)
1294 if (tableinfo.relpersistence == 'u')
1295 printfPQExpBuffer(&title, _("Unlogged Table \"%s.%s\""),
1296 schemaname, relationname);
1298 printfPQExpBuffer(&title, _("Table \"%s.%s\""),
1299 schemaname, relationname);
1302 printfPQExpBuffer(&title, _("View \"%s.%s\""),
1303 schemaname, relationname);
1306 printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
1307 schemaname, relationname);
1310 if (tableinfo.relpersistence == 'u')
1311 printfPQExpBuffer(&title, _("Unlogged Index \"%s.%s\""),
1312 schemaname, relationname);
1314 printfPQExpBuffer(&title, _("Index \"%s.%s\""),
1315 schemaname, relationname);
1318 /* not used as of 8.2, but keep it for backwards compatibility */
1319 printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
1320 schemaname, relationname);
1323 printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
1324 schemaname, relationname);
1327 printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
1328 schemaname, relationname);
1331 printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""),
1332 schemaname, relationname);
1335 /* untranslated unknown relkind */
1336 printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
1337 tableinfo.relkind, schemaname, relationname);
1341 /* Set the number of columns, and their names */
1342 headers[0] = gettext_noop("Column");
1343 headers[1] = gettext_noop("Type");
1346 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
1347 tableinfo.relkind == 'f')
1349 show_modifiers = true;
1350 headers[cols++] = gettext_noop("Modifiers");
1351 modifiers = pg_malloc_zero((numrows + 1) * sizeof(*modifiers));
1354 if (tableinfo.relkind == 'S')
1355 headers[cols++] = gettext_noop("Value");
1357 if (tableinfo.relkind == 'i')
1358 headers[cols++] = gettext_noop("Definition");
1362 headers[cols++] = gettext_noop("Storage");
1363 headers[cols++] = gettext_noop("Description");
1366 printTableInit(&cont, &myopt, title.data, cols, numrows);
1367 printTableInitialized = true;
1369 for (i = 0; i < cols; i++)
1370 printTableAddHeader(&cont, headers[i], true, 'l');
1372 /* Check if table is a view */
1373 if (tableinfo.relkind == 'v' && verbose)
1377 printfPQExpBuffer(&buf,
1378 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true)",
1380 result = PSQLexec(buf.data, false);
1384 if (PQntuples(result) > 0)
1385 view_def = pg_strdup(PQgetvalue(result, 0, 0));
1390 /* Generate table cells to be printed */
1391 for (i = 0; i < numrows; i++)
1394 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
1397 printTableAddCell(&cont, PQgetvalue(res, i, 1), false, false);
1399 /* Modifiers: not null and default */
1402 resetPQExpBuffer(&tmpbuf);
1403 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
1404 appendPQExpBufferStr(&tmpbuf, _("not null"));
1406 /* handle "default" here */
1407 /* (note: above we cut off the 'default' string at 128) */
1408 if (strlen(PQgetvalue(res, i, 2)) != 0)
1411 appendPQExpBufferStr(&tmpbuf, " ");
1412 /* translator: default values of column definitions */
1413 appendPQExpBuffer(&tmpbuf, _("default %s"),
1414 PQgetvalue(res, i, 2));
1417 modifiers[i] = pg_strdup(tmpbuf.data);
1418 printTableAddCell(&cont, modifiers[i], false, false);
1421 /* Value: for sequences only */
1422 if (tableinfo.relkind == 'S')
1423 printTableAddCell(&cont, seq_values[i], false, false);
1425 /* Expression for index column */
1426 if (tableinfo.relkind == 'i')
1427 printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
1429 /* Storage and Description */
1432 int firstvcol = (tableinfo.relkind == 'i' ? 6 : 5);
1433 char *storage = PQgetvalue(res, i, firstvcol);
1435 /* these strings are literal in our syntax, so not translated. */
1436 printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
1437 (storage[0] == 'm' ? "main" :
1438 (storage[0] == 'x' ? "extended" :
1439 (storage[0] == 'e' ? "external" :
1442 printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
1448 if (tableinfo.relkind == 'i')
1450 /* Footer information about an index */
1453 printfPQExpBuffer(&buf,
1454 "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
1455 if (pset.sversion >= 80200)
1456 appendPQExpBuffer(&buf, "i.indisvalid,\n");
1458 appendPQExpBuffer(&buf, "true AS indisvalid,\n");
1459 if (pset.sversion >= 90000)
1460 appendPQExpBuffer(&buf,
1461 " (NOT i.indimmediate) AND "
1462 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1463 "WHERE conrelid = i.indrelid AND "
1464 "conindid = i.indexrelid AND "
1465 "contype IN ('p','u','x') AND "
1466 "condeferrable) AS condeferrable,\n"
1467 " (NOT i.indimmediate) AND "
1468 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1469 "WHERE conrelid = i.indrelid AND "
1470 "conindid = i.indexrelid AND "
1471 "contype IN ('p','u','x') AND "
1472 "condeferred) AS condeferred,\n");
1474 appendPQExpBuffer(&buf,
1475 " false AS condeferrable, false AS condeferred,\n");
1476 appendPQExpBuffer(&buf, " a.amname, c2.relname, "
1477 "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
1478 "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
1479 "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
1480 "AND i.indrelid = c2.oid",
1483 result = PSQLexec(buf.data, false);
1486 else if (PQntuples(result) != 1)
1493 char *indisunique = PQgetvalue(result, 0, 0);
1494 char *indisprimary = PQgetvalue(result, 0, 1);
1495 char *indisclustered = PQgetvalue(result, 0, 2);
1496 char *indisvalid = PQgetvalue(result, 0, 3);
1497 char *deferrable = PQgetvalue(result, 0, 4);
1498 char *deferred = PQgetvalue(result, 0, 5);
1499 char *indamname = PQgetvalue(result, 0, 6);
1500 char *indtable = PQgetvalue(result, 0, 7);
1501 char *indpred = PQgetvalue(result, 0, 8);
1503 if (strcmp(indisprimary, "t") == 0)
1504 printfPQExpBuffer(&tmpbuf, _("primary key, "));
1505 else if (strcmp(indisunique, "t") == 0)
1506 printfPQExpBuffer(&tmpbuf, _("unique, "));
1508 resetPQExpBuffer(&tmpbuf);
1509 appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
1511 /* we assume here that index and table are in same schema */
1512 appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
1513 schemaname, indtable);
1515 if (strlen(indpred))
1516 appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
1518 if (strcmp(indisclustered, "t") == 0)
1519 appendPQExpBuffer(&tmpbuf, _(", clustered"));
1521 if (strcmp(indisvalid, "t") != 0)
1522 appendPQExpBuffer(&tmpbuf, _(", invalid"));
1524 if (strcmp(deferrable, "t") == 0)
1525 appendPQExpBuffer(&tmpbuf, _(", deferrable"));
1527 if (strcmp(deferred, "t") == 0)
1528 appendPQExpBuffer(&tmpbuf, _(", initially deferred"));
1530 printTableAddFooter(&cont, tmpbuf.data);
1531 add_tablespace_footer(&cont, tableinfo.relkind,
1532 tableinfo.tablespace, true);
1539 PGresult *result = NULL;
1541 /* Footer information about a view */
1542 printTableAddFooter(&cont, _("View definition:"));
1543 printTableAddFooter(&cont, view_def);
1546 if (tableinfo.hasrules)
1548 printfPQExpBuffer(&buf,
1549 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
1550 "FROM pg_catalog.pg_rewrite r\n"
1551 "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1",
1553 result = PSQLexec(buf.data, false);
1557 if (PQntuples(result) > 0)
1559 printTableAddFooter(&cont, _("Rules:"));
1560 for (i = 0; i < PQntuples(result); i++)
1562 const char *ruledef;
1564 /* Everything after "CREATE RULE" is echoed verbatim */
1565 ruledef = PQgetvalue(result, i, 1);
1568 printfPQExpBuffer(&buf, " %s", ruledef);
1569 printTableAddFooter(&cont, buf.data);
1575 else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'f')
1577 /* Footer information about a table */
1578 PGresult *result = NULL;
1582 if (tableinfo.hasindex)
1584 printfPQExpBuffer(&buf,
1585 "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
1586 if (pset.sversion >= 80200)
1587 appendPQExpBuffer(&buf, "i.indisvalid, ");
1589 appendPQExpBuffer(&buf, "true as indisvalid, ");
1590 appendPQExpBuffer(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n ");
1591 if (pset.sversion >= 90000)
1592 appendPQExpBuffer(&buf,
1593 "pg_catalog.pg_get_constraintdef(con.oid, true), "
1594 "contype, condeferrable, condeferred");
1596 appendPQExpBuffer(&buf,
1597 "null AS constraintdef, null AS contype, "
1598 "false AS condeferrable, false AS condeferred");
1599 if (pset.sversion >= 80000)
1600 appendPQExpBuffer(&buf, ", c2.reltablespace");
1601 appendPQExpBuffer(&buf,
1602 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
1603 if (pset.sversion >= 90000)
1604 appendPQExpBuffer(&buf,
1605 " LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
1606 appendPQExpBuffer(&buf,
1607 "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
1608 "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
1610 result = PSQLexec(buf.data, false);
1614 tuples = PQntuples(result);
1618 printTableAddFooter(&cont, _("Indexes:"));
1619 for (i = 0; i < tuples; i++)
1621 /* untranslated index name */
1622 printfPQExpBuffer(&buf, " \"%s\"",
1623 PQgetvalue(result, i, 0));
1625 /* If exclusion constraint, print the constraintdef */
1626 if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
1628 appendPQExpBuffer(&buf, " %s",
1629 PQgetvalue(result, i, 6));
1633 const char *indexdef;
1634 const char *usingpos;
1636 /* Label as primary key or unique (but not both) */
1637 if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
1638 appendPQExpBuffer(&buf, " PRIMARY KEY,");
1639 else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
1641 if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
1642 appendPQExpBuffer(&buf, " UNIQUE CONSTRAINT,");
1644 appendPQExpBuffer(&buf, " UNIQUE,");
1647 /* Everything after "USING" is echoed verbatim */
1648 indexdef = PQgetvalue(result, i, 5);
1649 usingpos = strstr(indexdef, " USING ");
1651 indexdef = usingpos + 7;
1652 appendPQExpBuffer(&buf, " %s", indexdef);
1654 /* Need these for deferrable PK/UNIQUE indexes */
1655 if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
1656 appendPQExpBuffer(&buf, " DEFERRABLE");
1658 if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
1659 appendPQExpBuffer(&buf, " INITIALLY DEFERRED");
1662 /* Add these for all cases */
1663 if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
1664 appendPQExpBuffer(&buf, " CLUSTER");
1666 if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
1667 appendPQExpBuffer(&buf, " INVALID");
1669 printTableAddFooter(&cont, buf.data);
1671 /* Print tablespace of the index on the same line */
1672 if (pset.sversion >= 80000)
1673 add_tablespace_footer(&cont, 'i',
1674 atooid(PQgetvalue(result, i, 10)),
1681 /* print table (and column) check constraints */
1682 if (tableinfo.checks)
1684 printfPQExpBuffer(&buf,
1685 "SELECT r.conname, "
1686 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
1687 "FROM pg_catalog.pg_constraint r\n"
1688 "WHERE r.conrelid = '%s' AND r.contype = 'c'\nORDER BY 1",
1690 result = PSQLexec(buf.data, false);
1694 tuples = PQntuples(result);
1698 printTableAddFooter(&cont, _("Check constraints:"));
1699 for (i = 0; i < tuples; i++)
1701 /* untranslated contraint name and def */
1702 printfPQExpBuffer(&buf, " \"%s\" %s",
1703 PQgetvalue(result, i, 0),
1704 PQgetvalue(result, i, 1));
1706 printTableAddFooter(&cont, buf.data);
1712 /* print foreign-key constraints (there are none if no triggers) */
1713 if (tableinfo.hastriggers)
1715 printfPQExpBuffer(&buf,
1717 " pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n"
1718 "FROM pg_catalog.pg_constraint r\n"
1719 "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1",
1721 result = PSQLexec(buf.data, false);
1725 tuples = PQntuples(result);
1729 printTableAddFooter(&cont, _("Foreign-key constraints:"));
1730 for (i = 0; i < tuples; i++)
1732 /* untranslated constraint name and def */
1733 printfPQExpBuffer(&buf, " \"%s\" %s",
1734 PQgetvalue(result, i, 0),
1735 PQgetvalue(result, i, 1));
1737 printTableAddFooter(&cont, buf.data);
1743 /* print incoming foreign-key references (none if no triggers) */
1744 if (tableinfo.hastriggers)
1746 printfPQExpBuffer(&buf,
1747 "SELECT conname, conrelid::pg_catalog.regclass,\n"
1748 " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
1749 "FROM pg_catalog.pg_constraint c\n"
1750 "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1",
1752 result = PSQLexec(buf.data, false);
1756 tuples = PQntuples(result);
1760 printTableAddFooter(&cont, _("Referenced by:"));
1761 for (i = 0; i < tuples; i++)
1763 printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
1764 PQgetvalue(result, i, 1),
1765 PQgetvalue(result, i, 0),
1766 PQgetvalue(result, i, 2));
1768 printTableAddFooter(&cont, buf.data);
1775 if (tableinfo.hasrules)
1777 if (pset.sversion >= 80300)
1779 printfPQExpBuffer(&buf,
1780 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
1782 "FROM pg_catalog.pg_rewrite r\n"
1783 "WHERE r.ev_class = '%s' ORDER BY 1",
1788 printfPQExpBuffer(&buf,
1789 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
1790 "'O'::char AS ev_enabled\n"
1791 "FROM pg_catalog.pg_rewrite r\n"
1792 "WHERE r.ev_class = '%s' ORDER BY 1",
1795 result = PSQLexec(buf.data, false);
1799 tuples = PQntuples(result);
1806 for (category = 0; category < 4; category++)
1808 have_heading = false;
1810 for (i = 0; i < tuples; i++)
1812 const char *ruledef;
1813 bool list_rule = false;
1818 if (*PQgetvalue(result, i, 2) == 'O')
1822 if (*PQgetvalue(result, i, 2) == 'D')
1826 if (*PQgetvalue(result, i, 2) == 'A')
1830 if (*PQgetvalue(result, i, 2) == 'R')
1842 printfPQExpBuffer(&buf, _("Rules:"));
1845 printfPQExpBuffer(&buf, _("Disabled rules:"));
1848 printfPQExpBuffer(&buf, _("Rules firing always:"));
1851 printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
1854 printTableAddFooter(&cont, buf.data);
1855 have_heading = true;
1858 /* Everything after "CREATE RULE" is echoed verbatim */
1859 ruledef = PQgetvalue(result, i, 1);
1861 printfPQExpBuffer(&buf, " %s", ruledef);
1862 printTableAddFooter(&cont, buf.data);
1871 * Print triggers next, if any (but only user-defined triggers). This
1872 * could apply to either a table or a view.
1874 if (tableinfo.hastriggers)
1879 printfPQExpBuffer(&buf,
1881 "pg_catalog.pg_get_triggerdef(t.oid%s), "
1883 "FROM pg_catalog.pg_trigger t\n"
1884 "WHERE t.tgrelid = '%s' AND ",
1885 (pset.sversion >= 90000 ? ", true" : ""),
1887 if (pset.sversion >= 90000)
1888 appendPQExpBuffer(&buf, "NOT t.tgisinternal");
1889 else if (pset.sversion >= 80300)
1890 appendPQExpBuffer(&buf, "t.tgconstraint = 0");
1892 appendPQExpBuffer(&buf,
1893 "(NOT tgisconstraint "
1895 " (SELECT 1 FROM pg_catalog.pg_depend d "
1896 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
1897 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
1898 appendPQExpBuffer(&buf, "\nORDER BY 1");
1900 result = PSQLexec(buf.data, false);
1904 tuples = PQntuples(result);
1912 * split the output into 4 different categories. Enabled
1913 * triggers, disabled triggers and the two special ALWAYS and
1914 * REPLICA configurations.
1916 for (category = 0; category < 4; category++)
1918 have_heading = false;
1919 for (i = 0; i < tuples; i++)
1923 const char *usingpos;
1924 const char *tgenabled;
1927 * Check if this trigger falls into the current
1930 tgenabled = PQgetvalue(result, i, 2);
1931 list_trigger = false;
1935 if (*tgenabled == 'O' || *tgenabled == 't')
1936 list_trigger = true;
1939 if (*tgenabled == 'D' || *tgenabled == 'f')
1940 list_trigger = true;
1943 if (*tgenabled == 'A')
1944 list_trigger = true;
1947 if (*tgenabled == 'R')
1948 list_trigger = true;
1951 if (list_trigger == false)
1954 /* Print the category heading once */
1955 if (have_heading == false)
1960 printfPQExpBuffer(&buf, _("Triggers:"));
1963 printfPQExpBuffer(&buf, _("Disabled triggers:"));
1966 printfPQExpBuffer(&buf, _("Triggers firing always:"));
1969 printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
1973 printTableAddFooter(&cont, buf.data);
1974 have_heading = true;
1977 /* Everything after "TRIGGER" is echoed verbatim */
1978 tgdef = PQgetvalue(result, i, 1);
1979 usingpos = strstr(tgdef, " TRIGGER ");
1981 tgdef = usingpos + 9;
1983 printfPQExpBuffer(&buf, " %s", tgdef);
1984 printTableAddFooter(&cont, buf.data);
1992 * Finish printing the footer information about a table.
1994 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'f')
1999 /* print foreign server name */
2000 if (tableinfo.relkind == 'f')
2002 /* Footer information about foreign table */
2003 printfPQExpBuffer(&buf,
2004 "SELECT s.srvname\n"
2005 "FROM pg_catalog.pg_foreign_table f,\n"
2006 " pg_catalog.pg_foreign_server s\n"
2007 "WHERE f.ftrelid = %s AND s.oid = f.ftserver",
2009 result = PSQLexec(buf.data, false);
2012 else if (PQntuples(result) != 1)
2018 printfPQExpBuffer(&buf, "Server: %s",
2019 PQgetvalue(result, 0, 0));
2020 printTableAddFooter(&cont, buf.data);
2024 /* print inherited tables */
2025 printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhparent AND i.inhrelid = '%s' ORDER BY inhseqno", oid);
2027 result = PSQLexec(buf.data, false);
2031 tuples = PQntuples(result);
2033 for (i = 0; i < tuples; i++)
2035 const char *s = _("Inherits");
2038 printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result, i, 0));
2040 printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result, i, 0));
2042 appendPQExpBuffer(&buf, ",");
2044 printTableAddFooter(&cont, buf.data);
2048 /* print child tables */
2049 if (pset.sversion >= 80300)
2050 printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid);
2052 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);
2054 result = PSQLexec(buf.data, false);
2058 tuples = PQntuples(result);
2062 /* print the number of child tables, if any */
2065 printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
2066 printTableAddFooter(&cont, buf.data);
2071 /* display the list of child tables */
2072 const char *ct = _("Child tables");
2074 for (i = 0; i < tuples; i++)
2077 printfPQExpBuffer(&buf, "%s: %s",
2078 ct, PQgetvalue(result, i, 0));
2080 printfPQExpBuffer(&buf, "%*s %s",
2081 (int) strlen(ct), "",
2082 PQgetvalue(result, i, 0));
2084 appendPQExpBuffer(&buf, ",");
2086 printTableAddFooter(&cont, buf.data);
2092 if (tableinfo.reloftype)
2094 printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
2095 printTableAddFooter(&cont, buf.data);
2098 /* OIDs and options */
2101 const char *s = _("Has OIDs");
2103 printfPQExpBuffer(&buf, "%s: %s", s,
2104 (tableinfo.hasoids ? _("yes") : _("no")));
2105 printTableAddFooter(&cont, buf.data);
2107 /* print reloptions */
2108 if (pset.sversion >= 80200)
2110 if (tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
2112 const char *t = _("Options");
2114 printfPQExpBuffer(&buf, "%s: %s", t,
2115 tableinfo.reloptions);
2116 printTableAddFooter(&cont, buf.data);
2121 add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
2125 printTable(&cont, pset.queryFout, pset.logfile);
2126 printTableCleanup(&cont);
2133 if (printTableInitialized)
2134 printTableCleanup(&cont);
2135 termPQExpBuffer(&buf);
2136 termPQExpBuffer(&title);
2137 termPQExpBuffer(&tmpbuf);
2141 for (ptr = seq_values; *ptr; ptr++)
2148 for (ptr = modifiers; *ptr; ptr++)
2163 * Add a tablespace description to a footer. If 'newline' is true, it is added
2164 * in a new line; otherwise it's appended to the current value of the last
2168 add_tablespace_footer(printTableContent *const cont, char relkind,
2169 Oid tablespace, const bool newline)
2171 /* relkinds for which we support tablespaces */
2172 if (relkind == 'r' || relkind == 'i')
2175 * We ignore the database default tablespace so that users not using
2176 * tablespaces don't need to know about them. This case also covers
2177 * pre-8.0 servers, for which tablespace will always be 0.
2179 if (tablespace != 0)
2181 PGresult *result = NULL;
2182 PQExpBufferData buf;
2184 initPQExpBuffer(&buf);
2185 printfPQExpBuffer(&buf,
2186 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
2187 "WHERE oid = '%u'", tablespace);
2188 result = PSQLexec(buf.data, false);
2191 /* Should always be the case, but.... */
2192 if (PQntuples(result) > 0)
2196 /* Add the tablespace as a new footer */
2197 printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
2198 PQgetvalue(result, 0, 0));
2199 printTableAddFooter(cont, buf.data);
2203 /* Append the tablespace to the latest footer */
2204 printfPQExpBuffer(&buf, "%s", cont->footer->data);
2207 * translator: before this string there's an index
2208 * description like '"foo_pkey" PRIMARY KEY, btree (a)'
2210 appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
2211 PQgetvalue(result, 0, 0));
2212 printTableSetFooter(cont, buf.data);
2216 termPQExpBuffer(&buf);
2224 * Describes roles. Any schema portion of the pattern is ignored.
2227 describeRoles(const char *pattern, bool verbose)
2229 PQExpBufferData buf;
2231 printTableContent cont;
2232 printTableOpt myopt = pset.popt.topt;
2237 const char align = 'l';
2240 initPQExpBuffer(&buf);
2242 if (pset.sversion >= 80100)
2244 printfPQExpBuffer(&buf,
2245 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
2246 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
2247 " r.rolconnlimit,\n"
2248 " ARRAY(SELECT b.rolname\n"
2249 " FROM pg_catalog.pg_auth_members m\n"
2250 " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
2251 " WHERE m.member = r.oid) as memberof");
2253 if (verbose && pset.sversion >= 80200)
2255 appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
2258 if (pset.sversion >= 90100)
2260 appendPQExpBufferStr(&buf,"\n, r.rolreplication");
2263 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
2265 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2266 NULL, "r.rolname", NULL, NULL);
2270 printfPQExpBuffer(&buf,
2271 "SELECT u.usename AS rolname,\n"
2272 " u.usesuper AS rolsuper,\n"
2273 " true AS rolinherit, false AS rolcreaterole,\n"
2274 " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
2275 " -1 AS rolconnlimit,\n"
2276 " ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
2277 "\nFROM pg_catalog.pg_user u\n");
2279 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2280 NULL, "u.usename", NULL, NULL);
2283 appendPQExpBuffer(&buf, "ORDER BY 1;");
2285 res = PSQLexec(buf.data, false);
2289 nrows = PQntuples(res);
2290 attr = pg_malloc_zero((nrows + 1) * sizeof(*attr));
2292 printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
2294 printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
2295 printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
2296 printTableAddHeader(&cont, gettext_noop("Member of"), true, align);
2298 if (verbose && pset.sversion >= 80200)
2299 printTableAddHeader(&cont, gettext_noop("Description"), true, align);
2301 for (i = 0; i < nrows; i++)
2303 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
2305 resetPQExpBuffer(&buf);
2306 if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
2307 add_role_attribute(&buf, _("Superuser"));
2309 if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
2310 add_role_attribute(&buf, _("No inheritance"));
2312 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
2313 add_role_attribute(&buf, _("Create role"));
2315 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
2316 add_role_attribute(&buf, _("Create DB"));
2318 if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
2319 add_role_attribute(&buf, _("Cannot login"));
2321 if (pset.sversion >= 90100)
2322 if (strcmp(PQgetvalue(res, i, 8), "t") == 0)
2323 add_role_attribute(&buf, _("Replication"));
2325 conns = atoi(PQgetvalue(res, i, 6));
2329 appendPQExpBufferStr(&buf, "\n");
2332 appendPQExpBuffer(&buf, _("No connections"));
2334 appendPQExpBuffer(&buf, ngettext("%d connection",
2340 attr[i] = pg_strdup(buf.data);
2342 printTableAddCell(&cont, attr[i], false, false);
2344 printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
2346 if (verbose && pset.sversion >= 80200)
2347 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
2349 termPQExpBuffer(&buf);
2351 printTable(&cont, pset.queryFout, pset.logfile);
2352 printTableCleanup(&cont);
2354 for (i = 0; i < nrows; i++)
2363 add_role_attribute(PQExpBuffer buf, const char *const str)
2366 appendPQExpBufferStr(buf, ", ");
2368 appendPQExpBufferStr(buf, str);
2375 listDbRoleSettings(const char *pattern, const char *pattern2)
2377 PQExpBufferData buf;
2379 printQueryOpt myopt = pset.popt;
2381 initPQExpBuffer(&buf);
2383 if (pset.sversion >= 90000)
2387 printfPQExpBuffer(&buf, "SELECT rolname AS role, datname AS database,\n"
2388 "pg_catalog.array_to_string(setconfig, E'\\n') AS settings\n"
2389 "FROM pg_db_role_setting AS s\n"
2390 "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n"
2391 "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n");
2392 havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
2393 NULL, "pg_roles.rolname", NULL, NULL);
2394 processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
2395 NULL, "pg_database.datname", NULL, NULL);
2396 appendPQExpBufferStr(&buf, "ORDER BY role, database");
2400 fprintf(pset.queryFout,
2401 _("No per-database role settings support in this server version.\n"));
2405 res = PSQLexec(buf.data, false);
2409 if (PQntuples(res) == 0 && !pset.quiet)
2412 fprintf(pset.queryFout, _("No matching settings found.\n"));
2414 fprintf(pset.queryFout, _("No settings found.\n"));
2418 myopt.nullPrint = NULL;
2419 myopt.title = _("List of settings");
2420 myopt.translate_header = true;
2422 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2426 resetPQExpBuffer(&buf);
2434 * handler for \dt, \di, etc.
2436 * tabtypes is an array of characters, specifying what info is desired:
2441 * E - foreign table (Note: different from 'f', the relkind value)
2442 * (any order of the above is fine)
2443 * If tabtypes is empty, we default to \dtvsE.
2446 listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
2448 bool showTables = strchr(tabtypes, 't') != NULL;
2449 bool showIndexes = strchr(tabtypes, 'i') != NULL;
2450 bool showViews = strchr(tabtypes, 'v') != NULL;
2451 bool showSeq = strchr(tabtypes, 's') != NULL;
2452 bool showForeign = strchr(tabtypes, 'E') != NULL;
2454 PQExpBufferData buf;
2456 printQueryOpt myopt = pset.popt;
2457 static const bool translate_columns[] = {false, false, true, false, false, false, false};
2459 if (!(showTables || showIndexes || showViews || showSeq || showForeign))
2460 showTables = showViews = showSeq = showForeign = true;
2462 initPQExpBuffer(&buf);
2465 * Note: as of Pg 8.2, we no longer use relkind 's', but we keep it here
2466 * for backwards compatibility.
2468 printfPQExpBuffer(&buf,
2469 "SELECT n.nspname as \"%s\",\n"
2470 " c.relname as \"%s\",\n"
2471 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' WHEN 'f' THEN '%s' END as \"%s\",\n"
2472 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
2473 gettext_noop("Schema"),
2474 gettext_noop("Name"),
2475 gettext_noop("table"),
2476 gettext_noop("view"),
2477 gettext_noop("index"),
2478 gettext_noop("sequence"),
2479 gettext_noop("special"),
2480 gettext_noop("foreign table"),
2481 gettext_noop("Type"),
2482 gettext_noop("Owner"));
2485 appendPQExpBuffer(&buf,
2486 ",\n c2.relname as \"%s\"",
2487 gettext_noop("Table"));
2489 if (verbose && pset.sversion >= 80100)
2490 appendPQExpBuffer(&buf,
2491 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
2492 gettext_noop("Size"));
2494 appendPQExpBuffer(&buf,
2495 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
2496 gettext_noop("Description"));
2498 appendPQExpBuffer(&buf,
2499 "\nFROM pg_catalog.pg_class c"
2500 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
2502 appendPQExpBuffer(&buf,
2503 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
2504 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
2506 appendPQExpBuffer(&buf, "\nWHERE c.relkind IN (");
2508 appendPQExpBuffer(&buf, "'r',");
2510 appendPQExpBuffer(&buf, "'v',");
2512 appendPQExpBuffer(&buf, "'i',");
2514 appendPQExpBuffer(&buf, "'S',");
2515 if (showSystem || pattern)
2516 appendPQExpBuffer(&buf, "'s',"); /* was RELKIND_SPECIAL in <=
2519 appendPQExpBuffer(&buf, "'f',");
2521 appendPQExpBuffer(&buf, "''"); /* dummy */
2522 appendPQExpBuffer(&buf, ")\n");
2524 if (!showSystem && !pattern)
2525 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
2526 " AND n.nspname <> 'information_schema'\n");
2529 * TOAST objects are suppressed unconditionally. Since we don't provide
2530 * any way to select relkind 't' above, we would never show toast tables
2531 * in any case; it seems a bit confusing to allow their indexes to be
2532 * shown. Use plain \d if you really need to look at a TOAST table/index.
2534 appendPQExpBuffer(&buf, " AND n.nspname !~ '^pg_toast'\n");
2536 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2537 "n.nspname", "c.relname", NULL,
2538 "pg_catalog.pg_table_is_visible(c.oid)");
2540 appendPQExpBuffer(&buf, "ORDER BY 1,2;");
2542 res = PSQLexec(buf.data, false);
2543 termPQExpBuffer(&buf);
2547 if (PQntuples(res) == 0 && !pset.quiet)
2550 fprintf(pset.queryFout, _("No matching relations found.\n"));
2552 fprintf(pset.queryFout, _("No relations found.\n"));
2556 myopt.nullPrint = NULL;
2557 myopt.title = _("List of relations");
2558 myopt.translate_header = true;
2559 myopt.translate_columns = translate_columns;
2561 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2572 * Describes languages.
2575 listLanguages(const char *pattern, bool verbose, bool showSystem)
2577 PQExpBufferData buf;
2579 printQueryOpt myopt = pset.popt;
2581 initPQExpBuffer(&buf);
2583 printfPQExpBuffer(&buf,
2584 "SELECT l.lanname AS \"%s\",\n",
2585 gettext_noop("Name"));
2586 if (pset.sversion >= 80300)
2587 appendPQExpBuffer(&buf,
2588 " pg_catalog.pg_get_userbyid(l.lanowner) as \"%s\",\n",
2589 gettext_noop("Owner"));
2591 appendPQExpBuffer(&buf,
2592 " l.lanpltrusted AS \"%s\"",
2593 gettext_noop("Trusted"));
2597 appendPQExpBuffer(&buf,
2598 ",\n NOT l.lanispl AS \"%s\",\n"
2599 " l.lanplcallfoid::regprocedure AS \"%s\",\n"
2600 " l.lanvalidator::regprocedure AS \"%s\",\n ",
2601 gettext_noop("Internal Language"),
2602 gettext_noop("Call Handler"),
2603 gettext_noop("Validator"));
2604 if (pset.sversion >= 90000)
2605 appendPQExpBuffer(&buf, "l.laninline::regprocedure AS \"%s\",\n ",
2606 gettext_noop("Inline Handler"));
2607 printACLColumn(&buf, "l.lanacl");
2610 appendPQExpBuffer(&buf,
2611 "\nFROM pg_catalog.pg_language l\n");
2613 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2614 NULL, "l.lanname", NULL, NULL);
2616 if (!showSystem && !pattern)
2617 appendPQExpBuffer(&buf, "WHERE lanplcallfoid != 0\n");
2619 appendPQExpBuffer(&buf, "ORDER BY 1;");
2621 res = PSQLexec(buf.data, false);
2622 termPQExpBuffer(&buf);
2626 myopt.nullPrint = NULL;
2627 myopt.title = _("List of languages");
2628 myopt.translate_header = true;
2630 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2640 * Describes domains.
2643 listDomains(const char *pattern, bool showSystem)
2645 PQExpBufferData buf;
2647 printQueryOpt myopt = pset.popt;
2649 initPQExpBuffer(&buf);
2651 printfPQExpBuffer(&buf,
2652 "SELECT n.nspname as \"%s\",\n"
2653 " t.typname as \"%s\",\n"
2654 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
2655 " CASE WHEN t.typnotnull AND t.typdefault IS NOT NULL THEN 'not null default '||t.typdefault\n"
2656 " WHEN t.typnotnull AND t.typdefault IS NULL THEN 'not null'\n"
2657 " WHEN NOT t.typnotnull AND t.typdefault IS NOT NULL THEN 'default '||t.typdefault\n"
2660 " pg_catalog.array_to_string(ARRAY(\n"
2661 " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
2662 " ), ' ') as \"%s\"\n"
2663 "FROM pg_catalog.pg_type t\n"
2664 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
2665 "WHERE t.typtype = 'd'\n",
2666 gettext_noop("Schema"),
2667 gettext_noop("Name"),
2668 gettext_noop("Type"),
2669 gettext_noop("Modifier"),
2670 gettext_noop("Check"));
2672 if (!showSystem && !pattern)
2673 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
2674 " AND n.nspname <> 'information_schema'\n");
2676 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2677 "n.nspname", "t.typname", NULL,
2678 "pg_catalog.pg_type_is_visible(t.oid)");
2680 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
2682 res = PSQLexec(buf.data, false);
2683 termPQExpBuffer(&buf);
2687 myopt.nullPrint = NULL;
2688 myopt.title = _("List of domains");
2689 myopt.translate_header = true;
2691 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2700 * Describes conversions.
2703 listConversions(const char *pattern, bool showSystem)
2705 PQExpBufferData buf;
2707 printQueryOpt myopt = pset.popt;
2708 static const bool translate_columns[] = {false, false, false, false, true};
2710 initPQExpBuffer(&buf);
2712 printfPQExpBuffer(&buf,
2713 "SELECT n.nspname AS \"%s\",\n"
2714 " c.conname AS \"%s\",\n"
2715 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
2716 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
2717 " CASE WHEN c.condefault THEN '%s'\n"
2718 " ELSE '%s' END AS \"%s\"\n"
2719 "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
2720 "WHERE n.oid = c.connamespace\n",
2721 gettext_noop("Schema"),
2722 gettext_noop("Name"),
2723 gettext_noop("Source"),
2724 gettext_noop("Destination"),
2725 gettext_noop("yes"), gettext_noop("no"),
2726 gettext_noop("Default?"));
2728 if (!showSystem && !pattern)
2729 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
2730 " AND n.nspname <> 'information_schema'\n");
2732 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2733 "n.nspname", "c.conname", NULL,
2734 "pg_catalog.pg_conversion_is_visible(c.oid)");
2736 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
2738 res = PSQLexec(buf.data, false);
2739 termPQExpBuffer(&buf);
2743 myopt.nullPrint = NULL;
2744 myopt.title = _("List of conversions");
2745 myopt.translate_header = true;
2746 myopt.translate_columns = translate_columns;
2748 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2760 listCasts(const char *pattern)
2762 PQExpBufferData buf;
2764 printQueryOpt myopt = pset.popt;
2765 static const bool translate_columns[] = {false, false, false, true};
2767 initPQExpBuffer(&buf);
2770 * We need a left join to pg_proc for binary casts; the others are just
2771 * paranoia. Also note that we don't attempt to localize '(binary
2772 * coercible)', because there's too much risk of gettext translating a
2773 * function name that happens to match some string in the PO database.
2775 printfPQExpBuffer(&buf,
2776 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
2777 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
2778 " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
2781 " CASE WHEN c.castcontext = 'e' THEN '%s'\n"
2782 " WHEN c.castcontext = 'a' THEN '%s'\n"
2785 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
2786 " ON c.castfunc = p.oid\n"
2787 " LEFT JOIN pg_catalog.pg_type ts\n"
2788 " ON c.castsource = ts.oid\n"
2789 " LEFT JOIN pg_catalog.pg_namespace ns\n"
2790 " ON ns.oid = ts.typnamespace\n"
2791 " LEFT JOIN pg_catalog.pg_type tt\n"
2792 " ON c.casttarget = tt.oid\n"
2793 " LEFT JOIN pg_catalog.pg_namespace nt\n"
2794 " ON nt.oid = tt.typnamespace\n"
2796 gettext_noop("Source type"),
2797 gettext_noop("Target type"),
2798 gettext_noop("Function"),
2799 gettext_noop("no"), gettext_noop("in assignment"), gettext_noop("yes"),
2800 gettext_noop("Implicit?"));
2803 * Match name pattern against either internal or external name of either
2804 * castsource or casttarget
2806 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2807 "ns.nspname", "ts.typname",
2808 "pg_catalog.format_type(ts.oid, NULL)",
2809 "pg_catalog.pg_type_is_visible(ts.oid)");
2811 appendPQExpBuffer(&buf, ") OR (true");
2813 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2814 "nt.nspname", "tt.typname",
2815 "pg_catalog.format_type(tt.oid, NULL)",
2816 "pg_catalog.pg_type_is_visible(tt.oid)");
2818 appendPQExpBuffer(&buf, ")\nORDER BY 1, 2;");
2820 res = PSQLexec(buf.data, false);
2821 termPQExpBuffer(&buf);
2825 myopt.nullPrint = NULL;
2826 myopt.title = _("List of casts");
2827 myopt.translate_header = true;
2828 myopt.translate_columns = translate_columns;
2830 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2839 * Describes schemas (namespaces)
2842 listSchemas(const char *pattern, bool verbose, bool showSystem)
2844 PQExpBufferData buf;
2846 printQueryOpt myopt = pset.popt;
2848 initPQExpBuffer(&buf);
2849 printfPQExpBuffer(&buf,
2850 "SELECT n.nspname AS \"%s\",\n"
2851 " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
2852 gettext_noop("Name"),
2853 gettext_noop("Owner"));
2857 appendPQExpBuffer(&buf, ",\n ");
2858 printACLColumn(&buf, "n.nspacl");
2859 appendPQExpBuffer(&buf,
2860 ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
2861 gettext_noop("Description"));
2864 appendPQExpBuffer(&buf,
2865 "\nFROM pg_catalog.pg_namespace n\n");
2867 if (!showSystem && !pattern)
2868 appendPQExpBuffer(&buf,
2869 "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
2871 processSQLNamePattern(pset.db, &buf, pattern,
2872 !showSystem && !pattern, false,
2873 NULL, "n.nspname", NULL,
2876 appendPQExpBuffer(&buf, "ORDER BY 1;");
2878 res = PSQLexec(buf.data, false);
2879 termPQExpBuffer(&buf);
2883 myopt.nullPrint = NULL;
2884 myopt.title = _("List of schemas");
2885 myopt.translate_header = true;
2887 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2896 * list text search parsers
2899 listTSParsers(const char *pattern, bool verbose)
2901 PQExpBufferData buf;
2903 printQueryOpt myopt = pset.popt;
2905 if (pset.sversion < 80300)
2907 fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
2908 pset.sversion / 10000, (pset.sversion / 100) % 100);
2913 return listTSParsersVerbose(pattern);
2915 initPQExpBuffer(&buf);
2917 printfPQExpBuffer(&buf,
2919 " n.nspname as \"%s\",\n"
2920 " p.prsname as \"%s\",\n"
2921 " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
2922 "FROM pg_catalog.pg_ts_parser p \n"
2923 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
2924 gettext_noop("Schema"),
2925 gettext_noop("Name"),
2926 gettext_noop("Description")
2929 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2930 "n.nspname", "p.prsname", NULL,
2931 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
2933 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
2935 res = PSQLexec(buf.data, false);
2936 termPQExpBuffer(&buf);
2940 myopt.nullPrint = NULL;
2941 myopt.title = _("List of text search parsers");
2942 myopt.translate_header = true;
2944 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2951 * full description of parsers
2954 listTSParsersVerbose(const char *pattern)
2956 PQExpBufferData buf;
2960 initPQExpBuffer(&buf);
2962 printfPQExpBuffer(&buf,
2966 "FROM pg_catalog.pg_ts_parser p\n"
2967 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
2970 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2971 "n.nspname", "p.prsname", NULL,
2972 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
2974 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
2976 res = PSQLexec(buf.data, false);
2977 termPQExpBuffer(&buf);
2981 if (PQntuples(res) == 0)
2984 fprintf(stderr, _("Did not find any text search parser named \"%s\".\n"),
2990 for (i = 0; i < PQntuples(res); i++)
2993 const char *nspname = NULL;
2994 const char *prsname;
2996 oid = PQgetvalue(res, i, 0);
2997 if (!PQgetisnull(res, i, 1))
2998 nspname = PQgetvalue(res, i, 1);
2999 prsname = PQgetvalue(res, i, 2);
3001 if (!describeOneTSParser(oid, nspname, prsname))
3019 describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
3021 PQExpBufferData buf;
3024 printQueryOpt myopt = pset.popt;
3025 static const bool translate_columns[] = {true, false, false};
3027 initPQExpBuffer(&buf);
3029 printfPQExpBuffer(&buf,
3030 "SELECT '%s' AS \"%s\", \n"
3031 " p.prsstart::pg_catalog.regproc AS \"%s\", \n"
3032 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\" \n"
3033 " FROM pg_catalog.pg_ts_parser p \n"
3034 " WHERE p.oid = '%s' \n"
3037 " p.prstoken::pg_catalog.regproc, \n"
3038 " pg_catalog.obj_description(p.prstoken, 'pg_proc') \n"
3039 " FROM pg_catalog.pg_ts_parser p \n"
3040 " WHERE p.oid = '%s' \n"
3043 " p.prsend::pg_catalog.regproc, \n"
3044 " pg_catalog.obj_description(p.prsend, 'pg_proc') \n"
3045 " FROM pg_catalog.pg_ts_parser p \n"
3046 " WHERE p.oid = '%s' \n"
3049 " p.prsheadline::pg_catalog.regproc, \n"
3050 " pg_catalog.obj_description(p.prsheadline, 'pg_proc') \n"
3051 " FROM pg_catalog.pg_ts_parser p \n"
3052 " WHERE p.oid = '%s' \n"
3055 " p.prslextype::pg_catalog.regproc, \n"
3056 " pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
3057 " FROM pg_catalog.pg_ts_parser p \n"
3058 " WHERE p.oid = '%s' \n",
3059 gettext_noop("Start parse"),
3060 gettext_noop("Method"),
3061 gettext_noop("Function"),
3062 gettext_noop("Description"),
3064 gettext_noop("Get next token"),
3066 gettext_noop("End parse"),
3068 gettext_noop("Get headline"),
3070 gettext_noop("Get token types"),
3073 res = PSQLexec(buf.data, false);
3074 termPQExpBuffer(&buf);
3078 myopt.nullPrint = NULL;
3080 sprintf(title, _("Text search parser \"%s.%s\""), nspname, prsname);
3082 sprintf(title, _("Text search parser \"%s\""), prsname);
3083 myopt.title = title;
3084 myopt.footers = NULL;
3085 myopt.default_footer = false;
3086 myopt.translate_header = true;
3087 myopt.translate_columns = translate_columns;
3089 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3093 initPQExpBuffer(&buf);
3095 printfPQExpBuffer(&buf,
3096 "SELECT t.alias as \"%s\", \n"
3097 " t.description as \"%s\" \n"
3098 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
3100 gettext_noop("Token name"),
3101 gettext_noop("Description"),
3104 res = PSQLexec(buf.data, false);
3105 termPQExpBuffer(&buf);
3109 myopt.nullPrint = NULL;
3111 sprintf(title, _("Token types for parser \"%s.%s\""), nspname, prsname);
3113 sprintf(title, _("Token types for parser \"%s\""), prsname);
3114 myopt.title = title;
3115 myopt.footers = NULL;
3116 myopt.default_footer = true;
3117 myopt.translate_header = true;
3118 myopt.translate_columns = NULL;
3120 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3129 * list text search dictionaries
3132 listTSDictionaries(const char *pattern, bool verbose)
3134 PQExpBufferData buf;
3136 printQueryOpt myopt = pset.popt;
3138 if (pset.sversion < 80300)
3140 fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
3141 pset.sversion / 10000, (pset.sversion / 100) % 100);
3145 initPQExpBuffer(&buf);
3147 printfPQExpBuffer(&buf,
3149 " n.nspname as \"%s\",\n"
3150 " d.dictname as \"%s\",\n",
3151 gettext_noop("Schema"),
3152 gettext_noop("Name"));
3156 appendPQExpBuffer(&buf,
3157 " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM \n"
3158 " pg_catalog.pg_ts_template t \n"
3159 " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
3160 " WHERE d.dicttemplate = t.oid ) AS \"%s\", \n"
3161 " d.dictinitoption as \"%s\", \n",
3162 gettext_noop("Template"),
3163 gettext_noop("Init options"));
3166 appendPQExpBuffer(&buf,
3167 " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
3168 gettext_noop("Description"));
3170 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_dict d\n"
3171 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
3173 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3174 "n.nspname", "d.dictname", NULL,
3175 "pg_catalog.pg_ts_dict_is_visible(d.oid)");
3177 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3179 res = PSQLexec(buf.data, false);
3180 termPQExpBuffer(&buf);
3184 myopt.nullPrint = NULL;
3185 myopt.title = _("List of text search dictionaries");
3186 myopt.translate_header = true;
3188 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3197 * list text search templates
3200 listTSTemplates(const char *pattern, bool verbose)
3202 PQExpBufferData buf;
3204 printQueryOpt myopt = pset.popt;
3206 if (pset.sversion < 80300)
3208 fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
3209 pset.sversion / 10000, (pset.sversion / 100) % 100);
3213 initPQExpBuffer(&buf);
3216 printfPQExpBuffer(&buf,
3218 " n.nspname AS \"%s\",\n"
3219 " t.tmplname AS \"%s\",\n"
3220 " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
3221 " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
3222 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
3223 gettext_noop("Schema"),
3224 gettext_noop("Name"),
3225 gettext_noop("Init"),
3226 gettext_noop("Lexize"),
3227 gettext_noop("Description"));
3229 printfPQExpBuffer(&buf,
3231 " n.nspname AS \"%s\",\n"
3232 " t.tmplname AS \"%s\",\n"
3233 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
3234 gettext_noop("Schema"),
3235 gettext_noop("Name"),
3236 gettext_noop("Description"));
3238 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_template t\n"
3239 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
3241 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3242 "n.nspname", "t.tmplname", NULL,
3243 "pg_catalog.pg_ts_template_is_visible(t.oid)");
3245 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3247 res = PSQLexec(buf.data, false);
3248 termPQExpBuffer(&buf);
3252 myopt.nullPrint = NULL;
3253 myopt.title = _("List of text search templates");
3254 myopt.translate_header = true;
3256 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3265 * list text search configurations
3268 listTSConfigs(const char *pattern, bool verbose)
3270 PQExpBufferData buf;
3272 printQueryOpt myopt = pset.popt;
3274 if (pset.sversion < 80300)
3276 fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
3277 pset.sversion / 10000, (pset.sversion / 100) % 100);
3282 return listTSConfigsVerbose(pattern);
3284 initPQExpBuffer(&buf);
3286 printfPQExpBuffer(&buf,
3288 " n.nspname as \"%s\",\n"
3289 " c.cfgname as \"%s\",\n"
3290 " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
3291 "FROM pg_catalog.pg_ts_config c\n"
3292 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
3293 gettext_noop("Schema"),
3294 gettext_noop("Name"),
3295 gettext_noop("Description")
3298 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3299 "n.nspname", "c.cfgname", NULL,
3300 "pg_catalog.pg_ts_config_is_visible(c.oid)");
3302 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3304 res = PSQLexec(buf.data, false);
3305 termPQExpBuffer(&buf);
3309 myopt.nullPrint = NULL;
3310 myopt.title = _("List of text search configurations");
3311 myopt.translate_header = true;
3313 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3320 listTSConfigsVerbose(const char *pattern)
3322 PQExpBufferData buf;
3326 initPQExpBuffer(&buf);
3328 printfPQExpBuffer(&buf,
3329 "SELECT c.oid, c.cfgname,\n"
3332 " np.nspname as pnspname \n"
3333 "FROM pg_catalog.pg_ts_config c \n"
3334 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace, \n"
3335 " pg_catalog.pg_ts_parser p \n"
3336 " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace \n"
3337 "WHERE p.oid = c.cfgparser\n"
3340 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3341 "n.nspname", "c.cfgname", NULL,
3342 "pg_catalog.pg_ts_config_is_visible(c.oid)");
3344 appendPQExpBuffer(&buf, "ORDER BY 3, 2;");
3346 res = PSQLexec(buf.data, false);
3347 termPQExpBuffer(&buf);
3351 if (PQntuples(res) == 0)
3354 fprintf(stderr, _("Did not find any text search configuration named \"%s\".\n"),
3360 for (i = 0; i < PQntuples(res); i++)
3363 const char *cfgname;
3364 const char *nspname = NULL;
3365 const char *prsname;
3366 const char *pnspname = NULL;
3368 oid = PQgetvalue(res, i, 0);
3369 cfgname = PQgetvalue(res, i, 1);
3370 if (!PQgetisnull(res, i, 2))
3371 nspname = PQgetvalue(res, i, 2);
3372 prsname = PQgetvalue(res, i, 3);
3373 if (!PQgetisnull(res, i, 4))
3374 pnspname = PQgetvalue(res, i, 4);
3376 if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname))
3394 describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
3395 const char *pnspname, const char *prsname)
3397 PQExpBufferData buf,
3400 printQueryOpt myopt = pset.popt;
3402 initPQExpBuffer(&buf);
3404 printfPQExpBuffer(&buf,
3406 " ( SELECT t.alias FROM \n"
3407 " pg_catalog.ts_token_type(c.cfgparser) AS t \n"
3408 " WHERE t.tokid = m.maptokentype ) AS \"%s\", \n"
3409 " pg_catalog.btrim( \n"
3410 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary \n"
3411 " FROM pg_catalog.pg_ts_config_map AS mm \n"
3412 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype \n"
3413 " ORDER BY mapcfg, maptokentype, mapseqno \n"
3414 " ) :: pg_catalog.text , \n"
3415 " '{}') AS \"%s\" \n"
3416 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n"
3417 "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
3418 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
3420 gettext_noop("Token"),
3421 gettext_noop("Dictionaries"),
3424 res = PSQLexec(buf.data, false);
3425 termPQExpBuffer(&buf);
3429 initPQExpBuffer(&title);
3432 appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
3435 appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
3439 appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
3442 appendPQExpBuffer(&title, _("\nParser: \"%s\""),
3445 myopt.nullPrint = NULL;
3446 myopt.title = title.data;
3447 myopt.footers = NULL;
3448 myopt.default_footer = false;
3449 myopt.translate_header = true;
3451 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3453 termPQExpBuffer(&title);
3463 * Describes foreign-data wrappers
3466 listForeignDataWrappers(const char *pattern, bool verbose)
3468 PQExpBufferData buf;
3470 printQueryOpt myopt = pset.popt;
3472 if (pset.sversion < 80400)
3474 fprintf(stderr, _("The server (version %d.%d) does not support foreign-data wrappers.\n"),
3475 pset.sversion / 10000, (pset.sversion / 100) % 100);
3479 initPQExpBuffer(&buf);
3480 printfPQExpBuffer(&buf,
3481 "SELECT fdwname AS \"%s\",\n"
3482 " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n"
3483 " fdwvalidator::pg_catalog.regproc AS \"%s\"",
3484 gettext_noop("Name"),
3485 gettext_noop("Owner"),
3486 gettext_noop("Validator"));
3490 appendPQExpBuffer(&buf, ",\n ");
3491 printACLColumn(&buf, "fdwacl");
3492 appendPQExpBuffer(&buf,
3493 ",\n fdwoptions AS \"%s\"",
3494 gettext_noop("Options"));
3497 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper\n");
3499 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3500 NULL, "fdwname", NULL, NULL);
3502 appendPQExpBuffer(&buf, "ORDER BY 1;");
3504 res = PSQLexec(buf.data, false);
3505 termPQExpBuffer(&buf);
3509 myopt.nullPrint = NULL;
3510 myopt.title = _("List of foreign-data wrappers");
3511 myopt.translate_header = true;
3513 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3522 * Describes foreign servers.
3525 listForeignServers(const char *pattern, bool verbose)
3527 PQExpBufferData buf;
3529 printQueryOpt myopt = pset.popt;
3531 if (pset.sversion < 80400)
3533 fprintf(stderr, _("The server (version %d.%d) does not support foreign servers.\n"),
3534 pset.sversion / 10000, (pset.sversion / 100) % 100);
3538 initPQExpBuffer(&buf);
3539 printfPQExpBuffer(&buf,
3540 "SELECT s.srvname AS \"%s\",\n"
3541 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
3542 " f.fdwname AS \"%s\"",
3543 gettext_noop("Name"),
3544 gettext_noop("Owner"),
3545 gettext_noop("Foreign-data wrapper"));
3549 appendPQExpBuffer(&buf, ",\n ");
3550 printACLColumn(&buf, "s.srvacl");
3551 appendPQExpBuffer(&buf,
3553 " s.srvtype AS \"%s\",\n"
3554 " s.srvversion AS \"%s\",\n"
3555 " s.srvoptions AS \"%s\"",
3556 gettext_noop("Type"),
3557 gettext_noop("Version"),
3558 gettext_noop("Options"));
3561 appendPQExpBuffer(&buf,
3562 "\nFROM pg_catalog.pg_foreign_server s\n"
3563 " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
3565 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3566 NULL, "s.srvname", NULL, NULL);
3568 appendPQExpBuffer(&buf, "ORDER BY 1;");
3570 res = PSQLexec(buf.data, false);
3571 termPQExpBuffer(&buf);
3575 myopt.nullPrint = NULL;
3576 myopt.title = _("List of foreign servers");
3577 myopt.translate_header = true;
3579 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3588 * Describes user mappings.
3591 listUserMappings(const char *pattern, bool verbose)
3593 PQExpBufferData buf;
3595 printQueryOpt myopt = pset.popt;
3597 if (pset.sversion < 80400)
3599 fprintf(stderr, _("The server (version %d.%d) does not support user mappings.\n"),
3600 pset.sversion / 10000, (pset.sversion / 100) % 100);
3604 initPQExpBuffer(&buf);
3605 printfPQExpBuffer(&buf,
3606 "SELECT um.srvname AS \"%s\",\n"
3607 " um.usename AS \"%s\"",
3608 gettext_noop("Server"),
3609 gettext_noop("User name"));
3612 appendPQExpBuffer(&buf,
3613 ",\n um.umoptions AS \"%s\"",
3614 gettext_noop("Options"));
3616 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
3618 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3619 NULL, "um.srvname", "um.usename", NULL);
3621 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3623 res = PSQLexec(buf.data, false);
3624 termPQExpBuffer(&buf);
3628 myopt.nullPrint = NULL;
3629 myopt.title = _("List of user mappings");
3630 myopt.translate_header = true;
3632 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3641 * Describes foreign tables.
3644 listForeignTables(const char *pattern, bool verbose)
3646 PQExpBufferData buf;
3648 printQueryOpt myopt = pset.popt;
3650 if (pset.sversion < 90100)
3652 fprintf(stderr, _("The server (version %d.%d) does not support foreign table.\n"),
3653 pset.sversion / 10000, (pset.sversion / 100) % 100);
3657 initPQExpBuffer(&buf);
3658 printfPQExpBuffer(&buf,
3659 "SELECT n.nspname AS \"%s\",\n"
3660 " c.relname AS \"%s\",\n"
3661 " s.srvname AS \"%s\"",
3662 gettext_noop("Schema"),
3663 gettext_noop("Table"),
3664 gettext_noop("Server"));
3667 appendPQExpBuffer(&buf,
3668 ",\n ft.ftoptions AS \"%s\"",
3669 gettext_noop("Options"));
3671 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_foreign_table ft,");
3672 appendPQExpBuffer(&buf, "\n pg_catalog.pg_class c,");
3673 appendPQExpBuffer(&buf, "\n pg_catalog.pg_namespace n,");
3674 appendPQExpBuffer(&buf, "\n pg_catalog.pg_foreign_server s\n");
3675 appendPQExpBuffer(&buf, "\nWHERE c.oid = ft.ftrelid");
3676 appendPQExpBuffer(&buf, "\nAND s.oid = ft.ftserver\n");
3677 appendPQExpBuffer(&buf, "\nAND n.oid = c.relnamespace\n");
3679 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3680 NULL, "n.nspname", "c.relname", NULL);
3682 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3684 res = PSQLexec(buf.data, false);
3685 termPQExpBuffer(&buf);
3689 myopt.nullPrint = NULL;
3690 myopt.title = _("List of foreign tables");
3691 myopt.translate_header = true;
3693 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3702 * Helper function for consistently formatting ACL (privilege) columns.
3703 * The proper targetlist entry is appended to buf. Note lack of any
3704 * whitespace or comma decoration.
3707 printACLColumn(PQExpBuffer buf, const char *colname)
3709 if (pset.sversion >= 80100)
3710 appendPQExpBuffer(buf,
3711 "pg_catalog.array_to_string(%s, E'\\n') AS \"%s\"",
3712 colname, gettext_noop("Access privileges"));
3714 appendPQExpBuffer(buf,
3715 "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"",
3716 colname, gettext_noop("Access privileges"));