PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 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 3796 of file describe.c.

3797 {
3798  if (buf->len > 0)
3799  appendPQExpBufferStr(buf, ", ");
3800 
3802 }
const char * str
static char * buf
Definition: pg_test_fsync.c:72
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367

References appendPQExpBufferStr(), buf, and 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 3596 of file describe.c.

3598 {
3599  /* relkinds for which we support tablespaces */
3600  if (relkind == RELKIND_RELATION ||
3601  relkind == RELKIND_MATVIEW ||
3602  relkind == RELKIND_INDEX ||
3603  relkind == RELKIND_PARTITIONED_TABLE ||
3604  relkind == RELKIND_PARTITIONED_INDEX ||
3605  relkind == RELKIND_TOASTVALUE)
3606  {
3607  /*
3608  * We ignore the database default tablespace so that users not using
3609  * tablespaces don't need to know about them.
3610  */
3611  if (tablespace != 0)
3612  {
3613  PGresult *result = NULL;
3615 
3616  initPQExpBuffer(&buf);
3618  "SELECT spcname FROM pg_catalog.pg_tablespace\n"
3619  "WHERE oid = '%u';", tablespace);
3620  result = PSQLexec(buf.data);
3621  if (!result)
3622  {
3623  termPQExpBuffer(&buf);
3624  return;
3625  }
3626  /* Should always be the case, but.... */
3627  if (PQntuples(result) > 0)
3628  {
3629  if (newline)
3630  {
3631  /* Add the tablespace as a new footer */
3632  printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
3633  PQgetvalue(result, 0, 0));
3634  printTableAddFooter(cont, buf.data);
3635  }
3636  else
3637  {
3638  /* Append the tablespace to the latest footer */
3639  printfPQExpBuffer(&buf, "%s", cont->footer->data);
3640 
3641  /*-------
3642  translator: before this string there's an index description like
3643  '"foo_pkey" PRIMARY KEY, btree (a)' */
3644  appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
3645  PQgetvalue(result, 0, 0));
3646  printTableSetFooter(cont, buf.data);
3647  }
3648  }
3649  PQclear(result);
3650  termPQExpBuffer(&buf);
3651  }
3652  }
3653 }
PGresult * PSQLexec(const char *query)
Definition: common.c:620
#define _(x)
Definition: elog.c:90
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3481
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3876
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
static 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 6354 of file describe.c.

6356 {
6357  PGresult *res;
6358  int count = 0;
6359  int i = 0;
6360 
6361  res = PSQLexec(buf->data);
6362  if (!res)
6363  return false;
6364  else
6365  count = PQntuples(res);
6366 
6367  if (count > 0)
6368  printTableAddFooter(cont, footermsg);
6369 
6370  for (i = 0; i < count; i++)
6371  {
6372  if (as_schema)
6373  printfPQExpBuffer(buf, " \"%s\"", PQgetvalue(res, i, 0));
6374  else
6375  {
6376  printfPQExpBuffer(buf, " \"%s.%s\"", PQgetvalue(res, i, 0),
6377  PQgetvalue(res, i, 1));
6378 
6379  if (!PQgetisnull(res, i, 3))
6380  appendPQExpBuffer(buf, " (%s)", PQgetvalue(res, i, 3));
6381 
6382  if (!PQgetisnull(res, i, 2))
6383  appendPQExpBuffer(buf, " WHERE %s", PQgetvalue(res, i, 2));
6384  }
6385 
6386  printTableAddFooter(cont, buf->data);
6387  }
6388 
6389  PQclear(res);
6390  return true;
6391 }
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3901
int i
Definition: isn.c:72

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

141 {
143  PGresult *res;
144  printQueryOpt myopt = pset.popt;
145  static const bool translate_columns[] = {false, true, false, false};
146 
147  if (pset.sversion < 90600)
148  {
149  char sverbuf[32];
150 
151  pg_log_error("The server (version %s) does not support access methods.",
153  sverbuf, sizeof(sverbuf)));
154  return true;
155  }
156 
158 
160  "SELECT amname AS \"%s\",\n"
161  " CASE amtype"
162  " WHEN 'i' THEN '%s'"
163  " WHEN 't' THEN '%s'"
164  " END AS \"%s\"",
165  gettext_noop("Name"),
166  gettext_noop("Index"),
167  gettext_noop("Table"),
168  gettext_noop("Type"));
169 
170  if (verbose)
171  {
173  ",\n amhandler AS \"%s\",\n"
174  " pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
175  gettext_noop("Handler"),
176  gettext_noop("Description"));
177  }
178 
180  "\nFROM pg_catalog.pg_am\n");
181 
182  if (!validateSQLNamePattern(&buf, pattern, false, false,
183  NULL, "amname", NULL,
184  NULL,
185  NULL, 1))
186  {
188  return false;
189  }
190 
191  appendPQExpBufferStr(&buf, "ORDER BY 1;");
192 
193  res = PSQLexec(buf.data);
195  if (!res)
196  return false;
197 
198  myopt.title = _("List of access methods");
199  myopt.translate_header = true;
200  myopt.translate_columns = translate_columns;
201  myopt.n_translate_columns = lengthof(translate_columns);
202 
203  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
204 
205  PQclear(res);
206  return true;
207 }
#define gettext_noop(x)
Definition: c.h:1201
#define lengthof(array)
Definition: c.h:793
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:6221
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:100
FILE * logfile
Definition: settings.h:131
FILE * queryFout
Definition: settings.h:93
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 70 of file describe.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

7128 {
7130  PGresult *res;
7131  printQueryOpt myopt = pset.popt;
7132 
7133  initPQExpBuffer(&buf);
7134 
7136  "SELECT oid as \"%s\",\n"
7137  " pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n ",
7138  gettext_noop("ID"),
7139  gettext_noop("Owner"));
7140 
7141  if (verbose)
7142  {
7143  printACLColumn(&buf, "lomacl");
7144  appendPQExpBufferStr(&buf, ",\n ");
7145  }
7146 
7148  "pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n"
7149  "FROM pg_catalog.pg_largeobject_metadata\n"
7150  "ORDER BY oid",
7151  gettext_noop("Description"));
7152 
7153  res = PSQLexec(buf.data);
7154  termPQExpBuffer(&buf);
7155  if (!res)
7156  return false;
7157 
7158  myopt.title = _("Large objects");
7159  myopt.translate_header = true;
7160 
7161  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7162 
7163  PQclear(res);
7164  return true;
7165 }

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

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

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

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

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

6853 {
6855  PGresult *res;
6856  printQueryOpt myopt = pset.popt;
6857  bool have_where = false;
6858  static const bool translate_columns[] = {false, false, false, false};
6859 
6860  initPQExpBuffer(&buf);
6861 
6863  "SELECT\n"
6864  " am.amname AS \"%s\",\n"
6865  " CASE\n"
6866  " WHEN pg_catalog.pg_opfamily_is_visible(f.oid)\n"
6867  " THEN pg_catalog.format('%%I', f.opfname)\n"
6868  " ELSE pg_catalog.format('%%I.%%I', n.nspname, f.opfname)\n"
6869  " END AS \"%s\",\n"
6870  " (SELECT\n"
6871  " pg_catalog.string_agg(pg_catalog.format_type(oc.opcintype, NULL), ', ')\n"
6872  " FROM pg_catalog.pg_opclass oc\n"
6873  " WHERE oc.opcfamily = f.oid) \"%s\"",
6874  gettext_noop("AM"),
6875  gettext_noop("Operator family"),
6876  gettext_noop("Applicable types"));
6877  if (verbose)
6879  ",\n pg_catalog.pg_get_userbyid(f.opfowner) AS \"%s\"\n",
6880  gettext_noop("Owner"));
6882  "\nFROM pg_catalog.pg_opfamily f\n"
6883  " LEFT JOIN pg_catalog.pg_am am on am.oid = f.opfmethod\n"
6884  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace\n");
6885 
6886  if (access_method_pattern)
6887  if (!validateSQLNamePattern(&buf, access_method_pattern,
6888  false, false, NULL, "am.amname", NULL, NULL,
6889  &have_where, 1))
6890  goto error_return;
6891  if (type_pattern)
6892  {
6894  " %s EXISTS (\n"
6895  " SELECT 1\n"
6896  " FROM pg_catalog.pg_type t\n"
6897  " JOIN pg_catalog.pg_opclass oc ON oc.opcintype = t.oid\n"
6898  " LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n"
6899  " WHERE oc.opcfamily = f.oid\n",
6900  have_where ? "AND" : "WHERE");
6901  /* Match type name pattern against either internal or external name */
6902  if (!validateSQLNamePattern(&buf, type_pattern, true, false,
6903  "tn.nspname", "t.typname",
6904  "pg_catalog.format_type(t.oid, NULL)",
6905  "pg_catalog.pg_type_is_visible(t.oid)",
6906  NULL, 3))
6907  goto error_return;
6908  appendPQExpBufferStr(&buf, " )\n");
6909  }
6910 
6911  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
6912  res = PSQLexec(buf.data);
6913  termPQExpBuffer(&buf);
6914  if (!res)
6915  return false;
6916 
6917  myopt.title = _("List of operator families");
6918  myopt.translate_header = true;
6919  myopt.translate_columns = translate_columns;
6920  myopt.n_translate_columns = lengthof(translate_columns);
6921 
6922  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6923 
6924  PQclear(res);
6925  return true;
6926 
6927 error_return:
6928  termPQExpBuffer(&buf);
6929  return false;
6930 }

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

7040 {
7042  PGresult *res;
7043  printQueryOpt myopt = pset.popt;
7044  bool have_where = false;
7045  static const bool translate_columns[] = {false, false, false, false, false, false};
7046 
7047  initPQExpBuffer(&buf);
7048 
7050  "SELECT\n"
7051  " am.amname AS \"%s\",\n"
7052  " CASE\n"
7053  " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
7054  " THEN pg_catalog.format('%%I', of.opfname)\n"
7055  " ELSE pg_catalog.format('%%I.%%I', ns.nspname, of.opfname)\n"
7056  " END AS \"%s\",\n"
7057  " pg_catalog.format_type(ap.amproclefttype, NULL) AS \"%s\",\n"
7058  " pg_catalog.format_type(ap.amprocrighttype, NULL) AS \"%s\",\n"
7059  " ap.amprocnum AS \"%s\"\n",
7060  gettext_noop("AM"),
7061  gettext_noop("Operator family"),
7062  gettext_noop("Registered left type"),
7063  gettext_noop("Registered right type"),
7064  gettext_noop("Number"));
7065 
7066  if (!verbose)
7068  ", p.proname AS \"%s\"\n",
7069  gettext_noop("Function"));
7070  else
7072  ", ap.amproc::pg_catalog.regprocedure AS \"%s\"\n",
7073  gettext_noop("Function"));
7074 
7076  "FROM pg_catalog.pg_amproc ap\n"
7077  " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = ap.amprocfamily\n"
7078  " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod\n"
7079  " LEFT JOIN pg_catalog.pg_namespace ns ON of.opfnamespace = ns.oid\n"
7080  " LEFT JOIN pg_catalog.pg_proc p ON ap.amproc = p.oid\n");
7081 
7082  if (access_method_pattern)
7083  {
7084  if (!validateSQLNamePattern(&buf, access_method_pattern,
7085  false, false, NULL, "am.amname",
7086  NULL, NULL,
7087  &have_where, 1))
7088  goto error_return;
7089  }
7090  if (family_pattern)
7091  {
7092  if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
7093  "ns.nspname", "of.opfname", NULL, NULL,
7094  NULL, 3))
7095  goto error_return;
7096  }
7097 
7098  appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
7099  " ap.amproclefttype = ap.amprocrighttype DESC,\n"
7100  " 3, 4, 5;");
7101 
7102  res = PSQLexec(buf.data);
7103  termPQExpBuffer(&buf);
7104  if (!res)
7105  return false;
7106 
7107  myopt.title = _("List of support functions of operator families");
7108  myopt.translate_header = true;
7109  myopt.translate_columns = translate_columns;
7110  myopt.n_translate_columns = lengthof(translate_columns);
7111 
7112  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7113 
7114  PQclear(res);
7115  return true;
7116 
7117 error_return:
7118  termPQExpBuffer(&buf);
7119  return false;
7120 }

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

6942 {
6944  PGresult *res;
6945  printQueryOpt myopt = pset.popt;
6946  bool have_where = false;
6947 
6948  static const bool translate_columns[] = {false, false, false, false, false, false};
6949 
6950  initPQExpBuffer(&buf);
6951 
6953  "SELECT\n"
6954  " am.amname AS \"%s\",\n"
6955  " CASE\n"
6956  " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
6957  " THEN pg_catalog.format('%%I', of.opfname)\n"
6958  " ELSE pg_catalog.format('%%I.%%I', nsf.nspname, of.opfname)\n"
6959  " END AS \"%s\",\n"
6960  " o.amopopr::pg_catalog.regoperator AS \"%s\"\n,"
6961  " o.amopstrategy AS \"%s\",\n"
6962  " CASE o.amoppurpose\n"
6963  " WHEN 'o' THEN '%s'\n"
6964  " WHEN 's' THEN '%s'\n"
6965  " END AS \"%s\"\n",
6966  gettext_noop("AM"),
6967  gettext_noop("Operator family"),
6968  gettext_noop("Operator"),
6969  gettext_noop("Strategy"),
6970  gettext_noop("ordering"),
6971  gettext_noop("search"),
6972  gettext_noop("Purpose"));
6973 
6974  if (verbose)
6976  ", ofs.opfname AS \"%s\"\n",
6977  gettext_noop("Sort opfamily"));
6979  "FROM pg_catalog.pg_amop o\n"
6980  " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\n"
6981  " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod AND am.oid = o.amopmethod\n"
6982  " LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n");
6983  if (verbose)
6985  " LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n");
6986 
6987  if (access_method_pattern)
6988  {
6989  if (!validateSQLNamePattern(&buf, access_method_pattern,
6990  false, false, NULL, "am.amname",
6991  NULL, NULL,
6992  &have_where, 1))
6993  goto error_return;
6994  }
6995 
6996  if (family_pattern)
6997  {
6998  if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
6999  "nsf.nspname", "of.opfname", NULL, NULL,
7000  NULL, 3))
7001  goto error_return;
7002  }
7003 
7004  appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
7005  " o.amoplefttype = o.amoprighttype DESC,\n"
7006  " pg_catalog.format_type(o.amoplefttype, NULL),\n"
7007  " pg_catalog.format_type(o.amoprighttype, NULL),\n"
7008  " o.amopstrategy;");
7009 
7010  res = PSQLexec(buf.data);
7011  termPQExpBuffer(&buf);
7012  if (!res)
7013  return false;
7014 
7015  myopt.title = _("List of operators of operator families");
7016  myopt.translate_header = true;
7017  myopt.translate_columns = translate_columns;
7018  myopt.n_translate_columns = lengthof(translate_columns);
7019 
7020  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7021 
7022  PQclear(res);
7023  return true;
7024 
7025 error_return:
7026  termPQExpBuffer(&buf);
7027  return false;
7028 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

6733 {
6735  "CASE"
6736  " WHEN pg_catalog.array_length(%s, 1) = 0 THEN '%s'"
6737  " ELSE pg_catalog.array_to_string(%s, E'\\n')"
6738  " END AS \"%s\"",
6739  colname, gettext_noop("(none)"),
6740  colname, gettext_noop("Access privileges"));
6741 }

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

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

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().