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"));
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
189 describeFunctions(const char *pattern
, bool verbose
, bool showSystem
)
193 printQueryOpt myopt
= pset
.popt
;
195 initPQExpBuffer(&buf
);
197 printfPQExpBuffer(&buf
,
198 "SELECT n.nspname as \"%s\",\n"
199 " p.proname as \"%s\",\n",
200 gettext_noop("Schema"),
201 gettext_noop("Name"));
203 if (pset
.sversion
>= 80400)
204 appendPQExpBuffer(&buf
,
205 " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
206 " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\"",
207 gettext_noop("Result data type"),
208 gettext_noop("Argument data types"));
209 else if (pset
.sversion
>= 80100)
210 appendPQExpBuffer(&buf
,
211 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
212 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
213 " CASE WHEN proallargtypes IS NOT NULL THEN\n"
214 " pg_catalog.array_to_string(ARRAY(\n"
217 " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
218 " WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
219 " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
220 " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
223 " WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
224 " ELSE p.proargnames[s.i] || ' ' \n"
226 " pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
228 " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
231 " pg_catalog.array_to_string(ARRAY(\n"
234 " WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
235 " ELSE p.proargnames[s.i+1] || ' '\n"
237 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
239 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
242 gettext_noop("Result data type"),
243 gettext_noop("Argument data types"));
245 appendPQExpBuffer(&buf
,
246 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
247 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
248 " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\"",
249 gettext_noop("Result data type"),
250 gettext_noop("Argument data types"));
253 appendPQExpBuffer(&buf
,
255 " WHEN p.provolatile = 'i' THEN 'immutable'\n"
256 " WHEN p.provolatile = 's' THEN 'stable'\n"
257 " WHEN p.provolatile = 'v' THEN 'volatile'\n"
259 ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\",\n"
260 " l.lanname as \"%s\",\n"
261 " p.prosrc as \"%s\",\n"
262 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
263 gettext_noop("Volatility"),
264 gettext_noop("Owner"),
265 gettext_noop("Language"),
266 gettext_noop("Source code"),
267 gettext_noop("Description"));
269 appendPQExpBuffer(&buf
,
270 "\nFROM pg_catalog.pg_proc p"
271 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
274 appendPQExpBuffer(&buf
,
275 " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
278 * we skip in/out funcs by excluding functions that take or return cstring
280 appendPQExpBuffer(&buf
,
281 "WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n"
282 " AND p.proargtypes[0] IS DISTINCT FROM 'pg_catalog.cstring'::pg_catalog.regtype\n"
283 " AND NOT p.proisagg\n");
285 if (!showSystem
&& !pattern
)
286 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
287 " AND n.nspname <> 'information_schema'\n");
289 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
290 "n.nspname", "p.proname", NULL
,
291 "pg_catalog.pg_function_is_visible(p.oid)");
293 appendPQExpBuffer(&buf
, "ORDER BY 1, 2, 4;");
295 res
= PSQLexec(buf
.data
, false);
296 termPQExpBuffer(&buf
);
300 myopt
.nullPrint
= NULL
;
301 myopt
.title
= _("List of functions");
302 myopt
.translate_header
= true;
304 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
317 describeTypes(const char *pattern
, bool verbose
, bool showSystem
)
321 printQueryOpt myopt
= pset
.popt
;
323 initPQExpBuffer(&buf
);
325 printfPQExpBuffer(&buf
,
326 "SELECT n.nspname as \"%s\",\n"
327 " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
328 gettext_noop("Schema"),
329 gettext_noop("Name"));
331 appendPQExpBuffer(&buf
,
332 " t.typname AS \"%s\",\n"
333 " CASE WHEN t.typrelid != 0\n"
334 " THEN CAST('tuple' AS pg_catalog.text)\n"
335 " WHEN t.typlen < 0\n"
336 " THEN CAST('var' AS pg_catalog.text)\n"
337 " ELSE CAST(t.typlen AS pg_catalog.text)\n"
339 gettext_noop("Internal name"),
340 gettext_noop("Size"));
341 if (verbose
&& pset
.sversion
>= 80300)
342 appendPQExpBuffer(&buf
,
343 " pg_catalog.array_to_string(\n"
345 " SELECT e.enumlabel\n"
346 " FROM pg_catalog.pg_enum e\n"
347 " WHERE e.enumtypid = t.oid\n"
352 gettext_noop("Elements"));
354 appendPQExpBuffer(&buf
,
355 " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
356 gettext_noop("Description"));
358 appendPQExpBuffer(&buf
, "FROM pg_catalog.pg_type t\n"
359 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
362 * do not include complex types (typrelid!=0) unless they are standalone
365 appendPQExpBuffer(&buf
, "WHERE (t.typrelid = 0 ");
366 appendPQExpBuffer(&buf
, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
367 "WHERE c.oid = t.typrelid))\n");
369 * do not include array types (before 8.3 we have to use the assumption
370 * that their names start with underscore)
372 if (pset
.sversion
>= 80300)
373 appendPQExpBuffer(&buf
, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
375 appendPQExpBuffer(&buf
, " AND t.typname !~ '^_'\n");
377 if (!showSystem
&& !pattern
)
378 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
379 " AND n.nspname <> 'information_schema'\n");
381 /* Match name pattern against either internal or external name */
382 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
383 "n.nspname", "t.typname",
384 "pg_catalog.format_type(t.oid, NULL)",
385 "pg_catalog.pg_type_is_visible(t.oid)");
387 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
389 res
= PSQLexec(buf
.data
, false);
390 termPQExpBuffer(&buf
);
394 myopt
.nullPrint
= NULL
;
395 myopt
.title
= _("List of data types");
396 myopt
.translate_header
= true;
398 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
408 describeOperators(const char *pattern
, bool showSystem
)
412 printQueryOpt myopt
= pset
.popt
;
414 initPQExpBuffer(&buf
);
416 printfPQExpBuffer(&buf
,
417 "SELECT n.nspname as \"%s\",\n"
418 " o.oprname AS \"%s\",\n"
419 " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
420 " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
421 " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n"
422 " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
423 " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
424 "FROM pg_catalog.pg_operator o\n"
425 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
426 gettext_noop("Schema"),
427 gettext_noop("Name"),
428 gettext_noop("Left arg type"),
429 gettext_noop("Right arg type"),
430 gettext_noop("Result type"),
431 gettext_noop("Description"));
433 if (!showSystem
&& !pattern
)
434 appendPQExpBuffer(&buf
, "WHERE n.nspname <> 'pg_catalog'\n"
435 " AND n.nspname <> 'information_schema'\n");
437 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
&& !pattern
, true,
438 "n.nspname", "o.oprname", NULL
,
439 "pg_catalog.pg_operator_is_visible(o.oid)");
441 appendPQExpBuffer(&buf
, "ORDER BY 1, 2, 3, 4;");
443 res
= PSQLexec(buf
.data
, false);
444 termPQExpBuffer(&buf
);
448 myopt
.nullPrint
= NULL
;
449 myopt
.title
= _("List of operators");
450 myopt
.translate_header
= true;
452 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
462 * for \l, \list, and -l switch
465 listAllDbs(bool verbose
)
469 printQueryOpt myopt
= pset
.popt
;
471 initPQExpBuffer(&buf
);
473 printfPQExpBuffer(&buf
,
474 "SELECT d.datname as \"%s\",\n"
475 " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
476 " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
477 gettext_noop("Name"),
478 gettext_noop("Owner"),
479 gettext_noop("Encoding"));
480 if (pset
.sversion
>= 80400)
481 appendPQExpBuffer(&buf
,
482 " d.datcollate as \"%s\",\n"
483 " d.datctype as \"%s\",\n",
484 gettext_noop("Collation"),
485 gettext_noop("Ctype"));
486 appendPQExpBuffer(&buf
, " ");
487 printACLColumn(&buf
, "d.datacl");
488 if (verbose
&& pset
.sversion
>= 80200)
489 appendPQExpBuffer(&buf
,
490 ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
491 " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
492 " ELSE 'No Access'\n"
494 gettext_noop("Size"));
495 if (verbose
&& pset
.sversion
>= 80000)
496 appendPQExpBuffer(&buf
,
497 ",\n t.spcname as \"%s\"",
498 gettext_noop("Tablespace"));
499 if (verbose
&& pset
.sversion
>= 80200)
500 appendPQExpBuffer(&buf
,
501 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
502 gettext_noop("Description"));
503 appendPQExpBuffer(&buf
,
504 "\nFROM pg_catalog.pg_database d\n");
505 if (verbose
&& pset
.sversion
>= 80000)
506 appendPQExpBuffer(&buf
,
507 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
508 appendPQExpBuffer(&buf
, "ORDER BY 1;");
509 res
= PSQLexec(buf
.data
, false);
510 termPQExpBuffer(&buf
);
514 myopt
.nullPrint
= NULL
;
515 myopt
.title
= _("List of databases");
516 myopt
.translate_header
= true;
518 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
526 * List Tables' Grant/Revoke Permissions
527 * \z (now also \dp -- perhaps more mnemonic)
530 permissionsList(const char *pattern
)
534 printQueryOpt myopt
= pset
.popt
;
535 static const bool translate_columns
[] = {false, false, true, false, false};
537 initPQExpBuffer(&buf
);
540 * we ignore indexes and toast tables since they have no meaningful rights
542 printfPQExpBuffer(&buf
,
543 "SELECT n.nspname as \"%s\",\n"
544 " c.relname as \"%s\",\n"
545 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \"%s\",\n"
547 gettext_noop("Schema"),
548 gettext_noop("Name"),
549 gettext_noop("table"), gettext_noop("view"), gettext_noop("sequence"),
550 gettext_noop("Type"));
552 printACLColumn(&buf
, "c.relacl");
554 if (pset
.sversion
>= 80400)
555 appendPQExpBuffer(&buf
,
556 ",\n pg_catalog.array_to_string(ARRAY(\n"
557 " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
558 " FROM pg_catalog.pg_attribute a\n"
559 " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
560 " ), E'\\n') AS \"%s\"",
561 gettext_noop("Column access privileges"));
563 appendPQExpBuffer(&buf
, "\nFROM pg_catalog.pg_class c\n"
564 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
565 "WHERE c.relkind IN ('r', 'v', 'S')\n");
568 * Unless a schema pattern is specified, we suppress system and temp
569 * tables, since they normally aren't very interesting from a permissions
570 * point of view. You can see 'em by explicit request though, eg with \z
573 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
574 "n.nspname", "c.relname", NULL
,
575 "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
577 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
579 res
= PSQLexec(buf
.data
, false);
582 termPQExpBuffer(&buf
);
586 myopt
.nullPrint
= NULL
;
587 printfPQExpBuffer(&buf
, _("Access privileges"));
588 myopt
.title
= buf
.data
;
589 myopt
.translate_header
= true;
590 myopt
.translate_columns
= translate_columns
;
592 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
594 termPQExpBuffer(&buf
);
602 * Get object comments
606 * Note: This only lists things that actually have a description. For complete
607 * lists of things, there are other \d? commands.
610 objectDescription(const char *pattern
, bool showSystem
)
614 printQueryOpt myopt
= pset
.popt
;
615 static const bool translate_columns
[] = {false, false, true, false};
617 initPQExpBuffer(&buf
);
619 appendPQExpBuffer(&buf
,
620 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
622 gettext_noop("Schema"),
623 gettext_noop("Name"),
624 gettext_noop("Object"),
625 gettext_noop("Description"));
627 /* Aggregate descriptions */
628 appendPQExpBuffer(&buf
,
629 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
630 " n.nspname as nspname,\n"
631 " CAST(p.proname AS pg_catalog.text) as name,"
632 " CAST('%s' AS pg_catalog.text) as object\n"
633 " FROM pg_catalog.pg_proc p\n"
634 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
635 " WHERE p.proisagg\n",
636 gettext_noop("aggregate"));
638 if (!showSystem
&& !pattern
)
639 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
640 " AND n.nspname <> 'information_schema'\n");
642 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
643 "n.nspname", "p.proname", NULL
,
644 "pg_catalog.pg_function_is_visible(p.oid)");
646 /* Function descriptions (except in/outs for datatypes) */
647 appendPQExpBuffer(&buf
,
649 " SELECT p.oid as oid, p.tableoid as tableoid,\n"
650 " n.nspname as nspname,\n"
651 " CAST(p.proname AS pg_catalog.text) as name,"
652 " CAST('%s' AS pg_catalog.text) as object\n"
653 " FROM pg_catalog.pg_proc p\n"
654 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
656 " WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n"
657 " AND (p.proargtypes[0] IS NULL\n"
658 " OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n"
659 " AND NOT p.proisagg\n",
660 gettext_noop("function"));
662 if (!showSystem
&& !pattern
)
663 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
664 " AND n.nspname <> 'information_schema'\n");
666 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
667 "n.nspname", "p.proname", NULL
,
668 "pg_catalog.pg_function_is_visible(p.oid)");
670 /* Operator descriptions (only if operator has its own comment) */
671 appendPQExpBuffer(&buf
,
673 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
674 " n.nspname as nspname,\n"
675 " CAST(o.oprname AS pg_catalog.text) as name,"
676 " CAST('%s' AS pg_catalog.text) as object\n"
677 " FROM pg_catalog.pg_operator o\n"
678 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
679 gettext_noop("operator"));
681 if (!showSystem
&& !pattern
)
682 appendPQExpBuffer(&buf
, "WHERE n.nspname <> 'pg_catalog'\n"
683 " AND n.nspname <> 'information_schema'\n");
685 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
&& !pattern
, false,
686 "n.nspname", "o.oprname", NULL
,
687 "pg_catalog.pg_operator_is_visible(o.oid)");
689 /* Type description */
690 appendPQExpBuffer(&buf
,
692 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
693 " n.nspname as nspname,\n"
694 " pg_catalog.format_type(t.oid, NULL) as name,"
695 " CAST('%s' AS pg_catalog.text) as object\n"
696 " FROM pg_catalog.pg_type t\n"
697 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n",
698 gettext_noop("data type"));
700 if (!showSystem
&& !pattern
)
701 appendPQExpBuffer(&buf
, "WHERE n.nspname <> 'pg_catalog'\n"
702 " AND n.nspname <> 'information_schema'\n");
704 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
&& !pattern
, false,
705 "n.nspname", "pg_catalog.format_type(t.oid, NULL)",
707 "pg_catalog.pg_type_is_visible(t.oid)");
709 /* Relation (tables, views, indexes, sequences) descriptions */
710 appendPQExpBuffer(&buf
,
712 " SELECT c.oid as oid, c.tableoid as tableoid,\n"
713 " n.nspname as nspname,\n"
714 " CAST(c.relname AS pg_catalog.text) as name,\n"
716 " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END"
717 " AS pg_catalog.text) as object\n"
718 " FROM pg_catalog.pg_class c\n"
719 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
720 " WHERE c.relkind IN ('r', 'v', 'i', 'S')\n",
721 gettext_noop("table"),
722 gettext_noop("view"),
723 gettext_noop("index"),
724 gettext_noop("sequence"));
726 if (!showSystem
&& !pattern
)
727 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
728 " AND n.nspname <> 'information_schema'\n");
730 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
731 "n.nspname", "c.relname", NULL
,
732 "pg_catalog.pg_table_is_visible(c.oid)");
734 /* Rule description (ignore rules for views) */
735 appendPQExpBuffer(&buf
,
737 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
738 " n.nspname as nspname,\n"
739 " CAST(r.rulename AS pg_catalog.text) as name,"
740 " CAST('%s' AS pg_catalog.text) as object\n"
741 " FROM pg_catalog.pg_rewrite r\n"
742 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
743 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
744 " WHERE r.rulename != '_RETURN'\n",
745 gettext_noop("rule"));
747 if (!showSystem
&& !pattern
)
748 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
749 " AND n.nspname <> 'information_schema'\n");
751 /* XXX not sure what to do about visibility rule here? */
752 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
753 "n.nspname", "r.rulename", NULL
,
754 "pg_catalog.pg_table_is_visible(c.oid)");
756 /* Trigger description */
757 appendPQExpBuffer(&buf
,
759 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
760 " n.nspname as nspname,\n"
761 " CAST(t.tgname AS pg_catalog.text) as name,"
762 " CAST('%s' AS pg_catalog.text) as object\n"
763 " FROM pg_catalog.pg_trigger t\n"
764 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
765 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
766 gettext_noop("trigger"));
768 if (!showSystem
&& !pattern
)
769 appendPQExpBuffer(&buf
, "WHERE n.nspname <> 'pg_catalog'\n"
770 " AND n.nspname <> 'information_schema'\n");
772 /* XXX not sure what to do about visibility rule here? */
773 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
&& !pattern
, false,
774 "n.nspname", "t.tgname", NULL
,
775 "pg_catalog.pg_table_is_visible(c.oid)");
777 appendPQExpBuffer(&buf
,
779 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
781 appendPQExpBuffer(&buf
, "ORDER BY 1, 2, 3;");
783 res
= PSQLexec(buf
.data
, false);
784 termPQExpBuffer(&buf
);
788 myopt
.nullPrint
= NULL
;
789 myopt
.title
= _("Object descriptions");
790 myopt
.translate_header
= true;
791 myopt
.translate_columns
= translate_columns
;
793 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
801 * describeTableDetails (for \d)
803 * This routine finds the tables to be displayed, and calls
804 * describeOneTableDetails for each one.
806 * verbose: if true, this is \d+
809 describeTableDetails(const char *pattern
, bool verbose
, bool showSystem
)
815 initPQExpBuffer(&buf
);
817 printfPQExpBuffer(&buf
,
821 "FROM pg_catalog.pg_class c\n"
822 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
824 if (!showSystem
&& !pattern
)
825 appendPQExpBuffer(&buf
, "WHERE n.nspname <> 'pg_catalog'\n"
826 " AND n.nspname <> 'information_schema'\n");
828 processSQLNamePattern(pset
.db
, &buf
, pattern
, !showSystem
&& !pattern
, false,
829 "n.nspname", "c.relname", NULL
,
830 "pg_catalog.pg_table_is_visible(c.oid)");
832 appendPQExpBuffer(&buf
, "ORDER BY 2, 3;");
834 res
= PSQLexec(buf
.data
, false);
835 termPQExpBuffer(&buf
);
839 if (PQntuples(res
) == 0)
842 fprintf(stderr
, _("Did not find any relation named \"%s\".\n"),
848 for (i
= 0; i
< PQntuples(res
); i
++)
854 oid
= PQgetvalue(res
, i
, 0);
855 nspname
= PQgetvalue(res
, i
, 1);
856 relname
= PQgetvalue(res
, i
, 2);
858 if (!describeOneTableDetails(nspname
, relname
, oid
, verbose
))
875 * describeOneTableDetails (for \d)
877 * Unfortunately, the information presented here is so complicated that it
878 * cannot be done in a single query. So we have to assemble the printed table
879 * by hand and pass it to the underlying printTable() function.
882 describeOneTableDetails(const char *schemaname
,
883 const char *relationname
,
888 PGresult
*res
= NULL
;
889 printTableOpt myopt
= pset
.popt
.topt
;
890 printTableContent cont
;
891 bool printTableInitialized
= false;
893 char *view_def
= NULL
;
895 char **seq_values
= NULL
;
896 char **modifiers
= NULL
;
898 PQExpBufferData title
;
899 PQExpBufferData tmpbuf
;
913 bool show_modifiers
= false;
918 /* This output looks confusing in expanded mode. */
919 myopt
.expanded
= false;
921 initPQExpBuffer(&buf
);
922 initPQExpBuffer(&title
);
923 initPQExpBuffer(&tmpbuf
);
925 /* Get general table info */
926 if (pset
.sversion
>= 80400)
928 printfPQExpBuffer(&buf
,
929 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
930 "c.relhastriggers, c.relhasoids, "
931 "%s, c.reltablespace\n"
932 "FROM pg_catalog.pg_class c\n "
933 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
934 "WHERE c.oid = '%s'\n",
936 "pg_catalog.array_to_string(c.reloptions || "
937 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
941 else if (pset
.sversion
>= 80200)
943 printfPQExpBuffer(&buf
,
944 "SELECT relchecks, relkind, relhasindex, relhasrules, "
945 "reltriggers <> 0, relhasoids, "
946 "%s, reltablespace\n"
947 "FROM pg_catalog.pg_class WHERE oid = '%s'",
949 "pg_catalog.array_to_string(reloptions, E', ')" : ",''"),
952 else if (pset
.sversion
>= 80000)
954 printfPQExpBuffer(&buf
,
955 "SELECT relchecks, relkind, relhasindex, relhasrules, "
956 "reltriggers <> 0, relhasoids, "
957 "'', reltablespace\n"
958 "FROM pg_catalog.pg_class WHERE oid = '%s'",
963 printfPQExpBuffer(&buf
,
964 "SELECT relchecks, relkind, relhasindex, relhasrules, "
965 "reltriggers <> 0, relhasoids, "
967 "FROM pg_catalog.pg_class WHERE oid = '%s'",
971 res
= PSQLexec(buf
.data
, false);
975 /* Did we get anything? */
976 if (PQntuples(res
) == 0)
979 fprintf(stderr
, _("Did not find any relation with OID %s.\n"),
984 tableinfo
.checks
= atoi(PQgetvalue(res
, 0, 0));
985 tableinfo
.relkind
= *(PQgetvalue(res
, 0, 1));
986 tableinfo
.hasindex
= strcmp(PQgetvalue(res
, 0, 2), "t") == 0;
987 tableinfo
.hasrules
= strcmp(PQgetvalue(res
, 0, 3), "t") == 0;
988 tableinfo
.hastriggers
= strcmp(PQgetvalue(res
, 0, 4), "t") == 0;
989 tableinfo
.hasoids
= strcmp(PQgetvalue(res
, 0, 5), "t") == 0;
990 tableinfo
.reloptions
= pset
.sversion
>= 80200 ?
991 strdup(PQgetvalue(res
, 0, 6)) : 0;
992 tableinfo
.tablespace
= (pset
.sversion
>= 80000) ?
993 atooid(PQgetvalue(res
, 0, 7)) : 0;
998 * If it's a sequence, fetch its values and store into an
999 * array that will be used later.
1001 if (tableinfo
.relkind
== 'S')
1005 #define SEQ_NUM_COLS 10
1006 printfPQExpBuffer(&buf
,
1007 "SELECT sequence_name, last_value,\n"
1008 " start_value, increment_by,\n"
1009 " max_value, min_value, cache_value,\n"
1010 " log_cnt, is_cycled, is_called\n"
1013 /* must be separate because fmtId isn't reentrant */
1014 appendPQExpBuffer(&buf
, ".%s", fmtId(relationname
));
1016 result
= PSQLexec(buf
.data
, false);
1020 seq_values
= pg_malloc_zero((SEQ_NUM_COLS
+1) * sizeof(*seq_values
));
1022 for (i
= 0; i
< SEQ_NUM_COLS
; i
++)
1023 seq_values
[i
] = pg_strdup(PQgetvalue(result
, 0, i
));
1028 /* Get column info (index requires additional checks) */
1029 printfPQExpBuffer(&buf
, "SELECT a.attname,");
1030 appendPQExpBuffer(&buf
, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
1031 "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
1032 "\n FROM pg_catalog.pg_attrdef d"
1033 "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
1034 "\n a.attnotnull, a.attnum");
1036 appendPQExpBuffer(&buf
, ", a.attstorage, pg_catalog.col_description(a.attrelid, a.attnum)");
1037 appendPQExpBuffer(&buf
, "\nFROM pg_catalog.pg_attribute a");
1038 if (tableinfo
.relkind
== 'i')
1039 appendPQExpBuffer(&buf
, ", pg_catalog.pg_index i");
1040 appendPQExpBuffer(&buf
, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid
);
1041 if (tableinfo
.relkind
== 'i')
1042 appendPQExpBuffer(&buf
, " AND a.attrelid = i.indexrelid");
1043 appendPQExpBuffer(&buf
, "\nORDER BY a.attnum");
1045 res
= PSQLexec(buf
.data
, false);
1048 numrows
= PQntuples(res
);
1051 switch (tableinfo
.relkind
)
1054 printfPQExpBuffer(&title
, _("Table \"%s.%s\""),
1055 schemaname
, relationname
);
1058 printfPQExpBuffer(&title
, _("View \"%s.%s\""),
1059 schemaname
, relationname
);
1062 printfPQExpBuffer(&title
, _("Sequence \"%s.%s\""),
1063 schemaname
, relationname
);
1066 printfPQExpBuffer(&title
, _("Index \"%s.%s\""),
1067 schemaname
, relationname
);
1070 /* not used as of 8.2, but keep it for backwards compatibility */
1071 printfPQExpBuffer(&title
, _("Special relation \"%s.%s\""),
1072 schemaname
, relationname
);
1075 printfPQExpBuffer(&title
, _("TOAST table \"%s.%s\""),
1076 schemaname
, relationname
);
1079 printfPQExpBuffer(&title
, _("Composite type \"%s.%s\""),
1080 schemaname
, relationname
);
1083 /* untranslated unknown relkind */
1084 printfPQExpBuffer(&title
, "?%c? \"%s.%s\"",
1085 tableinfo
.relkind
, schemaname
, relationname
);
1089 /* Set the number of columns, and their names */
1091 headers
[0] = gettext_noop("Column");
1092 headers
[1] = gettext_noop("Type");
1094 if (tableinfo
.relkind
== 'r' || tableinfo
.relkind
== 'v')
1096 show_modifiers
= true;
1097 headers
[cols
++] = gettext_noop("Modifiers");
1098 modifiers
= pg_malloc_zero((numrows
+ 1) * sizeof(*modifiers
));
1101 if (tableinfo
.relkind
== 'S')
1102 headers
[cols
++] = gettext_noop("Value");
1106 headers
[cols
++] = gettext_noop("Storage");
1107 headers
[cols
++] = gettext_noop("Description");
1110 printTableInit(&cont
, &myopt
, title
.data
, cols
, numrows
);
1111 printTableInitialized
= true;
1113 for (i
= 0; i
< cols
; i
++)
1114 printTableAddHeader(&cont
, headers
[i
], true, 'l');
1116 /* Check if table is a view */
1117 if (tableinfo
.relkind
== 'v')
1121 printfPQExpBuffer(&buf
,
1122 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true)",
1124 result
= PSQLexec(buf
.data
, false);
1128 if (PQntuples(result
) > 0)
1129 view_def
= pg_strdup(PQgetvalue(result
, 0, 0));
1134 /* Generate table cells to be printed */
1135 for (i
= 0; i
< numrows
; i
++)
1138 printTableAddCell(&cont
, PQgetvalue(res
, i
, 0), false);
1141 printTableAddCell(&cont
, PQgetvalue(res
, i
, 1), false);
1143 /* Modifiers: not null and default */
1146 resetPQExpBuffer(&tmpbuf
);
1147 if (strcmp(PQgetvalue(res
, i
, 3), "t") == 0)
1148 appendPQExpBufferStr(&tmpbuf
, _("not null"));
1150 /* handle "default" here */
1151 /* (note: above we cut off the 'default' string at 128) */
1152 if (strlen(PQgetvalue(res
, i
, 2)) != 0)
1155 appendPQExpBufferStr(&tmpbuf
, " ");
1156 /* translator: default values of column definitions */
1157 appendPQExpBuffer(&tmpbuf
, _("default %s"),
1158 PQgetvalue(res
, i
, 2));
1161 modifiers
[i
] = pg_strdup(tmpbuf
.data
);
1162 printTableAddCell(&cont
, modifiers
[i
], false);
1165 /* Value: for sequences only */
1166 if (tableinfo
.relkind
== 'S')
1167 printTableAddCell(&cont
, seq_values
[i
], false);
1169 /* Storage and Description */
1172 char *storage
= PQgetvalue(res
, i
, 5);
1174 /* these strings are literal in our syntax, so not translated. */
1175 printTableAddCell(&cont
, (storage
[0]=='p' ? "plain" :
1176 (storage
[0]=='m' ? "main" :
1177 (storage
[0]=='x' ? "extended" :
1178 (storage
[0]=='e' ? "external" :
1181 printTableAddCell(&cont
, PQgetvalue(res
, i
, 6), false);
1186 if (tableinfo
.relkind
== 'i')
1188 /* Footer information about an index */
1191 printfPQExpBuffer(&buf
,
1192 "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
1193 if (pset
.sversion
>= 80200)
1194 appendPQExpBuffer(&buf
, "i.indisvalid, ");
1196 appendPQExpBuffer(&buf
, "true as indisvalid, ");
1197 appendPQExpBuffer(&buf
, "a.amname, c2.relname,\n"
1198 " pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
1199 "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
1200 "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
1201 "AND i.indrelid = c2.oid",
1204 result
= PSQLexec(buf
.data
, false);
1207 else if (PQntuples(result
) != 1)
1214 char *indisunique
= PQgetvalue(result
, 0, 0);
1215 char *indisprimary
= PQgetvalue(result
, 0, 1);
1216 char *indisclustered
= PQgetvalue(result
, 0, 2);
1217 char *indisvalid
= PQgetvalue(result
, 0, 3);
1218 char *indamname
= PQgetvalue(result
, 0, 4);
1219 char *indtable
= PQgetvalue(result
, 0, 5);
1220 char *indpred
= PQgetvalue(result
, 0, 6);
1222 if (strcmp(indisprimary
, "t") == 0)
1223 printfPQExpBuffer(&tmpbuf
, _("primary key, "));
1224 else if (strcmp(indisunique
, "t") == 0)
1225 printfPQExpBuffer(&tmpbuf
, _("unique, "));
1227 resetPQExpBuffer(&tmpbuf
);
1228 appendPQExpBuffer(&tmpbuf
, "%s, ", indamname
);
1230 /* we assume here that index and table are in same schema */
1231 appendPQExpBuffer(&tmpbuf
, _("for table \"%s.%s\""),
1232 schemaname
, indtable
);
1234 if (strlen(indpred
))
1235 appendPQExpBuffer(&tmpbuf
, _(", predicate (%s)"), indpred
);
1237 if (strcmp(indisclustered
, "t") == 0)
1238 appendPQExpBuffer(&tmpbuf
, _(", clustered"));
1240 if (strcmp(indisvalid
, "t") != 0)
1241 appendPQExpBuffer(&tmpbuf
, _(", invalid"));
1243 printTableAddFooter(&cont
, tmpbuf
.data
);
1244 add_tablespace_footer(&cont
, tableinfo
.relkind
,
1245 tableinfo
.tablespace
, true);
1252 PGresult
*result
= NULL
;
1254 /* Footer information about a view */
1255 printTableAddFooter(&cont
, _("View definition:"));
1256 printTableAddFooter(&cont
, view_def
);
1259 if (tableinfo
.hasrules
)
1261 printfPQExpBuffer(&buf
,
1262 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
1263 "FROM pg_catalog.pg_rewrite r\n"
1264 "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1",
1266 result
= PSQLexec(buf
.data
, false);
1270 if (PQntuples(result
) > 0)
1272 printTableAddFooter(&cont
, _("Rules:"));
1273 for (i
= 0; i
< PQntuples(result
); i
++)
1275 const char *ruledef
;
1277 /* Everything after "CREATE RULE" is echoed verbatim */
1278 ruledef
= PQgetvalue(result
, i
, 1);
1281 printfPQExpBuffer(&buf
, " %s", ruledef
);
1282 printTableAddFooter(&cont
, buf
.data
);
1288 else if (tableinfo
.relkind
== 'r')
1290 /* Footer information about a table */
1291 PGresult
*result
= NULL
;
1295 if (tableinfo
.hasindex
)
1297 printfPQExpBuffer(&buf
,
1298 "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
1299 if (pset
.sversion
>= 80200)
1300 appendPQExpBuffer(&buf
, "i.indisvalid, ");
1302 appendPQExpBuffer(&buf
, "true as indisvalid, ");
1303 appendPQExpBuffer(&buf
, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)");
1304 if (pset
.sversion
>= 80000)
1305 appendPQExpBuffer(&buf
, ", c2.reltablespace");
1306 appendPQExpBuffer(&buf
,
1307 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
1308 "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
1309 "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
1311 result
= PSQLexec(buf
.data
, false);
1315 tuples
= PQntuples(result
);
1319 printTableAddFooter(&cont
, _("Indexes:"));
1320 for (i
= 0; i
< tuples
; i
++)
1322 const char *indexdef
;
1323 const char *usingpos
;
1325 /* untranslated index name */
1326 printfPQExpBuffer(&buf
, " \"%s\"",
1327 PQgetvalue(result
, i
, 0));
1329 /* Label as primary key or unique (but not both) */
1330 appendPQExpBuffer(&buf
,
1331 strcmp(PQgetvalue(result
, i
, 1), "t") == 0
1333 (strcmp(PQgetvalue(result
, i
, 2), "t") == 0
1336 /* Everything after "USING" is echoed verbatim */
1337 indexdef
= PQgetvalue(result
, i
, 5);
1338 usingpos
= strstr(indexdef
, " USING ");
1340 indexdef
= usingpos
+ 7;
1342 appendPQExpBuffer(&buf
, " %s", indexdef
);
1344 if (strcmp(PQgetvalue(result
, i
, 3), "t") == 0)
1345 appendPQExpBuffer(&buf
, " CLUSTER");
1347 if (strcmp(PQgetvalue(result
, i
, 4), "t") != 0)
1348 appendPQExpBuffer(&buf
, " INVALID");
1350 printTableAddFooter(&cont
, buf
.data
);
1352 /* Print tablespace of the index on the same line */
1353 if (pset
.sversion
>= 80000)
1354 add_tablespace_footer(&cont
, 'i',
1355 atooid(PQgetvalue(result
, i
, 6)),
1362 /* print table (and column) check constraints */
1363 if (tableinfo
.checks
)
1365 printfPQExpBuffer(&buf
,
1366 "SELECT r.conname, "
1367 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
1368 "FROM pg_catalog.pg_constraint r\n"
1369 "WHERE r.conrelid = '%s' AND r.contype = 'c'\nORDER BY 1",
1371 result
= PSQLexec(buf
.data
, false);
1375 tuples
= PQntuples(result
);
1379 printTableAddFooter(&cont
, _("Check constraints:"));
1380 for (i
= 0; i
< tuples
; i
++)
1382 /* untranslated contraint name and def */
1383 printfPQExpBuffer(&buf
, " \"%s\" %s",
1384 PQgetvalue(result
, i
, 0),
1385 PQgetvalue(result
, i
, 1));
1387 printTableAddFooter(&cont
, buf
.data
);
1393 /* print foreign-key constraints (there are none if no triggers) */
1394 if (tableinfo
.hastriggers
)
1396 printfPQExpBuffer(&buf
,
1398 " pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n"
1399 "FROM pg_catalog.pg_constraint r\n"
1400 "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1",
1402 result
= PSQLexec(buf
.data
, false);
1406 tuples
= PQntuples(result
);
1410 printTableAddFooter(&cont
, _("Foreign-key constraints:"));
1411 for (i
= 0; i
< tuples
; i
++)
1413 /* untranslated constraint name and def */
1414 printfPQExpBuffer(&buf
, " \"%s\" %s",
1415 PQgetvalue(result
, i
, 0),
1416 PQgetvalue(result
, i
, 1));
1418 printTableAddFooter(&cont
, buf
.data
);
1424 /* print incoming foreign-key references (none if no triggers) */
1425 if (tableinfo
.hastriggers
)
1427 printfPQExpBuffer(&buf
,
1428 "SELECT conname, conrelid::pg_catalog.regclass,\n"
1429 " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
1430 "FROM pg_catalog.pg_constraint c\n"
1431 "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1",
1433 result
= PSQLexec(buf
.data
, false);
1437 tuples
= PQntuples(result
);
1441 printTableAddFooter(&cont
, _("Referenced by:"));
1442 for (i
= 0; i
< tuples
; i
++)
1444 /* translator: the first %s is a FK name, the following are
1445 * a table name and the FK definition */
1446 printfPQExpBuffer(&buf
, _(" \"%s\" IN %s %s"),
1447 PQgetvalue(result
, i
, 0),
1448 PQgetvalue(result
, i
, 1),
1449 PQgetvalue(result
, i
, 2));
1451 printTableAddFooter(&cont
, buf
.data
);
1458 if (tableinfo
.hasrules
)
1460 if (pset
.sversion
>= 80300)
1462 printfPQExpBuffer(&buf
,
1463 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
1465 "FROM pg_catalog.pg_rewrite r\n"
1466 "WHERE r.ev_class = '%s' ORDER BY 1",
1471 printfPQExpBuffer(&buf
,
1472 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
1473 "'O'::char AS ev_enabled\n"
1474 "FROM pg_catalog.pg_rewrite r\n"
1475 "WHERE r.ev_class = '%s' ORDER BY 1",
1478 result
= PSQLexec(buf
.data
, false);
1482 tuples
= PQntuples(result
);
1489 for (category
= 0; category
< 4; category
++)
1491 have_heading
= false;
1493 for (i
= 0; i
< tuples
; i
++)
1495 const char *ruledef
;
1496 bool list_rule
= false;
1501 if (*PQgetvalue(result
, i
, 2) == 'O')
1505 if (*PQgetvalue(result
, i
, 2) == 'D')
1509 if (*PQgetvalue(result
, i
, 2) == 'A')
1513 if (*PQgetvalue(result
, i
, 2) == 'R')
1525 printfPQExpBuffer(&buf
, _("Rules:"));
1528 printfPQExpBuffer(&buf
, _("Disabled rules:"));
1531 printfPQExpBuffer(&buf
, _("Rules firing always:"));
1534 printfPQExpBuffer(&buf
, _("Rules firing on replica only:"));
1537 printTableAddFooter(&cont
, buf
.data
);
1538 have_heading
= true;
1541 /* Everything after "CREATE RULE" is echoed verbatim */
1542 ruledef
= PQgetvalue(result
, i
, 1);
1544 printfPQExpBuffer(&buf
, " %s", ruledef
);
1545 printTableAddFooter(&cont
, buf
.data
);
1552 /* print triggers (but ignore foreign-key triggers) */
1553 if (tableinfo
.hastriggers
)
1555 printfPQExpBuffer(&buf
,
1557 "pg_catalog.pg_get_triggerdef(t.oid), "
1559 "FROM pg_catalog.pg_trigger t\n"
1560 "WHERE t.tgrelid = '%s' AND ",
1562 if (pset
.sversion
>= 80300)
1563 appendPQExpBuffer(&buf
, "t.tgconstraint = 0");
1565 appendPQExpBuffer(&buf
,
1566 "(NOT tgisconstraint "
1568 " (SELECT 1 FROM pg_catalog.pg_depend d "
1569 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
1570 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
1571 appendPQExpBuffer(&buf
, "\nORDER BY 1");
1573 result
= PSQLexec(buf
.data
, false);
1577 tuples
= PQntuples(result
);
1585 * split the output into 4 different categories. Enabled triggers,
1586 * disabled triggers and the two special ALWAYS and REPLICA
1589 for (category
= 0; category
< 4; category
++)
1591 have_heading
= false;
1592 for (i
= 0; i
< tuples
; i
++)
1596 const char *usingpos
;
1597 const char *tgenabled
;
1599 /* Check if this trigger falls into the current category */
1600 tgenabled
= PQgetvalue(result
, i
, 2);
1601 list_trigger
= false;
1605 if (*tgenabled
== 'O' || *tgenabled
== 't')
1606 list_trigger
= true;
1609 if (*tgenabled
== 'D' || *tgenabled
== 'f')
1610 list_trigger
= true;
1613 if (*tgenabled
== 'A')
1614 list_trigger
= true;
1617 if (*tgenabled
== 'R')
1618 list_trigger
= true;
1621 if (list_trigger
== false)
1624 /* Print the category heading once */
1625 if (have_heading
== false)
1630 printfPQExpBuffer(&buf
, _("Triggers:"));
1633 printfPQExpBuffer(&buf
, _("Disabled triggers:"));
1636 printfPQExpBuffer(&buf
, _("Triggers firing always:"));
1639 printfPQExpBuffer(&buf
, _("Triggers firing on replica only:"));
1643 printTableAddFooter(&cont
, buf
.data
);
1644 have_heading
= true;
1647 /* Everything after "TRIGGER" is echoed verbatim */
1648 tgdef
= PQgetvalue(result
, i
, 1);
1649 usingpos
= strstr(tgdef
, " TRIGGER ");
1651 tgdef
= usingpos
+ 9;
1653 printfPQExpBuffer(&buf
, " %s", tgdef
);
1654 printTableAddFooter(&cont
, buf
.data
);
1661 /* print inherited tables */
1662 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
);
1664 result
= PSQLexec(buf
.data
, false);
1668 tuples
= PQntuples(result
);
1670 for (i
= 0; i
< tuples
; i
++)
1672 const char *s
= _("Inherits");
1675 printfPQExpBuffer(&buf
, "%s: %s", s
, PQgetvalue(result
, i
, 0));
1677 printfPQExpBuffer(&buf
, "%*s %s", (int) strlen(s
), "", PQgetvalue(result
, i
, 0));
1679 appendPQExpBuffer(&buf
, ",");
1681 printTableAddFooter(&cont
, buf
.data
);
1687 const char *s
= _("Has OIDs");
1689 printfPQExpBuffer(&buf
, "%s: %s", s
,
1690 (tableinfo
.hasoids
? _("yes") : _("no")));
1691 printTableAddFooter(&cont
, buf
.data
);
1693 /* print reloptions */
1694 if (pset
.sversion
>= 80200)
1696 if (tableinfo
.reloptions
&& tableinfo
.reloptions
[0] != '\0')
1698 const char *t
= _("Options");
1700 printfPQExpBuffer(&buf
, "%s: %s", t
,
1701 tableinfo
.reloptions
);
1702 printTableAddFooter(&cont
, buf
.data
);
1707 add_tablespace_footer(&cont
, tableinfo
.relkind
, tableinfo
.tablespace
,
1711 printTable(&cont
, pset
.queryFout
, pset
.logfile
);
1712 printTableCleanup(&cont
);
1719 if (printTableInitialized
)
1720 printTableCleanup(&cont
);
1721 termPQExpBuffer(&buf
);
1722 termPQExpBuffer(&title
);
1723 termPQExpBuffer(&tmpbuf
);
1727 for (ptr
= seq_values
; *ptr
; ptr
++)
1734 for (ptr
= modifiers
; *ptr
; ptr
++)
1749 * Add a tablespace description to a footer. If 'newline' is true, it is added
1750 * in a new line; otherwise it's appended to the current value of the last
1754 add_tablespace_footer(printTableContent
*const cont
, char relkind
,
1755 Oid tablespace
, const bool newline
)
1757 /* relkinds for which we support tablespaces */
1758 if (relkind
== 'r' || relkind
== 'i')
1761 * We ignore the database default tablespace so that users not using
1762 * tablespaces don't need to know about them. This case also covers
1763 * pre-8.0 servers, for which tablespace will always be 0.
1765 if (tablespace
!= 0)
1767 PGresult
*result
= NULL
;
1768 PQExpBufferData buf
;
1770 initPQExpBuffer(&buf
);
1771 printfPQExpBuffer(&buf
,
1772 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
1773 "WHERE oid = '%u'", tablespace
);
1774 result
= PSQLexec(buf
.data
, false);
1777 /* Should always be the case, but.... */
1778 if (PQntuples(result
) > 0)
1782 /* Add the tablespace as a new footer */
1783 printfPQExpBuffer(&buf
, _("Tablespace: \"%s\""),
1784 PQgetvalue(result
, 0, 0));
1785 printTableAddFooter(cont
, buf
.data
);
1789 /* Append the tablespace to the latest footer */
1790 printfPQExpBuffer(&buf
, "%s", cont
->footer
->data
);
1791 /* translator: before this string there's an index
1792 * description like '"foo_pkey" PRIMARY KEY, btree (a)' */
1793 appendPQExpBuffer(&buf
, _(", tablespace \"%s\""),
1794 PQgetvalue(result
, 0, 0));
1795 printTableSetFooter(cont
, buf
.data
);
1799 termPQExpBuffer(&buf
);
1807 * Describes roles. Any schema portion of the pattern is ignored.
1810 describeRoles(const char *pattern
, bool verbose
)
1812 PQExpBufferData buf
;
1814 printTableContent cont
;
1815 printTableOpt myopt
= pset
.popt
.topt
;
1820 const char align
= 'l';
1823 initPQExpBuffer(&buf
);
1825 if (pset
.sversion
>= 80100)
1827 printfPQExpBuffer(&buf
,
1828 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
1829 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
1830 " r.rolconnlimit,\n"
1831 " ARRAY(SELECT b.rolname\n"
1832 " FROM pg_catalog.pg_auth_members m\n"
1833 " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
1834 " WHERE m.member = r.oid) as memberof");
1836 if (verbose
&& pset
.sversion
>= 80200)
1838 appendPQExpBufferStr(&buf
, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
1842 appendPQExpBufferStr(&buf
, "\nFROM pg_catalog.pg_roles r\n");
1844 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
1845 NULL
, "r.rolname", NULL
, NULL
);
1849 printfPQExpBuffer(&buf
,
1850 "SELECT u.usename AS rolname,\n"
1851 " u.usesuper AS rolsuper,\n"
1852 " true AS rolinherit, false AS rolcreaterole,\n"
1853 " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
1854 " -1 AS rolconnlimit,\n"
1855 " ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
1856 "\nFROM pg_catalog.pg_user u\n");
1858 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
1859 NULL
, "u.usename", NULL
, NULL
);
1862 appendPQExpBuffer(&buf
, "ORDER BY 1;");
1864 res
= PSQLexec(buf
.data
, false);
1868 nrows
= PQntuples(res
);
1869 attr
= pg_malloc_zero((nrows
+ 1) * sizeof(*attr
));
1871 printTableInit(&cont
, &myopt
, _("List of roles"), ncols
, nrows
);
1873 printTableAddHeader(&cont
, gettext_noop("Role name"), true, align
);
1874 printTableAddHeader(&cont
, gettext_noop("Attributes"), true, align
);
1875 printTableAddHeader(&cont
, gettext_noop("Member of"), true, align
);
1877 if (verbose
&& pset
.sversion
>= 80200)
1878 printTableAddHeader(&cont
, gettext_noop("Description"), true, align
);
1880 for (i
= 0; i
< nrows
; i
++)
1882 printTableAddCell(&cont
, PQgetvalue(res
, i
, 0), false);
1884 resetPQExpBuffer(&buf
);
1885 if (strcmp(PQgetvalue(res
, i
, 1), "t") == 0)
1886 add_role_attribute(&buf
, _("Superuser"));
1888 if (strcmp(PQgetvalue(res
, i
, 2), "t") != 0)
1889 add_role_attribute(&buf
, _("No inheritance"));
1891 if (strcmp(PQgetvalue(res
, i
, 3), "t") == 0)
1892 add_role_attribute(&buf
, _("Create role"));
1894 if (strcmp(PQgetvalue(res
, i
, 4), "t") == 0)
1895 add_role_attribute(&buf
, _("Create DB"));
1897 if (strcmp(PQgetvalue(res
, i
, 5), "t") != 0)
1898 add_role_attribute(&buf
, _("Cannot login"));
1900 conns
= atoi(PQgetvalue(res
, i
, 6));
1904 appendPQExpBufferStr(&buf
, "\n");
1907 appendPQExpBuffer(&buf
, _("No connections"));
1909 appendPQExpBuffer(&buf
, ngettext("1 connection", "%d connections", conns
), conns
);
1912 attr
[i
] = pg_strdup(buf
.data
);
1914 printTableAddCell(&cont
, attr
[i
], false);
1916 printTableAddCell(&cont
, PQgetvalue(res
, i
, 7), false);
1918 if (verbose
&& pset
.sversion
>= 80200)
1919 printTableAddCell(&cont
, PQgetvalue(res
, i
, 8), false);
1921 termPQExpBuffer(&buf
);
1923 printTable(&cont
, pset
.queryFout
, pset
.logfile
);
1924 printTableCleanup(&cont
);
1926 for (i
= 0; i
< nrows
; i
++)
1935 add_role_attribute(PQExpBuffer buf
, const char *const str
)
1938 appendPQExpBufferStr(buf
, "\n");
1940 appendPQExpBufferStr(buf
, str
);
1947 * handler for \dt, \di, etc.
1949 * tabtypes is an array of characters, specifying what info is desired:
1954 * (any order of the above is fine)
1955 * If tabtypes is empty, we default to \dtvs.
1958 listTables(const char *tabtypes
, const char *pattern
, bool verbose
, bool showSystem
)
1960 bool showTables
= strchr(tabtypes
, 't') != NULL
;
1961 bool showIndexes
= strchr(tabtypes
, 'i') != NULL
;
1962 bool showViews
= strchr(tabtypes
, 'v') != NULL
;
1963 bool showSeq
= strchr(tabtypes
, 's') != NULL
;
1965 PQExpBufferData buf
;
1967 printQueryOpt myopt
= pset
.popt
;
1968 static const bool translate_columns
[] = {false, false, true, false, false, false, false};
1970 if (!(showTables
|| showIndexes
|| showViews
|| showSeq
))
1971 showTables
= showViews
= showSeq
= true;
1973 initPQExpBuffer(&buf
);
1976 * Note: as of Pg 8.2, we no longer use relkind 's', but we keep it here
1977 * for backwards compatibility.
1979 printfPQExpBuffer(&buf
,
1980 "SELECT n.nspname as \"%s\",\n"
1981 " c.relname as \"%s\",\n"
1982 " 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"
1983 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
1984 gettext_noop("Schema"),
1985 gettext_noop("Name"),
1986 gettext_noop("table"),
1987 gettext_noop("view"),
1988 gettext_noop("index"),
1989 gettext_noop("sequence"),
1990 gettext_noop("special"),
1991 gettext_noop("Type"),
1992 gettext_noop("Owner"));
1995 appendPQExpBuffer(&buf
,
1996 ",\n c2.relname as \"%s\"",
1997 gettext_noop("Table"));
1999 if (verbose
&& pset
.sversion
>= 80100)
2000 appendPQExpBuffer(&buf
,
2001 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
2002 gettext_noop("Size"));
2004 appendPQExpBuffer(&buf
,
2005 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
2006 gettext_noop("Description"));
2008 appendPQExpBuffer(&buf
,
2009 "\nFROM pg_catalog.pg_class c"
2010 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
2012 appendPQExpBuffer(&buf
,
2013 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
2014 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
2016 appendPQExpBuffer(&buf
, "\nWHERE c.relkind IN (");
2018 appendPQExpBuffer(&buf
, "'r',");
2020 appendPQExpBuffer(&buf
, "'v',");
2022 appendPQExpBuffer(&buf
, "'i',");
2024 appendPQExpBuffer(&buf
, "'S',");
2025 if (showSystem
|| pattern
)
2026 appendPQExpBuffer(&buf
, "'s',"); /* was RELKIND_SPECIAL in <= 8.1 */
2027 appendPQExpBuffer(&buf
, "''"); /* dummy */
2028 appendPQExpBuffer(&buf
, ")\n");
2030 if (!showSystem
&& !pattern
)
2031 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
2032 " AND n.nspname <> 'information_schema'\n");
2035 * TOAST objects are suppressed unconditionally. Since we don't provide
2036 * any way to select relkind 't' above, we would never show toast tables
2037 * in any case; it seems a bit confusing to allow their indexes to be
2038 * shown. Use plain \d if you really need to look at a TOAST table/index.
2040 appendPQExpBuffer(&buf
, " AND n.nspname !~ '^pg_toast'\n");
2042 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2043 "n.nspname", "c.relname", NULL
,
2044 "pg_catalog.pg_table_is_visible(c.oid)");
2046 appendPQExpBuffer(&buf
, "ORDER BY 1,2;");
2048 res
= PSQLexec(buf
.data
, false);
2049 termPQExpBuffer(&buf
);
2053 if (PQntuples(res
) == 0 && !pset
.quiet
)
2056 fprintf(pset
.queryFout
, _("No matching relations found.\n"));
2058 fprintf(pset
.queryFout
, _("No relations found.\n"));
2062 myopt
.nullPrint
= NULL
;
2063 myopt
.title
= _("List of relations");
2064 myopt
.translate_header
= true;
2065 myopt
.translate_columns
= translate_columns
;
2067 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2078 * Describes domains.
2081 listDomains(const char *pattern
, bool showSystem
)
2083 PQExpBufferData buf
;
2085 printQueryOpt myopt
= pset
.popt
;
2087 initPQExpBuffer(&buf
);
2089 printfPQExpBuffer(&buf
,
2090 "SELECT n.nspname as \"%s\",\n"
2091 " t.typname as \"%s\",\n"
2092 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
2093 " CASE WHEN t.typnotnull AND t.typdefault IS NOT NULL THEN 'not null default '||t.typdefault\n"
2094 " WHEN t.typnotnull AND t.typdefault IS NULL THEN 'not null'\n"
2095 " WHEN NOT t.typnotnull AND t.typdefault IS NOT NULL THEN 'default '||t.typdefault\n"
2098 " pg_catalog.array_to_string(ARRAY(\n"
2099 " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
2100 " ), ' ') as \"%s\"\n"
2101 "FROM pg_catalog.pg_type t\n"
2102 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"
2103 "WHERE t.typtype = 'd'\n",
2104 gettext_noop("Schema"),
2105 gettext_noop("Name"),
2106 gettext_noop("Type"),
2107 gettext_noop("Modifier"),
2108 gettext_noop("Check"));
2110 if (!showSystem
&& !pattern
)
2111 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
2112 " AND n.nspname <> 'information_schema'\n");
2114 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2115 "n.nspname", "t.typname", NULL
,
2116 "pg_catalog.pg_type_is_visible(t.oid)");
2118 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2120 res
= PSQLexec(buf
.data
, false);
2121 termPQExpBuffer(&buf
);
2125 myopt
.nullPrint
= NULL
;
2126 myopt
.title
= _("List of domains");
2127 myopt
.translate_header
= true;
2129 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2138 * Describes conversions.
2141 listConversions(const char *pattern
, bool showSystem
)
2143 PQExpBufferData buf
;
2145 printQueryOpt myopt
= pset
.popt
;
2146 static const bool translate_columns
[] = {false, false, false, false, true};
2148 initPQExpBuffer(&buf
);
2150 printfPQExpBuffer(&buf
,
2151 "SELECT n.nspname AS \"%s\",\n"
2152 " c.conname AS \"%s\",\n"
2153 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
2154 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
2155 " CASE WHEN c.condefault THEN '%s'\n"
2156 " ELSE '%s' END AS \"%s\"\n"
2157 "FROM pg_catalog.pg_conversion c, pg_catalog.pg_namespace n\n"
2158 "WHERE n.oid = c.connamespace\n",
2159 gettext_noop("Schema"),
2160 gettext_noop("Name"),
2161 gettext_noop("Source"),
2162 gettext_noop("Destination"),
2163 gettext_noop("yes"), gettext_noop("no"),
2164 gettext_noop("Default?"));
2166 if (!showSystem
&& !pattern
)
2167 appendPQExpBuffer(&buf
, " AND n.nspname <> 'pg_catalog'\n"
2168 " AND n.nspname <> 'information_schema'\n");
2170 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2171 "n.nspname", "c.conname", NULL
,
2172 "pg_catalog.pg_conversion_is_visible(c.oid)");
2174 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2176 res
= PSQLexec(buf
.data
, false);
2177 termPQExpBuffer(&buf
);
2181 myopt
.nullPrint
= NULL
;
2182 myopt
.title
= _("List of conversions");
2183 myopt
.translate_header
= true;
2184 myopt
.translate_columns
= translate_columns
;
2186 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2198 listCasts(const char *pattern
)
2200 PQExpBufferData buf
;
2202 printQueryOpt myopt
= pset
.popt
;
2203 static const bool translate_columns
[] = {false, false, false, true};
2205 initPQExpBuffer(&buf
);
2207 * We need a left join to pg_proc for binary casts; the others are just
2208 * paranoia. Also note that we don't attempt to localize '(binary
2209 * coercible)', because there's too much risk of gettext translating a
2210 * function name that happens to match some string in the PO database.
2212 printfPQExpBuffer(&buf
,
2213 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
2214 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
2215 " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
2218 " CASE WHEN c.castcontext = 'e' THEN '%s'\n"
2219 " WHEN c.castcontext = 'a' THEN '%s'\n"
2222 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
2223 " ON c.castfunc = p.oid\n"
2224 " LEFT JOIN pg_catalog.pg_type ts\n"
2225 " ON c.castsource = ts.oid\n"
2226 " LEFT JOIN pg_catalog.pg_namespace ns\n"
2227 " ON ns.oid = ts.typnamespace\n"
2228 " LEFT JOIN pg_catalog.pg_type tt\n"
2229 " ON c.casttarget = tt.oid\n"
2230 " LEFT JOIN pg_catalog.pg_namespace nt\n"
2231 " ON nt.oid = tt.typnamespace\n"
2233 gettext_noop("Source type"),
2234 gettext_noop("Target type"),
2235 gettext_noop("Function"),
2236 gettext_noop("no"), gettext_noop("in assignment"), gettext_noop("yes"),
2237 gettext_noop("Implicit?"));
2240 * Match name pattern against either internal or external name of either
2241 * castsource or casttarget
2243 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2244 "ns.nspname", "ts.typname",
2245 "pg_catalog.format_type(ts.oid, NULL)",
2246 "pg_catalog.pg_type_is_visible(ts.oid)");
2248 appendPQExpBuffer(&buf
, ") OR (true");
2250 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2251 "nt.nspname", "tt.typname",
2252 "pg_catalog.format_type(tt.oid, NULL)",
2253 "pg_catalog.pg_type_is_visible(tt.oid)");
2255 appendPQExpBuffer(&buf
, ")\nORDER BY 1, 2;");
2257 res
= PSQLexec(buf
.data
, false);
2258 termPQExpBuffer(&buf
);
2262 myopt
.nullPrint
= NULL
;
2263 myopt
.title
= _("List of casts");
2264 myopt
.translate_header
= true;
2265 myopt
.translate_columns
= translate_columns
;
2267 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2276 * Describes schemas (namespaces)
2279 listSchemas(const char *pattern
, bool verbose
)
2281 PQExpBufferData buf
;
2283 printQueryOpt myopt
= pset
.popt
;
2285 initPQExpBuffer(&buf
);
2286 printfPQExpBuffer(&buf
,
2287 "SELECT n.nspname AS \"%s\",\n"
2288 " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
2289 gettext_noop("Name"),
2290 gettext_noop("Owner"));
2294 appendPQExpBuffer(&buf
, ",\n ");
2295 printACLColumn(&buf
, "n.nspacl");
2296 appendPQExpBuffer(&buf
,
2297 ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
2298 gettext_noop("Description"));
2301 appendPQExpBuffer(&buf
,
2302 "\nFROM pg_catalog.pg_namespace n\n"
2303 "WHERE (n.nspname !~ '^pg_temp_' OR\n"
2304 " n.nspname = (pg_catalog.current_schemas(true))[1])\n"); /* temp schema is first */
2306 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2307 NULL
, "n.nspname", NULL
,
2310 appendPQExpBuffer(&buf
, "ORDER BY 1;");
2312 res
= PSQLexec(buf
.data
, false);
2313 termPQExpBuffer(&buf
);
2317 myopt
.nullPrint
= NULL
;
2318 myopt
.title
= _("List of schemas");
2319 myopt
.translate_header
= true;
2321 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2330 * list text search parsers
2333 listTSParsers(const char *pattern
, bool verbose
)
2335 PQExpBufferData buf
;
2337 printQueryOpt myopt
= pset
.popt
;
2339 if (pset
.sversion
< 80300)
2341 fprintf(stderr
, _("The server (version %d.%d) does not support full text search.\n"),
2342 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2347 return listTSParsersVerbose(pattern
);
2349 initPQExpBuffer(&buf
);
2351 printfPQExpBuffer(&buf
,
2353 " n.nspname as \"%s\",\n"
2354 " p.prsname as \"%s\",\n"
2355 " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
2356 "FROM pg_catalog.pg_ts_parser p \n"
2357 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
2358 gettext_noop("Schema"),
2359 gettext_noop("Name"),
2360 gettext_noop("Description")
2363 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2364 "n.nspname", "p.prsname", NULL
,
2365 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
2367 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2369 res
= PSQLexec(buf
.data
, false);
2370 termPQExpBuffer(&buf
);
2374 myopt
.nullPrint
= NULL
;
2375 myopt
.title
= _("List of text search parsers");
2376 myopt
.translate_header
= true;
2378 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2385 * full description of parsers
2388 listTSParsersVerbose(const char *pattern
)
2390 PQExpBufferData buf
;
2394 initPQExpBuffer(&buf
);
2396 printfPQExpBuffer(&buf
,
2400 "FROM pg_catalog.pg_ts_parser p\n"
2401 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
2404 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2405 "n.nspname", "p.prsname", NULL
,
2406 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
2408 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2410 res
= PSQLexec(buf
.data
, false);
2411 termPQExpBuffer(&buf
);
2415 if (PQntuples(res
) == 0)
2418 fprintf(stderr
, _("Did not find any text search parser named \"%s\".\n"),
2424 for (i
= 0; i
< PQntuples(res
); i
++)
2427 const char *nspname
= NULL
;
2428 const char *prsname
;
2430 oid
= PQgetvalue(res
, i
, 0);
2431 if (!PQgetisnull(res
, i
, 1))
2432 nspname
= PQgetvalue(res
, i
, 1);
2433 prsname
= PQgetvalue(res
, i
, 2);
2435 if (!describeOneTSParser(oid
, nspname
, prsname
))
2453 describeOneTSParser(const char *oid
, const char *nspname
, const char *prsname
)
2455 PQExpBufferData buf
;
2458 printQueryOpt myopt
= pset
.popt
;
2459 static const bool translate_columns
[] = {true, false, false};
2461 initPQExpBuffer(&buf
);
2463 printfPQExpBuffer(&buf
,
2464 "SELECT '%s' AS \"%s\", \n"
2465 " p.prsstart::pg_catalog.regproc AS \"%s\", \n"
2466 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\" \n"
2467 " FROM pg_catalog.pg_ts_parser p \n"
2468 " WHERE p.oid = '%s' \n"
2471 " p.prstoken::pg_catalog.regproc, \n"
2472 " pg_catalog.obj_description(p.prstoken, 'pg_proc') \n"
2473 " FROM pg_catalog.pg_ts_parser p \n"
2474 " WHERE p.oid = '%s' \n"
2477 " p.prsend::pg_catalog.regproc, \n"
2478 " pg_catalog.obj_description(p.prsend, 'pg_proc') \n"
2479 " FROM pg_catalog.pg_ts_parser p \n"
2480 " WHERE p.oid = '%s' \n"
2483 " p.prsheadline::pg_catalog.regproc, \n"
2484 " pg_catalog.obj_description(p.prsheadline, 'pg_proc') \n"
2485 " FROM pg_catalog.pg_ts_parser p \n"
2486 " WHERE p.oid = '%s' \n"
2489 " p.prslextype::pg_catalog.regproc, \n"
2490 " pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
2491 " FROM pg_catalog.pg_ts_parser p \n"
2492 " WHERE p.oid = '%s' \n",
2493 gettext_noop("Start parse"),
2494 gettext_noop("Method"),
2495 gettext_noop("Function"),
2496 gettext_noop("Description"),
2498 gettext_noop("Get next token"),
2500 gettext_noop("End parse"),
2502 gettext_noop("Get headline"),
2504 gettext_noop("Get token types"),
2507 res
= PSQLexec(buf
.data
, false);
2508 termPQExpBuffer(&buf
);
2512 myopt
.nullPrint
= NULL
;
2514 sprintf(title
, _("Text search parser \"%s.%s\""), nspname
, prsname
);
2516 sprintf(title
, _("Text search parser \"%s\""), prsname
);
2517 myopt
.title
= title
;
2518 myopt
.footers
= NULL
;
2519 myopt
.default_footer
= false;
2520 myopt
.translate_header
= true;
2521 myopt
.translate_columns
= translate_columns
;
2523 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2527 initPQExpBuffer(&buf
);
2529 printfPQExpBuffer(&buf
,
2530 "SELECT t.alias as \"%s\", \n"
2531 " t.description as \"%s\" \n"
2532 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
2534 gettext_noop("Token name"),
2535 gettext_noop("Description"),
2538 res
= PSQLexec(buf
.data
, false);
2539 termPQExpBuffer(&buf
);
2543 myopt
.nullPrint
= NULL
;
2545 sprintf(title
, _("Token types for parser \"%s.%s\""), nspname
, prsname
);
2547 sprintf(title
, _("Token types for parser \"%s\""), prsname
);
2548 myopt
.title
= title
;
2549 myopt
.footers
= NULL
;
2550 myopt
.default_footer
= true;
2551 myopt
.translate_header
= true;
2552 myopt
.translate_columns
= NULL
;
2554 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2563 * list text search dictionaries
2566 listTSDictionaries(const char *pattern
, bool verbose
)
2568 PQExpBufferData buf
;
2570 printQueryOpt myopt
= pset
.popt
;
2572 if (pset
.sversion
< 80300)
2574 fprintf(stderr
, _("The server (version %d.%d) does not support full text search.\n"),
2575 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2579 initPQExpBuffer(&buf
);
2581 printfPQExpBuffer(&buf
,
2583 " n.nspname as \"%s\",\n"
2584 " d.dictname as \"%s\",\n",
2585 gettext_noop("Schema"),
2586 gettext_noop("Name"));
2590 appendPQExpBuffer(&buf
,
2591 " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM \n"
2592 " pg_catalog.pg_ts_template t \n"
2593 " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
2594 " WHERE d.dicttemplate = t.oid ) AS \"%s\", \n"
2595 " d.dictinitoption as \"%s\", \n",
2596 gettext_noop("Template"),
2597 gettext_noop("Init options"));
2600 appendPQExpBuffer(&buf
,
2601 " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
2602 gettext_noop("Description"));
2604 appendPQExpBuffer(&buf
, "FROM pg_catalog.pg_ts_dict d\n"
2605 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
2607 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2608 "n.nspname", "d.dictname", NULL
,
2609 "pg_catalog.pg_ts_dict_is_visible(d.oid)");
2611 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2613 res
= PSQLexec(buf
.data
, false);
2614 termPQExpBuffer(&buf
);
2618 myopt
.nullPrint
= NULL
;
2619 myopt
.title
= _("List of text search dictionaries");
2620 myopt
.translate_header
= true;
2622 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2631 * list text search templates
2634 listTSTemplates(const char *pattern
, bool verbose
)
2636 PQExpBufferData buf
;
2638 printQueryOpt myopt
= pset
.popt
;
2640 if (pset
.sversion
< 80300)
2642 fprintf(stderr
, _("The server (version %d.%d) does not support full text search.\n"),
2643 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2647 initPQExpBuffer(&buf
);
2650 printfPQExpBuffer(&buf
,
2652 " n.nspname AS \"%s\",\n"
2653 " t.tmplname AS \"%s\",\n"
2654 " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
2655 " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
2656 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
2657 gettext_noop("Schema"),
2658 gettext_noop("Name"),
2659 gettext_noop("Init"),
2660 gettext_noop("Lexize"),
2661 gettext_noop("Description"));
2663 printfPQExpBuffer(&buf
,
2665 " n.nspname AS \"%s\",\n"
2666 " t.tmplname AS \"%s\",\n"
2667 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
2668 gettext_noop("Schema"),
2669 gettext_noop("Name"),
2670 gettext_noop("Description"));
2672 appendPQExpBuffer(&buf
, "FROM pg_catalog.pg_ts_template t\n"
2673 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
2675 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2676 "n.nspname", "t.tmplname", NULL
,
2677 "pg_catalog.pg_ts_template_is_visible(t.oid)");
2679 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2681 res
= PSQLexec(buf
.data
, false);
2682 termPQExpBuffer(&buf
);
2686 myopt
.nullPrint
= NULL
;
2687 myopt
.title
= _("List of text search templates");
2688 myopt
.translate_header
= true;
2690 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2699 * list text search configurations
2702 listTSConfigs(const char *pattern
, bool verbose
)
2704 PQExpBufferData buf
;
2706 printQueryOpt myopt
= pset
.popt
;
2708 if (pset
.sversion
< 80300)
2710 fprintf(stderr
, _("The server (version %d.%d) does not support full text search.\n"),
2711 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2716 return listTSConfigsVerbose(pattern
);
2718 initPQExpBuffer(&buf
);
2720 printfPQExpBuffer(&buf
,
2722 " n.nspname as \"%s\",\n"
2723 " c.cfgname as \"%s\",\n"
2724 " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
2725 "FROM pg_catalog.pg_ts_config c\n"
2726 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
2727 gettext_noop("Schema"),
2728 gettext_noop("Name"),
2729 gettext_noop("Description")
2732 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2733 "n.nspname", "c.cfgname", NULL
,
2734 "pg_catalog.pg_ts_config_is_visible(c.oid)");
2736 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
2738 res
= PSQLexec(buf
.data
, false);
2739 termPQExpBuffer(&buf
);
2743 myopt
.nullPrint
= NULL
;
2744 myopt
.title
= _("List of text search configurations");
2745 myopt
.translate_header
= true;
2747 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2754 listTSConfigsVerbose(const char *pattern
)
2756 PQExpBufferData buf
;
2760 initPQExpBuffer(&buf
);
2762 printfPQExpBuffer(&buf
,
2763 "SELECT c.oid, c.cfgname,\n"
2766 " np.nspname as pnspname \n"
2767 "FROM pg_catalog.pg_ts_config c \n"
2768 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace, \n"
2769 " pg_catalog.pg_ts_parser p \n"
2770 " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace \n"
2771 "WHERE p.oid = c.cfgparser\n"
2774 processSQLNamePattern(pset
.db
, &buf
, pattern
, true, false,
2775 "n.nspname", "c.cfgname", NULL
,
2776 "pg_catalog.pg_ts_config_is_visible(c.oid)");
2778 appendPQExpBuffer(&buf
, "ORDER BY 3, 2;");
2780 res
= PSQLexec(buf
.data
, false);
2781 termPQExpBuffer(&buf
);
2785 if (PQntuples(res
) == 0)
2788 fprintf(stderr
, _("Did not find any text search configuration named \"%s\".\n"),
2794 for (i
= 0; i
< PQntuples(res
); i
++)
2797 const char *cfgname
;
2798 const char *nspname
= NULL
;
2799 const char *prsname
;
2800 const char *pnspname
= NULL
;
2802 oid
= PQgetvalue(res
, i
, 0);
2803 cfgname
= PQgetvalue(res
, i
, 1);
2804 if (!PQgetisnull(res
, i
, 2))
2805 nspname
= PQgetvalue(res
, i
, 2);
2806 prsname
= PQgetvalue(res
, i
, 3);
2807 if (!PQgetisnull(res
, i
, 4))
2808 pnspname
= PQgetvalue(res
, i
, 4);
2810 if (!describeOneTSConfig(oid
, nspname
, cfgname
, pnspname
, prsname
))
2828 describeOneTSConfig(const char *oid
, const char *nspname
, const char *cfgname
,
2829 const char *pnspname
, const char *prsname
)
2831 PQExpBufferData buf
,
2834 printQueryOpt myopt
= pset
.popt
;
2836 initPQExpBuffer(&buf
);
2838 printfPQExpBuffer(&buf
,
2840 " ( SELECT t.alias FROM \n"
2841 " pg_catalog.ts_token_type(c.cfgparser) AS t \n"
2842 " WHERE t.tokid = m.maptokentype ) AS \"%s\", \n"
2843 " pg_catalog.btrim( \n"
2844 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary \n"
2845 " FROM pg_catalog.pg_ts_config_map AS mm \n"
2846 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype \n"
2847 " ORDER BY mapcfg, maptokentype, mapseqno \n"
2848 " ) :: pg_catalog.text , \n"
2849 " '{}') AS \"%s\" \n"
2850 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n"
2851 "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
2852 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
2854 gettext_noop("Token"),
2855 gettext_noop("Dictionaries"),
2858 res
= PSQLexec(buf
.data
, false);
2859 termPQExpBuffer(&buf
);
2863 initPQExpBuffer(&title
);
2866 appendPQExpBuffer(&title
, _("Text search configuration \"%s.%s\""),
2869 appendPQExpBuffer(&title
, _("Text search configuration \"%s\""),
2873 appendPQExpBuffer(&title
, _("\nParser: \"%s.%s\""),
2876 appendPQExpBuffer(&title
, _("\nParser: \"%s\""),
2879 myopt
.nullPrint
= NULL
;
2880 myopt
.title
= title
.data
;
2881 myopt
.footers
= NULL
;
2882 myopt
.default_footer
= false;
2883 myopt
.translate_header
= true;
2885 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2887 termPQExpBuffer(&title
);
2897 * Describes foreign-data wrappers
2900 listForeignDataWrappers(const char *pattern
, bool verbose
)
2902 PQExpBufferData buf
;
2904 printQueryOpt myopt
= pset
.popt
;
2906 if (pset
.sversion
< 80400)
2908 fprintf(stderr
, _("The server (version %d.%d) does not support foreign-data wrappers.\n"),
2909 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2913 initPQExpBuffer(&buf
);
2914 printfPQExpBuffer(&buf
,
2915 "SELECT fdwname AS \"%s\",\n"
2916 " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n"
2917 " fdwvalidator::pg_catalog.regproc AS \"%s\"",
2918 gettext_noop("Name"),
2919 gettext_noop("Owner"),
2920 gettext_noop("Validator"));
2924 appendPQExpBuffer(&buf
, ",\n ");
2925 printACLColumn(&buf
, "fdwacl");
2926 appendPQExpBuffer(&buf
,
2927 ",\n fdwoptions AS \"%s\"",
2928 gettext_noop("Options"));
2931 appendPQExpBuffer(&buf
, "\nFROM pg_catalog.pg_foreign_data_wrapper\n");
2933 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
2934 NULL
, "fdwname", NULL
, NULL
);
2936 appendPQExpBuffer(&buf
, "ORDER BY 1;");
2938 res
= PSQLexec(buf
.data
, false);
2939 termPQExpBuffer(&buf
);
2943 myopt
.nullPrint
= NULL
;
2944 myopt
.title
= _("List of foreign-data wrappers");
2945 myopt
.translate_header
= true;
2947 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
2956 * Describes foreign servers.
2959 listForeignServers(const char *pattern
, bool verbose
)
2961 PQExpBufferData buf
;
2963 printQueryOpt myopt
= pset
.popt
;
2965 if (pset
.sversion
< 80400)
2967 fprintf(stderr
, _("The server (version %d.%d) does not support foreign servers.\n"),
2968 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
2972 initPQExpBuffer(&buf
);
2973 printfPQExpBuffer(&buf
,
2974 "SELECT s.srvname AS \"%s\",\n"
2975 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
2976 " f.fdwname AS \"%s\"",
2977 gettext_noop("Name"),
2978 gettext_noop("Owner"),
2979 gettext_noop("Foreign-data wrapper"));
2983 appendPQExpBuffer(&buf
, ",\n ");
2984 printACLColumn(&buf
, "s.srvacl");
2985 appendPQExpBuffer(&buf
,
2987 " s.srvtype AS \"%s\",\n"
2988 " s.srvversion AS \"%s\",\n"
2989 " s.srvoptions AS \"%s\"",
2990 gettext_noop("Type"),
2991 gettext_noop("Version"),
2992 gettext_noop("Options"));
2995 appendPQExpBuffer(&buf
,
2996 "\nFROM pg_catalog.pg_foreign_server s\n"
2997 " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
2999 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
3000 NULL
, "s.srvname", NULL
, NULL
);
3002 appendPQExpBuffer(&buf
, "ORDER BY 1;");
3004 res
= PSQLexec(buf
.data
, false);
3005 termPQExpBuffer(&buf
);
3009 myopt
.nullPrint
= NULL
;
3010 myopt
.title
= _("List of foreign servers");
3011 myopt
.translate_header
= true;
3013 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
3022 * Describes user mappings.
3025 listUserMappings(const char *pattern
, bool verbose
)
3027 PQExpBufferData buf
;
3029 printQueryOpt myopt
= pset
.popt
;
3031 if (pset
.sversion
< 80400)
3033 fprintf(stderr
, _("The server (version %d.%d) does not support user mappings.\n"),
3034 pset
.sversion
/ 10000, (pset
.sversion
/ 100) % 100);
3038 initPQExpBuffer(&buf
);
3039 printfPQExpBuffer(&buf
,
3040 "SELECT um.srvname AS \"%s\",\n"
3041 " um.usename AS \"%s\"",
3042 gettext_noop("Server"),
3043 gettext_noop("User name"));
3046 appendPQExpBuffer(&buf
,
3047 ",\n um.umoptions AS \"%s\"",
3048 gettext_noop("Options"));
3050 appendPQExpBuffer(&buf
, "\nFROM pg_catalog.pg_user_mappings um\n");
3052 processSQLNamePattern(pset
.db
, &buf
, pattern
, false, false,
3053 NULL
, "um.srvname", "um.usename", NULL
);
3055 appendPQExpBuffer(&buf
, "ORDER BY 1, 2;");
3057 res
= PSQLexec(buf
.data
, false);
3058 termPQExpBuffer(&buf
);
3062 myopt
.nullPrint
= NULL
;
3063 myopt
.title
= _("List of user mappings");
3064 myopt
.translate_header
= true;
3066 printQuery(res
, &myopt
, pset
.queryFout
, pset
.logfile
);
3075 * Helper function for consistently formatting ACL (privilege) columns.
3076 * The proper targetlist entry is appended to buf. Note lack of any
3077 * whitespace or comma decoration.
3080 printACLColumn(PQExpBuffer buf
, const char *colname
)
3082 if (pset
.sversion
>= 80100)
3083 appendPQExpBuffer(buf
,
3084 "pg_catalog.array_to_string(%s, E'\\n') AS \"%s\"",
3085 colname
, gettext_noop("Access privileges"));
3087 appendPQExpBuffer(buf
,
3088 "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"",
3089 colname
, gettext_noop("Access privileges"));