PostgreSQL Source Code  git master
describe.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include "catalog/pg_am.h"
#include "catalog/pg_attribute_d.h"
#include "catalog/pg_cast_d.h"
#include "catalog/pg_class_d.h"
#include "catalog/pg_default_acl_d.h"
#include "common.h"
#include "common/logging.h"
#include "describe.h"
#include "fe_utils/mbprint.h"
#include "fe_utils/print.h"
#include "fe_utils/string_utils.h"
#include "settings.h"
#include "variables.h"
Include dependency graph for describe.c:

Go to the source code of this file.

Functions

static const char * map_typename_pattern (const char *pattern)
 
static bool describeOneTableDetails (const char *schemaname, const char *relationname, const char *oid, bool verbose)
 
static void add_tablespace_footer (printTableContent *const cont, char relkind, Oid tablespace, const bool newline)
 
static void add_role_attribute (PQExpBuffer buf, const char *const str)
 
static bool listTSParsersVerbose (const char *pattern)
 
static bool describeOneTSParser (const char *oid, const char *nspname, const char *prsname)
 
static bool listTSConfigsVerbose (const char *pattern)
 
static bool describeOneTSConfig (const char *oid, const char *nspname, const char *cfgname, const char *pnspname, const char *prsname)
 
static void printACLColumn (PQExpBuffer buf, const char *colname)
 
static bool listOneExtensionContents (const char *extname, const char *oid)
 
bool describeAggregates (const char *pattern, bool verbose, bool showSystem)
 
bool describeAccessMethods (const char *pattern, bool verbose)
 
bool describeTablespaces (const char *pattern, bool verbose)
 
bool describeFunctions (const char *functypes, const char *func_pattern, char **arg_patterns, int num_arg_patterns, bool verbose, bool showSystem)
 
bool describeTypes (const char *pattern, bool verbose, bool showSystem)
 
bool describeOperators (const char *oper_pattern, char **arg_patterns, int num_arg_patterns, bool verbose, bool showSystem)
 
bool listAllDbs (const char *pattern, bool verbose)
 
bool permissionsList (const char *pattern)
 
bool listDefaultACLs (const char *pattern)
 
bool objectDescription (const char *pattern, bool showSystem)
 
bool describeTableDetails (const char *pattern, bool verbose, bool showSystem)
 
bool describeRoles (const char *pattern, bool verbose, bool showSystem)
 
bool listDbRoleSettings (const char *pattern, const char *pattern2)
 
bool listTables (const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
 
bool listPartitionedTables (const char *reltypes, const char *pattern, bool verbose)
 
bool listLanguages (const char *pattern, bool verbose, bool showSystem)
 
bool listDomains (const char *pattern, bool verbose, bool showSystem)
 
bool listConversions (const char *pattern, bool verbose, bool showSystem)
 
bool listEventTriggers (const char *pattern, bool verbose)
 
bool listExtendedStats (const char *pattern)
 
bool listCasts (const char *pattern, bool verbose)
 
bool listCollations (const char *pattern, bool verbose, bool showSystem)
 
bool listSchemas (const char *pattern, bool verbose, bool showSystem)
 
bool listTSParsers (const char *pattern, bool verbose)
 
bool listTSDictionaries (const char *pattern, bool verbose)
 
bool listTSTemplates (const char *pattern, bool verbose)
 
bool listTSConfigs (const char *pattern, bool verbose)
 
bool listForeignDataWrappers (const char *pattern, bool verbose)
 
bool listForeignServers (const char *pattern, bool verbose)
 
bool listUserMappings (const char *pattern, bool verbose)
 
bool listForeignTables (const char *pattern, bool verbose)
 
bool listExtensions (const char *pattern)
 
bool listExtensionContents (const char *pattern)
 
bool listPublications (const char *pattern)
 
static bool addFooterToPublicationDesc (PQExpBuffer buf, char *footermsg, bool singlecol, printTableContent *cont)
 
bool describePublications (const char *pattern)
 
bool describeSubscriptions (const char *pattern, bool verbose)
 
bool listOperatorClasses (const char *access_method_pattern, const char *type_pattern, bool verbose)
 
bool listOperatorFamilies (const char *access_method_pattern, const char *type_pattern, bool verbose)
 
bool listOpFamilyOperators (const char *access_method_pattern, const char *family_pattern, bool verbose)
 
bool listOpFamilyFunctions (const char *access_method_pattern, const char *family_pattern, bool verbose)
 
bool listLargeObjects (bool verbose)
 

Function Documentation

◆ add_role_attribute()

static void add_role_attribute ( PQExpBuffer  buf,
const char *const  str 
)
static

Definition at line 3621 of file describe.c.

3622 {
3623  if (buf->len > 0)
3624  appendPQExpBufferStr(buf, ", ");
3625 
3627 }
static char * buf
Definition: pg_test_fsync.c:70
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369

References appendPQExpBufferStr(), buf, and generate_unaccent_rules::str.

Referenced by describeRoles().

◆ add_tablespace_footer()

static void add_tablespace_footer ( printTableContent *const  cont,
char  relkind,
Oid  tablespace,
const bool  newline 
)
static

Definition at line 3418 of file describe.c.

3420 {
3421  /* relkinds for which we support tablespaces */
3422  if (relkind == RELKIND_RELATION ||
3423  relkind == RELKIND_MATVIEW ||
3424  relkind == RELKIND_INDEX ||
3425  relkind == RELKIND_PARTITIONED_TABLE ||
3426  relkind == RELKIND_PARTITIONED_INDEX ||
3427  relkind == RELKIND_TOASTVALUE)
3428  {
3429  /*
3430  * We ignore the database default tablespace so that users not using
3431  * tablespaces don't need to know about them.
3432  */
3433  if (tablespace != 0)
3434  {
3435  PGresult *result = NULL;
3437 
3438  initPQExpBuffer(&buf);
3440  "SELECT spcname FROM pg_catalog.pg_tablespace\n"
3441  "WHERE oid = '%u';", tablespace);
3442  result = PSQLexec(buf.data);
3443  if (!result)
3444  {
3445  termPQExpBuffer(&buf);
3446  return;
3447  }
3448  /* Should always be the case, but.... */
3449  if (PQntuples(result) > 0)
3450  {
3451  if (newline)
3452  {
3453  /* Add the tablespace as a new footer */
3454  printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
3455  PQgetvalue(result, 0, 0));
3456  printTableAddFooter(cont, buf.data);
3457  }
3458  else
3459  {
3460  /* Append the tablespace to the latest footer */
3461  printfPQExpBuffer(&buf, "%s", cont->footer->data);
3462 
3463  /*-------
3464  translator: before this string there's an index description like
3465  '"foo_pkey" PRIMARY KEY, btree (a)' */
3466  appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
3467  PQgetvalue(result, 0, 0));
3468  printTableSetFooter(cont, buf.data);
3469  }
3470  }
3471  PQclear(result);
3472  termPQExpBuffer(&buf);
3473  }
3474  }
3475 }
PGresult * PSQLexec(const char *query)
Definition: common.c:541
#define _(x)
Definition: elog.c:89
void PQclear(PGresult *res)
Definition: fe-exec.c:694
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3248
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3642
void printTableSetFooter(printTableContent *const content, const char *footer)
Definition: print.c:3277
void printTableAddFooter(printTableContent *const content, const char *footer)
Definition: print.c:3252
char * tablespace
Definition: pgbench.c:227
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
static chr newline(void)
Definition: regc_lex.c:1001
printTableFooter * footer
Definition: print.h:161
char * data
Definition: print.h:139

References _, appendPQExpBuffer(), buf, printTableFooter::data, printTableContent::footer, initPQExpBuffer(), newline(), PQclear(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), printTableAddFooter(), printTableSetFooter(), PSQLexec(), tablespace, and termPQExpBuffer().

Referenced by describeOneTableDetails().

◆ addFooterToPublicationDesc()

static bool addFooterToPublicationDesc ( PQExpBuffer  buf,
char *  footermsg,
bool  singlecol,
printTableContent cont 
)
static

Definition at line 5847 of file describe.c.

5849 {
5850  PGresult *res;
5851  int count = 0;
5852  int i = 0;
5853 
5854  res = PSQLexec(buf->data);
5855  if (!res)
5856  return false;
5857  else
5858  count = PQntuples(res);
5859 
5860  if (count > 0)
5861  printTableAddFooter(cont, _(footermsg));
5862 
5863  for (i = 0; i < count; i++)
5864  {
5865  if (!singlecol)
5866  printfPQExpBuffer(buf, " \"%s.%s\"", PQgetvalue(res, i, 0),
5867  PQgetvalue(res, i, 1));
5868  else
5869  printfPQExpBuffer(buf, " \"%s\"", PQgetvalue(res, i, 0));
5870 
5871  printTableAddFooter(cont, buf->data);
5872  }
5873 
5874  PQclear(res);
5875  return true;
5876 }
int i
Definition: isn.c:73

References _, buf, i, PQclear(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), printTableAddFooter(), PSQLexec(), and res.

Referenced by describePublications().

◆ describeAccessMethods()

bool describeAccessMethods ( const char *  pattern,
bool  verbose 
)

Definition at line 131 of file describe.c.

132 {
134  PGresult *res;
135  printQueryOpt myopt = pset.popt;
136  static const bool translate_columns[] = {false, true, false, false};
137 
138  if (pset.sversion < 90600)
139  {
140  char sverbuf[32];
141 
142  pg_log_error("The server (version %s) does not support access methods.",
144  sverbuf, sizeof(sverbuf)));
145  return true;
146  }
147 
149 
151  "SELECT amname AS \"%s\",\n"
152  " CASE amtype"
153  " WHEN 'i' THEN '%s'"
154  " WHEN 't' THEN '%s'"
155  " END AS \"%s\"",
156  gettext_noop("Name"),
157  gettext_noop("Index"),
158  gettext_noop("Table"),
159  gettext_noop("Type"));
160 
161  if (verbose)
162  {
164  ",\n amhandler AS \"%s\",\n"
165  " pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
166  gettext_noop("Handler"),
167  gettext_noop("Description"));
168  }
169 
171  "\nFROM pg_catalog.pg_am\n");
172 
173  processSQLNamePattern(pset.db, &buf, pattern, false, false,
174  NULL, "amname", NULL,
175  NULL);
176 
177  appendPQExpBufferStr(&buf, "ORDER BY 1;");
178 
179  res = PSQLexec(buf.data);
181  if (!res)
182  return false;
183 
184  myopt.nullPrint = NULL;
185  myopt.title = _("List of access methods");
186  myopt.translate_header = true;
187  myopt.translate_columns = translate_columns;
188  myopt.n_translate_columns = lengthof(translate_columns);
189 
190  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
191 
192  PQclear(res);
193  return true;
194 }
#define gettext_noop(x)
Definition: c.h:1194
#define lengthof(array)
Definition: c.h:734
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3490
#define pg_log_error(...)
Definition: logging.h:80
static int verbose
PsqlSettings pset
Definition: startup.c:32
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:890
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177
printQueryOpt popt
Definition: settings.h:91
FILE * logfile
Definition: settings.h:116
PGconn * db
Definition: settings.h:82
FILE * queryFout
Definition: settings.h:84
const bool * translate_columns
Definition: print.h:174
char * nullPrint
Definition: print.h:170
char * title
Definition: print.h:171
bool translate_header
Definition: print.h:173
int n_translate_columns
Definition: print.h:176

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, formatPGVersionNumber(), gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, pg_log_error, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ describeAggregates()

bool describeAggregates ( const char *  pattern,
bool  verbose,
bool  showSystem 
)

Definition at line 65 of file describe.c.

66 {
68  PGresult *res;
69  printQueryOpt myopt = pset.popt;
70 
72 
74  "SELECT n.nspname as \"%s\",\n"
75  " p.proname AS \"%s\",\n"
76  " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n"
77  " CASE WHEN p.pronargs = 0\n"
78  " THEN CAST('*' AS pg_catalog.text)\n"
79  " ELSE pg_catalog.pg_get_function_arguments(p.oid)\n"
80  " END AS \"%s\",\n",
81  gettext_noop("Schema"),
82  gettext_noop("Name"),
83  gettext_noop("Result data type"),
84  gettext_noop("Argument data types"));
85 
86  if (pset.sversion >= 110000)
88  " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
89  "FROM pg_catalog.pg_proc p\n"
90  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
91  "WHERE p.prokind = 'a'\n",
92  gettext_noop("Description"));
93  else
95  " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
96  "FROM pg_catalog.pg_proc p\n"
97  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
98  "WHERE p.proisagg\n",
99  gettext_noop("Description"));
100 
101  if (!showSystem && !pattern)
102  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
103  " AND n.nspname <> 'information_schema'\n");
104 
105  processSQLNamePattern(pset.db, &buf, pattern, true, false,
106  "n.nspname", "p.proname", NULL,
107  "pg_catalog.pg_function_is_visible(p.oid)");
108 
109  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
110 
111  res = PSQLexec(buf.data);
113  if (!res)
114  return false;
115 
116  myopt.nullPrint = NULL;
117  myopt.title = _("List of aggregate functions");
118  myopt.translate_header = true;
119 
120  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
121 
122  PQclear(res);
123  return true;
124 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, and printQueryOpt::translate_header.

Referenced by exec_command_d().

◆ describeFunctions()

bool describeFunctions ( const char *  functypes,
const char *  func_pattern,
char **  arg_patterns,
int  num_arg_patterns,
bool  verbose,
bool  showSystem 
)

Definition at line 270 of file describe.c.

273 {
274  bool showAggregate = strchr(functypes, 'a') != NULL;
275  bool showNormal = strchr(functypes, 'n') != NULL;
276  bool showProcedure = strchr(functypes, 'p') != NULL;
277  bool showTrigger = strchr(functypes, 't') != NULL;
278  bool showWindow = strchr(functypes, 'w') != NULL;
279  bool have_where;
281  PGresult *res;
282  printQueryOpt myopt = pset.popt;
283  static const bool translate_columns[] = {false, false, false, false, true, true, true, false, true, false, false, false, false};
284 
285  /* No "Parallel" column before 9.6 */
286  static const bool translate_columns_pre_96[] = {false, false, false, false, true, true, false, true, false, false, false, false};
287 
288  if (strlen(functypes) != strspn(functypes, "anptwS+"))
289  {
290  pg_log_error("\\df only takes [anptwS+] as options");
291  return true;
292  }
293 
294  if (showProcedure && pset.sversion < 110000)
295  {
296  char sverbuf[32];
297 
298  pg_log_error("\\df does not take a \"%c\" option with server version %s",
299  'p',
301  sverbuf, sizeof(sverbuf)));
302  return true;
303  }
304 
305  if (!showAggregate && !showNormal && !showProcedure && !showTrigger && !showWindow)
306  {
307  showAggregate = showNormal = showTrigger = showWindow = true;
308  if (pset.sversion >= 110000)
309  showProcedure = true;
310  }
311 
313 
315  "SELECT n.nspname as \"%s\",\n"
316  " p.proname as \"%s\",\n",
317  gettext_noop("Schema"),
318  gettext_noop("Name"));
319 
320  if (pset.sversion >= 110000)
322  " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
323  " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
324  " CASE p.prokind\n"
325  " WHEN 'a' THEN '%s'\n"
326  " WHEN 'w' THEN '%s'\n"
327  " WHEN 'p' THEN '%s'\n"
328  " ELSE '%s'\n"
329  " END as \"%s\"",
330  gettext_noop("Result data type"),
331  gettext_noop("Argument data types"),
332  /* translator: "agg" is short for "aggregate" */
333  gettext_noop("agg"),
334  gettext_noop("window"),
335  gettext_noop("proc"),
336  gettext_noop("func"),
337  gettext_noop("Type"));
338  else
340  " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
341  " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
342  " CASE\n"
343  " WHEN p.proisagg THEN '%s'\n"
344  " WHEN p.proiswindow THEN '%s'\n"
345  " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
346  " ELSE '%s'\n"
347  " END as \"%s\"",
348  gettext_noop("Result data type"),
349  gettext_noop("Argument data types"),
350  /* translator: "agg" is short for "aggregate" */
351  gettext_noop("agg"),
352  gettext_noop("window"),
353  gettext_noop("trigger"),
354  gettext_noop("func"),
355  gettext_noop("Type"));
356 
357  if (verbose)
358  {
360  ",\n CASE\n"
361  " WHEN p.provolatile = 'i' THEN '%s'\n"
362  " WHEN p.provolatile = 's' THEN '%s'\n"
363  " WHEN p.provolatile = 'v' THEN '%s'\n"
364  " END as \"%s\"",
365  gettext_noop("immutable"),
366  gettext_noop("stable"),
367  gettext_noop("volatile"),
368  gettext_noop("Volatility"));
369  if (pset.sversion >= 90600)
371  ",\n CASE\n"
372  " WHEN p.proparallel = 'r' THEN '%s'\n"
373  " WHEN p.proparallel = 's' THEN '%s'\n"
374  " WHEN p.proparallel = 'u' THEN '%s'\n"
375  " END as \"%s\"",
376  gettext_noop("restricted"),
377  gettext_noop("safe"),
378  gettext_noop("unsafe"),
379  gettext_noop("Parallel"));
381  ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\""
382  ",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\"",
383  gettext_noop("Owner"),
384  gettext_noop("definer"),
385  gettext_noop("invoker"),
386  gettext_noop("Security"));
387  appendPQExpBufferStr(&buf, ",\n ");
388  printACLColumn(&buf, "p.proacl");
390  ",\n l.lanname as \"%s\"",
391  gettext_noop("Language"));
392  if (pset.sversion >= 140000)
394  ",\n COALESCE(pg_catalog.pg_get_function_sqlbody(p.oid), p.prosrc) as \"%s\"",
395  gettext_noop("Source code"));
396  else
398  ",\n p.prosrc as \"%s\"",
399  gettext_noop("Source code"));
401  ",\n pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
402  gettext_noop("Description"));
403  }
404 
406  "\nFROM pg_catalog.pg_proc p"
407  "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
408 
409  for (int i = 0; i < num_arg_patterns; i++)
410  {
412  " LEFT JOIN pg_catalog.pg_type t%d ON t%d.oid = p.proargtypes[%d]\n"
413  " LEFT JOIN pg_catalog.pg_namespace nt%d ON nt%d.oid = t%d.typnamespace\n",
414  i, i, i, i, i, i);
415  }
416 
417  if (verbose)
419  " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
420 
421  have_where = false;
422 
423  /* filter by function type, if requested */
424  if (showNormal && showAggregate && showProcedure && showTrigger && showWindow)
425  /* Do nothing */ ;
426  else if (showNormal)
427  {
428  if (!showAggregate)
429  {
430  if (have_where)
431  appendPQExpBufferStr(&buf, " AND ");
432  else
433  {
434  appendPQExpBufferStr(&buf, "WHERE ");
435  have_where = true;
436  }
437  if (pset.sversion >= 110000)
438  appendPQExpBufferStr(&buf, "p.prokind <> 'a'\n");
439  else
440  appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
441  }
442  if (!showProcedure && pset.sversion >= 110000)
443  {
444  if (have_where)
445  appendPQExpBufferStr(&buf, " AND ");
446  else
447  {
448  appendPQExpBufferStr(&buf, "WHERE ");
449  have_where = true;
450  }
451  appendPQExpBufferStr(&buf, "p.prokind <> 'p'\n");
452  }
453  if (!showTrigger)
454  {
455  if (have_where)
456  appendPQExpBufferStr(&buf, " AND ");
457  else
458  {
459  appendPQExpBufferStr(&buf, "WHERE ");
460  have_where = true;
461  }
462  appendPQExpBufferStr(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
463  }
464  if (!showWindow)
465  {
466  if (have_where)
467  appendPQExpBufferStr(&buf, " AND ");
468  else
469  {
470  appendPQExpBufferStr(&buf, "WHERE ");
471  have_where = true;
472  }
473  if (pset.sversion >= 110000)
474  appendPQExpBufferStr(&buf, "p.prokind <> 'w'\n");
475  else
476  appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
477  }
478  }
479  else
480  {
481  bool needs_or = false;
482 
483  appendPQExpBufferStr(&buf, "WHERE (\n ");
484  have_where = true;
485  /* Note: at least one of these must be true ... */
486  if (showAggregate)
487  {
488  if (pset.sversion >= 110000)
489  appendPQExpBufferStr(&buf, "p.prokind = 'a'\n");
490  else
491  appendPQExpBufferStr(&buf, "p.proisagg\n");
492  needs_or = true;
493  }
494  if (showTrigger)
495  {
496  if (needs_or)
497  appendPQExpBufferStr(&buf, " OR ");
499  "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n");
500  needs_or = true;
501  }
502  if (showProcedure)
503  {
504  if (needs_or)
505  appendPQExpBufferStr(&buf, " OR ");
506  appendPQExpBufferStr(&buf, "p.prokind = 'p'\n");
507  needs_or = true;
508  }
509  if (showWindow)
510  {
511  if (needs_or)
512  appendPQExpBufferStr(&buf, " OR ");
513  if (pset.sversion >= 110000)
514  appendPQExpBufferStr(&buf, "p.prokind = 'w'\n");
515  else
516  appendPQExpBufferStr(&buf, "p.proiswindow\n");
517  }
518  appendPQExpBufferStr(&buf, " )\n");
519  }
520 
521  processSQLNamePattern(pset.db, &buf, func_pattern, have_where, false,
522  "n.nspname", "p.proname", NULL,
523  "pg_catalog.pg_function_is_visible(p.oid)");
524 
525  for (int i = 0; i < num_arg_patterns; i++)
526  {
527  if (strcmp(arg_patterns[i], "-") != 0)
528  {
529  /*
530  * Match type-name patterns against either internal or external
531  * name, like \dT. Unlike \dT, there seems no reason to
532  * discriminate against arrays or composite types.
533  */
534  char nspname[64];
535  char typname[64];
536  char ft[64];
537  char tiv[64];
538 
539  snprintf(nspname, sizeof(nspname), "nt%d.nspname", i);
540  snprintf(typname, sizeof(typname), "t%d.typname", i);
541  snprintf(ft, sizeof(ft),
542  "pg_catalog.format_type(t%d.oid, NULL)", i);
543  snprintf(tiv, sizeof(tiv),
544  "pg_catalog.pg_type_is_visible(t%d.oid)", i);
546  map_typename_pattern(arg_patterns[i]),
547  true, false,
548  nspname, typname, ft, tiv);
549  }
550  else
551  {
552  /* "-" pattern specifies no such parameter */
553  appendPQExpBuffer(&buf, " AND t%d.typname IS NULL\n", i);
554  }
555  }
556 
557  if (!showSystem && !func_pattern)
558  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
559  " AND n.nspname <> 'information_schema'\n");
560 
561  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
562 
563  res = PSQLexec(buf.data);
565  if (!res)
566  return false;
567 
568  myopt.nullPrint = NULL;
569  myopt.title = _("List of functions");
570  myopt.translate_header = true;
571  if (pset.sversion >= 90600)
572  {
573  myopt.translate_columns = translate_columns;
574  myopt.n_translate_columns = lengthof(translate_columns);
575  }
576  else
577  {
578  myopt.translate_columns = translate_columns_pre_96;
579  myopt.n_translate_columns = lengthof(translate_columns_pre_96);
580  }
581 
582  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
583 
584  PQclear(res);
585  return true;
586 }
static const char * map_typename_pattern(const char *pattern)
Definition: describe.c:696
static void printACLColumn(PQExpBuffer buf, const char *colname)
Definition: describe.c:6139
NameData typname
Definition: pg_type.h:41
#define snprintf
Definition: port.h:225

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, formatPGVersionNumber(), gettext_noop, i, initPQExpBuffer(), lengthof, _psqlSettings::logfile, map_typename_pattern(), printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, pg_log_error, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, snprintf, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, typname, and verbose.

Referenced by exec_command_dfo().

◆ describeOneTableDetails()

static bool describeOneTableDetails ( const char *  schemaname,
const char *  relationname,
const char *  oid,
bool  verbose 
)
static

Definition at line 1434 of file describe.c.

1438 {
1439  bool retval = false;
1441  PGresult *res = NULL;
1442  printTableOpt myopt = pset.popt.topt;
1443  printTableContent cont;
1444  bool printTableInitialized = false;
1445  int i;
1446  char *view_def = NULL;
1447  char *headers[12];
1448  PQExpBufferData title;
1450  int cols;
1451  int attname_col = -1, /* column indexes in "res" */
1452  atttype_col = -1,
1453  attrdef_col = -1,
1454  attnotnull_col = -1,
1455  attcoll_col = -1,
1456  attidentity_col = -1,
1457  attgenerated_col = -1,
1458  isindexkey_col = -1,
1459  indexdef_col = -1,
1460  fdwopts_col = -1,
1461  attstorage_col = -1,
1462  attcompression_col = -1,
1463  attstattarget_col = -1,
1464  attdescr_col = -1;
1465  int numrows;
1466  struct
1467  {
1468  int16 checks;
1469  char relkind;
1470  bool hasindex;
1471  bool hasrules;
1472  bool hastriggers;
1473  bool rowsecurity;
1474  bool forcerowsecurity;
1475  bool hasoids;
1476  bool ispartition;
1477  Oid tablespace;
1478  char *reloptions;
1479  char *reloftype;
1480  char relpersistence;
1481  char relreplident;
1482  char *relam;
1483  } tableinfo;
1484  bool show_column_details = false;
1485 
1486  myopt.default_footer = false;
1487  /* This output looks confusing in expanded mode. */
1488  myopt.expanded = false;
1489 
1490  initPQExpBuffer(&buf);
1491  initPQExpBuffer(&title);
1493 
1494  /* Get general table info */
1495  if (pset.sversion >= 120000)
1496  {
1498  "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1499  "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
1500  "false AS relhasoids, c.relispartition, %s, c.reltablespace, "
1501  "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1502  "c.relpersistence, c.relreplident, am.amname\n"
1503  "FROM pg_catalog.pg_class c\n "
1504  "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1505  "LEFT JOIN pg_catalog.pg_am am ON (c.relam = am.oid)\n"
1506  "WHERE c.oid = '%s';",
1507  (verbose ?
1508  "pg_catalog.array_to_string(c.reloptions || "
1509  "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1510  : "''"),
1511  oid);
1512  }
1513  else if (pset.sversion >= 100000)
1514  {
1516  "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1517  "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
1518  "c.relhasoids, c.relispartition, %s, c.reltablespace, "
1519  "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1520  "c.relpersistence, c.relreplident\n"
1521  "FROM pg_catalog.pg_class c\n "
1522  "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1523  "WHERE c.oid = '%s';",
1524  (verbose ?
1525  "pg_catalog.array_to_string(c.reloptions || "
1526  "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1527  : "''"),
1528  oid);
1529  }
1530  else if (pset.sversion >= 90500)
1531  {
1533  "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1534  "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
1535  "c.relhasoids, false as relispartition, %s, c.reltablespace, "
1536  "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1537  "c.relpersistence, c.relreplident\n"
1538  "FROM pg_catalog.pg_class c\n "
1539  "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1540  "WHERE c.oid = '%s';",
1541  (verbose ?
1542  "pg_catalog.array_to_string(c.reloptions || "
1543  "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1544  : "''"),
1545  oid);
1546  }
1547  else if (pset.sversion >= 90400)
1548  {
1550  "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1551  "c.relhastriggers, false, false, c.relhasoids, "
1552  "false as relispartition, %s, c.reltablespace, "
1553  "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1554  "c.relpersistence, c.relreplident\n"
1555  "FROM pg_catalog.pg_class c\n "
1556  "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1557  "WHERE c.oid = '%s';",
1558  (verbose ?
1559  "pg_catalog.array_to_string(c.reloptions || "
1560  "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1561  : "''"),
1562  oid);
1563  }
1564  else
1565  {
1567  "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1568  "c.relhastriggers, false, false, c.relhasoids, "
1569  "false as relispartition, %s, c.reltablespace, "
1570  "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1571  "c.relpersistence\n"
1572  "FROM pg_catalog.pg_class c\n "
1573  "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1574  "WHERE c.oid = '%s';",
1575  (verbose ?
1576  "pg_catalog.array_to_string(c.reloptions || "
1577  "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1578  : "''"),
1579  oid);
1580  }
1581 
1582  res = PSQLexec(buf.data);
1583  if (!res)
1584  goto error_return;
1585 
1586  /* Did we get anything? */
1587  if (PQntuples(res) == 0)
1588  {
1589  if (!pset.quiet)
1590  pg_log_error("Did not find any relation with OID %s.", oid);
1591  goto error_return;
1592  }
1593 
1594  tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
1595  tableinfo.relkind = *(PQgetvalue(res, 0, 1));
1596  tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
1597  tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
1598  tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
1599  tableinfo.rowsecurity = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
1600  tableinfo.forcerowsecurity = strcmp(PQgetvalue(res, 0, 6), "t") == 0;
1601  tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 7), "t") == 0;
1602  tableinfo.ispartition = strcmp(PQgetvalue(res, 0, 8), "t") == 0;
1603  tableinfo.reloptions = pg_strdup(PQgetvalue(res, 0, 9));
1604  tableinfo.tablespace = atooid(PQgetvalue(res, 0, 10));
1605  tableinfo.reloftype = (strcmp(PQgetvalue(res, 0, 11), "") != 0) ?
1606  pg_strdup(PQgetvalue(res, 0, 11)) : NULL;
1607  tableinfo.relpersistence = *(PQgetvalue(res, 0, 12));
1608  tableinfo.relreplident = (pset.sversion >= 90400) ?
1609  *(PQgetvalue(res, 0, 13)) : 'd';
1610  if (pset.sversion >= 120000)
1611  tableinfo.relam = PQgetisnull(res, 0, 14) ?
1612  (char *) NULL : pg_strdup(PQgetvalue(res, 0, 14));
1613  else
1614  tableinfo.relam = NULL;
1615  PQclear(res);
1616  res = NULL;
1617 
1618  /*
1619  * If it's a sequence, deal with it here separately.
1620  */
1621  if (tableinfo.relkind == RELKIND_SEQUENCE)
1622  {
1623  PGresult *result = NULL;
1624  printQueryOpt myopt = pset.popt;
1625  char *footers[2] = {NULL, NULL};
1626 
1627  if (pset.sversion >= 100000)
1628  {
1630  "SELECT pg_catalog.format_type(seqtypid, NULL) AS \"%s\",\n"
1631  " seqstart AS \"%s\",\n"
1632  " seqmin AS \"%s\",\n"
1633  " seqmax AS \"%s\",\n"
1634  " seqincrement AS \"%s\",\n"
1635  " CASE WHEN seqcycle THEN '%s' ELSE '%s' END AS \"%s\",\n"
1636  " seqcache AS \"%s\"\n",
1637  gettext_noop("Type"),
1638  gettext_noop("Start"),
1639  gettext_noop("Minimum"),
1640  gettext_noop("Maximum"),
1641  gettext_noop("Increment"),
1642  gettext_noop("yes"),
1643  gettext_noop("no"),
1644  gettext_noop("Cycles?"),
1645  gettext_noop("Cache"));
1647  "FROM pg_catalog.pg_sequence\n"
1648  "WHERE seqrelid = '%s';",
1649  oid);
1650  }
1651  else
1652  {
1654  "SELECT 'bigint' AS \"%s\",\n"
1655  " start_value AS \"%s\",\n"
1656  " min_value AS \"%s\",\n"
1657  " max_value AS \"%s\",\n"
1658  " increment_by AS \"%s\",\n"
1659  " CASE WHEN is_cycled THEN '%s' ELSE '%s' END AS \"%s\",\n"
1660  " cache_value AS \"%s\"\n",
1661  gettext_noop("Type"),
1662  gettext_noop("Start"),
1663  gettext_noop("Minimum"),
1664  gettext_noop("Maximum"),
1665  gettext_noop("Increment"),
1666  gettext_noop("yes"),
1667  gettext_noop("no"),
1668  gettext_noop("Cycles?"),
1669  gettext_noop("Cache"));
1670  appendPQExpBuffer(&buf, "FROM %s", fmtId(schemaname));
1671  /* must be separate because fmtId isn't reentrant */
1672  appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
1673  }
1674 
1675  res = PSQLexec(buf.data);
1676  if (!res)
1677  goto error_return;
1678 
1679  /* Footer information about a sequence */
1680 
1681  /* Get the column that owns this sequence */
1682  printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
1683  "\n pg_catalog.quote_ident(relname) || '.' ||"
1684  "\n pg_catalog.quote_ident(attname),"
1685  "\n d.deptype"
1686  "\nFROM pg_catalog.pg_class c"
1687  "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
1688  "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
1689  "\nINNER JOIN pg_catalog.pg_attribute a ON ("
1690  "\n a.attrelid=c.oid AND"
1691  "\n a.attnum=d.refobjsubid)"
1692  "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
1693  "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
1694  "\n AND d.objid='%s'"
1695  "\n AND d.deptype IN ('a', 'i')",
1696  oid);
1697 
1698  result = PSQLexec(buf.data);
1699 
1700  /*
1701  * If we get no rows back, don't show anything (obviously). We should
1702  * never get more than one row back, but if we do, just ignore it and
1703  * don't print anything.
1704  */
1705  if (!result)
1706  goto error_return;
1707  else if (PQntuples(result) == 1)
1708  {
1709  switch (PQgetvalue(result, 0, 1)[0])
1710  {
1711  case 'a':
1712  footers[0] = psprintf(_("Owned by: %s"),
1713  PQgetvalue(result, 0, 0));
1714  break;
1715  case 'i':
1716  footers[0] = psprintf(_("Sequence for identity column: %s"),
1717  PQgetvalue(result, 0, 0));
1718  break;
1719  }
1720  }
1721  PQclear(result);
1722 
1723  printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
1724  schemaname, relationname);
1725 
1726  myopt.footers = footers;
1727  myopt.topt.default_footer = false;
1728  myopt.title = title.data;
1729  myopt.translate_header = true;
1730 
1731  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1732 
1733  if (footers[0])
1734  free(footers[0]);
1735 
1736  retval = true;
1737  goto error_return; /* not an error, just return early */
1738  }
1739 
1740  /* Identify whether we should print collation, nullable, default vals */
1741  if (tableinfo.relkind == RELKIND_RELATION ||
1742  tableinfo.relkind == RELKIND_VIEW ||
1743  tableinfo.relkind == RELKIND_MATVIEW ||
1744  tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1745  tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
1746  tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1747  show_column_details = true;
1748 
1749  /*
1750  * Get per-column info
1751  *
1752  * Since the set of query columns we need varies depending on relkind and
1753  * server version, we compute all the column numbers on-the-fly. Column
1754  * number variables for columns not fetched are left as -1; this avoids
1755  * duplicative test logic below.
1756  */
1757  cols = 0;
1758  printfPQExpBuffer(&buf, "SELECT a.attname");
1759  attname_col = cols++;
1760  appendPQExpBufferStr(&buf, ",\n pg_catalog.format_type(a.atttypid, a.atttypmod)");
1761  atttype_col = cols++;
1762 
1763  if (show_column_details)
1764  {
1765  /* use "pretty" mode for expression to avoid excessive parentheses */
1767  ",\n (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid, true)"
1768  "\n FROM pg_catalog.pg_attrdef d"
1769  "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)"
1770  ",\n a.attnotnull");
1771  attrdef_col = cols++;
1772  attnotnull_col = cols++;
1773  appendPQExpBufferStr(&buf, ",\n (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
1774  " WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
1775  attcoll_col = cols++;
1776  if (pset.sversion >= 100000)
1777  appendPQExpBufferStr(&buf, ",\n a.attidentity");
1778  else
1779  appendPQExpBufferStr(&buf, ",\n ''::pg_catalog.char AS attidentity");
1780  attidentity_col = cols++;
1781  if (pset.sversion >= 120000)
1782  appendPQExpBufferStr(&buf, ",\n a.attgenerated");
1783  else
1784  appendPQExpBufferStr(&buf, ",\n ''::pg_catalog.char AS attgenerated");
1785  attgenerated_col = cols++;
1786  }
1787  if (tableinfo.relkind == RELKIND_INDEX ||
1788  tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
1789  {
1790  if (pset.sversion >= 110000)
1791  {
1792  appendPQExpBuffer(&buf, ",\n CASE WHEN a.attnum <= (SELECT i.indnkeyatts FROM pg_catalog.pg_index i WHERE i.indexrelid = '%s') THEN '%s' ELSE '%s' END AS is_key",
1793  oid,
1794  gettext_noop("yes"),
1795  gettext_noop("no"));
1796  isindexkey_col = cols++;
1797  }
1798  appendPQExpBufferStr(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
1799  indexdef_col = cols++;
1800  }
1801  /* FDW options for foreign table column */
1802  if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
1803  {
1804  appendPQExpBufferStr(&buf, ",\n CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
1805  " '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM "
1806  " pg_catalog.pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
1807  fdwopts_col = cols++;
1808  }
1809  if (verbose)
1810  {
1811  appendPQExpBufferStr(&buf, ",\n a.attstorage");
1812  attstorage_col = cols++;
1813 
1814  /* compression info, if relevant to relkind */
1815  if (pset.sversion >= 140000 &&
1817  (tableinfo.relkind == RELKIND_RELATION ||
1818  tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
1819  tableinfo.relkind == RELKIND_MATVIEW))
1820  {
1821  appendPQExpBufferStr(&buf, ",\n a.attcompression AS attcompression");
1822  attcompression_col = cols++;
1823  }
1824 
1825  /* stats target, if relevant to relkind */
1826  if (tableinfo.relkind == RELKIND_RELATION ||
1827  tableinfo.relkind == RELKIND_INDEX ||
1828  tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
1829  tableinfo.relkind == RELKIND_MATVIEW ||
1830  tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1831  tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1832  {
1833  appendPQExpBufferStr(&buf, ",\n CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
1834  attstattarget_col = cols++;
1835  }
1836 
1837  /*
1838  * In 9.0+, we have column comments for: relations, views, composite
1839  * types, and foreign tables (cf. CommentObject() in comment.c).
1840  */
1841  if (tableinfo.relkind == RELKIND_RELATION ||
1842  tableinfo.relkind == RELKIND_VIEW ||
1843  tableinfo.relkind == RELKIND_MATVIEW ||
1844  tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1845  tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
1846  tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1847  {
1848  appendPQExpBufferStr(&buf, ",\n pg_catalog.col_description(a.attrelid, a.attnum)");
1849  attdescr_col = cols++;
1850  }
1851  }
1852 
1853  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_attribute a");
1854  appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
1855  appendPQExpBufferStr(&buf, "\nORDER BY a.attnum;");
1856 
1857  res = PSQLexec(buf.data);
1858  if (!res)
1859  goto error_return;
1860  numrows = PQntuples(res);
1861 
1862  /* Make title */
1863  switch (tableinfo.relkind)
1864  {
1865  case RELKIND_RELATION:
1866  if (tableinfo.relpersistence == 'u')
1867  printfPQExpBuffer(&title, _("Unlogged table \"%s.%s\""),
1868  schemaname, relationname);
1869  else
1870  printfPQExpBuffer(&title, _("Table \"%s.%s\""),
1871  schemaname, relationname);
1872  break;
1873  case RELKIND_VIEW:
1874  printfPQExpBuffer(&title, _("View \"%s.%s\""),
1875  schemaname, relationname);
1876  break;
1877  case RELKIND_MATVIEW:
1878  if (tableinfo.relpersistence == 'u')
1879  printfPQExpBuffer(&title, _("Unlogged materialized view \"%s.%s\""),
1880  schemaname, relationname);
1881  else
1882  printfPQExpBuffer(&title, _("Materialized view \"%s.%s\""),
1883  schemaname, relationname);
1884  break;
1885  case RELKIND_INDEX:
1886  if (tableinfo.relpersistence == 'u')
1887  printfPQExpBuffer(&title, _("Unlogged index \"%s.%s\""),
1888  schemaname, relationname);
1889  else
1890  printfPQExpBuffer(&title, _("Index \"%s.%s\""),
1891  schemaname, relationname);
1892  break;
1893  case RELKIND_PARTITIONED_INDEX:
1894  if (tableinfo.relpersistence == 'u')
1895  printfPQExpBuffer(&title, _("Unlogged partitioned index \"%s.%s\""),
1896  schemaname, relationname);
1897  else
1898  printfPQExpBuffer(&title, _("Partitioned index \"%s.%s\""),
1899  schemaname, relationname);
1900  break;
1901  case RELKIND_TOASTVALUE:
1902  printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
1903  schemaname, relationname);
1904  break;
1905  case RELKIND_COMPOSITE_TYPE:
1906  printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
1907  schemaname, relationname);
1908  break;
1909  case RELKIND_FOREIGN_TABLE:
1910  printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""),
1911  schemaname, relationname);
1912  break;
1913  case RELKIND_PARTITIONED_TABLE:
1914  if (tableinfo.relpersistence == 'u')
1915  printfPQExpBuffer(&title, _("Unlogged partitioned table \"%s.%s\""),
1916  schemaname, relationname);
1917  else
1918  printfPQExpBuffer(&title, _("Partitioned table \"%s.%s\""),
1919  schemaname, relationname);
1920  break;
1921  default:
1922  /* untranslated unknown relkind */
1923  printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
1924  tableinfo.relkind, schemaname, relationname);
1925  break;
1926  }
1927 
1928  /* Fill headers[] with the names of the columns we will output */
1929  cols = 0;
1930  headers[cols++] = gettext_noop("Column");
1931  headers[cols++] = gettext_noop("Type");
1932  if (show_column_details)
1933  {
1934  headers[cols++] = gettext_noop("Collation");
1935  headers[cols++] = gettext_noop("Nullable");
1936  headers[cols++] = gettext_noop("Default");
1937  }
1938  if (isindexkey_col >= 0)
1939  headers[cols++] = gettext_noop("Key?");
1940  if (indexdef_col >= 0)
1941  headers[cols++] = gettext_noop("Definition");
1942  if (fdwopts_col >= 0)
1943  headers[cols++] = gettext_noop("FDW options");
1944  if (attstorage_col >= 0)
1945  headers[cols++] = gettext_noop("Storage");
1946  if (attcompression_col >= 0)
1947  headers[cols++] = gettext_noop("Compression");
1948  if (attstattarget_col >= 0)
1949  headers[cols++] = gettext_noop("Stats target");
1950  if (attdescr_col >= 0)
1951  headers[cols++] = gettext_noop("Description");
1952 
1953  Assert(cols <= lengthof(headers));
1954 
1955  printTableInit(&cont, &myopt, title.data, cols, numrows);
1956  printTableInitialized = true;
1957 
1958  for (i = 0; i < cols; i++)
1959  printTableAddHeader(&cont, headers[i], true, 'l');
1960 
1961  /* Generate table cells to be printed */
1962  for (i = 0; i < numrows; i++)
1963  {
1964  /* Column */
1965  printTableAddCell(&cont, PQgetvalue(res, i, attname_col), false, false);
1966 
1967  /* Type */
1968  printTableAddCell(&cont, PQgetvalue(res, i, atttype_col), false, false);
1969 
1970  /* Collation, Nullable, Default */
1971  if (show_column_details)
1972  {
1973  char *identity;
1974  char *generated;
1975  char *default_str;
1976  bool mustfree = false;
1977 
1978  printTableAddCell(&cont, PQgetvalue(res, i, attcoll_col), false, false);
1979 
1980  printTableAddCell(&cont,
1981  strcmp(PQgetvalue(res, i, attnotnull_col), "t") == 0 ? "not null" : "",
1982  false, false);
1983 
1984  identity = PQgetvalue(res, i, attidentity_col);
1985  generated = PQgetvalue(res, i, attgenerated_col);
1986 
1987  if (identity[0] == ATTRIBUTE_IDENTITY_ALWAYS)
1988  default_str = "generated always as identity";
1989  else if (identity[0] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
1990  default_str = "generated by default as identity";
1991  else if (generated[0] == ATTRIBUTE_GENERATED_STORED)
1992  {
1993  default_str = psprintf("generated always as (%s) stored",
1994  PQgetvalue(res, i, attrdef_col));
1995  mustfree = true;
1996  }
1997  else
1998  default_str = PQgetvalue(res, i, attrdef_col);
1999 
2000  printTableAddCell(&cont, default_str, false, mustfree);
2001  }
2002 
2003  /* Info for index columns */
2004  if (isindexkey_col >= 0)
2005  printTableAddCell(&cont, PQgetvalue(res, i, isindexkey_col), true, false);
2006  if (indexdef_col >= 0)
2007  printTableAddCell(&cont, PQgetvalue(res, i, indexdef_col), false, false);
2008 
2009  /* FDW options for foreign table columns */
2010  if (fdwopts_col >= 0)
2011  printTableAddCell(&cont, PQgetvalue(res, i, fdwopts_col), false, false);
2012 
2013  /* Storage mode, if relevant */
2014  if (attstorage_col >= 0)
2015  {
2016  char *storage = PQgetvalue(res, i, attstorage_col);
2017 
2018  /* these strings are literal in our syntax, so not translated. */
2019  printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
2020  (storage[0] == 'm' ? "main" :
2021  (storage[0] == 'x' ? "extended" :
2022  (storage[0] == 'e' ? "external" :
2023  "???")))),
2024  false, false);
2025  }
2026 
2027  /* Column compression, if relevant */
2028  if (attcompression_col >= 0)
2029  {
2030  char *compression = PQgetvalue(res, i, attcompression_col);
2031 
2032  /* these strings are literal in our syntax, so not translated. */
2033  printTableAddCell(&cont, (compression[0] == 'p' ? "pglz" :
2034  (compression[0] == 'l' ? "lz4" :
2035  (compression[0] == '\0' ? "" :
2036  "???"))),
2037  false, false);
2038  }
2039 
2040  /* Statistics target, if the relkind supports this feature */
2041  if (attstattarget_col >= 0)
2042  printTableAddCell(&cont, PQgetvalue(res, i, attstattarget_col),
2043  false, false);
2044 
2045  /* Column comments, if the relkind supports this feature */
2046  if (attdescr_col >= 0)
2047  printTableAddCell(&cont, PQgetvalue(res, i, attdescr_col),
2048  false, false);
2049  }
2050 
2051  /* Make footers */
2052 
2053  if (tableinfo.ispartition)
2054  {
2055  /* Footer information for a partition child table */
2056  PGresult *result;
2057 
2059  "SELECT inhparent::pg_catalog.regclass,\n"
2060  " pg_catalog.pg_get_expr(c.relpartbound, c.oid),\n ");
2061 
2063  pset.sversion >= 140000 ? "inhdetachpending" :
2064  "false as inhdetachpending");
2065 
2066  /* If verbose, also request the partition constraint definition */
2067  if (verbose)
2069  ",\n pg_catalog.pg_get_partition_constraintdef(c.oid)");
2071  "\nFROM pg_catalog.pg_class c"
2072  " JOIN pg_catalog.pg_inherits i"
2073  " ON c.oid = inhrelid"
2074  "\nWHERE c.oid = '%s';", oid);
2075  result = PSQLexec(buf.data);
2076  if (!result)
2077  goto error_return;
2078 
2079  if (PQntuples(result) > 0)
2080  {
2081  char *parent_name = PQgetvalue(result, 0, 0);
2082  char *partdef = PQgetvalue(result, 0, 1);
2083  char *detached = PQgetvalue(result, 0, 2);
2084 
2085  printfPQExpBuffer(&tmpbuf, _("Partition of: %s %s%s"), parent_name,
2086  partdef,
2087  strcmp(detached, "t") == 0 ? " DETACH PENDING" : "");
2089 
2090  if (verbose)
2091  {
2092  char *partconstraintdef = NULL;
2093 
2094  if (!PQgetisnull(result, 0, 3))
2095  partconstraintdef = PQgetvalue(result, 0, 3);
2096  /* If there isn't any constraint, show that explicitly */
2097  if (partconstraintdef == NULL || partconstraintdef[0] == '\0')
2098  printfPQExpBuffer(&tmpbuf, _("No partition constraint"));
2099  else
2100  printfPQExpBuffer(&tmpbuf, _("Partition constraint: %s"),
2101  partconstraintdef);
2103  }
2104  }
2105  PQclear(result);
2106  }
2107 
2108  if (tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
2109  {
2110  /* Footer information for a partitioned table (partitioning parent) */
2111  PGresult *result;
2112 
2114  "SELECT pg_catalog.pg_get_partkeydef('%s'::pg_catalog.oid);",
2115  oid);
2116  result = PSQLexec(buf.data);
2117  if (!result)
2118  goto error_return;
2119 
2120  if (PQntuples(result) == 1)
2121  {
2122  char *partkeydef = PQgetvalue(result, 0, 0);
2123 
2124  printfPQExpBuffer(&tmpbuf, _("Partition key: %s"), partkeydef);
2126  }
2127  PQclear(result);
2128  }
2129 
2130  if (tableinfo.relkind == RELKIND_TOASTVALUE)
2131  {
2132  /* For a TOAST table, print name of owning table */
2133  PGresult *result;
2134 
2136  "SELECT n.nspname, c.relname\n"
2137  "FROM pg_catalog.pg_class c"
2138  " JOIN pg_catalog.pg_namespace n"
2139  " ON n.oid = c.relnamespace\n"
2140  "WHERE reltoastrelid = '%s';", oid);
2141  result = PSQLexec(buf.data);
2142  if (!result)
2143  goto error_return;
2144 
2145  if (PQntuples(result) == 1)
2146  {
2147  char *schemaname = PQgetvalue(result, 0, 0);
2148  char *relname = PQgetvalue(result, 0, 1);
2149 
2150  printfPQExpBuffer(&tmpbuf, _("Owning table: \"%s.%s\""),
2151  schemaname, relname);
2153  }
2154  PQclear(result);
2155  }
2156 
2157  if (tableinfo.relkind == RELKIND_INDEX ||
2158  tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
2159  {
2160  /* Footer information about an index */
2161  PGresult *result;
2162 
2164  "SELECT i.indisunique, i.indisprimary, i.indisclustered, "
2165  "i.indisvalid,\n"
2166  " (NOT i.indimmediate) AND "
2167  "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
2168  "WHERE conrelid = i.indrelid AND "
2169  "conindid = i.indexrelid AND "
2170  "contype IN ('p','u','x') AND "
2171  "condeferrable) AS condeferrable,\n"
2172  " (NOT i.indimmediate) AND "
2173  "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
2174  "WHERE conrelid = i.indrelid AND "
2175  "conindid = i.indexrelid AND "
2176  "contype IN ('p','u','x') AND "
2177  "condeferred) AS condeferred,\n");
2178 
2179  if (pset.sversion >= 90400)
2180  appendPQExpBufferStr(&buf, "i.indisreplident,\n");
2181  else
2182  appendPQExpBufferStr(&buf, "false AS indisreplident,\n");
2183 
2184  appendPQExpBuffer(&buf, " a.amname, c2.relname, "
2185  "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
2186  "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
2187  "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
2188  "AND i.indrelid = c2.oid;",
2189  oid);
2190 
2191  result = PSQLexec(buf.data);
2192  if (!result)
2193  goto error_return;
2194  else if (PQntuples(result) != 1)
2195  {
2196  PQclear(result);
2197  goto error_return;
2198  }
2199  else
2200  {
2201  char *indisunique = PQgetvalue(result, 0, 0);
2202  char *indisprimary = PQgetvalue(result, 0, 1);
2203  char *indisclustered = PQgetvalue(result, 0, 2);
2204  char *indisvalid = PQgetvalue(result, 0, 3);
2205  char *deferrable = PQgetvalue(result, 0, 4);
2206  char *deferred = PQgetvalue(result, 0, 5);
2207  char *indisreplident = PQgetvalue(result, 0, 6);
2208  char *indamname = PQgetvalue(result, 0, 7);
2209  char *indtable = PQgetvalue(result, 0, 8);
2210  char *indpred = PQgetvalue(result, 0, 9);
2211 
2212  if (strcmp(indisprimary, "t") == 0)
2213  printfPQExpBuffer(&tmpbuf, _("primary key, "));
2214  else if (strcmp(indisunique, "t") == 0)
2215  printfPQExpBuffer(&tmpbuf, _("unique, "));
2216  else
2218  appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
2219 
2220  /* we assume here that index and table are in same schema */
2221  appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
2222  schemaname, indtable);
2223 
2224  if (strlen(indpred))
2225  appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
2226 
2227  if (strcmp(indisclustered, "t") == 0)
2228  appendPQExpBufferStr(&tmpbuf, _(", clustered"));
2229 
2230  if (strcmp(indisvalid, "t") != 0)
2231  appendPQExpBufferStr(&tmpbuf, _(", invalid"));
2232 
2233  if (strcmp(deferrable, "t") == 0)
2234  appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
2235 
2236  if (strcmp(deferred, "t") == 0)
2237  appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
2238 
2239  if (strcmp(indisreplident, "t") == 0)
2240  appendPQExpBufferStr(&tmpbuf, _(", replica identity"));
2241 
2243 
2244  /*
2245  * If it's a partitioned index, we'll print the tablespace below
2246  */
2247  if (tableinfo.relkind == RELKIND_INDEX)
2248  add_tablespace_footer(&cont, tableinfo.relkind,
2249  tableinfo.tablespace, true);
2250  }
2251 
2252  PQclear(result);
2253  }
2254  /* If you add relkinds here, see also "Finish printing..." stanza below */
2255  else if (tableinfo.relkind == RELKIND_RELATION ||
2256  tableinfo.relkind == RELKIND_MATVIEW ||
2257  tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
2258  tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
2259  tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
2260  tableinfo.relkind == RELKIND_TOASTVALUE)
2261  {
2262  /* Footer information about a table */
2263  PGresult *result = NULL;
2264  int tuples = 0;
2265 
2266  /* print indexes */
2267  if (tableinfo.hasindex)
2268  {
2270  "SELECT c2.relname, i.indisprimary, i.indisunique, "
2271  "i.indisclustered, i.indisvalid, "
2272  "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n "
2273  "pg_catalog.pg_get_constraintdef(con.oid, true), "
2274  "contype, condeferrable, condeferred");
2275  if (pset.sversion >= 90400)
2276  appendPQExpBufferStr(&buf, ", i.indisreplident");
2277  else
2278  appendPQExpBufferStr(&buf, ", false AS indisreplident");
2279  appendPQExpBufferStr(&buf, ", c2.reltablespace");
2281  "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
2282  " LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n"
2283  "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
2284  "ORDER BY i.indisprimary DESC, c2.relname;",
2285  oid);
2286  result = PSQLexec(buf.data);
2287  if (!result)
2288  goto error_return;
2289  else
2290  tuples = PQntuples(result);
2291 
2292  if (tuples > 0)
2293  {
2294  printTableAddFooter(&cont, _("Indexes:"));
2295  for (i = 0; i < tuples; i++)
2296  {
2297  /* untranslated index name */
2298  printfPQExpBuffer(&buf, " \"%s\"",
2299  PQgetvalue(result, i, 0));
2300 
2301  /* If exclusion constraint, print the constraintdef */
2302  if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
2303  {
2304  appendPQExpBuffer(&buf, " %s",
2305  PQgetvalue(result, i, 6));
2306  }
2307  else
2308  {
2309  const char *indexdef;
2310  const char *usingpos;
2311 
2312  /* Label as primary key or unique (but not both) */
2313  if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
2314  appendPQExpBufferStr(&buf, " PRIMARY KEY,");
2315  else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
2316  {
2317  if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
2318  appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
2319  else
2320  appendPQExpBufferStr(&buf, " UNIQUE,");
2321  }
2322 
2323  /* Everything after "USING" is echoed verbatim */
2324  indexdef = PQgetvalue(result, i, 5);
2325  usingpos = strstr(indexdef, " USING ");
2326  if (usingpos)
2327  indexdef = usingpos + 7;
2328  appendPQExpBuffer(&buf, " %s", indexdef);
2329 
2330  /* Need these for deferrable PK/UNIQUE indexes */
2331  if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
2332  appendPQExpBufferStr(&buf, " DEFERRABLE");
2333 
2334  if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
2335  appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
2336  }
2337 
2338  /* Add these for all cases */
2339  if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
2340  appendPQExpBufferStr(&buf, " CLUSTER");
2341 
2342  if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
2343  appendPQExpBufferStr(&buf, " INVALID");
2344 
2345  if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
2346  appendPQExpBufferStr(&buf, " REPLICA IDENTITY");
2347 
2348  printTableAddFooter(&cont, buf.data);
2349 
2350  /* Print tablespace of the index on the same line */
2351  add_tablespace_footer(&cont, RELKIND_INDEX,
2352  atooid(PQgetvalue(result, i, 11)),
2353  false);
2354  }
2355  }
2356  PQclear(result);
2357  }
2358 
2359  /* print table (and column) check constraints */
2360  if (tableinfo.checks)
2361  {
2363  "SELECT r.conname, "
2364  "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
2365  "FROM pg_catalog.pg_constraint r\n"
2366  "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
2367  "ORDER BY 1;",
2368  oid);
2369  result = PSQLexec(buf.data);
2370  if (!result)
2371  goto error_return;
2372  else
2373  tuples = PQntuples(result);
2374 
2375  if (tuples > 0)
2376  {
2377  printTableAddFooter(&cont, _("Check constraints:"));
2378  for (i = 0; i < tuples; i++)
2379  {
2380  /* untranslated constraint name and def */
2381  printfPQExpBuffer(&buf, " \"%s\" %s",
2382  PQgetvalue(result, i, 0),
2383  PQgetvalue(result, i, 1));
2384 
2385  printTableAddFooter(&cont, buf.data);
2386  }
2387  }
2388  PQclear(result);
2389  }
2390 
2391  /*
2392  * Print foreign-key constraints (there are none if no triggers,
2393  * except if the table is partitioned, in which case the triggers
2394  * appear in the partitions)
2395  */
2396  if (tableinfo.hastriggers ||
2397  tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
2398  {
2399  if (pset.sversion >= 120000 &&
2400  (tableinfo.ispartition || tableinfo.relkind == RELKIND_PARTITIONED_TABLE))
2401  {
2402  /*
2403  * Put the constraints defined in this table first, followed
2404  * by the constraints defined in ancestor partitioned tables.
2405  */
2407  "SELECT conrelid = '%s'::pg_catalog.regclass AS sametable,\n"
2408  " conname,\n"
2409  " pg_catalog.pg_get_constraintdef(oid, true) AS condef,\n"
2410  " conrelid::pg_catalog.regclass AS ontable\n"
2411  " FROM pg_catalog.pg_constraint,\n"
2412  " pg_catalog.pg_partition_ancestors('%s')\n"
2413  " WHERE conrelid = relid AND contype = 'f' AND conparentid = 0\n"
2414  "ORDER BY sametable DESC, conname;",
2415  oid, oid);
2416  }
2417  else
2418  {
2420  "SELECT true as sametable, conname,\n"
2421  " pg_catalog.pg_get_constraintdef(r.oid, true) as condef,\n"
2422  " conrelid::pg_catalog.regclass AS ontable\n"
2423  "FROM pg_catalog.pg_constraint r\n"
2424  "WHERE r.conrelid = '%s' AND r.contype = 'f'\n",
2425  oid);
2426 
2427  if (pset.sversion >= 120000)
2428  appendPQExpBufferStr(&buf, " AND conparentid = 0\n");
2429  appendPQExpBufferStr(&buf, "ORDER BY conname");
2430  }
2431 
2432  result = PSQLexec(buf.data);
2433  if (!result)
2434  goto error_return;
2435  else
2436  tuples = PQntuples(result);
2437 
2438  if (tuples > 0)
2439  {
2440  int i_sametable = PQfnumber(result, "sametable"),
2441  i_conname = PQfnumber(result, "conname"),
2442  i_condef = PQfnumber(result, "condef"),
2443  i_ontable = PQfnumber(result, "ontable");
2444 
2445  printTableAddFooter(&cont, _("Foreign-key constraints:"));
2446  for (i = 0; i < tuples; i++)
2447  {
2448  /*
2449  * Print untranslated constraint name and definition. Use
2450  * a "TABLE tab" prefix when the constraint is defined in
2451  * a parent partitioned table.
2452  */
2453  if (strcmp(PQgetvalue(result, i, i_sametable), "f") == 0)
2454  printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
2455  PQgetvalue(result, i, i_ontable),
2456  PQgetvalue(result, i, i_conname),
2457  PQgetvalue(result, i, i_condef));
2458  else
2459  printfPQExpBuffer(&buf, " \"%s\" %s",
2460  PQgetvalue(result, i, i_conname),
2461  PQgetvalue(result, i, i_condef));
2462 
2463  printTableAddFooter(&cont, buf.data);
2464  }
2465  }
2466  PQclear(result);
2467  }
2468 
2469  /* print incoming foreign-key references */
2470  if (tableinfo.hastriggers ||
2471  tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
2472  {
2473  if (pset.sversion >= 120000)
2474  {
2476  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
2477  " pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
2478  " FROM pg_catalog.pg_constraint c\n"
2479  " WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('%s')\n"
2480  " UNION ALL VALUES ('%s'::pg_catalog.regclass))\n"
2481  " AND contype = 'f' AND conparentid = 0\n"
2482  "ORDER BY conname;",
2483  oid, oid);
2484  }
2485  else
2486  {
2488  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
2489  " pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
2490  " FROM pg_catalog.pg_constraint\n"
2491  " WHERE confrelid = %s AND contype = 'f'\n"
2492  "ORDER BY conname;",
2493  oid);
2494  }
2495 
2496  result = PSQLexec(buf.data);
2497  if (!result)
2498  goto error_return;
2499  else
2500  tuples = PQntuples(result);
2501 
2502  if (tuples > 0)
2503  {
2504  int i_conname = PQfnumber(result, "conname"),
2505  i_ontable = PQfnumber(result, "ontable"),
2506  i_condef = PQfnumber(result, "condef");
2507 
2508  printTableAddFooter(&cont, _("Referenced by:"));
2509  for (i = 0; i < tuples; i++)
2510  {
2511  printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
2512  PQgetvalue(result, i, i_ontable),
2513  PQgetvalue(result, i, i_conname),
2514  PQgetvalue(result, i, i_condef));
2515 
2516  printTableAddFooter(&cont, buf.data);
2517  }
2518  }
2519  PQclear(result);
2520  }
2521 
2522  /* print any row-level policies */
2523  if (pset.sversion >= 90500)
2524  {
2525  printfPQExpBuffer(&buf, "SELECT pol.polname,");
2526  if (pset.sversion >= 100000)
2528  " pol.polpermissive,\n");
2529  else
2531  " 't' as polpermissive,\n");
2533  " CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
2534  " pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
2535  " pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
2536  " CASE pol.polcmd\n"
2537  " WHEN 'r' THEN 'SELECT'\n"
2538  " WHEN 'a' THEN 'INSERT'\n"
2539  " WHEN 'w' THEN 'UPDATE'\n"
2540  " WHEN 'd' THEN 'DELETE'\n"
2541  " END AS cmd\n"
2542  "FROM pg_catalog.pg_policy pol\n"
2543  "WHERE pol.polrelid = '%s' ORDER BY 1;",
2544  oid);
2545 
2546  result = PSQLexec(buf.data);
2547  if (!result)
2548  goto error_return;
2549  else
2550  tuples = PQntuples(result);
2551 
2552  /*
2553  * Handle cases where RLS is enabled and there are policies, or
2554  * there aren't policies, or RLS isn't enabled but there are
2555  * policies
2556  */
2557  if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
2558  printTableAddFooter(&cont, _("Policies:"));
2559 
2560  if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
2561  printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
2562 
2563  if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
2564  printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
2565 
2566  if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
2567  printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
2568 
2569  if (!tableinfo.rowsecurity && tuples > 0)
2570  printTableAddFooter(&cont, _("Policies (row security disabled):"));
2571 
2572  /* Might be an empty set - that's ok */
2573  for (i = 0; i < tuples; i++)
2574  {
2575  printfPQExpBuffer(&buf, " POLICY \"%s\"",
2576  PQgetvalue(result, i, 0));
2577 
2578  if (*(PQgetvalue(result, i, 1)) == 'f')
2579  appendPQExpBufferStr(&buf, " AS RESTRICTIVE");
2580 
2581  if (!PQgetisnull(result, i, 5))
2582  appendPQExpBuffer(&buf, " FOR %s",
2583  PQgetvalue(result, i, 5));
2584 
2585  if (!PQgetisnull(result, i, 2))
2586  {
2587  appendPQExpBuffer(&buf, "\n TO %s",
2588  PQgetvalue(result, i, 2));
2589  }
2590 
2591  if (!PQgetisnull(result, i, 3))
2592  appendPQExpBuffer(&buf, "\n USING (%s)",
2593  PQgetvalue(result, i, 3));
2594 
2595  if (!PQgetisnull(result, i, 4))
2596  appendPQExpBuffer(&buf, "\n WITH CHECK (%s)",
2597  PQgetvalue(result, i, 4));
2598 
2599  printTableAddFooter(&cont, buf.data);
2600 
2601  }
2602  PQclear(result);
2603  }
2604 
2605  /* print any extended statistics */
2606  if (pset.sversion >= 140000)
2607  {
2609  "SELECT oid, "
2610  "stxrelid::pg_catalog.regclass, "
2611  "stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS nsp, "
2612  "stxname,\n"
2613  "pg_catalog.pg_get_statisticsobjdef_columns(oid) AS columns,\n"
2614  " 'd' = any(stxkind) AS ndist_enabled,\n"
2615  " 'f' = any(stxkind) AS deps_enabled,\n"
2616  " 'm' = any(stxkind) AS mcv_enabled,\n"
2617  "stxstattarget\n"
2618  "FROM pg_catalog.pg_statistic_ext\n"
2619  "WHERE stxrelid = '%s'\n"
2620  "ORDER BY nsp, stxname;",
2621  oid);
2622 
2623  result = PSQLexec(buf.data);
2624  if (!result)
2625  goto error_return;
2626  else
2627  tuples = PQntuples(result);
2628 
2629  if (tuples > 0)
2630  {
2631  printTableAddFooter(&cont, _("Statistics objects:"));
2632 
2633  for (i = 0; i < tuples; i++)
2634  {
2635  bool gotone = false;
2636  bool has_ndistinct;
2637  bool has_dependencies;
2638  bool has_mcv;
2639  bool has_all;
2640  bool has_some;
2641 
2642  has_ndistinct = (strcmp(PQgetvalue(result, i, 5), "t") == 0);
2643  has_dependencies = (strcmp(PQgetvalue(result, i, 6), "t") == 0);
2644  has_mcv = (strcmp(PQgetvalue(result, i, 7), "t") == 0);
2645 
2646  printfPQExpBuffer(&buf, " ");
2647 
2648  /* statistics object name (qualified with namespace) */
2649  appendPQExpBuffer(&buf, "\"%s.%s\"",
2650  PQgetvalue(result, i, 2),
2651  PQgetvalue(result, i, 3));
2652 
2653  /*
2654  * When printing kinds we ignore expression statistics,
2655  * which is used only internally and can't be specified by
2656  * user. We don't print the kinds when either none are
2657  * specified (in which case it has to be statistics on a
2658  * single expr) or when all are specified (in which case
2659  * we assume it's expanded by CREATE STATISTICS).
2660  */
2661  has_all = (has_ndistinct && has_dependencies && has_mcv);
2662  has_some = (has_ndistinct || has_dependencies || has_mcv);
2663 
2664  if (has_some && !has_all)
2665  {
2666  appendPQExpBufferStr(&buf, " (");
2667 
2668  /* options */
2669  if (has_ndistinct)
2670  {
2671  appendPQExpBufferStr(&buf, "ndistinct");
2672  gotone = true;
2673  }
2674 
2675  if (has_dependencies)
2676  {
2677  appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
2678  gotone = true;
2679  }
2680 
2681  if (has_mcv)
2682  {
2683  appendPQExpBuffer(&buf, "%smcv", gotone ? ", " : "");
2684  }
2685 
2686  appendPQExpBufferChar(&buf, ')');
2687  }
2688 
2689  appendPQExpBuffer(&buf, " ON %s FROM %s",
2690  PQgetvalue(result, i, 4),
2691  PQgetvalue(result, i, 1));
2692 
2693  /* Show the stats target if it's not default */
2694  if (strcmp(PQgetvalue(result, i, 8), "-1") != 0)
2695  appendPQExpBuffer(&buf, "; STATISTICS %s",
2696  PQgetvalue(result, i, 8));
2697 
2698  printTableAddFooter(&cont, buf.data);
2699  }
2700  }
2701  PQclear(result);
2702  }
2703  else if (pset.sversion >= 100000)
2704  {
2706  "SELECT oid, "
2707  "stxrelid::pg_catalog.regclass, "
2708  "stxnamespace::pg_catalog.regnamespace AS nsp, "
2709  "stxname,\n"
2710  " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(attname),', ')\n"
2711  " FROM pg_catalog.unnest(stxkeys) s(attnum)\n"
2712  " JOIN pg_catalog.pg_attribute a ON (stxrelid = a.attrelid AND\n"
2713  " a.attnum = s.attnum AND NOT attisdropped)) AS columns,\n"
2714  " 'd' = any(stxkind) AS ndist_enabled,\n"
2715  " 'f' = any(stxkind) AS deps_enabled,\n"
2716  " 'm' = any(stxkind) AS mcv_enabled,\n");
2717 
2718  if (pset.sversion >= 130000)
2719  appendPQExpBufferStr(&buf, " stxstattarget\n");
2720  else
2721  appendPQExpBufferStr(&buf, " -1 AS stxstattarget\n");
2722  appendPQExpBuffer(&buf, "FROM pg_catalog.pg_statistic_ext\n"
2723  "WHERE stxrelid = '%s'\n"
2724  "ORDER BY 1;",
2725  oid);
2726 
2727  result = PSQLexec(buf.data);
2728  if (!result)
2729  goto error_return;
2730  else
2731  tuples = PQntuples(result);
2732 
2733  if (tuples > 0)
2734  {
2735  printTableAddFooter(&cont, _("Statistics objects:"));
2736 
2737  for (i = 0; i < tuples; i++)
2738  {
2739  bool gotone = false;
2740 
2741  printfPQExpBuffer(&buf, " ");
2742 
2743  /* statistics object name (qualified with namespace) */
2744  appendPQExpBuffer(&buf, "\"%s.%s\" (",
2745  PQgetvalue(result, i, 2),
2746  PQgetvalue(result, i, 3));
2747 
2748  /* options */
2749  if (strcmp(PQgetvalue(result, i, 5), "t") == 0)
2750  {
2751  appendPQExpBufferStr(&buf, "ndistinct");
2752  gotone = true;
2753  }
2754 
2755  if (strcmp(PQgetvalue(result, i, 6), "t") == 0)
2756  {
2757  appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
2758  gotone = true;
2759  }
2760 
2761  if (strcmp(PQgetvalue(result, i, 7), "t") == 0)
2762  {
2763  appendPQExpBuffer(&buf, "%smcv", gotone ? ", " : "");
2764  }
2765 
2766  appendPQExpBuffer(&buf, ") ON %s FROM %s",
2767  PQgetvalue(result, i, 4),
2768  PQgetvalue(result, i, 1));
2769 
2770  /* Show the stats target if it's not default */
2771  if (strcmp(PQgetvalue(result, i, 8), "-1") != 0)
2772  appendPQExpBuffer(&buf, "; STATISTICS %s",
2773  PQgetvalue(result, i, 8));
2774 
2775  printTableAddFooter(&cont, buf.data);
2776  }
2777  }
2778  PQclear(result);
2779  }
2780 
2781  /* print rules */
2782  if (tableinfo.hasrules && tableinfo.relkind != RELKIND_MATVIEW)
2783  {
2785  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
2786  "ev_enabled\n"
2787  "FROM pg_catalog.pg_rewrite r\n"
2788  "WHERE r.ev_class = '%s' ORDER BY 1;",
2789  oid);
2790  result = PSQLexec(buf.data);
2791  if (!result)
2792  goto error_return;
2793  else
2794  tuples = PQntuples(result);
2795 
2796  if (tuples > 0)
2797  {
2798  bool have_heading;
2799  int category;
2800 
2801  for (category = 0; category < 4; category++)
2802  {
2803  have_heading = false;
2804 
2805  for (i = 0; i < tuples; i++)
2806  {
2807  const char *ruledef;
2808  bool list_rule = false;
2809 
2810  switch (category)
2811  {
2812  case 0:
2813  if (*PQgetvalue(result, i, 2) == 'O')
2814  list_rule = true;
2815  break;
2816  case 1:
2817  if (*PQgetvalue(result, i, 2) == 'D')
2818  list_rule = true;
2819  break;
2820  case 2:
2821  if (*PQgetvalue(result, i, 2) == 'A')
2822  list_rule = true;
2823  break;
2824  case 3:
2825  if (*PQgetvalue(result, i, 2) == 'R')
2826  list_rule = true;
2827  break;
2828  }
2829  if (!list_rule)
2830  continue;
2831 
2832  if (!have_heading)
2833  {
2834  switch (category)
2835  {
2836  case 0:
2837  printfPQExpBuffer(&buf, _("Rules:"));
2838  break;
2839  case 1:
2840  printfPQExpBuffer(&buf, _("Disabled rules:"));
2841  break;
2842  case 2:
2843  printfPQExpBuffer(&buf, _("Rules firing always:"));
2844  break;
2845  case 3:
2846  printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
2847  break;
2848  }
2849  printTableAddFooter(&cont, buf.data);
2850  have_heading = true;
2851  }
2852 
2853  /* Everything after "CREATE RULE" is echoed verbatim */
2854  ruledef = PQgetvalue(result, i, 1);
2855  ruledef += 12;
2856  printfPQExpBuffer(&buf, " %s", ruledef);
2857  printTableAddFooter(&cont, buf.data);
2858  }
2859  }
2860  }
2861  PQclear(result);
2862  }
2863 
2864  /* print any publications */
2865  if (pset.sversion >= 100000)
2866  {
2867  if (pset.sversion >= 150000)
2868  {
2870  "SELECT pubname\n"
2871  "FROM pg_catalog.pg_publication p\n"
2872  " JOIN pg_catalog.pg_publication_namespace pn ON p.oid = pn.pnpubid\n"
2873  " JOIN pg_catalog.pg_class pc ON pc.relnamespace = pn.pnnspid\n"
2874  "WHERE pc.oid ='%s' and pg_catalog.pg_relation_is_publishable('%s')\n"
2875  "UNION\n"
2876  "SELECT pubname\n"
2877  "FROM pg_catalog.pg_publication p\n"
2878  " JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
2879  "WHERE pr.prrelid = '%s'\n"
2880  "UNION\n"
2881  "SELECT pubname\n"
2882  "FROM pg_catalog.pg_publication p\n"
2883  "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
2884  "ORDER BY 1;",
2885  oid, oid, oid, oid);
2886  }
2887  else
2888  {
2890  "SELECT pubname\n"
2891  "FROM pg_catalog.pg_publication p\n"
2892  "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
2893  "WHERE pr.prrelid = '%s'\n"
2894  "UNION ALL\n"
2895  "SELECT pubname\n"
2896  "FROM pg_catalog.pg_publication p\n"
2897  "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
2898  "ORDER BY 1;",
2899  oid, oid);
2900  }
2901 
2902  result = PSQLexec(buf.data);
2903  if (!result)
2904  goto error_return;
2905  else
2906  tuples = PQntuples(result);
2907 
2908  if (tuples > 0)
2909  printTableAddFooter(&cont, _("Publications:"));
2910 
2911  /* Might be an empty set - that's ok */
2912  for (i = 0; i < tuples; i++)
2913  {
2914  printfPQExpBuffer(&buf, " \"%s\"",
2915  PQgetvalue(result, i, 0));
2916 
2917  printTableAddFooter(&cont, buf.data);
2918  }
2919  PQclear(result);
2920  }
2921  }
2922 
2923  /* Get view_def if table is a view or materialized view */
2924  if ((tableinfo.relkind == RELKIND_VIEW ||
2925  tableinfo.relkind == RELKIND_MATVIEW) && verbose)
2926  {
2927  PGresult *result;
2928 
2930  "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
2931  oid);
2932  result = PSQLexec(buf.data);
2933  if (!result)
2934  goto error_return;
2935 
2936  if (PQntuples(result) > 0)
2937  view_def = pg_strdup(PQgetvalue(result, 0, 0));
2938 
2939  PQclear(result);
2940  }
2941 
2942  if (view_def)
2943  {
2944  PGresult *result = NULL;
2945 
2946  /* Footer information about a view */
2947  printTableAddFooter(&cont, _("View definition:"));
2948  printTableAddFooter(&cont, view_def);
2949 
2950  /* print rules */
2951  if (tableinfo.hasrules)
2952  {
2954  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
2955  "FROM pg_catalog.pg_rewrite r\n"
2956  "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1;",
2957  oid);
2958  result = PSQLexec(buf.data);
2959  if (!result)
2960  goto error_return;
2961 
2962  if (PQntuples(result) > 0)
2963  {
2964  printTableAddFooter(&cont, _("Rules:"));
2965  for (i = 0; i < PQntuples(result); i++)
2966  {
2967  const char *ruledef;
2968 
2969  /* Everything after "CREATE RULE" is echoed verbatim */
2970  ruledef = PQgetvalue(result, i, 1);
2971  ruledef += 12;
2972 
2973  printfPQExpBuffer(&buf, " %s", ruledef);
2974  printTableAddFooter(&cont, buf.data);
2975  }
2976  }
2977  PQclear(result);
2978  }
2979  }
2980 
2981  /*
2982  * Print triggers next, if any (but only user-defined triggers). This
2983  * could apply to either a table or a view.
2984  */
2985  if (tableinfo.hastriggers)
2986  {
2987  PGresult *result;
2988  int tuples;
2989 
2991  "SELECT t.tgname, "
2992  "pg_catalog.pg_get_triggerdef(t.oid, true), "
2993  "t.tgenabled, t.tgisinternal,\n");
2994 
2995  /*
2996  * Detect whether each trigger is inherited, and if so, get the name
2997  * of the topmost table it's inherited from. We have no easy way to
2998  * do that pre-v13, for lack of the tgparentid column. Even with
2999  * tgparentid, a straightforward search for the topmost parent would
3000  * require a recursive CTE, which seems unduly expensive. We cheat a
3001  * bit by assuming parent triggers will match by tgname; then, joining
3002  * with pg_partition_ancestors() allows the planner to make use of
3003  * pg_trigger_tgrelid_tgname_index if it wishes. We ensure we find
3004  * the correct topmost parent by stopping at the first-in-partition-
3005  * ancestry-order trigger that has tgparentid = 0. (There might be
3006  * unrelated, non-inherited triggers with the same name further up the
3007  * stack, so this is important.)
3008  */
3009  if (pset.sversion >= 130000)
3011  " CASE WHEN t.tgparentid != 0 THEN\n"
3012  " (SELECT u.tgrelid::pg_catalog.regclass\n"
3013  " FROM pg_catalog.pg_trigger AS u,\n"
3014  " pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)\n"
3015  " WHERE u.tgname = t.tgname AND u.tgrelid = a.relid\n"
3016  " AND u.tgparentid = 0\n"
3017  " ORDER BY a.depth LIMIT 1)\n"
3018  " END AS parent\n");
3019  else
3020  appendPQExpBufferStr(&buf, " NULL AS parent\n");
3021 
3023  "FROM pg_catalog.pg_trigger t\n"
3024  "WHERE t.tgrelid = '%s' AND ",
3025  oid);
3026 
3027  /*
3028  * tgisinternal is set true for inherited triggers of partitions in
3029  * servers between v11 and v14, though these must still be shown to
3030  * the user. So we use another property that is true for such
3031  * inherited triggers to avoid them being hidden, which is their
3032  * dependendence on another trigger.
3033  */
3034  if (pset.sversion >= 110000 && pset.sversion < 150000)
3035  appendPQExpBufferStr(&buf, "(NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D') \n"
3036  " OR EXISTS (SELECT 1 FROM pg_catalog.pg_depend WHERE objid = t.oid \n"
3037  " AND refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass))");
3038  else
3039  /* display/warn about disabled internal triggers */
3040  appendPQExpBufferStr(&buf, "(NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))");
3041  appendPQExpBufferStr(&buf, "\nORDER BY 1;");
3042 
3043  result = PSQLexec(buf.data);
3044  if (!result)
3045  goto error_return;
3046  else
3047  tuples = PQntuples(result);
3048 
3049  if (tuples > 0)
3050  {
3051  bool have_heading;
3052  int category;
3053 
3054  /*
3055  * split the output into 4 different categories. Enabled triggers,
3056  * disabled triggers and the two special ALWAYS and REPLICA
3057  * configurations.
3058  */
3059  for (category = 0; category <= 4; category++)
3060  {
3061  have_heading = false;
3062  for (i = 0; i < tuples; i++)
3063  {
3064  bool list_trigger;
3065  const char *tgdef;
3066  const char *usingpos;
3067  const char *tgenabled;
3068  const char *tgisinternal;
3069 
3070  /*
3071  * Check if this trigger falls into the current category
3072  */
3073  tgenabled = PQgetvalue(result, i, 2);
3074  tgisinternal = PQgetvalue(result, i, 3);
3075  list_trigger = false;
3076  switch (category)
3077  {
3078  case 0:
3079  if (*tgenabled == 'O' || *tgenabled == 't')
3080  list_trigger = true;
3081  break;
3082  case 1:
3083  if ((*tgenabled == 'D' || *tgenabled == 'f') &&
3084  *tgisinternal == 'f')
3085  list_trigger = true;
3086  break;
3087  case 2:
3088  if ((*tgenabled == 'D' || *tgenabled == 'f') &&
3089  *tgisinternal == 't')
3090  list_trigger = true;
3091  break;
3092  case 3:
3093  if (*tgenabled == 'A')
3094  list_trigger = true;
3095  break;
3096  case 4:
3097  if (*tgenabled == 'R')
3098  list_trigger = true;
3099  break;
3100  }
3101  if (list_trigger == false)
3102  continue;
3103 
3104  /* Print the category heading once */
3105  if (have_heading == false)
3106  {
3107  switch (category)
3108  {
3109  case 0:
3110  printfPQExpBuffer(&buf, _("Triggers:"));
3111  break;
3112  case 1:
3113  printfPQExpBuffer(&buf, _("Disabled user triggers:"));
3114  break;
3115  case 2:
3116  printfPQExpBuffer(&buf, _("Disabled internal triggers:"));
3117  break;
3118  case 3:
3119  printfPQExpBuffer(&buf, _("Triggers firing always:"));
3120  break;
3121  case 4:
3122  printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
3123  break;
3124 
3125  }
3126  printTableAddFooter(&cont, buf.data);
3127  have_heading = true;
3128  }
3129 
3130  /* Everything after "TRIGGER" is echoed verbatim */
3131  tgdef = PQgetvalue(result, i, 1);
3132  usingpos = strstr(tgdef, " TRIGGER ");
3133  if (usingpos)
3134  tgdef = usingpos + 9;
3135 
3136  printfPQExpBuffer(&buf, " %s", tgdef);
3137 
3138  /* Visually distinguish inherited triggers */
3139  if (!PQgetisnull(result, i, 4))
3140  appendPQExpBuffer(&buf, ", ON TABLE %s",
3141  PQgetvalue(result, i, 4));
3142 
3143  printTableAddFooter(&cont, buf.data);
3144  }
3145  }
3146  }
3147  PQclear(result);
3148  }
3149 
3150  /*
3151  * Finish printing the footer information about a table.
3152  */
3153  if (tableinfo.relkind == RELKIND_RELATION ||
3154  tableinfo.relkind == RELKIND_MATVIEW ||
3155  tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
3156  tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
3157  tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
3158  tableinfo.relkind == RELKIND_TOASTVALUE)
3159  {
3160  bool is_partitioned;
3161  PGresult *result;
3162  int tuples;
3163 
3164  /* simplify some repeated tests below */
3165  is_partitioned = (tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
3166  tableinfo.relkind == RELKIND_PARTITIONED_INDEX);
3167 
3168  /* print foreign server name */
3169  if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
3170  {
3171  char *ftoptions;
3172 
3173  /* Footer information about foreign table */
3175  "SELECT s.srvname,\n"
3176  " pg_catalog.array_to_string(ARRAY(\n"
3177  " SELECT pg_catalog.quote_ident(option_name)"
3178  " || ' ' || pg_catalog.quote_literal(option_value)\n"
3179  " FROM pg_catalog.pg_options_to_table(ftoptions)), ', ')\n"
3180  "FROM pg_catalog.pg_foreign_table f,\n"
3181  " pg_catalog.pg_foreign_server s\n"
3182  "WHERE f.ftrelid = '%s' AND s.oid = f.ftserver;",
3183  oid);
3184  result = PSQLexec(buf.data);
3185  if (!result)
3186  goto error_return;
3187  else if (PQntuples(result) != 1)
3188  {
3189  PQclear(result);
3190  goto error_return;
3191  }
3192 
3193  /* Print server name */
3194  printfPQExpBuffer(&buf, _("Server: %s"),
3195  PQgetvalue(result, 0, 0));
3196  printTableAddFooter(&cont, buf.data);
3197 
3198  /* Print per-table FDW options, if any */
3199  ftoptions = PQgetvalue(result, 0, 1);
3200  if (ftoptions && ftoptions[0] != '\0')
3201  {
3202  printfPQExpBuffer(&buf, _("FDW options: (%s)"), ftoptions);
3203  printTableAddFooter(&cont, buf.data);
3204  }
3205  PQclear(result);
3206  }
3207 
3208  /* print tables inherited from (exclude partitioned parents) */
3210  "SELECT c.oid::pg_catalog.regclass\n"
3211  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
3212  "WHERE c.oid = i.inhparent AND i.inhrelid = '%s'\n"
3213  " AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_TABLE)
3214  " AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_INDEX)
3215  "\nORDER BY inhseqno;",
3216  oid);
3217 
3218  result = PSQLexec(buf.data);
3219  if (!result)
3220  goto error_return;
3221  else
3222  {
3223  const char *s = _("Inherits");
3224  int sw = pg_wcswidth(s, strlen(s), pset.encoding);
3225 
3226  tuples = PQntuples(result);
3227 
3228  for (i = 0; i < tuples; i++)
3229  {
3230  if (i == 0)
3231  printfPQExpBuffer(&buf, "%s: %s",
3232  s, PQgetvalue(result, i, 0));
3233  else
3234  printfPQExpBuffer(&buf, "%*s %s",
3235  sw, "", PQgetvalue(result, i, 0));
3236  if (i < tuples - 1)
3237  appendPQExpBufferChar(&buf, ',');
3238 
3239  printTableAddFooter(&cont, buf.data);
3240  }
3241 
3242  PQclear(result);
3243  }
3244 
3245  /* print child tables (with additional info if partitions) */
3246  if (pset.sversion >= 140000)
3248  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
3249  " inhdetachpending,"
3250  " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
3251  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
3252  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
3253  "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
3254  " c.oid::pg_catalog.regclass::pg_catalog.text;",
3255  oid);
3256  else if (pset.sversion >= 100000)
3258  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
3259  " false AS inhdetachpending,"
3260  " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
3261  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
3262  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
3263  "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
3264  " c.oid::pg_catalog.regclass::pg_catalog.text;",
3265  oid);
3266  else
3268  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
3269  " false AS inhdetachpending, NULL\n"
3270  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
3271  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
3272  "ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;",
3273  oid);
3274 
3275  result = PSQLexec(buf.data);
3276  if (!result)
3277  goto error_return;
3278  tuples = PQntuples(result);
3279 
3280  /*
3281  * For a partitioned table with no partitions, always print the number
3282  * of partitions as zero, even when verbose output is expected.
3283  * Otherwise, we will not print "Partitions" section for a partitioned
3284  * table without any partitions.
3285  */
3286  if (is_partitioned && tuples == 0)
3287  {
3288  printfPQExpBuffer(&buf, _("Number of partitions: %d"), tuples);
3289  printTableAddFooter(&cont, buf.data);
3290  }
3291  else if (!verbose)
3292  {
3293  /* print the number of child tables, if any */
3294  if (tuples > 0)
3295  {
3296  if (is_partitioned)
3297  printfPQExpBuffer(&buf, _("Number of partitions: %d (Use \\d+ to list them.)"), tuples);
3298  else
3299  printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
3300  printTableAddFooter(&cont, buf.data);
3301  }
3302  }
3303  else
3304  {
3305  /* display the list of child tables */
3306  const char *ct = is_partitioned ? _("Partitions") : _("Child tables");
3307  int ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
3308 
3309  for (i = 0; i < tuples; i++)
3310  {
3311  char child_relkind = *PQgetvalue(result, i, 1);
3312 
3313  if (i == 0)
3314  printfPQExpBuffer(&buf, "%s: %s",
3315  ct, PQgetvalue(result, i, 0));
3316  else
3317  printfPQExpBuffer(&buf, "%*s %s",
3318  ctw, "", PQgetvalue(result, i, 0));
3319  if (!PQgetisnull(result, i, 3))
3320  appendPQExpBuffer(&buf, " %s", PQgetvalue(result, i, 3));
3321  if (child_relkind == RELKIND_PARTITIONED_TABLE ||
3322  child_relkind == RELKIND_PARTITIONED_INDEX)
3323  appendPQExpBufferStr(&buf, ", PARTITIONED");
3324  if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
3325  appendPQExpBufferStr(&buf, " (DETACH PENDING)");
3326  if (i < tuples - 1)
3327  appendPQExpBufferChar(&buf, ',');
3328 
3329  printTableAddFooter(&cont, buf.data);
3330  }
3331  }
3332  PQclear(result);
3333 
3334  /* Table type */
3335  if (tableinfo.reloftype)
3336  {
3337  printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
3338  printTableAddFooter(&cont, buf.data);
3339  }
3340 
3341  if (verbose &&
3342  (tableinfo.relkind == RELKIND_RELATION ||
3343  tableinfo.relkind == RELKIND_MATVIEW) &&
3344 
3345  /*
3346  * No need to display default values; we already display a REPLICA
3347  * IDENTITY marker on indexes.
3348  */
3349  tableinfo.relreplident != 'i' &&
3350  ((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
3351  (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
3352  {
3353  const char *s = _("Replica Identity");
3354 
3355  printfPQExpBuffer(&buf, "%s: %s",
3356  s,
3357  tableinfo.relreplident == 'f' ? "FULL" :
3358  tableinfo.relreplident == 'n' ? "NOTHING" :
3359  "???");
3360 
3361  printTableAddFooter(&cont, buf.data);
3362  }
3363 
3364  /* OIDs, if verbose and not a materialized view */
3365  if (verbose && tableinfo.relkind != RELKIND_MATVIEW && tableinfo.hasoids)
3366  printTableAddFooter(&cont, _("Has OIDs: yes"));
3367 
3368  /* Tablespace info */
3369  add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
3370  true);
3371 
3372  /* Access method info */
3373  if (verbose && tableinfo.relam != NULL && !pset.hide_tableam)
3374  {
3375  printfPQExpBuffer(&buf, _("Access method: %s"), tableinfo.relam);
3376  printTableAddFooter(&cont, buf.data);
3377  }
3378  }
3379 
3380  /* reloptions, if verbose */
3381  if (verbose &&
3382  tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
3383  {
3384  const char *t = _("Options");
3385 
3386  printfPQExpBuffer(&buf, "%s: %s", t, tableinfo.reloptions);
3387  printTableAddFooter(&cont, buf.data);
3388  }
3389 
3390  printTable(&cont, pset.queryFout, false, pset.logfile);
3391 
3392  retval = true;
3393 
3394 error_return:
3395 
3396  /* clean up */
3397  if (printTableInitialized)
3398  printTableCleanup(&cont);
3399  termPQExpBuffer(&buf);
3400  termPQExpBuffer(&title);
3402 
3403  if (view_def)
3404  free(view_def);
3405 
3406  if (res)
3407  PQclear(res);
3408 
3409  return retval;
3410 }
signed short int16
Definition: c.h:428
#define CppAsString2(x)
Definition: c.h:289
static void add_tablespace_footer(printTableContent *const cont, char relkind, Oid tablespace, const bool newline)
Definition: describe.c:3418
int PQfnumber(const PGresult *res, const char *field_name)
Definition: fe-exec.c:3356
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3667
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void printTableInit(printTableContent *const content, const printTableOpt *opt, const char *title, const int ncolumns, const int nrows)
Definition: print.c:3127
void printTableCleanup(printTableContent *const content)
Definition: print.c:3295
void printTableAddCell(printTableContent *const content, char *cell, const bool translate, const bool mustfree)
Definition: print.c:3204
void printTable(const printTableContent *cont, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3384
void printTableAddHeader(printTableContent *const content, char *header, const bool translate, const char align)
Definition: print.c:3164
#define free(a)
Definition: header.h:65
Assert(fmt[strlen(fmt) - 1] !='\n')
int pg_wcswidth(const char *pwcs, size_t len, int encoding)
Definition: mbprint.c:177
NameData relname
Definition: pg_class.h:38
unsigned int Oid
Definition: postgres_ext.h:31
#define atooid(x)
Definition: postgres_ext.h:42
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:148
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:380
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
const char * fmtId(const char *rawid)
Definition: string_utils.c:64
bool hide_tableam
Definition: settings.h:138
int encoding
Definition: settings.h:83
bool hide_compression
Definition: settings.h:137
printTableOpt topt
Definition: print.h:169
char ** footers
Definition: print.h:172
unsigned short int expanded
Definition: print.h:102
bool default_footer
Definition: print.h:113
static StringInfoData tmpbuf
Definition: walsender.c:159

References _, add_tablespace_footer(), appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), Assert(), atooid, buf, CppAsString2, StringInfoData::data, PQExpBufferData::data, printTableOpt::default_footer, _psqlSettings::encoding, printTableOpt::expanded, fmtId(), printQueryOpt::footers, free, gettext_noop, _psqlSettings::hide_compression, _psqlSettings::hide_tableam, i, initPQExpBuffer(), lengthof, _psqlSettings::logfile, pg_log_error, pg_strdup(), pg_wcswidth(), _psqlSettings::popt, PQclear(), PQfnumber(), PQgetisnull(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), printQuery(), printTable(), printTableAddCell(), printTableAddFooter(), printTableAddHeader(), printTableCleanup(), printTableInit(), pset, psprintf(), PSQLexec(), _psqlSettings::queryFout, _psqlSettings::quiet, relname, res, resetPQExpBuffer(), _psqlSettings::sversion, tablespace, termPQExpBuffer(), printQueryOpt::title, tmpbuf, printQueryOpt::topt, printQueryOpt::translate_header, and verbose.

Referenced by describeTableDetails().

◆ describeOneTSConfig()

static bool describeOneTSConfig ( const char *  oid,
const char *  nspname,
const char *  cfgname,
const char *  pnspname,
const char *  prsname 
)
static

Definition at line 5295 of file describe.c.

5297 {
5299  title;
5300  PGresult *res;
5301  printQueryOpt myopt = pset.popt;
5302 
5303  initPQExpBuffer(&buf);
5304 
5306  "SELECT\n"
5307  " ( SELECT t.alias FROM\n"
5308  " pg_catalog.ts_token_type(c.cfgparser) AS t\n"
5309  " WHERE t.tokid = m.maptokentype ) AS \"%s\",\n"
5310  " pg_catalog.btrim(\n"
5311  " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary\n"
5312  " FROM pg_catalog.pg_ts_config_map AS mm\n"
5313  " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype\n"
5314  " ORDER BY mapcfg, maptokentype, mapseqno\n"
5315  " ) :: pg_catalog.text,\n"
5316  " '{}') AS \"%s\"\n"
5317  "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m\n"
5318  "WHERE c.oid = '%s' AND m.mapcfg = c.oid\n"
5319  "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser\n"
5320  "ORDER BY 1;",
5321  gettext_noop("Token"),
5322  gettext_noop("Dictionaries"),
5323  oid);
5324 
5325  res = PSQLexec(buf.data);
5326  termPQExpBuffer(&buf);
5327  if (!res)
5328  return false;
5329 
5330  initPQExpBuffer(&title);
5331 
5332  if (nspname)
5333  appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
5334  nspname, cfgname);
5335  else
5336  appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
5337  cfgname);
5338 
5339  if (pnspname)
5340  appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
5341  pnspname, prsname);
5342  else
5343  appendPQExpBuffer(&title, _("\nParser: \"%s\""),
5344  prsname);
5345 
5346  myopt.nullPrint = NULL;
5347  myopt.title = title.data;
5348  myopt.footers = NULL;
5349  myopt.topt.default_footer = false;
5350  myopt.translate_header = true;
5351 
5352  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5353 
5354  termPQExpBuffer(&title);
5355 
5356  PQclear(res);
5357  return true;
5358 }

References _, appendPQExpBuffer(), buf, PQExpBufferData::data, printTableOpt::default_footer, printQueryOpt::footers, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::topt, and printQueryOpt::translate_header.

Referenced by listTSConfigsVerbose().

◆ describeOneTSParser()

static bool describeOneTSParser ( const char *  oid,
const char *  nspname,
const char *  prsname 
)
static

Definition at line 4930 of file describe.c.

4931 {
4933  PGresult *res;
4934  PQExpBufferData title;
4935  printQueryOpt myopt = pset.popt;
4936  static const bool translate_columns[] = {true, false, false};
4937 
4938  initPQExpBuffer(&buf);
4939 
4941  "SELECT '%s' AS \"%s\",\n"
4942  " p.prsstart::pg_catalog.regproc AS \"%s\",\n"
4943  " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\"\n"
4944  " FROM pg_catalog.pg_ts_parser p\n"
4945  " WHERE p.oid = '%s'\n"
4946  "UNION ALL\n"
4947  "SELECT '%s',\n"
4948  " p.prstoken::pg_catalog.regproc,\n"
4949  " pg_catalog.obj_description(p.prstoken, 'pg_proc')\n"
4950  " FROM pg_catalog.pg_ts_parser p\n"
4951  " WHERE p.oid = '%s'\n"
4952  "UNION ALL\n"
4953  "SELECT '%s',\n"
4954  " p.prsend::pg_catalog.regproc,\n"
4955  " pg_catalog.obj_description(p.prsend, 'pg_proc')\n"
4956  " FROM pg_catalog.pg_ts_parser p\n"
4957  " WHERE p.oid = '%s'\n"
4958  "UNION ALL\n"
4959  "SELECT '%s',\n"
4960  " p.prsheadline::pg_catalog.regproc,\n"
4961  " pg_catalog.obj_description(p.prsheadline, 'pg_proc')\n"
4962  " FROM pg_catalog.pg_ts_parser p\n"
4963  " WHERE p.oid = '%s'\n"
4964  "UNION ALL\n"
4965  "SELECT '%s',\n"
4966  " p.prslextype::pg_catalog.regproc,\n"
4967  " pg_catalog.obj_description(p.prslextype, 'pg_proc')\n"
4968  " FROM pg_catalog.pg_ts_parser p\n"
4969  " WHERE p.oid = '%s';",
4970  gettext_noop("Start parse"),
4971  gettext_noop("Method"),
4972  gettext_noop("Function"),
4973  gettext_noop("Description"),
4974  oid,
4975  gettext_noop("Get next token"),
4976  oid,
4977  gettext_noop("End parse"),
4978  oid,
4979  gettext_noop("Get headline"),
4980  oid,
4981  gettext_noop("Get token types"),
4982  oid);
4983 
4984  res = PSQLexec(buf.data);
4985  termPQExpBuffer(&buf);
4986  if (!res)
4987  return false;
4988 
4989  myopt.nullPrint = NULL;
4990  initPQExpBuffer(&title);
4991  if (nspname)
4992  printfPQExpBuffer(&title, _("Text search parser \"%s.%s\""),
4993  nspname, prsname);
4994  else
4995  printfPQExpBuffer(&title, _("Text search parser \"%s\""), prsname);
4996  myopt.title = title.data;
4997  myopt.footers = NULL;
4998  myopt.topt.default_footer = false;
4999  myopt.translate_header = true;
5000  myopt.translate_columns = translate_columns;
5001  myopt.n_translate_columns = lengthof(translate_columns);
5002 
5003  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5004 
5005  PQclear(res);
5006 
5007  initPQExpBuffer(&buf);
5008 
5010  "SELECT t.alias as \"%s\",\n"
5011  " t.description as \"%s\"\n"
5012  "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t\n"
5013  "ORDER BY 1;",
5014  gettext_noop("Token name"),
5015  gettext_noop("Description"),
5016  oid);
5017 
5018  res = PSQLexec(buf.data);
5019  termPQExpBuffer(&buf);
5020  if (!res)
5021  return false;
5022 
5023  myopt.nullPrint = NULL;
5024  if (nspname)
5025  printfPQExpBuffer(&title, _("Token types for parser \"%s.%s\""),
5026  nspname, prsname);
5027  else
5028  printfPQExpBuffer(&title, _("Token types for parser \"%s\""), prsname);
5029  myopt.title = title.data;
5030  myopt.footers = NULL;
5031  myopt.topt.default_footer = true;
5032  myopt.translate_header = true;
5033  myopt.translate_columns = NULL;
5034  myopt.n_translate_columns = 0;
5035 
5036  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5037 
5038  termPQExpBuffer(&title);
5039  PQclear(res);
5040  return true;
5041 }

References _, buf, PQExpBufferData::data, printTableOpt::default_footer, printQueryOpt::footers, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::topt, printQueryOpt::translate_columns, and printQueryOpt::translate_header.

Referenced by listTSParsersVerbose().

◆ describeOperators()

bool describeOperators ( const char *  oper_pattern,
char **  arg_patterns,
int  num_arg_patterns,
bool  verbose,
bool  showSystem 
)

Definition at line 746 of file describe.c.

749 {
751  PGresult *res;
752  printQueryOpt myopt = pset.popt;
753 
755 
756  /*
757  * Note: before Postgres 9.1, we did not assign comments to any built-in
758  * operators, preferring to let the comment on the underlying function
759  * suffice. The coalesce() on the obj_description() calls below supports
760  * this convention by providing a fallback lookup of a comment on the
761  * operator's function. Since 9.1 there is a policy that every built-in
762  * operator should have a comment; so the coalesce() is no longer
763  * necessary so far as built-in operators are concerned. We keep it
764  * anyway, for now, because third-party modules may still be following the
765  * old convention.
766  *
767  * The support for postfix operators in this query is dead code as of
768  * Postgres 14, but we need to keep it for as long as we support talking
769  * to pre-v14 servers.
770  */
771 
773  "SELECT n.nspname as \"%s\",\n"
774  " o.oprname AS \"%s\",\n"
775  " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
776  " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
777  " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
778  gettext_noop("Schema"),
779  gettext_noop("Name"),
780  gettext_noop("Left arg type"),
781  gettext_noop("Right arg type"),
782  gettext_noop("Result type"));
783 
784  if (verbose)
786  " o.oprcode AS \"%s\",\n",
787  gettext_noop("Function"));
788 
790  " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
791  " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
792  "FROM pg_catalog.pg_operator o\n"
793  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
794  gettext_noop("Description"));
795 
796  if (num_arg_patterns >= 2)
797  {
798  num_arg_patterns = 2; /* ignore any additional arguments */
800  " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprleft\n"
801  " LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n"
802  " LEFT JOIN pg_catalog.pg_type t1 ON t1.oid = o.oprright\n"
803  " LEFT JOIN pg_catalog.pg_namespace nt1 ON nt1.oid = t1.typnamespace\n");
804  }
805  else if (num_arg_patterns == 1)
806  {
808  " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprright\n"
809  " LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n");
810  }
811 
812  if (!showSystem && !oper_pattern)
813  appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
814  " AND n.nspname <> 'information_schema'\n");
815 
816  processSQLNamePattern(pset.db, &buf, oper_pattern,
817  !showSystem && !oper_pattern, true,
818  "n.nspname", "o.oprname", NULL,
819  "pg_catalog.pg_operator_is_visible(o.oid)");
820 
821  if (num_arg_patterns == 1)
822  appendPQExpBufferStr(&buf, " AND o.oprleft = 0\n");
823 
824  for (int i = 0; i < num_arg_patterns; i++)
825  {
826  if (strcmp(arg_patterns[i], "-") != 0)
827  {
828  /*
829  * Match type-name patterns against either internal or external
830  * name, like \dT. Unlike \dT, there seems no reason to
831  * discriminate against arrays or composite types.
832  */
833  char nspname[64];
834  char typname[64];
835  char ft[64];
836  char tiv[64];
837 
838  snprintf(nspname, sizeof(nspname), "nt%d.nspname", i);
839  snprintf(typname, sizeof(typname), "t%d.typname", i);
840  snprintf(ft, sizeof(ft),
841  "pg_catalog.format_type(t%d.oid, NULL)", i);
842  snprintf(tiv, sizeof(tiv),
843  "pg_catalog.pg_type_is_visible(t%d.oid)", i);
845  map_typename_pattern(arg_patterns[i]),
846  true, false,
847  nspname, typname, ft, tiv);
848  }
849  else
850  {
851  /* "-" pattern specifies no such parameter */
852  appendPQExpBuffer(&buf, " AND t%d.typname IS NULL\n", i);
853  }
854  }
855 
856  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4;");
857 
858  res = PSQLexec(buf.data);
860  if (!res)
861  return false;
862 
863  myopt.nullPrint = NULL;
864  myopt.title = _("List of operators");
865  myopt.translate_header = true;
866 
867  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
868 
869  PQclear(res);
870  return true;
871 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, i, initPQExpBuffer(), _psqlSettings::logfile, map_typename_pattern(), printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, snprintf, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_header, typname, and verbose.

Referenced by exec_command_dfo().

◆ describePublications()

bool describePublications ( const char *  pattern)

Definition at line 5885 of file describe.c.

5886 {
5888  int i;
5889  PGresult *res;
5890  bool has_pubtruncate;
5891  bool has_pubviaroot;
5892 
5893  PQExpBufferData title;
5894  printTableContent cont;
5895 
5896  if (pset.sversion < 100000)
5897  {
5898  char sverbuf[32];
5899 
5900  pg_log_error("The server (version %s) does not support publications.",
5902  sverbuf, sizeof(sverbuf)));
5903  return true;
5904  }
5905 
5906  has_pubtruncate = (pset.sversion >= 110000);
5907  has_pubviaroot = (pset.sversion >= 130000);
5908 
5909  initPQExpBuffer(&buf);
5910 
5912  "SELECT oid, pubname,\n"
5913  " pg_catalog.pg_get_userbyid(pubowner) AS owner,\n"
5914  " puballtables, pubinsert, pubupdate, pubdelete");
5915  if (has_pubtruncate)
5917  ", pubtruncate");
5918  if (has_pubviaroot)
5920  ", pubviaroot");
5922  "\nFROM pg_catalog.pg_publication\n");
5923 
5924  processSQLNamePattern(pset.db, &buf, pattern, false, false,
5925  NULL, "pubname", NULL,
5926  NULL);
5927 
5928  appendPQExpBufferStr(&buf, "ORDER BY 2;");
5929 
5930  res = PSQLexec(buf.data);
5931  if (!res)
5932  {
5933  termPQExpBuffer(&buf);
5934  return false;
5935  }
5936 
5937  if (PQntuples(res) == 0)
5938  {
5939  if (!pset.quiet)
5940  {
5941  if (pattern)
5942  pg_log_error("Did not find any publication named \"%s\".",
5943  pattern);
5944  else
5945  pg_log_error("Did not find any publications.");
5946  }
5947 
5948  termPQExpBuffer(&buf);
5949  PQclear(res);
5950  return false;
5951  }
5952 
5953  for (i = 0; i < PQntuples(res); i++)
5954  {
5955  const char align = 'l';
5956  int ncols = 5;
5957  int nrows = 1;
5958  char *pubid = PQgetvalue(res, i, 0);
5959  char *pubname = PQgetvalue(res, i, 1);
5960  bool puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
5961  printTableOpt myopt = pset.popt.topt;
5962 
5963  if (has_pubtruncate)
5964  ncols++;
5965  if (has_pubviaroot)
5966  ncols++;
5967 
5968  initPQExpBuffer(&title);
5969  printfPQExpBuffer(&title, _("Publication %s"), pubname);
5970  printTableInit(&cont, &myopt, title.data, ncols, nrows);
5971 
5972  printTableAddHeader(&cont, gettext_noop("Owner"), true, align);
5973  printTableAddHeader(&cont, gettext_noop("All tables"), true, align);
5974  printTableAddHeader(&cont, gettext_noop("Inserts"), true, align);
5975  printTableAddHeader(&cont, gettext_noop("Updates"), true, align);
5976  printTableAddHeader(&cont, gettext_noop("Deletes"), true, align);
5977  if (has_pubtruncate)
5978  printTableAddHeader(&cont, gettext_noop("Truncates"), true, align);
5979  if (has_pubviaroot)
5980  printTableAddHeader(&cont, gettext_noop("Via root"), true, align);
5981 
5982  printTableAddCell(&cont, PQgetvalue(res, i, 2), false, false);
5983  printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false);
5984  printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false);
5985  printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
5986  printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
5987  if (has_pubtruncate)
5988  printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
5989  if (has_pubviaroot)
5990  printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
5991 
5992  if (!puballtables)
5993  {
5994  /* Get the tables for the specified publication */
5996  "SELECT n.nspname, c.relname\n"
5997  "FROM pg_catalog.pg_class c,\n"
5998  " pg_catalog.pg_namespace n,\n"
5999  " pg_catalog.pg_publication_rel pr\n"
6000  "WHERE c.relnamespace = n.oid\n"
6001  " AND c.oid = pr.prrelid\n"
6002  " AND pr.prpubid = '%s'\n"
6003  "ORDER BY 1,2", pubid);
6004  if (!addFooterToPublicationDesc(&buf, "Tables:", false, &cont))
6005  goto error_return;
6006 
6007  if (pset.sversion >= 150000)
6008  {
6009  /* Get the schemas for the specified publication */
6011  "SELECT n.nspname\n"
6012  "FROM pg_catalog.pg_namespace n\n"
6013  " JOIN pg_catalog.pg_publication_namespace pn ON n.oid = pn.pnnspid\n"
6014  "WHERE pn.pnpubid = '%s'\n"
6015  "ORDER BY 1", pubid);
6016  if (!addFooterToPublicationDesc(&buf, "Tables from schemas:",
6017  true, &cont))
6018  goto error_return;
6019  }
6020  }
6021 
6022  printTable(&cont, pset.queryFout, false, pset.logfile);
6023  printTableCleanup(&cont);
6024 
6025  termPQExpBuffer(&title);
6026  }
6027 
6028  termPQExpBuffer(&buf);
6029  PQclear(res);
6030 
6031  return true;
6032 
6033 error_return:
6034  printTableCleanup(&cont);
6035  PQclear(res);
6036  termPQExpBuffer(&buf);
6037  termPQExpBuffer(&title);
6038  return false;
6039 }
static bool addFooterToPublicationDesc(PQExpBuffer buf, char *footermsg, bool singlecol, printTableContent *cont)
Definition: describe.c:5847

References _, addFooterToPublicationDesc(), appendPQExpBufferStr(), buf, PQExpBufferData::data, _psqlSettings::db, formatPGVersionNumber(), gettext_noop, i, initPQExpBuffer(), _psqlSettings::logfile, pg_log_error, _psqlSettings::popt, PQclear(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), printTable(), printTableAddCell(), printTableAddHeader(), printTableCleanup(), printTableInit(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, _psqlSettings::quiet, res, _psqlSettings::sversion, termPQExpBuffer(), and printQueryOpt::topt.

Referenced by exec_command_d().

◆ describeRoles()

bool describeRoles ( const char *  pattern,
bool  verbose,
bool  showSystem 
)

Definition at line 3483 of file describe.c.

3484 {
3486  PGresult *res;
3487  printTableContent cont;
3488  printTableOpt myopt = pset.popt.topt;
3489  int ncols = 3;
3490  int nrows = 0;
3491  int i;
3492  int conns;
3493  const char align = 'l';
3494  char **attr;
3495 
3496  myopt.default_footer = false;
3497 
3498  initPQExpBuffer(&buf);
3499 
3501  "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
3502  " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
3503  " r.rolconnlimit, r.rolvaliduntil,\n"
3504  " ARRAY(SELECT b.rolname\n"
3505  " FROM pg_catalog.pg_auth_members m\n"
3506  " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
3507  " WHERE m.member = r.oid) as memberof");
3508 
3509  if (verbose)
3510  {
3511  appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
3512  ncols++;
3513  }
3514  appendPQExpBufferStr(&buf, "\n, r.rolreplication");
3515 
3516  if (pset.sversion >= 90500)
3517  {
3518  appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
3519  }
3520 
3521  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
3522 
3523  if (!showSystem && !pattern)
3524  appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
3525 
3526  processSQLNamePattern(pset.db, &buf, pattern, false, false,
3527  NULL, "r.rolname", NULL, NULL);
3528 
3529  appendPQExpBufferStr(&buf, "ORDER BY 1;");
3530 
3531  res = PSQLexec(buf.data);
3532  if (!res)
3533  return false;
3534 
3535  nrows = PQntuples(res);
3536  attr = pg_malloc0((nrows + 1) * sizeof(*attr));
3537 
3538  printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
3539 
3540  printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
3541  printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
3542  /* ignores implicit memberships from superuser & pg_database_owner */
3543  printTableAddHeader(&cont, gettext_noop("Member of"), true, align);
3544 
3545  if (verbose)
3546  printTableAddHeader(&cont, gettext_noop("Description"), true, align);
3547 
3548  for (i = 0; i < nrows; i++)
3549  {
3550  printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
3551 
3553  if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
3554  add_role_attribute(&buf, _("Superuser"));
3555 
3556  if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
3557  add_role_attribute(&buf, _("No inheritance"));
3558 
3559  if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
3560  add_role_attribute(&buf, _("Create role"));
3561 
3562  if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
3563  add_role_attribute(&buf, _("Create DB"));
3564 
3565  if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
3566  add_role_attribute(&buf, _("Cannot login"));
3567 
3568  if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
3569  add_role_attribute(&buf, _("Replication"));
3570 
3571  if (pset.sversion >= 90500)
3572  if (strcmp(PQgetvalue(res, i, (verbose ? 11 : 10)), "t") == 0)
3573  add_role_attribute(&buf, _("Bypass RLS"));
3574 
3575  conns = atoi(PQgetvalue(res, i, 6));
3576  if (conns >= 0)
3577  {
3578  if (buf.len > 0)
3579  appendPQExpBufferChar(&buf, '\n');
3580 
3581  if (conns == 0)
3582  appendPQExpBufferStr(&buf, _("No connections"));
3583  else
3584  appendPQExpBuffer(&buf, ngettext("%d connection",
3585  "%d connections",
3586  conns),
3587  conns);
3588  }
3589 
3590  if (strcmp(PQgetvalue(res, i, 7), "") != 0)
3591  {
3592  if (buf.len > 0)
3593  appendPQExpBufferChar(&buf, '\n');
3594  appendPQExpBufferStr(&buf, _("Password valid until "));
3596  }
3597 
3598  attr[i] = pg_strdup(buf.data);
3599 
3600  printTableAddCell(&cont, attr[i], false, false);
3601 
3602  printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
3603 
3604  if (verbose)
3605  printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
3606  }
3607  termPQExpBuffer(&buf);
3608 
3609  printTable(&cont, pset.queryFout, false, pset.logfile);
3610  printTableCleanup(&cont);
3611 
3612  for (i = 0; i < nrows; i++)
3613  free(attr[i]);
3614  free(attr);
3615 
3616  PQclear(res);
3617  return true;
3618 }
#define ngettext(s, p, n)
Definition: c.h:1179
static void add_role_attribute(PQExpBuffer buf, const char *const str)
Definition: describe.c:3621
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
static IsoConnInfo * conns

References _, add_role_attribute(), appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), buf, conns, _psqlSettings::db, printTableOpt::default_footer, free, gettext_noop, i, initPQExpBuffer(), _psqlSettings::logfile, ngettext, pg_malloc0(), pg_strdup(), _psqlSettings::popt, PQclear(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), printTable(), printTableAddCell(), printTableAddHeader(), printTableCleanup(), printTableInit(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, resetPQExpBuffer(), _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::topt, and verbose.

Referenced by exec_command_d().

◆ describeSubscriptions()

bool describeSubscriptions ( const char *  pattern,
bool  verbose 
)

Definition at line 6048 of file describe.c.

6049 {
6051  PGresult *res;
6052  printQueryOpt myopt = pset.popt;
6053  static const bool translate_columns[] = {false, false, false, false,
6054  false, false, false, false, false};
6055 
6056  if (pset.sversion < 100000)
6057  {
6058  char sverbuf[32];
6059 
6060  pg_log_error("The server (version %s) does not support subscriptions.",
6062  sverbuf, sizeof(sverbuf)));
6063  return true;
6064  }
6065 
6066  initPQExpBuffer(&buf);
6067 
6069  "SELECT subname AS \"%s\"\n"
6070  ", pg_catalog.pg_get_userbyid(subowner) AS \"%s\"\n"
6071  ", subenabled AS \"%s\"\n"
6072  ", subpublications AS \"%s\"\n",
6073  gettext_noop("Name"),
6074  gettext_noop("Owner"),
6075  gettext_noop("Enabled"),
6076  gettext_noop("Publication"));
6077 
6078  if (verbose)
6079  {
6080  /* Binary mode and streaming are only supported in v14 and higher */
6081  if (pset.sversion >= 140000)
6083  ", subbinary AS \"%s\"\n"
6084  ", substream AS \"%s\"\n",
6085  gettext_noop("Binary"),
6086  gettext_noop("Streaming"));
6087 
6088  /* Two_phase is only supported in v15 and higher */
6089  if (pset.sversion >= 150000)
6091  ", subtwophasestate AS \"%s\"\n",
6092  gettext_noop("Two phase commit"));
6093 
6095  ", subsynccommit AS \"%s\"\n"
6096  ", subconninfo AS \"%s\"\n",
6097  gettext_noop("Synchronous commit"),
6098  gettext_noop("Conninfo"));
6099  }
6100 
6101  /* Only display subscriptions in current database. */
6103  "FROM pg_catalog.pg_subscription\n"
6104  "WHERE subdbid = (SELECT oid\n"
6105  " FROM pg_catalog.pg_database\n"
6106  " WHERE datname = pg_catalog.current_database())");
6107 
6108  processSQLNamePattern(pset.db, &buf, pattern, true, false,
6109  NULL, "subname", NULL,
6110  NULL);
6111 
6112  appendPQExpBufferStr(&buf, "ORDER BY 1;");
6113 
6114  res = PSQLexec(buf.data);
6115  termPQExpBuffer(&buf);
6116  if (!res)
6117  return false;
6118 
6119  myopt.nullPrint = NULL;
6120  myopt.title = _("List of subscriptions");
6121  myopt.translate_header = true;
6122  myopt.translate_columns = translate_columns;
6123  myopt.n_translate_columns = lengthof(translate_columns);
6124 
6125  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6126 
6127  PQclear(res);
6128  return true;
6129 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, formatPGVersionNumber(), gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, pg_log_error, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ describeTableDetails()

bool describeTableDetails ( const char *  pattern,
bool  verbose,
bool  showSystem 
)

Definition at line 1356 of file describe.c.

1357 {
1359  PGresult *res;
1360  int i;
1361 
1362  initPQExpBuffer(&buf);
1363 
1365  "SELECT c.oid,\n"
1366  " n.nspname,\n"
1367  " c.relname\n"
1368  "FROM pg_catalog.pg_class c\n"
1369  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1370 
1371  if (!showSystem && !pattern)
1372  appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1373  " AND n.nspname <> 'information_schema'\n");
1374 
1375  processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
1376  "n.nspname", "c.relname", NULL,
1377  "pg_catalog.pg_table_is_visible(c.oid)");
1378 
1379  appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
1380 
1381  res = PSQLexec(buf.data);
1382  termPQExpBuffer(&buf);
1383  if (!res)
1384  return false;
1385 
1386  if (PQntuples(res) == 0)
1387  {
1388  if (!pset.quiet)
1389  {
1390  if (pattern)
1391  pg_log_error("Did not find any relation named \"%s\".",
1392  pattern);
1393  else
1394  pg_log_error("Did not find any relations.");
1395  }
1396  PQclear(res);
1397  return false;
1398  }
1399 
1400  for (i = 0; i < PQntuples(res); i++)
1401  {
1402  const char *oid;
1403  const char *nspname;
1404  const char *relname;
1405 
1406  oid = PQgetvalue(res, i, 0);
1407  nspname = PQgetvalue(res, i, 1);
1408  relname = PQgetvalue(res, i, 2);
1409 
1410  if (!describeOneTableDetails(nspname, relname, oid, verbose))
1411  {
1412  PQclear(res);
1413  return false;
1414  }
1415  if (cancel_pressed)
1416  {
1417  PQclear(res);
1418  return false;
1419  }
1420  }
1421 
1422  PQclear(res);
1423  return true;
1424 }
static bool describeOneTableDetails(const char *schemaname, const char *relationname, const char *oid, bool verbose)
Definition: describe.c:1434
volatile sig_atomic_t cancel_pressed
Definition: print.c:43

References appendPQExpBufferStr(), buf, cancel_pressed, _psqlSettings::db, describeOneTableDetails(), i, initPQExpBuffer(), pg_log_error, PQclear(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::quiet, relname, res, termPQExpBuffer(), and verbose.

Referenced by exec_command_d().

◆ describeTablespaces()

bool describeTablespaces ( const char *  pattern,
bool  verbose 
)

Definition at line 201 of file describe.c.

202 {
204  PGresult *res;
205  printQueryOpt myopt = pset.popt;
206 
208 
210  "SELECT spcname AS \"%s\",\n"
211  " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
212  " pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
213  gettext_noop("Name"),
214  gettext_noop("Owner"),
215  gettext_noop("Location"));
216 
217  if (verbose)
218  {
219  appendPQExpBufferStr(&buf, ",\n ");
220  printACLColumn(&buf, "spcacl");
222  ",\n spcoptions AS \"%s\""
223  ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\""
224  ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
225  gettext_noop("Options"),
226  gettext_noop("Size"),
227  gettext_noop("Description"));
228  }
229 
231  "\nFROM pg_catalog.pg_tablespace\n");
232 
233  processSQLNamePattern(pset.db, &buf, pattern, false, false,
234  NULL, "spcname", NULL,
235  NULL);
236 
237  appendPQExpBufferStr(&buf, "ORDER BY 1;");
238 
239  res = PSQLexec(buf.data);
241  if (!res)
242  return false;
243 
244  myopt.nullPrint = NULL;
245  myopt.title = _("List of tablespaces");
246  myopt.translate_header = true;
247 
248  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
249 
250  PQclear(res);
251  return true;
252 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ describeTypes()

bool describeTypes ( const char *  pattern,
bool  verbose,
bool  showSystem 
)

Definition at line 595 of file describe.c.

596 {
598  PGresult *res;
599  printQueryOpt myopt = pset.popt;
600 
602 
604  "SELECT n.nspname as \"%s\",\n"
605  " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
606  gettext_noop("Schema"),
607  gettext_noop("Name"));
608  if (verbose)
609  {
611  " t.typname AS \"%s\",\n"
612  " CASE WHEN t.typrelid != 0\n"
613  " THEN CAST('tuple' AS pg_catalog.text)\n"
614  " WHEN t.typlen < 0\n"
615  " THEN CAST('var' AS pg_catalog.text)\n"
616  " ELSE CAST(t.typlen AS pg_catalog.text)\n"
617  " END AS \"%s\",\n"
618  " pg_catalog.array_to_string(\n"
619  " ARRAY(\n"
620  " SELECT e.enumlabel\n"
621  " FROM pg_catalog.pg_enum e\n"
622  " WHERE e.enumtypid = t.oid\n"
623  " ORDER BY e.enumsortorder\n"
624  " ),\n"
625  " E'\\n'\n"
626  " ) AS \"%s\",\n"
627  " pg_catalog.pg_get_userbyid(t.typowner) AS \"%s\",\n",
628  gettext_noop("Internal name"),
629  gettext_noop("Size"),
630  gettext_noop("Elements"),
631  gettext_noop("Owner"));
632  printACLColumn(&buf, "t.typacl");
633  appendPQExpBufferStr(&buf, ",\n ");
634  }
635 
637  " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
638  gettext_noop("Description"));
639 
640  appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_type t\n"
641  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
642 
643  /*
644  * do not include complex types (typrelid!=0) unless they are standalone
645  * composite types
646  */
647  appendPQExpBufferStr(&buf, "WHERE (t.typrelid = 0 ");
648  appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
649  " FROM pg_catalog.pg_class c "
650  "WHERE c.oid = t.typrelid))\n");
651 
652  /*
653  * do not include array types unless the pattern contains []
654  */
655  if (pattern == NULL || strstr(pattern, "[]") == NULL)
656  appendPQExpBufferStr(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
657 
658  if (!showSystem && !pattern)
659  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
660  " AND n.nspname <> 'information_schema'\n");
661 
662  /* Match name pattern against either internal or external name */
664  true, false,
665  "n.nspname", "t.typname",
666  "pg_catalog.format_type(t.oid, NULL)",
667  "pg_catalog.pg_type_is_visible(t.oid)");
668 
669  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
670 
671  res = PSQLexec(buf.data);
673  if (!res)
674  return false;
675 
676  myopt.nullPrint = NULL;
677  myopt.title = _("List of data types");
678  myopt.translate_header = true;
679 
680  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
681 
682  PQclear(res);
683  return true;
684 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, CppAsString2, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, map_typename_pattern(), printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ listAllDbs()

bool listAllDbs ( const char *  pattern,
bool  verbose 
)

Definition at line 880 of file describe.c.

881 {
882  PGresult *res;
884  printQueryOpt myopt = pset.popt;
885 
887 
889  "SELECT d.datname as \"%s\",\n"
890  " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
891  " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n"
892  " d.datcollate as \"%s\",\n"
893  " d.datctype as \"%s\",\n",
894  gettext_noop("Name"),
895  gettext_noop("Owner"),
896  gettext_noop("Encoding"),
897  gettext_noop("Collate"),
898  gettext_noop("Ctype"));
899  appendPQExpBufferStr(&buf, " ");
900  printACLColumn(&buf, "d.datacl");
901  if (verbose)
903  ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
904  " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
905  " ELSE 'No Access'\n"
906  " END as \"%s\""
907  ",\n t.spcname as \"%s\""
908  ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
909  gettext_noop("Size"),
910  gettext_noop("Tablespace"),
911  gettext_noop("Description"));
913  "\nFROM pg_catalog.pg_database d\n");
914  if (verbose)
916  " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
917 
918  if (pattern)
919  processSQLNamePattern(pset.db, &buf, pattern, false, false,
920  NULL, "d.datname", NULL, NULL);
921 
922  appendPQExpBufferStr(&buf, "ORDER BY 1;");
923  res = PSQLexec(buf.data);
925  if (!res)
926  return false;
927 
928  myopt.nullPrint = NULL;
929  myopt.title = _("List of databases");
930  myopt.translate_header = true;
931 
932  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
933 
934  PQclear(res);
935  return true;
936 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_list(), and main().

◆ listCasts()

bool listCasts ( const char *  pattern,
bool  verbose 
)

Definition at line 4490 of file describe.c.

4491 {
4493  PGresult *res;
4494  printQueryOpt myopt = pset.popt;
4495  static const bool translate_columns[] = {false, false, false, true, false};
4496 
4497  initPQExpBuffer(&buf);
4498 
4500  "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
4501  " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n",
4502  gettext_noop("Source type"),
4503  gettext_noop("Target type"));
4504 
4505  /*
4506  * We don't attempt to localize '(binary coercible)' or '(with inout)',
4507  * because there's too much risk of gettext translating a function name
4508  * that happens to match some string in the PO database.
4509  */
4511  " CASE WHEN c.castmethod = '%c' THEN '(binary coercible)'\n"
4512  " WHEN c.castmethod = '%c' THEN '(with inout)'\n"
4513  " ELSE p.proname\n"
4514  " END AS \"%s\",\n",
4515  COERCION_METHOD_BINARY,
4516  COERCION_METHOD_INOUT,
4517  gettext_noop("Function"));
4518 
4520  " CASE WHEN c.castcontext = '%c' THEN '%s'\n"
4521  " WHEN c.castcontext = '%c' THEN '%s'\n"
4522  " ELSE '%s'\n"
4523  " END AS \"%s\"",
4524  COERCION_CODE_EXPLICIT,
4525  gettext_noop("no"),
4526  COERCION_CODE_ASSIGNMENT,
4527  gettext_noop("in assignment"),
4528  gettext_noop("yes"),
4529  gettext_noop("Implicit?"));
4530 
4531  if (verbose)
4533  ",\n d.description AS \"%s\"",
4534  gettext_noop("Description"));
4535 
4536  /*
4537  * We need a left join to pg_proc for binary casts; the others are just
4538  * paranoia.
4539  */
4541  "\nFROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
4542  " ON c.castfunc = p.oid\n"
4543  " LEFT JOIN pg_catalog.pg_type ts\n"
4544  " ON c.castsource = ts.oid\n"
4545  " LEFT JOIN pg_catalog.pg_namespace ns\n"
4546  " ON ns.oid = ts.typnamespace\n"
4547  " LEFT JOIN pg_catalog.pg_type tt\n"
4548  " ON c.casttarget = tt.oid\n"
4549  " LEFT JOIN pg_catalog.pg_namespace nt\n"
4550  " ON nt.oid = tt.typnamespace\n");
4551 
4552  if (verbose)
4554  " LEFT JOIN pg_catalog.pg_description d\n"
4555  " ON d.classoid = c.tableoid AND d.objoid = "
4556  "c.oid AND d.objsubid = 0\n");
4557 
4558  appendPQExpBufferStr(&buf, "WHERE ( (true");
4559 
4560  /*
4561  * Match name pattern against either internal or external name of either
4562  * castsource or casttarget
4563  */
4564  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4565  "ns.nspname", "ts.typname",
4566  "pg_catalog.format_type(ts.oid, NULL)",
4567  "pg_catalog.pg_type_is_visible(ts.oid)");
4568 
4569  appendPQExpBufferStr(&buf, ") OR (true");
4570 
4571  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4572  "nt.nspname", "tt.typname",
4573  "pg_catalog.format_type(tt.oid, NULL)",
4574  "pg_catalog.pg_type_is_visible(tt.oid)");
4575 
4576  appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
4577 
4578  res = PSQLexec(buf.data);
4579  termPQExpBuffer(&buf);
4580  if (!res)
4581  return false;
4582 
4583  myopt.nullPrint = NULL;
4584  myopt.title = _("List of casts");
4585  myopt.translate_header = true;
4586  myopt.translate_columns = translate_columns;
4587  myopt.n_translate_columns = lengthof(translate_columns);
4588 
4589  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4590 
4591  PQclear(res);
4592  return true;
4593 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ listCollations()

bool listCollations ( const char *  pattern,
bool  verbose,
bool  showSystem 
)

Definition at line 4601 of file describe.c.

4602 {
4604  PGresult *res;
4605  printQueryOpt myopt = pset.popt;
4606  static const bool translate_columns[] = {false, false, false, false, false, true, false};
4607 
4608  initPQExpBuffer(&buf);
4609 
4611  "SELECT n.nspname AS \"%s\",\n"
4612  " c.collname AS \"%s\",\n"
4613  " c.collcollate AS \"%s\",\n"
4614  " c.collctype AS \"%s\"",
4615  gettext_noop("Schema"),
4616  gettext_noop("Name"),
4617  gettext_noop("Collate"),
4618  gettext_noop("Ctype"));
4619 
4620  if (pset.sversion >= 100000)
4622  ",\n CASE c.collprovider WHEN 'd' THEN 'default' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"%s\"",
4623  gettext_noop("Provider"));
4624  else
4626  ",\n 'libc' AS \"%s\"",
4627  gettext_noop("Provider"));
4628 
4629  if (pset.sversion >= 120000)
4631  ",\n CASE WHEN c.collisdeterministic THEN '%s' ELSE '%s' END AS \"%s\"",
4632  gettext_noop("yes"), gettext_noop("no"),
4633  gettext_noop("Deterministic?"));
4634  else
4636  ",\n '%s' AS \"%s\"",
4637  gettext_noop("yes"),
4638  gettext_noop("Deterministic?"));
4639 
4640  if (verbose)
4642  ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
4643  gettext_noop("Description"));
4644 
4646  "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
4647  "WHERE n.oid = c.collnamespace\n");
4648 
4649  if (!showSystem && !pattern)
4650  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4651  " AND n.nspname <> 'information_schema'\n");
4652 
4653  /*
4654  * Hide collations that aren't usable in the current database's encoding.
4655  * If you think to change this, note that pg_collation_is_visible rejects
4656  * unusable collations, so you will need to hack name pattern processing
4657  * somehow to avoid inconsistent behavior.
4658  */
4659  appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
4660 
4661  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4662  "n.nspname", "c.collname", NULL,
4663  "pg_catalog.pg_collation_is_visible(c.oid)");
4664 
4665  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4666 
4667  res = PSQLexec(buf.data);
4668  termPQExpBuffer(&buf);
4669  if (!res)
4670  return false;
4671 
4672  myopt.nullPrint = NULL;
4673  myopt.title = _("List of collations");
4674  myopt.translate_header = true;
4675  myopt.translate_columns = translate_columns;
4676  myopt.n_translate_columns = lengthof(translate_columns);
4677 
4678  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4679 
4680  PQclear(res);
4681  return true;
4682 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ listConversions()

bool listConversions ( const char *  pattern,
bool  verbose,
bool  showSystem 
)

Definition at line 4246 of file describe.c.

4247 {
4249  PGresult *res;
4250  printQueryOpt myopt = pset.popt;
4251  static const bool translate_columns[] =
4252  {false, false, false, false, true, false};
4253 
4254  initPQExpBuffer(&buf);
4255 
4257  "SELECT n.nspname AS \"%s\",\n"
4258  " c.conname AS \"%s\",\n"
4259  " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
4260  " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
4261  " CASE WHEN c.condefault THEN '%s'\n"
4262  " ELSE '%s' END AS \"%s\"",
4263  gettext_noop("Schema"),
4264  gettext_noop("Name"),
4265  gettext_noop("Source"),
4266  gettext_noop("Destination"),
4267  gettext_noop("yes"), gettext_noop("no"),
4268  gettext_noop("Default?"));
4269 
4270  if (verbose)
4272  ",\n d.description AS \"%s\"",
4273  gettext_noop("Description"));
4274 
4276  "\nFROM pg_catalog.pg_conversion c\n"
4277  " JOIN pg_catalog.pg_namespace n "
4278  "ON n.oid = c.connamespace\n");
4279 
4280  if (verbose)
4282  "LEFT JOIN pg_catalog.pg_description d "
4283  "ON d.classoid = c.tableoid\n"
4284  " AND d.objoid = c.oid "
4285  "AND d.objsubid = 0\n");
4286 
4287  appendPQExpBufferStr(&buf, "WHERE true\n");
4288 
4289  if (!showSystem && !pattern)
4290  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4291  " AND n.nspname <> 'information_schema'\n");
4292 
4293  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4294  "n.nspname", "c.conname", NULL,
4295  "pg_catalog.pg_conversion_is_visible(c.oid)");
4296 
4297  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4298 
4299  res = PSQLexec(buf.data);
4300  termPQExpBuffer(&buf);
4301  if (!res)
4302  return false;
4303 
4304  myopt.nullPrint = NULL;
4305  myopt.title = _("List of conversions");
4306  myopt.translate_header = true;
4307  myopt.translate_columns = translate_columns;
4308  myopt.n_translate_columns = lengthof(translate_columns);
4309 
4310  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4311 
4312  PQclear(res);
4313  return true;
4314 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ listDbRoleSettings()

bool listDbRoleSettings ( const char *  pattern,
const char *  pattern2 
)

Definition at line 3633 of file describe.c.

3634 {
3636  PGresult *res;
3637  printQueryOpt myopt = pset.popt;
3638  bool havewhere;
3639 
3640  initPQExpBuffer(&buf);
3641 
3642  printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
3643  "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
3644  "FROM pg_catalog.pg_db_role_setting s\n"
3645  "LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n"
3646  "LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n",
3647  gettext_noop("Role"),
3648  gettext_noop("Database"),
3649  gettext_noop("Settings"));
3650  havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
3651  NULL, "r.rolname", NULL, NULL);
3652  processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
3653  NULL, "d.datname", NULL, NULL);
3654  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3655 
3656  res = PSQLexec(buf.data);
3657  termPQExpBuffer(&buf);
3658  if (!res)
3659  return false;
3660 
3661  /*
3662  * Most functions in this file are content to print an empty table when
3663  * there are no matching objects. We intentionally deviate from that
3664  * here, but only in !quiet mode, because of the possibility that the user
3665  * is confused about what the two pattern arguments mean.
3666  */
3667  if (PQntuples(res) == 0 && !pset.quiet)
3668  {
3669  if (pattern && pattern2)
3670  pg_log_error("Did not find any settings for role \"%s\" and database \"%s\".",
3671  pattern, pattern2);
3672  else if (pattern)
3673  pg_log_error("Did not find any settings for role \"%s\".",
3674  pattern);
3675  else
3676  pg_log_error("Did not find any settings.");
3677  }
3678  else
3679  {
3680  myopt.nullPrint = NULL;
3681  myopt.title = _("List of settings");
3682  myopt.translate_header = true;
3683 
3684  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3685  }
3686 
3687  PQclear(res);
3688  return true;
3689 }

References _, appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, pg_log_error, _psqlSettings::popt, PQclear(), PQntuples(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, _psqlSettings::quiet, res, termPQExpBuffer(), printQueryOpt::title, and printQueryOpt::translate_header.

Referenced by exec_command_d().

◆ listDefaultACLs()

bool listDefaultACLs ( const char *  pattern)

Definition at line 1103 of file describe.c.

1104 {
1106  PGresult *res;
1107  printQueryOpt myopt = pset.popt;
1108  static const bool translate_columns[] = {false, false, true, false};
1109 
1110  initPQExpBuffer(&buf);
1111 
1113  "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
1114  " n.nspname AS \"%s\",\n"
1115  " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
1116  " ",
1117  gettext_noop("Owner"),
1118  gettext_noop("Schema"),
1119  DEFACLOBJ_RELATION,
1120  gettext_noop("table"),
1121  DEFACLOBJ_SEQUENCE,
1122  gettext_noop("sequence"),
1123  DEFACLOBJ_FUNCTION,
1124  gettext_noop("function"),
1125  DEFACLOBJ_TYPE,
1126  gettext_noop("type"),
1127  DEFACLOBJ_NAMESPACE,
1128  gettext_noop("schema"),
1129  gettext_noop("Type"));
1130 
1131  printACLColumn(&buf, "d.defaclacl");
1132 
1133  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
1134  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
1135 
1136  processSQLNamePattern(pset.db, &buf, pattern, false, false,
1137  NULL,
1138  "n.nspname",
1139  "pg_catalog.pg_get_userbyid(d.defaclrole)",
1140  NULL);
1141 
1142  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1143 
1144  res = PSQLexec(buf.data);
1145  if (!res)
1146  {
1147  termPQExpBuffer(&buf);
1148  return false;
1149  }
1150 
1151  myopt.nullPrint = NULL;
1152  printfPQExpBuffer(&buf, _("Default access privileges"));
1153  myopt.title = buf.data;
1154  myopt.translate_header = true;
1155  myopt.translate_columns = translate_columns;
1156  myopt.n_translate_columns = lengthof(translate_columns);
1157 
1158  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1159 
1160  termPQExpBuffer(&buf);
1161  PQclear(res);
1162  return true;
1163 }

References _, appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, and printQueryOpt::translate_header.

Referenced by exec_command_d().

◆ listDomains()

bool listDomains ( const char *  pattern,
bool  verbose,
bool  showSystem 
)

Definition at line 4167 of file describe.c.

4168 {
4170  PGresult *res;
4171  printQueryOpt myopt = pset.popt;
4172 
4173  initPQExpBuffer(&buf);
4174 
4176  "SELECT n.nspname as \"%s\",\n"
4177  " t.typname as \"%s\",\n"
4178  " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
4179  " (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
4180  " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as \"%s\",\n"
4181  " CASE WHEN t.typnotnull THEN 'not null' END as \"%s\",\n"
4182  " t.typdefault as \"%s\",\n"
4183  " pg_catalog.array_to_string(ARRAY(\n"
4184  " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
4185  " ), ' ') as \"%s\"",
4186  gettext_noop("Schema"),
4187  gettext_noop("Name"),
4188  gettext_noop("Type"),
4189  gettext_noop("Collation"),
4190  gettext_noop("Nullable"),
4191  gettext_noop("Default"),
4192  gettext_noop("Check"));
4193 
4194  if (verbose)
4195  {
4196  appendPQExpBufferStr(&buf, ",\n ");
4197  printACLColumn(&buf, "t.typacl");
4199  ",\n d.description as \"%s\"",
4200  gettext_noop("Description"));
4201  }
4202 
4204  "\nFROM pg_catalog.pg_type t\n"
4205  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
4206 
4207  if (verbose)
4209  " LEFT JOIN pg_catalog.pg_description d "
4210  "ON d.classoid = t.tableoid AND d.objoid = t.oid "
4211  "AND d.objsubid = 0\n");
4212 
4213  appendPQExpBufferStr(&buf, "WHERE t.typtype = 'd'\n");
4214 
4215  if (!showSystem && !pattern)
4216  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4217  " AND n.nspname <> 'information_schema'\n");
4218 
4219  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4220  "n.nspname", "t.typname", NULL,
4221  "pg_catalog.pg_type_is_visible(t.oid)");
4222 
4223  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4224 
4225  res = PSQLexec(buf.data);
4226  termPQExpBuffer(&buf);
4227  if (!res)
4228  return false;
4229 
4230  myopt.nullPrint = NULL;
4231  myopt.title = _("List of domains");
4232  myopt.translate_header = true;
4233 
4234  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4235 
4236  PQclear(res);
4237  return true;
4238 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ listEventTriggers()

bool listEventTriggers ( const char *  pattern,
bool  verbose 
)

Definition at line 4322 of file describe.c.

4323 {
4325  PGresult *res;
4326  printQueryOpt myopt = pset.popt;
4327  static const bool translate_columns[] =
4328  {false, false, false, true, false, false, false};
4329 
4330  if (pset.sversion < 90300)
4331  {
4332  char sverbuf[32];
4333 
4334  pg_log_error("The server (version %s) does not support event triggers.",
4336  sverbuf, sizeof(sverbuf)));
4337  return true;
4338  }
4339 
4340  initPQExpBuffer(&buf);
4341 
4343  "SELECT evtname as \"%s\", "
4344  "evtevent as \"%s\", "
4345  "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
4346  " case evtenabled when 'O' then '%s'"
4347  " when 'R' then '%s'"
4348  " when 'A' then '%s'"
4349  " when 'D' then '%s' end as \"%s\",\n"
4350  " e.evtfoid::pg_catalog.regproc as \"%s\", "
4351  "pg_catalog.array_to_string(array(select x"
4352  " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
4353  gettext_noop("Name"),
4354  gettext_noop("Event"),
4355  gettext_noop("Owner"),
4356  gettext_noop("enabled"),
4357  gettext_noop("replica"),
4358  gettext_noop("always"),
4359  gettext_noop("disabled"),
4360  gettext_noop("Enabled"),
4361  gettext_noop("Function"),
4362  gettext_noop("Tags"));
4363  if (verbose)
4365  ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
4366  gettext_noop("Description"));
4368  "\nFROM pg_catalog.pg_event_trigger e ");
4369 
4370  processSQLNamePattern(pset.db, &buf, pattern, false, false,
4371  NULL, "evtname", NULL, NULL);
4372 
4373  appendPQExpBufferStr(&buf, "ORDER BY 1");
4374 
4375  res = PSQLexec(buf.data);
4376  termPQExpBuffer(&buf);
4377  if (!res)
4378  return false;
4379 
4380  myopt.nullPrint = NULL;
4381  myopt.title = _("List of event triggers");
4382  myopt.translate_header = true;
4383  myopt.translate_columns = translate_columns;
4384  myopt.n_translate_columns = lengthof(translate_columns);
4385 
4386  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4387 
4388  PQclear(res);
4389  return true;
4390 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, formatPGVersionNumber(), gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, printQueryOpt::nullPrint, pg_log_error, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ listExtendedStats()

bool listExtendedStats ( const char *  pattern)

Definition at line 4398 of file describe.c.

4399 {
4401  PGresult *res;
4402  printQueryOpt myopt = pset.popt;
4403 
4404  if (pset.sversion < 100000)
4405  {
4406  char sverbuf[32];
4407 
4408  pg_log_error("The server (version %s) does not support extended statistics.",
4410  sverbuf, sizeof(sverbuf)));
4411  return true;
4412  }
4413 
4414  initPQExpBuffer(&buf);
4416  "SELECT \n"
4417  "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS \"%s\", \n"
4418  "es.stxname AS \"%s\", \n",
4419  gettext_noop("Schema"),
4420  gettext_noop("Name"));
4421 
4422  if (pset.sversion >= 140000)
4424  "pg_catalog.format('%%s FROM %%s', \n"
4425  " pg_catalog.pg_get_statisticsobjdef_columns(es.oid), \n"
4426  " es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4427  gettext_noop("Definition"));
4428  else
4430  "pg_catalog.format('%%s FROM %%s', \n"
4431  " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n"
4432  " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n"
4433  " JOIN pg_catalog.pg_attribute a \n"
4434  " ON (es.stxrelid = a.attrelid \n"
4435  " AND a.attnum = s.attnum \n"
4436  " AND NOT a.attisdropped)), \n"
4437  "es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4438  gettext_noop("Definition"));
4439 
4441  ",\nCASE WHEN 'd' = any(es.stxkind) THEN 'defined' \n"
4442  "END AS \"%s\", \n"
4443  "CASE WHEN 'f' = any(es.stxkind) THEN 'defined' \n"
4444  "END AS \"%s\"",
4445  gettext_noop("Ndistinct"),
4446  gettext_noop("Dependencies"));
4447 
4448  /*
4449  * Include the MCV statistics kind.
4450  */
4451  if (pset.sversion >= 120000)
4452  {
4454  ",\nCASE WHEN 'm' = any(es.stxkind) THEN 'defined' \n"
4455  "END AS \"%s\" ",
4456  gettext_noop("MCV"));
4457  }
4458 
4460  " \nFROM pg_catalog.pg_statistic_ext es \n");
4461 
4462  processSQLNamePattern(pset.db, &buf, pattern,
4463  false, false,
4464  "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname",
4465  NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)");
4466 
4467  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4468 
4469  res = PSQLexec(buf.data);
4470  termPQExpBuffer(&buf);
4471  if (!res)
4472  return false;
4473 
4474  myopt.nullPrint = NULL;
4475  myopt.title = _("List of extended statistics");
4476  myopt.translate_header = true;
4477 
4478  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4479 
4480  PQclear(res);
4481  return true;
4482 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, formatPGVersionNumber(), gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, pg_log_error, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, and printQueryOpt::translate_header.

Referenced by exec_command_d().

◆ listExtensionContents()

bool listExtensionContents ( const char *  pattern)

Definition at line 5672 of file describe.c.

5673 {
5675  PGresult *res;
5676  int i;
5677 
5678  initPQExpBuffer(&buf);
5680  "SELECT e.extname, e.oid\n"
5681  "FROM pg_catalog.pg_extension e\n");
5682 
5683  processSQLNamePattern(pset.db, &buf, pattern,
5684  false, false,
5685  NULL, "e.extname", NULL,
5686  NULL);
5687 
5688  appendPQExpBufferStr(&buf, "ORDER BY 1;");
5689 
5690  res = PSQLexec(buf.data);
5691  termPQExpBuffer(&buf);
5692  if (!res)
5693  return false;
5694 
5695  if (PQntuples(res) == 0)
5696  {
5697  if (!pset.quiet)
5698  {
5699  if (pattern)
5700  pg_log_error("Did not find any extension named \"%s\".",
5701  pattern);
5702  else
5703  pg_log_error("Did not find any extensions.");
5704  }
5705  PQclear(res);
5706  return false;
5707  }
5708 
5709  for (i = 0; i < PQntuples(res); i++)
5710  {
5711  const char *extname;
5712  const char *oid;
5713 
5714  extname = PQgetvalue(res, i, 0);
5715  oid = PQgetvalue(res, i, 1);
5716 
5717  if (!listOneExtensionContents(extname, oid))
5718  {
5719  PQclear(res);
5720  return false;
5721  }
5722  if (cancel_pressed)
5723  {
5724  PQclear(res);
5725  return false;
5726  }
5727  }
5728 
5729  PQclear(res);
5730  return true;
5731 }
static bool listOneExtensionContents(const char *extname, const char *oid)
Definition: describe.c:5734

References appendPQExpBufferStr(), buf, cancel_pressed, _psqlSettings::db, i, initPQExpBuffer(), listOneExtensionContents(), pg_log_error, PQclear(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::quiet, res, and termPQExpBuffer().

Referenced by exec_command_d().

◆ listExtensions()

bool listExtensions ( const char *  pattern)

Definition at line 5625 of file describe.c.

5626 {
5628  PGresult *res;
5629  printQueryOpt myopt = pset.popt;
5630 
5631  initPQExpBuffer(&buf);
5633  "SELECT e.extname AS \"%s\", "
5634  "e.extversion AS \"%s\", n.nspname AS \"%s\", c.description AS \"%s\"\n"
5635  "FROM pg_catalog.pg_extension e "
5636  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
5637  "LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
5638  "AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass\n",
5639  gettext_noop("Name"),
5640  gettext_noop("Version"),
5641  gettext_noop("Schema"),
5642  gettext_noop("Description"));
5643 
5644  processSQLNamePattern(pset.db, &buf, pattern,
5645  false, false,
5646  NULL, "e.extname", NULL,
5647  NULL);
5648 
5649  appendPQExpBufferStr(&buf, "ORDER BY 1;");
5650 
5651  res = PSQLexec(buf.data);
5652  termPQExpBuffer(&buf);
5653  if (!res)
5654  return false;
5655 
5656  myopt.nullPrint = NULL;
5657  myopt.title = _("List of installed extensions");
5658  myopt.translate_header = true;
5659 
5660  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5661 
5662  PQclear(res);
5663  return true;
5664 }

References _, appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, and printQueryOpt::translate_header.

Referenced by exec_command_d().

◆ listForeignDataWrappers()

bool listForeignDataWrappers ( const char *  pattern,
bool  verbose 
)

Definition at line 5367 of file describe.c.

5368 {
5370  PGresult *res;
5371  printQueryOpt myopt = pset.popt;
5372 
5373  initPQExpBuffer(&buf);
5375  "SELECT fdw.fdwname AS \"%s\",\n"
5376  " pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n"
5377  " fdw.fdwhandler::pg_catalog.regproc AS \"%s\",\n"
5378  " fdw.fdwvalidator::pg_catalog.regproc AS \"%s\"",
5379  gettext_noop("Name"),
5380  gettext_noop("Owner"),
5381  gettext_noop("Handler"),
5382  gettext_noop("Validator"));
5383 
5384  if (verbose)
5385  {
5386  appendPQExpBufferStr(&buf, ",\n ");
5387  printACLColumn(&buf, "fdwacl");
5389  ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
5390  " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5391  " pg_catalog.quote_ident(option_name) || ' ' || "
5392  " pg_catalog.quote_literal(option_value) FROM "
5393  " pg_catalog.pg_options_to_table(fdwoptions)), ', ') || ')' "
5394  " END AS \"%s\""
5395  ",\n d.description AS \"%s\" ",
5396  gettext_noop("FDW options"),
5397  gettext_noop("Description"));
5398  }
5399 
5400  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
5401 
5402  if (verbose)
5404  "LEFT JOIN pg_catalog.pg_description d\n"
5405  " ON d.classoid = fdw.tableoid "
5406  "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
5407 
5408  processSQLNamePattern(pset.db, &buf, pattern, false, false,
5409  NULL, "fdwname", NULL, NULL);
5410 
5411  appendPQExpBufferStr(&buf, "ORDER BY 1;");
5412 
5413  res = PSQLexec(buf.data);
5414  termPQExpBuffer(&buf);
5415  if (!res)
5416  return false;
5417 
5418  myopt.nullPrint = NULL;
5419  myopt.title = _("List of foreign-data wrappers");
5420  myopt.translate_header = true;
5421 
5422  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5423 
5424  PQclear(res);
5425  return true;
5426 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ listForeignServers()

bool listForeignServers ( const char *  pattern,
bool  verbose 
)

Definition at line 5434 of file describe.c.

5435 {
5437  PGresult *res;
5438  printQueryOpt myopt = pset.popt;
5439 
5440  initPQExpBuffer(&buf);
5442  "SELECT s.srvname AS \"%s\",\n"
5443  " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
5444  " f.fdwname AS \"%s\"",
5445  gettext_noop("Name"),
5446  gettext_noop("Owner"),
5447  gettext_noop("Foreign-data wrapper"));
5448 
5449  if (verbose)
5450  {
5451  appendPQExpBufferStr(&buf, ",\n ");
5452  printACLColumn(&buf, "s.srvacl");
5454  ",\n"
5455  " s.srvtype AS \"%s\",\n"
5456  " s.srvversion AS \"%s\",\n"
5457  " CASE WHEN srvoptions IS NULL THEN '' ELSE "
5458  " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5459  " pg_catalog.quote_ident(option_name) || ' ' || "
5460  " pg_catalog.quote_literal(option_value) FROM "
5461  " pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')' "
5462  " END AS \"%s\",\n"
5463  " d.description AS \"%s\"",
5464  gettext_noop("Type"),
5465  gettext_noop("Version"),
5466  gettext_noop("FDW options"),
5467  gettext_noop("Description"));
5468  }
5469 
5471  "\nFROM pg_catalog.pg_foreign_server s\n"
5472  " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
5473 
5474  if (verbose)
5476  "LEFT JOIN pg_catalog.pg_description d\n "
5477  "ON d.classoid = s.tableoid AND d.objoid = s.oid "
5478  "AND d.objsubid = 0\n");
5479 
5480  processSQLNamePattern(pset.db, &buf, pattern, false, false,
5481  NULL, "s.srvname", NULL, NULL);
5482 
5483  appendPQExpBufferStr(&buf, "ORDER BY 1;");
5484 
5485  res = PSQLexec(buf.data);
5486  termPQExpBuffer(&buf);
5487  if (!res)
5488  return false;
5489 
5490  myopt.nullPrint = NULL;
5491  myopt.title = _("List of foreign servers");
5492  myopt.translate_header = true;
5493 
5494  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5495 
5496  PQclear(res);
5497  return true;
5498 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, _psqlSettings::db, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, printQueryOpt::nullPrint, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), processSQLNamePattern(), pset, PSQLexec(), _psqlSettings::queryFout, res, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_header, and verbose.

Referenced by exec_command_d().

◆ listForeignTables()

bool listForeignTables ( const char *  pattern,
bool  verbose 
)

Definition at line 5557 of file describe.c.

5558 {
5560  PGresult *res;
5561  printQueryOpt myopt = pset.popt;
5562 
5563  initPQExpBuffer(&buf);
5565  "SELECT n.nspname AS \"%s\",\n"
5566  " c.relname AS \"%s\",\n"
5567  " s.srvname AS \"%s\"",
5568  gettext_noop("Schema"),
5569  gettext_noop("Table"),