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-2010, PostgreSQL Global Development Group
11 * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.240 2010/03/11 04:36:43 tgl Exp $
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)
476 appendPQExpBuffer(&buf,
477 " pg_catalog.array_to_string(\n"
479 " SELECT e.enumlabel\n"
480 " FROM pg_catalog.pg_enum e\n"
481 " WHERE e.enumtypid = t.oid\n"
486 gettext_noop("Elements"));
488 appendPQExpBuffer(&buf,
489 " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
490 gettext_noop("Description"));
492 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n"
493 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
496 * do not include complex types (typrelid!=0) unless they are standalone
499 appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 ");
500 appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
501 "WHERE c.oid = t.typrelid))\n");
504 * do not include array types (before 8.3 we have to use the assumption
505 * that their names start with underscore)
507 if (pset.sversion >= 80300)
508 appendPQExpBuffer(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
510 appendPQExpBuffer(&buf, " AND t.typname !~ '^_'\n");
512 if (!showSystem && !pattern)
513 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
514 " AND n.nspname <> 'information_schema'\n");
516 /* Match name pattern against either internal or external name */
517 processSQLNamePattern(pset.db, &buf, pattern, true, false,
518 "n.nspname", "t.typname",
519 "pg_catalog.format_type(t.oid, NULL)",
520 "pg_catalog.pg_type_is_visible(t.oid)");
522 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
524 res = PSQLexec(buf.data, false);
525 termPQExpBuffer(&buf);
529 myopt.nullPrint = NULL;
530 myopt.title = _("List of data types");
531 myopt.translate_header = true;
533 printQuery(res, &myopt, pset.queryFout, pset.logfile);
543 describeOperators(const char *pattern, bool showSystem)
547 printQueryOpt myopt = pset.popt;
549 initPQExpBuffer(&buf);
551 printfPQExpBuffer(&buf,
552 "SELECT n.nspname as \"%s\",\n"
553 " o.oprname AS \"%s\",\n"
554 " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
555 " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
556 " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n"
557 " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
558 " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
559 "FROM pg_catalog.pg_operator o\n"
560 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
561 gettext_noop("Schema"),
562 gettext_noop("Name"),
563 gettext_noop("Left arg type"),
564 gettext_noop("Right arg type"),
565 gettext_noop("Result type"),
566 gettext_noop("Description"));
568 if (!showSystem && !pattern)
569 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
570 " AND n.nspname <> 'information_schema'\n");
572 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, true,
573 "n.nspname", "o.oprname", NULL,
574 "pg_catalog.pg_operator_is_visible(o.oid)");
576 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;");
578 res = PSQLexec(buf.data, false);
579 termPQExpBuffer(&buf);
583 myopt.nullPrint = NULL;
584 myopt.title = _("List of operators");
585 myopt.translate_header = true;
587 printQuery(res, &myopt, pset.queryFout, pset.logfile);
597 * for \l, \list, and -l switch
600 listAllDbs(bool verbose)
604 printQueryOpt myopt = pset.popt;
606 initPQExpBuffer(&buf);
608 printfPQExpBuffer(&buf,
609 "SELECT d.datname as \"%s\",\n"
610 " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
611 " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
612 gettext_noop("Name"),
613 gettext_noop("Owner"),
614 gettext_noop("Encoding"));
615 if (pset.sversion >= 80400)
616 appendPQExpBuffer(&buf,
617 " d.datcollate as \"%s\",\n"
618 " d.datctype as \"%s\",\n",
619 gettext_noop("Collation"),
620 gettext_noop("Ctype"));
621 appendPQExpBuffer(&buf, " ");
622 printACLColumn(&buf, "d.datacl");
623 if (verbose && pset.sversion >= 80200)
624 appendPQExpBuffer(&buf,
625 ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
626 " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
627 " ELSE 'No Access'\n"
629 gettext_noop("Size"));
630 if (verbose && pset.sversion >= 80000)
631 appendPQExpBuffer(&buf,
632 ",\n t.spcname as \"%s\"",
633 gettext_noop("Tablespace"));
634 if (verbose && pset.sversion >= 80200)
635 appendPQExpBuffer(&buf,
636 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
637 gettext_noop("Description"));
638 appendPQExpBuffer(&buf,
639 "\nFROM pg_catalog.pg_database d\n");
640 if (verbose && pset.sversion >= 80000)
641 appendPQExpBuffer(&buf,
642 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
643 appendPQExpBuffer(&buf, "ORDER BY 1;");
644 res = PSQLexec(buf.data, false);
645 termPQExpBuffer(&buf);
649 myopt.nullPrint = NULL;
650 myopt.title = _("List of databases");
651 myopt.translate_header = true;
653 printQuery(res, &myopt, pset.queryFout, pset.logfile);
661 * List Tables' Grant/Revoke Permissions
662 * \z (now also \dp -- perhaps more mnemonic)
665 permissionsList(const char *pattern)
669 printQueryOpt myopt = pset.popt;
670 static const bool translate_columns[] = {false, false, true, false, false};
672 initPQExpBuffer(&buf);
675 * we ignore indexes and toast tables since they have no meaningful rights
677 printfPQExpBuffer(&buf,
678 "SELECT n.nspname as \"%s\",\n"
679 " c.relname as \"%s\",\n"
680 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \"%s\",\n"
682 gettext_noop("Schema"),
683 gettext_noop("Name"),
684 gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
685 gettext_noop("Type"));
687 printACLColumn(&buf, "c.relacl");
689 if (pset.sversion >= 80400)
690 appendPQExpBuffer(&buf,
691 ",\n pg_catalog.array_to_string(ARRAY(\n"
692 " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
693 " FROM pg_catalog.pg_attribute a\n"
694 " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
695 " ), E'\\n') AS \"%s\"",
696 gettext_noop("Column access privileges"));
698 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_class c\n"
699 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
700 "WHERE c.relkind IN ('r', 'v', 'S')\n");
703 * Unless a schema pattern is specified, we suppress system and temp
704 * tables, since they normally aren't very interesting from a permissions
705 * point of view. You can see 'em by explicit request though, eg with \z
708 processSQLNamePattern(pset.db, &buf, pattern, true, false,
709 "n.nspname", "c.relname", NULL,
710 "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
712 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
714 res = PSQLexec(buf.data, false);
717 termPQExpBuffer(&buf);
721 myopt.nullPrint = NULL;
722 printfPQExpBuffer(&buf, _("Access privileges"));
723 myopt.title = buf.data;
724 myopt.translate_header = true;
725 myopt.translate_columns = translate_columns;
727 printQuery(res, &myopt, pset.queryFout, pset.logfile);
729 termPQExpBuffer(&buf);
738 * List DefaultACLs. The pattern can match either schema or role name.
741 listDefaultACLs(const char *pattern)
745 printQueryOpt myopt = pset.popt;
746 static const bool translate_columns[] = {false, false, true, false};
748 if (pset.sversion < 90000)
750 fprintf(stderr, _("The server (version %d.%d) does not support altering default privileges.\n"),
751 pset.sversion / 10000, (pset.sversion / 100) % 100);
755 initPQExpBuffer(&buf);
757 printfPQExpBuffer(&buf,
758 "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
759 " n.nspname AS \"%s\",\n"
760 " CASE d.defaclobjtype WHEN 'r' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END AS \"%s\",\n"
762 gettext_noop("Owner"),
763 gettext_noop("Schema"),
764 gettext_noop("table"),
765 gettext_noop("sequence"),
766 gettext_noop("function"),
767 gettext_noop("Type"));
769 printACLColumn(&buf, "d.defaclacl");
771 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
772 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
774 processSQLNamePattern(pset.db, &buf, pattern, false, false,
777 "pg_catalog.pg_get_userbyid(d.defaclrole)",
780 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
782 res = PSQLexec(buf.data, false);
785 termPQExpBuffer(&buf);
789 myopt.nullPrint = NULL;
790 printfPQExpBuffer(&buf, _("Default access privileges"));
791 myopt.title = buf.data;
792 myopt.translate_header = true;
793 myopt.translate_columns = translate_columns;
795 printQuery(res, &myopt, pset.queryFout, pset.logfile);
797 termPQExpBuffer(&buf);
804 * Get object comments
808 * Note: This only lists things that actually have a description. For complete
809 * lists of things, there are other \d? commands.
812 objectDescription(const char *pattern, bool showSystem)
816 printQueryOpt myopt = pset.popt;
817 static const bool translate_columns[] = {false, false, true, false};
819 initPQExpBuffer(&buf);
821 appendPQExpBuffer(&buf,
822 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
824 gettext_noop("Schema"),
825 gettext_noop("Name"),
826 gettext_noop("Object"),
827 gettext_noop("Description"));
829 /* Aggregate descriptions */
830 appendPQExpBuffer(&buf,
831 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
832 " n.nspname as nspname,\n"
833 " CAST(p.proname AS pg_catalog.text) as name,"
834 " CAST('%s' AS pg_catalog.text) as object\n"
835 " FROM pg_catalog.pg_proc p\n"
836 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
837 " WHERE p.proisagg\n",
838 gettext_noop("aggregate"));
840 if (!showSystem && !pattern)
841 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
842 " AND n.nspname <> 'information_schema'\n");
844 processSQLNamePattern(pset.db, &buf, pattern, true, false,
845 "n.nspname", "p.proname", NULL,
846 "pg_catalog.pg_function_is_visible(p.oid)");
848 /* Function descriptions */
849 appendPQExpBuffer(&buf,
851 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
852 " n.nspname as nspname,\n"
853 " CAST(p.proname AS pg_catalog.text) as name,"
854 " CAST('%s' AS pg_catalog.text) as object\n"
855 " FROM pg_catalog.pg_proc p\n"
856 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
857 " WHERE NOT p.proisagg\n",
858 gettext_noop("function"));
860 if (!showSystem && !pattern)
861 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
862 " AND n.nspname <> 'information_schema'\n");
864 processSQLNamePattern(pset.db, &buf, pattern, true, false,
865 "n.nspname", "p.proname", NULL,
866 "pg_catalog.pg_function_is_visible(p.oid)");
868 /* Operator descriptions (only if operator has its own comment) */
869 appendPQExpBuffer(&buf,
871 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
872 " n.nspname as nspname,\n"
873 " CAST(o.oprname AS pg_catalog.text) as name,"
874 " CAST('%s' AS pg_catalog.text) as object\n"
875 " FROM pg_catalog.pg_operator o\n"
876 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
877 gettext_noop("operator"));
879 if (!showSystem && !pattern)
880 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
881 " AND n.nspname <> 'information_schema'\n");
883 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
884 "n.nspname", "o.oprname", NULL,
885 "pg_catalog.pg_operator_is_visible(o.oid)");
887 /* Type description */
888 appendPQExpBuffer(&buf,
890 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
891 " n.nspname as nspname,\n"
892 " pg_catalog.format_type(t.oid, NULL) as name,"
893 " CAST('%s' AS pg_catalog.text) as object\n"
894 " FROM pg_catalog.pg_type t\n"
895 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
896 gettext_noop("data type"));
898 if (!showSystem && !pattern)
899 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
900 " AND n.nspname <> 'information_schema'\n");
902 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
903 "n.nspname", "pg_catalog.format_type(t.oid, NULL)",
905 "pg_catalog.pg_type_is_visible(t.oid)");
907 /* Relation (tables, views, indexes, sequences) descriptions */
908 appendPQExpBuffer(&buf,
910 " SELECT c.oid as oid, c.tableoid as tableoid,\n"
911 " n.nspname as nspname,\n"
912 " CAST(c.relname AS pg_catalog.text) as name,\n"
914 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END"
915 " AS pg_catalog.text) as object\n"
916 " FROM pg_catalog.pg_class c\n"
917 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
918 " WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
919 gettext_noop("table"),
920 gettext_noop("view"),
921 gettext_noop("index"),
922 gettext_noop("sequence"));
924 if (!showSystem && !pattern)
925 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
926 " AND n.nspname <> 'information_schema'\n");
928 processSQLNamePattern(pset.db, &buf, pattern, true, false,
929 "n.nspname", "c.relname", NULL,
930 "pg_catalog.pg_table_is_visible(c.oid)");
932 /* Rule description (ignore rules for views) */
933 appendPQExpBuffer(&buf,
935 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
936 " n.nspname as nspname,\n"
937 " CAST(r.rulename AS pg_catalog.text) as name,"
938 " CAST('%s' AS pg_catalog.text) as object\n"
939 " FROM pg_catalog.pg_rewrite r\n"
940 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
941 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
942 " WHERE r.rulename != '_RETURN'\n",
943 gettext_noop("rule"));
945 if (!showSystem && !pattern)
946 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
947 " AND n.nspname <> 'information_schema'\n");
949 /* XXX not sure what to do about visibility rule here? */
950 processSQLNamePattern(pset.db, &buf, pattern, true, false,
951 "n.nspname", "r.rulename", NULL,
952 "pg_catalog.pg_table_is_visible(c.oid)");
954 /* Trigger description */
955 appendPQExpBuffer(&buf,
957 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
958 " n.nspname as nspname,\n"
959 " CAST(t.tgname AS pg_catalog.text) as name,"
960 " CAST('%s' AS pg_catalog.text) as object\n"
961 " FROM pg_catalog.pg_trigger t\n"
962 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
963 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
964 gettext_noop("trigger"));
966 if (!showSystem && !pattern)
967 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
968 " AND n.nspname <> 'information_schema'\n");
970 /* XXX not sure what to do about visibility rule here? */
971 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
972 "n.nspname", "t.tgname", NULL,
973 "pg_catalog.pg_table_is_visible(c.oid)");
975 appendPQExpBuffer(&buf,
977 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
979 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
981 res = PSQLexec(buf.data, false);
982 termPQExpBuffer(&buf);
986 myopt.nullPrint = NULL;
987 myopt.title = _("Object descriptions");
988 myopt.translate_header = true;
989 myopt.translate_columns = translate_columns;
991 printQuery(res, &myopt, pset.queryFout, pset.logfile);
999 * describeTableDetails (for \d)
1001 * This routine finds the tables to be displayed, and calls
1002 * describeOneTableDetails for each one.
1004 * verbose: if true, this is \d+
1007 describeTableDetails(const char *pattern, bool verbose, bool showSystem)
1009 PQExpBufferData buf;
1013 initPQExpBuffer(&buf);
1015 printfPQExpBuffer(&buf,
1019 "FROM pg_catalog.pg_class c\n"
1020 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1022 if (!showSystem && !pattern)
1023 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1024 " AND n.nspname <> 'information_schema'\n");
1026 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
1027 "n.nspname", "c.relname", NULL,
1028 "pg_catalog.pg_table_is_visible(c.oid)");
1030 appendPQExpBuffer(&buf, "ORDER BY 2, 3;");
1032 res = PSQLexec(buf.data, false);
1033 termPQExpBuffer(&buf);
1037 if (PQntuples(res) == 0)
1040 fprintf(stderr, _("Did not find any relation named \"%s\".\n"),
1046 for (i = 0; i < PQntuples(res); i++)
1049 const char *nspname;
1050 const char *relname;
1052 oid = PQgetvalue(res, i, 0);
1053 nspname = PQgetvalue(res, i, 1);
1054 relname = PQgetvalue(res, i, 2);
1056 if (!describeOneTableDetails(nspname, relname, oid, verbose))
1073 * describeOneTableDetails (for \d)
1075 * Unfortunately, the information presented here is so complicated that it
1076 * cannot be done in a single query. So we have to assemble the printed table
1077 * by hand and pass it to the underlying printTable() function.
1080 describeOneTableDetails(const char *schemaname,
1081 const char *relationname,
1085 PQExpBufferData buf;
1086 PGresult *res = NULL;
1087 printTableOpt myopt = pset.popt.topt;
1088 printTableContent cont;
1089 bool printTableInitialized = false;
1091 char *view_def = NULL;
1093 char **seq_values = NULL;
1094 char **modifiers = NULL;
1096 PQExpBufferData title;
1097 PQExpBufferData tmpbuf;
1113 bool show_modifiers = false;
1118 /* This output looks confusing in expanded mode. */
1119 myopt.expanded = false;
1121 initPQExpBuffer(&buf);
1122 initPQExpBuffer(&title);
1123 initPQExpBuffer(&tmpbuf);
1125 /* Get general table info */
1126 if (pset.sversion >= 90000)
1128 printfPQExpBuffer(&buf,
1129 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1130 "c.relhastriggers, c.relhasoids, "
1131 "%s, c.reltablespace, c.relhasexclusion, "
1132 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::text END\n"
1133 "FROM pg_catalog.pg_class c\n "
1134 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1135 "WHERE c.oid = '%s'\n",
1137 "pg_catalog.array_to_string(c.reloptions || "
1138 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1142 else if (pset.sversion >= 80400)
1144 printfPQExpBuffer(&buf,
1145 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1146 "c.relhastriggers, c.relhasoids, "
1147 "%s, c.reltablespace\n"
1148 "FROM pg_catalog.pg_class c\n "
1149 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1150 "WHERE c.oid = '%s'\n",
1152 "pg_catalog.array_to_string(c.reloptions || "
1153 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1157 else if (pset.sversion >= 80200)
1159 printfPQExpBuffer(&buf,
1160 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1161 "reltriggers <> 0, relhasoids, "
1162 "%s, reltablespace\n"
1163 "FROM pg_catalog.pg_class WHERE oid = '%s'",
1165 "pg_catalog.array_to_string(reloptions, E', ')" : "''"),
1168 else if (pset.sversion >= 80000)
1170 printfPQExpBuffer(&buf,
1171 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1172 "reltriggers <> 0, relhasoids, "
1173 "'', reltablespace\n"
1174 "FROM pg_catalog.pg_class WHERE oid = '%s'",
1179 printfPQExpBuffer(&buf,
1180 "SELECT relchecks, relkind, relhasindex, relhasrules, "
1181 "reltriggers <> 0, relhasoids, "
1183 "FROM pg_catalog.pg_class WHERE oid = '%s'",
1187 res = PSQLexec(buf.data, false);
1191 /* Did we get anything? */
1192 if (PQntuples(res) == 0)
1195 fprintf(stderr, _("Did not find any relation with OID %s.\n"),
1200 tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
1201 tableinfo.relkind = *(PQgetvalue(res, 0, 1));
1202 tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
1203 tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
1204 tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
1205 tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
1206 tableinfo.reloptions = (pset.sversion >= 80200) ?
1207 strdup(PQgetvalue(res, 0, 6)) : 0;
1208 tableinfo.tablespace = (pset.sversion >= 80000) ?
1209 atooid(PQgetvalue(res, 0, 7)) : 0;
1210 tableinfo.hasexclusion = (pset.sversion >= 90000) ?
1211 strcmp(PQgetvalue(res, 0, 8), "t") == 0 : false;
1212 tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 9), "") != 0) ?
1213 strdup(PQgetvalue(res, 0, 9)) : 0;
1218 * If it's a sequence, fetch its values and store into an array that will
1221 if (tableinfo.relkind == 'S')
1223 printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
1224 /* must be separate because fmtId isn't reentrant */
1225 appendPQExpBuffer(&buf, ".%s", fmtId(relationname));
1227 res = PSQLexec(buf.data, false);
1231 seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
1233 for (i = 0; i < PQnfields(res); i++)
1234 seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
1235 seq_values[i] = NULL;
1241 /* Get column info */
1242 printfPQExpBuffer(&buf, "SELECT a.attname,");
1243 appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
1244 "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
1245 "\n FROM pg_catalog.pg_attrdef d"
1246 "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
1247 "\n a.attnotnull, a.attnum");
1248 if (tableinfo.relkind == 'i')
1249 appendPQExpBuffer(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
1251 appendPQExpBuffer(&buf, ",\n a.attstorage, pg_catalog.col_description(a.attrelid, a.attnum)");
1252 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_attribute a");
1253 appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
1254 appendPQExpBuffer(&buf, "\nORDER BY a.attnum");
1256 res = PSQLexec(buf.data, false);
1259 numrows = PQntuples(res);
1262 switch (tableinfo.relkind)
1265 printfPQExpBuffer(&title, _("Table \"%s.%s\""),
1266 schemaname, relationname);
1269 printfPQExpBuffer(&title, _("View \"%s.%s\""),
1270 schemaname, relationname);
1273 printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
1274 schemaname, relationname);
1277 printfPQExpBuffer(&title, _("Index \"%s.%s\""),
1278 schemaname, relationname);
1281 /* not used as of 8.2, but keep it for backwards compatibility */
1282 printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
1283 schemaname, relationname);
1286 printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
1287 schemaname, relationname);
1290 printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
1291 schemaname, relationname);
1294 /* untranslated unknown relkind */
1295 printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
1296 tableinfo.relkind, schemaname, relationname);
1300 /* Set the number of columns, and their names */
1301 headers[0] = gettext_noop("Column");
1302 headers[1] = gettext_noop("Type");
1305 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
1307 show_modifiers = true;
1308 headers[cols++] = gettext_noop("Modifiers");
1309 modifiers = pg_malloc_zero((numrows + 1) * sizeof(*modifiers));
1312 if (tableinfo.relkind == 'S')
1313 headers[cols++] = gettext_noop("Value");
1315 if (tableinfo.relkind == 'i')
1316 headers[cols++] = gettext_noop("Definition");
1320 headers[cols++] = gettext_noop("Storage");
1321 headers[cols++] = gettext_noop("Description");
1324 printTableInit(&cont, &myopt, title.data, cols, numrows);
1325 printTableInitialized = true;
1327 for (i = 0; i < cols; i++)
1328 printTableAddHeader(&cont, headers[i], true, 'l');
1330 /* Check if table is a view */
1331 if (tableinfo.relkind == 'v' && verbose)
1335 printfPQExpBuffer(&buf,
1336 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true)",
1338 result = PSQLexec(buf.data, false);
1342 if (PQntuples(result) > 0)
1343 view_def = pg_strdup(PQgetvalue(result, 0, 0));
1348 /* Generate table cells to be printed */
1349 for (i = 0; i < numrows; i++)
1352 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
1355 printTableAddCell(&cont, PQgetvalue(res, i, 1), false, false);
1357 /* Modifiers: not null and default */
1360 resetPQExpBuffer(&tmpbuf);
1361 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
1362 appendPQExpBufferStr(&tmpbuf, _("not null"));
1364 /* handle "default" here */
1365 /* (note: above we cut off the 'default' string at 128) */
1366 if (strlen(PQgetvalue(res, i, 2)) != 0)
1369 appendPQExpBufferStr(&tmpbuf, " ");
1370 /* translator: default values of column definitions */
1371 appendPQExpBuffer(&tmpbuf, _("default %s"),
1372 PQgetvalue(res, i, 2));
1375 modifiers[i] = pg_strdup(tmpbuf.data);
1376 printTableAddCell(&cont, modifiers[i], false, false);
1379 /* Value: for sequences only */
1380 if (tableinfo.relkind == 'S')
1381 printTableAddCell(&cont, seq_values[i], false, false);
1383 /* Expression for index column */
1384 if (tableinfo.relkind == 'i')
1385 printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
1387 /* Storage and Description */
1390 int firstvcol = (tableinfo.relkind == 'i' ? 6 : 5);
1391 char *storage = PQgetvalue(res, i, firstvcol);
1393 /* these strings are literal in our syntax, so not translated. */
1394 printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
1395 (storage[0] == 'm' ? "main" :
1396 (storage[0] == 'x' ? "extended" :
1397 (storage[0] == 'e' ? "external" :
1400 printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
1406 if (tableinfo.relkind == 'i')
1408 /* Footer information about an index */
1411 printfPQExpBuffer(&buf,
1412 "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
1413 if (pset.sversion >= 80200)
1414 appendPQExpBuffer(&buf, "i.indisvalid,\n");
1416 appendPQExpBuffer(&buf, "true AS indisvalid,\n");
1417 if (pset.sversion >= 90000)
1418 appendPQExpBuffer(&buf,
1419 " (NOT i.indimmediate) AND "
1420 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1421 "WHERE conrelid = i.indrelid AND "
1422 "conindid = i.indexrelid AND "
1423 "contype IN ('p','u','x') AND "
1424 "condeferrable) AS condeferrable,\n"
1425 " (NOT i.indimmediate) AND "
1426 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1427 "WHERE conrelid = i.indrelid AND "
1428 "conindid = i.indexrelid AND "
1429 "contype IN ('p','u','x') AND "
1430 "condeferred) AS condeferred,\n");
1432 appendPQExpBuffer(&buf,
1433 " false AS condeferrable, false AS condeferred,\n");
1434 appendPQExpBuffer(&buf, " a.amname, c2.relname, "
1435 "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
1436 "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
1437 "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
1438 "AND i.indrelid = c2.oid",
1441 result = PSQLexec(buf.data, false);
1444 else if (PQntuples(result) != 1)
1451 char *indisunique = PQgetvalue(result, 0, 0);
1452 char *indisprimary = PQgetvalue(result, 0, 1);
1453 char *indisclustered = PQgetvalue(result, 0, 2);
1454 char *indisvalid = PQgetvalue(result, 0, 3);
1455 char *deferrable = PQgetvalue(result, 0, 4);
1456 char *deferred = PQgetvalue(result, 0, 5);
1457 char *indamname = PQgetvalue(result, 0, 6);
1458 char *indtable = PQgetvalue(result, 0, 7);
1459 char *indpred = PQgetvalue(result, 0, 8);
1461 if (strcmp(indisprimary, "t") == 0)
1462 printfPQExpBuffer(&tmpbuf, _("primary key, "));
1463 else if (strcmp(indisunique, "t") == 0)
1464 printfPQExpBuffer(&tmpbuf, _("unique, "));
1466 resetPQExpBuffer(&tmpbuf);
1467 appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
1469 /* we assume here that index and table are in same schema */
1470 appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
1471 schemaname, indtable);
1473 if (strlen(indpred))
1474 appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
1476 if (strcmp(indisclustered, "t") == 0)
1477 appendPQExpBuffer(&tmpbuf, _(", clustered"));
1479 if (strcmp(indisvalid, "t") != 0)
1480 appendPQExpBuffer(&tmpbuf, _(", invalid"));
1482 if (strcmp(deferrable, "t") == 0)
1483 appendPQExpBuffer(&tmpbuf, _(", deferrable"));
1485 if (strcmp(deferred, "t") == 0)
1486 appendPQExpBuffer(&tmpbuf, _(", initially deferred"));
1488 printTableAddFooter(&cont, tmpbuf.data);
1489 add_tablespace_footer(&cont, tableinfo.relkind,
1490 tableinfo.tablespace, true);
1497 PGresult *result = NULL;
1499 /* Footer information about a view */
1500 printTableAddFooter(&cont, _("View definition:"));
1501 printTableAddFooter(&cont, view_def);
1504 if (tableinfo.hasrules)
1506 printfPQExpBuffer(&buf,
1507 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
1508 "FROM pg_catalog.pg_rewrite r\n"
1509 "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1",
1511 result = PSQLexec(buf.data, false);
1515 if (PQntuples(result) > 0)
1517 printTableAddFooter(&cont, _("Rules:"));
1518 for (i = 0; i < PQntuples(result); i++)
1520 const char *ruledef;
1522 /* Everything after "CREATE RULE" is echoed verbatim */
1523 ruledef = PQgetvalue(result, i, 1);
1526 printfPQExpBuffer(&buf, " %s", ruledef);
1527 printTableAddFooter(&cont, buf.data);
1533 else if (tableinfo.relkind == 'r')
1535 /* Footer information about a table */
1536 PGresult *result = NULL;
1540 if (tableinfo.hasindex)
1542 printfPQExpBuffer(&buf,
1543 "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
1544 if (pset.sversion >= 80200)
1545 appendPQExpBuffer(&buf, "i.indisvalid, ");
1547 appendPQExpBuffer(&buf, "true as indisvalid, ");
1548 appendPQExpBuffer(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)");
1549 if (pset.sversion >= 90000)
1550 appendPQExpBuffer(&buf,
1551 ",\n (NOT i.indimmediate) AND "
1552 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1553 "WHERE conrelid = i.indrelid AND "
1554 "conindid = i.indexrelid AND "
1555 "contype IN ('p','u','x') AND "
1556 "condeferrable) AS condeferrable"
1557 ",\n (NOT i.indimmediate) AND "
1558 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
1559 "WHERE conrelid = i.indrelid AND "
1560 "conindid = i.indexrelid AND "
1561 "contype IN ('p','u','x') AND "
1562 "condeferred) AS condeferred");
1564 appendPQExpBuffer(&buf, ", false AS condeferrable, false AS condeferred");
1565 if (pset.sversion >= 80000)
1566 appendPQExpBuffer(&buf, ", c2.reltablespace");
1567 appendPQExpBuffer(&buf,
1568 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
1569 "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
1570 "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
1572 result = PSQLexec(buf.data, false);
1576 tuples = PQntuples(result);
1580 printTableAddFooter(&cont, _("Indexes:"));
1581 for (i = 0; i < tuples; i++)
1583 const char *indexdef;
1584 const char *usingpos;
1586 /* untranslated index name */
1587 printfPQExpBuffer(&buf, " \"%s\"",
1588 PQgetvalue(result, i, 0));
1590 /* Label as primary key or unique (but not both) */
1591 appendPQExpBuffer(&buf,
1592 strcmp(PQgetvalue(result, i, 1), "t") == 0
1594 (strcmp(PQgetvalue(result, i, 2), "t") == 0
1597 /* Everything after "USING" is echoed verbatim */
1598 indexdef = PQgetvalue(result, i, 5);
1599 usingpos = strstr(indexdef, " USING ");
1601 indexdef = usingpos + 7;
1603 appendPQExpBuffer(&buf, " %s", indexdef);
1605 if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
1606 appendPQExpBuffer(&buf, " CLUSTER");
1608 if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
1609 appendPQExpBuffer(&buf, " INVALID");
1611 if (strcmp(PQgetvalue(result, i, 6), "t") == 0)
1612 appendPQExpBuffer(&buf, " DEFERRABLE");
1614 if (strcmp(PQgetvalue(result, i, 7), "t") == 0)
1615 appendPQExpBuffer(&buf, " INITIALLY DEFERRED");
1617 printTableAddFooter(&cont, buf.data);
1619 /* Print tablespace of the index on the same line */
1620 if (pset.sversion >= 80000)
1621 add_tablespace_footer(&cont, 'i',
1622 atooid(PQgetvalue(result, i, 8)),
1629 /* print table (and column) check constraints */
1630 if (tableinfo.checks)
1632 printfPQExpBuffer(&buf,
1633 "SELECT r.conname, "
1634 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
1635 "FROM pg_catalog.pg_constraint r\n"
1636 "WHERE r.conrelid = '%s' AND r.contype = 'c'\nORDER BY 1",
1638 result = PSQLexec(buf.data, false);
1642 tuples = PQntuples(result);
1646 printTableAddFooter(&cont, _("Check constraints:"));
1647 for (i = 0; i < tuples; i++)
1649 /* untranslated contraint name and def */
1650 printfPQExpBuffer(&buf, " \"%s\" %s",
1651 PQgetvalue(result, i, 0),
1652 PQgetvalue(result, i, 1));
1654 printTableAddFooter(&cont, buf.data);
1660 /* print exclusion constraints */
1661 if (tableinfo.hasexclusion)
1663 printfPQExpBuffer(&buf,
1664 "SELECT r.conname, "
1665 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
1666 "FROM pg_catalog.pg_constraint r\n"
1667 "WHERE r.conrelid = '%s' AND r.contype = 'x'\n"
1670 result = PSQLexec(buf.data, false);
1674 tuples = PQntuples(result);
1678 printTableAddFooter(&cont, _("Exclusion constraints:"));
1679 for (i = 0; i < tuples; i++)
1681 /* untranslated contraint name and def */
1682 printfPQExpBuffer(&buf, " \"%s\" %s",
1683 PQgetvalue(result, i, 0),
1684 PQgetvalue(result, i, 1));
1686 printTableAddFooter(&cont, buf.data);
1692 /* print foreign-key constraints (there are none if no triggers) */
1693 if (tableinfo.hastriggers)
1695 printfPQExpBuffer(&buf,
1697 " pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n"
1698 "FROM pg_catalog.pg_constraint r\n"
1699 "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1",
1701 result = PSQLexec(buf.data, false);
1705 tuples = PQntuples(result);
1709 printTableAddFooter(&cont, _("Foreign-key constraints:"));
1710 for (i = 0; i < tuples; i++)
1712 /* untranslated constraint name and def */
1713 printfPQExpBuffer(&buf, " \"%s\" %s",
1714 PQgetvalue(result, i, 0),
1715 PQgetvalue(result, i, 1));
1717 printTableAddFooter(&cont, buf.data);
1723 /* print incoming foreign-key references (none if no triggers) */
1724 if (tableinfo.hastriggers)
1726 printfPQExpBuffer(&buf,
1727 "SELECT conname, conrelid::pg_catalog.regclass,\n"
1728 " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
1729 "FROM pg_catalog.pg_constraint c\n"
1730 "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1",
1732 result = PSQLexec(buf.data, false);
1736 tuples = PQntuples(result);
1740 printTableAddFooter(&cont, _("Referenced by:"));
1741 for (i = 0; i < tuples; i++)
1743 printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
1744 PQgetvalue(result, i, 1),
1745 PQgetvalue(result, i, 0),
1746 PQgetvalue(result, i, 2));
1748 printTableAddFooter(&cont, buf.data);
1755 if (tableinfo.hasrules)
1757 if (pset.sversion >= 80300)
1759 printfPQExpBuffer(&buf,
1760 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
1762 "FROM pg_catalog.pg_rewrite r\n"
1763 "WHERE r.ev_class = '%s' ORDER BY 1",
1768 printfPQExpBuffer(&buf,
1769 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
1770 "'O'::char AS ev_enabled\n"
1771 "FROM pg_catalog.pg_rewrite r\n"
1772 "WHERE r.ev_class = '%s' ORDER BY 1",
1775 result = PSQLexec(buf.data, false);
1779 tuples = PQntuples(result);
1786 for (category = 0; category < 4; category++)
1788 have_heading = false;
1790 for (i = 0; i < tuples; i++)
1792 const char *ruledef;
1793 bool list_rule = false;
1798 if (*PQgetvalue(result, i, 2) == 'O')
1802 if (*PQgetvalue(result, i, 2) == 'D')
1806 if (*PQgetvalue(result, i, 2) == 'A')
1810 if (*PQgetvalue(result, i, 2) == 'R')
1822 printfPQExpBuffer(&buf, _("Rules:"));
1825 printfPQExpBuffer(&buf, _("Disabled rules:"));
1828 printfPQExpBuffer(&buf, _("Rules firing always:"));
1831 printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
1834 printTableAddFooter(&cont, buf.data);
1835 have_heading = true;
1838 /* Everything after "CREATE RULE" is echoed verbatim */
1839 ruledef = PQgetvalue(result, i, 1);
1841 printfPQExpBuffer(&buf, " %s", ruledef);
1842 printTableAddFooter(&cont, buf.data);
1849 /* print triggers (but only user-defined triggers) */
1850 if (tableinfo.hastriggers)
1852 printfPQExpBuffer(&buf,
1854 "pg_catalog.pg_get_triggerdef(t.oid%s), "
1856 "FROM pg_catalog.pg_trigger t\n"
1857 "WHERE t.tgrelid = '%s' AND ",
1858 (pset.sversion >= 90000 ? ", true" : ""),
1860 if (pset.sversion >= 90000)
1861 appendPQExpBuffer(&buf, "NOT t.tgisinternal");
1862 else if (pset.sversion >= 80300)
1863 appendPQExpBuffer(&buf, "t.tgconstraint = 0");
1865 appendPQExpBuffer(&buf,
1866 "(NOT tgisconstraint "
1868 " (SELECT 1 FROM pg_catalog.pg_depend d "
1869 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
1870 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
1871 appendPQExpBuffer(&buf, "\nORDER BY 1");
1873 result = PSQLexec(buf.data, false);
1877 tuples = PQntuples(result);
1885 * split the output into 4 different categories. Enabled
1886 * triggers, disabled triggers and the two special ALWAYS and
1887 * REPLICA configurations.
1889 for (category = 0; category < 4; category++)
1891 have_heading = false;
1892 for (i = 0; i < tuples; i++)
1896 const char *usingpos;
1897 const char *tgenabled;
1900 * Check if this trigger falls into the current
1903 tgenabled = PQgetvalue(result, i, 2);
1904 list_trigger = false;
1908 if (*tgenabled == 'O' || *tgenabled == 't')
1909 list_trigger = true;
1912 if (*tgenabled == 'D' || *tgenabled == 'f')
1913 list_trigger = true;
1916 if (*tgenabled == 'A')
1917 list_trigger = true;
1920 if (*tgenabled == 'R')
1921 list_trigger = true;
1924 if (list_trigger == false)
1927 /* Print the category heading once */
1928 if (have_heading == false)
1933 printfPQExpBuffer(&buf, _("Triggers:"));
1936 printfPQExpBuffer(&buf, _("Disabled triggers:"));
1939 printfPQExpBuffer(&buf, _("Triggers firing always:"));
1942 printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
1946 printTableAddFooter(&cont, buf.data);
1947 have_heading = true;
1950 /* Everything after "TRIGGER" is echoed verbatim */
1951 tgdef = PQgetvalue(result, i, 1);
1952 usingpos = strstr(tgdef, " TRIGGER ");
1954 tgdef = usingpos + 9;
1956 printfPQExpBuffer(&buf, " %s", tgdef);
1957 printTableAddFooter(&cont, buf.data);
1964 /* print inherited tables */
1965 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);
1967 result = PSQLexec(buf.data, false);
1971 tuples = PQntuples(result);
1973 for (i = 0; i < tuples; i++)
1975 const char *s = _("Inherits");
1978 printfPQExpBuffer(&buf, "%s: %s", s, PQgetvalue(result, i, 0));
1980 printfPQExpBuffer(&buf, "%*s %s", (int) strlen(s), "", PQgetvalue(result, i, 0));
1982 appendPQExpBuffer(&buf, ",");
1984 printTableAddFooter(&cont, buf.data);
1988 /* print child tables */
1989 if (pset.sversion >= 80300)
1990 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);
1992 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);
1994 result = PSQLexec(buf.data, false);
1998 tuples = PQntuples(result);
2002 /* print the number of child tables, if any */
2005 printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
2006 printTableAddFooter(&cont, buf.data);
2011 /* display the list of child tables */
2012 const char *ct = _("Child tables");
2014 for (i = 0; i < tuples; i++)
2017 printfPQExpBuffer(&buf, "%s: %s",
2018 ct, PQgetvalue(result, i, 0));
2020 printfPQExpBuffer(&buf, "%*s %s",
2021 (int) strlen(ct), "",
2022 PQgetvalue(result, i, 0));
2024 appendPQExpBuffer(&buf, ",");
2026 printTableAddFooter(&cont, buf.data);
2032 if (tableinfo.reloftype)
2034 printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
2035 printTableAddFooter(&cont, buf.data);
2038 /* OIDs and options */
2041 const char *s = _("Has OIDs");
2043 printfPQExpBuffer(&buf, "%s: %s", s,
2044 (tableinfo.hasoids ? _("yes") : _("no")));
2045 printTableAddFooter(&cont, buf.data);
2047 /* print reloptions */
2048 if (pset.sversion >= 80200)
2050 if (tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
2052 const char *t = _("Options");
2054 printfPQExpBuffer(&buf, "%s: %s", t,
2055 tableinfo.reloptions);
2056 printTableAddFooter(&cont, buf.data);
2061 add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
2065 printTable(&cont, pset.queryFout, pset.logfile);
2066 printTableCleanup(&cont);
2073 if (printTableInitialized)
2074 printTableCleanup(&cont);
2075 termPQExpBuffer(&buf);
2076 termPQExpBuffer(&title);
2077 termPQExpBuffer(&tmpbuf);
2081 for (ptr = seq_values; *ptr; ptr++)
2088 for (ptr = modifiers; *ptr; ptr++)
2103 * Add a tablespace description to a footer. If 'newline' is true, it is added
2104 * in a new line; otherwise it's appended to the current value of the last
2108 add_tablespace_footer(printTableContent *const cont, char relkind,
2109 Oid tablespace, const bool newline)
2111 /* relkinds for which we support tablespaces */
2112 if (relkind == 'r' || relkind == 'i')
2115 * We ignore the database default tablespace so that users not using
2116 * tablespaces don't need to know about them. This case also covers
2117 * pre-8.0 servers, for which tablespace will always be 0.
2119 if (tablespace != 0)
2121 PGresult *result = NULL;
2122 PQExpBufferData buf;
2124 initPQExpBuffer(&buf);
2125 printfPQExpBuffer(&buf,
2126 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
2127 "WHERE oid = '%u'", tablespace);
2128 result = PSQLexec(buf.data, false);
2131 /* Should always be the case, but.... */
2132 if (PQntuples(result) > 0)
2136 /* Add the tablespace as a new footer */
2137 printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
2138 PQgetvalue(result, 0, 0));
2139 printTableAddFooter(cont, buf.data);
2143 /* Append the tablespace to the latest footer */
2144 printfPQExpBuffer(&buf, "%s", cont->footer->data);
2147 * translator: before this string there's an index
2148 * description like '"foo_pkey" PRIMARY KEY, btree (a)'
2150 appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
2151 PQgetvalue(result, 0, 0));
2152 printTableSetFooter(cont, buf.data);
2156 termPQExpBuffer(&buf);
2164 * Describes roles. Any schema portion of the pattern is ignored.
2167 describeRoles(const char *pattern, bool verbose)
2169 PQExpBufferData buf;
2171 printTableContent cont;
2172 printTableOpt myopt = pset.popt.topt;
2177 const char align = 'l';
2180 initPQExpBuffer(&buf);
2182 if (pset.sversion >= 80100)
2184 printfPQExpBuffer(&buf,
2185 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
2186 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
2187 " r.rolconnlimit,\n"
2188 " ARRAY(SELECT b.rolname\n"
2189 " FROM pg_catalog.pg_auth_members m\n"
2190 " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
2191 " WHERE m.member = r.oid) as memberof");
2193 if (verbose && pset.sversion >= 80200)
2195 appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
2199 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
2201 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2202 NULL, "r.rolname", NULL, NULL);
2206 printfPQExpBuffer(&buf,
2207 "SELECT u.usename AS rolname,\n"
2208 " u.usesuper AS rolsuper,\n"
2209 " true AS rolinherit, false AS rolcreaterole,\n"
2210 " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
2211 " -1 AS rolconnlimit,\n"
2212 " ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
2213 "\nFROM pg_catalog.pg_user u\n");
2215 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2216 NULL, "u.usename", NULL, NULL);
2219 appendPQExpBuffer(&buf, "ORDER BY 1;");
2221 res = PSQLexec(buf.data, false);
2225 nrows = PQntuples(res);
2226 attr = pg_malloc_zero((nrows + 1) * sizeof(*attr));
2228 printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
2230 printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
2231 printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
2232 printTableAddHeader(&cont, gettext_noop("Member of"), true, align);
2234 if (verbose && pset.sversion >= 80200)
2235 printTableAddHeader(&cont, gettext_noop("Description"), true, align);
2237 for (i = 0; i < nrows; i++)
2239 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
2241 resetPQExpBuffer(&buf);
2242 if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
2243 add_role_attribute(&buf, _("Superuser"));
2245 if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
2246 add_role_attribute(&buf, _("No inheritance"));
2248 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
2249 add_role_attribute(&buf, _("Create role"));
2251 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
2252 add_role_attribute(&buf, _("Create DB"));
2254 if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
2255 add_role_attribute(&buf, _("Cannot login"));
2257 conns = atoi(PQgetvalue(res, i, 6));
2261 appendPQExpBufferStr(&buf, "\n");
2264 appendPQExpBuffer(&buf, _("No connections"));
2266 appendPQExpBuffer(&buf, ngettext("%d connection",
2272 attr[i] = pg_strdup(buf.data);
2274 printTableAddCell(&cont, attr[i], false, false);
2276 printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
2278 if (verbose && pset.sversion >= 80200)
2279 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
2281 termPQExpBuffer(&buf);
2283 printTable(&cont, pset.queryFout, pset.logfile);
2284 printTableCleanup(&cont);
2286 for (i = 0; i < nrows; i++)
2295 add_role_attribute(PQExpBuffer buf, const char *const str)
2298 appendPQExpBufferStr(buf, ", ");
2300 appendPQExpBufferStr(buf, str);
2307 listDbRoleSettings(const char *pattern, const char *pattern2)
2309 PQExpBufferData buf;
2311 printQueryOpt myopt = pset.popt;
2313 initPQExpBuffer(&buf);
2315 if (pset.sversion >= 90000)
2319 printfPQExpBuffer(&buf, "SELECT rolname AS role, datname AS database,\n"
2320 "pg_catalog.array_to_string(setconfig, E'\\n') AS settings\n"
2321 "FROM pg_db_role_setting AS s\n"
2322 "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n"
2323 "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n");
2324 havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
2325 NULL, "pg_roles.rolname", NULL, NULL);
2326 processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
2327 NULL, "pg_database.datname", NULL, NULL);
2328 appendPQExpBufferStr(&buf, "ORDER BY role, database");
2332 fprintf(pset.queryFout,
2333 _("No per-database role settings support in this server version.\n"));
2337 res = PSQLexec(buf.data, false);
2341 if (PQntuples(res) == 0 && !pset.quiet)
2344 fprintf(pset.queryFout, _("No matching settings found.\n"));
2346 fprintf(pset.queryFout, _("No settings found.\n"));
2350 myopt.nullPrint = NULL;
2351 myopt.title = _("List of settings");
2352 myopt.translate_header = true;
2354 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2358 resetPQExpBuffer(&buf);
2366 * handler for \dt, \di, etc.
2368 * tabtypes is an array of characters, specifying what info is desired:
2373 * (any order of the above is fine)
2374 * If tabtypes is empty, we default to \dtvs.
2377 listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
2379 bool showTables = strchr(tabtypes, 't') != NULL;
2380 bool showIndexes = strchr(tabtypes, 'i') != NULL;
2381 bool showViews = strchr(tabtypes, 'v') != NULL;
2382 bool showSeq = strchr(tabtypes, 's') != NULL;
2384 PQExpBufferData buf;
2386 printQueryOpt myopt = pset.popt;
2387 static const bool translate_columns[] = {false, false, true, false, false, false, false};
2389 if (!(showTables || showIndexes || showViews || showSeq))
2390 showTables = showViews = showSeq = true;
2392 initPQExpBuffer(&buf);
2395 * Note: as of Pg 8.2, we no longer use relkind 's', but we keep it here
2396 * for backwards compatibility.
2398 printfPQExpBuffer(&buf,
2399 "SELECT n.nspname as \"%s\",\n"
2400 " c.relname as \"%s\",\n"
2401 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' WHEN 's' THEN '%s' END as \"%s\",\n"
2402 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
2403 gettext_noop("Schema"),
2404 gettext_noop("Name"),
2405 gettext_noop("table"),
2406 gettext_noop("view"),
2407 gettext_noop("index"),
2408 gettext_noop("sequence"),
2409 gettext_noop("special"),
2410 gettext_noop("Type"),
2411 gettext_noop("Owner"));
2414 appendPQExpBuffer(&buf,
2415 ",\n c2.relname as \"%s\"",
2416 gettext_noop("Table"));
2418 if (verbose && pset.sversion >= 80100)
2419 appendPQExpBuffer(&buf,
2420 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
2421 gettext_noop("Size"));
2423 appendPQExpBuffer(&buf,
2424 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
2425 gettext_noop("Description"));
2427 appendPQExpBuffer(&buf,
2428 "\nFROM pg_catalog.pg_class c"
2429 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
2431 appendPQExpBuffer(&buf,
2432 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
2433 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
2435 appendPQExpBuffer(&buf, "\nWHERE c.relkind IN (");
2437 appendPQExpBuffer(&buf, "'r',");
2439 appendPQExpBuffer(&buf, "'v',");
2441 appendPQExpBuffer(&buf, "'i',");
2443 appendPQExpBuffer(&buf, "'S',");
2444 if (showSystem || pattern)
2445 appendPQExpBuffer(&buf, "'s',"); /* was RELKIND_SPECIAL in <=
2447 appendPQExpBuffer(&buf, "''"); /* dummy */
2448 appendPQExpBuffer(&buf, ")\n");
2450 if (!showSystem && !pattern)
2451 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
2452 " AND n.nspname <> 'information_schema'\n");
2455 * TOAST objects are suppressed unconditionally. Since we don't provide
2456 * any way to select relkind 't' above, we would never show toast tables
2457 * in any case; it seems a bit confusing to allow their indexes to be
2458 * shown. Use plain \d if you really need to look at a TOAST table/index.
2460 appendPQExpBuffer(&buf, " AND n.nspname !~ '^pg_toast'\n");
2462 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2463 "n.nspname", "c.relname", NULL,
2464 "pg_catalog.pg_table_is_visible(c.oid)");
2466 appendPQExpBuffer(&buf, "ORDER BY 1,2;");
2468 res = PSQLexec(buf.data, false);
2469 termPQExpBuffer(&buf);
2473 if (PQntuples(res) == 0 && !pset.quiet)
2476 fprintf(pset.queryFout, _("No matching relations found.\n"));
2478 fprintf(pset.queryFout, _("No relations found.\n"));
2482 myopt.nullPrint = NULL;
2483 myopt.title = _("List of relations");
2484 myopt.translate_header = true;
2485 myopt.translate_columns = translate_columns;
2487 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2498 * Describes domains.
2501 listDomains(const char *pattern, bool showSystem)
2503 PQExpBufferData buf;
2505 printQueryOpt myopt = pset.popt;
2507 initPQExpBuffer(&buf);
2509 printfPQExpBuffer(&buf,
2510 "SELECT n.nspname as \"%s\",\n"
2511 " t.typname as \"%s\",\n"
2512 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
2513 " CASE WHEN t.typnotnull AND t.typdefault IS NOT NULL THEN 'not null default '||t.typdefault\n"
2514 " WHEN t.typnotnull AND t.typdefault IS NULL THEN 'not null'\n"
2515 " WHEN NOT t.typnotnull AND t.typdefault IS NOT NULL THEN 'default '||t.typdefault\n"
2518 " pg_catalog.array_to_string(ARRAY(\n"
2519 " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
2520 " ), ' ') as \"%s\"\n"
2521 "FROM pg_catalog.pg_type t\n"
2522 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
2523 "WHERE t.typtype = 'd'\n",
2524 gettext_noop("Schema"),
2525 gettext_noop("Name"),
2526 gettext_noop("Type"),
2527 gettext_noop("Modifier"),
2528 gettext_noop("Check"));
2530 if (!showSystem && !pattern)
2531 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
2532 " AND n.nspname <> 'information_schema'\n");
2534 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2535 "n.nspname", "t.typname", NULL,
2536 "pg_catalog.pg_type_is_visible(t.oid)");
2538 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
2540 res = PSQLexec(buf.data, false);
2541 termPQExpBuffer(&buf);
2545 myopt.nullPrint = NULL;
2546 myopt.title = _("List of domains");
2547 myopt.translate_header = true;
2549 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2558 * Describes conversions.
2561 listConversions(const char *pattern, bool showSystem)
2563 PQExpBufferData buf;
2565 printQueryOpt myopt = pset.popt;
2566 static const bool translate_columns[] = {false, false, false, false, true};
2568 initPQExpBuffer(&buf);
2570 printfPQExpBuffer(&buf,
2571 "SELECT n.nspname AS \"%s\",\n"
2572 " c.conname AS \"%s\",\n"
2573 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
2574 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
2575 " CASE WHEN c.condefault THEN '%s'\n"
2576 " ELSE '%s' END AS \"%s\"\n"
2577 "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
2578 "WHERE n.oid = c.connamespace\n",
2579 gettext_noop("Schema"),
2580 gettext_noop("Name"),
2581 gettext_noop("Source"),
2582 gettext_noop("Destination"),
2583 gettext_noop("yes"), gettext_noop("no"),
2584 gettext_noop("Default?"));
2586 if (!showSystem && !pattern)
2587 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
2588 " AND n.nspname <> 'information_schema'\n");
2590 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2591 "n.nspname", "c.conname", NULL,
2592 "pg_catalog.pg_conversion_is_visible(c.oid)");
2594 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
2596 res = PSQLexec(buf.data, false);
2597 termPQExpBuffer(&buf);
2601 myopt.nullPrint = NULL;
2602 myopt.title = _("List of conversions");
2603 myopt.translate_header = true;
2604 myopt.translate_columns = translate_columns;
2606 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2618 listCasts(const char *pattern)
2620 PQExpBufferData buf;
2622 printQueryOpt myopt = pset.popt;
2623 static const bool translate_columns[] = {false, false, false, true};
2625 initPQExpBuffer(&buf);
2628 * We need a left join to pg_proc for binary casts; the others are just
2629 * paranoia. Also note that we don't attempt to localize '(binary
2630 * coercible)', because there's too much risk of gettext translating a
2631 * function name that happens to match some string in the PO database.
2633 printfPQExpBuffer(&buf,
2634 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
2635 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
2636 " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
2639 " CASE WHEN c.castcontext = 'e' THEN '%s'\n"
2640 " WHEN c.castcontext = 'a' THEN '%s'\n"
2643 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
2644 " ON c.castfunc = p.oid\n"
2645 " LEFT JOIN pg_catalog.pg_type ts\n"
2646 " ON c.castsource = ts.oid\n"
2647 " LEFT JOIN pg_catalog.pg_namespace ns\n"
2648 " ON ns.oid = ts.typnamespace\n"
2649 " LEFT JOIN pg_catalog.pg_type tt\n"
2650 " ON c.casttarget = tt.oid\n"
2651 " LEFT JOIN pg_catalog.pg_namespace nt\n"
2652 " ON nt.oid = tt.typnamespace\n"
2654 gettext_noop("Source type"),
2655 gettext_noop("Target type"),
2656 gettext_noop("Function"),
2657 gettext_noop("no"), gettext_noop("in assignment"), gettext_noop("yes"),
2658 gettext_noop("Implicit?"));
2661 * Match name pattern against either internal or external name of either
2662 * castsource or casttarget
2664 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2665 "ns.nspname", "ts.typname",
2666 "pg_catalog.format_type(ts.oid, NULL)",
2667 "pg_catalog.pg_type_is_visible(ts.oid)");
2669 appendPQExpBuffer(&buf, ") OR (true");
2671 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2672 "nt.nspname", "tt.typname",
2673 "pg_catalog.format_type(tt.oid, NULL)",
2674 "pg_catalog.pg_type_is_visible(tt.oid)");
2676 appendPQExpBuffer(&buf, ")\nORDER BY 1, 2;");
2678 res = PSQLexec(buf.data, false);
2679 termPQExpBuffer(&buf);
2683 myopt.nullPrint = NULL;
2684 myopt.title = _("List of casts");
2685 myopt.translate_header = true;
2686 myopt.translate_columns = translate_columns;
2688 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2697 * Describes schemas (namespaces)
2700 listSchemas(const char *pattern, bool verbose)
2702 PQExpBufferData buf;
2704 printQueryOpt myopt = pset.popt;
2706 initPQExpBuffer(&buf);
2707 printfPQExpBuffer(&buf,
2708 "SELECT n.nspname AS \"%s\",\n"
2709 " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
2710 gettext_noop("Name"),
2711 gettext_noop("Owner"));
2715 appendPQExpBuffer(&buf, ",\n ");
2716 printACLColumn(&buf, "n.nspacl");
2717 appendPQExpBuffer(&buf,
2718 ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
2719 gettext_noop("Description"));
2722 appendPQExpBuffer(&buf,
2723 "\nFROM pg_catalog.pg_namespace n\n"
2724 "WHERE (n.nspname !~ '^pg_temp_' OR\n"
2725 " n.nspname = (pg_catalog.current_schemas(true))[1])\n"); /* temp schema is first */
2727 processSQLNamePattern(pset.db, &buf, pattern, true, false,
2728 NULL, "n.nspname", NULL,
2731 appendPQExpBuffer(&buf, "ORDER BY 1;");
2733 res = PSQLexec(buf.data, false);
2734 termPQExpBuffer(&buf);
2738 myopt.nullPrint = NULL;
2739 myopt.title = _("List of schemas");
2740 myopt.translate_header = true;
2742 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2751 * list text search parsers
2754 listTSParsers(const char *pattern, bool verbose)
2756 PQExpBufferData buf;
2758 printQueryOpt myopt = pset.popt;
2760 if (pset.sversion < 80300)
2762 fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
2763 pset.sversion / 10000, (pset.sversion / 100) % 100);
2768 return listTSParsersVerbose(pattern);
2770 initPQExpBuffer(&buf);
2772 printfPQExpBuffer(&buf,
2774 " n.nspname as \"%s\",\n"
2775 " p.prsname as \"%s\",\n"
2776 " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
2777 "FROM pg_catalog.pg_ts_parser p \n"
2778 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
2779 gettext_noop("Schema"),
2780 gettext_noop("Name"),
2781 gettext_noop("Description")
2784 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2785 "n.nspname", "p.prsname", NULL,
2786 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
2788 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
2790 res = PSQLexec(buf.data, false);
2791 termPQExpBuffer(&buf);
2795 myopt.nullPrint = NULL;
2796 myopt.title = _("List of text search parsers");
2797 myopt.translate_header = true;
2799 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2806 * full description of parsers
2809 listTSParsersVerbose(const char *pattern)
2811 PQExpBufferData buf;
2815 initPQExpBuffer(&buf);
2817 printfPQExpBuffer(&buf,
2821 "FROM pg_catalog.pg_ts_parser p\n"
2822 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
2825 processSQLNamePattern(pset.db, &buf, pattern, false, false,
2826 "n.nspname", "p.prsname", NULL,
2827 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
2829 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
2831 res = PSQLexec(buf.data, false);
2832 termPQExpBuffer(&buf);
2836 if (PQntuples(res) == 0)
2839 fprintf(stderr, _("Did not find any text search parser named \"%s\".\n"),
2845 for (i = 0; i < PQntuples(res); i++)
2848 const char *nspname = NULL;
2849 const char *prsname;
2851 oid = PQgetvalue(res, i, 0);
2852 if (!PQgetisnull(res, i, 1))
2853 nspname = PQgetvalue(res, i, 1);
2854 prsname = PQgetvalue(res, i, 2);
2856 if (!describeOneTSParser(oid, nspname, prsname))
2874 describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
2876 PQExpBufferData buf;
2879 printQueryOpt myopt = pset.popt;
2880 static const bool translate_columns[] = {true, false, false};
2882 initPQExpBuffer(&buf);
2884 printfPQExpBuffer(&buf,
2885 "SELECT '%s' AS \"%s\", \n"
2886 " p.prsstart::pg_catalog.regproc AS \"%s\", \n"
2887 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\" \n"
2888 " FROM pg_catalog.pg_ts_parser p \n"
2889 " WHERE p.oid = '%s' \n"
2892 " p.prstoken::pg_catalog.regproc, \n"
2893 " pg_catalog.obj_description(p.prstoken, 'pg_proc') \n"
2894 " FROM pg_catalog.pg_ts_parser p \n"
2895 " WHERE p.oid = '%s' \n"
2898 " p.prsend::pg_catalog.regproc, \n"
2899 " pg_catalog.obj_description(p.prsend, 'pg_proc') \n"
2900 " FROM pg_catalog.pg_ts_parser p \n"
2901 " WHERE p.oid = '%s' \n"
2904 " p.prsheadline::pg_catalog.regproc, \n"
2905 " pg_catalog.obj_description(p.prsheadline, 'pg_proc') \n"
2906 " FROM pg_catalog.pg_ts_parser p \n"
2907 " WHERE p.oid = '%s' \n"
2910 " p.prslextype::pg_catalog.regproc, \n"
2911 " pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
2912 " FROM pg_catalog.pg_ts_parser p \n"
2913 " WHERE p.oid = '%s' \n",
2914 gettext_noop("Start parse"),
2915 gettext_noop("Method"),
2916 gettext_noop("Function"),
2917 gettext_noop("Description"),
2919 gettext_noop("Get next token"),
2921 gettext_noop("End parse"),
2923 gettext_noop("Get headline"),
2925 gettext_noop("Get token types"),
2928 res = PSQLexec(buf.data, false);
2929 termPQExpBuffer(&buf);
2933 myopt.nullPrint = NULL;
2935 sprintf(title, _("Text search parser \"%s.%s\""), nspname, prsname);
2937 sprintf(title, _("Text search parser \"%s\""), prsname);
2938 myopt.title = title;
2939 myopt.footers = NULL;
2940 myopt.default_footer = false;
2941 myopt.translate_header = true;
2942 myopt.translate_columns = translate_columns;
2944 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2948 initPQExpBuffer(&buf);
2950 printfPQExpBuffer(&buf,
2951 "SELECT t.alias as \"%s\", \n"
2952 " t.description as \"%s\" \n"
2953 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
2955 gettext_noop("Token name"),
2956 gettext_noop("Description"),
2959 res = PSQLexec(buf.data, false);
2960 termPQExpBuffer(&buf);
2964 myopt.nullPrint = NULL;
2966 sprintf(title, _("Token types for parser \"%s.%s\""), nspname, prsname);
2968 sprintf(title, _("Token types for parser \"%s\""), prsname);
2969 myopt.title = title;
2970 myopt.footers = NULL;
2971 myopt.default_footer = true;
2972 myopt.translate_header = true;
2973 myopt.translate_columns = NULL;
2975 printQuery(res, &myopt, pset.queryFout, pset.logfile);
2984 * list text search dictionaries
2987 listTSDictionaries(const char *pattern, bool verbose)
2989 PQExpBufferData buf;
2991 printQueryOpt myopt = pset.popt;
2993 if (pset.sversion < 80300)
2995 fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
2996 pset.sversion / 10000, (pset.sversion / 100) % 100);
3000 initPQExpBuffer(&buf);
3002 printfPQExpBuffer(&buf,
3004 " n.nspname as \"%s\",\n"
3005 " d.dictname as \"%s\",\n",
3006 gettext_noop("Schema"),
3007 gettext_noop("Name"));
3011 appendPQExpBuffer(&buf,
3012 " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM \n"
3013 " pg_catalog.pg_ts_template t \n"
3014 " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
3015 " WHERE d.dicttemplate = t.oid ) AS \"%s\", \n"
3016 " d.dictinitoption as \"%s\", \n",
3017 gettext_noop("Template"),
3018 gettext_noop("Init options"));
3021 appendPQExpBuffer(&buf,
3022 " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
3023 gettext_noop("Description"));
3025 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_dict d\n"
3026 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
3028 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3029 "n.nspname", "d.dictname", NULL,
3030 "pg_catalog.pg_ts_dict_is_visible(d.oid)");
3032 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3034 res = PSQLexec(buf.data, false);
3035 termPQExpBuffer(&buf);
3039 myopt.nullPrint = NULL;
3040 myopt.title = _("List of text search dictionaries");
3041 myopt.translate_header = true;
3043 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3052 * list text search templates
3055 listTSTemplates(const char *pattern, bool verbose)
3057 PQExpBufferData buf;
3059 printQueryOpt myopt = pset.popt;
3061 if (pset.sversion < 80300)
3063 fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
3064 pset.sversion / 10000, (pset.sversion / 100) % 100);
3068 initPQExpBuffer(&buf);
3071 printfPQExpBuffer(&buf,
3073 " n.nspname AS \"%s\",\n"
3074 " t.tmplname AS \"%s\",\n"
3075 " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
3076 " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
3077 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
3078 gettext_noop("Schema"),
3079 gettext_noop("Name"),
3080 gettext_noop("Init"),
3081 gettext_noop("Lexize"),
3082 gettext_noop("Description"));
3084 printfPQExpBuffer(&buf,
3086 " n.nspname AS \"%s\",\n"
3087 " t.tmplname AS \"%s\",\n"
3088 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
3089 gettext_noop("Schema"),
3090 gettext_noop("Name"),
3091 gettext_noop("Description"));
3093 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_template t\n"
3094 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
3096 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3097 "n.nspname", "t.tmplname", NULL,
3098 "pg_catalog.pg_ts_template_is_visible(t.oid)");
3100 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3102 res = PSQLexec(buf.data, false);
3103 termPQExpBuffer(&buf);
3107 myopt.nullPrint = NULL;
3108 myopt.title = _("List of text search templates");
3109 myopt.translate_header = true;
3111 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3120 * list text search configurations
3123 listTSConfigs(const char *pattern, bool verbose)
3125 PQExpBufferData buf;
3127 printQueryOpt myopt = pset.popt;
3129 if (pset.sversion < 80300)
3131 fprintf(stderr, _("The server (version %d.%d) does not support full text search.\n"),
3132 pset.sversion / 10000, (pset.sversion / 100) % 100);
3137 return listTSConfigsVerbose(pattern);
3139 initPQExpBuffer(&buf);
3141 printfPQExpBuffer(&buf,
3143 " n.nspname as \"%s\",\n"
3144 " c.cfgname as \"%s\",\n"
3145 " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
3146 "FROM pg_catalog.pg_ts_config c\n"
3147 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
3148 gettext_noop("Schema"),
3149 gettext_noop("Name"),
3150 gettext_noop("Description")
3153 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3154 "n.nspname", "c.cfgname", NULL,
3155 "pg_catalog.pg_ts_config_is_visible(c.oid)");
3157 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3159 res = PSQLexec(buf.data, false);
3160 termPQExpBuffer(&buf);
3164 myopt.nullPrint = NULL;
3165 myopt.title = _("List of text search configurations");
3166 myopt.translate_header = true;
3168 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3175 listTSConfigsVerbose(const char *pattern)
3177 PQExpBufferData buf;
3181 initPQExpBuffer(&buf);
3183 printfPQExpBuffer(&buf,
3184 "SELECT c.oid, c.cfgname,\n"
3187 " np.nspname as pnspname \n"
3188 "FROM pg_catalog.pg_ts_config c \n"
3189 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace, \n"
3190 " pg_catalog.pg_ts_parser p \n"
3191 " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace \n"
3192 "WHERE p.oid = c.cfgparser\n"
3195 processSQLNamePattern(pset.db, &buf, pattern, true, false,
3196 "n.nspname", "c.cfgname", NULL,
3197 "pg_catalog.pg_ts_config_is_visible(c.oid)");
3199 appendPQExpBuffer(&buf, "ORDER BY 3, 2;");
3201 res = PSQLexec(buf.data, false);
3202 termPQExpBuffer(&buf);
3206 if (PQntuples(res) == 0)
3209 fprintf(stderr, _("Did not find any text search configuration named \"%s\".\n"),
3215 for (i = 0; i < PQntuples(res); i++)
3218 const char *cfgname;
3219 const char *nspname = NULL;
3220 const char *prsname;
3221 const char *pnspname = NULL;
3223 oid = PQgetvalue(res, i, 0);
3224 cfgname = PQgetvalue(res, i, 1);
3225 if (!PQgetisnull(res, i, 2))
3226 nspname = PQgetvalue(res, i, 2);
3227 prsname = PQgetvalue(res, i, 3);
3228 if (!PQgetisnull(res, i, 4))
3229 pnspname = PQgetvalue(res, i, 4);
3231 if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname))
3249 describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
3250 const char *pnspname, const char *prsname)
3252 PQExpBufferData buf,
3255 printQueryOpt myopt = pset.popt;
3257 initPQExpBuffer(&buf);
3259 printfPQExpBuffer(&buf,
3261 " ( SELECT t.alias FROM \n"
3262 " pg_catalog.ts_token_type(c.cfgparser) AS t \n"
3263 " WHERE t.tokid = m.maptokentype ) AS \"%s\", \n"
3264 " pg_catalog.btrim( \n"
3265 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary \n"
3266 " FROM pg_catalog.pg_ts_config_map AS mm \n"
3267 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype \n"
3268 " ORDER BY mapcfg, maptokentype, mapseqno \n"
3269 " ) :: pg_catalog.text , \n"
3270 " '{}') AS \"%s\" \n"
3271 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n"
3272 "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
3273 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
3275 gettext_noop("Token"),
3276 gettext_noop("Dictionaries"),
3279 res = PSQLexec(buf.data, false);
3280 termPQExpBuffer(&buf);
3284 initPQExpBuffer(&title);
3287 appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
3290 appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
3294 appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
3297 appendPQExpBuffer(&title, _("\nParser: \"%s\""),
3300 myopt.nullPrint = NULL;
3301 myopt.title = title.data;
3302 myopt.footers = NULL;
3303 myopt.default_footer = false;
3304 myopt.translate_header = true;
3306 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3308 termPQExpBuffer(&title);
3318 * Describes foreign-data wrappers
3321 listForeignDataWrappers(const char *pattern, bool verbose)
3323 PQExpBufferData buf;
3325 printQueryOpt myopt = pset.popt;
3327 if (pset.sversion < 80400)
3329 fprintf(stderr, _("The server (version %d.%d) does not support foreign-data wrappers.\n"),
3330 pset.sversion / 10000, (pset.sversion / 100) % 100);
3334 initPQExpBuffer(&buf);
3335 printfPQExpBuffer(&buf,
3336 "SELECT fdwname AS \"%s\",\n"
3337 " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n"
3338 " fdwvalidator::pg_catalog.regproc AS \"%s\"",
3339 gettext_noop("Name"),
3340 gettext_noop("Owner"),
3341 gettext_noop("Validator"));
3345 appendPQExpBuffer(&buf, ",\n ");
3346 printACLColumn(&buf, "fdwacl");
3347 appendPQExpBuffer(&buf,
3348 ",\n fdwoptions AS \"%s\"",
3349 gettext_noop("Options"));
3352 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper\n");
3354 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3355 NULL, "fdwname", NULL, NULL);
3357 appendPQExpBuffer(&buf, "ORDER BY 1;");
3359 res = PSQLexec(buf.data, false);
3360 termPQExpBuffer(&buf);
3364 myopt.nullPrint = NULL;
3365 myopt.title = _("List of foreign-data wrappers");
3366 myopt.translate_header = true;
3368 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3377 * Describes foreign servers.
3380 listForeignServers(const char *pattern, bool verbose)
3382 PQExpBufferData buf;
3384 printQueryOpt myopt = pset.popt;
3386 if (pset.sversion < 80400)
3388 fprintf(stderr, _("The server (version %d.%d) does not support foreign servers.\n"),
3389 pset.sversion / 10000, (pset.sversion / 100) % 100);
3393 initPQExpBuffer(&buf);
3394 printfPQExpBuffer(&buf,
3395 "SELECT s.srvname AS \"%s\",\n"
3396 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
3397 " f.fdwname AS \"%s\"",
3398 gettext_noop("Name"),
3399 gettext_noop("Owner"),
3400 gettext_noop("Foreign-data wrapper"));
3404 appendPQExpBuffer(&buf, ",\n ");
3405 printACLColumn(&buf, "s.srvacl");
3406 appendPQExpBuffer(&buf,
3408 " s.srvtype AS \"%s\",\n"
3409 " s.srvversion AS \"%s\",\n"
3410 " s.srvoptions AS \"%s\"",
3411 gettext_noop("Type"),
3412 gettext_noop("Version"),
3413 gettext_noop("Options"));
3416 appendPQExpBuffer(&buf,
3417 "\nFROM pg_catalog.pg_foreign_server s\n"
3418 " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
3420 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3421 NULL, "s.srvname", NULL, NULL);
3423 appendPQExpBuffer(&buf, "ORDER BY 1;");
3425 res = PSQLexec(buf.data, false);
3426 termPQExpBuffer(&buf);
3430 myopt.nullPrint = NULL;
3431 myopt.title = _("List of foreign servers");
3432 myopt.translate_header = true;
3434 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3443 * Describes user mappings.
3446 listUserMappings(const char *pattern, bool verbose)
3448 PQExpBufferData buf;
3450 printQueryOpt myopt = pset.popt;
3452 if (pset.sversion < 80400)
3454 fprintf(stderr, _("The server (version %d.%d) does not support user mappings.\n"),
3455 pset.sversion / 10000, (pset.sversion / 100) % 100);
3459 initPQExpBuffer(&buf);
3460 printfPQExpBuffer(&buf,
3461 "SELECT um.srvname AS \"%s\",\n"
3462 " um.usename AS \"%s\"",
3463 gettext_noop("Server"),
3464 gettext_noop("User name"));
3467 appendPQExpBuffer(&buf,
3468 ",\n um.umoptions AS \"%s\"",
3469 gettext_noop("Options"));
3471 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
3473 processSQLNamePattern(pset.db, &buf, pattern, false, false,
3474 NULL, "um.srvname", "um.usename", NULL);
3476 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
3478 res = PSQLexec(buf.data, false);
3479 termPQExpBuffer(&buf);
3483 myopt.nullPrint = NULL;
3484 myopt.title = _("List of user mappings");
3485 myopt.translate_header = true;
3487 printQuery(res, &myopt, pset.queryFout, pset.logfile);
3496 * Helper function for consistently formatting ACL (privilege) columns.
3497 * The proper targetlist entry is appended to buf. Note lack of any
3498 * whitespace or comma decoration.
3501 printACLColumn(PQExpBuffer buf, const char *colname)
3503 if (pset.sversion >= 80100)
3504 appendPQExpBuffer(buf,
3505 "pg_catalog.array_to_string(%s, E'\\n') AS \"%s\"",
3506 colname, gettext_noop("Access privileges"));
3508 appendPQExpBuffer(buf,
3509 "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"",
3510 colname, gettext_noop("Access privileges"));