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-2009, PostgreSQL Global Development Group
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"));
98 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
100 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
101 "n.nspname", "p.proname", NULL
,
102 "pg_catalog.pg_function_is_visible(p.oid)");
104 appendPQExpBuffer(&buf
, "ORDER BY 1, 2, 4;");
106 res
= PSQLexec(buf
.data
, false);
107 termPQExpBuffer(&buf
);
111 myopt
.nullPrint
= NULL
;
112 myopt
.title
= _("List of aggregate functions");
113 myopt
.translate_header
= true;
115 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
122 * Takes an optional regexp to select particular tablespaces
125 describeTablespaces(const char *pattern
, bool verbose
)
129 printQueryOpt myopt
= pset
.popt
;
131 if (pset
.sversion
< 80000)
133 fprintf(stderr
, _("The server (version %d.%d) does not support tablespaces.\n"),
134 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
138 initPQExpBuffer(&buf
);
140 printfPQExpBuffer(&buf
,
141 "SELECT spcname AS \"%s\",\n"
142 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
143 " spclocation AS \"%s\"",
144 gettext_noop("Name"),
145 gettext_noop("Owner"),
146 gettext_noop("Location"));
150 appendPQExpBuffer(&buf
, ",\n ");
151 printACLColumn(&buf
, "spcacl");
154 if (verbose
&& pset
.sversion
>= 80200)
155 appendPQExpBuffer(&buf
,
156 ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
157 gettext_noop("Description"));
159 appendPQExpBuffer(&buf
,
160 "\nFROM pg_catalog.pg_tablespace\n");
162 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
163 NULL
, "spcname", NULL
,
166 appendPQExpBuffer(&buf
, "ORDER BY 1;");
168 res
= PSQLexec(buf
.data
, false);
169 termPQExpBuffer(&buf
);
173 myopt
.nullPrint
= NULL
;
174 myopt
.title
= _("List of tablespaces");
175 myopt
.translate_header
= true;
177 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
185 * Takes an optional regexp to select particular functions
188 describeFunctions(const char *pattern
, bool verbose
, bool showSystem
)
192 printQueryOpt myopt
= pset
.popt
;
194 initPQExpBuffer(&buf
);
196 printfPQExpBuffer(&buf
,
197 "SELECT n.nspname as \"%s\",\n"
198 " p.proname as \"%s\",\n",
199 gettext_noop("Schema"),
200 gettext_noop("Name"));
202 if (pset
.sversion
>= 80400)
203 appendPQExpBuffer(&buf
,
204 " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
205 " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\"",
206 gettext_noop("Result data type"),
207 gettext_noop("Argument data types"));
208 else if (pset
.sversion
>= 80100)
209 appendPQExpBuffer(&buf
,
210 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
211 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
212 " CASE WHEN proallargtypes IS NOT NULL THEN\n"
213 " pg_catalog.array_to_string(ARRAY(\n"
216 " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
217 " WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
218 " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
219 " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
222 " WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
223 " ELSE p.proargnames[s.i] || ' ' \n"
225 " pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
227 " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
230 " pg_catalog.array_to_string(ARRAY(\n"
233 " WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
234 " ELSE p.proargnames[s.i+1] || ' '\n"
236 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
238 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
241 gettext_noop("Result data type"),
242 gettext_noop("Argument data types"));
244 appendPQExpBuffer(&buf
,
245 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
246 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
247 " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\"",
248 gettext_noop("Result data type"),
249 gettext_noop("Argument data types"));
252 appendPQExpBuffer(&buf
,
254 " WHEN p.provolatile = 'i' THEN 'immutable'\n"
255 " WHEN p.provolatile = 's' THEN 'stable'\n"
256 " WHEN p.provolatile = 'v' THEN 'volatile'\n"
258 ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\",\n"
259 " l.lanname as \"%s\",\n"
260 " p.prosrc as \"%s\",\n"
261 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
262 gettext_noop("Volatility"),
263 gettext_noop("Owner"),
264 gettext_noop("Language"),
265 gettext_noop("Source code"),
266 gettext_noop("Description"));
268 appendPQExpBuffer(&buf
,
269 "\nFROM pg_catalog.pg_proc p"
270 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
273 appendPQExpBuffer(&buf
,
274 " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
277 * we skip in/out funcs by excluding functions that take or return cstring
279 appendPQExpBuffer(&buf
,
280 "WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n"
281 " AND p.proargtypes[0] IS DISTINCT FROM 'pg_catalog.cstring'::pg_catalog.regtype\n"
282 " AND NOT p.proisagg\n");
285 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
287 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
288 "n.nspname", "p.proname", NULL
,
289 "pg_catalog.pg_function_is_visible(p.oid)");
291 appendPQExpBuffer(&buf
, "ORDER BY 1, 2, 4;");
293 res
= PSQLexec(buf
.data
, false);
294 termPQExpBuffer(&buf
);
298 myopt
.nullPrint
= NULL
;
299 myopt
.title
= _("List of functions");
300 myopt
.translate_header
= true;
302 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
315 describeTypes(const char *pattern
, bool verbose
, bool showSystem
)
319 printQueryOpt myopt
= pset
.popt
;
321 initPQExpBuffer(&buf
);
323 printfPQExpBuffer(&buf
,
324 "SELECT n.nspname as \"%s\",\n"
325 " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
326 gettext_noop("Schema"),
327 gettext_noop("Name"));
329 appendPQExpBuffer(&buf
,
330 " t.typname AS \"%s\",\n"
331 " CASE WHEN t.typrelid != 0\n"
332 " THEN CAST('tuple' AS pg_catalog.text)\n"
333 " WHEN t.typlen < 0\n"
334 " THEN CAST('var' AS pg_catalog.text)\n"
335 " ELSE CAST(t.typlen AS pg_catalog.text)\n"
337 gettext_noop("Internal name"),
338 gettext_noop("Size"));
339 if (verbose
&& pset
.sversion
>= 80300)
340 appendPQExpBuffer(&buf
,
341 " pg_catalog.array_to_string(\n"
343 " SELECT e.enumlabel\n"
344 " FROM pg_catalog.pg_enum e\n"
345 " WHERE e.enumtypid = t.oid\n"
350 gettext_noop("Elements"));
352 appendPQExpBuffer(&buf
,
353 " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
354 gettext_noop("Description"));
356 appendPQExpBuffer(&buf
, "FROM pg_catalog.pg_type t\n"
357 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
360 * do not include complex types (typrelid!=0) unless they are standalone
363 appendPQExpBuffer(&buf
, "WHERE (t.typrelid = 0 ");
364 appendPQExpBuffer(&buf
, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
365 "WHERE c.oid = t.typrelid))\n");
367 * do not include array types (before 8.3 we have to use the assumption
368 * that their names start with underscore)
370 if (pset
.sversion
>= 80300)
371 appendPQExpBuffer(&buf
, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
373 appendPQExpBuffer(&buf
, " AND t.typname !~ '^_'\n");
376 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
378 /* Match name pattern against either internal or external name */
379 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
380 "n.nspname", "t.typname",
381 "pg_catalog.format_type(t.oid, NULL)",
382 "pg_catalog.pg_type_is_visible(t.oid)");
384 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
386 res
= PSQLexec(buf
.data
, false);
387 termPQExpBuffer(&buf
);
391 myopt
.nullPrint
= NULL
;
392 myopt
.title
= _("List of data types");
393 myopt
.translate_header
= true;
395 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
405 describeOperators(const char *pattern
, bool showSystem
)
409 printQueryOpt myopt
= pset
.popt
;
411 initPQExpBuffer(&buf
);
413 printfPQExpBuffer(&buf
,
414 "SELECT n.nspname as \"%s\",\n"
415 " o.oprname AS \"%s\",\n"
416 " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
417 " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
418 " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n"
419 " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
420 " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
421 "FROM pg_catalog.pg_operator o\n"
422 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
423 gettext_noop("Schema"),
424 gettext_noop("Name"),
425 gettext_noop("Left arg type"),
426 gettext_noop("Right arg type"),
427 gettext_noop("Result type"),
428 gettext_noop("Description"));
431 appendPQExpBuffer(&buf
, " WHERE n.nspname <> 'pg_catalog'\n");
433 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
, true,
434 "n.nspname", "o.oprname", NULL
,
435 "pg_catalog.pg_operator_is_visible(o.oid)");
437 appendPQExpBuffer(&buf
, "ORDER BY 1, 2, 3, 4;");
439 res
= PSQLexec(buf
.data
, false);
440 termPQExpBuffer(&buf
);
444 myopt
.nullPrint
= NULL
;
445 myopt
.title
= _("List of operators");
446 myopt
.translate_header
= true;
448 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
458 * for \l, \list, and -l switch
461 listAllDbs(bool verbose
)
465 printQueryOpt myopt
= pset
.popt
;
467 initPQExpBuffer(&buf
);
469 printfPQExpBuffer(&buf
,
470 "SELECT d.datname as \"%s\",\n"
471 " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
472 " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
473 gettext_noop("Name"),
474 gettext_noop("Owner"),
475 gettext_noop("Encoding"));
476 if (pset
.sversion
>= 80400)
477 appendPQExpBuffer(&buf
,
478 " d.datcollate as \"%s\",\n"
479 " d.datctype as \"%s\",\n",
480 gettext_noop("Collation"),
481 gettext_noop("Ctype"));
482 appendPQExpBuffer(&buf
, " ");
483 printACLColumn(&buf
, "d.datacl");
484 if (verbose
&& pset
.sversion
>= 80200)
485 appendPQExpBuffer(&buf
,
486 ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
487 " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
488 " ELSE 'No Access'\n"
490 gettext_noop("Size"));
491 if (verbose
&& pset
.sversion
>= 80000)
492 appendPQExpBuffer(&buf
,
493 ",\n t.spcname as \"%s\"",
494 gettext_noop("Tablespace"));
495 if (verbose
&& pset
.sversion
>= 80200)
496 appendPQExpBuffer(&buf
,
497 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
498 gettext_noop("Description"));
499 appendPQExpBuffer(&buf
,
500 "\nFROM pg_catalog.pg_database d\n");
501 if (verbose
&& pset
.sversion
>= 80000)
502 appendPQExpBuffer(&buf
,
503 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
504 appendPQExpBuffer(&buf
, "ORDER BY 1;");
505 res
= PSQLexec(buf
.data
, false);
506 termPQExpBuffer(&buf
);
510 myopt
.nullPrint
= NULL
;
511 myopt
.title
= _("List of databases");
512 myopt
.translate_header
= true;
514 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
522 * List Tables Grant/Revoke Permissions
523 * \z (now also \dp -- perhaps more mnemonic)
526 permissionsList(const char *pattern
)
530 printQueryOpt myopt
= pset
.popt
;
531 static const bool translate_columns
[] = {false, false, true, false};
533 initPQExpBuffer(&buf
);
536 * we ignore indexes and toast tables since they have no meaningful rights
538 printfPQExpBuffer(&buf
,
539 "SELECT n.nspname as \"%s\",\n"
540 " c.relname as \"%s\",\n"
541 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \"%s\",\n"
543 gettext_noop("Schema"),
544 gettext_noop("Name"),
545 gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
546 gettext_noop("Type"));
547 printACLColumn(&buf
, "c.relacl");
548 appendPQExpBuffer(&buf
, "\nFROM pg_catalog.pg_class c\n"
549 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
550 "WHERE c.relkind IN ('r', 'v', 'S')\n");
553 * Unless a schema pattern is specified, we suppress system and temp
554 * tables, since they normally aren't very interesting from a permissions
555 * point of view. You can see 'em by explicit request though, eg with \z
558 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
559 "n.nspname", "c.relname", NULL
,
560 "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
562 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
564 res
= PSQLexec(buf
.data
, false);
567 termPQExpBuffer(&buf
);
571 myopt
.nullPrint
= NULL
;
572 printfPQExpBuffer(&buf
, _("Access privileges"));
573 myopt
.title
= buf
.data
;
574 myopt
.translate_header
= true;
575 myopt
.translate_columns
= translate_columns
;
577 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
579 termPQExpBuffer(&buf
);
587 * Get object comments
591 * Note: This only lists things that actually have a description. For complete
592 * lists of things, there are other \d? commands.
595 objectDescription(const char *pattern
, bool showSystem
)
599 printQueryOpt myopt
= pset
.popt
;
600 static const bool translate_columns
[] = {false, false, true, false};
602 initPQExpBuffer(&buf
);
604 appendPQExpBuffer(&buf
,
605 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
607 gettext_noop("Schema"),
608 gettext_noop("Name"),
609 gettext_noop("Object"),
610 gettext_noop("Description"));
612 /* Aggregate descriptions */
613 appendPQExpBuffer(&buf
,
614 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
615 " n.nspname as nspname,\n"
616 " CAST(p.proname AS pg_catalog.text) as name,"
617 " CAST('%s' AS pg_catalog.text) as object\n"
618 " FROM pg_catalog.pg_proc p\n"
619 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
620 " WHERE p.proisagg\n",
621 gettext_noop("aggregate"));
624 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
626 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
627 "n.nspname", "p.proname", NULL
,
628 "pg_catalog.pg_function_is_visible(p.oid)");
630 /* Function descriptions (except in/outs for datatypes) */
631 appendPQExpBuffer(&buf
,
633 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
634 " n.nspname as nspname,\n"
635 " CAST(p.proname AS pg_catalog.text) as name,"
636 " CAST('%s' AS pg_catalog.text) as object\n"
637 " FROM pg_catalog.pg_proc p\n"
638 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
640 " WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n"
641 " AND (p.proargtypes[0] IS NULL\n"
642 " OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n"
643 " AND NOT p.proisagg\n",
644 gettext_noop("function"));
647 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
649 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
650 "n.nspname", "p.proname", NULL
,
651 "pg_catalog.pg_function_is_visible(p.oid)");
653 /* Operator descriptions (only if operator has its own comment) */
654 appendPQExpBuffer(&buf
,
656 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
657 " n.nspname as nspname,\n"
658 " CAST(o.oprname AS pg_catalog.text) as name,"
659 " CAST('%s' AS pg_catalog.text) as object\n"
660 " FROM pg_catalog.pg_operator o\n"
661 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
662 gettext_noop("operator"));
665 appendPQExpBuffer(&buf
, " WHERE n.nspname <> 'pg_catalog'\n");
667 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
, false,
668 "n.nspname", "o.oprname", NULL
,
669 "pg_catalog.pg_operator_is_visible(o.oid)");
671 /* Type description */
672 appendPQExpBuffer(&buf
,
674 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
675 " n.nspname as nspname,\n"
676 " pg_catalog.format_type(t.oid, NULL) as name,"
677 " CAST('%s' AS pg_catalog.text) as object\n"
678 " FROM pg_catalog.pg_type t\n"
679 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
680 gettext_noop("data type"));
683 appendPQExpBuffer(&buf
, " WHERE n.nspname <> 'pg_catalog'\n");
685 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
, false,
686 "n.nspname", "pg_catalog.format_type(t.oid, NULL)",
688 "pg_catalog.pg_type_is_visible(t.oid)");
690 /* Relation (tables, views, indexes, sequences) descriptions */
691 appendPQExpBuffer(&buf
,
693 " SELECT c.oid as oid, c.tableoid as tableoid,\n"
694 " n.nspname as nspname,\n"
695 " CAST(c.relname AS pg_catalog.text) as name,\n"
697 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END"
698 " AS pg_catalog.text) as object\n"
699 " FROM pg_catalog.pg_class c\n"
700 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
701 " WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
702 gettext_noop("table"),
703 gettext_noop("view"),
704 gettext_noop("index"),
705 gettext_noop("sequence"));
707 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
709 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
710 "n.nspname", "c.relname", NULL
,
711 "pg_catalog.pg_table_is_visible(c.oid)");
713 /* Rule description (ignore rules for views) */
714 appendPQExpBuffer(&buf
,
716 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
717 " n.nspname as nspname,\n"
718 " CAST(r.rulename AS pg_catalog.text) as name,"
719 " CAST('%s' AS pg_catalog.text) as object\n"
720 " FROM pg_catalog.pg_rewrite r\n"
721 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
722 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
723 " WHERE r.rulename != '_RETURN'\n",
724 gettext_noop("rule"));
727 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
729 /* XXX not sure what to do about visibility rule here? */
730 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
731 "n.nspname", "r.rulename", NULL
,
732 "pg_catalog.pg_table_is_visible(c.oid)");
734 /* Trigger description */
735 appendPQExpBuffer(&buf
,
737 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
738 " n.nspname as nspname,\n"
739 " CAST(t.tgname AS pg_catalog.text) as name,"
740 " CAST('%s' AS pg_catalog.text) as object\n"
741 " FROM pg_catalog.pg_trigger t\n"
742 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
743 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
744 gettext_noop("trigger"));
746 appendPQExpBuffer(&buf
, " WHERE n.nspname <> 'pg_catalog'\n");
748 /* XXX not sure what to do about visibility rule here? */
749 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
, false,
750 "n.nspname", "t.tgname", NULL
,
751 "pg_catalog.pg_table_is_visible(c.oid)");
753 appendPQExpBuffer(&buf
,
755 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
757 appendPQExpBuffer(&buf
, "ORDER BY 1, 2, 3;");
759 res
= PSQLexec(buf
.data
, false);
760 termPQExpBuffer(&buf
);
764 myopt
.nullPrint
= NULL
;
765 myopt
.title
= _("Object descriptions");
766 myopt
.translate_header
= true;
767 myopt
.translate_columns
= translate_columns
;
769 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
777 * describeTableDetails (for \d)
779 * This routine finds the tables to be displayed, and calls
780 * describeOneTableDetails for each one.
782 * verbose: if true, this is \d+
785 describeTableDetails(const char *pattern
, bool verbose
)
791 initPQExpBuffer(&buf
);
793 printfPQExpBuffer(&buf
,
797 "FROM pg_catalog.pg_class c\n"
798 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
800 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
801 "n.nspname", "c.relname", NULL
,
802 "pg_catalog.pg_table_is_visible(c.oid)");
804 appendPQExpBuffer(&buf
, "ORDER BY 2, 3;");
806 res
= PSQLexec(buf
.data
, false);
807 termPQExpBuffer(&buf
);
811 if (PQntuples(res
) == 0)
814 fprintf(stderr
, _("Did not find any relation named \"%s\".\n"),
820 for (i
= 0; i
< PQntuples(res
); i
++)
826 oid
= PQgetvalue(res
, i
, 0);
827 nspname
= PQgetvalue(res
, i
, 1);
828 relname
= PQgetvalue(res
, i
, 2);
830 if (!describeOneTableDetails(nspname
, relname
, oid
, verbose
))
847 * describeOneTableDetails (for \d)
849 * Unfortunately, the information presented here is so complicated that it
850 * cannot be done in a single query. So we have to assemble the printed table
851 * by hand and pass it to the underlying printTable() function.
854 describeOneTableDetails(const char *schemaname
,
855 const char *relationname
,
860 PGresult
*res
= NULL
;
861 printTableOpt myopt
= pset
.popt
.topt
;
862 printTableContent cont
;
863 bool printTableInitialized
= false;
865 char *view_def
= NULL
;
867 char **seq_values
= NULL
;
868 char **modifiers
= NULL
;
870 PQExpBufferData title
;
871 PQExpBufferData tmpbuf
;
885 bool show_modifiers
= false;
890 /* This output looks confusing in expanded mode. */
891 myopt
.expanded
= false;
893 initPQExpBuffer(&buf
);
894 initPQExpBuffer(&title
);
895 initPQExpBuffer(&tmpbuf
);
897 /* Get general table info */
898 printfPQExpBuffer(&buf
,
899 "SELECT relchecks, relkind, relhasindex, relhasrules, %s, "
902 "FROM pg_catalog.pg_class WHERE oid = '%s'",
903 (pset
.sversion
>= 80400 ? "relhastriggers" : "reltriggers <> 0"),
904 (pset
.sversion
>= 80200 && verbose
?
905 ", pg_catalog.array_to_string(reloptions, E', ')" : ",''"),
906 (pset
.sversion
>= 80000 ? ", reltablespace" : ""),
908 res
= PSQLexec(buf
.data
, false);
912 /* Did we get anything? */
913 if (PQntuples(res
) == 0)
916 fprintf(stderr
, _("Did not find any relation with OID %s.\n"),
921 tableinfo
.checks
= atoi(PQgetvalue(res
, 0, 0));
922 tableinfo
.relkind
= *(PQgetvalue(res
, 0, 1));
923 tableinfo
.hasindex
= strcmp(PQgetvalue(res
, 0, 2), "t") == 0;
924 tableinfo
.hasrules
= strcmp(PQgetvalue(res
, 0, 3), "t") == 0;
925 tableinfo
.hastriggers
= strcmp(PQgetvalue(res
, 0, 4), "t") == 0;
926 tableinfo
.hasoids
= strcmp(PQgetvalue(res
, 0, 5), "t") == 0;
927 tableinfo
.reloptions
= pset
.sversion
>= 80200 ?
928 strdup(PQgetvalue(res
, 0, 6)) : 0;
929 tableinfo
.tablespace
= (pset
.sversion
>= 80000) ?
930 atooid(PQgetvalue(res
, 0, 7)) : 0;
935 * If it's a sequence, fetch its values and store into an
936 * array that will be used later.
938 if (tableinfo
.relkind
== 'S')
942 #define SEQ_NUM_COLS 10
943 printfPQExpBuffer(&buf
,
944 "SELECT sequence_name, last_value,\n"
945 " start_value, increment_by,\n"
946 " max_value, min_value, cache_value,\n"
947 " log_cnt, is_cycled, is_called\n"
950 /* must be separate because fmtId isn't reentrant */
951 appendPQExpBuffer(&buf
, ".%s", fmtId(relationname
));
953 result
= PSQLexec(buf
.data
, false);
957 seq_values
= pg_malloc_zero((SEQ_NUM_COLS
+1) * sizeof(*seq_values
));
959 for (i
= 0; i
< SEQ_NUM_COLS
; i
++)
960 seq_values
[i
] = pg_strdup(PQgetvalue(result
, 0, i
));
965 /* Get column info (index requires additional checks) */
966 printfPQExpBuffer(&buf
, "SELECT a.attname,");
967 appendPQExpBuffer(&buf
, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
968 "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
969 "\n FROM pg_catalog.pg_attrdef d"
970 "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
971 "\n a.attnotnull, a.attnum");
973 appendPQExpBuffer(&buf
, ", a.attstorage, pg_catalog.col_description(a.attrelid, a.attnum)");
974 appendPQExpBuffer(&buf
, "\nFROM pg_catalog.pg_attribute a");
975 if (tableinfo
.relkind
== 'i')
976 appendPQExpBuffer(&buf
, ", pg_catalog.pg_index i");
977 appendPQExpBuffer(&buf
, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid
);
978 if (tableinfo
.relkind
== 'i')
979 appendPQExpBuffer(&buf
, " AND a.attrelid = i.indexrelid");
980 appendPQExpBuffer(&buf
, "\nORDER BY a.attnum");
982 res
= PSQLexec(buf
.data
, false);
985 numrows
= PQntuples(res
);
988 switch (tableinfo
.relkind
)
991 printfPQExpBuffer(&title
, _("Table \"%s.%s\""),
992 schemaname
, relationname
);
995 printfPQExpBuffer(&title
, _("View \"%s.%s\""),
996 schemaname
, relationname
);
999 printfPQExpBuffer(&title
, _("Sequence \"%s.%s\""),
1000 schemaname
, relationname
);
1003 printfPQExpBuffer(&title
, _("Index \"%s.%s\""),
1004 schemaname
, relationname
);
1007 /* not used as of 8.2, but keep it for backwards compatibility */
1008 printfPQExpBuffer(&title
, _("Special relation \"%s.%s\""),
1009 schemaname
, relationname
);
1012 printfPQExpBuffer(&title
, _("TOAST table \"%s.%s\""),
1013 schemaname
, relationname
);
1016 printfPQExpBuffer(&title
, _("Composite type \"%s.%s\""),
1017 schemaname
, relationname
);
1020 /* untranslated unknown relkind */
1021 printfPQExpBuffer(&title
, "?%c? \"%s.%s\"",
1022 tableinfo
.relkind
, schemaname
, relationname
);
1026 /* Set the number of columns, and their names */
1028 headers
[0] = gettext_noop("Column");
1029 headers
[1] = gettext_noop("Type");
1031 if (tableinfo
.relkind
== 'r' || tableinfo
.relkind
== 'v')
1033 show_modifiers
= true;
1034 headers
[cols
++] = gettext_noop("Modifiers");
1035 modifiers
= pg_malloc_zero((numrows
+ 1) * sizeof(*modifiers
));
1038 if (tableinfo
.relkind
== 'S')
1039 headers
[cols
++] = gettext_noop("Value");
1043 headers
[cols
++] = gettext_noop("Storage");
1044 headers
[cols
++] = gettext_noop("Description");
1047 printTableInit(&cont
, &myopt
, title
.data
, cols
, numrows
);
1048 printTableInitialized
= true;
1050 for (i
= 0; i
< cols
; i
++)
1051 printTableAddHeader(&cont
, headers
[i
], true, 'l');
1053 /* Check if table is a view */
1054 if (tableinfo
.relkind
== 'v')
1058 printfPQExpBuffer(&buf
,
1059 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true)",
1061 result
= PSQLexec(buf
.data
, false);
1065 if (PQntuples(result
) > 0)
1066 view_def
= pg_strdup(PQgetvalue(result
, 0, 0));
1071 /* Generate table cells to be printed */
1072 for (i
= 0; i
< numrows
; i
++)
1075 printTableAddCell(&cont
, PQgetvalue(res
, i
, 0), false);
1078 printTableAddCell(&cont
, PQgetvalue(res
, i
, 1), false);
1080 /* Modifiers: not null and default */
1083 resetPQExpBuffer(&tmpbuf
);
1084 if (strcmp(PQgetvalue(res
, i
, 3), "t") == 0)
1085 appendPQExpBufferStr(&tmpbuf
, _("not null"));
1087 /* handle "default" here */
1088 /* (note: above we cut off the 'default' string at 128) */
1089 if (strlen(PQgetvalue(res
, i
, 2)) != 0)
1092 appendPQExpBufferStr(&tmpbuf
, " ");
1093 /* translator: default values of column definitions */
1094 appendPQExpBuffer(&tmpbuf
, _("default %s"),
1095 PQgetvalue(res
, i
, 2));
1098 modifiers
[i
] = pg_strdup(tmpbuf
.data
);
1099 printTableAddCell(&cont
, modifiers
[i
], false);
1102 /* Value: for sequences only */
1103 if (tableinfo
.relkind
== 'S')
1104 printTableAddCell(&cont
, seq_values
[i
], false);
1106 /* Storage and Description */
1109 char *storage
= PQgetvalue(res
, i
, 5);
1111 /* these strings are literal in our syntax, so not translated. */
1112 printTableAddCell(&cont
, (storage
[0]=='p' ? "plain" :
1113 (storage
[0]=='m' ? "main" :
1114 (storage
[0]=='x' ? "extended" :
1115 (storage
[0]=='e' ? "external" :
1118 printTableAddCell(&cont
, PQgetvalue(res
, i
, 6), false);
1123 if (tableinfo
.relkind
== 'i')
1125 /* Footer information about an index */
1128 printfPQExpBuffer(&buf
,
1129 "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
1130 if (pset
.sversion
>= 80200)
1131 appendPQExpBuffer(&buf
, "i.indisvalid, ");
1133 appendPQExpBuffer(&buf
, "true as indisvalid, ");
1134 appendPQExpBuffer(&buf
, "a.amname, c2.relname,\n"
1135 " pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
1136 "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
1137 "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
1138 "AND i.indrelid = c2.oid",
1141 result
= PSQLexec(buf
.data
, false);
1144 else if (PQntuples(result
) != 1)
1151 char *indisunique
= PQgetvalue(result
, 0, 0);
1152 char *indisprimary
= PQgetvalue(result
, 0, 1);
1153 char *indisclustered
= PQgetvalue(result
, 0, 2);
1154 char *indisvalid
= PQgetvalue(result
, 0, 3);
1155 char *indamname
= PQgetvalue(result
, 0, 4);
1156 char *indtable
= PQgetvalue(result
, 0, 5);
1157 char *indpred
= PQgetvalue(result
, 0, 6);
1159 if (strcmp(indisprimary
, "t") == 0)
1160 printfPQExpBuffer(&tmpbuf
, _("primary key, "));
1161 else if (strcmp(indisunique
, "t") == 0)
1162 printfPQExpBuffer(&tmpbuf
, _("unique, "));
1164 resetPQExpBuffer(&tmpbuf
);
1165 appendPQExpBuffer(&tmpbuf
, "%s, ", indamname
);
1167 /* we assume here that index and table are in same schema */
1168 appendPQExpBuffer(&tmpbuf
, _("for table \"%s.%s\""),
1169 schemaname
, indtable
);
1171 if (strlen(indpred
))
1172 appendPQExpBuffer(&tmpbuf
, _(", predicate (%s)"), indpred
);
1174 if (strcmp(indisclustered
, "t") == 0)
1175 appendPQExpBuffer(&tmpbuf
, _(", clustered"));
1177 if (strcmp(indisvalid
, "t") != 0)
1178 appendPQExpBuffer(&tmpbuf
, _(", invalid"));
1180 printTableAddFooter(&cont
, tmpbuf
.data
);
1181 add_tablespace_footer(&cont
, tableinfo
.relkind
,
1182 tableinfo
.tablespace
, true);
1189 PGresult
*result
= NULL
;
1191 /* Footer information about a view */
1192 printTableAddFooter(&cont
, _("View definition:"));
1193 printTableAddFooter(&cont
, view_def
);
1196 if (tableinfo
.hasrules
)
1198 printfPQExpBuffer(&buf
,
1199 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
1200 "FROM pg_catalog.pg_rewrite r\n"
1201 "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1",
1203 result
= PSQLexec(buf
.data
, false);
1207 if (PQntuples(result
) > 0)
1209 printTableAddFooter(&cont
, _("Rules:"));
1210 for (i
= 0; i
< PQntuples(result
); i
++)
1212 const char *ruledef
;
1214 /* Everything after "CREATE RULE" is echoed verbatim */
1215 ruledef
= PQgetvalue(result
, i
, 1);
1218 printfPQExpBuffer(&buf
, " %s", ruledef
);
1219 printTableAddFooter(&cont
, buf
.data
);
1225 else if (tableinfo
.relkind
== 'r')
1227 /* Footer information about a table */
1228 PGresult
*result
= NULL
;
1232 if (tableinfo
.hasindex
)
1234 printfPQExpBuffer(&buf
,
1235 "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
1236 if (pset
.sversion
>= 80200)
1237 appendPQExpBuffer(&buf
, "i.indisvalid, ");
1239 appendPQExpBuffer(&buf
, "true as indisvalid, ");
1240 appendPQExpBuffer(&buf
, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)");
1241 if (pset
.sversion
>= 80000)
1242 appendPQExpBuffer(&buf
, ", c2.reltablespace");
1243 appendPQExpBuffer(&buf
,
1244 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
1245 "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
1246 "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
1248 result
= PSQLexec(buf
.data
, false);
1252 tuples
= PQntuples(result
);
1256 printTableAddFooter(&cont
, _("Indexes:"));
1257 for (i
= 0; i
< tuples
; i
++)
1259 const char *indexdef
;
1260 const char *usingpos
;
1262 /* untranslated index name */
1263 printfPQExpBuffer(&buf
, " \"%s\"",
1264 PQgetvalue(result
, i
, 0));
1266 /* Label as primary key or unique (but not both) */
1267 appendPQExpBuffer(&buf
,
1268 strcmp(PQgetvalue(result
, i
, 1), "t") == 0
1270 (strcmp(PQgetvalue(result
, i
, 2), "t") == 0
1273 /* Everything after "USING" is echoed verbatim */
1274 indexdef
= PQgetvalue(result
, i
, 5);
1275 usingpos
= strstr(indexdef
, " USING ");
1277 indexdef
= usingpos
+ 7;
1279 appendPQExpBuffer(&buf
, " %s", indexdef
);
1281 if (strcmp(PQgetvalue(result
, i
, 3), "t") == 0)
1282 appendPQExpBuffer(&buf
, " CLUSTER");
1284 if (strcmp(PQgetvalue(result
, i
, 4), "t") != 0)
1285 appendPQExpBuffer(&buf
, " INVALID");
1287 printTableAddFooter(&cont
, buf
.data
);
1289 /* Print tablespace of the index on the same line */
1290 if (pset
.sversion
>= 80000)
1291 add_tablespace_footer(&cont
, 'i',
1292 atooid(PQgetvalue(result
, i
, 6)),
1299 /* print table (and column) check constraints */
1300 if (tableinfo
.checks
)
1302 printfPQExpBuffer(&buf
,
1303 "SELECT r.conname, "
1304 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
1305 "FROM pg_catalog.pg_constraint r\n"
1306 "WHERE r.conrelid = '%s' AND r.contype = 'c'\nORDER BY 1",
1308 result
= PSQLexec(buf
.data
, false);
1312 tuples
= PQntuples(result
);
1316 printTableAddFooter(&cont
, _("Check constraints:"));
1317 for (i
= 0; i
< tuples
; i
++)
1319 /* untranslated contraint name and def */
1320 printfPQExpBuffer(&buf
, " \"%s\" %s",
1321 PQgetvalue(result
, i
, 0),
1322 PQgetvalue(result
, i
, 1));
1324 printTableAddFooter(&cont
, buf
.data
);
1330 /* print foreign-key constraints (there are none if no triggers) */
1331 if (tableinfo
.hastriggers
)
1333 printfPQExpBuffer(&buf
,
1335 " pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n"
1336 "FROM pg_catalog.pg_constraint r\n"
1337 "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1",
1339 result
= PSQLexec(buf
.data
, false);
1343 tuples
= PQntuples(result
);
1347 printTableAddFooter(&cont
, _("Foreign-key constraints:"));
1348 for (i
= 0; i
< tuples
; i
++)
1350 /* untranslated constraint name and def */
1351 printfPQExpBuffer(&buf
, " \"%s\" %s",
1352 PQgetvalue(result
, i
, 0),
1353 PQgetvalue(result
, i
, 1));
1355 printTableAddFooter(&cont
, buf
.data
);
1361 /* print incoming foreign-key references (none if no triggers) */
1362 if (tableinfo
.hastriggers
)
1364 printfPQExpBuffer(&buf
,
1365 "SELECT conname, conrelid::pg_catalog.regclass,\n"
1366 " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
1367 "FROM pg_catalog.pg_constraint c\n"
1368 "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1",
1370 result
= PSQLexec(buf
.data
, false);
1374 tuples
= PQntuples(result
);
1378 printTableAddFooter(&cont
, _("Referenced by:"));
1379 for (i
= 0; i
< tuples
; i
++)
1381 /* translator: the first %s is a FK name, the following are
1382 * a table name and the FK definition */
1383 printfPQExpBuffer(&buf
, _(" \"%s\" IN %s %s"),
1384 PQgetvalue(result
, i
, 0),
1385 PQgetvalue(result
, i
, 1),
1386 PQgetvalue(result
, i
, 2));
1388 printTableAddFooter(&cont
, buf
.data
);
1395 if (tableinfo
.hasrules
)
1397 if (pset
.sversion
>= 80300)
1399 printfPQExpBuffer(&buf
,
1400 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
1402 "FROM pg_catalog.pg_rewrite r\n"
1403 "WHERE r.ev_class = '%s' ORDER BY 1",
1408 printfPQExpBuffer(&buf
,
1409 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
1410 "'O'::char AS ev_enabled\n"
1411 "FROM pg_catalog.pg_rewrite r\n"
1412 "WHERE r.ev_class = '%s' ORDER BY 1",
1415 result
= PSQLexec(buf
.data
, false);
1419 tuples
= PQntuples(result
);
1426 for (category
= 0; category
< 4; category
++)
1428 have_heading
= false;
1430 for (i
= 0; i
< tuples
; i
++)
1432 const char *ruledef
;
1433 bool list_rule
= false;
1438 if (*PQgetvalue(result
, i
, 2) == 'O')
1442 if (*PQgetvalue(result
, i
, 2) == 'D')
1446 if (*PQgetvalue(result
, i
, 2) == 'A')
1450 if (*PQgetvalue(result
, i
, 2) == 'R')
1462 printfPQExpBuffer(&buf
, _("Rules:"));
1465 printfPQExpBuffer(&buf
, _("Disabled rules:"));
1468 printfPQExpBuffer(&buf
, _("Rules firing always:"));
1471 printfPQExpBuffer(&buf
, _("Rules firing on replica only:"));
1474 printTableAddFooter(&cont
, buf
.data
);
1475 have_heading
= true;
1478 /* Everything after "CREATE RULE" is echoed verbatim */
1479 ruledef
= PQgetvalue(result
, i
, 1);
1481 printfPQExpBuffer(&buf
, " %s", ruledef
);
1482 printTableAddFooter(&cont
, buf
.data
);
1489 /* print triggers (but ignore foreign-key triggers) */
1490 if (tableinfo
.hastriggers
)
1492 printfPQExpBuffer(&buf
,
1494 "pg_catalog.pg_get_triggerdef(t.oid), "
1496 "FROM pg_catalog.pg_trigger t\n"
1497 "WHERE t.tgrelid = '%s' AND ",
1499 if (pset
.sversion
>= 80300)
1500 appendPQExpBuffer(&buf
, "t.tgconstraint = 0");
1502 appendPQExpBuffer(&buf
,
1503 "(NOT tgisconstraint "
1505 " (SELECT 1 FROM pg_catalog.pg_depend d "
1506 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
1507 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
1508 appendPQExpBuffer(&buf
, "\nORDER BY 1");
1510 result
= PSQLexec(buf
.data
, false);
1514 tuples
= PQntuples(result
);
1522 * split the output into 4 different categories. Enabled triggers,
1523 * disabled triggers and the two special ALWAYS and REPLICA
1526 for (category
= 0; category
< 4; category
++)
1528 have_heading
= false;
1529 for (i
= 0; i
< tuples
; i
++)
1533 const char *usingpos
;
1534 const char *tgenabled
;
1536 /* Check if this trigger falls into the current category */
1537 tgenabled
= PQgetvalue(result
, i
, 2);
1538 list_trigger
= false;
1542 if (*tgenabled
== 'O' || *tgenabled
== 't')
1543 list_trigger
= true;
1546 if (*tgenabled
== 'D' || *tgenabled
== 'f')
1547 list_trigger
= true;
1550 if (*tgenabled
== 'A')
1551 list_trigger
= true;
1554 if (*tgenabled
== 'R')
1555 list_trigger
= true;
1558 if (list_trigger
== false)
1561 /* Print the category heading once */
1562 if (have_heading
== false)
1567 printfPQExpBuffer(&buf
, _("Triggers:"));
1570 printfPQExpBuffer(&buf
, _("Disabled triggers:"));
1573 printfPQExpBuffer(&buf
, _("Triggers firing always:"));
1576 printfPQExpBuffer(&buf
, _("Triggers firing on replica only:"));
1580 printTableAddFooter(&cont
, buf
.data
);
1581 have_heading
= true;
1584 /* Everything after "TRIGGER" is echoed verbatim */
1585 tgdef
= PQgetvalue(result
, i
, 1);
1586 usingpos
= strstr(tgdef
, " TRIGGER ");
1588 tgdef
= usingpos
+ 9;
1590 printfPQExpBuffer(&buf
, " %s", tgdef
);
1591 printTableAddFooter(&cont
, buf
.data
);
1598 /* print inherited tables */
1599 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
);
1601 result
= PSQLexec(buf
.data
, false);
1605 tuples
= PQntuples(result
);
1607 for (i
= 0; i
< tuples
; i
++)
1609 const char *s
= _("Inherits");
1612 printfPQExpBuffer(&buf
, "%s: %s", s
, PQgetvalue(result
, i
, 0));
1614 printfPQExpBuffer(&buf
, "%*s %s", (int) strlen(s
), "", PQgetvalue(result
, i
, 0));
1616 appendPQExpBuffer(&buf
, ",");
1618 printTableAddFooter(&cont
, buf
.data
);
1624 const char *s
= _("Has OIDs");
1626 printfPQExpBuffer(&buf
, "%s: %s", s
,
1627 (tableinfo
.hasoids
? _("yes") : _("no")));
1628 printTableAddFooter(&cont
, buf
.data
);
1630 /* print reloptions */
1631 if (pset
.sversion
>= 80200)
1633 if (tableinfo
.reloptions
&& tableinfo
.reloptions
[0] != '\0')
1635 const char *t
= _("Options");
1637 printfPQExpBuffer(&buf
, "%s: %s", t
,
1638 tableinfo
.reloptions
);
1639 printTableAddFooter(&cont
, buf
.data
);
1644 add_tablespace_footer(&cont
, tableinfo
.relkind
, tableinfo
.tablespace
,
1648 printTable(&cont
, pset
.queryFout
, pset
.logfile
);
1649 printTableCleanup(&cont
);
1656 if (printTableInitialized
)
1657 printTableCleanup(&cont
);
1658 termPQExpBuffer(&buf
);
1659 termPQExpBuffer(&title
);
1660 termPQExpBuffer(&tmpbuf
);
1664 for (ptr
= seq_values
; *ptr
; ptr
++)
1671 for (ptr
= modifiers
; *ptr
; ptr
++)
1686 * Add a tablespace description to a footer. If 'newline' is true, it is added
1687 * in a new line; otherwise it's appended to the current value of the last
1691 add_tablespace_footer(printTableContent
*const cont
, char relkind
,
1692 Oid tablespace
, const bool newline
)
1694 /* relkinds for which we support tablespaces */
1695 if (relkind
== 'r' || relkind
== 'i')
1698 * We ignore the database default tablespace so that users not using
1699 * tablespaces don't need to know about them. This case also covers
1700 * pre-8.0 servers, for which tablespace will always be 0.
1702 if (tablespace
!= 0)
1704 PGresult
*result
= NULL
;
1705 PQExpBufferData buf
;
1707 initPQExpBuffer(&buf
);
1708 printfPQExpBuffer(&buf
,
1709 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
1710 "WHERE oid = '%u'", tablespace
);
1711 result
= PSQLexec(buf
.data
, false);
1714 /* Should always be the case, but.... */
1715 if (PQntuples(result
) > 0)
1719 /* Add the tablespace as a new footer */
1720 printfPQExpBuffer(&buf
, _("Tablespace: \"%s\""),
1721 PQgetvalue(result
, 0, 0));
1722 printTableAddFooter(cont
, buf
.data
);
1726 /* Append the tablespace to the latest footer */
1727 printfPQExpBuffer(&buf
, "%s", cont
->footer
->data
);
1728 /* translator: before this string there's an index
1729 * description like '"foo_pkey" PRIMARY KEY, btree (a)' */
1730 appendPQExpBuffer(&buf
, _(", tablespace \"%s\""),
1731 PQgetvalue(result
, 0, 0));
1732 printTableSetFooter(cont
, buf
.data
);
1736 termPQExpBuffer(&buf
);
1744 * Describes roles. Any schema portion of the pattern is ignored.
1747 describeRoles(const char *pattern
, bool verbose
)
1749 PQExpBufferData buf
;
1751 printTableContent cont
;
1752 printTableOpt myopt
= pset
.popt
.topt
;
1757 const char align
= 'l';
1760 initPQExpBuffer(&buf
);
1762 if (pset
.sversion
>= 80100)
1764 printfPQExpBuffer(&buf
,
1765 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
1766 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
1767 " r.rolconnlimit,\n"
1768 " ARRAY(SELECT b.rolname\n"
1769 " FROM pg_catalog.pg_auth_members m\n"
1770 " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
1771 " WHERE m.member = r.oid) as memberof");
1773 if (verbose
&& pset
.sversion
>= 80200)
1775 appendPQExpBufferStr(&buf
, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
1779 appendPQExpBufferStr(&buf
, "\nFROM pg_catalog.pg_roles r\n");
1781 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
1782 NULL
, "r.rolname", NULL
, NULL
);
1786 printfPQExpBuffer(&buf
,
1787 "SELECT u.usename AS rolname,\n"
1788 " u.usesuper AS rolsuper,\n"
1789 " true AS rolinherit, false AS rolcreaterole,\n"
1790 " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
1791 " -1 AS rolconnlimit,\n"
1792 " ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
1793 "\nFROM pg_catalog.pg_user u\n");
1795 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
1796 NULL
, "u.usename", NULL
, NULL
);
1799 appendPQExpBuffer(&buf
, "ORDER BY 1;");
1801 res
= PSQLexec(buf
.data
, false);
1805 nrows
= PQntuples(res
);
1806 attr
= pg_malloc_zero((nrows
+ 1) * sizeof(*attr
));
1808 printTableInit(&cont
, &myopt
, _("List of roles"), ncols
, nrows
);
1810 printTableAddHeader(&cont
, gettext_noop("Role name"), true, align
);
1811 printTableAddHeader(&cont
, gettext_noop("Attributes"), true, align
);
1812 printTableAddHeader(&cont
, gettext_noop("Member of"), true, align
);
1814 if (verbose
&& pset
.sversion
>= 80200)
1815 printTableAddHeader(&cont
, gettext_noop("Description"), true, align
);
1817 for (i
= 0; i
< nrows
; i
++)
1819 printTableAddCell(&cont
, PQgetvalue(res
, i
, 0), false);
1821 resetPQExpBuffer(&buf
);
1822 if (strcmp(PQgetvalue(res
, i
, 1), "t") == 0)
1823 add_role_attribute(&buf
, _("Superuser"));
1825 if (strcmp(PQgetvalue(res
, i
, 2), "t") != 0)
1826 add_role_attribute(&buf
, _("No inheritance"));
1828 if (strcmp(PQgetvalue(res
, i
, 3), "t") == 0)
1829 add_role_attribute(&buf
, _("Create role"));
1831 if (strcmp(PQgetvalue(res
, i
, 4), "t") == 0)
1832 add_role_attribute(&buf
, _("Create DB"));
1834 if (strcmp(PQgetvalue(res
, i
, 5), "t") != 0)
1835 add_role_attribute(&buf
, _("Cannot login"));
1837 conns
= atoi(PQgetvalue(res
, i
, 6));
1841 appendPQExpBufferStr(&buf
, "\n");
1844 appendPQExpBuffer(&buf
, _("No connections"));
1845 else if (conns
== 1)
1846 appendPQExpBuffer(&buf
, _("1 connection"));
1848 appendPQExpBuffer(&buf
, _("%d connections"), conns
);
1851 attr
[i
] = pg_strdup(buf
.data
);
1853 printTableAddCell(&cont
, attr
[i
], false);
1855 printTableAddCell(&cont
, PQgetvalue(res
, i
, 7), false);
1857 if (verbose
&& pset
.sversion
>= 80200)
1858 printTableAddCell(&cont
, PQgetvalue(res
, i
, 8), false);
1860 termPQExpBuffer(&buf
);
1862 printTable(&cont
, pset
.queryFout
, pset
.logfile
);
1863 printTableCleanup(&cont
);
1865 for (i
= 0; i
< nrows
; i
++)
1874 add_role_attribute(PQExpBuffer buf
, const char *const str
)
1877 appendPQExpBufferStr(buf
, "\n");
1879 appendPQExpBufferStr(buf
, str
);
1886 * handler for \d, \dt, etc.
1888 * tabtypes is an array of characters, specifying what info is desired:
1893 * S - system tables (pg_catalog)
1894 * (any order of the above is fine)
1897 listTables(const char *tabtypes
, const char *pattern
, bool verbose
, bool showSystem
)
1899 bool showTables
= strchr(tabtypes
, 't') != NULL
;
1900 bool showIndexes
= strchr(tabtypes
, 'i') != NULL
;
1901 bool showViews
= strchr(tabtypes
, 'v') != NULL
;
1902 bool showSeq
= strchr(tabtypes
, 's') != NULL
;
1904 PQExpBufferData buf
;
1906 printQueryOpt myopt
= pset
.popt
;
1907 static const bool translate_columns
[] = {false, false, true, false, false, false};
1909 if (!(showTables
|| showIndexes
|| showViews
|| showSeq
))
1910 showTables
= showViews
= showSeq
= true;
1912 initPQExpBuffer(&buf
);
1915 * Note: as of Pg 8.2, we no longer use relkind 's', but we keep it here
1916 * for backwards compatibility.
1918 printfPQExpBuffer(&buf
,
1919 "SELECT n.nspname as \"%s\",\n"
1920 " c.relname as \"%s\",\n"
1921 " 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"
1922 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
1923 gettext_noop("Schema"),
1924 gettext_noop("Name"),
1925 gettext_noop("table"),
1926 gettext_noop("view"),
1927 gettext_noop("index"),
1928 gettext_noop("sequence"),
1929 gettext_noop("special"),
1930 gettext_noop("Type"),
1931 gettext_noop("Owner"));
1934 appendPQExpBuffer(&buf
,
1935 ",\n c2.relname as \"%s\"",
1936 gettext_noop("Table"));
1938 if (verbose
&& pset
.sversion
>= 80100)
1939 appendPQExpBuffer(&buf
,
1940 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
1941 gettext_noop("Size"));
1943 appendPQExpBuffer(&buf
,
1944 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
1945 gettext_noop("Description"));
1947 appendPQExpBuffer(&buf
,
1948 "\nFROM pg_catalog.pg_class c"
1949 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
1951 appendPQExpBuffer(&buf
,
1952 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
1953 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
1955 appendPQExpBuffer(&buf
, "\nWHERE c.relkind IN (");
1957 appendPQExpBuffer(&buf
, "'r',");
1959 appendPQExpBuffer(&buf
, "'v',");
1961 appendPQExpBuffer(&buf
, "'i',");
1963 appendPQExpBuffer(&buf
, "'S',");
1964 if (showSystem
&& showTables
)
1965 appendPQExpBuffer(&buf
, "'s',");
1966 appendPQExpBuffer(&buf
, "''"); /* dummy */
1967 appendPQExpBuffer(&buf
, ")\n");
1970 * If showSystem is specified, show only system objects (those in
1971 * pg_catalog). Otherwise, suppress system objects, including those in
1972 * pg_catalog and pg_toast. (We don't want to hide temp tables though.)
1975 appendPQExpBuffer(&buf
,
1976 " AND n.nspname = 'pg_catalog'\n");
1978 appendPQExpBuffer(&buf
,
1979 " AND n.nspname <> 'pg_catalog'\n"
1980 " AND n.nspname !~ '^pg_toast'\n");
1982 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
1983 "n.nspname", "c.relname", NULL
,
1984 "pg_catalog.pg_table_is_visible(c.oid)");
1986 appendPQExpBuffer(&buf
, "ORDER BY 1,2;");
1988 res
= PSQLexec(buf
.data
, false);
1989 termPQExpBuffer(&buf
);
1993 if (PQntuples(res
) == 0 && !pset
.quiet
)
1996 fprintf(pset
.queryFout
, _("No matching relations found.\n"));
1998 fprintf(pset
.queryFout
, _("No relations found.\n"));
2002 myopt
.nullPrint
= NULL
;
2003 myopt
.title
= _("List of relations");
2004 myopt
.translate_header
= true;
2005 myopt
.translate_columns
= translate_columns
;
2007 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2018 * Describes domains.
2021 listDomains(const char *pattern
, bool showSystem
)
2023 PQExpBufferData buf
;
2025 printQueryOpt myopt
= pset
.popt
;
2027 initPQExpBuffer(&buf
);
2029 printfPQExpBuffer(&buf
,
2030 "SELECT n.nspname as \"%s\",\n"
2031 " t.typname as \"%s\",\n"
2032 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
2033 " CASE WHEN t.typnotnull AND t.typdefault IS NOT NULL THEN 'not null default '||t.typdefault\n"
2034 " WHEN t.typnotnull AND t.typdefault IS NULL THEN 'not null'\n"
2035 " WHEN NOT t.typnotnull AND t.typdefault IS NOT NULL THEN 'default '||t.typdefault\n"
2038 " pg_catalog.pg_get_constraintdef(r.oid, true) as \"%s\"\n"
2039 "FROM pg_catalog.pg_type t\n"
2040 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
2041 " LEFT JOIN pg_catalog.pg_constraint r ON t.oid = r.contypid\n"
2042 "WHERE t.typtype = 'd'\n",
2043 gettext_noop("Schema"),
2044 gettext_noop("Name"),
2045 gettext_noop("Type"),
2046 gettext_noop("Modifier"),
2047 gettext_noop("Check"));
2050 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
2052 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2053 "n.nspname", "t.typname", NULL
,
2054 "pg_catalog.pg_type_is_visible(t.oid)");
2056 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2058 res
= PSQLexec(buf
.data
, false);
2059 termPQExpBuffer(&buf
);
2063 myopt
.nullPrint
= NULL
;
2064 myopt
.title
= _("List of domains");
2065 myopt
.translate_header
= true;
2067 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2076 * Describes conversions.
2079 listConversions(const char *pattern
, bool showSystem
)
2081 PQExpBufferData buf
;
2083 printQueryOpt myopt
= pset
.popt
;
2084 static const bool translate_columns
[] = {false, false, false, false, true};
2086 initPQExpBuffer(&buf
);
2088 printfPQExpBuffer(&buf
,
2089 "SELECT n.nspname AS \"%s\",\n"
2090 " c.conname AS \"%s\",\n"
2091 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
2092 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
2093 " CASE WHEN c.condefault THEN '%s'\n"
2094 " ELSE '%s' END AS \"%s\"\n"
2095 "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
2096 "WHERE n.oid = c.connamespace\n",
2097 gettext_noop("Schema"),
2098 gettext_noop("Name"),
2099 gettext_noop("Source"),
2100 gettext_noop("Destination"),
2101 gettext_noop("yes"), gettext_noop("no"),
2102 gettext_noop("Default?"));
2105 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n");
2107 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2108 "n.nspname", "c.conname", NULL
,
2109 "pg_catalog.pg_conversion_is_visible(c.oid)");
2111 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2113 res
= PSQLexec(buf
.data
, false);
2114 termPQExpBuffer(&buf
);
2118 myopt
.nullPrint
= NULL
;
2119 myopt
.title
= _("List of conversions");
2120 myopt
.translate_header
= true;
2121 myopt
.translate_columns
= translate_columns
;
2123 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2135 listCasts(const char *pattern
)
2137 PQExpBufferData buf
;
2139 printQueryOpt myopt
= pset
.popt
;
2140 static const bool translate_columns
[] = {false, false, false, true};
2142 initPQExpBuffer(&buf
);
2144 * We need a left join to pg_proc for binary casts; the others are just
2145 * paranoia. Also note that we don't attempt to localize '(binary
2146 * coercible)', because there's too much risk of gettext translating a
2147 * function name that happens to match some string in the PO database.
2149 printfPQExpBuffer(&buf
,
2150 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
2151 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
2152 " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
2155 " CASE WHEN c.castcontext = 'e' THEN '%s'\n"
2156 " WHEN c.castcontext = 'a' THEN '%s'\n"
2159 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
2160 " ON c.castfunc = p.oid\n"
2161 " LEFT JOIN pg_catalog.pg_type ts\n"
2162 " ON c.castsource = ts.oid\n"
2163 " LEFT JOIN pg_catalog.pg_namespace ns\n"
2164 " ON ns.oid = ts.typnamespace\n"
2165 " LEFT JOIN pg_catalog.pg_type tt\n"
2166 " ON c.casttarget = tt.oid\n"
2167 " LEFT JOIN pg_catalog.pg_namespace nt\n"
2168 " ON nt.oid = tt.typnamespace\n"
2170 gettext_noop("Source type"),
2171 gettext_noop("Target type"),
2172 gettext_noop("Function"),
2173 gettext_noop("no"), gettext_noop("in assignment"), gettext_noop("yes"),
2174 gettext_noop("Implicit?"));
2177 * Match name pattern against either internal or external name of either
2178 * castsource or casttarget
2180 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2181 "ns.nspname", "ts.typname",
2182 "pg_catalog.format_type(ts.oid, NULL)",
2183 "pg_catalog.pg_type_is_visible(ts.oid)");
2185 appendPQExpBuffer(&buf
, ") OR (true");
2187 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2188 "nt.nspname", "tt.typname",
2189 "pg_catalog.format_type(tt.oid, NULL)",
2190 "pg_catalog.pg_type_is_visible(tt.oid)");
2192 appendPQExpBuffer(&buf
, ")\nORDER BY 1, 2;");
2194 res
= PSQLexec(buf
.data
, false);
2195 termPQExpBuffer(&buf
);
2199 myopt
.nullPrint
= NULL
;
2200 myopt
.title
= _("List of casts");
2201 myopt
.translate_header
= true;
2202 myopt
.translate_columns
= translate_columns
;
2204 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2213 * Describes schemas (namespaces)
2216 listSchemas(const char *pattern
, bool verbose
)
2218 PQExpBufferData buf
;
2220 printQueryOpt myopt
= pset
.popt
;
2222 initPQExpBuffer(&buf
);
2223 printfPQExpBuffer(&buf
,
2224 "SELECT n.nspname AS \"%s\",\n"
2225 " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
2226 gettext_noop("Name"),
2227 gettext_noop("Owner"));
2231 appendPQExpBuffer(&buf
, ",\n ");
2232 printACLColumn(&buf
, "n.nspacl");
2233 appendPQExpBuffer(&buf
,
2234 ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
2235 gettext_noop("Description"));
2238 appendPQExpBuffer(&buf
,
2239 "\nFROM pg_catalog.pg_namespace n\n"
2240 "WHERE (n.nspname !~ '^pg_temp_' OR\n"
2241 " n.nspname = (pg_catalog.current_schemas(true))[1])\n"); /* temp schema is first */
2243 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2244 NULL
, "n.nspname", NULL
,
2247 appendPQExpBuffer(&buf
, "ORDER BY 1;");
2249 res
= PSQLexec(buf
.data
, false);
2250 termPQExpBuffer(&buf
);
2254 myopt
.nullPrint
= NULL
;
2255 myopt
.title
= _("List of schemas");
2256 myopt
.translate_header
= true;
2258 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2267 * list text search parsers
2270 listTSParsers(const char *pattern
, bool verbose
)
2272 PQExpBufferData buf
;
2274 printQueryOpt myopt
= pset
.popt
;
2276 if (pset
.sversion
< 80300)
2278 fprintf(stderr
, _("The server (version %d.%d) does not support full text search.\n"),
2279 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2284 return listTSParsersVerbose(pattern
);
2286 initPQExpBuffer(&buf
);
2288 printfPQExpBuffer(&buf
,
2290 " n.nspname as \"%s\",\n"
2291 " p.prsname as \"%s\",\n"
2292 " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
2293 "FROM pg_catalog.pg_ts_parser p \n"
2294 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
2295 gettext_noop("Schema"),
2296 gettext_noop("Name"),
2297 gettext_noop("Description")
2300 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2301 "n.nspname", "p.prsname", NULL
,
2302 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
2304 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2306 res
= PSQLexec(buf
.data
, false);
2307 termPQExpBuffer(&buf
);
2311 myopt
.nullPrint
= NULL
;
2312 myopt
.title
= _("List of text search parsers");
2313 myopt
.translate_header
= true;
2315 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2322 * full description of parsers
2325 listTSParsersVerbose(const char *pattern
)
2327 PQExpBufferData buf
;
2331 initPQExpBuffer(&buf
);
2333 printfPQExpBuffer(&buf
,
2337 "FROM pg_catalog.pg_ts_parser p\n"
2338 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
2341 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2342 "n.nspname", "p.prsname", NULL
,
2343 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
2345 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2347 res
= PSQLexec(buf
.data
, false);
2348 termPQExpBuffer(&buf
);
2352 if (PQntuples(res
) == 0)
2355 fprintf(stderr
, _("Did not find any text search parser named \"%s\".\n"),
2361 for (i
= 0; i
< PQntuples(res
); i
++)
2364 const char *nspname
= NULL
;
2365 const char *prsname
;
2367 oid
= PQgetvalue(res
, i
, 0);
2368 if (!PQgetisnull(res
, i
, 1))
2369 nspname
= PQgetvalue(res
, i
, 1);
2370 prsname
= PQgetvalue(res
, i
, 2);
2372 if (!describeOneTSParser(oid
, nspname
, prsname
))
2390 describeOneTSParser(const char *oid
, const char *nspname
, const char *prsname
)
2392 PQExpBufferData buf
;
2395 printQueryOpt myopt
= pset
.popt
;
2396 static const bool translate_columns
[] = {true, false, false};
2398 initPQExpBuffer(&buf
);
2400 printfPQExpBuffer(&buf
,
2401 "SELECT '%s' AS \"%s\", \n"
2402 " p.prsstart::pg_catalog.regproc AS \"%s\", \n"
2403 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\" \n"
2404 " FROM pg_catalog.pg_ts_parser p \n"
2405 " WHERE p.oid = '%s' \n"
2408 " p.prstoken::pg_catalog.regproc, \n"
2409 " pg_catalog.obj_description(p.prstoken, 'pg_proc') \n"
2410 " FROM pg_catalog.pg_ts_parser p \n"
2411 " WHERE p.oid = '%s' \n"
2414 " p.prsend::pg_catalog.regproc, \n"
2415 " pg_catalog.obj_description(p.prsend, 'pg_proc') \n"
2416 " FROM pg_catalog.pg_ts_parser p \n"
2417 " WHERE p.oid = '%s' \n"
2420 " p.prsheadline::pg_catalog.regproc, \n"
2421 " pg_catalog.obj_description(p.prsheadline, 'pg_proc') \n"
2422 " FROM pg_catalog.pg_ts_parser p \n"
2423 " WHERE p.oid = '%s' \n"
2426 " p.prslextype::pg_catalog.regproc, \n"
2427 " pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
2428 " FROM pg_catalog.pg_ts_parser p \n"
2429 " WHERE p.oid = '%s' \n",
2430 gettext_noop("Start parse"),
2431 gettext_noop("Method"),
2432 gettext_noop("Function"),
2433 gettext_noop("Description"),
2435 gettext_noop("Get next token"),
2437 gettext_noop("End parse"),
2439 gettext_noop("Get headline"),
2441 gettext_noop("Get token types"),
2444 res
= PSQLexec(buf
.data
, false);
2445 termPQExpBuffer(&buf
);
2449 myopt
.nullPrint
= NULL
;
2451 sprintf(title
, _("Text search parser \"%s.%s\""), nspname
, prsname
);
2453 sprintf(title
, _("Text search parser \"%s\""), prsname
);
2454 myopt
.title
= title
;
2455 myopt
.footers
= NULL
;
2456 myopt
.default_footer
= false;
2457 myopt
.translate_header
= true;
2458 myopt
.translate_columns
= translate_columns
;
2460 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2464 initPQExpBuffer(&buf
);
2466 printfPQExpBuffer(&buf
,
2467 "SELECT t.alias as \"%s\", \n"
2468 " t.description as \"%s\" \n"
2469 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
2471 gettext_noop("Token name"),
2472 gettext_noop("Description"),
2475 res
= PSQLexec(buf
.data
, false);
2476 termPQExpBuffer(&buf
);
2480 myopt
.nullPrint
= NULL
;
2482 sprintf(title
, _("Token types for parser \"%s.%s\""), nspname
, prsname
);
2484 sprintf(title
, _("Token types for parser \"%s\""), prsname
);
2485 myopt
.title
= title
;
2486 myopt
.footers
= NULL
;
2487 myopt
.default_footer
= true;
2488 myopt
.translate_header
= true;
2489 myopt
.translate_columns
= NULL
;
2491 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2500 * list text search dictionaries
2503 listTSDictionaries(const char *pattern
, bool verbose
)
2505 PQExpBufferData buf
;
2507 printQueryOpt myopt
= pset
.popt
;
2509 if (pset
.sversion
< 80300)
2511 fprintf(stderr
, _("The server (version %d.%d) does not support full text search.\n"),
2512 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2516 initPQExpBuffer(&buf
);
2518 printfPQExpBuffer(&buf
,
2520 " n.nspname as \"%s\",\n"
2521 " d.dictname as \"%s\",\n",
2522 gettext_noop("Schema"),
2523 gettext_noop("Name"));
2527 appendPQExpBuffer(&buf
,
2528 " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM \n"
2529 " pg_catalog.pg_ts_template t \n"
2530 " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
2531 " WHERE d.dicttemplate = t.oid ) AS \"%s\", \n"
2532 " d.dictinitoption as \"%s\", \n",
2533 gettext_noop("Template"),
2534 gettext_noop("Init options"));
2537 appendPQExpBuffer(&buf
,
2538 " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
2539 gettext_noop("Description"));
2541 appendPQExpBuffer(&buf
, "FROM pg_catalog.pg_ts_dict d\n"
2542 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
2544 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2545 "n.nspname", "d.dictname", NULL
,
2546 "pg_catalog.pg_ts_dict_is_visible(d.oid)");
2548 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2550 res
= PSQLexec(buf
.data
, false);
2551 termPQExpBuffer(&buf
);
2555 myopt
.nullPrint
= NULL
;
2556 myopt
.title
= _("List of text search dictionaries");
2557 myopt
.translate_header
= true;
2559 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2568 * list text search templates
2571 listTSTemplates(const char *pattern
, bool verbose
)
2573 PQExpBufferData buf
;
2575 printQueryOpt myopt
= pset
.popt
;
2577 if (pset
.sversion
< 80300)
2579 fprintf(stderr
, _("The server (version %d.%d) does not support full text search.\n"),
2580 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2584 initPQExpBuffer(&buf
);
2587 printfPQExpBuffer(&buf
,
2589 " n.nspname AS \"%s\",\n"
2590 " t.tmplname AS \"%s\",\n"
2591 " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
2592 " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
2593 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
2594 gettext_noop("Schema"),
2595 gettext_noop("Name"),
2596 gettext_noop("Init"),
2597 gettext_noop("Lexize"),
2598 gettext_noop("Description"));
2600 printfPQExpBuffer(&buf
,
2602 " n.nspname AS \"%s\",\n"
2603 " t.tmplname AS \"%s\",\n"
2604 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
2605 gettext_noop("Schema"),
2606 gettext_noop("Name"),
2607 gettext_noop("Description"));
2609 appendPQExpBuffer(&buf
, "FROM pg_catalog.pg_ts_template t\n"
2610 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
2612 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2613 "n.nspname", "t.tmplname", NULL
,
2614 "pg_catalog.pg_ts_template_is_visible(t.oid)");
2616 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2618 res
= PSQLexec(buf
.data
, false);
2619 termPQExpBuffer(&buf
);
2623 myopt
.nullPrint
= NULL
;
2624 myopt
.title
= _("List of text search templates");
2625 myopt
.translate_header
= true;
2627 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2636 * list text search configurations
2639 listTSConfigs(const char *pattern
, bool verbose
)
2641 PQExpBufferData buf
;
2643 printQueryOpt myopt
= pset
.popt
;
2645 if (pset
.sversion
< 80300)
2647 fprintf(stderr
, _("The server (version %d.%d) does not support full text search.\n"),
2648 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2653 return listTSConfigsVerbose(pattern
);
2655 initPQExpBuffer(&buf
);
2657 printfPQExpBuffer(&buf
,
2659 " n.nspname as \"%s\",\n"
2660 " c.cfgname as \"%s\",\n"
2661 " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
2662 "FROM pg_catalog.pg_ts_config c\n"
2663 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
2664 gettext_noop("Schema"),
2665 gettext_noop("Name"),
2666 gettext_noop("Description")
2669 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2670 "n.nspname", "c.cfgname", NULL
,
2671 "pg_catalog.pg_ts_config_is_visible(c.oid)");
2673 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2675 res
= PSQLexec(buf
.data
, false);
2676 termPQExpBuffer(&buf
);
2680 myopt
.nullPrint
= NULL
;
2681 myopt
.title
= _("List of text search configurations");
2682 myopt
.translate_header
= true;
2684 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2691 listTSConfigsVerbose(const char *pattern
)
2693 PQExpBufferData buf
;
2697 initPQExpBuffer(&buf
);
2699 printfPQExpBuffer(&buf
,
2700 "SELECT c.oid, c.cfgname,\n"
2703 " np.nspname as pnspname \n"
2704 "FROM pg_catalog.pg_ts_config c \n"
2705 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace, \n"
2706 " pg_catalog.pg_ts_parser p \n"
2707 " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace \n"
2708 "WHERE p.oid = c.cfgparser\n"
2711 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2712 "n.nspname", "c.cfgname", NULL
,
2713 "pg_catalog.pg_ts_config_is_visible(c.oid)");
2715 appendPQExpBuffer(&buf
, "ORDER BY 3, 2;");
2717 res
= PSQLexec(buf
.data
, false);
2718 termPQExpBuffer(&buf
);
2722 if (PQntuples(res
) == 0)
2725 fprintf(stderr
, _("Did not find any text search configuration named \"%s\".\n"),
2731 for (i
= 0; i
< PQntuples(res
); i
++)
2734 const char *cfgname
;
2735 const char *nspname
= NULL
;
2736 const char *prsname
;
2737 const char *pnspname
= NULL
;
2739 oid
= PQgetvalue(res
, i
, 0);
2740 cfgname
= PQgetvalue(res
, i
, 1);
2741 if (!PQgetisnull(res
, i
, 2))
2742 nspname
= PQgetvalue(res
, i
, 2);
2743 prsname
= PQgetvalue(res
, i
, 3);
2744 if (!PQgetisnull(res
, i
, 4))
2745 pnspname
= PQgetvalue(res
, i
, 4);
2747 if (!describeOneTSConfig(oid
, nspname
, cfgname
, pnspname
, prsname
))
2765 describeOneTSConfig(const char *oid
, const char *nspname
, const char *cfgname
,
2766 const char *pnspname
, const char *prsname
)
2768 PQExpBufferData buf
,
2771 printQueryOpt myopt
= pset
.popt
;
2773 initPQExpBuffer(&buf
);
2775 printfPQExpBuffer(&buf
,
2777 " ( SELECT t.alias FROM \n"
2778 " pg_catalog.ts_token_type(c.cfgparser) AS t \n"
2779 " WHERE t.tokid = m.maptokentype ) AS \"%s\", \n"
2780 " pg_catalog.btrim( \n"
2781 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary \n"
2782 " FROM pg_catalog.pg_ts_config_map AS mm \n"
2783 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype \n"
2784 " ORDER BY mapcfg, maptokentype, mapseqno \n"
2785 " ) :: pg_catalog.text , \n"
2786 " '{}') AS \"%s\" \n"
2787 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n"
2788 "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
2789 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
2791 gettext_noop("Token"),
2792 gettext_noop("Dictionaries"),
2795 res
= PSQLexec(buf
.data
, false);
2796 termPQExpBuffer(&buf
);
2800 initPQExpBuffer(&title
);
2803 appendPQExpBuffer(&title
, _("Text search configuration \"%s.%s\""),
2806 appendPQExpBuffer(&title
, _("Text search configuration \"%s\""),
2810 appendPQExpBuffer(&title
, _("\nParser: \"%s.%s\""),
2813 appendPQExpBuffer(&title
, _("\nParser: \"%s\""),
2816 myopt
.nullPrint
= NULL
;
2817 myopt
.title
= title
.data
;
2818 myopt
.footers
= NULL
;
2819 myopt
.default_footer
= false;
2820 myopt
.translate_header
= true;
2822 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2824 termPQExpBuffer(&title
);
2834 * Describes foreign-data wrappers
2837 listForeignDataWrappers(const char *pattern
, bool verbose
)
2839 PQExpBufferData buf
;
2841 printQueryOpt myopt
= pset
.popt
;
2843 if (pset
.sversion
< 80400)
2845 fprintf(stderr
, _("The server (version %d.%d) does not support foreign-data wrappers.\n"),
2846 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2850 initPQExpBuffer(&buf
);
2851 printfPQExpBuffer(&buf
,
2852 "SELECT fdwname AS \"%s\",\n"
2853 " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n"
2854 " fdwlibrary AS \"%s\"",
2855 gettext_noop("Name"),
2856 gettext_noop("Owner"),
2857 gettext_noop("Library"));
2861 appendPQExpBuffer(&buf
, ",\n ");
2862 printACLColumn(&buf
, "fdwacl");
2863 appendPQExpBuffer(&buf
,
2864 ",\n fdwoptions AS \"%s\"",
2865 gettext_noop("Options"));
2868 appendPQExpBuffer(&buf
, "\nFROM pg_catalog.pg_foreign_data_wrapper\n");
2870 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2871 NULL
, "fdwname", NULL
, NULL
);
2873 appendPQExpBuffer(&buf
, "ORDER BY 1;");
2875 res
= PSQLexec(buf
.data
, false);
2876 termPQExpBuffer(&buf
);
2880 myopt
.nullPrint
= NULL
;
2881 myopt
.title
= _("List of foreign-data wrappers");
2882 myopt
.translate_header
= true;
2884 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2893 * Describes foreign-data servers.
2896 listForeignServers(const char *pattern
, bool verbose
)
2898 PQExpBufferData buf
;
2900 printQueryOpt myopt
= pset
.popt
;
2902 if (pset
.sversion
< 80400)
2904 fprintf(stderr
, _("The server (version %d.%d) does not support foreign-data servers.\n"),
2905 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2909 initPQExpBuffer(&buf
);
2910 printfPQExpBuffer(&buf
,
2911 "SELECT s.srvname AS \"%s\",\n"
2912 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
2913 " f.fdwname AS \"%s\"",
2914 gettext_noop("Name"),
2915 gettext_noop("Owner"),
2916 gettext_noop("Foreign-data wrapper"));
2920 appendPQExpBuffer(&buf
, ",\n ");
2921 printACLColumn(&buf
, "s.srvacl");
2922 appendPQExpBuffer(&buf
,
2924 " s.srvtype AS \"%s\",\n"
2925 " s.srvversion AS \"%s\",\n"
2926 " s.srvoptions AS \"%s\"",
2927 gettext_noop("Type"),
2928 gettext_noop("Version"),
2929 gettext_noop("Options"));
2932 appendPQExpBuffer(&buf
,
2933 "\nFROM pg_catalog.pg_foreign_server s\n"
2934 " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
2936 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2937 NULL
, "s.srvname", NULL
, NULL
);
2939 appendPQExpBuffer(&buf
, "ORDER BY 1;");
2941 res
= PSQLexec(buf
.data
, false);
2942 termPQExpBuffer(&buf
);
2946 myopt
.nullPrint
= NULL
;
2947 myopt
.title
= _("List of foreign servers");
2948 myopt
.translate_header
= true;
2950 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2959 * Describes user mappings.
2962 listUserMappings(const char *pattern
, bool verbose
)
2964 PQExpBufferData buf
;
2966 printQueryOpt myopt
= pset
.popt
;
2968 if (pset
.sversion
< 80400)
2970 fprintf(stderr
, _("The server (version %d.%d) does not support foreign-data user mappings.\n"),
2971 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2975 initPQExpBuffer(&buf
);
2976 printfPQExpBuffer(&buf
,
2977 "SELECT um.srvname AS \"%s\",\n"
2978 " um.usename AS \"%s\"",
2979 gettext_noop("Server"),
2980 gettext_noop("Username"));
2983 appendPQExpBuffer(&buf
,
2984 ",\n um.umoptions AS \"%s\"",
2985 gettext_noop("Options"));
2987 appendPQExpBuffer(&buf
, "\nFROM pg_catalog.pg_user_mappings um\n");
2989 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2990 NULL
, "um.srvname", "um.usename", NULL
);
2992 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2994 res
= PSQLexec(buf
.data
, false);
2995 termPQExpBuffer(&buf
);
2999 myopt
.nullPrint
= NULL
;
3000 myopt
.title
= _("List of user mappings");
3001 myopt
.translate_header
= true;
3003 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
3012 * Helper function for consistently formatting ACL (privilege) columns.
3013 * The proper targetlist entry is appended to buf. Note lack of any
3014 * whitespace or comma decoration.
3017 printACLColumn(PQExpBuffer buf
, const char *colname
)
3019 if (pset
.sversion
>= 80100)
3020 appendPQExpBuffer(buf
,
3021 "pg_catalog.array_to_string(%s, E'\\n') AS \"%s\"",
3022 colname
, gettext_noop("Access privileges"));
3024 appendPQExpBuffer(buf
,
3025 "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"",
3026 colname
, gettext_noop("Access privileges"));