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

Go to the source code of this file.

Functions

static const char * map_typename_pattern (const char *pattern)
 
static bool describeOneTableDetails (const char *schemaname, const char *relationname, const char *oid, bool verbose)
 
static void add_tablespace_footer (printTableContent *const cont, char relkind, Oid tablespace, const bool newline)
 
static void add_role_attribute (PQExpBuffer buf, const char *const str)
 
static bool listTSParsersVerbose (const char *pattern)
 
static bool describeOneTSParser (const char *oid, const char *nspname, const char *prsname)
 
static bool listTSConfigsVerbose (const char *pattern)
 
static bool describeOneTSConfig (const char *oid, const char *nspname, const char *cfgname, const char *pnspname, const char *prsname)
 
static void printACLColumn (PQExpBuffer buf, const char *colname)
 
static bool listOneExtensionContents (const char *extname, const char *oid)
 
bool describeAggregates (const char *pattern, bool verbose, bool showSystem)
 
bool describeAccessMethods (const char *pattern, bool verbose)
 
bool describeTablespaces (const char *pattern, bool verbose)
 
bool describeFunctions (const char *functypes, const char *func_pattern, char **arg_patterns, int num_arg_patterns, bool verbose, bool showSystem)
 
bool describeTypes (const char *pattern, bool verbose, bool showSystem)
 
bool describeOperators (const char *oper_pattern, char **arg_patterns, int num_arg_patterns, bool verbose, bool showSystem)
 
bool listAllDbs (const char *pattern, bool verbose)
 
bool permissionsList (const char *pattern)
 
bool listDefaultACLs (const char *pattern)
 
bool objectDescription (const char *pattern, bool showSystem)
 
bool describeTableDetails (const char *pattern, bool verbose, bool showSystem)
 
bool describeRoles (const char *pattern, bool verbose, bool showSystem)
 
bool listDbRoleSettings (const char *pattern, const char *pattern2)
 
bool listTables (const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
 
bool listPartitionedTables (const char *reltypes, const char *pattern, bool verbose)
 
bool listLanguages (const char *pattern, bool verbose, bool showSystem)
 
bool listDomains (const char *pattern, bool verbose, bool showSystem)
 
bool listConversions (const char *pattern, bool verbose, bool showSystem)
 
bool listEventTriggers (const char *pattern, bool verbose)
 
bool listExtendedStats (const char *pattern)
 
bool listCasts (const char *pattern, bool verbose)
 
bool listCollations (const char *pattern, bool verbose, bool showSystem)
 
bool listSchemas (const char *pattern, bool verbose, bool showSystem)
 
bool listTSParsers (const char *pattern, bool verbose)
 
bool listTSDictionaries (const char *pattern, bool verbose)
 
bool listTSTemplates (const char *pattern, bool verbose)
 
bool listTSConfigs (const char *pattern, bool verbose)
 
bool listForeignDataWrappers (const char *pattern, bool verbose)
 
bool listForeignServers (const char *pattern, bool verbose)
 
bool listUserMappings (const char *pattern, bool verbose)
 
bool listForeignTables (const char *pattern, bool verbose)
 
bool listExtensions (const char *pattern)
 
bool listExtensionContents (const char *pattern)
 
bool listPublications (const char *pattern)
 
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)
 

Function Documentation

◆ add_role_attribute()

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

Definition at line 3899 of file describe.c.

References appendPQExpBufferStr(), and PQExpBufferData::len.

Referenced by describeRoles().

3900 {
3901  if (buf->len > 0)
3902  appendPQExpBufferStr(buf, ", ");
3903 
3904  appendPQExpBufferStr(buf, str);
3905 }
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369

◆ add_tablespace_footer()

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

Definition at line 3673 of file describe.c.

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

Referenced by describeOneTableDetails().

3675 {
3676  /* relkinds for which we support tablespaces */
3677  if (relkind == RELKIND_RELATION ||
3678  relkind == RELKIND_MATVIEW ||
3679  relkind == RELKIND_INDEX ||
3680  relkind == RELKIND_PARTITIONED_TABLE ||
3681  relkind == RELKIND_PARTITIONED_INDEX ||
3682  relkind == RELKIND_TOASTVALUE)
3683  {
3684  /*
3685  * We ignore the database default tablespace so that users not using
3686  * tablespaces don't need to know about them. This case also covers
3687  * pre-8.0 servers, for which tablespace will always be 0.
3688  */
3689  if (tablespace != 0)
3690  {
3691  PGresult *result = NULL;
3693 
3694  initPQExpBuffer(&buf);
3695  printfPQExpBuffer(&buf,
3696  "SELECT spcname FROM pg_catalog.pg_tablespace\n"
3697  "WHERE oid = '%u';", tablespace);
3698  result = PSQLexec(buf.data);
3699  if (!result)
3700  {
3701  termPQExpBuffer(&buf);
3702  return;
3703  }
3704  /* Should always be the case, but.... */
3705  if (PQntuples(result) > 0)
3706  {
3707  if (newline)
3708  {
3709  /* Add the tablespace as a new footer */
3710  printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
3711  PQgetvalue(result, 0, 0));
3712  printTableAddFooter(cont, buf.data);
3713  }
3714  else
3715  {
3716  /* Append the tablespace to the latest footer */
3717  printfPQExpBuffer(&buf, "%s", cont->footer->data);
3718 
3719  /*-------
3720  translator: before this string there's an index description like
3721  '"foo_pkey" PRIMARY KEY, btree (a)' */
3722  appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
3723  PQgetvalue(result, 0, 0));
3724  printTableSetFooter(cont, buf.data);
3725  }
3726  }
3727  PQclear(result);
3728  termPQExpBuffer(&buf);
3729  }
3730  }
3731 }
void printTableSetFooter(printTableContent *const content, const char *footer)
Definition: print.c:3207
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3642
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3248
static chr newline(void)
Definition: regc_lex.c:1001
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
char * tablespace
Definition: pgbench.c:226
void printTableAddFooter(printTableContent *const content, const char *footer)
Definition: print.c:3182
printTableFooter * footer
Definition: print.h:161
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * data
Definition: print.h:139
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeAccessMethods()

bool describeAccessMethods ( const char *  pattern,
bool  verbose 
)

Definition at line 150 of file describe.c.

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

Referenced by exec_command_d().

151 {
153  PGresult *res;
154  printQueryOpt myopt = pset.popt;
155  static const bool translate_columns[] = {false, true, false, false};
156 
157  if (pset.sversion < 90600)
158  {
159  char sverbuf[32];
160 
161  pg_log_error("The server (version %s) does not support access methods.",
163  sverbuf, sizeof(sverbuf)));
164  return true;
165  }
166 
167  initPQExpBuffer(&buf);
168 
169  printfPQExpBuffer(&buf,
170  "SELECT amname AS \"%s\",\n"
171  " CASE amtype"
172  " WHEN 'i' THEN '%s'"
173  " WHEN 't' THEN '%s'"
174  " END AS \"%s\"",
175  gettext_noop("Name"),
176  gettext_noop("Index"),
177  gettext_noop("Table"),
178  gettext_noop("Type"));
179 
180  if (verbose)
181  {
182  appendPQExpBuffer(&buf,
183  ",\n amhandler AS \"%s\",\n"
184  " pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
185  gettext_noop("Handler"),
186  gettext_noop("Description"));
187  }
188 
190  "\nFROM pg_catalog.pg_am\n");
191 
192  processSQLNamePattern(pset.db, &buf, pattern, false, false,
193  NULL, "amname", NULL,
194  NULL);
195 
196  appendPQExpBufferStr(&buf, "ORDER BY 1;");
197 
198  res = PSQLexec(buf.data);
199  termPQExpBuffer(&buf);
200  if (!res)
201  return false;
202 
203  myopt.nullPrint = NULL;
204  myopt.title = _("List of access methods");
205  myopt.translate_header = true;
206  myopt.translate_columns = translate_columns;
207  myopt.n_translate_columns = lengthof(translate_columns);
208 
209  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
210 
211  PQclear(res);
212  return true;
213 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:80
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
#define lengthof(array)
Definition: c.h:734
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
int n_translate_columns
Definition: print.h:176
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
const bool * translate_columns
Definition: print.h:174
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeAggregates()

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

Definition at line 64 of file describe.c.

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

Referenced by exec_command_d().

65 {
67  PGresult *res;
68  printQueryOpt myopt = pset.popt;
69 
70  initPQExpBuffer(&buf);
71 
72  printfPQExpBuffer(&buf,
73  "SELECT n.nspname as \"%s\",\n"
74  " p.proname AS \"%s\",\n"
75  " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n",
76  gettext_noop("Schema"),
77  gettext_noop("Name"),
78  gettext_noop("Result data type"));
79 
80  if (pset.sversion >= 80400)
81  appendPQExpBuffer(&buf,
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("Argument data types"));
87  else if (pset.sversion >= 80200)
88  appendPQExpBuffer(&buf,
89  " CASE WHEN p.pronargs = 0\n"
90  " THEN CAST('*' AS pg_catalog.text)\n"
91  " ELSE\n"
92  " pg_catalog.array_to_string(ARRAY(\n"
93  " SELECT\n"
94  " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
95  " FROM\n"
96  " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
97  " ), ', ')\n"
98  " END AS \"%s\",\n",
99  gettext_noop("Argument data types"));
100  else
101  appendPQExpBuffer(&buf,
102  " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
103  gettext_noop("Argument data types"));
104 
105  if (pset.sversion >= 110000)
106  appendPQExpBuffer(&buf,
107  " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
108  "FROM pg_catalog.pg_proc p\n"
109  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
110  "WHERE p.prokind = 'a'\n",
111  gettext_noop("Description"));
112  else
113  appendPQExpBuffer(&buf,
114  " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
115  "FROM pg_catalog.pg_proc p\n"
116  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
117  "WHERE p.proisagg\n",
118  gettext_noop("Description"));
119 
120  if (!showSystem && !pattern)
121  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
122  " AND n.nspname <> 'information_schema'\n");
123 
124  processSQLNamePattern(pset.db, &buf, pattern, true, false,
125  "n.nspname", "p.proname", NULL,
126  "pg_catalog.pg_function_is_visible(p.oid)");
127 
128  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
129 
130  res = PSQLexec(buf.data);
131  termPQExpBuffer(&buf);
132  if (!res)
133  return false;
134 
135  myopt.nullPrint = NULL;
136  myopt.title = _("List of aggregate functions");
137  myopt.translate_header = true;
138 
139  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
140 
141  PQclear(res);
142  return true;
143 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeFunctions()

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

Definition at line 316 of file describe.c.

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

Referenced by exec_command_dfo().

319 {
320  bool showAggregate = strchr(functypes, 'a') != NULL;
321  bool showNormal = strchr(functypes, 'n') != NULL;
322  bool showProcedure = strchr(functypes, 'p') != NULL;
323  bool showTrigger = strchr(functypes, 't') != NULL;
324  bool showWindow = strchr(functypes, 'w') != NULL;
325  bool have_where;
327  PGresult *res;
328  printQueryOpt myopt = pset.popt;
329  static const bool translate_columns[] = {false, false, false, false, true, true, true, false, true, false, false, false, false};
330 
331  /* No "Parallel" column before 9.6 */
332  static const bool translate_columns_pre_96[] = {false, false, false, false, true, true, false, true, false, false, false, false};
333 
334  if (strlen(functypes) != strspn(functypes, "anptwS+"))
335  {
336  pg_log_error("\\df only takes [anptwS+] as options");
337  return true;
338  }
339 
340  if (showProcedure && pset.sversion < 110000)
341  {
342  char sverbuf[32];
343 
344  pg_log_error("\\df does not take a \"%c\" option with server version %s",
345  'p',
347  sverbuf, sizeof(sverbuf)));
348  return true;
349  }
350 
351  if (showWindow && pset.sversion < 80400)
352  {
353  char sverbuf[32];
354 
355  pg_log_error("\\df does not take a \"%c\" option with server version %s",
356  'w',
358  sverbuf, sizeof(sverbuf)));
359  return true;
360  }
361 
362  if (!showAggregate && !showNormal && !showProcedure && !showTrigger && !showWindow)
363  {
364  showAggregate = showNormal = showTrigger = true;
365  if (pset.sversion >= 110000)
366  showProcedure = true;
367  if (pset.sversion >= 80400)
368  showWindow = true;
369  }
370 
371  initPQExpBuffer(&buf);
372 
373  printfPQExpBuffer(&buf,
374  "SELECT n.nspname as \"%s\",\n"
375  " p.proname as \"%s\",\n",
376  gettext_noop("Schema"),
377  gettext_noop("Name"));
378 
379  if (pset.sversion >= 110000)
380  appendPQExpBuffer(&buf,
381  " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
382  " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
383  " CASE p.prokind\n"
384  " WHEN 'a' THEN '%s'\n"
385  " WHEN 'w' THEN '%s'\n"
386  " WHEN 'p' THEN '%s'\n"
387  " ELSE '%s'\n"
388  " END as \"%s\"",
389  gettext_noop("Result data type"),
390  gettext_noop("Argument data types"),
391  /* translator: "agg" is short for "aggregate" */
392  gettext_noop("agg"),
393  gettext_noop("window"),
394  gettext_noop("proc"),
395  gettext_noop("func"),
396  gettext_noop("Type"));
397  else if (pset.sversion >= 80400)
398  appendPQExpBuffer(&buf,
399  " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
400  " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
401  " CASE\n"
402  " WHEN p.proisagg THEN '%s'\n"
403  " WHEN p.proiswindow THEN '%s'\n"
404  " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
405  " ELSE '%s'\n"
406  " END as \"%s\"",
407  gettext_noop("Result data type"),
408  gettext_noop("Argument data types"),
409  /* translator: "agg" is short for "aggregate" */
410  gettext_noop("agg"),
411  gettext_noop("window"),
412  gettext_noop("trigger"),
413  gettext_noop("func"),
414  gettext_noop("Type"));
415  else if (pset.sversion >= 80100)
416  appendPQExpBuffer(&buf,
417  " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
418  " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
419  " CASE WHEN proallargtypes IS NOT NULL THEN\n"
420  " pg_catalog.array_to_string(ARRAY(\n"
421  " SELECT\n"
422  " CASE\n"
423  " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
424  " WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
425  " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
426  " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
427  " END ||\n"
428  " CASE\n"
429  " WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
430  " ELSE p.proargnames[s.i] || ' '\n"
431  " END ||\n"
432  " pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
433  " FROM\n"
434  " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
435  " ), ', ')\n"
436  " ELSE\n"
437  " pg_catalog.array_to_string(ARRAY(\n"
438  " SELECT\n"
439  " CASE\n"
440  " WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
441  " ELSE p.proargnames[s.i+1] || ' '\n"
442  " END ||\n"
443  " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
444  " FROM\n"
445  " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
446  " ), ', ')\n"
447  " END AS \"%s\",\n"
448  " CASE\n"
449  " WHEN p.proisagg THEN '%s'\n"
450  " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
451  " ELSE '%s'\n"
452  " END AS \"%s\"",
453  gettext_noop("Result data type"),
454  gettext_noop("Argument data types"),
455  /* translator: "agg" is short for "aggregate" */
456  gettext_noop("agg"),
457  gettext_noop("trigger"),
458  gettext_noop("func"),
459  gettext_noop("Type"));
460  else
461  appendPQExpBuffer(&buf,
462  " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
463  " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
464  " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\",\n"
465  " CASE\n"
466  " WHEN p.proisagg THEN '%s'\n"
467  " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
468  " ELSE '%s'\n"
469  " END AS \"%s\"",
470  gettext_noop("Result data type"),
471  gettext_noop("Argument data types"),
472  /* translator: "agg" is short for "aggregate" */
473  gettext_noop("agg"),
474  gettext_noop("trigger"),
475  gettext_noop("func"),
476  gettext_noop("Type"));
477 
478  if (verbose)
479  {
480  appendPQExpBuffer(&buf,
481  ",\n CASE\n"
482  " WHEN p.provolatile = 'i' THEN '%s'\n"
483  " WHEN p.provolatile = 's' THEN '%s'\n"
484  " WHEN p.provolatile = 'v' THEN '%s'\n"
485  " END as \"%s\"",
486  gettext_noop("immutable"),
487  gettext_noop("stable"),
488  gettext_noop("volatile"),
489  gettext_noop("Volatility"));
490  if (pset.sversion >= 90600)
491  appendPQExpBuffer(&buf,
492  ",\n CASE\n"
493  " WHEN p.proparallel = 'r' THEN '%s'\n"
494  " WHEN p.proparallel = 's' THEN '%s'\n"
495  " WHEN p.proparallel = 'u' THEN '%s'\n"
496  " END as \"%s\"",
497  gettext_noop("restricted"),
498  gettext_noop("safe"),
499  gettext_noop("unsafe"),
500  gettext_noop("Parallel"));
501  appendPQExpBuffer(&buf,
502  ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\""
503  ",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\"",
504  gettext_noop("Owner"),
505  gettext_noop("definer"),
506  gettext_noop("invoker"),
507  gettext_noop("Security"));
508  appendPQExpBufferStr(&buf, ",\n ");
509  printACLColumn(&buf, "p.proacl");
510  appendPQExpBuffer(&buf,
511  ",\n l.lanname as \"%s\"",
512  gettext_noop("Language"));
513  if (pset.sversion >= 140000)
514  appendPQExpBuffer(&buf,
515  ",\n COALESCE(pg_catalog.pg_get_function_sqlbody(p.oid), p.prosrc) as \"%s\"",
516  gettext_noop("Source code"));
517  else
518  appendPQExpBuffer(&buf,
519  ",\n p.prosrc as \"%s\"",
520  gettext_noop("Source code"));
521  appendPQExpBuffer(&buf,
522  ",\n pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
523  gettext_noop("Description"));
524  }
525 
527  "\nFROM pg_catalog.pg_proc p"
528  "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
529 
530  for (int i = 0; i < num_arg_patterns; i++)
531  {
532  appendPQExpBuffer(&buf,
533  " LEFT JOIN pg_catalog.pg_type t%d ON t%d.oid = p.proargtypes[%d]\n"
534  " LEFT JOIN pg_catalog.pg_namespace nt%d ON nt%d.oid = t%d.typnamespace\n",
535  i, i, i, i, i, i);
536  }
537 
538  if (verbose)
540  " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
541 
542  have_where = false;
543 
544  /* filter by function type, if requested */
545  if (showNormal && showAggregate && showProcedure && showTrigger && showWindow)
546  /* Do nothing */ ;
547  else if (showNormal)
548  {
549  if (!showAggregate)
550  {
551  if (have_where)
552  appendPQExpBufferStr(&buf, " AND ");
553  else
554  {
555  appendPQExpBufferStr(&buf, "WHERE ");
556  have_where = true;
557  }
558  if (pset.sversion >= 110000)
559  appendPQExpBufferStr(&buf, "p.prokind <> 'a'\n");
560  else
561  appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
562  }
563  if (!showProcedure && pset.sversion >= 110000)
564  {
565  if (have_where)
566  appendPQExpBufferStr(&buf, " AND ");
567  else
568  {
569  appendPQExpBufferStr(&buf, "WHERE ");
570  have_where = true;
571  }
572  appendPQExpBufferStr(&buf, "p.prokind <> 'p'\n");
573  }
574  if (!showTrigger)
575  {
576  if (have_where)
577  appendPQExpBufferStr(&buf, " AND ");
578  else
579  {
580  appendPQExpBufferStr(&buf, "WHERE ");
581  have_where = true;
582  }
583  appendPQExpBufferStr(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
584  }
585  if (!showWindow && pset.sversion >= 80400)
586  {
587  if (have_where)
588  appendPQExpBufferStr(&buf, " AND ");
589  else
590  {
591  appendPQExpBufferStr(&buf, "WHERE ");
592  have_where = true;
593  }
594  if (pset.sversion >= 110000)
595  appendPQExpBufferStr(&buf, "p.prokind <> 'w'\n");
596  else
597  appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
598  }
599  }
600  else
601  {
602  bool needs_or = false;
603 
604  appendPQExpBufferStr(&buf, "WHERE (\n ");
605  have_where = true;
606  /* Note: at least one of these must be true ... */
607  if (showAggregate)
608  {
609  if (pset.sversion >= 110000)
610  appendPQExpBufferStr(&buf, "p.prokind = 'a'\n");
611  else
612  appendPQExpBufferStr(&buf, "p.proisagg\n");
613  needs_or = true;
614  }
615  if (showTrigger)
616  {
617  if (needs_or)
618  appendPQExpBufferStr(&buf, " OR ");
620  "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n");
621  needs_or = true;
622  }
623  if (showProcedure)
624  {
625  if (needs_or)
626  appendPQExpBufferStr(&buf, " OR ");
627  appendPQExpBufferStr(&buf, "p.prokind = 'p'\n");
628  needs_or = true;
629  }
630  if (showWindow)
631  {
632  if (needs_or)
633  appendPQExpBufferStr(&buf, " OR ");
634  if (pset.sversion >= 110000)
635  appendPQExpBufferStr(&buf, "p.prokind = 'w'\n");
636  else
637  appendPQExpBufferStr(&buf, "p.proiswindow\n");
638  needs_or = true;
639  }
640  appendPQExpBufferStr(&buf, " )\n");
641  }
642 
643  processSQLNamePattern(pset.db, &buf, func_pattern, have_where, false,
644  "n.nspname", "p.proname", NULL,
645  "pg_catalog.pg_function_is_visible(p.oid)");
646 
647  for (int i = 0; i < num_arg_patterns; i++)
648  {
649  if (strcmp(arg_patterns[i], "-") != 0)
650  {
651  /*
652  * Match type-name patterns against either internal or external
653  * name, like \dT. Unlike \dT, there seems no reason to
654  * discriminate against arrays or composite types.
655  */
656  char nspname[64];
657  char typname[64];
658  char ft[64];
659  char tiv[64];
660 
661  snprintf(nspname, sizeof(nspname), "nt%d.nspname", i);
662  snprintf(typname, sizeof(typname), "t%d.typname", i);
663  snprintf(ft, sizeof(ft),
664  "pg_catalog.format_type(t%d.oid, NULL)", i);
665  snprintf(tiv, sizeof(tiv),
666  "pg_catalog.pg_type_is_visible(t%d.oid)", i);
668  map_typename_pattern(arg_patterns[i]),
669  true, false,
670  nspname, typname, ft, tiv);
671  }
672  else
673  {
674  /* "-" pattern specifies no such parameter */
675  appendPQExpBuffer(&buf, " AND t%d.typname IS NULL\n", i);
676  }
677  }
678 
679  if (!showSystem && !func_pattern)
680  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
681  " AND n.nspname <> 'information_schema'\n");
682 
683  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
684 
685  res = PSQLexec(buf.data);
686  termPQExpBuffer(&buf);
687  if (!res)
688  return false;
689 
690  myopt.nullPrint = NULL;
691  myopt.title = _("List of functions");
692  myopt.translate_header = true;
693  if (pset.sversion >= 90600)
694  {
695  myopt.translate_columns = translate_columns;
696  myopt.n_translate_columns = lengthof(translate_columns);
697  }
698  else
699  {
700  myopt.translate_columns = translate_columns_pre_96;
701  myopt.n_translate_columns = lengthof(translate_columns_pre_96);
702  }
703 
704  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
705 
706  PQclear(res);
707  return true;
708 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:80
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
#define lengthof(array)
Definition: c.h:734
static const char * map_typename_pattern(const char *pattern)
Definition: describe.c:841
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
NameData typname
Definition: pg_type.h:41
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
int n_translate_columns
Definition: print.h:176
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
int i
const bool * translate_columns
Definition: print.h:174
#define snprintf
Definition: port.h:216
static void printACLColumn(PQExpBuffer buf, const char *colname)
Definition: describe.c:6477
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeOneTableDetails()

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

Definition at line 1611 of file describe.c.

References _, add_tablespace_footer(), appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), Assert, atooid, buf, CppAsString2, 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, resetPQExpBuffer(), _psqlSettings::sversion, tablespace, termPQExpBuffer(), printQueryOpt::title, tmpbuf, printQueryOpt::topt, and printQueryOpt::translate_header.

Referenced by describeTableDetails().

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

◆ describeOneTSConfig()

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

Definition at line 5599 of file describe.c.

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

Referenced by listTSConfigsVerbose().

5601 {
5603  title;
5604  PGresult *res;
5605  printQueryOpt myopt = pset.popt;
5606 
5607  initPQExpBuffer(&buf);
5608 
5609  printfPQExpBuffer(&buf,
5610  "SELECT\n"
5611  " ( SELECT t.alias FROM\n"
5612  " pg_catalog.ts_token_type(c.cfgparser) AS t\n"
5613  " WHERE t.tokid = m.maptokentype ) AS \"%s\",\n"
5614  " pg_catalog.btrim(\n"
5615  " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary\n"
5616  " FROM pg_catalog.pg_ts_config_map AS mm\n"
5617  " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype\n"
5618  " ORDER BY mapcfg, maptokentype, mapseqno\n"
5619  " ) :: pg_catalog.text,\n"
5620  " '{}') AS \"%s\"\n"
5621  "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m\n"
5622  "WHERE c.oid = '%s' AND m.mapcfg = c.oid\n"
5623  "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser\n"
5624  "ORDER BY 1;",
5625  gettext_noop("Token"),
5626  gettext_noop("Dictionaries"),
5627  oid);
5628 
5629  res = PSQLexec(buf.data);
5630  termPQExpBuffer(&buf);
5631  if (!res)
5632  return false;
5633 
5634  initPQExpBuffer(&title);
5635 
5636  if (nspname)
5637  appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
5638  nspname, cfgname);
5639  else
5640  appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
5641  cfgname);
5642 
5643  if (pnspname)
5644  appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
5645  pnspname, prsname);
5646  else
5647  appendPQExpBuffer(&title, _("\nParser: \"%s\""),
5648  prsname);
5649 
5650  myopt.nullPrint = NULL;
5651  myopt.title = title.data;
5652  myopt.footers = NULL;
5653  myopt.topt.default_footer = false;
5654  myopt.translate_header = true;
5655 
5656  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5657 
5658  termPQExpBuffer(&title);
5659 
5660  PQclear(res);
5661  return true;
5662 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
printTableOpt topt
Definition: print.h:169
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
char ** footers
Definition: print.h:172
bool default_footer
Definition: print.h:113
printQueryOpt popt
Definition: settings.h:91
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeOneTSParser()

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

Definition at line 5204 of file describe.c.

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

Referenced by listTSParsersVerbose().

5205 {
5207  PGresult *res;
5208  PQExpBufferData title;
5209  printQueryOpt myopt = pset.popt;
5210  static const bool translate_columns[] = {true, false, false};
5211 
5212  initPQExpBuffer(&buf);
5213 
5214  printfPQExpBuffer(&buf,
5215  "SELECT '%s' AS \"%s\",\n"
5216  " p.prsstart::pg_catalog.regproc AS \"%s\",\n"
5217  " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\"\n"
5218  " FROM pg_catalog.pg_ts_parser p\n"
5219  " WHERE p.oid = '%s'\n"
5220  "UNION ALL\n"
5221  "SELECT '%s',\n"
5222  " p.prstoken::pg_catalog.regproc,\n"
5223  " pg_catalog.obj_description(p.prstoken, 'pg_proc')\n"
5224  " FROM pg_catalog.pg_ts_parser p\n"
5225  " WHERE p.oid = '%s'\n"
5226  "UNION ALL\n"
5227  "SELECT '%s',\n"
5228  " p.prsend::pg_catalog.regproc,\n"
5229  " pg_catalog.obj_description(p.prsend, 'pg_proc')\n"
5230  " FROM pg_catalog.pg_ts_parser p\n"
5231  " WHERE p.oid = '%s'\n"
5232  "UNION ALL\n"
5233  "SELECT '%s',\n"
5234  " p.prsheadline::pg_catalog.regproc,\n"
5235  " pg_catalog.obj_description(p.prsheadline, 'pg_proc')\n"
5236  " FROM pg_catalog.pg_ts_parser p\n"
5237  " WHERE p.oid = '%s'\n"
5238  "UNION ALL\n"
5239  "SELECT '%s',\n"
5240  " p.prslextype::pg_catalog.regproc,\n"
5241  " pg_catalog.obj_description(p.prslextype, 'pg_proc')\n"
5242  " FROM pg_catalog.pg_ts_parser p\n"
5243  " WHERE p.oid = '%s';",
5244  gettext_noop("Start parse"),
5245  gettext_noop("Method"),
5246  gettext_noop("Function"),
5247  gettext_noop("Description"),
5248  oid,
5249  gettext_noop("Get next token"),
5250  oid,
5251  gettext_noop("End parse"),
5252  oid,
5253  gettext_noop("Get headline"),
5254  oid,
5255  gettext_noop("Get token types"),
5256  oid);
5257 
5258  res = PSQLexec(buf.data);
5259  termPQExpBuffer(&buf);
5260  if (!res)
5261  return false;
5262 
5263  myopt.nullPrint = NULL;
5264  initPQExpBuffer(&title);
5265  if (nspname)
5266  printfPQExpBuffer(&title, _("Text search parser \"%s.%s\""),
5267  nspname, prsname);
5268  else
5269  printfPQExpBuffer(&title, _("Text search parser \"%s\""), prsname);
5270  myopt.title = title.data;
5271  myopt.footers = NULL;
5272  myopt.topt.default_footer = false;
5273  myopt.translate_header = true;
5274  myopt.translate_columns = translate_columns;
5275  myopt.n_translate_columns = lengthof(translate_columns);
5276 
5277  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5278 
5279  PQclear(res);
5280 
5281  initPQExpBuffer(&buf);
5282 
5283  printfPQExpBuffer(&buf,
5284  "SELECT t.alias as \"%s\",\n"
5285  " t.description as \"%s\"\n"
5286  "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t\n"
5287  "ORDER BY 1;",
5288  gettext_noop("Token name"),
5289  gettext_noop("Description"),
5290  oid);
5291 
5292  res = PSQLexec(buf.data);
5293  termPQExpBuffer(&buf);
5294  if (!res)
5295  return false;
5296 
5297  myopt.nullPrint = NULL;
5298  if (nspname)
5299  printfPQExpBuffer(&title, _("Token types for parser \"%s.%s\""),
5300  nspname, prsname);
5301  else
5302  printfPQExpBuffer(&title, _("Token types for parser \"%s\""), prsname);
5303  myopt.title = title.data;
5304  myopt.footers = NULL;
5305  myopt.topt.default_footer = true;
5306  myopt.translate_header = true;
5307  myopt.translate_columns = NULL;
5308  myopt.n_translate_columns = 0;
5309 
5310  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5311 
5312  termPQExpBuffer(&title);
5313  PQclear(res);
5314  return true;
5315 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
printTableOpt topt
Definition: print.h:169
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
#define lengthof(array)
Definition: c.h:734
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
char ** footers
Definition: print.h:172
bool default_footer
Definition: print.h:113
printQueryOpt popt
Definition: settings.h:91
int n_translate_columns
Definition: print.h:176
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
const bool * translate_columns
Definition: print.h:174
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeOperators()

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

Definition at line 891 of file describe.c.

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

Referenced by exec_command_dfo().

894 {
896  PGresult *res;
897  printQueryOpt myopt = pset.popt;
898 
899  initPQExpBuffer(&buf);
900 
901  /*
902  * Note: before Postgres 9.1, we did not assign comments to any built-in
903  * operators, preferring to let the comment on the underlying function
904  * suffice. The coalesce() on the obj_description() calls below supports
905  * this convention by providing a fallback lookup of a comment on the
906  * operator's function. As of 9.1 there is a policy that every built-in
907  * operator should have a comment; so the coalesce() is no longer
908  * necessary so far as built-in operators are concerned. We keep it
909  * anyway, for now, because (1) third-party modules may still be following
910  * the old convention, and (2) we'd need to do it anyway when talking to a
911  * pre-9.1 server.
912  *
913  * The support for postfix operators in this query is dead code as of
914  * Postgres 14, but we need to keep it for as long as we support talking
915  * to pre-v14 servers.
916  */
917 
918  printfPQExpBuffer(&buf,
919  "SELECT n.nspname as \"%s\",\n"
920  " o.oprname AS \"%s\",\n"
921  " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
922  " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
923  " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
924  gettext_noop("Schema"),
925  gettext_noop("Name"),
926  gettext_noop("Left arg type"),
927  gettext_noop("Right arg type"),
928  gettext_noop("Result type"));
929 
930  if (verbose)
931  appendPQExpBuffer(&buf,
932  " o.oprcode AS \"%s\",\n",
933  gettext_noop("Function"));
934 
935  appendPQExpBuffer(&buf,
936  " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
937  " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
938  "FROM pg_catalog.pg_operator o\n"
939  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
940  gettext_noop("Description"));
941 
942  if (num_arg_patterns >= 2)
943  {
944  num_arg_patterns = 2; /* ignore any additional arguments */
946  " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprleft\n"
947  " LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n"
948  " LEFT JOIN pg_catalog.pg_type t1 ON t1.oid = o.oprright\n"
949  " LEFT JOIN pg_catalog.pg_namespace nt1 ON nt1.oid = t1.typnamespace\n");
950  }
951  else if (num_arg_patterns == 1)
952  {
954  " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprright\n"
955  " LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n");
956  }
957 
958  if (!showSystem && !oper_pattern)
959  appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
960  " AND n.nspname <> 'information_schema'\n");
961 
962  processSQLNamePattern(pset.db, &buf, oper_pattern,
963  !showSystem && !oper_pattern, true,
964  "n.nspname", "o.oprname", NULL,
965  "pg_catalog.pg_operator_is_visible(o.oid)");
966 
967  if (num_arg_patterns == 1)
968  appendPQExpBufferStr(&buf, " AND o.oprleft = 0\n");
969 
970  for (int i = 0; i < num_arg_patterns; i++)
971  {
972  if (strcmp(arg_patterns[i], "-") != 0)
973  {
974  /*
975  * Match type-name patterns against either internal or external
976  * name, like \dT. Unlike \dT, there seems no reason to
977  * discriminate against arrays or composite types.
978  */
979  char nspname[64];
980  char typname[64];
981  char ft[64];
982  char tiv[64];
983 
984  snprintf(nspname, sizeof(nspname), "nt%d.nspname", i);
985  snprintf(typname, sizeof(typname), "t%d.typname", i);
986  snprintf(ft, sizeof(ft),
987  "pg_catalog.format_type(t%d.oid, NULL)", i);
988  snprintf(tiv, sizeof(tiv),
989  "pg_catalog.pg_type_is_visible(t%d.oid)", i);
991  map_typename_pattern(arg_patterns[i]),
992  true, false,
993  nspname, typname, ft, tiv);
994  }
995  else
996  {
997  /* "-" pattern specifies no such parameter */
998  appendPQExpBuffer(&buf, " AND t%d.typname IS NULL\n", i);
999  }
1000  }
1001 
1002  appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4;");
1003 
1004  res = PSQLexec(buf.data);
1005  termPQExpBuffer(&buf);
1006  if (!res)
1007  return false;
1008 
1009  myopt.nullPrint = NULL;
1010  myopt.title = _("List of operators");
1011  myopt.translate_header = true;
1012 
1013  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1014 
1015  PQclear(res);
1016  return true;
1017 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
static const char * map_typename_pattern(const char *pattern)
Definition: describe.c:841
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
NameData typname
Definition: pg_type.h:41
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
int i
#define snprintf
Definition: port.h:216
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describePublications()

bool describePublications ( const char *  pattern)

Definition at line 6220 of file describe.c.

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

Referenced by exec_command_d().

6221 {
6223  int i;
6224  PGresult *res;
6225  bool has_pubtruncate;
6226  bool has_pubviaroot;
6227 
6228  if (pset.sversion < 100000)
6229  {
6230  char sverbuf[32];
6231 
6232  pg_log_error("The server (version %s) does not support publications.",
6234  sverbuf, sizeof(sverbuf)));
6235  return true;
6236  }
6237 
6238  has_pubtruncate = (pset.sversion >= 110000);
6239  has_pubviaroot = (pset.sversion >= 130000);
6240 
6241  initPQExpBuffer(&buf);
6242 
6243  printfPQExpBuffer(&buf,
6244  "SELECT oid, pubname,\n"
6245  " pg_catalog.pg_get_userbyid(pubowner) AS owner,\n"
6246  " puballtables, pubinsert, pubupdate, pubdelete");
6247  if (has_pubtruncate)
6248  appendPQExpBufferStr(&buf,
6249  ", pubtruncate");
6250  if (has_pubviaroot)
6251  appendPQExpBufferStr(&buf,
6252  ", pubviaroot");
6253  appendPQExpBufferStr(&buf,
6254  "\nFROM pg_catalog.pg_publication\n");
6255 
6256  processSQLNamePattern(pset.db, &buf, pattern, false, false,
6257  NULL, "pubname", NULL,
6258  NULL);
6259 
6260  appendPQExpBufferStr(&buf, "ORDER BY 2;");
6261 
6262  res = PSQLexec(buf.data);
6263  if (!res)
6264  {
6265  termPQExpBuffer(&buf);
6266  return false;
6267  }
6268 
6269  if (PQntuples(res) == 0)
6270  {
6271  if (!pset.quiet)
6272  {
6273  if (pattern)
6274  pg_log_error("Did not find any publication named \"%s\".",
6275  pattern);
6276  else
6277  pg_log_error("Did not find any publications.");
6278  }
6279 
6280  termPQExpBuffer(&buf);
6281  PQclear(res);
6282  return false;
6283  }
6284 
6285  for (i = 0; i < PQntuples(res); i++)
6286  {
6287  const char align = 'l';
6288  int ncols = 5;
6289  int nrows = 1;
6290  int tables = 0;
6291  PGresult *tabres;
6292  char *pubid = PQgetvalue(res, i, 0);
6293  char *pubname = PQgetvalue(res, i, 1);
6294  bool puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
6295  int j;
6296  PQExpBufferData title;
6297  printTableOpt myopt = pset.popt.topt;
6298  printTableContent cont;
6299 
6300  if (has_pubtruncate)
6301  ncols++;
6302  if (has_pubviaroot)
6303  ncols++;
6304 
6305  initPQExpBuffer(&title);
6306  printfPQExpBuffer(&title, _("Publication %s"), pubname);
6307  printTableInit(&cont, &myopt, title.data, ncols, nrows);
6308 
6309  printTableAddHeader(&cont, gettext_noop("Owner"), true, align);
6310  printTableAddHeader(&cont, gettext_noop("All tables"), true, align);
6311  printTableAddHeader(&cont, gettext_noop("Inserts"), true, align);
6312  printTableAddHeader(&cont, gettext_noop("Updates"), true, align);
6313  printTableAddHeader(&cont, gettext_noop("Deletes"), true, align);
6314  if (has_pubtruncate)
6315  printTableAddHeader(&cont, gettext_noop("Truncates"), true, align);
6316  if (has_pubviaroot)
6317  printTableAddHeader(&cont, gettext_noop("Via root"), true, align);
6318 
6319  printTableAddCell(&cont, PQgetvalue(res, i, 2), false, false);
6320  printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false);
6321  printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false);
6322  printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
6323  printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
6324  if (has_pubtruncate)
6325  printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
6326  if (has_pubviaroot)
6327  printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
6328 
6329  if (!puballtables)
6330  {
6331  printfPQExpBuffer(&buf,
6332  "SELECT n.nspname, c.relname\n"
6333  "FROM pg_catalog.pg_class c,\n"
6334  " pg_catalog.pg_namespace n,\n"
6335  " pg_catalog.pg_publication_rel pr\n"
6336  "WHERE c.relnamespace = n.oid\n"
6337  " AND c.oid = pr.prrelid\n"
6338  " AND pr.prpubid = '%s'\n"
6339  "ORDER BY 1,2", pubid);
6340 
6341  tabres = PSQLexec(buf.data);
6342  if (!tabres)
6343  {
6344  printTableCleanup(&cont);
6345  PQclear(res);
6346  termPQExpBuffer(&buf);
6347  termPQExpBuffer(&title);
6348  return false;
6349  }
6350  else
6351  tables = PQntuples(tabres);
6352 
6353  if (tables > 0)
6354  printTableAddFooter(&cont, _("Tables:"));
6355 
6356  for (j = 0; j < tables; j++)
6357  {
6358  printfPQExpBuffer(&buf, " \"%s.%s\"",
6359  PQgetvalue(tabres, j, 0),
6360  PQgetvalue(tabres, j, 1));
6361 
6362  printTableAddFooter(&cont, buf.data);
6363  }
6364  PQclear(tabres);
6365  }
6366 
6367  printTable(&cont, pset.queryFout, false, pset.logfile);
6368  printTableCleanup(&cont);
6369 
6370  termPQExpBuffer(&title);
6371  }
6372 
6373  termPQExpBuffer(&buf);
6374  PQclear(res);
6375 
6376  return true;
6377 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
PsqlSettings pset
Definition: startup.c:32
void printTableCleanup(printTableContent *const content)
Definition: print.c:3225
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3642
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:80
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
printTableOpt topt
Definition: print.h:169
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3248
void printTableAddHeader(printTableContent *const content, char *header, const bool translate, const char align)
Definition: print.c:3094
void printTableAddCell(printTableContent *const content, char *cell, const bool translate, const bool mustfree)
Definition: print.c:3134
static char * buf
Definition: pg_test_fsync.c:68
void printTable(const printTableContent *cont, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3314
void printTableAddFooter(printTableContent *const content, const char *footer)
Definition: print.c:3182
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
printQueryOpt popt
Definition: settings.h:91
void printTableInit(printTableContent *const content, const printTableOpt *opt, const char *title, const int ncolumns, const int nrows)
Definition: print.c:3057
int i
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeRoles()

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

Definition at line 3739 of file describe.c.

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

Referenced by exec_command_d().

3740 {
3742  PGresult *res;
3743  printTableContent cont;
3744  printTableOpt myopt = pset.popt.topt;
3745  int ncols = 3;
3746  int nrows = 0;
3747  int i;
3748  int conns;
3749  const char align = 'l';
3750  char **attr;
3751 
3752  myopt.default_footer = false;
3753 
3754  initPQExpBuffer(&buf);
3755 
3756  if (pset.sversion >= 80100)
3757  {
3758  printfPQExpBuffer(&buf,
3759  "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
3760  " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
3761  " r.rolconnlimit, r.rolvaliduntil,\n"
3762  " ARRAY(SELECT b.rolname\n"
3763  " FROM pg_catalog.pg_auth_members m\n"
3764  " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
3765  " WHERE m.member = r.oid) as memberof");
3766 
3767  if (verbose && pset.sversion >= 80200)
3768  {
3769  appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
3770  ncols++;
3771  }
3772  if (pset.sversion >= 90100)
3773  {
3774  appendPQExpBufferStr(&buf, "\n, r.rolreplication");
3775  }
3776 
3777  if (pset.sversion >= 90500)
3778  {
3779  appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
3780  }
3781 
3782  appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
3783 
3784  if (!showSystem && !pattern)
3785  appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
3786 
3787  processSQLNamePattern(pset.db, &buf, pattern, false, false,
3788  NULL, "r.rolname", NULL, NULL);
3789  }
3790  else
3791  {
3792  printfPQExpBuffer(&buf,
3793  "SELECT u.usename AS rolname,\n"
3794  " u.usesuper AS rolsuper,\n"
3795  " true AS rolinherit, false AS rolcreaterole,\n"
3796  " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
3797  " -1 AS rolconnlimit,"
3798  " u.valuntil as rolvaliduntil,\n"
3799  " ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
3800  "\nFROM pg_catalog.pg_user u\n");
3801 
3802  processSQLNamePattern(pset.db, &buf, pattern, false, false,
3803  NULL, "u.usename", NULL, NULL);
3804  }
3805 
3806  appendPQExpBufferStr(&buf, "ORDER BY 1;");
3807 
3808  res = PSQLexec(buf.data);
3809  if (!res)
3810  return false;
3811 
3812  nrows = PQntuples(res);
3813  attr = pg_malloc0((nrows + 1) * sizeof(*attr));
3814 
3815  printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
3816 
3817  printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
3818  printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
3819  /* ignores implicit memberships from superuser & pg_database_owner */
3820  printTableAddHeader(&cont, gettext_noop("Member of"), true, align);
3821 
3822  if (verbose && pset.sversion >= 80200)
3823  printTableAddHeader(&cont, gettext_noop("Description"), true, align);
3824 
3825  for (i = 0; i < nrows; i++)
3826  {
3827  printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
3828 
3829  resetPQExpBuffer(&buf);
3830  if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
3831  add_role_attribute(&buf, _("Superuser"));
3832 
3833  if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
3834  add_role_attribute(&buf, _("No inheritance"));
3835 
3836  if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
3837  add_role_attribute(&buf, _("Create role"));
3838 
3839  if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
3840  add_role_attribute(&buf, _("Create DB"));
3841 
3842  if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
3843  add_role_attribute(&buf, _("Cannot login"));
3844 
3845  if (pset.sversion >= 90100)
3846  if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
3847  add_role_attribute(&buf, _("Replication"));
3848 
3849  if (pset.sversion >= 90500)
3850  if (strcmp(PQgetvalue(res, i, (verbose ? 11 : 10)), "t") == 0)
3851  add_role_attribute(&buf, _("Bypass RLS"));
3852 
3853  conns = atoi(PQgetvalue(res, i, 6));
3854  if (conns >= 0)
3855  {
3856  if (buf.len > 0)
3857  appendPQExpBufferChar(&buf, '\n');
3858 
3859  if (conns == 0)
3860  appendPQExpBufferStr(&buf, _("No connections"));
3861  else
3862  appendPQExpBuffer(&buf, ngettext("%d connection",
3863  "%d connections",
3864  conns),
3865  conns);
3866  }
3867 
3868  if (strcmp(PQgetvalue(res, i, 7), "") != 0)
3869  {
3870  if (buf.len > 0)
3871  appendPQExpBufferChar(&buf, '\n');
3872  appendPQExpBufferStr(&buf, _("Password valid until "));
3873  appendPQExpBufferStr(&buf, PQgetvalue(res, i, 7));
3874  }
3875 
3876  attr[i] = pg_strdup(buf.data);
3877 
3878  printTableAddCell(&cont, attr[i], false, false);
3879 
3880  printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
3881 
3882  if (verbose && pset.sversion >= 80200)
3883  printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
3884  }
3885  termPQExpBuffer(&buf);
3886 
3887  printTable(&cont, pset.queryFout, false, pset.logfile);
3888  printTableCleanup(&cont);
3889 
3890  for (i = 0; i < nrows; i++)
3891  free(attr[i]);
3892  free(attr);
3893 
3894  PQclear(res);
3895  return true;
3896 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
PsqlSettings pset
Definition: startup.c:32
void printTableCleanup(printTableContent *const content)
Definition: print.c:3225
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3642
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
printTableOpt topt
Definition: print.h:169
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3248
static void add_role_attribute(PQExpBuffer buf, const char *const str)
Definition: describe.c:3899
void printTableAddHeader(printTableContent *const content, char *header, const bool translate, const char align)
Definition: print.c:3094
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
static IsoConnInfo * conns
void printTableAddCell(printTableContent *const content, char *cell, const bool translate, const bool mustfree)
Definition: print.c:3134
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void printTable(const printTableContent *cont, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3314
static int verbose
#define ngettext(s, p, n)
Definition: c.h:1182
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:380
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
#define free(a)
Definition: header.h:65
bool default_footer
Definition: print.h:113
printQueryOpt popt
Definition: settings.h:91
void printTableInit(printTableContent *const content, const printTableOpt *opt, const char *title, const int ncolumns, const int nrows)
Definition: print.c:3057
int i
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:148
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeSubscriptions()

bool describeSubscriptions ( const char *  pattern,
bool  verbose 
)

Definition at line 6386 of file describe.c.

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

Referenced by exec_command_d().

6387 {
6389  PGresult *res;
6390  printQueryOpt myopt = pset.popt;
6391  static const bool translate_columns[] = {false, false, false, false,
6392  false, false, false, false, false};
6393 
6394  if (pset.sversion < 100000)
6395  {
6396  char sverbuf[32];
6397 
6398  pg_log_error("The server (version %s) does not support subscriptions.",
6400  sverbuf, sizeof(sverbuf)));
6401  return true;
6402  }
6403 
6404  initPQExpBuffer(&buf);
6405 
6406  printfPQExpBuffer(&buf,
6407  "SELECT subname AS \"%s\"\n"
6408  ", pg_catalog.pg_get_userbyid(subowner) AS \"%s\"\n"
6409  ", subenabled AS \"%s\"\n"
6410  ", subpublications AS \"%s\"\n",
6411  gettext_noop("Name"),
6412  gettext_noop("Owner"),
6413  gettext_noop("Enabled"),
6414  gettext_noop("Publication"));
6415 
6416  if (verbose)
6417  {
6418  /* Binary mode and streaming are only supported in v14 and higher */
6419  if (pset.sversion >= 140000)
6420  appendPQExpBuffer(&buf,
6421  ", subbinary AS \"%s\"\n"
6422  ", substream AS \"%s\"\n",
6423  gettext_noop("Binary"),
6424  gettext_noop("Streaming"));
6425 
6426  /* Two_phase is only supported in v15 and higher */
6427  if (pset.sversion >= 150000)
6428  appendPQExpBuffer(&buf,
6429  ", subtwophasestate AS \"%s\"\n",
6430  gettext_noop("Two phase commit"));
6431 
6432  appendPQExpBuffer(&buf,
6433  ", subsynccommit AS \"%s\"\n"
6434  ", subconninfo AS \"%s\"\n",
6435  gettext_noop("Synchronous commit"),
6436  gettext_noop("Conninfo"));
6437  }
6438 
6439  /* Only display subscriptions in current database. */
6440  appendPQExpBufferStr(&buf,
6441  "FROM pg_catalog.pg_subscription\n"
6442  "WHERE subdbid = (SELECT oid\n"
6443  " FROM pg_catalog.pg_database\n"
6444  " WHERE datname = pg_catalog.current_database())");
6445 
6446  processSQLNamePattern(pset.db, &buf, pattern, true, false,
6447  NULL, "subname", NULL,
6448  NULL);
6449 
6450  appendPQExpBufferStr(&buf, "ORDER BY 1;");
6451 
6452  res = PSQLexec(buf.data);
6453  termPQExpBuffer(&buf);
6454  if (!res)
6455  return false;
6456 
6457  myopt.nullPrint = NULL;
6458  myopt.title = _("List of subscriptions");
6459  myopt.translate_header = true;
6460  myopt.translate_columns = translate_columns;
6461  myopt.n_translate_columns = lengthof(translate_columns);
6462 
6463  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6464 
6465  PQclear(res);
6466  return true;
6467 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:80
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
#define lengthof(array)
Definition: c.h:734
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
int n_translate_columns
Definition: print.h:176
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
const bool * translate_columns
Definition: print.h:174
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeTableDetails()

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

Definition at line 1533 of file describe.c.

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

Referenced by exec_command_d().

1534 {
1536  PGresult *res;
1537  int i;
1538 
1539  initPQExpBuffer(&buf);
1540 
1541  printfPQExpBuffer(&buf,
1542  "SELECT c.oid,\n"
1543  " n.nspname,\n"
1544  " c.relname\n"
1545  "FROM pg_catalog.pg_class c\n"
1546  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1547 
1548  if (!showSystem && !pattern)
1549  appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1550  " AND n.nspname <> 'information_schema'\n");
1551 
1552  processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
1553  "n.nspname", "c.relname", NULL,
1554  "pg_catalog.pg_table_is_visible(c.oid)");
1555 
1556  appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
1557 
1558  res = PSQLexec(buf.data);
1559  termPQExpBuffer(&buf);
1560  if (!res)
1561  return false;
1562 
1563  if (PQntuples(res) == 0)
1564  {
1565  if (!pset.quiet)
1566  {
1567  if (pattern)
1568  pg_log_error("Did not find any relation named \"%s\".",
1569  pattern);
1570  else
1571  pg_log_error("Did not find any relations.");
1572  }
1573  PQclear(res);
1574  return false;
1575  }
1576 
1577  for (i = 0; i < PQntuples(res); i++)
1578  {
1579  const char *oid;
1580  const char *nspname;
1581  const char *relname;
1582 
1583  oid = PQgetvalue(res, i, 0);
1584  nspname = PQgetvalue(res, i, 1);
1585  relname = PQgetvalue(res, i, 2);
1586 
1587  if (!describeOneTableDetails(nspname, relname, oid, verbose))
1588  {
1589  PQclear(res);
1590  return false;
1591  }
1592  if (cancel_pressed)
1593  {
1594  PQclear(res);
1595  return false;
1596  }
1597  }
1598 
1599  PQclear(res);
1600  return true;
1601 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
PsqlSettings pset
Definition: startup.c:32
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3642
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:80
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
NameData relname
Definition: pg_class.h:38
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3248
static char * buf
Definition: pg_test_fsync.c:68
static bool describeOneTableDetails(const char *schemaname, const char *relationname, const char *oid, bool verbose)
Definition: describe.c:1611
static int verbose
volatile sig_atomic_t cancel_pressed
Definition: print.c:43
void PQclear(PGresult *res)
Definition: fe-exec.c:694
int i
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeTablespaces()

bool describeTablespaces ( const char *  pattern,
bool  verbose 
)

Definition at line 220 of file describe.c.

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

Referenced by exec_command_d().

221 {
223  PGresult *res;
224  printQueryOpt myopt = pset.popt;
225 
226  if (pset.sversion < 80000)
227  {
228  char sverbuf[32];
229 
230  pg_log_info("The server (version %s) does not support tablespaces.",
232  sverbuf, sizeof(sverbuf)));
233  return true;
234  }
235 
236  initPQExpBuffer(&buf);
237 
238  if (pset.sversion >= 90200)
239  printfPQExpBuffer(&buf,
240  "SELECT spcname AS \"%s\",\n"
241  " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
242  " pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
243  gettext_noop("Name"),
244  gettext_noop("Owner"),
245  gettext_noop("Location"));
246  else
247  printfPQExpBuffer(&buf,
248  "SELECT spcname AS \"%s\",\n"
249  " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
250  " spclocation AS \"%s\"",
251  gettext_noop("Name"),
252  gettext_noop("Owner"),
253  gettext_noop("Location"));
254 
255  if (verbose)
256  {
257  appendPQExpBufferStr(&buf, ",\n ");
258  printACLColumn(&buf, "spcacl");
259  }
260 
261  if (verbose && pset.sversion >= 90000)
262  appendPQExpBuffer(&buf,
263  ",\n spcoptions AS \"%s\"",
264  gettext_noop("Options"));
265 
266  if (verbose && pset.sversion >= 90200)
267  appendPQExpBuffer(&buf,
268  ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\"",
269  gettext_noop("Size"));
270 
271  if (verbose && pset.sversion >= 80200)
272  appendPQExpBuffer(&buf,
273  ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
274  gettext_noop("Description"));
275 
277  "\nFROM pg_catalog.pg_tablespace\n");
278 
279  processSQLNamePattern(pset.db, &buf, pattern, false, false,
280  NULL, "spcname", NULL,
281  NULL);
282 
283  appendPQExpBufferStr(&buf, "ORDER BY 1;");
284 
285  res = PSQLexec(buf.data);
286  termPQExpBuffer(&buf);
287  if (!res)
288  return false;
289 
290  myopt.nullPrint = NULL;
291  myopt.title = _("List of tablespaces");
292  myopt.translate_header = true;
293 
294  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
295 
296  PQclear(res);
297  return true;
298 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
static void printACLColumn(PQExpBuffer buf, const char *colname)
Definition: describe.c:6477
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
#define pg_log_info(...)
Definition: logging.h:88
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ describeTypes()

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

Definition at line 717 of file describe.c.

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

Referenced by exec_command_d().

718 {
720  PGresult *res;
721  printQueryOpt myopt = pset.popt;
722 
723  initPQExpBuffer(&buf);
724 
725  printfPQExpBuffer(&buf,
726  "SELECT n.nspname as \"%s\",\n"
727  " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
728  gettext_noop("Schema"),
729  gettext_noop("Name"));
730  if (verbose)
731  appendPQExpBuffer(&buf,
732  " t.typname AS \"%s\",\n"
733  " CASE WHEN t.typrelid != 0\n"
734  " THEN CAST('tuple' AS pg_catalog.text)\n"
735  " WHEN t.typlen < 0\n"
736  " THEN CAST('var' AS pg_catalog.text)\n"
737  " ELSE CAST(t.typlen AS pg_catalog.text)\n"
738  " END AS \"%s\",\n",
739  gettext_noop("Internal name"),
740  gettext_noop("Size"));
741  if (verbose && pset.sversion >= 80300)
742  {
744  " pg_catalog.array_to_string(\n"
745  " ARRAY(\n"
746  " SELECT e.enumlabel\n"
747  " FROM pg_catalog.pg_enum e\n"
748  " WHERE e.enumtypid = t.oid\n");
749 
750  if (pset.sversion >= 90100)
752  " ORDER BY e.enumsortorder\n");
753  else
755  " ORDER BY e.oid\n");
756 
757  appendPQExpBuffer(&buf,
758  " ),\n"
759  " E'\\n'\n"
760  " ) AS \"%s\",\n",
761  gettext_noop("Elements"));
762  }
763  if (verbose)
764  {
765  appendPQExpBuffer(&buf,
766  " pg_catalog.pg_get_userbyid(t.typowner) AS \"%s\",\n",
767  gettext_noop("Owner"));
768  }
769  if (verbose && pset.sversion >= 90200)
770  {
771  printACLColumn(&buf, "t.typacl");
772  appendPQExpBufferStr(&buf, ",\n ");
773  }
774 
775  appendPQExpBuffer(&buf,
776  " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
777  gettext_noop("Description"));
778 
779  appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_type t\n"
780  " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
781 
782  /*
783  * do not include complex types (typrelid!=0) unless they are standalone
784  * composite types
785  */
786  appendPQExpBufferStr(&buf, "WHERE (t.typrelid = 0 ");
787  appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
788  " FROM pg_catalog.pg_class c "
789  "WHERE c.oid = t.typrelid))\n");
790 
791  /*
792  * do not include array types unless the pattern contains [] (before 8.3
793  * we have to use the assumption that their names start with underscore)
794  */
795  if (pattern == NULL || strstr(pattern, "[]") == NULL)
796  {
797  if (pset.sversion >= 80300)
798  appendPQExpBufferStr(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
799  else
800  appendPQExpBufferStr(&buf, " AND t.typname !~ '^_'\n");
801  }
802 
803  if (!showSystem && !pattern)
804  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
805  " AND n.nspname <> 'information_schema'\n");
806 
807  /* Match name pattern against either internal or external name */
809  true, false,
810  "n.nspname", "t.typname",
811  "pg_catalog.format_type(t.oid, NULL)",
812  "pg_catalog.pg_type_is_visible(t.oid)");
813 
814  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
815 
816  res = PSQLexec(buf.data);
817  termPQExpBuffer(&buf);
818  if (!res)
819  return false;
820 
821  myopt.nullPrint = NULL;
822  myopt.title = _("List of data types");
823  myopt.translate_header = true;
824 
825  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
826 
827  PQclear(res);
828  return true;
829 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
static const char * map_typename_pattern(const char *pattern)
Definition: describe.c:841
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
static int verbose
#define CppAsString2(x)
Definition: c.h:289
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
static void printACLColumn(PQExpBuffer buf, const char *colname)
Definition: describe.c:6477
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ listAllDbs()

bool listAllDbs ( const char *  pattern,
bool  verbose 
)

Definition at line 1026 of file describe.c.

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

Referenced by exec_command_list(), and main().

1027 {
1028  PGresult *res;
1030  printQueryOpt myopt = pset.popt;
1031 
1032  initPQExpBuffer(&buf);
1033 
1034  printfPQExpBuffer(&buf,
1035  "SELECT d.datname as \"%s\",\n"
1036  " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
1037  " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
1038  gettext_noop("Name"),
1039  gettext_noop("Owner"),
1040  gettext_noop("Encoding"));
1041  if (pset.sversion >= 80400)
1042  appendPQExpBuffer(&buf,
1043  " d.datcollate as \"%s\",\n"
1044  " d.datctype as \"%s\",\n",
1045  gettext_noop("Collate"),
1046  gettext_noop("Ctype"));
1047  appendPQExpBufferStr(&buf, " ");
1048  printACLColumn(&buf, "d.datacl");
1049  if (verbose && pset.sversion >= 80200)
1050  appendPQExpBuffer(&buf,
1051  ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
1052  " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
1053  " ELSE 'No Access'\n"
1054  " END as \"%s\"",
1055  gettext_noop("Size"));
1056  if (verbose && pset.sversion >= 80000)
1057  appendPQExpBuffer(&buf,
1058  ",\n t.spcname as \"%s\"",
1059  gettext_noop("Tablespace"));
1060  if (verbose && pset.sversion >= 80200)
1061  appendPQExpBuffer(&buf,
1062  ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
1063  gettext_noop("Description"));
1064  appendPQExpBufferStr(&buf,
1065  "\nFROM pg_catalog.pg_database d\n");
1066  if (verbose && pset.sversion >= 80000)
1067  appendPQExpBufferStr(&buf,
1068  " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
1069 
1070  if (pattern)
1071  processSQLNamePattern(pset.db, &buf, pattern, false, false,
1072  NULL, "d.datname", NULL, NULL);
1073 
1074  appendPQExpBufferStr(&buf, "ORDER BY 1;");
1075  res = PSQLexec(buf.data);
1076  termPQExpBuffer(&buf);
1077  if (!res)
1078  return false;
1079 
1080  myopt.nullPrint = NULL;
1081  myopt.title = _("List of databases");
1082  myopt.translate_header = true;
1083 
1084  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1085 
1086  PQclear(res);
1087  return true;
1088 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
static void printACLColumn(PQExpBuffer buf, const char *colname)
Definition: describe.c:6477
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ listCasts()

bool listCasts ( const char *  pattern,
bool  verbose 
)

Definition at line 4802 of file describe.c.

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

Referenced by exec_command_d().

4803 {
4805  PGresult *res;
4806  printQueryOpt myopt = pset.popt;
4807  static const bool translate_columns[] = {false, false, false, true, false};
4808 
4809  initPQExpBuffer(&buf);
4810 
4811  printfPQExpBuffer(&buf,
4812  "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
4813  " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n",
4814  gettext_noop("Source type"),
4815  gettext_noop("Target type"));
4816 
4817  /*
4818  * We don't attempt to localize '(binary coercible)' or '(with inout)',
4819  * because there's too much risk of gettext translating a function name
4820  * that happens to match some string in the PO database.
4821  */
4822  if (pset.sversion >= 80400)
4823  appendPQExpBuffer(&buf,
4824  " CASE WHEN c.castmethod = '%c' THEN '(binary coercible)'\n"
4825  " WHEN c.castmethod = '%c' THEN '(with inout)'\n"
4826  " ELSE p.proname\n"
4827  " END AS \"%s\",\n",
4828  COERCION_METHOD_BINARY,
4829  COERCION_METHOD_INOUT,
4830  gettext_noop("Function"));
4831  else
4832  appendPQExpBuffer(&buf,
4833  " CASE WHEN c.castfunc = 0 THEN '(binary coercible)'\n"
4834  " ELSE p.proname\n"
4835  " END AS \"%s\",\n",
4836  gettext_noop("Function"));
4837 
4838  appendPQExpBuffer(&buf,
4839  " CASE WHEN c.castcontext = '%c' THEN '%s'\n"
4840  " WHEN c.castcontext = '%c' THEN '%s'\n"
4841  " ELSE '%s'\n"
4842  " END AS \"%s\"",
4843  COERCION_CODE_EXPLICIT,
4844  gettext_noop("no"),
4845  COERCION_CODE_ASSIGNMENT,
4846  gettext_noop("in assignment"),
4847  gettext_noop("yes"),
4848  gettext_noop("Implicit?"));
4849 
4850  if (verbose)
4851  appendPQExpBuffer(&buf,
4852  ",\n d.description AS \"%s\"",
4853  gettext_noop("Description"));
4854 
4855  /*
4856  * We need a left join to pg_proc for binary casts; the others are just
4857  * paranoia.
4858  */
4859  appendPQExpBufferStr(&buf,
4860  "\nFROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
4861  " ON c.castfunc = p.oid\n"
4862  " LEFT JOIN pg_catalog.pg_type ts\n"
4863  " ON c.castsource = ts.oid\n"
4864  " LEFT JOIN pg_catalog.pg_namespace ns\n"
4865  " ON ns.oid = ts.typnamespace\n"
4866  " LEFT JOIN pg_catalog.pg_type tt\n"
4867  " ON c.casttarget = tt.oid\n"
4868  " LEFT JOIN pg_catalog.pg_namespace nt\n"
4869  " ON nt.oid = tt.typnamespace\n");
4870 
4871  if (verbose)
4872  appendPQExpBufferStr(&buf,
4873  " LEFT JOIN pg_catalog.pg_description d\n"
4874  " ON d.classoid = c.tableoid AND d.objoid = "
4875  "c.oid AND d.objsubid = 0\n");
4876 
4877  appendPQExpBufferStr(&buf, "WHERE ( (true");
4878 
4879  /*
4880  * Match name pattern against either internal or external name of either
4881  * castsource or casttarget
4882  */
4883  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4884  "ns.nspname", "ts.typname",
4885  "pg_catalog.format_type(ts.oid, NULL)",
4886  "pg_catalog.pg_type_is_visible(ts.oid)");
4887 
4888  appendPQExpBufferStr(&buf, ") OR (true");
4889 
4890  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4891  "nt.nspname", "tt.typname",
4892  "pg_catalog.format_type(tt.oid, NULL)",
4893  "pg_catalog.pg_type_is_visible(tt.oid)");
4894 
4895  appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
4896 
4897  res = PSQLexec(buf.data);
4898  termPQExpBuffer(&buf);
4899  if (!res)
4900  return false;
4901 
4902  myopt.nullPrint = NULL;
4903  myopt.title = _("List of casts");
4904  myopt.translate_header = true;
4905  myopt.translate_columns = translate_columns;
4906  myopt.n_translate_columns = lengthof(translate_columns);
4907 
4908  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4909 
4910  PQclear(res);
4911  return true;
4912 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
#define lengthof(array)
Definition: c.h:734
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
int n_translate_columns
Definition: print.h:176
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
const bool * translate_columns
Definition: print.h:174
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ listCollations()

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

Definition at line 4920 of file describe.c.

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

Referenced by exec_command_d().

4921 {
4923  PGresult *res;
4924  printQueryOpt myopt = pset.popt;
4925  static const bool translate_columns[] = {false, false, false, false, false, true, false};
4926 
4927  if (pset.sversion < 90100)
4928  {
4929  char sverbuf[32];
4930 
4931  pg_log_error("The server (version %s) does not support collations.",
4933  sverbuf, sizeof(sverbuf)));
4934  return true;
4935  }
4936 
4937  initPQExpBuffer(&buf);
4938 
4939  printfPQExpBuffer(&buf,
4940  "SELECT n.nspname AS \"%s\",\n"
4941  " c.collname AS \"%s\",\n"
4942  " c.collcollate AS \"%s\",\n"
4943  " c.collctype AS \"%s\"",
4944  gettext_noop("Schema"),
4945  gettext_noop("Name"),
4946  gettext_noop("Collate"),
4947  gettext_noop("Ctype"));
4948 
4949  if (pset.sversion >= 100000)
4950  appendPQExpBuffer(&buf,
4951  ",\n CASE c.collprovider WHEN 'd' THEN 'default' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"%s\"",
4952  gettext_noop("Provider"));
4953  else
4954  appendPQExpBuffer(&buf,
4955  ",\n 'libc' AS \"%s\"",
4956  gettext_noop("Provider"));
4957 
4958  if (pset.sversion >= 120000)
4959  appendPQExpBuffer(&buf,
4960  ",\n CASE WHEN c.collisdeterministic THEN '%s' ELSE '%s' END AS \"%s\"",
4961  gettext_noop("yes"), gettext_noop("no"),
4962  gettext_noop("Deterministic?"));
4963  else
4964  appendPQExpBuffer(&buf,
4965  ",\n '%s' AS \"%s\"",
4966  gettext_noop("yes"),
4967  gettext_noop("Deterministic?"));
4968 
4969  if (verbose)
4970  appendPQExpBuffer(&buf,
4971  ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
4972  gettext_noop("Description"));
4973 
4974  appendPQExpBufferStr(&buf,
4975  "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
4976  "WHERE n.oid = c.collnamespace\n");
4977 
4978  if (!showSystem && !pattern)
4979  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4980  " AND n.nspname <> 'information_schema'\n");
4981 
4982  /*
4983  * Hide collations that aren't usable in the current database's encoding.
4984  * If you think to change this, note that pg_collation_is_visible rejects
4985  * unusable collations, so you will need to hack name pattern processing
4986  * somehow to avoid inconsistent behavior.
4987  */
4988  appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
4989 
4990  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4991  "n.nspname", "c.collname", NULL,
4992  "pg_catalog.pg_collation_is_visible(c.oid)");
4993 
4994  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4995 
4996  res = PSQLexec(buf.data);
4997  termPQExpBuffer(&buf);
4998  if (!res)
4999  return false;
5000 
5001  myopt.nullPrint = NULL;
5002  myopt.title = _("List of collations");
5003  myopt.translate_header = true;
5004  myopt.translate_columns = translate_columns;
5005  myopt.n_translate_columns = lengthof(translate_columns);
5006 
5007  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5008 
5009  PQclear(res);
5010  return true;
5011 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:80
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
#define lengthof(array)
Definition: c.h:734
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
int n_translate_columns
Definition: print.h:176
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
const bool * translate_columns
Definition: print.h:174
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177
PGresult * PSQLexec(const char *query)
Definition: common.c:540

◆ listConversions()

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

Definition at line 4568 of file describe.c.

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

Referenced by exec_command_d().

4569 {
4571  PGresult *res;
4572  printQueryOpt myopt = pset.popt;
4573  static const bool translate_columns[] =
4574  {false, false, false, false, true, false};
4575 
4576  initPQExpBuffer(&buf);
4577 
4578  printfPQExpBuffer(&buf,
4579  "SELECT n.nspname AS \"%s\",\n"
4580  " c.conname AS \"%s\",\n"
4581  " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
4582  " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
4583  " CASE WHEN c.condefault THEN '%s'\n"
4584  " ELSE '%s' END AS \"%s\"",
4585  gettext_noop("Schema"),
4586  gettext_noop("Name"),
4587  gettext_noop("Source"),
4588  gettext_noop("Destination"),
4589  gettext_noop("yes"), gettext_noop("no"),
4590  gettext_noop("Default?"));
4591 
4592  if (verbose)
4593  appendPQExpBuffer(&buf,
4594  ",\n d.description AS \"%s\"",
4595  gettext_noop("Description"));
4596 
4597  appendPQExpBufferStr(&buf,
4598  "\nFROM pg_catalog.pg_conversion c\n"
4599  " JOIN pg_catalog.pg_namespace n "
4600  "ON n.oid = c.connamespace\n");
4601 
4602  if (verbose)
4603  appendPQExpBufferStr(&buf,
4604  "LEFT JOIN pg_catalog.pg_description d "
4605  "ON d.classoid = c.tableoid\n"
4606  " AND d.objoid = c.oid "
4607  "AND d.objsubid = 0\n");
4608 
4609  appendPQExpBufferStr(&buf, "WHERE true\n");
4610 
4611  if (!showSystem && !pattern)
4612  appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4613  " AND n.nspname <> 'information_schema'\n");
4614 
4615  processSQLNamePattern(pset.db, &buf, pattern, true, false,
4616  "n.nspname", "c.conname", NULL,
4617  "pg_catalog.pg_conversion_is_visible(c.oid)");
4618 
4619  appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4620 
4621  res = PSQLexec(buf.data);
4622  termPQExpBuffer(&buf);
4623  if (!res)
4624  return false;
4625 
4626  myopt.nullPrint = NULL;
4627  myopt.title = _("List of conversions");
4628  myopt.translate_header = true;
4629  myopt.translate_columns = translate_columns;
4630  myopt.n_translate_columns = lengthof(translate_columns);
4631 
4632  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4633 
4634  PQclear(res);
4635  return true;
4636 }
PGconn * db
Definition: settings.h:82
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * nullPrint
Definition: print.h:170
PsqlSettings pset
Definition: startup.c:32
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define gettext_noop(x)
Definition: c.h:1197
FILE * queryFout
Definition: settings.h:84
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule)
Definition: string_utils.c:827
#define lengthof(array)
Definition: c.h:734
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
bool translate_header
Definition: print.h:173
static int verbose
FILE * logfile
Definition: settings.h:116
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * title
Definition: print.h:171
printQueryOpt popt
Definition: settings.h:91
int n_translate_columns
Definition: print.h:176
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3420
const bool * translate_columns
Definition: print.h:174
#define _(x)
Definition: elog.c:89
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
PGresult * PSQLexec(const char *query)
Definition: common.c:540