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)
 
static bool validateSQLNamePattern (PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule, bool *added_clause, int maxparts)
 
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 showSystem)
 
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 describeRoleGrants (const char *pattern, bool showSystem)
 
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 describeConfigurationParameters (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, const char *footermsg, bool as_schema, printTableContent *const 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 3801 of file describe.c.

3802 {
3803  if (buf->len > 0)
3804  appendPQExpBufferStr(buf, ", ");
3805 
3807 }
static char * buf
Definition: pg_test_fsync.c:73
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367

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 3601 of file describe.c.

3603 {
3604  /* relkinds for which we support tablespaces */
3605  if (relkind == RELKIND_RELATION ||
3606  relkind == RELKIND_MATVIEW ||
3607  relkind == RELKIND_INDEX ||
3608  relkind == RELKIND_PARTITIONED_TABLE ||
3609  relkind == RELKIND_PARTITIONED_INDEX ||
3610  relkind == RELKIND_TOASTVALUE)
3611  {
3612  /*
3613  * We ignore the database default tablespace so that users not using
3614  * tablespaces don't need to know about them.
3615  */
3616  if (tablespace != 0)
3617  {
3618  PGresult *result = NULL;
3620 
3621  initPQExpBuffer(&buf);
3623  "SELECT spcname FROM pg_catalog.pg_tablespace\n"
3624  "WHERE oid = '%u';", tablespace);
3625  result = PSQLexec(buf.data);
3626  if (!result)
3627  {
3628  termPQExpBuffer(&buf);
3629  return;
3630  }
3631  /* Should always be the case, but.... */
3632  if (PQntuples(result) > 0)
3633  {
3634  if (newline)
3635  {
3636  /* Add the tablespace as a new footer */
3637  printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
3638  PQgetvalue(result, 0, 0));
3639  printTableAddFooter(cont, buf.data);
3640  }
3641  else
3642  {
3643  /* Append the tablespace to the latest footer */
3644  printfPQExpBuffer(&buf, "%s", cont->footer->data);
3645 
3646  /*-------
3647  translator: before this string there's an index description like
3648  '"foo_pkey" PRIMARY KEY, btree (a)' */
3649  appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
3650  PQgetvalue(result, 0, 0));
3651  printTableSetFooter(cont, buf.data);
3652  }
3653  }
3654  PQclear(result);
3655  termPQExpBuffer(&buf);
3656  }
3657  }
3658 }
PGresult * PSQLexec(const char *query)
Definition: common.c:581
#define _(x)
Definition: elog.c:90
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3441
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3836
void printTableSetFooter(printTableContent *const content, const char *footer)
Definition: print.c:3335
void printTableAddFooter(printTableContent *const content, const char *footer)
Definition: print.c:3310
#define newline
Definition: indent_codes.h:35
char * tablespace
Definition: pgbench.c:216
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
printTableFooter * footer
Definition: print.h:177
char * data
Definition: print.h:155

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,
const char *  footermsg,
bool  as_schema,
printTableContent *const  cont 
)
static

Definition at line 6345 of file describe.c.

6347 {
6348  PGresult *res;
6349  int count = 0;
6350  int i = 0;
6351 
6352  res = PSQLexec(buf->data);
6353  if (!res)
6354  return false;
6355  else
6356  count = PQntuples(res);
6357 
6358  if (count > 0)
6359  printTableAddFooter(cont, footermsg);
6360 
6361  for (i = 0; i < count; i++)
6362  {
6363  if (as_schema)
6364  printfPQExpBuffer(buf, " \"%s\"", PQgetvalue(res, i, 0));
6365  else
6366  {
6367  printfPQExpBuffer(buf, " \"%s.%s\"", PQgetvalue(res, i, 0),
6368  PQgetvalue(res, i, 1));
6369 
6370  if (!PQgetisnull(res, i, 3))
6371  appendPQExpBuffer(buf, " (%s)", PQgetvalue(res, i, 3));
6372 
6373  if (!PQgetisnull(res, i, 2))
6374  appendPQExpBuffer(buf, " WHERE %s", PQgetvalue(res, i, 2));
6375  }
6376 
6377  printTableAddFooter(cont, buf->data);
6378  }
6379 
6380  PQclear(res);
6381  return true;
6382 }
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3861
int i
Definition: isn.c:73

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

Referenced by describePublications().

◆ describeAccessMethods()

bool describeAccessMethods ( const char *  pattern,
bool  verbose 
)

Definition at line 141 of file describe.c.

142 {
144  PGresult *res;
145  printQueryOpt myopt = pset.popt;
146  static const bool translate_columns[] = {false, true, false, false};
147 
148  if (pset.sversion < 90600)
149  {
150  char sverbuf[32];
151 
152  pg_log_error("The server (version %s) does not support access methods.",
154  sverbuf, sizeof(sverbuf)));
155  return true;
156  }
157 
159 
161  "SELECT amname AS \"%s\",\n"
162  " CASE amtype"
163  " WHEN 'i' THEN '%s'"
164  " WHEN 't' THEN '%s'"
165  " END AS \"%s\"",
166  gettext_noop("Name"),
167  gettext_noop("Index"),
168  gettext_noop("Table"),
169  gettext_noop("Type"));
170 
171  if (verbose)
172  {
174  ",\n amhandler AS \"%s\",\n"
175  " pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
176  gettext_noop("Handler"),
177  gettext_noop("Description"));
178  }
179 
181  "\nFROM pg_catalog.pg_am\n");
182 
183  if (!validateSQLNamePattern(&buf, pattern, false, false,
184  NULL, "amname", NULL,
185  NULL,
186  NULL, 1))
187  {
189  return false;
190  }
191 
192  appendPQExpBufferStr(&buf, "ORDER BY 1;");
193 
194  res = PSQLexec(buf.data);
196  if (!res)
197  return false;
198 
199  myopt.title = _("List of access methods");
200  myopt.translate_header = true;
201  myopt.translate_columns = translate_columns;
202  myopt.n_translate_columns = lengthof(translate_columns);
203 
204  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
205 
206  PQclear(res);
207  return true;
208 }
#define gettext_noop(x)
Definition: c.h:1183
#define lengthof(array)
Definition: c.h:775
static bool validateSQLNamePattern(PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule, bool *added_clause, int maxparts)
Definition: describe.c:6216
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3549
int verbose
#define pg_log_error(...)
Definition: logging.h:106
PsqlSettings pset
Definition: startup.c:32
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:120
FILE * queryFout
Definition: settings.h:84
const bool * translate_columns
Definition: print.h:190
char * title
Definition: print.h:187
bool translate_header
Definition: print.h:189
int n_translate_columns
Definition: print.h:192

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

Referenced by exec_command_d().

◆ describeAggregates()

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

Definition at line 71 of file describe.c.

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

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

Referenced by exec_command_d().

◆ describeConfigurationParameters()

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

Definition at line 4598 of file describe.c.

4600 {
4602  PGresult *res;
4603  printQueryOpt myopt = pset.popt;
4604 
4605  initPQExpBuffer(&buf);
4607  "SELECT s.name AS \"%s\", "
4608  "pg_catalog.current_setting(s.name) AS \"%s\"",
4609  gettext_noop("Parameter"),
4610  gettext_noop("Value"));
4611 
4612  if (verbose)
4613  {
4615  ", s.vartype AS \"%s\", s.context AS \"%s\", ",
4616  gettext_noop("Type"),
4617  gettext_noop("Context"));
4618  if (pset.sversion >= 150000)
4619  printACLColumn(&buf, "p.paracl");
4620  else
4621  appendPQExpBuffer(&buf, "NULL AS \"%s\"",
4622  gettext_noop("Access privileges"));
4623  }
4624 
4625  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_settings s\n");
4626 
4627  if (verbose && pset.sversion >= 150000)
4629  " LEFT JOIN pg_catalog.pg_parameter_acl p\n"
4630  " ON pg_catalog.lower(s.name) = p.parname\n");
4631 
4632  if (pattern)
4633  processSQLNamePattern(pset.db, &buf, pattern,
4634  false, false,
4635  NULL, "pg_catalog.lower(s.name)", NULL,
4636  NULL, NULL, NULL);
4637  else
4638  appendPQExpBufferStr(&buf, "WHERE s.source <> 'default' AND\n"
4639  " s.setting IS DISTINCT FROM s.boot_val\n");
4640 
4641  appendPQExpBufferStr(&buf, "ORDER BY 1;");
4642 
4643  res = PSQLexec(buf.data);
4644  termPQExpBuffer(&buf);
4645  if (!res)
4646  return false;
4647 
4648  if (pattern)
4649  myopt.title = _("List of configuration parameters");
4650  else
4651  myopt.title = _("List of non-default configuration parameters");
4652  myopt.translate_header = true;
4653 
4654  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4655 
4656  PQclear(res);
4657  return true;
4658 }
static void printACLColumn(PQExpBuffer buf, const char *colname)
Definition: describe.c:6711
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, PQExpBuffer dbnamebuf, int *dotcnt)
Definition: string_utils.c:891
PGconn * db
Definition: settings.h:82

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

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 288 of file describe.c.

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

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, formatPGVersionNumber(), gettext_noop, i, initPQExpBuffer(), lengthof, _psqlSettings::logfile, map_typename_pattern(), printQueryOpt::n_translate_columns, pg_log_error, _psqlSettings::popt, PQclear(), printACLColumn(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, res, snprintf, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, typname, validateSQLNamePattern(), 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 1528 of file describe.c.

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

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(), storage, _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 5709 of file describe.c.

5711 {
5713  title;
5714  PGresult *res;
5715  printQueryOpt myopt = pset.popt;
5716 
5717  initPQExpBuffer(&buf);
5718 
5720  "SELECT\n"
5721  " ( SELECT t.alias FROM\n"
5722  " pg_catalog.ts_token_type(c.cfgparser) AS t\n"
5723  " WHERE t.tokid = m.maptokentype ) AS \"%s\",\n"
5724  " pg_catalog.btrim(\n"
5725  " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary\n"
5726  " FROM pg_catalog.pg_ts_config_map AS mm\n"
5727  " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype\n"
5728  " ORDER BY mapcfg, maptokentype, mapseqno\n"
5729  " ) :: pg_catalog.text,\n"
5730  " '{}') AS \"%s\"\n"
5731  "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m\n"
5732  "WHERE c.oid = '%s' AND m.mapcfg = c.oid\n"
5733  "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser\n"
5734  "ORDER BY 1;",
5735  gettext_noop("Token"),
5736  gettext_noop("Dictionaries"),
5737  oid);
5738 
5739  res = PSQLexec(buf.data);
5740  termPQExpBuffer(&buf);
5741  if (!res)
5742  return false;
5743 
5744  initPQExpBuffer(&title);
5745 
5746  if (nspname)
5747  appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
5748  nspname, cfgname);
5749  else
5750  appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
5751  cfgname);
5752 
5753  if (pnspname)
5754  appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
5755  pnspname, prsname);
5756  else
5757  appendPQExpBuffer(&title, _("\nParser: \"%s\""),
5758  prsname);
5759 
5760  myopt.title = title.data;
5761  myopt.footers = NULL;
5762  myopt.topt.default_footer = false;
5763  myopt.translate_header = true;
5764 
5765  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5766 
5767  termPQExpBuffer(&title);
5768 
5769  PQclear(res);
5770  return true;
5771 }

References _, appendPQExpBuffer(), buf, PQExpBufferData::data, printTableOpt::default_footer, printQueryOpt::footers, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, _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 5326 of file describe.c.

5327 {
5329  PGresult *res;
5330  PQExpBufferData title;
5331  printQueryOpt myopt = pset.popt;
5332  static const bool translate_columns[] = {true, false, false};
5333 
5334  initPQExpBuffer(&buf);
5335 
5337  "SELECT '%s' AS \"%s\",\n"
5338  " p.prsstart::pg_catalog.regproc AS \"%s\",\n"
5339  " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\"\n"
5340  " FROM pg_catalog.pg_ts_parser p\n"
5341  " WHERE p.oid = '%s'\n"
5342  "UNION ALL\n"
5343  "SELECT '%s',\n"
5344  " p.prstoken::pg_catalog.regproc,\n"
5345  " pg_catalog.obj_description(p.prstoken, 'pg_proc')\n"
5346  " FROM pg_catalog.pg_ts_parser p\n"
5347  " WHERE p.oid = '%s'\n"
5348  "UNION ALL\n"
5349  "SELECT '%s',\n"
5350  " p.prsend::pg_catalog.regproc,\n"
5351  " pg_catalog.obj_description(p.prsend, 'pg_proc')\n"
5352  " FROM pg_catalog.pg_ts_parser p\n"
5353  " WHERE p.oid = '%s'\n"
5354  "UNION ALL\n"
5355  "SELECT '%s',\n"
5356  " p.prsheadline::pg_catalog.regproc,\n"
5357  " pg_catalog.obj_description(p.prsheadline, 'pg_proc')\n"
5358  " FROM pg_catalog.pg_ts_parser p\n"
5359  " WHERE p.oid = '%s'\n"
5360  "UNION ALL\n"
5361  "SELECT '%s',\n"
5362  " p.prslextype::pg_catalog.regproc,\n"
5363  " pg_catalog.obj_description(p.prslextype, 'pg_proc')\n"
5364  " FROM pg_catalog.pg_ts_parser p\n"
5365  " WHERE p.oid = '%s';",
5366  gettext_noop("Start parse"),
5367  gettext_noop("Method"),
5368  gettext_noop("Function"),
5369  gettext_noop("Description"),
5370  oid,
5371  gettext_noop("Get next token"),
5372  oid,
5373  gettext_noop("End parse"),
5374  oid,
5375  gettext_noop("Get headline"),
5376  oid,
5377  gettext_noop("Get token types"),
5378  oid);
5379 
5380  res = PSQLexec(buf.data);
5381  termPQExpBuffer(&buf);
5382  if (!res)
5383  return false;
5384 
5385  initPQExpBuffer(&title);
5386  if (nspname)
5387  printfPQExpBuffer(&title, _("Text search parser \"%s.%s\""),
5388  nspname, prsname);
5389  else
5390  printfPQExpBuffer(&title, _("Text search parser \"%s\""), prsname);
5391  myopt.title = title.data;
5392  myopt.footers = NULL;
5393  myopt.topt.default_footer = false;
5394  myopt.translate_header = true;
5395  myopt.translate_columns = translate_columns;
5396  myopt.n_translate_columns = lengthof(translate_columns);
5397 
5398  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5399 
5400  PQclear(res);
5401 
5402  initPQExpBuffer(&buf);
5403 
5405  "SELECT t.alias as \"%s\",\n"
5406  " t.description as \"%s\"\n"
5407  "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t\n"
5408  "ORDER BY 1;",
5409  gettext_noop("Token name"),
5410  gettext_noop("Description"),
5411  oid);
5412 
5413  res = PSQLexec(buf.data);
5414  termPQExpBuffer(&buf);
5415  if (!res)
5416  {
5417  termPQExpBuffer(&title);
5418  return false;
5419  }
5420 
5421  if (nspname)
5422  printfPQExpBuffer(&title, _("Token types for parser \"%s.%s\""),
5423  nspname, prsname);
5424  else
5425  printfPQExpBuffer(&title, _("Token types for parser \"%s\""), prsname);
5426  myopt.title = title.data;
5427  myopt.footers = NULL;
5428  myopt.topt.default_footer = true;
5429  myopt.translate_header = true;
5430  myopt.translate_columns = NULL;
5431  myopt.n_translate_columns = 0;
5432 
5433  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5434 
5435  termPQExpBuffer(&title);
5436  PQclear(res);
5437  return true;
5438 }

References _, buf, PQExpBufferData::data, printTableOpt::default_footer, printQueryOpt::footers, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, _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 770 of file describe.c.

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

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

Referenced by exec_command_dfo().

◆ describePublications()

bool describePublications ( const char *  pattern)

Definition at line 6391 of file describe.c.

6392 {
6394  int i;
6395  PGresult *res;
6396  bool has_pubtruncate;
6397  bool has_pubviaroot;
6398 
6399  PQExpBufferData title;
6400  printTableContent cont;
6401 
6402  if (pset.sversion < 100000)
6403  {
6404  char sverbuf[32];
6405 
6406  pg_log_error("The server (version %s) does not support publications.",
6408  sverbuf, sizeof(sverbuf)));
6409  return true;
6410  }
6411 
6412  has_pubtruncate = (pset.sversion >= 110000);
6413  has_pubviaroot = (pset.sversion >= 130000);
6414 
6415  initPQExpBuffer(&buf);
6416 
6418  "SELECT oid, pubname,\n"
6419  " pg_catalog.pg_get_userbyid(pubowner) AS owner,\n"
6420  " puballtables, pubinsert, pubupdate, pubdelete");
6421  if (has_pubtruncate)
6423  ", pubtruncate");
6424  if (has_pubviaroot)
6426  ", pubviaroot");
6428  "\nFROM pg_catalog.pg_publication\n");
6429 
6430  if (!validateSQLNamePattern(&buf, pattern, false, false,
6431  NULL, "pubname", NULL,
6432  NULL,
6433  NULL, 1))
6434  {
6435  termPQExpBuffer(&buf);
6436  return false;
6437  }
6438 
6439  appendPQExpBufferStr(&buf, "ORDER BY 2;");
6440 
6441  res = PSQLexec(buf.data);
6442  if (!res)
6443  {
6444  termPQExpBuffer(&buf);
6445  return false;
6446  }
6447 
6448  if (PQntuples(res) == 0)
6449  {
6450  if (!pset.quiet)
6451  {
6452  if (pattern)
6453  pg_log_error("Did not find any publication named \"%s\".",
6454  pattern);
6455  else
6456  pg_log_error("Did not find any publications.");
6457  }
6458 
6459  termPQExpBuffer(&buf);
6460  PQclear(res);
6461  return false;
6462  }
6463 
6464  for (i = 0; i < PQntuples(res); i++)
6465  {
6466  const char align = 'l';
6467  int ncols = 5;
6468  int nrows = 1;
6469  char *pubid = PQgetvalue(res, i, 0);
6470  char *pubname = PQgetvalue(res, i, 1);
6471  bool puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
6472  printTableOpt myopt = pset.popt.topt;
6473 
6474  if (has_pubtruncate)
6475  ncols++;
6476  if (has_pubviaroot)
6477  ncols++;
6478 
6479  initPQExpBuffer(&title);
6480  printfPQExpBuffer(&title, _("Publication %s"), pubname);
6481  printTableInit(&cont, &myopt, title.data, ncols, nrows);
6482 
6483  printTableAddHeader(&cont, gettext_noop("Owner"), true, align);
6484  printTableAddHeader(&cont, gettext_noop("All tables"), true, align);
6485  printTableAddHeader(&cont, gettext_noop("Inserts"), true, align);
6486  printTableAddHeader(&cont, gettext_noop("Updates"), true, align);
6487  printTableAddHeader(&cont, gettext_noop("Deletes"), true, align);
6488  if (has_pubtruncate)
6489  printTableAddHeader(&cont, gettext_noop("Truncates"), true, align);
6490  if (has_pubviaroot)
6491  printTableAddHeader(&cont, gettext_noop("Via root"), true, align);
6492 
6493  printTableAddCell(&cont, PQgetvalue(res, i, 2), false, false);
6494  printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false);
6495  printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false);
6496  printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
6497  printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
6498  if (has_pubtruncate)
6499  printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
6500  if (has_pubviaroot)
6501  printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
6502 
6503  if (!puballtables)
6504  {
6505  /* Get the tables for the specified publication */
6507  "SELECT n.nspname, c.relname");
6508  if (pset.sversion >= 150000)
6509  {
6511  ", pg_get_expr(pr.prqual, c.oid)");
6513  ", (CASE WHEN pr.prattrs IS NOT NULL THEN\n"
6514  " pg_catalog.array_to_string("
6515  " ARRAY(SELECT attname\n"
6516  " FROM\n"
6517  " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
6518  " pg_catalog.pg_attribute\n"
6519  " WHERE attrelid = c.oid AND attnum = prattrs[s]), ', ')\n"
6520  " ELSE NULL END)");
6521  }
6522  else
6524  ", NULL, NULL");
6526  "\nFROM pg_catalog.pg_class c,\n"
6527  " pg_catalog.pg_namespace n,\n"
6528  " pg_catalog.pg_publication_rel pr\n"
6529  "WHERE c.relnamespace = n.oid\n"
6530  " AND c.oid = pr.prrelid\n"
6531  " AND pr.prpubid = '%s'\n"
6532  "ORDER BY 1,2", pubid);
6533  if (!addFooterToPublicationDesc(&buf, _("Tables:"), false, &cont))
6534  goto error_return;
6535 
6536  if (pset.sversion >= 150000)
6537  {
6538  /* Get the schemas for the specified publication */
6540  "SELECT n.nspname\n"
6541  "FROM pg_catalog.pg_namespace n\n"
6542  " JOIN pg_catalog.pg_publication_namespace pn ON n.oid = pn.pnnspid\n"
6543  "WHERE pn.pnpubid = '%s'\n"
6544  "ORDER BY 1", pubid);
6545  if (!addFooterToPublicationDesc(&buf, _("Tables from schemas:"),
6546  true, &cont))
6547  goto error_return;
6548  }
6549  }
6550 
6551  printTable(&cont, pset.queryFout, false, pset.logfile);
6552  printTableCleanup(&cont);
6553 
6554  termPQExpBuffer(&title);
6555  }
6556 
6557  termPQExpBuffer(&buf);
6558  PQclear(res);
6559 
6560  return true;
6561 
6562 error_return:
6563  printTableCleanup(&cont);
6564  PQclear(res);
6565  termPQExpBuffer(&buf);
6566  termPQExpBuffer(&title);
6567  return false;
6568 }
static bool addFooterToPublicationDesc(PQExpBuffer buf, const char *footermsg, bool as_schema, printTableContent *const cont)
Definition: describe.c:6345

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

Referenced by exec_command_d().

◆ describeRoleGrants()

bool describeRoleGrants ( const char *  pattern,
bool  showSystem 
)

Definition at line 3882 of file describe.c.

3883 {
3885  PGresult *res;
3886  printQueryOpt myopt = pset.popt;
3887 
3888  initPQExpBuffer(&buf);
3890  "SELECT m.rolname AS \"%s\", r.rolname AS \"%s\",\n"
3891  " pg_catalog.concat_ws(', ',\n",
3892  gettext_noop("Role name"),
3893  gettext_noop("Member of"));
3894 
3895  if (pset.sversion >= 160000)
3897  " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
3898  " CASE WHEN pam.inherit_option THEN 'INHERIT' END,\n"
3899  " CASE WHEN pam.set_option THEN 'SET' END\n");
3900  else
3902  " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
3903  " CASE WHEN m.rolinherit THEN 'INHERIT' END,\n"
3904  " 'SET'\n");
3905 
3907  " ) AS \"%s\",\n"
3908  " g.rolname AS \"%s\"\n",
3909  gettext_noop("Options"),
3910  gettext_noop("Grantor"));
3911 
3913  "FROM pg_catalog.pg_roles m\n"
3914  " JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)\n"
3915  " LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)\n"
3916  " LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)\n");
3917 
3918  if (!showSystem && !pattern)
3919  appendPQExpBufferStr(&buf, "WHERE m.rolname !~ '^pg_'\n");
3920 
3921  if (!validateSQLNamePattern(&buf, pattern, false, false,
3922  NULL, "m.rolname", NULL, NULL,
3923  NULL, 1))
3924  {
3925  termPQExpBuffer(&buf);
3926  return false;
3927  }
3928 
3929  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;\n");
3930 
3931  res = PSQLexec(buf.data);
3932  termPQExpBuffer(&buf);
3933  if (!res)
3934  return false;
3935 
3936  myopt.title = _("List of role grants");
3937  myopt.translate_header = true;
3938 
3939  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3940 
3941  PQclear(res);
3942  return true;
3943 }

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

Referenced by exec_command_d().

◆ describeRoles()

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

Definition at line 3666 of file describe.c.

3667 {
3669  PGresult *res;
3670  printTableContent cont;
3671  printTableOpt myopt = pset.popt.topt;
3672  int ncols = 2;
3673  int nrows = 0;
3674  int i;
3675  int conns;
3676  const char align = 'l';
3677  char **attr;
3678 
3679  myopt.default_footer = false;
3680 
3681  initPQExpBuffer(&buf);
3682 
3684  "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
3685  " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
3686  " r.rolconnlimit, r.rolvaliduntil");
3687 
3688  if (verbose)
3689  {
3690  appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
3691  ncols++;
3692  }
3693  appendPQExpBufferStr(&buf, "\n, r.rolreplication");
3694 
3695  if (pset.sversion >= 90500)
3696  {
3697  appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
3698  }
3699 
3700  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
3701 
3702  if (!showSystem && !pattern)
3703  appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
3704 
3705  if (!validateSQLNamePattern(&buf, pattern, false, false,
3706  NULL, "r.rolname", NULL, NULL,
3707  NULL, 1))
3708  {
3709  termPQExpBuffer(&buf);
3710  return false;
3711  }
3712 
3713  appendPQExpBufferStr(&buf, "ORDER BY 1;");
3714 
3715  res = PSQLexec(buf.data);
3716  if (!res)
3717  return false;
3718 
3719  nrows = PQntuples(res);
3720  attr = pg_malloc0((nrows + 1) * sizeof(*attr));
3721 
3722  printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
3723 
3724  printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
3725  printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
3726 
3727  if (verbose)
3728  printTableAddHeader(&cont, gettext_noop("Description"), true, align);
3729 
3730  for (i = 0; i < nrows; i++)
3731  {
3732  printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
3733 
3735  if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
3736  add_role_attribute(&buf, _("Superuser"));
3737 
3738  if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
3739  add_role_attribute(&buf, _("No inheritance"));
3740 
3741  if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
3742  add_role_attribute(&buf, _("Create role"));
3743 
3744  if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
3745  add_role_attribute(&buf, _("Create DB"));
3746 
3747  if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
3748  add_role_attribute(&buf, _("Cannot login"));
3749 
3750  if (strcmp(PQgetvalue(res, i, (verbose ? 9 : 8)), "t") == 0)
3751  add_role_attribute(&buf, _("Replication"));
3752 
3753  if (pset.sversion >= 90500)
3754  if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
3755  add_role_attribute(&buf, _("Bypass RLS"));
3756 
3757  conns = atoi(PQgetvalue(res, i, 6));
3758  if (conns >= 0)
3759  {
3760  if (buf.len > 0)
3761  appendPQExpBufferChar(&buf, '\n');
3762 
3763  if (conns == 0)
3764  appendPQExpBufferStr(&buf, _("No connections"));
3765  else
3766  appendPQExpBuffer(&buf, ngettext("%d connection",
3767  "%d connections",
3768  conns),
3769  conns);
3770  }
3771 
3772  if (strcmp(PQgetvalue(res, i, 7), "") != 0)
3773  {
3774  if (buf.len > 0)
3775  appendPQExpBufferChar(&buf, '\n');
3776  appendPQExpBufferStr(&buf, _("Password valid until "));
3778  }
3779 
3780  attr[i] = pg_strdup(buf.data);
3781 
3782  printTableAddCell(&cont, attr[i], false, false);
3783 
3784  if (verbose)
3785  printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
3786  }
3787  termPQExpBuffer(&buf);
3788 
3789  printTable(&cont, pset.queryFout, false, pset.logfile);
3790  printTableCleanup(&cont);
3791 
3792  for (i = 0; i < nrows; i++)
3793  free(attr[i]);
3794  free(attr);
3795 
3796  PQclear(res);
3797  return true;
3798 }
#define ngettext(s, p, n)
Definition: c.h:1168
static void add_role_attribute(PQExpBuffer buf, const char *const str)
Definition: describe.c:3801
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
static IsoConnInfo * conns

References _, add_role_attribute(), appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), buf, conns, 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(), pset, PSQLexec(), _psqlSettings::queryFout, res, resetPQExpBuffer(), _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::topt, validateSQLNamePattern(), and verbose.

Referenced by exec_command_d().

◆ describeSubscriptions()

bool describeSubscriptions ( const char *  pattern,
bool  verbose 
)

Definition at line 6577 of file describe.c.

6578 {
6580  PGresult *res;
6581  printQueryOpt myopt = pset.popt;
6582  static const bool translate_columns[] = {false, false, false, false,
6583  false, false, false, false, false, false, false, false, false, false,
6584  false};
6585 
6586  if (pset.sversion < 100000)
6587  {
6588  char sverbuf[32];
6589 
6590  pg_log_error("The server (version %s) does not support subscriptions.",
6592  sverbuf, sizeof(sverbuf)));
6593  return true;
6594  }
6595 
6596  initPQExpBuffer(&buf);
6597 
6599  "SELECT subname AS \"%s\"\n"
6600  ", pg_catalog.pg_get_userbyid(subowner) AS \"%s\"\n"
6601  ", subenabled AS \"%s\"\n"
6602  ", subpublications AS \"%s\"\n",
6603  gettext_noop("Name"),
6604  gettext_noop("Owner"),
6605  gettext_noop("Enabled"),
6606  gettext_noop("Publication"));
6607 
6608  if (verbose)
6609  {
6610  /* Binary mode and streaming are only supported in v14 and higher */
6611  if (pset.sversion >= 140000)
6612  {
6614  ", subbinary AS \"%s\"\n",
6615  gettext_noop("Binary"));
6616 
6617  if (pset.sversion >= 160000)
6619  ", (CASE substream\n"
6620  " WHEN 'f' THEN 'off'\n"
6621  " WHEN 't' THEN 'on'\n"
6622  " WHEN 'p' THEN 'parallel'\n"
6623  " END) AS \"%s\"\n",
6624  gettext_noop("Streaming"));
6625  else
6627  ", substream AS \"%s\"\n",
6628  gettext_noop("Streaming"));
6629  }
6630 
6631  /* Two_phase and disable_on_error are only supported in v15 and higher */
6632  if (pset.sversion >= 150000)
6634  ", subtwophasestate AS \"%s\"\n"
6635  ", subdisableonerr AS \"%s\"\n",
6636  gettext_noop("Two-phase commit"),
6637  gettext_noop("Disable on error"));
6638 
6639  if (pset.sversion >= 160000)
6641  ", suborigin AS \"%s\"\n"
6642  ", subpasswordrequired AS \"%s\"\n"
6643  ", subrunasowner AS \"%s\"\n",
6644  gettext_noop("Origin"),
6645  gettext_noop("Password required"),
6646  gettext_noop("Run as owner?"));
6647 
6648  if (pset.sversion >= 170000)
6650  ", subfailover AS \"%s\"\n",
6651  gettext_noop("Failover"));
6652 
6654  ", subsynccommit AS \"%s\"\n"
6655  ", subconninfo AS \"%s\"\n",
6656  gettext_noop("Synchronous commit"),
6657  gettext_noop("Conninfo"));
6658 
6659  /* Skip LSN is only supported in v15 and higher */
6660  if (pset.sversion >= 150000)
6662  ", subskiplsn AS \"%s\"\n",
6663  gettext_noop("Skip LSN"));
6664  }
6665 
6666  /* Only display subscriptions in current database. */
6668  "FROM pg_catalog.pg_subscription\n"
6669  "WHERE subdbid = (SELECT oid\n"
6670  " FROM pg_catalog.pg_database\n"
6671  " WHERE datname = pg_catalog.current_database())");
6672 
6673  if (!validateSQLNamePattern(&buf, pattern, true, false,
6674  NULL, "subname", NULL,
6675  NULL,
6676  NULL, 1))
6677  {
6678  termPQExpBuffer(&buf);
6679  return false;
6680  }
6681 
6682  appendPQExpBufferStr(&buf, "ORDER BY 1;");
6683 
6684  res = PSQLexec(buf.data);
6685  termPQExpBuffer(&buf);
6686  if (!res)
6687  return false;
6688 
6689  myopt.title = _("List of subscriptions");
6690  myopt.translate_header = true;
6691  myopt.translate_columns = translate_columns;
6692  myopt.n_translate_columns = lengthof(translate_columns);
6693 
6694  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6695 
6696  PQclear(res);
6697  return true;
6698 }

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

Referenced by exec_command_d().

◆ describeTableDetails()

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

Definition at line 1445 of file describe.c.

1446 {
1448  PGresult *res;
1449  int i;
1450 
1451  initPQExpBuffer(&buf);
1452 
1454  "SELECT c.oid,\n"
1455  " n.nspname,\n"
1456  " c.relname\n"
1457  "FROM pg_catalog.pg_class c\n"
1458  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1459 
1460  if (!showSystem && !pattern)
1461  appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1462  " AND n.nspname <> 'information_schema'\n");
1463 
1464  if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, false,
1465  "n.nspname", "c.relname", NULL,
1466  "pg_catalog.pg_table_is_visible(c.oid)",
1467  NULL, 3))
1468  {
1469  termPQExpBuffer(&buf);
1470  return false;
1471  }
1472 
1473  appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
1474 
1475  res = PSQLexec(buf.data);
1476  termPQExpBuffer(&buf);
1477  if (!res)
1478  return false;
1479 
1480  if (PQntuples(res) == 0)
1481  {
1482  if (!pset.quiet)
1483  {
1484  if (pattern)
1485  pg_log_error("Did not find any relation named \"%s\".",
1486  pattern);
1487  else
1488  pg_log_error("Did not find any relations.");
1489  }
1490  PQclear(res);
1491  return false;
1492  }
1493 
1494  for (i = 0; i < PQntuples(res); i++)
1495  {
1496  const char *oid;
1497  const char *nspname;
1498  const char *relname;
1499 
1500  oid = PQgetvalue(res, i, 0);
1501  nspname = PQgetvalue(res, i, 1);
1502  relname = PQgetvalue(res, i, 2);
1503 
1504  if (!describeOneTableDetails(nspname, relname, oid, verbose))
1505  {
1506  PQclear(res);
1507  return false;
1508  }
1509  if (cancel_pressed)
1510  {
1511  PQclear(res);
1512  return false;
1513  }
1514  }
1515 
1516  PQclear(res);
1517  return true;
1518 }
static bool describeOneTableDetails(const char *schemaname, const char *relationname, const char *oid, bool verbose)
Definition: describe.c:1528
volatile sig_atomic_t cancel_pressed
Definition: print.c:43

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

Referenced by exec_command_d().

◆ describeTablespaces()

bool describeTablespaces ( const char *  pattern,
bool  verbose 
)

Definition at line 215 of file describe.c.

216 {
218  PGresult *res;
219  printQueryOpt myopt = pset.popt;
220 
222 
224  "SELECT spcname AS \"%s\",\n"
225  " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
226  " pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
227  gettext_noop("Name"),
228  gettext_noop("Owner"),
229  gettext_noop("Location"));
230 
231  if (verbose)
232  {
233  appendPQExpBufferStr(&buf, ",\n ");
234  printACLColumn(&buf, "spcacl");
236  ",\n spcoptions AS \"%s\""
237  ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\""
238  ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
239  gettext_noop("Options"),
240  gettext_noop("Size"),
241  gettext_noop("Description"));
242  }
243 
245  "\nFROM pg_catalog.pg_tablespace\n");
246 
247  if (!validateSQLNamePattern(&buf, pattern, false, false,
248  NULL, "spcname", NULL,
249  NULL,
250  NULL, 1))
251  {
253  return false;
254  }
255 
256  appendPQExpBufferStr(&buf, "ORDER BY 1;");
257 
258  res = PSQLexec(buf.data);
260  if (!res)
261  return false;
262 
263  myopt.title = _("List of tablespaces");
264  myopt.translate_header = true;
265 
266  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
267 
268  PQclear(res);
269  return true;
270 }

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

Referenced by exec_command_d().

◆ describeTypes()

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

Definition at line 615 of file describe.c.

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

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

Referenced by exec_command_d().

◆ listAllDbs()

bool listAllDbs ( const char *  pattern,
bool  verbose 
)

Definition at line 911 of file describe.c.

912 {
913  PGresult *res;
915  printQueryOpt myopt = pset.popt;
916 
918 
920  "SELECT\n"
921  " d.datname as \"%s\",\n"
922  " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
923  " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
924  gettext_noop("Name"),
925  gettext_noop("Owner"),
926  gettext_noop("Encoding"));
927  if (pset.sversion >= 150000)
929  " CASE d.datlocprovider WHEN 'b' THEN 'builtin' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"%s\",\n",
930  gettext_noop("Locale Provider"));
931  else
933  " 'libc' AS \"%s\",\n",
934  gettext_noop("Locale Provider"));
936  " d.datcollate as \"%s\",\n"
937  " d.datctype as \"%s\",\n",
938  gettext_noop("Collate"),
939  gettext_noop("Ctype"));
940  if (pset.sversion >= 170000)
942  " d.datlocale as \"%s\",\n",
943  gettext_noop("Locale"));
944  else if (pset.sversion >= 150000)
946  " d.daticulocale as \"%s\",\n",
947  gettext_noop("Locale"));
948  else
950  " NULL as \"%s\",\n",
951  gettext_noop("Locale"));
952  if (pset.sversion >= 160000)
954  " d.daticurules as \"%s\",\n",
955  gettext_noop("ICU Rules"));
956  else
958  " NULL as \"%s\",\n",
959  gettext_noop("ICU Rules"));
960  appendPQExpBufferStr(&buf, " ");
961  printACLColumn(&buf, "d.datacl");
962  if (verbose)
964  ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
965  " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
966  " ELSE 'No Access'\n"
967  " END as \"%s\""
968  ",\n t.spcname as \"%s\""
969  ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
970  gettext_noop("Size"),
971  gettext_noop("Tablespace"),
972  gettext_noop("Description"));
974  "\nFROM pg_catalog.pg_database d\n");
975  if (verbose)
977  " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
978 
979  if (pattern)
980  {
981  if (!validateSQLNamePattern(&buf, pattern, false, false,
982  NULL, "d.datname", NULL, NULL,
983  NULL, 1))
984  {
986  return false;
987  }
988  }
989 
990  appendPQExpBufferStr(&buf, "ORDER BY 1;");
991  res = PSQLexec(buf.data);
993  if (!res)
994  return false;
995 
996  myopt.title = _("List of databases");
997  myopt.translate_header = true;
998 
999  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1000 
1001  PQclear(res);
1002  return true;
1003 }

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

Referenced by exec_command_list(), and main().

◆ listCasts()

bool listCasts ( const char *  pattern,
bool  verbose 
)

Definition at line 4842 of file describe.c.

4843 {
4845  PGresult *res;
4846  printQueryOpt myopt = pset.popt;
4847  static const bool translate_columns[] = {false, false, false, true, false};
4848 
4849  initPQExpBuffer(&buf);
4850 
4852  "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
4853  " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n",
4854  gettext_noop("Source type"),
4855  gettext_noop("Target type"));
4856 
4857  /*
4858  * We don't attempt to localize '(binary coercible)' or '(with inout)',
4859  * because there's too much risk of gettext translating a function name
4860  * that happens to match some string in the PO database.
4861  */
4863  " CASE WHEN c.castmethod = '%c' THEN '(binary coercible)'\n"
4864  " WHEN c.castmethod = '%c' THEN '(with inout)'\n"
4865  " ELSE p.proname\n"
4866  " END AS \"%s\",\n",
4867  COERCION_METHOD_BINARY,
4868  COERCION_METHOD_INOUT,
4869  gettext_noop("Function"));
4870 
4872  " CASE WHEN c.castcontext = '%c' THEN '%s'\n"
4873  " WHEN c.castcontext = '%c' THEN '%s'\n"
4874  " ELSE '%s'\n"
4875  " END AS \"%s\"",
4876  COERCION_CODE_EXPLICIT,
4877  gettext_noop("no"),
4878  COERCION_CODE_ASSIGNMENT,
4879  gettext_noop("in assignment"),
4880  gettext_noop("yes"),
4881  gettext_noop("Implicit?"));
4882 
4883  if (verbose)
4885  ",\n d.description AS \"%s\"",
4886  gettext_noop("Description"));
4887 
4888  /*
4889  * We need a left join to pg_proc for binary casts; the others are just
4890  * paranoia.
4891  */
4893  "\nFROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
4894  " ON c.castfunc = p.oid\n"
4895  " LEFT JOIN pg_catalog.pg_type ts\n"
4896  " ON c.castsource = ts.oid\n"
4897  " LEFT JOIN pg_catalog.pg_namespace ns\n"
4898  " ON ns.oid = ts.typnamespace\n"
4899  " LEFT JOIN pg_catalog.pg_type tt\n"
4900  " ON c.casttarget = tt.oid\n"
4901  " LEFT JOIN pg_catalog.pg_namespace nt\n"
4902  " ON nt.oid = tt.typnamespace\n");
4903 
4904  if (verbose)
4906  " LEFT JOIN pg_catalog.pg_description d\n"
4907  " ON d.classoid = c.tableoid AND d.objoid = "
4908  "c.oid AND d.objsubid = 0\n");
4909 
4910  appendPQExpBufferStr(&buf, "WHERE ( (true");
4911 
4912  /*
4913  * Match name pattern against either internal or external name of either
4914  * castsource or casttarget
4915  */
4916  if (!validateSQLNamePattern(&buf, pattern, true, false,
4917  "ns.nspname", "ts.typname",
4918  "pg_catalog.format_type(ts.oid, NULL)",
4919  "pg_catalog.pg_type_is_visible(ts.oid)",
4920  NULL, 3))
4921  goto error_return;
4922 
4923  appendPQExpBufferStr(&buf, ") OR (true");
4924 
4925  if (!validateSQLNamePattern(&buf, pattern, true, false,
4926  "nt.nspname", "tt.typname",
4927  "pg_catalog.format_type(tt.oid, NULL)",
4928  "pg_catalog.pg_type_is_visible(tt.oid)",
4929  NULL, 3))
4930  goto error_return;
4931 
4932  appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
4933 
4934  res = PSQLexec(buf.data);
4935  termPQExpBuffer(&buf);
4936  if (!res)
4937  return false;
4938 
4939  myopt.title = _("List of casts");
4940  myopt.translate_header = true;
4941  myopt.translate_columns = translate_columns;
4942  myopt.n_translate_columns = lengthof(translate_columns);
4943 
4944  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4945 
4946  PQclear(res);
4947  return true;
4948 
4949 error_return:
4950  termPQExpBuffer(&buf);
4951  return false;
4952 }

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

Referenced by exec_command_d().

◆ listCollations()

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

Definition at line 4960 of file describe.c.

4961 {
4963  PGresult *res;
4964  printQueryOpt myopt = pset.popt;
4965  static const bool translate_columns[] = {false, false, false, false, false, false, false, true, false};
4966 
4967  initPQExpBuffer(&buf);
4968 
4970  "SELECT\n"
4971  " n.nspname AS \"%s\",\n"
4972  " c.collname AS \"%s\",\n",
4973  gettext_noop("Schema"),
4974  gettext_noop("Name"));
4975 
4976  if (pset.sversion >= 100000)
4978  " CASE c.collprovider WHEN 'd' THEN 'default' WHEN 'b' THEN 'builtin' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"%s\",\n",
4979  gettext_noop("Provider"));
4980  else
4982  " 'libc' AS \"%s\",\n",
4983  gettext_noop("Provider"));
4984 
4986  " c.collcollate AS \"%s\",\n"
4987  " c.collctype AS \"%s\",\n",
4988  gettext_noop("Collate"),
4989  gettext_noop("Ctype"));
4990 
4991  if (pset.sversion >= 170000)
4993  " c.colllocale AS \"%s\",\n",
4994  gettext_noop("Locale"));
4995  else if (pset.sversion >= 150000)
4997  " c.colliculocale AS \"%s\",\n",
4998  gettext_noop("Locale"));
4999  else
5001  " c.collcollate AS \"%s\",\n",
5002  gettext_noop("Locale"));
5003 
5004  if (pset.sversion >= 160000)
5006  " c.collicurules AS \"%s\",\n",
5007  gettext_noop("ICU Rules"));
5008  else
5010  " NULL AS \"%s\",\n",
5011  gettext_noop("ICU Rules"));
5012 
5013  if (pset.sversion >= 120000)
5015  " CASE WHEN c.collisdeterministic THEN '%s' ELSE '%s' END AS \"%s\"",
5016  gettext_noop("yes"), gettext_noop("no"),
5017  gettext_noop("Deterministic?"));
5018  else
5020  " '%s' AS \"%s\"",
5021  gettext_noop("yes"),
5022  gettext_noop("Deterministic?"));
5023 
5024  if (verbose)
5026  ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
5027  gettext_noop("Description"));
5028 
5030  "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
5031  "WHERE n.oid = c.collnamespace\n");
5032 
5033  if (!showSystem && !pattern)
5034  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
5035  " AND n.nspname <> 'information_schema'\n");
5036 
5037  /*
5038  * Hide collations that aren't usable in the current database's encoding.
5039  * If you think to change this, note that pg_collation_is_visible rejects
5040  * unusable collations, so you will need to hack name pattern processing
5041  * somehow to avoid inconsistent behavior.
5042  */
5043  appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
5044 
5045  if (!validateSQLNamePattern(&buf, pattern, true, false,
5046  "n.nspname", "c.collname", NULL,
5047  "pg_catalog.pg_collation_is_visible(c.oid)",
5048  NULL, 3))
5049  {
5050  termPQExpBuffer(&buf);
5051  return false;
5052  }
5053 
5054  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5055 
5056  res = PSQLexec(buf.data);
5057  termPQExpBuffer(&buf);
5058  if (!res)
5059  return false;
5060 
5061  myopt.title = _("List of collations");
5062  myopt.translate_header = true;
5063  myopt.translate_columns = translate_columns;
5064  myopt.n_translate_columns = lengthof(translate_columns);
5065 
5066  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5067 
5068  PQclear(res);
5069  return true;
5070 }

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

Referenced by exec_command_d().

◆ listConversions()

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

Definition at line 4518 of file describe.c.

4519 {
4521  PGresult *res;
4522  printQueryOpt myopt = pset.popt;
4523  static const bool translate_columns[] =
4524  {false, false, false, false, true, false};
4525 
4526  initPQExpBuffer(&buf);
4527 
4529  "SELECT n.nspname AS \"%s\",\n"
4530  " c.conname AS \"%s\",\n"
4531  " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
4532  " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
4533  " CASE WHEN c.condefault THEN '%s'\n"
4534  " ELSE '%s' END AS \"%s\"",
4535  gettext_noop("Schema"),
4536  gettext_noop("Name"),
4537  gettext_noop("Source"),
4538  gettext_noop("Destination"),
4539  gettext_noop("yes"), gettext_noop("no"),
4540  gettext_noop("Default?"));
4541 
4542  if (verbose)
4544  ",\n d.description AS \"%s\"",
4545  gettext_noop("Description"));
4546 
4548  "\nFROM pg_catalog.pg_conversion c\n"
4549  " JOIN pg_catalog.pg_namespace n "
4550  "ON n.oid = c.connamespace\n");
4551 
4552  if (verbose)
4554  "LEFT JOIN pg_catalog.pg_description d "
4555  "ON d.classoid = c.tableoid\n"
4556  " AND d.objoid = c.oid "
4557  "AND d.objsubid = 0\n");
4558 
4559  appendPQExpBufferStr(&buf, "WHERE true\n");
4560 
4561  if (!showSystem && !pattern)
4562  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4563  " AND n.nspname <> 'information_schema'\n");
4564 
4565  if (!validateSQLNamePattern(&buf, pattern, true, false,
4566  "n.nspname", "c.conname", NULL,
4567  "pg_catalog.pg_conversion_is_visible(c.oid)",
4568  NULL, 3))
4569  {
4570  termPQExpBuffer(&buf);
4571  return false;
4572  }
4573 
4574  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4575 
4576  res = PSQLexec(buf.data);
4577  termPQExpBuffer(&buf);
4578  if (!res)
4579  return false;
4580 
4581  myopt.title = _("List of conversions");
4582  myopt.translate_header = true;
4583  myopt.translate_columns = translate_columns;
4584  myopt.n_translate_columns = lengthof(translate_columns);
4585 
4586  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4587 
4588  PQclear(res);
4589  return true;
4590 }

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

Referenced by exec_command_d().

◆ listDbRoleSettings()

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

Definition at line 3813 of file describe.c.

3814 {
3816  PGresult *res;
3817  printQueryOpt myopt = pset.popt;
3818  bool havewhere;
3819 
3820  initPQExpBuffer(&buf);
3821 
3822  printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
3823  "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
3824  "FROM pg_catalog.pg_db_role_setting s\n"
3825  "LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n"
3826  "LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n",
3827  gettext_noop("Role"),
3828  gettext_noop("Database"),
3829  gettext_noop("Settings"));
3830  if (!validateSQLNamePattern(&buf, pattern, false, false,
3831  NULL, "r.rolname", NULL, NULL, &havewhere, 1))
3832  goto error_return;
3833  if (!validateSQLNamePattern(&buf, pattern2, havewhere, false,
3834  NULL, "d.datname", NULL, NULL,
3835  NULL, 1))
3836  goto error_return;
3837  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3838 
3839  res = PSQLexec(buf.data);
3840  termPQExpBuffer(&buf);
3841  if (!res)
3842  return false;
3843 
3844  /*
3845  * Most functions in this file are content to print an empty table when
3846  * there are no matching objects. We intentionally deviate from that
3847  * here, but only in !quiet mode, because of the possibility that the user
3848  * is confused about what the two pattern arguments mean.
3849  */
3850  if (PQntuples(res) == 0 && !pset.quiet)
3851  {
3852  if (pattern && pattern2)
3853  pg_log_error("Did not find any settings for role \"%s\" and database \"%s\".",
3854  pattern, pattern2);
3855  else if (pattern)
3856  pg_log_error("Did not find any settings for role \"%s\".",
3857  pattern);
3858  else
3859  pg_log_error("Did not find any settings.");
3860  }
3861  else
3862  {
3863  myopt.title = _("List of settings");
3864  myopt.translate_header = true;
3865 
3866  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3867  }
3868 
3869  PQclear(res);
3870  return true;
3871 
3872 error_return:
3873  termPQExpBuffer(&buf);
3874  return false;
3875 }

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

Referenced by exec_command_d().

◆ listDefaultACLs()

bool listDefaultACLs ( const char *  pattern)

Definition at line 1175 of file describe.c.

1176 {
1178  PGresult *res;
1179  printQueryOpt myopt = pset.popt;
1180  static const bool translate_columns[] = {false, false, true, false};
1181 
1182  initPQExpBuffer(&buf);
1183 
1185  "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
1186  " n.nspname AS \"%s\",\n"
1187  " 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"
1188  " ",
1189  gettext_noop("Owner"),
1190  gettext_noop("Schema"),
1191  DEFACLOBJ_RELATION,
1192  gettext_noop("table"),
1193  DEFACLOBJ_SEQUENCE,
1194  gettext_noop("sequence"),
1195  DEFACLOBJ_FUNCTION,
1196  gettext_noop("function"),
1197  DEFACLOBJ_TYPE,
1198  gettext_noop("type"),
1199  DEFACLOBJ_NAMESPACE,
1200  gettext_noop("schema"),
1201  gettext_noop("Type"));
1202 
1203  printACLColumn(&buf, "d.defaclacl");
1204 
1205  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
1206  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
1207 
1208  if (!validateSQLNamePattern(&buf, pattern, false, false,
1209  NULL,
1210  "n.nspname",
1211  "pg_catalog.pg_get_userbyid(d.defaclrole)",
1212  NULL,
1213  NULL, 3))
1214  goto error_return;
1215 
1216  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1217 
1218  res = PSQLexec(buf.data);
1219  if (!res)
1220  goto error_return;
1221 
1222  printfPQExpBuffer(&buf, _("Default access privileges"));
1223  myopt.title = buf.data;
1224  myopt.translate_header = true;
1225  myopt.translate_columns = translate_columns;
1226  myopt.n_translate_columns = lengthof(translate_columns);
1227 
1228  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1229 
1230  termPQExpBuffer(&buf);
1231  PQclear(res);
1232  return true;
1233 
1234 error_return:
1235  termPQExpBuffer(&buf);
1236  return false;
1237 }

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

Referenced by exec_command_d().

◆ listDomains()

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

Definition at line 4435 of file describe.c.

4436 {
4438  PGresult *res;
4439  printQueryOpt myopt = pset.popt;
4440 
4441  initPQExpBuffer(&buf);
4442 
4444  "SELECT n.nspname as \"%s\",\n"
4445  " t.typname as \"%s\",\n"
4446  " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
4447  " (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
4448  " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as \"%s\",\n"
4449  " CASE WHEN t.typnotnull THEN 'not null' END as \"%s\",\n"
4450  " t.typdefault as \"%s\",\n"
4451  " pg_catalog.array_to_string(ARRAY(\n"
4452  " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
4453  " ), ' ') as \"%s\"",
4454  gettext_noop("Schema"),
4455  gettext_noop("Name"),
4456  gettext_noop("Type"),
4457  gettext_noop("Collation"),
4458  gettext_noop("Nullable"),
4459  gettext_noop("Default"),
4460  gettext_noop("Check"));
4461 
4462  if (verbose)
4463  {
4464  appendPQExpBufferStr(&buf, ",\n ");
4465  printACLColumn(&buf, "t.typacl");
4467  ",\n d.description as \"%s\"",
4468  gettext_noop("Description"));
4469  }
4470 
4472  "\nFROM pg_catalog.pg_type t\n"
4473  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
4474 
4475  if (verbose)
4477  " LEFT JOIN pg_catalog.pg_description d "
4478  "ON d.classoid = t.tableoid AND d.objoid = t.oid "
4479  "AND d.objsubid = 0\n");
4480 
4481  appendPQExpBufferStr(&buf, "WHERE t.typtype = 'd'\n");
4482 
4483  if (!showSystem && !pattern)
4484  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4485  " AND n.nspname <> 'information_schema'\n");
4486 
4487  if (!validateSQLNamePattern(&buf, pattern, true, false,
4488  "n.nspname", "t.typname", NULL,
4489  "pg_catalog.pg_type_is_visible(t.oid)",
4490  NULL, 3))
4491  {
4492  termPQExpBuffer(&buf);
4493  return false;
4494  }
4495 
4496  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4497 
4498  res = PSQLexec(buf.data);
4499  termPQExpBuffer(&buf);
4500  if (!res)
4501  return false;
4502 
4503  myopt.title = _("List of domains");
4504  myopt.translate_header = true;
4505 
4506  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4507 
4508  PQclear(res);
4509  return true;
4510 }

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

Referenced by exec_command_d().

◆ listEventTriggers()

bool listEventTriggers ( const char *  pattern,
bool  verbose 
)

Definition at line 4666 of file describe.c.

4667 {
4669  PGresult *res;
4670  printQueryOpt myopt = pset.popt;
4671  static const bool translate_columns[] =
4672  {false, false, false, true, false, false, false};
4673 
4674  if (pset.sversion < 90300)
4675  {
4676  char sverbuf[32];
4677 
4678  pg_log_error("The server (version %s) does not support event triggers.",
4680  sverbuf, sizeof(sverbuf)));
4681  return true;
4682  }
4683 
4684  initPQExpBuffer(&buf);
4685 
4687  "SELECT evtname as \"%s\", "
4688  "evtevent as \"%s\", "
4689  "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
4690  " case evtenabled when 'O' then '%s'"
4691  " when 'R' then '%s'"
4692  " when 'A' then '%s'"
4693  " when 'D' then '%s' end as \"%s\",\n"
4694  " e.evtfoid::pg_catalog.regproc as \"%s\", "
4695  "pg_catalog.array_to_string(array(select x"
4696  " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
4697  gettext_noop("Name"),
4698  gettext_noop("Event"),
4699  gettext_noop("Owner"),
4700  gettext_noop("enabled"),
4701  gettext_noop("replica"),
4702  gettext_noop("always"),
4703  gettext_noop("disabled"),
4704  gettext_noop("Enabled"),
4705  gettext_noop("Function"),
4706  gettext_noop("Tags"));
4707  if (verbose)
4709  ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
4710  gettext_noop("Description"));
4712  "\nFROM pg_catalog.pg_event_trigger e ");
4713 
4714  if (!validateSQLNamePattern(&buf, pattern, false, false,
4715  NULL, "evtname", NULL, NULL,
4716  NULL, 1))
4717  {
4718  termPQExpBuffer(&buf);
4719  return false;
4720  }
4721 
4722  appendPQExpBufferStr(&buf, "ORDER BY 1");
4723 
4724  res = PSQLexec(buf.data);
4725  termPQExpBuffer(&buf);
4726  if (!res)
4727  return false;
4728 
4729  myopt.title = _("List of event triggers");
4730  myopt.translate_header = true;
4731  myopt.translate_columns = translate_columns;
4732  myopt.n_translate_columns = lengthof(translate_columns);
4733 
4734  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4735 
4736  PQclear(res);
4737  return true;
4738 }

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

Referenced by exec_command_d().

◆ listExtendedStats()

bool listExtendedStats ( const char *  pattern)

Definition at line 4746 of file describe.c.

4747 {
4749  PGresult *res;
4750  printQueryOpt myopt = pset.popt;
4751 
4752  if (pset.sversion < 100000)
4753  {
4754  char sverbuf[32];
4755 
4756  pg_log_error("The server (version %s) does not support extended statistics.",
4758  sverbuf, sizeof(sverbuf)));
4759  return true;
4760  }
4761 
4762  initPQExpBuffer(&buf);
4764  "SELECT \n"
4765  "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS \"%s\", \n"
4766  "es.stxname AS \"%s\", \n",
4767  gettext_noop("Schema"),
4768  gettext_noop("Name"));
4769 
4770  if (pset.sversion >= 140000)
4772  "pg_catalog.format('%%s FROM %%s', \n"
4773  " pg_catalog.pg_get_statisticsobjdef_columns(es.oid), \n"
4774  " es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4775  gettext_noop("Definition"));
4776  else
4778  "pg_catalog.format('%%s FROM %%s', \n"
4779  " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n"
4780  " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n"
4781  " JOIN pg_catalog.pg_attribute a \n"
4782  " ON (es.stxrelid = a.attrelid \n"
4783  " AND a.attnum = s.attnum \n"
4784  " AND NOT a.attisdropped)), \n"
4785  "es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4786  gettext_noop("Definition"));
4787 
4789  ",\nCASE WHEN 'd' = any(es.stxkind) THEN 'defined' \n"
4790  "END AS \"%s\", \n"
4791  "CASE WHEN 'f' = any(es.stxkind) THEN 'defined' \n"
4792  "END AS \"%s\"",
4793  gettext_noop("Ndistinct"),
4794  gettext_noop("Dependencies"));
4795 
4796  /*
4797  * Include the MCV statistics kind.
4798  */
4799  if (pset.sversion >= 120000)
4800  {
4802  ",\nCASE WHEN 'm' = any(es.stxkind) THEN 'defined' \n"
4803  "END AS \"%s\" ",
4804  gettext_noop("MCV"));
4805  }
4806 
4808  " \nFROM pg_catalog.pg_statistic_ext es \n");
4809 
4810  if (!validateSQLNamePattern(&buf, pattern,
4811  false, false,
4812  "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname",
4813  NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)",
4814  NULL, 3))
4815  {
4816  termPQExpBuffer(&buf);
4817  return false;
4818  }
4819 
4820  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4821 
4822  res = PSQLexec(buf.data);
4823  termPQExpBuffer(&buf);
4824  if (!res)
4825  return false;
4826 
4827  myopt.title = _("List of extended statistics");
4828  myopt.translate_header = true;
4829 
4830  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4831 
4832  PQclear(res);
4833  return true;
4834 }

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

Referenced by exec_command_d().

◆ listExtensionContents()

bool listExtensionContents ( const char *  pattern)

Definition at line 6105 of file describe.c.

6106 {
6108  PGresult *res;
6109  int i;
6110 
6111  initPQExpBuffer(&buf);
6113  "SELECT e.extname, e.oid\n"
6114  "FROM pg_catalog.pg_extension e\n");
6115 
6116  if (!validateSQLNamePattern(&buf, pattern,
6117  false, false,
6118  NULL, "e.extname", NULL,
6119  NULL,
6120  NULL, 1))
6121  {
6122  termPQExpBuffer(&buf);
6123  return false;
6124  }
6125 
6126  appendPQExpBufferStr(&buf, "ORDER BY 1;");
6127 
6128  res = PSQLexec(buf.data);
6129  termPQExpBuffer(&buf);
6130  if (!res)
6131  return false;
6132 
6133  if (PQntuples(res) == 0)
6134  {
6135  if (!pset.quiet)
6136  {
6137  if (pattern)
6138  pg_log_error("Did not find any extension named \"%s\".",
6139  pattern);
6140  else
6141  pg_log_error("Did not find any extensions.");
6142  }
6143  PQclear(res);
6144  return false;
6145  }
6146 
6147  for (i = 0; i < PQntuples(res); i++)
6148  {
6149  const char *extname;
6150  const char *oid;
6151 
6152  extname = PQgetvalue(res, i, 0);
6153  oid = PQgetvalue(res, i, 1);
6154 
6155  if (!listOneExtensionContents(extname, oid))
6156  {
6157  PQclear(res);
6158  return false;
6159  }
6160  if (cancel_pressed)
6161  {
6162  PQclear(res);
6163  return false;
6164  }
6165  }
6166 
6167  PQclear(res);
6168  return true;
6169 }
static bool listOneExtensionContents(const char *extname, const char *oid)
Definition: describe.c:6172

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

Referenced by exec_command_d().

◆ listExtensions()

bool listExtensions ( const char *  pattern)

Definition at line 6054 of file describe.c.

6055 {
6057  PGresult *res;
6058  printQueryOpt myopt = pset.popt;
6059 
6060  initPQExpBuffer(&buf);
6062  "SELECT e.extname AS \"%s\", "
6063  "e.extversion AS \"%s\", n.nspname AS \"%s\", c.description AS \"%s\"\n"
6064  "FROM pg_catalog.pg_extension e "
6065  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
6066  "LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
6067  "AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass\n",
6068  gettext_noop("Name"),
6069  gettext_noop("Version"),
6070  gettext_noop("Schema"),
6071  gettext_noop("Description"));
6072 
6073  if (!validateSQLNamePattern(&buf, pattern,
6074  false, false,
6075  NULL, "e.extname", NULL,
6076  NULL,
6077  NULL, 1))
6078  {
6079  termPQExpBuffer(&buf);
6080  return false;
6081  }
6082 
6083  appendPQExpBufferStr(&buf, "ORDER BY 1;");
6084 
6085  res = PSQLexec(buf.data);
6086  termPQExpBuffer(&buf);
6087  if (!res)
6088  return false;
6089 
6090  myopt.title = _("List of installed extensions");
6091  myopt.translate_header = true;
6092 
6093  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6094 
6095  PQclear(res);
6096  return true;
6097 }

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

Referenced by exec_command_d().

◆ listForeignDataWrappers()

bool listForeignDataWrappers ( const char *  pattern,
bool  verbose 
)

Definition at line 5780 of file describe.c.

5781 {
5783  PGresult *res;
5784  printQueryOpt myopt = pset.popt;
5785 
5786  initPQExpBuffer(&buf);
5788  "SELECT fdw.fdwname AS \"%s\",\n"
5789  " pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n"
5790  " fdw.fdwhandler::pg_catalog.regproc AS \"%s\",\n"
5791  " fdw.fdwvalidator::pg_catalog.regproc AS \"%s\"",
5792  gettext_noop("Name"),
5793  gettext_noop("Owner"),
5794  gettext_noop("Handler"),
5795  gettext_noop("Validator"));
5796 
5797  if (verbose)
5798  {
5799  appendPQExpBufferStr(&buf, ",\n ");
5800  printACLColumn(&buf, "fdwacl");
5802  ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
5803  " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5804  " pg_catalog.quote_ident(option_name) || ' ' || "
5805  " pg_catalog.quote_literal(option_value) FROM "
5806  " pg_catalog.pg_options_to_table(fdwoptions)), ', ') || ')' "
5807  " END AS \"%s\""
5808  ",\n d.description AS \"%s\" ",
5809  gettext_noop("FDW options"),
5810  gettext_noop("Description"));
5811  }
5812 
5813  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
5814 
5815  if (verbose)
5817  "LEFT JOIN pg_catalog.pg_description d\n"
5818  " ON d.classoid = fdw.tableoid "
5819  "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
5820 
5821  if (!validateSQLNamePattern(&buf, pattern, false, false,
5822  NULL, "fdwname", NULL, NULL,
5823  NULL, 1))
5824  {
5825  termPQExpBuffer(&buf);
5826  return false;
5827  }
5828 
5829  appendPQExpBufferStr(&buf, "ORDER BY 1;");
5830 
5831  res = PSQLexec(buf.data);
5832  termPQExpBuffer(&buf);
5833  if (!res)
5834  return false;
5835 
5836  myopt.title = _("List of foreign-data wrappers");
5837  myopt.translate_header = true;
5838 
5839  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5840 
5841  PQclear(res);
5842  return true;
5843 }

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

Referenced by exec_command_d().

◆ listForeignServers()

bool listForeignServers ( const char *  pattern,
bool  verbose 
)

Definition at line 5851 of file describe.c.

5852 {
5854  PGresult *res;
5855  printQueryOpt myopt = pset.popt;
5856 
5857  initPQExpBuffer(&buf);
5859  "SELECT s.srvname AS \"%s\",\n"
5860  " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
5861  " f.fdwname AS \"%s\"",
5862  gettext_noop("Name"),
5863  gettext_noop("Owner"),
5864  gettext_noop("Foreign-data wrapper"));
5865 
5866  if (verbose)
5867  {
5868  appendPQExpBufferStr(&buf, ",\n ");
5869  printACLColumn(&buf, "s.srvacl");
5871  ",\n"
5872  " s.srvtype AS \"%s\",\n"
5873  " s.srvversion AS \"%s\",\n"
5874  " CASE WHEN srvoptions IS NULL THEN '' ELSE "
5875  " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5876  " pg_catalog.quote_ident(option_name) || ' ' || "
5877  " pg_catalog.quote_literal(option_value) FROM "
5878  " pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')' "
5879  " END AS \"%s\",\n"
5880  " d.description AS \"%s\"",
5881  gettext_noop("Type"),
5882  gettext_noop("Version"),
5883  gettext_noop("FDW options"),
5884  gettext_noop("Description"));
5885  }
5886 
5888  "\nFROM pg_catalog.pg_foreign_server s\n"
5889  " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
5890 
5891  if (verbose)
5893  "LEFT JOIN pg_catalog.pg_description d\n "
5894  "ON d.classoid = s.tableoid AND d.objoid = s.oid "
5895  "AND d.objsubid = 0\n");
5896 
5897  if (!validateSQLNamePattern(&buf, pattern, false, false,
5898  NULL, "s.srvname", NULL, NULL,
5899  NULL, 1))
5900  {
5901  termPQExpBuffer(&buf);
5902  return false;
5903  }
5904 
5905  appendPQExpBufferStr(&buf, "ORDER BY 1;");
5906 
5907  res = PSQLexec(buf.data);
5908  termPQExpBuffer(&buf);
5909  if (!res)
5910  return false;
5911 
5912  myopt.title = _("List of foreign servers");
5913  myopt.translate_header = true;
5914 
5915  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5916 
5917  PQclear(res);
5918  return true;
5919 }

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

Referenced by exec_command_d().

◆ listForeignTables()

bool listForeignTables ( const char *  pattern,
bool  verbose 
)

Definition at line 5982 of file describe.c.

5983 {
5985  PGresult *res;
5986  printQueryOpt myopt = pset.popt;
5987 
5988  initPQExpBuffer(&buf);
5990  "SELECT n.nspname AS \"%s\",\n"
5991  " c.relname AS \"%s\",\n"
5992  " s.srvname AS \"%s\"",
5993  gettext_noop("Schema"),
5994  gettext_noop("Table"),
5995  gettext_noop("Server"));
5996 
5997  if (verbose)
5999  ",\n CASE WHEN ftoptions IS NULL THEN '' ELSE "
6000  " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
6001  " pg_catalog.quote_ident(option_name) || ' ' || "
6002  " pg_catalog.quote_literal(option_value) FROM "
6003  " pg_catalog.pg_options_to_table(ftoptions)), ', ') || ')' "
6004  " END AS \"%s\",\n"
6005  " d.description AS \"%s\"",
6006  gettext_noop("FDW options"),
6007  gettext_noop("Description"));
6008 
6010  "\nFROM pg_catalog.pg_foreign_table ft\n"
6011  " INNER JOIN pg_catalog.pg_class c"
6012  " ON c.oid = ft.ftrelid\n"
6013  " INNER JOIN pg_catalog.pg_namespace n"
6014  " ON n.oid = c.relnamespace\n"
6015  " INNER JOIN pg_catalog.pg_foreign_server s"
6016  " ON s.oid = ft.ftserver\n");
6017  if (verbose)
6019  " LEFT JOIN pg_catalog.pg_description d\n"
6020  " ON d.classoid = c.tableoid AND "
6021  "d.objoid = c.oid AND d.objsubid = 0\n");
6022 
6023  if (!validateSQLNamePattern(&buf, pattern, false, false,
6024  "n.nspname", "c.relname", NULL,
6025  "pg_catalog.pg_table_is_visible(c.oid)",
6026  NULL, 3))
6027  {
6028  termPQExpBuffer(&buf);
6029  return false;
6030  }
6031 
6032  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
6033 
6034  res = PSQLexec(buf.data);
6035  termPQExpBuffer(&buf);
6036  if (!res)
6037  return false;
6038 
6039  myopt.title = _("List of foreign tables");
6040  myopt.translate_header = true;
6041 
6042  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6043 
6044  PQclear(res);
6045  return true;
6046 }

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

Referenced by exec_command_d().

◆ listLanguages()

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

Definition at line 4359 of file describe.c.

4360 {
4362  PGresult *res;
4363  printQueryOpt myopt = pset.popt;
4364 
4365  initPQExpBuffer(&buf);
4366 
4368  "SELECT l.lanname AS \"%s\",\n"
4369  " pg_catalog.pg_get_userbyid(l.lanowner) as \"%s\",\n"
4370  " l.lanpltrusted AS \"%s\"",
4371  gettext_noop("Name"),
4372  gettext_noop("Owner"),
4373  gettext_noop("Trusted"));
4374 
4375  if (verbose)
4376  {
4378  ",\n NOT l.lanispl AS \"%s\",\n"
4379  " l.lanplcallfoid::pg_catalog.regprocedure AS \"%s\",\n"
4380  " l.lanvalidator::pg_catalog.regprocedure AS \"%s\",\n "
4381  "l.laninline::pg_catalog.regprocedure AS \"%s\",\n ",
4382  gettext_noop("Internal language"),
4383  gettext_noop("Call handler"),
4384  gettext_noop("Validator"),
4385  gettext_noop("Inline handler"));
4386  printACLColumn(&buf, "l.lanacl");
4387  }
4388 
4390  ",\n d.description AS \"%s\""
4391  "\nFROM pg_catalog.pg_language l\n"
4392  "LEFT JOIN pg_catalog.pg_description d\n"
4393  " ON d.classoid = l.tableoid AND d.objoid = l.oid\n"
4394  " AND d.objsubid = 0\n",
4395  gettext_noop("Description"));
4396 
4397  if (pattern)
4398  {
4399  if (!validateSQLNamePattern(&buf, pattern, false, false,
4400  NULL, "l.lanname", NULL, NULL,
4401  NULL, 2))
4402  {
4403  termPQExpBuffer(&buf);
4404  return false;
4405  }
4406  }
4407 
4408  if (!showSystem && !pattern)
4409  appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n");
4410 
4411 
4412  appendPQExpBufferStr(&buf, "ORDER BY 1;");
4413 
4414  res = PSQLexec(buf.data);
4415  termPQExpBuffer(&buf);
4416  if (!res)
4417  return false;
4418 
4419  myopt.title = _("List of languages");
4420  myopt.translate_header = true;
4421 
4422  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4423 
4424  PQclear(res);
4425  return true;
4426 }

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

Referenced by exec_command_d().

◆ listLargeObjects()

bool listLargeObjects ( bool  verbose)

Definition at line 7106 of file describe.c.

7107 {
7109  PGresult *res;
7110  printQueryOpt myopt = pset.popt;
7111 
7112  initPQExpBuffer(&buf);
7113 
7115  "SELECT oid as \"%s\",\n"
7116  " pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n ",
7117  gettext_noop("ID"),
7118  gettext_noop("Owner"));
7119 
7120  if (verbose)
7121  {
7122  printACLColumn(&buf, "lomacl");
7123  appendPQExpBufferStr(&buf, ",\n ");
7124  }
7125 
7127  "pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n"
7128  "FROM pg_catalog.pg_largeobject_metadata\n"
7129  "ORDER BY oid",
7130  gettext_noop("Description"));
7131 
7132  res = PSQLexec(buf.data);
7133  termPQExpBuffer(&buf);
7134  if (!res)
7135  return false;
7136 
7137  myopt.title = _("Large objects");
7138  myopt.translate_header = true;
7139 
7140  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7141 
7142  PQclear(res);
7143  return true;
7144 }

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

Referenced by exec_command_d(), and exec_command_lo().

◆ listOneExtensionContents()

static bool listOneExtensionContents ( const char *  extname,
const char *  oid 
)
static

Definition at line 6172 of file describe.c.

6173 {
6175  PGresult *res;
6176  PQExpBufferData title;
6177  printQueryOpt myopt = pset.popt;
6178 
6179  initPQExpBuffer(&buf);
6181  "SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS \"%s\"\n"
6182  "FROM pg_catalog.pg_depend\n"
6183  "WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '%s' AND deptype = 'e'\n"
6184  "ORDER BY 1;",
6185  gettext_noop("Object description"),
6186  oid);
6187 
6188  res = PSQLexec(buf.data);
6189  termPQExpBuffer(&buf);
6190  if (!res)
6191  return false;
6192 
6193  initPQExpBuffer(&title);
6194  printfPQExpBuffer(&title, _("Objects in extension \"%s\""), extname);
6195  myopt.title = title.data;
6196  myopt.translate_header = true;
6197 
6198  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6199 
6200  termPQExpBuffer(&title);
6201  PQclear(res);
6202  return true;
6203 }

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

Referenced by listExtensionContents().

◆ listOperatorClasses()

bool listOperatorClasses ( const char *  access_method_pattern,
const char *  type_pattern,
bool  verbose 
)

Definition at line 6729 of file describe.c.

6731 {
6733  PGresult *res;
6734  printQueryOpt myopt = pset.popt;
6735  bool have_where = false;
6736  static const bool translate_columns[] = {false, false, false, false, false, false, false};
6737 
6738  initPQExpBuffer(&buf);
6739 
6741  "SELECT\n"
6742  " am.amname AS \"%s\",\n"
6743  " pg_catalog.format_type(c.opcintype, NULL) AS \"%s\",\n"
6744  " CASE\n"
6745  " WHEN c.opckeytype <> 0 AND c.opckeytype <> c.opcintype\n"
6746  " THEN pg_catalog.format_type(c.opckeytype, NULL)\n"
6747  " ELSE NULL\n"
6748  " END AS \"%s\",\n"
6749  " CASE\n"
6750  " WHEN pg_catalog.pg_opclass_is_visible(c.oid)\n"
6751  " THEN pg_catalog.format('%%I', c.opcname)\n"
6752  " ELSE pg_catalog.format('%%I.%%I', n.nspname, c.opcname)\n"
6753  " END AS \"%s\",\n"
6754  " (CASE WHEN c.opcdefault\n"
6755  " THEN '%s'\n"
6756  " ELSE '%s'\n"
6757  " END) AS \"%s\"",
6758  gettext_noop("AM"),
6759  gettext_noop("Input type"),
6760  gettext_noop("Storage type"),
6761  gettext_noop("Operator class"),
6762  gettext_noop("yes"),
6763  gettext_noop("no"),
6764  gettext_noop("Default?"));
6765  if (verbose)
6767  ",\n CASE\n"
6768  " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
6769  " THEN pg_catalog.format('%%I', of.opfname)\n"
6770  " ELSE pg_catalog.format('%%I.%%I', ofn.nspname, of.opfname)\n"
6771  " END AS \"%s\",\n"
6772  " pg_catalog.pg_get_userbyid(c.opcowner) AS \"%s\"\n",
6773  gettext_noop("Operator family"),
6774  gettext_noop("Owner"));
6776  "\nFROM pg_catalog.pg_opclass c\n"
6777  " LEFT JOIN pg_catalog.pg_am am on am.oid = c.opcmethod\n"
6778  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.opcnamespace\n"
6779  " LEFT JOIN pg_catalog.pg_type t ON t.oid = c.opcintype\n"
6780  " LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n");
6781  if (verbose)
6783  " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = c.opcfamily\n"
6784  " LEFT JOIN pg_catalog.pg_namespace ofn ON ofn.oid = of.opfnamespace\n");
6785 
6786  if (access_method_pattern)
6787  if (!validateSQLNamePattern(&buf, access_method_pattern,
6788  false, false, NULL, "am.amname", NULL, NULL,
6789  &have_where, 1))
6790  goto error_return;
6791  if (type_pattern)
6792  {
6793  /* Match type name pattern against either internal or external name */
6794  if (!validateSQLNamePattern(&buf, type_pattern, have_where, false,
6795  "tn.nspname", "t.typname",
6796  "pg_catalog.format_type(t.oid, NULL)",
6797  "pg_catalog.pg_type_is_visible(t.oid)",
6798  NULL, 3))
6799  goto error_return;
6800  }
6801 
6802  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
6803  res = PSQLexec(buf.data);
6804  termPQExpBuffer(&buf);
6805  if (!res)
6806  return false;
6807 
6808  myopt.title = _("List of operator classes");
6809  myopt.translate_header = true;
6810  myopt.translate_columns = translate_columns;
6811  myopt.n_translate_columns = lengthof(translate_columns);
6812 
6813  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6814 
6815  PQclear(res);
6816  return true;
6817 
6818 error_return:
6819  termPQExpBuffer(&buf);
6820  return false;
6821 }

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

Referenced by exec_command_d().

◆ listOperatorFamilies()

bool listOperatorFamilies ( const char *  access_method_pattern,
const char *  type_pattern,
bool  verbose 
)

Definition at line 6830 of file describe.c.

6832 {
6834  PGresult *res;
6835  printQueryOpt myopt = pset.popt;
6836  bool have_where = false;
6837  static const bool translate_columns[] = {false, false, false, false};
6838 
6839  initPQExpBuffer(&buf);
6840 
6842  "SELECT\n"
6843  " am.amname AS \"%s\",\n"
6844  " CASE\n"
6845  " WHEN pg_catalog.pg_opfamily_is_visible(f.oid)\n"
6846  " THEN pg_catalog.format('%%I', f.opfname)\n"
6847  " ELSE pg_catalog.format('%%I.%%I', n.nspname, f.opfname)\n"
6848  " END AS \"%s\",\n"
6849  " (SELECT\n"
6850  " pg_catalog.string_agg(pg_catalog.format_type(oc.opcintype, NULL), ', ')\n"
6851  " FROM pg_catalog.pg_opclass oc\n"
6852  " WHERE oc.opcfamily = f.oid) \"%s\"",
6853  gettext_noop("AM"),
6854  gettext_noop("Operator family"),
6855  gettext_noop("Applicable types"));
6856  if (verbose)
6858  ",\n pg_catalog.pg_get_userbyid(f.opfowner) AS \"%s\"\n",
6859  gettext_noop("Owner"));
6861  "\nFROM pg_catalog.pg_opfamily f\n"
6862  " LEFT JOIN pg_catalog.pg_am am on am.oid = f.opfmethod\n"
6863  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace\n");
6864 
6865  if (access_method_pattern)
6866  if (!validateSQLNamePattern(&buf, access_method_pattern,
6867  false, false, NULL, "am.amname", NULL, NULL,
6868  &have_where, 1))
6869  goto error_return;
6870  if (type_pattern)
6871  {
6873  " %s EXISTS (\n"
6874  " SELECT 1\n"
6875  " FROM pg_catalog.pg_type t\n"
6876  " JOIN pg_catalog.pg_opclass oc ON oc.opcintype = t.oid\n"
6877  " LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n"
6878  " WHERE oc.opcfamily = f.oid\n",
6879  have_where ? "AND" : "WHERE");
6880  /* Match type name pattern against either internal or external name */
6881  if (!validateSQLNamePattern(&buf, type_pattern, true, false,
6882  "tn.nspname", "t.typname",
6883  "pg_catalog.format_type(t.oid, NULL)",
6884  "pg_catalog.pg_type_is_visible(t.oid)",
6885  NULL, 3))
6886  goto error_return;
6887  appendPQExpBufferStr(&buf, " )\n");
6888  }
6889 
6890  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
6891  res = PSQLexec(buf.data);
6892  termPQExpBuffer(&buf);
6893  if (!res)
6894  return false;
6895 
6896  myopt.title = _("List of operator families");
6897  myopt.translate_header = true;
6898  myopt.translate_columns = translate_columns;
6899  myopt.n_translate_columns = lengthof(translate_columns);
6900 
6901  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6902 
6903  PQclear(res);
6904  return true;
6905 
6906 error_return:
6907  termPQExpBuffer(&buf);
6908  return false;
6909 }

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

Referenced by exec_command_d().

◆ listOpFamilyFunctions()

bool listOpFamilyFunctions ( const char *  access_method_pattern,
const char *  family_pattern,
bool  verbose 
)

Definition at line 7017 of file describe.c.

7019 {
7021  PGresult *res;
7022  printQueryOpt myopt = pset.popt;
7023  bool have_where = false;
7024  static const bool translate_columns[] = {false, false, false, false, false, false};
7025 
7026  initPQExpBuffer(&buf);
7027 
7029  "SELECT\n"
7030  " am.amname AS \"%s\",\n"
7031  " CASE\n"
7032  " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
7033  " THEN pg_catalog.format('%%I', of.opfname)\n"
7034  " ELSE pg_catalog.format('%%I.%%I', ns.nspname, of.opfname)\n"
7035  " END AS \"%s\",\n"
7036  " pg_catalog.format_type(ap.amproclefttype, NULL) AS \"%s\",\n"
7037  " pg_catalog.format_type(ap.amprocrighttype, NULL) AS \"%s\",\n"
7038  " ap.amprocnum AS \"%s\"\n",
7039  gettext_noop("AM"),
7040  gettext_noop("Operator family"),
7041  gettext_noop("Registered left type"),
7042  gettext_noop("Registered right type"),
7043  gettext_noop("Number"));
7044 
7045  if (!verbose)
7047  ", p.proname AS \"%s\"\n",
7048  gettext_noop("Function"));
7049  else
7051  ", ap.amproc::pg_catalog.regprocedure AS \"%s\"\n",
7052  gettext_noop("Function"));
7053 
7055  "FROM pg_catalog.pg_amproc ap\n"
7056  " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = ap.amprocfamily\n"
7057  " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod\n"
7058  " LEFT JOIN pg_catalog.pg_namespace ns ON of.opfnamespace = ns.oid\n"
7059  " LEFT JOIN pg_catalog.pg_proc p ON ap.amproc = p.oid\n");
7060 
7061  if (access_method_pattern)
7062  {
7063  if (!validateSQLNamePattern(&buf, access_method_pattern,
7064  false, false, NULL, "am.amname",
7065  NULL, NULL,
7066  &have_where, 1))
7067  goto error_return;
7068  }
7069  if (family_pattern)
7070  {
7071  if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
7072  "ns.nspname", "of.opfname", NULL, NULL,
7073  NULL, 3))
7074  goto error_return;
7075  }
7076 
7077  appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
7078  " ap.amproclefttype = ap.amprocrighttype DESC,\n"
7079  " 3, 4, 5;");
7080 
7081  res = PSQLexec(buf.data);
7082  termPQExpBuffer(&buf);
7083  if (!res)
7084  return false;
7085 
7086  myopt.title = _("List of support functions of operator families");
7087  myopt.translate_header = true;
7088  myopt.translate_columns = translate_columns;
7089  myopt.n_translate_columns = lengthof(translate_columns);
7090 
7091  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7092 
7093  PQclear(res);
7094  return true;
7095 
7096 error_return:
7097  termPQExpBuffer(&buf);
7098  return false;
7099 }

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

Referenced by exec_command_d().

◆ listOpFamilyOperators()

bool listOpFamilyOperators ( const char *  access_method_pattern,
const char *  family_pattern,
bool  verbose 
)

Definition at line 6919 of file describe.c.

6921 {
6923  PGresult *res;
6924  printQueryOpt myopt = pset.popt;
6925  bool have_where = false;
6926 
6927  static const bool translate_columns[] = {false, false, false, false, false, false};
6928 
6929  initPQExpBuffer(&buf);
6930 
6932  "SELECT\n"
6933  " am.amname AS \"%s\",\n"
6934  " CASE\n"
6935  " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
6936  " THEN pg_catalog.format('%%I', of.opfname)\n"
6937  " ELSE pg_catalog.format('%%I.%%I', nsf.nspname, of.opfname)\n"
6938  " END AS \"%s\",\n"
6939  " o.amopopr::pg_catalog.regoperator AS \"%s\"\n,"
6940  " o.amopstrategy AS \"%s\",\n"
6941  " CASE o.amoppurpose\n"
6942  " WHEN 'o' THEN '%s'\n"
6943  " WHEN 's' THEN '%s'\n"
6944  " END AS \"%s\"\n",
6945  gettext_noop("AM"),
6946  gettext_noop("Operator family"),
6947  gettext_noop("Operator"),
6948  gettext_noop("Strategy"),
6949  gettext_noop("ordering"),
6950  gettext_noop("search"),
6951  gettext_noop("Purpose"));
6952 
6953  if (verbose)
6955  ", ofs.opfname AS \"%s\"\n",
6956  gettext_noop("Sort opfamily"));
6958  "FROM pg_catalog.pg_amop o\n"
6959  " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\n"
6960  " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod AND am.oid = o.amopmethod\n"
6961  " LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n");
6962  if (verbose)
6964  " LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n");
6965 
6966  if (access_method_pattern)
6967  {
6968  if (!validateSQLNamePattern(&buf, access_method_pattern,
6969  false, false, NULL, "am.amname",
6970  NULL, NULL,
6971  &have_where, 1))
6972  goto error_return;
6973  }
6974 
6975  if (family_pattern)
6976  {
6977  if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
6978  "nsf.nspname", "of.opfname", NULL, NULL,
6979  NULL, 3))
6980  goto error_return;
6981  }
6982 
6983  appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
6984  " o.amoplefttype = o.amoprighttype DESC,\n"
6985  " pg_catalog.format_type(o.amoplefttype, NULL),\n"
6986  " pg_catalog.format_type(o.amoprighttype, NULL),\n"
6987  " o.amopstrategy;");
6988 
6989  res = PSQLexec(buf.data);
6990  termPQExpBuffer(&buf);
6991  if (!res)
6992  return false;
6993 
6994  myopt.title = _("List of operators of operator families");
6995  myopt.translate_header = true;
6996  myopt.translate_columns = translate_columns;
6997  myopt.n_translate_columns = lengthof(translate_columns);
6998 
6999  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7000 
7001  PQclear(res);
7002  return true;
7003 
7004 error_return:
7005  termPQExpBuffer(&buf);
7006  return false;
7007 }

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

Referenced by exec_command_d().

◆ listPartitionedTables()

bool listPartitionedTables ( const char *  reltypes,
const char *  pattern,
bool  verbose 
)

Definition at line 4159 of file describe.c.

4160 {
4161  bool showTables = strchr(reltypes, 't') != NULL;
4162  bool showIndexes = strchr(reltypes, 'i') != NULL;
4163  bool showNested = strchr(reltypes, 'n') != NULL;
4165  PQExpBufferData title;
4166  PGresult *res;
4167  printQueryOpt myopt = pset.popt;
4168  bool translate_columns[] = {false, false, false, false, false, false, false, false, false};
4169  const char *tabletitle;
4170  bool mixed_output = false;
4171 
4172  /*
4173  * Note: Declarative table partitioning is only supported as of Pg 10.0.
4174  */
4175  if (pset.sversion < 100000)
4176  {
4177  char sverbuf[32];
4178 
4179  pg_log_error("The server (version %s) does not support declarative table partitioning.",
4181  sverbuf, sizeof(sverbuf)));
4182  return true;
4183  }
4184 
4185  /* If no relation kind was selected, show them all */
4186  if (!showTables && !showIndexes)
4187  showTables = showIndexes = true;
4188 
4189  if (showIndexes && !showTables)
4190  tabletitle = _("List of partitioned indexes"); /* \dPi */
4191  else if (showTables && !showIndexes)
4192  tabletitle = _("List of partitioned tables"); /* \dPt */
4193  else
4194  {
4195  /* show all kinds */
4196  tabletitle = _("List of partitioned relations");
4197  mixed_output = true;
4198  }
4199 
4200  initPQExpBuffer(&buf);
4201 
4203  "SELECT n.nspname as \"%s\",\n"
4204  " c.relname as \"%s\",\n"
4205  " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
4206  gettext_noop("Schema"),
4207  gettext_noop("Name"),
4208  gettext_noop("Owner"));
4209 
4210  if (mixed_output)
4211  {
4213  ",\n CASE c.relkind"
4214  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
4215  " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
4216  " END as \"%s\"",
4217  gettext_noop("partitioned table"),
4218  gettext_noop("partitioned index"),
4219  gettext_noop("Type"));
4220 
4221  translate_columns[3] = true;
4222  }
4223 
4224  if (showNested || pattern)
4226  ",\n inh.inhparent::pg_catalog.regclass as \"%s\"",
4227  gettext_noop("Parent name"));
4228 
4229  if (showIndexes)
4231  ",\n c2.oid::pg_catalog.regclass as \"%s\"",
4232  gettext_noop("Table"));
4233 
4234  if (verbose)
4235  {
4236  if (showNested)
4237  {
4239  ",\n s.dps as \"%s\"",
4240  gettext_noop("Leaf partition size"));
4242  ",\n s.tps as \"%s\"",
4243  gettext_noop("Total size"));
4244  }
4245  else
4246  /* Sizes of all partitions are considered in this case. */
4248  ",\n s.tps as \"%s\"",
4249  gettext_noop("Total size"));
4250 
4252  ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
4253  gettext_noop("Description"));
4254  }
4255 
4257  "\nFROM pg_catalog.pg_class c"
4258  "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
4259 
4260  if (showIndexes)
4262  "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
4263  "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
4264 
4265  if (showNested || pattern)
4267  "\n LEFT JOIN pg_catalog.pg_inherits inh ON c.oid = inh.inhrelid");
4268 
4269  if (verbose)
4270  {
4271  if (pset.sversion < 120000)
4272  {
4274  ",\n LATERAL (WITH RECURSIVE d\n"
4275  " AS (SELECT inhrelid AS oid, 1 AS level\n"
4276  " FROM pg_catalog.pg_inherits\n"
4277  " WHERE inhparent = c.oid\n"
4278  " UNION ALL\n"
4279  " SELECT inhrelid, level + 1\n"
4280  " FROM pg_catalog.pg_inherits i\n"
4281  " JOIN d ON i.inhparent = d.oid)\n"
4282  " SELECT pg_catalog.pg_size_pretty(sum(pg_catalog.pg_table_size("
4283  "d.oid))) AS tps,\n"
4284  " pg_catalog.pg_size_pretty(sum("
4285  "\n CASE WHEN d.level = 1"
4286  " THEN pg_catalog.pg_table_size(d.oid) ELSE 0 END)) AS dps\n"
4287  " FROM d) s");
4288  }
4289  else
4290  {
4291  /* PostgreSQL 12 has pg_partition_tree function */
4293  ",\n LATERAL (SELECT pg_catalog.pg_size_pretty(sum("
4294  "\n CASE WHEN ppt.isleaf AND ppt.level = 1"
4295  "\n THEN pg_catalog.pg_table_size(ppt.relid)"
4296  " ELSE 0 END)) AS dps"
4297  ",\n pg_catalog.pg_size_pretty(sum("
4298  "pg_catalog.pg_table_size(ppt.relid))) AS tps"
4299  "\n FROM pg_catalog.pg_partition_tree(c.oid) ppt) s");
4300  }
4301  }
4302 
4303  appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
4304  if (showTables)
4305  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
4306  if (showIndexes)
4307  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
4308  appendPQExpBufferStr(&buf, "''"); /* dummy */
4309  appendPQExpBufferStr(&buf, ")\n");
4310 
4311  appendPQExpBufferStr(&buf, !showNested && !pattern ?
4312  " AND NOT c.relispartition\n" : "");
4313 
4314  if (!pattern)
4315  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4316  " AND n.nspname !~ '^pg_toast'\n"
4317  " AND n.nspname <> 'information_schema'\n");
4318 
4319  if (!validateSQLNamePattern(&buf, pattern, true, false,
4320  "n.nspname", "c.relname", NULL,
4321  "pg_catalog.pg_table_is_visible(c.oid)",
4322  NULL, 3))
4323  {
4324  termPQExpBuffer(&buf);
4325  return false;
4326  }
4327 
4328  appendPQExpBuffer(&buf, "ORDER BY \"Schema\", %s%s\"Name\";",
4329  mixed_output ? "\"Type\" DESC, " : "",
4330  showNested || pattern ? "\"Parent name\" NULLS FIRST, " : "");
4331 
4332  res = PSQLexec(buf.data);
4333  termPQExpBuffer(&buf);
4334  if (!res)
4335  return false;
4336 
4337  initPQExpBuffer(&title);
4338  appendPQExpBufferStr(&title, tabletitle);
4339 
4340  myopt.title = title.data;
4341  myopt.translate_header = true;
4342  myopt.translate_columns = translate_columns;
4343  myopt.n_translate_columns = lengthof(translate_columns);
4344 
4345  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4346 
4347  termPQExpBuffer(&title);
4348 
4349  PQclear(res);
4350  return true;
4351 }

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

Referenced by exec_command_d().

◆ listPublications()

bool listPublications ( const char *  pattern)

Definition at line 6269 of file describe.c.

6270 {
6272  PGresult *res;
6273  printQueryOpt myopt = pset.popt;
6274  static const bool translate_columns[] = {false, false, false, false, false, false, false, false};
6275 
6276  if (pset.sversion < 100000)
6277  {
6278  char sverbuf[32];
6279 
6280  pg_log_error("The server (version %s) does not support publications.",
6282  sverbuf, sizeof(sverbuf)));
6283  return true;
6284  }
6285 
6286  initPQExpBuffer(&buf);
6287 
6289  "SELECT pubname AS \"%s\",\n"
6290  " pg_catalog.pg_get_userbyid(pubowner) AS \"%s\",\n"
6291  " puballtables AS \"%s\",\n"
6292  " pubinsert AS \"%s\",\n"
6293  " pubupdate AS \"%s\",\n"
6294  " pubdelete AS \"%s\"",
6295  gettext_noop("Name"),
6296  gettext_noop("Owner"),
6297  gettext_noop("All tables"),
6298  gettext_noop("Inserts"),
6299  gettext_noop("Updates"),
6300  gettext_noop("Deletes"));
6301  if (pset.sversion >= 110000)
6303  ",\n pubtruncate AS \"%s\"",
6304  gettext_noop("Truncates"));
6305  if (pset.sversion >= 130000)
6307  ",\n pubviaroot AS \"%s\"",
6308  gettext_noop("Via root"));
6309 
6311  "\nFROM pg_catalog.pg_publication\n");
6312 
6313  if (!validateSQLNamePattern(&buf, pattern, false, false,
6314  NULL, "pubname", NULL,
6315  NULL,
6316  NULL, 1))
6317  {
6318  termPQExpBuffer(&buf);
6319  return false;
6320  }
6321 
6322  appendPQExpBufferStr(&buf, "ORDER BY 1;");
6323 
6324  res = PSQLexec(buf.data);
6325  termPQExpBuffer(&buf);
6326  if (!res)
6327  return false;
6328 
6329  myopt.title = _("List of publications");
6330  myopt.translate_header = true;
6331  myopt.translate_columns = translate_columns;
6332  myopt.n_translate_columns = lengthof(translate_columns);
6333 
6334  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6335 
6336  PQclear(res);
6337 
6338  return true;
6339 }

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

Referenced by exec_command_d().

◆ listSchemas()

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

Definition at line 5078 of file describe.c.

5079 {
5081  PGresult *res;
5082  printQueryOpt myopt = pset.popt;
5083  int pub_schema_tuples = 0;
5084  char **footers = NULL;
5085 
5086  initPQExpBuffer(&buf);
5088  "SELECT n.nspname AS \"%s\",\n"
5089  " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
5090  gettext_noop("Name"),
5091  gettext_noop("Owner"));
5092 
5093  if (verbose)
5094  {
5095  appendPQExpBufferStr(&buf, ",\n ");
5096  printACLColumn(&buf, "n.nspacl");
5098  ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
5099  gettext_noop("Description"));
5100  }
5101 
5103  "\nFROM pg_catalog.pg_namespace n\n");
5104 
5105  if (!showSystem && !pattern)
5107  "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
5108 
5109  if (!validateSQLNamePattern(&buf, pattern,
5110  !showSystem && !pattern, false,
5111  NULL, "n.nspname", NULL,
5112  NULL,
5113  NULL, 2))
5114  goto error_return;
5115 
5116  appendPQExpBufferStr(&buf, "ORDER BY 1;");
5117 
5118  res = PSQLexec(buf.data);
5119  if (!res)
5120  goto error_return;
5121 
5122  myopt.title = _("List of schemas");
5123  myopt.translate_header = true;
5124 
5125  if (pattern && pset.sversion >= 150000)
5126  {
5127  PGresult *result;
5128  int i;
5129 
5131  "SELECT pubname \n"
5132  "FROM pg_catalog.pg_publication p\n"
5133  " JOIN pg_catalog.pg_publication_namespace pn ON p.oid = pn.pnpubid\n"
5134  " JOIN pg_catalog.pg_namespace n ON n.oid = pn.pnnspid \n"
5135  "WHERE n.nspname = '%s'\n"
5136  "ORDER BY 1",
5137  pattern);
5138  result = PSQLexec(buf.data);
5139  if (!result)
5140  goto error_return;
5141  else
5142  pub_schema_tuples = PQntuples(result);
5143 
5144  if (pub_schema_tuples > 0)
5145  {
5146  /*
5147  * Allocate memory for footers. Size of footers will be 1 (for
5148  * storing "Publications:" string) + publication schema mapping
5149  * count + 1 (for storing NULL).
5150  */
5151  footers = (char **) pg_malloc((1 + pub_schema_tuples + 1) * sizeof(char *));
5152  footers[0] = pg_strdup(_("Publications:"));
5153 
5154  /* Might be an empty set - that's ok */
5155  for (i = 0; i < pub_schema_tuples; i++)
5156  {
5157  printfPQExpBuffer(&buf, " \"%s\"",
5158  PQgetvalue(result, i, 0));
5159 
5160  footers[i + 1] = pg_strdup(buf.data);
5161  }
5162 
5163  footers[i + 1] = NULL;
5164  myopt.footers = footers;
5165  }
5166 
5167  PQclear(result);
5168  }
5169 
5170  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5171 
5172  termPQExpBuffer(&buf);
5173  PQclear(res);
5174 
5175  /* Free the memory allocated for the footer */
5176  if (footers)
5177  {
5178  char **footer = NULL;
5179 
5180  for (footer = footers; *footer; footer++)
5181  pg_free(*footer);
5182 
5183  pg_free(footers);
5184  }
5185 
5186  return true;
5187 
5188 error_return:
5189  termPQExpBuffer(&buf);
5190  return false;
5191 }
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, printQueryOpt::footers, gettext_noop, i, initPQExpBuffer(), _psqlSettings::logfile, pg_free(), pg_malloc(), pg_strdup(), _psqlSettings::popt, PQclear(), PQgetvalue(), PQntuples(), printACLColumn(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, res, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_header, validateSQLNamePattern(), and verbose.

Referenced by exec_command_d().

◆ listTables()

bool listTables ( const char *  tabtypes,
const char *  pattern,
bool  verbose,
bool  showSystem 
)

Definition at line 3961 of file describe.c.

3962 {
3963  bool showTables = strchr(tabtypes, 't') != NULL;
3964  bool showIndexes = strchr(tabtypes, 'i') != NULL;
3965  bool showViews = strchr(tabtypes, 'v') != NULL;
3966  bool showMatViews = strchr(tabtypes, 'm') != NULL;
3967  bool showSeq = strchr(tabtypes, 's') != NULL;
3968  bool showForeign = strchr(tabtypes, 'E') != NULL;
3969 
3971  PGresult *res;
3972  printQueryOpt myopt = pset.popt;
3973  int cols_so_far;
3974  bool translate_columns[] = {false, false, true, false, false, false, false, false, false};
3975 
3976  /* If tabtypes is empty, we default to \dtvmsE (but see also command.c) */
3977  if (!(showTables || showIndexes || showViews || showMatViews || showSeq || showForeign))
3978  showTables = showViews = showMatViews = showSeq = showForeign = true;
3979 
3980  initPQExpBuffer(&buf);
3981 
3983  "SELECT n.nspname as \"%s\",\n"
3984  " c.relname as \"%s\",\n"
3985  " CASE c.relkind"
3986  " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
3987  " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
3988  " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
3989  " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'"
3990  " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
3991  " WHEN " CppAsString2(RELKIND_TOASTVALUE) " THEN '%s'"
3992  " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
3993  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
3994  " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
3995  " END as \"%s\",\n"
3996  " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
3997  gettext_noop("Schema"),
3998  gettext_noop("Name"),
3999  gettext_noop("table"),
4000  gettext_noop("view"),
4001  gettext_noop("materialized view"),
4002  gettext_noop("index"),
4003  gettext_noop("sequence"),
4004  gettext_noop("TOAST table"),
4005  gettext_noop("foreign table"),
4006  gettext_noop("partitioned table"),
4007  gettext_noop("partitioned index"),
4008  gettext_noop("Type"),
4009  gettext_noop("Owner"));
4010  cols_so_far = 4;
4011 
4012  if (showIndexes)
4013  {
4015  ",\n c2.relname as \"%s\"",
4016  gettext_noop("Table"));
4017  cols_so_far++;
4018  }
4019 
4020  if (verbose)
4021  {
4022  /*
4023  * Show whether a relation is permanent, temporary, or unlogged.
4024  */
4026  ",\n CASE c.relpersistence WHEN 'p' THEN '%s' WHEN 't' THEN '%s' WHEN 'u' THEN '%s' END as \"%s\"",
4027  gettext_noop("permanent"),
4028  gettext_noop("temporary"),
4029  gettext_noop("unlogged"),
4030  gettext_noop("Persistence"));
4031  translate_columns[cols_so_far] = true;
4032 
4033  /*
4034  * We don't bother to count cols_so_far below here, as there's no need
4035  * to; this might change with future additions to the output columns.
4036  */
4037 
4038  /*
4039  * Access methods exist for tables, materialized views and indexes.
4040  * This has been introduced in PostgreSQL 12 for tables.
4041  */
4042  if (pset.sversion >= 120000 && !pset.hide_tableam &&
4043  (showTables || showMatViews || showIndexes))
4045  ",\n am.amname as \"%s\"",
4046  gettext_noop("Access method"));
4047 
4049  ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \"%s\""
4050  ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
4051  gettext_noop("Size"),
4052  gettext_noop("Description"));
4053  }
4054 
4056  "\nFROM pg_catalog.pg_class c"
4057  "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
4058 
4059  if (pset.sversion >= 120000 && !pset.hide_tableam &&
4060  (showTables || showMatViews || showIndexes))
4062  "\n LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam");
4063 
4064  if (showIndexes)
4066  "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
4067  "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
4068 
4069  appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
4070  if (showTables)
4071  {
4072  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_RELATION) ","
4073  CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
4074  /* with 'S' or a pattern, allow 't' to match TOAST tables too */
4075  if (showSystem || pattern)
4076  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_TOASTVALUE) ",");
4077  }
4078  if (showViews)
4079  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_VIEW) ",");
4080  if (showMatViews)
4081  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_MATVIEW) ",");
4082  if (showIndexes)
4083  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_INDEX) ","
4084  CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
4085  if (showSeq)
4086  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_SEQUENCE) ",");
4087  if (showSystem || pattern)
4088  appendPQExpBufferStr(&buf, "'s',"); /* was RELKIND_SPECIAL */
4089  if (showForeign)
4090  appendPQExpBufferStr(&buf, CppAsString2(RELKIND_FOREIGN_TABLE) ",");
4091 
4092  appendPQExpBufferStr(&buf, "''"); /* dummy */
4093  appendPQExpBufferStr(&buf, ")\n");
4094 
4095  if (!showSystem && !pattern)
4096  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4097  " AND n.nspname !~ '^pg_toast'\n"
4098  " AND n.nspname <> 'information_schema'\n");
4099 
4100  if (!validateSQLNamePattern(&buf, pattern, true, false,
4101  "n.nspname", "c.relname", NULL,
4102  "pg_catalog.pg_table_is_visible(c.oid)",
4103  NULL, 3))
4104  {
4105  termPQExpBuffer(&buf);
4106  return false;
4107  }
4108 
4109  appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
4110 
4111  res = PSQLexec(buf.data);
4112  termPQExpBuffer(&buf);
4113  if (!res)
4114  return false;
4115 
4116  /*
4117  * Most functions in this file are content to print an empty table when
4118  * there are no matching objects. We intentionally deviate from that
4119  * here, but only in !quiet mode, for historical reasons.
4120  */
4121  if (PQntuples(res) == 0 && !pset.quiet)
4122  {
4123  if (pattern)
4124  pg_log_error("Did not find any relation named \"%s\".",
4125  pattern);
4126  else
4127  pg_log_error("Did not find any relations.");
4128  }
4129  else
4130  {
4131  myopt.title = _("List of relations");
4132  myopt.translate_header = true;
4133  myopt.translate_columns = translate_columns;
4134  myopt.n_translate_columns = lengthof(translate_columns);
4135 
4136  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4137  }
4138 
4139  PQclear(res);
4140  return true;
4141 }

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, CppAsString2, gettext_noop, _psqlSettings::hide_tableam, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, pg_log_error, _psqlSettings::popt, PQclear(), PQntuples(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, _psqlSettings::quiet, res, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, validateSQLNamePattern(), and verbose.

Referenced by exec_command_d().

◆ listTSConfigs()

bool listTSConfigs ( const char *  pattern,
bool  verbose 
)

Definition at line 5576 of file describe.c.

5577 {
5579  PGresult *res;
5580  printQueryOpt myopt = pset.popt;
5581 
5582  if (verbose)
5583  return listTSConfigsVerbose(pattern);
5584 
5585  initPQExpBuffer(&buf);
5586 
5588  "SELECT\n"
5589  " n.nspname as \"%s\",\n"
5590  " c.cfgname as \"%s\",\n"
5591  " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
5592  "FROM pg_catalog.pg_ts_config c\n"
5593  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace\n",
5594  gettext_noop("Schema"),
5595  gettext_noop("Name"),
5596  gettext_noop("Description")
5597  );
5598 
5599  if (!validateSQLNamePattern(&buf, pattern, false, false,
5600  "n.nspname", "c.cfgname", NULL,
5601  "pg_catalog.pg_ts_config_is_visible(c.oid)",
5602  NULL, 3))
5603  {
5604  termPQExpBuffer(&buf);
5605  return false;
5606  }
5607 
5608  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5609 
5610  res = PSQLexec(buf.data);
5611  termPQExpBuffer(&buf);
5612  if (!res)
5613  return false;
5614 
5615  myopt.title = _("List of text search configurations");
5616  myopt.translate_header = true;
5617 
5618  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5619 
5620  PQclear(res);
5621  return true;
5622 }
static bool listTSConfigsVerbose(const char *pattern)
Definition: describe.c:5625

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

Referenced by exec_command_d().

◆ listTSConfigsVerbose()

static bool listTSConfigsVerbose ( const char *  pattern)
static

Definition at line 5625 of file describe.c.

5626 {
5628  PGresult *res;
5629  int i;
5630 
5631  initPQExpBuffer(&buf);
5632 
5634  "SELECT c.oid, c.cfgname,\n"
5635  " n.nspname,\n"
5636  " p.prsname,\n"
5637  " np.nspname as pnspname\n"
5638  "FROM pg_catalog.pg_ts_config c\n"
5639  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace,\n"
5640  " pg_catalog.pg_ts_parser p\n"
5641  " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace\n"
5642  "WHERE p.oid = c.cfgparser\n"
5643  );
5644 
5645  if (!validateSQLNamePattern(&buf, pattern, true, false,
5646  "n.nspname", "c.cfgname", NULL,
5647  "pg_catalog.pg_ts_config_is_visible(c.oid)",
5648  NULL, 3))
5649  {
5650  termPQExpBuffer(&buf);
5651  return false;
5652  }
5653 
5654  appendPQExpBufferStr(&buf, "ORDER BY 3, 2;");
5655 
5656  res = PSQLexec(buf.data);
5657  termPQExpBuffer(&buf);
5658  if (!res)
5659  return false;
5660 
5661  if (PQntuples(res) == 0)
5662  {
5663  if (!pset.quiet)
5664  {
5665  if (pattern)
5666  pg_log_error("Did not find any text search configuration named \"%s\".",
5667  pattern);
5668  else
5669  pg_log_error("Did not find any text search configurations.");
5670  }
5671  PQclear(res);
5672  return false;
5673  }
5674 
5675  for (i = 0; i < PQntuples(res); i++)
5676  {
5677  const char *oid;
5678  const char *cfgname;
5679  const char *nspname = NULL;
5680  const char *prsname;
5681  const char *pnspname = NULL;
5682 
5683  oid = PQgetvalue(res, i, 0);
5684  cfgname = PQgetvalue(res, i, 1);
5685  if (!PQgetisnull(res, i, 2))
5686  nspname = PQgetvalue(res, i, 2);
5687  prsname = PQgetvalue(res, i, 3);
5688  if (!PQgetisnull(res, i, 4))
5689  pnspname = PQgetvalue(res, i, 4);
5690 
5691  if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname))
5692  {
5693  PQclear(res);
5694  return false;
5695  }
5696 
5697  if (cancel_pressed)
5698  {
5699  PQclear(res);
5700  return false;
5701  }
5702  }
5703 
5704  PQclear(res);
5705  return true;
5706 }
static bool describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname, const char *pnspname, const char *prsname)
Definition: describe.c:5709

References appendPQExpBufferStr(), buf, cancel_pressed, describeOneTSConfig(), i, initPQExpBuffer(), pg_log_error, PQclear(), PQgetisnull(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), pset, PSQLexec(), _psqlSettings::quiet, res, termPQExpBuffer(), and validateSQLNamePattern().

Referenced by listTSConfigs().

◆ listTSDictionaries()

bool listTSDictionaries ( const char *  pattern,
bool  verbose 
)

Definition at line 5446 of file describe.c.

5447 {
5449  PGresult *res;
5450  printQueryOpt myopt = pset.popt;
5451 
5452  initPQExpBuffer(&buf);
5453 
5455  "SELECT\n"
5456  " n.nspname as \"%s\",\n"
5457  " d.dictname as \"%s\",\n",
5458  gettext_noop("Schema"),
5459  gettext_noop("Name"));
5460 
5461  if (verbose)
5462  {
5464  " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM\n"
5465  " pg_catalog.pg_ts_template t\n"
5466  " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace\n"
5467  " WHERE d.dicttemplate = t.oid ) AS \"%s\",\n"
5468  " d.dictinitoption as \"%s\",\n",
5469  gettext_noop("Template"),
5470  gettext_noop("Init options"));
5471  }
5472 
5474  " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
5475  gettext_noop("Description"));
5476 
5477  appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_dict d\n"
5478  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
5479 
5480  if (!validateSQLNamePattern(&buf, pattern, false, false,
5481  "n.nspname", "d.dictname", NULL,
5482  "pg_catalog.pg_ts_dict_is_visible(d.oid)",
5483  NULL, 3))
5484  {
5485  termPQExpBuffer(&buf);
5486  return false;
5487  }
5488 
5489  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5490 
5491  res = PSQLexec(buf.data);
5492  termPQExpBuffer(&buf);
5493  if (!res)
5494  return false;
5495 
5496  myopt.title = _("List of text search dictionaries");
5497  myopt.translate_header = true;
5498 
5499  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5500 
5501  PQclear(res);
5502  return true;
5503 }

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

Referenced by exec_command_d().

◆ listTSParsers()

bool listTSParsers ( const char *  pattern,
bool  verbose 
)

Definition at line 5199 of file describe.c.

5200 {
5202  PGresult *res;
5203  printQueryOpt myopt = pset.popt;
5204 
5205  if (verbose)
5206  return listTSParsersVerbose(pattern);
5207 
5208  initPQExpBuffer(&buf);
5209 
5211  "SELECT\n"
5212  " n.nspname as \"%s\",\n"
5213  " p.prsname as \"%s\",\n"
5214  " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
5215  "FROM pg_catalog.pg_ts_parser p\n"
5216  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
5217  gettext_noop("Schema"),
5218  gettext_noop("Name"),
5219  gettext_noop("Description")
5220  );
5221 
5222  if (!validateSQLNamePattern(&buf, pattern, false, false,
5223  "n.nspname", "p.prsname", NULL,
5224  "pg_catalog.pg_ts_parser_is_visible(p.oid)",
5225  NULL, 3))
5226  {
5227  termPQExpBuffer(&buf);
5228  return false;
5229  }
5230 
5231  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5232 
5233  res = PSQLexec(buf.data);
5234  termPQExpBuffer(&buf);
5235  if (!res)
5236  return false;
5237 
5238  myopt.title = _("List of text search parsers");
5239  myopt.translate_header = true;
5240 
5241  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5242 
5243  PQclear(res);
5244  return true;
5245 }
static bool listTSParsersVerbose(const char *pattern)
Definition: describe.c:5251

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

Referenced by exec_command_d().

◆ listTSParsersVerbose()

static bool listTSParsersVerbose ( const char *  pattern)
static

Definition at line 5251 of file describe.c.

5252 {
5254  PGresult *res;
5255  int i;
5256 
5257  initPQExpBuffer(&buf);
5258 
5260  "SELECT p.oid,\n"
5261  " n.nspname,\n"
5262  " p.prsname\n"
5263  "FROM pg_catalog.pg_ts_parser p\n"
5264  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
5265  );
5266 
5267  if (!validateSQLNamePattern(&buf, pattern, false, false,
5268  "n.nspname", "p.prsname", NULL,
5269  "pg_catalog.pg_ts_parser_is_visible(p.oid)",
5270  NULL, 3))
5271  {
5272  termPQExpBuffer(&buf);
5273  return false;
5274  }
5275 
5276  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5277 
5278  res = PSQLexec(buf.data);
5279  termPQExpBuffer(&buf);
5280  if (!res)
5281  return false;
5282 
5283  if (PQntuples(res) == 0)
5284  {
5285  if (!pset.quiet)
5286  {
5287  if (pattern)
5288  pg_log_error("Did not find any text search parser named \"%s\".",
5289  pattern);
5290  else
5291  pg_log_error("Did not find any text search parsers.");
5292  }
5293  PQclear(res);
5294  return false;
5295  }
5296 
5297  for (i = 0; i < PQntuples(res); i++)
5298  {
5299  const char *oid;
5300  const char *nspname = NULL;
5301  const char *prsname;
5302 
5303  oid = PQgetvalue(res, i, 0);
5304  if (!PQgetisnull(res, i, 1))
5305  nspname = PQgetvalue(res, i, 1);
5306  prsname = PQgetvalue(res, i, 2);
5307 
5308  if (!describeOneTSParser(oid, nspname, prsname))
5309  {
5310  PQclear(res);
5311  return false;
5312  }
5313 
5314  if (cancel_pressed)
5315  {
5316  PQclear(res);
5317  return false;
5318  }
5319  }
5320 
5321  PQclear(res);
5322  return true;
5323 }
static bool describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
Definition: describe.c:5326

References appendPQExpBufferStr(), buf, cancel_pressed, describeOneTSParser(), i, initPQExpBuffer(), pg_log_error, PQclear(), PQgetisnull(), PQgetvalue(), PQntuples(), printfPQExpBuffer(), pset, PSQLexec(), _psqlSettings::quiet, res, termPQExpBuffer(), and validateSQLNamePattern().

Referenced by listTSParsers().

◆ listTSTemplates()

bool listTSTemplates ( const char *  pattern,
bool  verbose 
)

Definition at line 5511 of file describe.c.

5512 {
5514  PGresult *res;
5515  printQueryOpt myopt = pset.popt;
5516 
5517  initPQExpBuffer(&buf);
5518 
5519  if (verbose)
5521  "SELECT\n"
5522  " n.nspname AS \"%s\",\n"
5523  " t.tmplname AS \"%s\",\n"
5524  " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
5525  " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
5526  " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
5527  gettext_noop("Schema"),
5528  gettext_noop("Name"),
5529  gettext_noop("Init"),
5530  gettext_noop("Lexize"),
5531  gettext_noop("Description"));
5532  else
5534  "SELECT\n"
5535  " n.nspname AS \"%s\",\n"
5536  " t.tmplname AS \"%s\",\n"
5537  " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
5538  gettext_noop("Schema"),
5539  gettext_noop("Name"),
5540  gettext_noop("Description"));
5541 
5542  appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_template t\n"
5543  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
5544 
5545  if (!validateSQLNamePattern(&buf, pattern, false, false,
5546  "n.nspname", "t.tmplname", NULL,
5547  "pg_catalog.pg_ts_template_is_visible(t.oid)",
5548  NULL, 3))
5549  {
5550  termPQExpBuffer(&buf);
5551  return false;
5552  }
5553 
5554  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5555 
5556  res = PSQLexec(buf.data);
5557  termPQExpBuffer(&buf);
5558  if (!res)
5559  return false;
5560 
5561  myopt.title = _("List of text search templates");
5562  myopt.translate_header = true;
5563 
5564  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5565 
5566  PQclear(res);
5567  return true;
5568 }

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

Referenced by exec_command_d().

◆ listUserMappings()

bool listUserMappings ( const char *  pattern,
bool  verbose 
)

Definition at line 5927 of file describe.c.

5928 {
5930  PGresult *res;
5931  printQueryOpt myopt = pset.popt;
5932 
5933  initPQExpBuffer(&buf);
5935  "SELECT um.srvname AS \"%s\",\n"
5936  " um.usename AS \"%s\"",
5937  gettext_noop("Server"),
5938  gettext_noop("User name"));
5939 
5940  if (verbose)
5942  ",\n CASE WHEN umoptions IS NULL THEN '' ELSE "
5943  " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5944  " pg_catalog.quote_ident(option_name) || ' ' || "
5945  " pg_catalog.quote_literal(option_value) FROM "
5946  " pg_catalog.pg_options_to_table(umoptions)), ', ') || ')' "
5947  " END AS \"%s\"",
5948  gettext_noop("FDW options"));
5949 
5950  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
5951 
5952  if (!validateSQLNamePattern(&buf, pattern, false, false,
5953  NULL, "um.srvname", "um.usename", NULL,
5954  NULL, 1))
5955  {
5956  termPQExpBuffer(&buf);
5957  return false;
5958  }
5959 
5960  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5961 
5962  res = PSQLexec(buf.data);
5963  termPQExpBuffer(&buf);
5964  if (!res)
5965  return false;
5966 
5967  myopt.title = _("List of user mappings");
5968  myopt.translate_header = true;
5969 
5970  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5971 
5972  PQclear(res);
5973  return true;
5974 }

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

Referenced by exec_command_d().

◆ map_typename_pattern()

static const char * map_typename_pattern ( const char *  pattern)
static

Definition at line 720 of file describe.c.

721 {
722  static const char *const typename_map[] = {
723  /*
724  * These names are accepted by gram.y, although they are neither the
725  * "real" name seen in pg_type nor the canonical name printed by
726  * format_type().
727  */
728  "decimal", "numeric",
729  "float", "double precision",
730  "int", "integer",
731 
732  /*
733  * We also have to map the array names for cases where the canonical
734  * name is different from what pg_type says.
735  */
736  "bool[]", "boolean[]",
737  "decimal[]", "numeric[]",
738  "float[]", "double precision[]",
739  "float4[]", "real[]",
740  "float8[]", "double precision[]",
741  "int[]", "integer[]",
742  "int2[]", "smallint[]",
743  "int4[]", "integer[]",
744  "int8[]", "bigint[]",
745  "time[]", "time without time zone[]",
746  "timetz[]", "time with time zone[]",
747  "timestamp[]", "timestamp without time zone[]",
748  "timestamptz[]", "timestamp with time zone[]",
749  "varbit[]", "bit varying[]",
750  "varchar[]", "character varying[]",
751  NULL
752  };
753 
754  if (pattern == NULL)
755  return NULL;
756  for (int i = 0; typename_map[i] != NULL; i += 2)
757  {
758  if (pg_strcasecmp(pattern, typename_map[i]) == 0)
759  return typename_map[i + 1];
760  }
761  return pattern;
762 }
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

References i, and pg_strcasecmp().

Referenced by describeFunctions(), describeOperators(), and describeTypes().

◆ objectDescription()

bool objectDescription ( const char *  pattern,
bool  showSystem 
)

Definition at line 1252 of file describe.c.

1253 {
1255  PGresult *res;
1256  printQueryOpt myopt = pset.popt;
1257  static const bool translate_columns[] = {false, false, true, false};
1258 
1259  initPQExpBuffer(&buf);
1260 
1262  "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
1263  "FROM (\n",
1264  gettext_noop("Schema"),
1265  gettext_noop("Name"),
1266  gettext_noop("Object"),
1267  gettext_noop("Description"));
1268 
1269  /* Table constraint descriptions */
1271  " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1272  " n.nspname as nspname,\n"
1273  " CAST(pgc.conname AS pg_catalog.text) as name,"
1274  " CAST('%s' AS pg_catalog.text) as object\n"
1275  " FROM pg_catalog.pg_constraint pgc\n"
1276  " JOIN pg_catalog.pg_class c "
1277  "ON c.oid = pgc.conrelid\n"
1278  " LEFT JOIN pg_catalog.pg_namespace n "
1279  " ON n.oid = c.relnamespace\n",
1280  gettext_noop("table constraint"));
1281 
1282  if (!showSystem && !pattern)
1283  appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1284  " AND n.nspname <> 'information_schema'\n");
1285 
1286  if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern,
1287  false, "n.nspname", "pgc.conname", NULL,
1288  "pg_catalog.pg_table_is_visible(c.oid)",
1289  NULL, 3))
1290  goto error_return;
1291 
1292  /* Domain constraint descriptions */
1294  "UNION ALL\n"
1295  " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1296  " n.nspname as nspname,\n"
1297  " CAST(pgc.conname AS pg_catalog.text) as name,"
1298  " CAST('%s' AS pg_catalog.text) as object\n"
1299  " FROM pg_catalog.pg_constraint pgc\n"
1300  " JOIN pg_catalog.pg_type t "
1301  "ON t.oid = pgc.contypid\n"
1302  " LEFT JOIN pg_catalog.pg_namespace n "
1303  " ON n.oid = t.typnamespace\n",
1304  gettext_noop("domain constraint"));
1305 
1306  if (!showSystem && !pattern)
1307  appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1308  " AND n.nspname <> 'information_schema'\n");
1309 
1310  if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern,
1311  false, "n.nspname", "pgc.conname", NULL,
1312  "pg_catalog.pg_type_is_visible(t.oid)",
1313  NULL, 3))
1314  goto error_return;
1315 
1316  /* Operator class descriptions */
1318  "UNION ALL\n"
1319  " SELECT o.oid as oid, o.tableoid as tableoid,\n"
1320  " n.nspname as nspname,\n"
1321  " CAST(o.opcname AS pg_catalog.text) as name,\n"
1322  " CAST('%s' AS pg_catalog.text) as object\n"
1323  " FROM pg_catalog.pg_opclass o\n"
1324  " JOIN pg_catalog.pg_am am ON "
1325  "o.opcmethod = am.oid\n"
1326  " JOIN pg_catalog.pg_namespace n ON "
1327  "n.oid = o.opcnamespace\n",
1328  gettext_noop("operator class"));
1329 
1330  if (!showSystem && !pattern)
1331  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1332  " AND n.nspname <> 'information_schema'\n");
1333 
1334  if (!validateSQLNamePattern(&buf, pattern, true, false,
1335  "n.nspname", "o.opcname", NULL,
1336  "pg_catalog.pg_opclass_is_visible(o.oid)",
1337  NULL, 3))
1338  goto error_return;
1339 
1340  /* Operator family descriptions */
1342  "UNION ALL\n"
1343  " SELECT opf.oid as oid, opf.tableoid as tableoid,\n"
1344  " n.nspname as nspname,\n"
1345  " CAST(opf.opfname AS pg_catalog.text) AS name,\n"
1346  " CAST('%s' AS pg_catalog.text) as object\n"
1347  " FROM pg_catalog.pg_opfamily opf\n"
1348  " JOIN pg_catalog.pg_am am "
1349  "ON opf.opfmethod = am.oid\n"
1350  " JOIN pg_catalog.pg_namespace n "
1351  "ON opf.opfnamespace = n.oid\n",
1352  gettext_noop("operator family"));
1353 
1354  if (!showSystem && !pattern)
1355  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1356  " AND n.nspname <> 'information_schema'\n");
1357 
1358  if (!validateSQLNamePattern(&buf, pattern, true, false,
1359  "n.nspname", "opf.opfname", NULL,
1360  "pg_catalog.pg_opfamily_is_visible(opf.oid)",
1361  NULL, 3))
1362  goto error_return;
1363 
1364  /* Rule descriptions (ignore rules for views) */
1366  "UNION ALL\n"
1367  " SELECT r.oid as oid, r.tableoid as tableoid,\n"
1368  " n.nspname as nspname,\n"
1369  " CAST(r.rulename AS pg_catalog.text) as name,"
1370  " CAST('%s' AS pg_catalog.text) as object\n"
1371  " FROM pg_catalog.pg_rewrite r\n"
1372  " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
1373  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
1374  " WHERE r.rulename != '_RETURN'\n",
1375  gettext_noop("rule"));
1376 
1377  if (!showSystem && !pattern)
1378  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1379  " AND n.nspname <> 'information_schema'\n");
1380 
1381  if (!validateSQLNamePattern(&buf, pattern, true, false,
1382  "n.nspname", "r.rulename", NULL,
1383  "pg_catalog.pg_table_is_visible(c.oid)",
1384  NULL, 3))
1385  goto error_return;
1386 
1387  /* Trigger descriptions */
1389  "UNION ALL\n"
1390  " SELECT t.oid as oid, t.tableoid as tableoid,\n"
1391  " n.nspname as nspname,\n"
1392  " CAST(t.tgname AS pg_catalog.text) as name,"
1393  " CAST('%s' AS pg_catalog.text) as object\n"
1394  " FROM pg_catalog.pg_trigger t\n"
1395  " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
1396  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
1397  gettext_noop("trigger"));
1398 
1399  if (!showSystem && !pattern)
1400  appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1401  " AND n.nspname <> 'information_schema'\n");
1402 
1403  if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, false,
1404  "n.nspname", "t.tgname", NULL,
1405  "pg_catalog.pg_table_is_visible(c.oid)",
1406  NULL, 3))
1407  goto error_return;
1408 
1410  ") AS tt\n"
1411  " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
1412 
1413  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1414 
1415  res = PSQLexec(buf.data);
1416  termPQExpBuffer(&buf);
1417  if (!res)
1418  return false;
1419 
1420  myopt.title = _("Object descriptions");
1421  myopt.translate_header = true;
1422  myopt.translate_columns = translate_columns;
1423  myopt.n_translate_columns = lengthof(translate_columns);
1424 
1425  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1426 
1427  PQclear(res);
1428  return true;
1429 
1430 error_return:
1431  termPQExpBuffer(&buf);
1432  return false;
1433 }

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

Referenced by exec_command_d().

◆ permissionsList()

bool permissionsList ( const char *  pattern,
bool  showSystem 
)

Definition at line 1011 of file describe.c.

1012 {
1014  PGresult *res;
1015  printQueryOpt myopt = pset.popt;
1016  static const bool translate_columns[] = {false, false, true, false, false, false};
1017 
1018  initPQExpBuffer(&buf);
1019 
1020  /*
1021  * we ignore indexes and toast tables since they have no meaningful rights
1022  */
1024  "SELECT n.nspname as \"%s\",\n"
1025  " c.relname as \"%s\",\n"
1026  " CASE c.relkind"
1027  " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
1028  " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
1029  " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
1030  " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
1031  " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
1032  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
1033  " END as \"%s\",\n"
1034  " ",
1035  gettext_noop("Schema"),
1036  gettext_noop("Name"),
1037  gettext_noop("table"),
1038  gettext_noop("view"),
1039  gettext_noop("materialized view"),
1040  gettext_noop("sequence"),
1041  gettext_noop("foreign table"),
1042  gettext_noop("partitioned table"),
1043  gettext_noop("Type"));
1044 
1045  printACLColumn(&buf, "c.relacl");
1046 
1047  /*
1048  * The formatting of attacl should match printACLColumn(). However, we
1049  * need no special case for an empty attacl, because the backend always
1050  * optimizes that back to NULL.
1051  */
1053  ",\n pg_catalog.array_to_string(ARRAY(\n"
1054  " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
1055  " FROM pg_catalog.pg_attribute a\n"
1056  " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
1057  " ), E'\\n') AS \"%s\"",
1058  gettext_noop("Column privileges"));
1059 
1060  if (pset.sversion >= 90500 && pset.sversion < 100000)
1062  ",\n pg_catalog.array_to_string(ARRAY(\n"
1063  " SELECT polname\n"
1064  " || CASE WHEN polcmd != '*' THEN\n"
1065  " E' (' || polcmd::pg_catalog.text || E'):'\n"
1066  " ELSE E':'\n"
1067  " END\n"
1068  " || CASE WHEN polqual IS NOT NULL THEN\n"
1069  " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
1070  " ELSE E''\n"
1071  " END\n"
1072  " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
1073  " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
1074  " ELSE E''\n"
1075  " END"
1076  " || CASE WHEN polroles <> '{0}' THEN\n"
1077  " E'\\n to: ' || pg_catalog.array_to_string(\n"
1078  " ARRAY(\n"
1079  " SELECT rolname\n"
1080  " FROM pg_catalog.pg_roles\n"
1081  " WHERE oid = ANY (polroles)\n"
1082  " ORDER BY 1\n"
1083  " ), E', ')\n"
1084  " ELSE E''\n"
1085  " END\n"
1086  " FROM pg_catalog.pg_policy pol\n"
1087  " WHERE polrelid = c.oid), E'\\n')\n"
1088  " AS \"%s\"",
1089  gettext_noop("Policies"));
1090 
1091  if (pset.sversion >= 100000)
1093  ",\n pg_catalog.array_to_string(ARRAY(\n"
1094  " SELECT polname\n"
1095  " || CASE WHEN NOT polpermissive THEN\n"
1096  " E' (RESTRICTIVE)'\n"
1097  " ELSE '' END\n"
1098  " || CASE WHEN polcmd != '*' THEN\n"
1099  " E' (' || polcmd::pg_catalog.text || E'):'\n"
1100  " ELSE E':'\n"
1101  " END\n"
1102  " || CASE WHEN polqual IS NOT NULL THEN\n"
1103  " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
1104  " ELSE E''\n"
1105  " END\n"
1106  " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
1107  " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
1108  " ELSE E''\n"
1109  " END"
1110  " || CASE WHEN polroles <> '{0}' THEN\n"
1111  " E'\\n to: ' || pg_catalog.array_to_string(\n"
1112  " ARRAY(\n"
1113  " SELECT rolname\n"
1114  " FROM pg_catalog.pg_roles\n"
1115  " WHERE oid = ANY (polroles)\n"
1116  " ORDER BY 1\n"
1117  " ), E', ')\n"
1118  " ELSE E''\n"
1119  " END\n"
1120  " FROM pg_catalog.pg_policy pol\n"
1121  " WHERE polrelid = c.oid), E'\\n')\n"
1122  " AS \"%s\"",
1123  gettext_noop("Policies"));
1124 
1125  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_class c\n"
1126  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
1127  "WHERE c.relkind IN ("
1128  CppAsString2(RELKIND_RELATION) ","
1129  CppAsString2(RELKIND_VIEW) ","
1130  CppAsString2(RELKIND_MATVIEW) ","
1131  CppAsString2(RELKIND_SEQUENCE) ","
1132  CppAsString2(RELKIND_FOREIGN_TABLE) ","
1133  CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
1134 
1135  if (!showSystem && !pattern)
1136  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1137  " AND n.nspname <> 'information_schema'\n");
1138 
1139  if (!validateSQLNamePattern(&buf, pattern, true, false,
1140  "n.nspname", "c.relname", NULL,
1141  "pg_catalog.pg_table_is_visible(c.oid)",
1142  NULL, 3))
1143  goto error_return;
1144 
1145  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
1146 
1147  res = PSQLexec(buf.data);
1148  if (!res)
1149  goto error_return;
1150 
1151  printfPQExpBuffer(&buf, _("Access privileges"));
1152  myopt.title = buf.data;
1153  myopt.translate_header = true;
1154  myopt.translate_columns = translate_columns;
1155  myopt.n_translate_columns = lengthof(translate_columns);
1156 
1157  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1158 
1159  termPQExpBuffer(&buf);
1160  PQclear(res);
1161  return true;
1162 
1163 error_return:
1164  termPQExpBuffer(&buf);
1165  return false;
1166 }

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

Referenced by exec_command_d(), and exec_command_z().

◆ printACLColumn()

static void printACLColumn ( PQExpBuffer  buf,
const char *  colname 
)
static

Definition at line 6711 of file describe.c.

6712 {
6714  "CASE"
6715  " WHEN pg_catalog.cardinality(%s) = 0 THEN '%s'"
6716  " ELSE pg_catalog.array_to_string(%s, E'\\n')"
6717  " END AS \"%s\"",
6718  colname, gettext_noop("(none)"),
6719  colname, gettext_noop("Access privileges"));
6720 }

References appendPQExpBuffer(), buf, and gettext_noop.

Referenced by describeConfigurationParameters(), describeFunctions(), describeTablespaces(), describeTypes(), listAllDbs(), listDefaultACLs(), listDomains(), listForeignDataWrappers(), listForeignServers(), listLanguages(), listLargeObjects(), listSchemas(), and permissionsList().

◆ validateSQLNamePattern()

static bool validateSQLNamePattern ( PQExpBuffer  buf,
const char *  pattern,
bool  have_where,
bool  force_escape,
const char *  schemavar,
const char *  namevar,
const char *  altnamevar,
const char *  visibilityrule,
bool added_clause,
int  maxparts 
)
static

Definition at line 6216 of file describe.c.

6221 {
6222  PQExpBufferData dbbuf;
6223  int dotcnt;
6224  bool added;
6225 
6226  initPQExpBuffer(&dbbuf);
6227  added = processSQLNamePattern(pset.db, buf, pattern, have_where, force_escape,
6228  schemavar, namevar, altnamevar,
6229  visibilityrule, &dbbuf, &dotcnt);
6230  if (added_clause != NULL)
6231  *added_clause = added;
6232 
6233  if (dotcnt >= maxparts)
6234  {
6235  pg_log_error("improper qualified name (too many dotted names): %s",
6236  pattern);
6237  goto error_return;
6238  }
6239 
6240  if (maxparts > 1 && dotcnt == maxparts - 1)
6241  {
6242  if (PQdb(pset.db) == NULL)
6243  {
6244  pg_log_error("You are currently not connected to a database.");
6245  goto error_return;
6246  }
6247  if (strcmp(PQdb(pset.db), dbbuf.data) != 0)
6248  {
6249  pg_log_error("cross-database references are not implemented: %s",
6250  pattern);
6251  goto error_return;
6252  }
6253  }
6254  termPQExpBuffer(&dbbuf);
6255  return true;
6256 
6257 error_return:
6258  termPQExpBuffer(&dbbuf);
6259  return false;
6260 }
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6794

References buf, PQExpBufferData::data, _psqlSettings::db, initPQExpBuffer(), pg_log_error, PQdb(), processSQLNamePattern(), pset, and termPQExpBuffer().

Referenced by describeAccessMethods(), describeAggregates(), describeFunctions(), describeOperators(), describePublications(), describeRoleGrants(), describeRoles(), describeSubscriptions(), describeTableDetails(), describeTablespaces(), describeTypes(), listAllDbs(), listCasts(), listCollations(), listConversions(), listDbRoleSettings(), listDefaultACLs(), listDomains(), listEventTriggers(), listExtendedStats(), listExtensionContents(), listExtensions(), listForeignDataWrappers(), listForeignServers(), listForeignTables(), listLanguages(), listOperatorClasses(), listOperatorFamilies(), listOpFamilyFunctions(), listOpFamilyOperators(), listPartitionedTables(), listPublications(), listSchemas(), listTables(), listTSConfigs(), listTSConfigsVerbose(), listTSDictionaries(), listTSParsers(), listTSParsersVerbose(), listTSTemplates(), listUserMappings(), objectDescription(), and permissionsList().