PostgreSQL Source Code git master
describe.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include "catalog/pg_am_d.h"
#include "catalog/pg_amop_d.h"
#include "catalog/pg_attribute_d.h"
#include "catalog/pg_cast_d.h"
#include "catalog/pg_class_d.h"
#include "catalog/pg_collation_d.h"
#include "catalog/pg_constraint_d.h"
#include "catalog/pg_default_acl_d.h"
#include "catalog/pg_proc_d.h"
#include "catalog/pg_publication_d.h"
#include "catalog/pg_statistic_ext_d.h"
#include "catalog/pg_subscription_d.h"
#include "catalog/pg_type_d.h"
#include "common.h"
#include "common/logging.h"
#include "describe.h"
#include "fe_utils/mbprint.h"
#include "fe_utils/print.h"
#include "fe_utils/string_utils.h"
#include "settings.h"
Include dependency graph for describe.c:

Go to the source code of this file.

Functions

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

Function Documentation

◆ add_role_attribute()

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

Definition at line 3845 of file describe.c.

3846{
3847 if (buf->len > 0)
3849
3851}
const char * str
static char * buf
Definition: pg_test_fsync.c:72
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367

References appendPQExpBufferStr(), buf, and str.

Referenced by describeRoles().

◆ add_tablespace_footer()

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

Definition at line 3645 of file describe.c.

3647{
3648 /* relkinds for which we support tablespaces */
3649 if (relkind == RELKIND_RELATION ||
3650 relkind == RELKIND_MATVIEW ||
3651 relkind == RELKIND_INDEX ||
3652 relkind == RELKIND_PARTITIONED_TABLE ||
3653 relkind == RELKIND_PARTITIONED_INDEX ||
3654 relkind == RELKIND_TOASTVALUE)
3655 {
3656 /*
3657 * We ignore the database default tablespace so that users not using
3658 * tablespaces don't need to know about them.
3659 */
3660 if (tablespace != 0)
3661 {
3662 PGresult *result = NULL;
3664
3667 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
3668 "WHERE oid = '%u';", tablespace);
3669 result = PSQLexec(buf.data);
3670 if (!result)
3671 {
3673 return;
3674 }
3675 /* Should always be the case, but.... */
3676 if (PQntuples(result) > 0)
3677 {
3678 if (newline)
3679 {
3680 /* Add the tablespace as a new footer */
3681 printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
3682 PQgetvalue(result, 0, 0));
3683 printTableAddFooter(cont, buf.data);
3684 }
3685 else
3686 {
3687 /* Append the tablespace to the latest footer */
3688 printfPQExpBuffer(&buf, "%s", cont->footer->data);
3689
3690 /*-------
3691 translator: before this string there's an index description like
3692 '"foo_pkey" PRIMARY KEY, btree (a)' */
3693 appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
3694 PQgetvalue(result, 0, 0));
3695 printTableSetFooter(cont, buf.data);
3696 }
3697 }
3698 PQclear(result);
3700 }
3701 }
3702}
PGresult * PSQLexec(const char *query)
Definition: common.c:620
#define _(x)
Definition: elog.c:90
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3876
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3481
void printTableSetFooter(printTableContent *const content, const char *footer)
Definition: print.c:3335
void printTableAddFooter(printTableContent *const content, const char *footer)
Definition: print.c:3310
#define newline
Definition: indent_codes.h:35
static char * tablespace
Definition: pgbench.c:216
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
printTableFooter * footer
Definition: print.h:177
char * data
Definition: print.h:155

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

Referenced by describeOneTableDetails().

◆ addFooterToPublicationDesc()

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

Definition at line 6476 of file describe.c.

6478{
6479 PGresult *res;
6480 int count = 0;
6481 int i = 0;
6482
6483 res = PSQLexec(buf->data);
6484 if (!res)
6485 return false;
6486 else
6487 count = PQntuples(res);
6488
6489 if (count > 0)
6490 printTableAddFooter(cont, footermsg);
6491
6492 for (i = 0; i < count; i++)
6493 {
6494 if (as_schema)
6495 printfPQExpBuffer(buf, " \"%s\"", PQgetvalue(res, i, 0));
6496 else
6497 {
6498 printfPQExpBuffer(buf, " \"%s.%s\"", PQgetvalue(res, i, 0),
6499 PQgetvalue(res, i, 1));
6500
6501 if (!PQgetisnull(res, i, 3))
6502 appendPQExpBuffer(buf, " (%s)", PQgetvalue(res, i, 3));
6503
6504 if (!PQgetisnull(res, i, 2))
6505 appendPQExpBuffer(buf, " WHERE %s", PQgetvalue(res, i, 2));
6506 }
6507
6508 printTableAddFooter(cont, buf->data);
6509 }
6510
6511 PQclear(res);
6512 return true;
6513}
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3901
int i
Definition: isn.c:72

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

Referenced by describePublications().

◆ describeAccessMethods()

bool describeAccessMethods ( const char *  pattern,
bool  verbose 
)

Definition at line 148 of file describe.c.

149{
151 PGresult *res;
152 printQueryOpt myopt = pset.popt;
153 static const bool translate_columns[] = {false, true, false, false};
154
155 if (pset.sversion < 90600)
156 {
157 char sverbuf[32];
158
159 pg_log_error("The server (version %s) does not support access methods.",
161 sverbuf, sizeof(sverbuf)));
162 return true;
163 }
164
166
168 "SELECT amname AS \"%s\",\n"
169 " CASE amtype"
170 " WHEN " CppAsString2(AMTYPE_INDEX) " THEN '%s'"
171 " WHEN " CppAsString2(AMTYPE_TABLE) " THEN '%s'"
172 " END AS \"%s\"",
173 gettext_noop("Name"),
174 gettext_noop("Index"),
175 gettext_noop("Table"),
176 gettext_noop("Type"));
177
178 if (verbose)
179 {
181 ",\n amhandler AS \"%s\",\n"
182 " pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
183 gettext_noop("Handler"),
184 gettext_noop("Description"));
185 }
186
188 "\nFROM pg_catalog.pg_am\n");
189
190 if (!validateSQLNamePattern(&buf, pattern, false, false,
191 NULL, "amname", NULL,
192 NULL,
193 NULL, 1))
194 {
196 return false;
197 }
198
199 appendPQExpBufferStr(&buf, "ORDER BY 1;");
200
201 res = PSQLexec(buf.data);
203 if (!res)
204 return false;
205
206 myopt.title = _("List of access methods");
207 myopt.translate_header = true;
208 myopt.translate_columns = translate_columns;
209 myopt.n_translate_columns = lengthof(translate_columns);
210
211 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
212
213 PQclear(res);
214 return true;
215}
#define gettext_noop(x)
Definition: c.h:1153
#define CppAsString2(x)
Definition: c.h:349
#define lengthof(array)
Definition: c.h:745
static bool validateSQLNamePattern(PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule, bool *added_clause, int maxparts)
Definition: describe.c:6338
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3549
int verbose
#define pg_log_error(...)
Definition: logging.h:106
PsqlSettings pset
Definition: startup.c:32
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177
printQueryOpt popt
Definition: settings.h:100
FILE * logfile
Definition: settings.h:131
FILE * queryFout
Definition: settings.h:93
const bool * translate_columns
Definition: print.h:190
char * title
Definition: print.h:187
bool translate_header
Definition: print.h:189
int n_translate_columns
Definition: print.h:192

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

Referenced by exec_command_d().

◆ describeAggregates()

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

Definition at line 78 of file describe.c.

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

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

Referenced by exec_command_d().

◆ describeConfigurationParameters()

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

Definition at line 4709 of file describe.c.

4711{
4713 PGresult *res;
4714 printQueryOpt myopt = pset.popt;
4715
4718 "SELECT s.name AS \"%s\", "
4719 "pg_catalog.current_setting(s.name) AS \"%s\"",
4720 gettext_noop("Parameter"),
4721 gettext_noop("Value"));
4722
4723 if (verbose)
4724 {
4726 ", s.vartype AS \"%s\", s.context AS \"%s\", ",
4727 gettext_noop("Type"),
4728 gettext_noop("Context"));
4729 if (pset.sversion >= 150000)
4730 printACLColumn(&buf, "p.paracl");
4731 else
4732 appendPQExpBuffer(&buf, "NULL AS \"%s\"",
4733 gettext_noop("Access privileges"));
4734 }
4735
4736 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_settings s\n");
4737
4738 if (verbose && pset.sversion >= 150000)
4740 " LEFT JOIN pg_catalog.pg_parameter_acl p\n"
4741 " ON pg_catalog.lower(s.name) = p.parname\n");
4742
4743 if (pattern)
4744 processSQLNamePattern(pset.db, &buf, pattern,
4745 false, false,
4746 NULL, "pg_catalog.lower(s.name)", NULL,
4747 NULL, NULL, NULL);
4748 else
4749 appendPQExpBufferStr(&buf, "WHERE s.source <> 'default' AND\n"
4750 " s.setting IS DISTINCT FROM s.boot_val\n");
4751
4752 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4753
4754 res = PSQLexec(buf.data);
4756 if (!res)
4757 return false;
4758
4759 if (pattern)
4760 myopt.title = _("List of configuration parameters");
4761 else
4762 myopt.title = _("List of non-default configuration parameters");
4763 myopt.translate_header = true;
4764
4765 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4766
4767 PQclear(res);
4768 return true;
4769}
static void printACLColumn(PQExpBuffer buf, const char *colname)
Definition: describe.c:6871
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule, PQExpBuffer dbnamebuf, int *dotcnt)
Definition: string_utils.c:891
PGconn * db
Definition: settings.h:91

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

Referenced by exec_command_d().

◆ describeFunctions()

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

Definition at line 295 of file describe.c.

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

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

Referenced by exec_command_dfo().

◆ describeOneTableDetails()

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

Definition at line 1566 of file describe.c.

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

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

Referenced by describeTableDetails().

◆ describeOneTSConfig()

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

Definition at line 5831 of file describe.c.

5833{
5835 title;
5836 PGresult *res;
5837 printQueryOpt myopt = pset.popt;
5838
5840
5842 "SELECT\n"
5843 " ( SELECT t.alias FROM\n"
5844 " pg_catalog.ts_token_type(c.cfgparser) AS t\n"
5845 " WHERE t.tokid = m.maptokentype ) AS \"%s\",\n"
5846 " pg_catalog.btrim(\n"
5847 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary\n"
5848 " FROM pg_catalog.pg_ts_config_map AS mm\n"
5849 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype\n"
5850 " ORDER BY mapcfg, maptokentype, mapseqno\n"
5851 " ) :: pg_catalog.text,\n"
5852 " '{}') AS \"%s\"\n"
5853 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m\n"
5854 "WHERE c.oid = '%s' AND m.mapcfg = c.oid\n"
5855 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser\n"
5856 "ORDER BY 1;",
5857 gettext_noop("Token"),
5858 gettext_noop("Dictionaries"),
5859 oid);
5860
5861 res = PSQLexec(buf.data);
5863 if (!res)
5864 return false;
5865
5866 initPQExpBuffer(&title);
5867
5868 if (nspname)
5869 appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
5870 nspname, cfgname);
5871 else
5872 appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
5873 cfgname);
5874
5875 if (pnspname)
5876 appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
5877 pnspname, prsname);
5878 else
5879 appendPQExpBuffer(&title, _("\nParser: \"%s\""),
5880 prsname);
5881
5882 myopt.title = title.data;
5883 myopt.footers = NULL;
5884 myopt.topt.default_footer = false;
5885 myopt.translate_header = true;
5886
5887 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5888
5889 termPQExpBuffer(&title);
5890
5891 PQclear(res);
5892 return true;
5893}

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

Referenced by listTSConfigsVerbose().

◆ describeOneTSParser()

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

Definition at line 5448 of file describe.c.

5449{
5451 PGresult *res;
5452 PQExpBufferData title;
5453 printQueryOpt myopt = pset.popt;
5454 static const bool translate_columns[] = {true, false, false};
5455
5457
5459 "SELECT '%s' AS \"%s\",\n"
5460 " p.prsstart::pg_catalog.regproc AS \"%s\",\n"
5461 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\"\n"
5462 " FROM pg_catalog.pg_ts_parser p\n"
5463 " WHERE p.oid = '%s'\n"
5464 "UNION ALL\n"
5465 "SELECT '%s',\n"
5466 " p.prstoken::pg_catalog.regproc,\n"
5467 " pg_catalog.obj_description(p.prstoken, 'pg_proc')\n"
5468 " FROM pg_catalog.pg_ts_parser p\n"
5469 " WHERE p.oid = '%s'\n"
5470 "UNION ALL\n"
5471 "SELECT '%s',\n"
5472 " p.prsend::pg_catalog.regproc,\n"
5473 " pg_catalog.obj_description(p.prsend, 'pg_proc')\n"
5474 " FROM pg_catalog.pg_ts_parser p\n"
5475 " WHERE p.oid = '%s'\n"
5476 "UNION ALL\n"
5477 "SELECT '%s',\n"
5478 " p.prsheadline::pg_catalog.regproc,\n"
5479 " pg_catalog.obj_description(p.prsheadline, 'pg_proc')\n"
5480 " FROM pg_catalog.pg_ts_parser p\n"
5481 " WHERE p.oid = '%s'\n"
5482 "UNION ALL\n"
5483 "SELECT '%s',\n"
5484 " p.prslextype::pg_catalog.regproc,\n"
5485 " pg_catalog.obj_description(p.prslextype, 'pg_proc')\n"
5486 " FROM pg_catalog.pg_ts_parser p\n"
5487 " WHERE p.oid = '%s';",
5488 gettext_noop("Start parse"),
5489 gettext_noop("Method"),
5490 gettext_noop("Function"),
5491 gettext_noop("Description"),
5492 oid,
5493 gettext_noop("Get next token"),
5494 oid,
5495 gettext_noop("End parse"),
5496 oid,
5497 gettext_noop("Get headline"),
5498 oid,
5499 gettext_noop("Get token types"),
5500 oid);
5501
5502 res = PSQLexec(buf.data);
5504 if (!res)
5505 return false;
5506
5507 initPQExpBuffer(&title);
5508 if (nspname)
5509 printfPQExpBuffer(&title, _("Text search parser \"%s.%s\""),
5510 nspname, prsname);
5511 else
5512 printfPQExpBuffer(&title, _("Text search parser \"%s\""), prsname);
5513 myopt.title = title.data;
5514 myopt.footers = NULL;
5515 myopt.topt.default_footer = false;
5516 myopt.translate_header = true;
5517 myopt.translate_columns = translate_columns;
5518 myopt.n_translate_columns = lengthof(translate_columns);
5519
5520 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5521
5522 PQclear(res);
5523
5525
5527 "SELECT t.alias as \"%s\",\n"
5528 " t.description as \"%s\"\n"
5529 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t\n"
5530 "ORDER BY 1;",
5531 gettext_noop("Token name"),
5532 gettext_noop("Description"),
5533 oid);
5534
5535 res = PSQLexec(buf.data);
5537 if (!res)
5538 {
5539 termPQExpBuffer(&title);
5540 return false;
5541 }
5542
5543 if (nspname)
5544 printfPQExpBuffer(&title, _("Token types for parser \"%s.%s\""),
5545 nspname, prsname);
5546 else
5547 printfPQExpBuffer(&title, _("Token types for parser \"%s\""), prsname);
5548 myopt.title = title.data;
5549 myopt.footers = NULL;
5550 myopt.topt.default_footer = true;
5551 myopt.translate_header = true;
5552 myopt.translate_columns = NULL;
5553 myopt.n_translate_columns = 0;
5554
5555 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5556
5557 termPQExpBuffer(&title);
5558 PQclear(res);
5559 return true;
5560}

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

Referenced by listTSParsersVerbose().

◆ describeOperators()

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

Definition at line 793 of file describe.c.

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

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

Referenced by exec_command_dfo().

◆ describePublications()

bool describePublications ( const char *  pattern)

Definition at line 6522 of file describe.c.

6523{
6525 int i;
6526 PGresult *res;
6527 bool has_pubtruncate;
6528 bool has_pubgencols;
6529 bool has_pubviaroot;
6530
6531 PQExpBufferData title;
6532 printTableContent cont;
6533
6534 if (pset.sversion < 100000)
6535 {
6536 char sverbuf[32];
6537
6538 pg_log_error("The server (version %s) does not support publications.",
6540 sverbuf, sizeof(sverbuf)));
6541 return true;
6542 }
6543
6544 has_pubtruncate = (pset.sversion >= 110000);
6545 has_pubgencols = (pset.sversion >= 180000);
6546 has_pubviaroot = (pset.sversion >= 130000);
6547
6549
6551 "SELECT oid, pubname,\n"
6552 " pg_catalog.pg_get_userbyid(pubowner) AS owner,\n"
6553 " puballtables, pubinsert, pubupdate, pubdelete");
6554 if (has_pubtruncate)
6556 ", pubtruncate");
6557 else
6559 ", false AS pubtruncate");
6560
6561 if (has_pubgencols)
6563 ", (CASE pubgencols\n"
6564 " WHEN '%c' THEN 'none'\n"
6565 " WHEN '%c' THEN 'stored'\n"
6566 " END) AS \"%s\"\n",
6567 PUBLISH_GENCOLS_NONE,
6568 PUBLISH_GENCOLS_STORED,
6569 gettext_noop("Generated columns"));
6570 else
6572 ", 'none' AS pubgencols");
6573
6574 if (has_pubviaroot)
6576 ", pubviaroot");
6577 else
6579 ", false AS pubviaroot");
6580
6582 "\nFROM pg_catalog.pg_publication\n");
6583
6584 if (!validateSQLNamePattern(&buf, pattern, false, false,
6585 NULL, "pubname", NULL,
6586 NULL,
6587 NULL, 1))
6588 {
6590 return false;
6591 }
6592
6593 appendPQExpBufferStr(&buf, "ORDER BY 2;");
6594
6595 res = PSQLexec(buf.data);
6596 if (!res)
6597 {
6599 return false;
6600 }
6601
6602 if (PQntuples(res) == 0)
6603 {
6604 if (!pset.quiet)
6605 {
6606 if (pattern)
6607 pg_log_error("Did not find any publication named \"%s\".",
6608 pattern);
6609 else
6610 pg_log_error("Did not find any publications.");
6611 }
6612
6614 PQclear(res);
6615 return false;
6616 }
6617
6618 for (i = 0; i < PQntuples(res); i++)
6619 {
6620 const char align = 'l';
6621 int ncols = 5;
6622 int nrows = 1;
6623 char *pubid = PQgetvalue(res, i, 0);
6624 char *pubname = PQgetvalue(res, i, 1);
6625 bool puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
6626 printTableOpt myopt = pset.popt.topt;
6627
6628 if (has_pubtruncate)
6629 ncols++;
6630 if (has_pubgencols)
6631 ncols++;
6632 if (has_pubviaroot)
6633 ncols++;
6634
6635 initPQExpBuffer(&title);
6636 printfPQExpBuffer(&title, _("Publication %s"), pubname);
6637 printTableInit(&cont, &myopt, title.data, ncols, nrows);
6638
6639 printTableAddHeader(&cont, gettext_noop("Owner"), true, align);
6640 printTableAddHeader(&cont, gettext_noop("All tables"), true, align);
6641 printTableAddHeader(&cont, gettext_noop("Inserts"), true, align);
6642 printTableAddHeader(&cont, gettext_noop("Updates"), true, align);
6643 printTableAddHeader(&cont, gettext_noop("Deletes"), true, align);
6644 if (has_pubtruncate)
6645 printTableAddHeader(&cont, gettext_noop("Truncates"), true, align);
6646 if (has_pubgencols)
6647 printTableAddHeader(&cont, gettext_noop("Generated columns"), true, align);
6648 if (has_pubviaroot)
6649 printTableAddHeader(&cont, gettext_noop("Via root"), true, align);
6650
6651 printTableAddCell(&cont, PQgetvalue(res, i, 2), false, false);
6652 printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false);
6653 printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false);
6654 printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
6655 printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
6656 if (has_pubtruncate)
6657 printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
6658 if (has_pubgencols)
6659 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
6660 if (has_pubviaroot)
6661 printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
6662
6663 if (!puballtables)
6664 {
6665 /* Get the tables for the specified publication */
6667 "SELECT n.nspname, c.relname");
6668 if (pset.sversion >= 150000)
6669 {
6671 ", pg_get_expr(pr.prqual, c.oid)");
6673 ", (CASE WHEN pr.prattrs IS NOT NULL THEN\n"
6674 " pg_catalog.array_to_string("
6675 " ARRAY(SELECT attname\n"
6676 " FROM\n"
6677 " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
6678 " pg_catalog.pg_attribute\n"
6679 " WHERE attrelid = c.oid AND attnum = prattrs[s]), ', ')\n"
6680 " ELSE NULL END)");
6681 }
6682 else
6684 ", NULL, NULL");
6686 "\nFROM pg_catalog.pg_class c,\n"
6687 " pg_catalog.pg_namespace n,\n"
6688 " pg_catalog.pg_publication_rel pr\n"
6689 "WHERE c.relnamespace = n.oid\n"
6690 " AND c.oid = pr.prrelid\n"
6691 " AND pr.prpubid = '%s'\n"
6692 "ORDER BY 1,2", pubid);
6693 if (!addFooterToPublicationDesc(&buf, _("Tables:"), false, &cont))
6694 goto error_return;
6695
6696 if (pset.sversion >= 150000)
6697 {
6698 /* Get the schemas for the specified publication */
6700 "SELECT n.nspname\n"
6701 "FROM pg_catalog.pg_namespace n\n"
6702 " JOIN pg_catalog.pg_publication_namespace pn ON n.oid = pn.pnnspid\n"
6703 "WHERE pn.pnpubid = '%s'\n"
6704 "ORDER BY 1", pubid);
6705 if (!addFooterToPublicationDesc(&buf, _("Tables from schemas:"),
6706 true, &cont))
6707 goto error_return;
6708 }
6709 }
6710
6711 printTable(&cont, pset.queryFout, false, pset.logfile);
6712 printTableCleanup(&cont);
6713
6714 termPQExpBuffer(&title);
6715 }
6716
6718 PQclear(res);
6719
6720 return true;
6721
6722error_return:
6723 printTableCleanup(&cont);
6724 PQclear(res);
6726 termPQExpBuffer(&title);
6727 return false;
6728}
static bool addFooterToPublicationDesc(PQExpBuffer buf, const char *footermsg, bool as_schema, printTableContent *const cont)
Definition: describe.c:6476

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

Referenced by exec_command_d().

◆ describeRoleGrants()

bool describeRoleGrants ( const char *  pattern,
bool  showSystem 
)

Definition at line 3926 of file describe.c.

3927{
3929 PGresult *res;
3930 printQueryOpt myopt = pset.popt;
3931
3934 "SELECT m.rolname AS \"%s\", r.rolname AS \"%s\",\n"
3935 " pg_catalog.concat_ws(', ',\n",
3936 gettext_noop("Role name"),
3937 gettext_noop("Member of"));
3938
3939 if (pset.sversion >= 160000)
3941 " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
3942 " CASE WHEN pam.inherit_option THEN 'INHERIT' END,\n"
3943 " CASE WHEN pam.set_option THEN 'SET' END\n");
3944 else
3946 " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
3947 " CASE WHEN m.rolinherit THEN 'INHERIT' END,\n"
3948 " 'SET'\n");
3949
3951 " ) AS \"%s\",\n"
3952 " g.rolname AS \"%s\"\n",
3953 gettext_noop("Options"),
3954 gettext_noop("Grantor"));
3955
3957 "FROM pg_catalog.pg_roles m\n"
3958 " JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)\n"
3959 " LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)\n"
3960 " LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)\n");
3961
3962 if (!showSystem && !pattern)
3963 appendPQExpBufferStr(&buf, "WHERE m.rolname !~ '^pg_'\n");
3964
3965 if (!validateSQLNamePattern(&buf, pattern, false, false,
3966 NULL, "m.rolname", NULL, NULL,
3967 NULL, 1))
3968 {
3970 return false;
3971 }
3972
3973 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;\n");
3974
3975 res = PSQLexec(buf.data);
3977 if (!res)
3978 return false;
3979
3980 myopt.title = _("List of role grants");
3981 myopt.translate_header = true;
3982
3983 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3984
3985 PQclear(res);
3986 return true;
3987}

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

Referenced by exec_command_d().

◆ describeRoles()

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

Definition at line 3710 of file describe.c.

3711{
3713 PGresult *res;
3714 printTableContent cont;
3715 printTableOpt myopt = pset.popt.topt;
3716 int ncols = 2;
3717 int nrows = 0;
3718 int i;
3719 int conns;
3720 const char align = 'l';
3721 char **attr;
3722
3723 myopt.default_footer = false;
3724
3726
3728 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
3729 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
3730 " r.rolconnlimit, r.rolvaliduntil");
3731
3732 if (verbose)
3733 {
3734 appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
3735 ncols++;
3736 }
3737 appendPQExpBufferStr(&buf, "\n, r.rolreplication");
3738
3739 if (pset.sversion >= 90500)
3740 {
3741 appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
3742 }
3743
3744 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
3745
3746 if (!showSystem && !pattern)
3747 appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
3748
3749 if (!validateSQLNamePattern(&buf, pattern, false, false,
3750 NULL, "r.rolname", NULL, NULL,
3751 NULL, 1))
3752 {
3754 return false;
3755 }
3756
3757 appendPQExpBufferStr(&buf, "ORDER BY 1;");
3758
3759 res = PSQLexec(buf.data);
3760 if (!res)
3761 return false;
3762
3763 nrows = PQntuples(res);
3764 attr = pg_malloc0((nrows + 1) * sizeof(*attr));
3765
3766 printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
3767
3768 printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
3769 printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
3770
3771 if (verbose)
3772 printTableAddHeader(&cont, gettext_noop("Description"), true, align);
3773
3774 for (i = 0; i < nrows; i++)
3775 {
3776 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
3777
3779 if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
3780 add_role_attribute(&buf, _("Superuser"));
3781
3782 if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
3783 add_role_attribute(&buf, _("No inheritance"));
3784
3785 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
3786 add_role_attribute(&buf, _("Create role"));
3787
3788 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
3789 add_role_attribute(&buf, _("Create DB"));
3790
3791 if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
3792 add_role_attribute(&buf, _("Cannot login"));
3793
3794 if (strcmp(PQgetvalue(res, i, (verbose ? 9 : 8)), "t") == 0)
3795 add_role_attribute(&buf, _("Replication"));
3796
3797 if (pset.sversion >= 90500)
3798 if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
3799 add_role_attribute(&buf, _("Bypass RLS"));
3800
3801 conns = atoi(PQgetvalue(res, i, 6));
3802 if (conns >= 0)
3803 {
3804 if (buf.len > 0)
3805 appendPQExpBufferChar(&buf, '\n');
3806
3807 if (conns == 0)
3808 appendPQExpBufferStr(&buf, _("No connections"));
3809 else
3810 appendPQExpBuffer(&buf, ngettext("%d connection",
3811 "%d connections",
3812 conns),
3813 conns);
3814 }
3815
3816 if (strcmp(PQgetvalue(res, i, 7), "") != 0)
3817 {
3818 if (buf.len > 0)
3819 appendPQExpBufferChar(&buf, '\n');
3820 appendPQExpBufferStr(&buf, _("Password valid until "));
3822 }
3823
3824 attr[i] = pg_strdup(buf.data);
3825
3826 printTableAddCell(&cont, attr[i], false, false);
3827
3828 if (verbose)
3829 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
3830 }
3832
3833 printTable(&cont, pset.queryFout, false, pset.logfile);
3834 printTableCleanup(&cont);
3835
3836 for (i = 0; i < nrows; i++)
3837 free(attr[i]);
3838 free(attr);
3839
3840 PQclear(res);
3841 return true;
3842}
#define ngettext(s, p, n)
Definition: c.h:1138
static void add_role_attribute(PQExpBuffer buf, const char *const str)
Definition: describe.c:3845
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
static IsoConnInfo * conns

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

Referenced by exec_command_d().

◆ describeSubscriptions()

bool describeSubscriptions ( const char *  pattern,
bool  verbose 
)

Definition at line 6737 of file describe.c.

6738{
6740 PGresult *res;
6741 printQueryOpt myopt = pset.popt;
6742 static const bool translate_columns[] = {false, false, false, false,
6743 false, false, false, false, false, false, false, false, false, false,
6744 false};
6745
6746 if (pset.sversion < 100000)
6747 {
6748 char sverbuf[32];
6749
6750 pg_log_error("The server (version %s) does not support subscriptions.",
6752 sverbuf, sizeof(sverbuf)));
6753 return true;
6754 }
6755
6757
6759 "SELECT subname AS \"%s\"\n"
6760 ", pg_catalog.pg_get_userbyid(subowner) AS \"%s\"\n"
6761 ", subenabled AS \"%s\"\n"
6762 ", subpublications AS \"%s\"\n",
6763 gettext_noop("Name"),
6764 gettext_noop("Owner"),
6765 gettext_noop("Enabled"),
6766 gettext_noop("Publication"));
6767
6768 if (verbose)
6769 {
6770 /* Binary mode and streaming are only supported in v14 and higher */
6771 if (pset.sversion >= 140000)
6772 {
6774 ", subbinary AS \"%s\"\n",
6775 gettext_noop("Binary"));
6776
6777 if (pset.sversion >= 160000)
6779 ", (CASE substream\n"
6780 " WHEN " CppAsString2(LOGICALREP_STREAM_OFF) " THEN 'off'\n"
6781 " WHEN " CppAsString2(LOGICALREP_STREAM_ON) " THEN 'on'\n"
6782 " WHEN " CppAsString2(LOGICALREP_STREAM_PARALLEL) " THEN 'parallel'\n"
6783 " END) AS \"%s\"\n",
6784 gettext_noop("Streaming"));
6785 else
6787 ", substream AS \"%s\"\n",
6788 gettext_noop("Streaming"));
6789 }
6790
6791 /* Two_phase and disable_on_error are only supported in v15 and higher */
6792 if (pset.sversion >= 150000)
6794 ", subtwophasestate AS \"%s\"\n"
6795 ", subdisableonerr AS \"%s\"\n",
6796 gettext_noop("Two-phase commit"),
6797 gettext_noop("Disable on error"));
6798
6799 if (pset.sversion >= 160000)
6801 ", suborigin AS \"%s\"\n"
6802 ", subpasswordrequired AS \"%s\"\n"
6803 ", subrunasowner AS \"%s\"\n",
6804 gettext_noop("Origin"),
6805 gettext_noop("Password required"),
6806 gettext_noop("Run as owner?"));
6807
6808 if (pset.sversion >= 170000)
6810 ", subfailover AS \"%s\"\n",
6811 gettext_noop("Failover"));
6812
6814 ", subsynccommit AS \"%s\"\n"
6815 ", subconninfo AS \"%s\"\n",
6816 gettext_noop("Synchronous commit"),
6817 gettext_noop("Conninfo"));
6818
6819 /* Skip LSN is only supported in v15 and higher */
6820 if (pset.sversion >= 150000)
6822 ", subskiplsn AS \"%s\"\n",
6823 gettext_noop("Skip LSN"));
6824 }
6825
6826 /* Only display subscriptions in current database. */
6828 "FROM pg_catalog.pg_subscription\n"
6829 "WHERE subdbid = (SELECT oid\n"
6830 " FROM pg_catalog.pg_database\n"
6831 " WHERE datname = pg_catalog.current_database())");
6832
6833 if (!validateSQLNamePattern(&buf, pattern, true, false,
6834 NULL, "subname", NULL,
6835 NULL,
6836 NULL, 1))
6837 {
6839 return false;
6840 }
6841
6842 appendPQExpBufferStr(&buf, "ORDER BY 1;");
6843
6844 res = PSQLexec(buf.data);
6846 if (!res)
6847 return false;
6848
6849 myopt.title = _("List of subscriptions");
6850 myopt.translate_header = true;
6851 myopt.translate_columns = translate_columns;
6852 myopt.n_translate_columns = lengthof(translate_columns);
6853
6854 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6855
6856 PQclear(res);
6857 return true;
6858}

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

Referenced by exec_command_d().

◆ describeTableDetails()

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

Definition at line 1483 of file describe.c.

1484{
1486 PGresult *res;
1487 int i;
1488
1490
1492 "SELECT c.oid,\n"
1493 " n.nspname,\n"
1494 " c.relname\n"
1495 "FROM pg_catalog.pg_class c\n"
1496 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1497
1498 if (!showSystem && !pattern)
1499 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1500 " AND n.nspname <> 'information_schema'\n");
1501
1502 if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, false,
1503 "n.nspname", "c.relname", NULL,
1504 "pg_catalog.pg_table_is_visible(c.oid)",
1505 NULL, 3))
1506 {
1508 return false;
1509 }
1510
1511 appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
1512
1513 res = PSQLexec(buf.data);
1515 if (!res)
1516 return false;
1517
1518 if (PQntuples(res) == 0)
1519 {
1520 if (!pset.quiet)
1521 {
1522 if (pattern)
1523 pg_log_error("Did not find any relation named \"%s\".",
1524 pattern);
1525 else
1526 pg_log_error("Did not find any relations.");
1527 }
1528 PQclear(res);
1529 return false;
1530 }
1531
1532 for (i = 0; i < PQntuples(res); i++)
1533 {
1534 const char *oid;
1535 const char *nspname;
1536 const char *relname;
1537
1538 oid = PQgetvalue(res, i, 0);
1539 nspname = PQgetvalue(res, i, 1);
1540 relname = PQgetvalue(res, i, 2);
1541
1542 if (!describeOneTableDetails(nspname, relname, oid, verbose))
1543 {
1544 PQclear(res);
1545 return false;
1546 }
1547 if (cancel_pressed)
1548 {
1549 PQclear(res);
1550 return false;
1551 }
1552 }
1553
1554 PQclear(res);
1555 return true;
1556}
static bool describeOneTableDetails(const char *schemaname, const char *relationname, const char *oid, bool verbose)
Definition: describe.c:1566
volatile sig_atomic_t cancel_pressed
Definition: print.c:43

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

Referenced by exec_command_d().

◆ describeTablespaces()

bool describeTablespaces ( const char *  pattern,
bool  verbose 
)

Definition at line 222 of file describe.c.

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

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

Referenced by exec_command_d().

◆ describeTypes()

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

Definition at line 638 of file describe.c.

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

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

Referenced by exec_command_d().

◆ listAllDbs()

bool listAllDbs ( const char *  pattern,
bool  verbose 
)

Definition at line 945 of file describe.c.

946{
947 PGresult *res;
949 printQueryOpt myopt = pset.popt;
950
952
954 "SELECT\n"
955 " d.datname as \"%s\",\n"
956 " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
957 " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
958 gettext_noop("Name"),
959 gettext_noop("Owner"),
960 gettext_noop("Encoding"));
961 if (pset.sversion >= 150000)
963 " CASE d.datlocprovider "
964 "WHEN " CppAsString2(COLLPROVIDER_BUILTIN) " THEN 'builtin' "
965 "WHEN " CppAsString2(COLLPROVIDER_LIBC) " THEN 'libc' "
966 "WHEN " CppAsString2(COLLPROVIDER_ICU) " THEN 'icu' "
967 "END AS \"%s\",\n",
968 gettext_noop("Locale Provider"));
969 else
971 " 'libc' AS \"%s\",\n",
972 gettext_noop("Locale Provider"));
974 " d.datcollate as \"%s\",\n"
975 " d.datctype as \"%s\",\n",
976 gettext_noop("Collate"),
977 gettext_noop("Ctype"));
978 if (pset.sversion >= 170000)
980 " d.datlocale as \"%s\",\n",
981 gettext_noop("Locale"));
982 else if (pset.sversion >= 150000)
984 " d.daticulocale as \"%s\",\n",
985 gettext_noop("Locale"));
986 else
988 " NULL as \"%s\",\n",
989 gettext_noop("Locale"));
990 if (pset.sversion >= 160000)
992 " d.daticurules as \"%s\",\n",
993 gettext_noop("ICU Rules"));
994 else
996 " NULL as \"%s\",\n",
997 gettext_noop("ICU Rules"));
999 printACLColumn(&buf, "d.datacl");
1000 if (verbose)
1002 ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
1003 " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
1004 " ELSE 'No Access'\n"
1005 " END as \"%s\""
1006 ",\n t.spcname as \"%s\""
1007 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
1008 gettext_noop("Size"),
1009 gettext_noop("Tablespace"),
1010 gettext_noop("Description"));
1012 "\nFROM pg_catalog.pg_database d\n");
1013 if (verbose)
1015 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
1016
1017 if (pattern)
1018 {
1019 if (!validateSQLNamePattern(&buf, pattern, false, false,
1020 NULL, "d.datname", NULL, NULL,
1021 NULL, 1))
1022 {
1024 return false;
1025 }
1026 }
1027
1028 appendPQExpBufferStr(&buf, "ORDER BY 1;");
1029 res = PSQLexec(buf.data);
1031 if (!res)
1032 return false;
1033
1034 myopt.title = _("List of databases");
1035 myopt.translate_header = true;
1036
1037 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1038
1039 PQclear(res);
1040 return true;
1041}

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

Referenced by exec_command_list(), and main().

◆ listCasts()

bool listCasts ( const char *  pattern,
bool  verbose 
)

Definition at line 4953 of file describe.c.

4954{
4956 PGresult *res;
4957 printQueryOpt myopt = pset.popt;
4958 static const bool translate_columns[] = {false, false, false, true, true, false};
4959
4961
4963 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
4964 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n",
4965 gettext_noop("Source type"),
4966 gettext_noop("Target type"));
4967
4968 /*
4969 * We don't attempt to localize '(binary coercible)' or '(with inout)',
4970 * because there's too much risk of gettext translating a function name
4971 * that happens to match some string in the PO database.
4972 */
4974 " CASE WHEN c.castmethod = '%c' THEN '(binary coercible)'\n"
4975 " WHEN c.castmethod = '%c' THEN '(with inout)'\n"
4976 " ELSE p.proname\n"
4977 " END AS \"%s\",\n",
4978 COERCION_METHOD_BINARY,
4979 COERCION_METHOD_INOUT,
4980 gettext_noop("Function"));
4981
4983 " CASE WHEN c.castcontext = '%c' THEN '%s'\n"
4984 " WHEN c.castcontext = '%c' THEN '%s'\n"
4985 " ELSE '%s'\n"
4986 " END AS \"%s\"",
4987 COERCION_CODE_EXPLICIT,
4988 gettext_noop("no"),
4989 COERCION_CODE_ASSIGNMENT,
4990 gettext_noop("in assignment"),
4991 gettext_noop("yes"),
4992 gettext_noop("Implicit?"));
4993
4994 if (verbose)
4996 ",\n CASE WHEN p.proleakproof THEN '%s'\n"
4997 " ELSE '%s'\n"
4998 " END AS \"%s\",\n"
4999 " d.description AS \"%s\"",
5000 gettext_noop("yes"),
5001 gettext_noop("no"),
5002 gettext_noop("Leakproof?"),
5003 gettext_noop("Description"));
5004
5005 /*
5006 * We need a left join to pg_proc for binary casts; the others are just
5007 * paranoia.
5008 */
5010 "\nFROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
5011 " ON c.castfunc = p.oid\n"
5012 " LEFT JOIN pg_catalog.pg_type ts\n"
5013 " ON c.castsource = ts.oid\n"
5014 " LEFT JOIN pg_catalog.pg_namespace ns\n"
5015 " ON ns.oid = ts.typnamespace\n"
5016 " LEFT JOIN pg_catalog.pg_type tt\n"
5017 " ON c.casttarget = tt.oid\n"
5018 " LEFT JOIN pg_catalog.pg_namespace nt\n"
5019 " ON nt.oid = tt.typnamespace\n");
5020
5021 if (verbose)
5023 " LEFT JOIN pg_catalog.pg_description d\n"
5024 " ON d.classoid = c.tableoid AND d.objoid = "
5025 "c.oid AND d.objsubid = 0\n");
5026
5027 appendPQExpBufferStr(&buf, "WHERE ( (true");
5028
5029 /*
5030 * Match name pattern against either internal or external name of either
5031 * castsource or casttarget
5032 */
5033 if (!validateSQLNamePattern(&buf, pattern, true, false,
5034 "ns.nspname", "ts.typname",
5035 "pg_catalog.format_type(ts.oid, NULL)",
5036 "pg_catalog.pg_type_is_visible(ts.oid)",
5037 NULL, 3))
5038 goto error_return;
5039
5040 appendPQExpBufferStr(&buf, ") OR (true");
5041
5042 if (!validateSQLNamePattern(&buf, pattern, true, false,
5043 "nt.nspname", "tt.typname",
5044 "pg_catalog.format_type(tt.oid, NULL)",
5045 "pg_catalog.pg_type_is_visible(tt.oid)",
5046 NULL, 3))
5047 goto error_return;
5048
5049 appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
5050
5051 res = PSQLexec(buf.data);
5053 if (!res)
5054 return false;
5055
5056 myopt.title = _("List of casts");
5057 myopt.translate_header = true;
5058 myopt.translate_columns = translate_columns;
5059 myopt.n_translate_columns = lengthof(translate_columns);
5060
5061 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5062
5063 PQclear(res);
5064 return true;
5065
5066error_return:
5068 return false;
5069}

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

Referenced by exec_command_d().

◆ listCollations()

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

Definition at line 5077 of file describe.c.

5078{
5080 PGresult *res;
5081 printQueryOpt myopt = pset.popt;
5082 static const bool translate_columns[] = {false, false, false, false, false, false, false, true, false};
5083
5085
5087 "SELECT\n"
5088 " n.nspname AS \"%s\",\n"
5089 " c.collname AS \"%s\",\n",
5090 gettext_noop("Schema"),
5091 gettext_noop("Name"));
5092
5093 if (pset.sversion >= 100000)
5095 " CASE c.collprovider "
5096 "WHEN " CppAsString2(COLLPROVIDER_DEFAULT) " THEN 'default' "
5097 "WHEN " CppAsString2(COLLPROVIDER_BUILTIN) " THEN 'builtin' "
5098 "WHEN " CppAsString2(COLLPROVIDER_LIBC) " THEN 'libc' "
5099 "WHEN " CppAsString2(COLLPROVIDER_ICU) " THEN 'icu' "
5100 "END AS \"%s\",\n",
5101 gettext_noop("Provider"));
5102 else
5104 " 'libc' AS \"%s\",\n",
5105 gettext_noop("Provider"));
5106
5108 " c.collcollate AS \"%s\",\n"
5109 " c.collctype AS \"%s\",\n",
5110 gettext_noop("Collate"),
5111 gettext_noop("Ctype"));
5112
5113 if (pset.sversion >= 170000)
5115 " c.colllocale AS \"%s\",\n",
5116 gettext_noop("Locale"));
5117 else if (pset.sversion >= 150000)
5119 " c.colliculocale AS \"%s\",\n",
5120 gettext_noop("Locale"));
5121 else
5123 " c.collcollate AS \"%s\",\n",
5124 gettext_noop("Locale"));
5125
5126 if (pset.sversion >= 160000)
5128 " c.collicurules AS \"%s\",\n",
5129 gettext_noop("ICU Rules"));
5130 else
5132 " NULL AS \"%s\",\n",
5133 gettext_noop("ICU Rules"));
5134
5135 if (pset.sversion >= 120000)
5137 " CASE WHEN c.collisdeterministic THEN '%s' ELSE '%s' END AS \"%s\"",
5138 gettext_noop("yes"), gettext_noop("no"),
5139 gettext_noop("Deterministic?"));
5140 else
5142 " '%s' AS \"%s\"",
5143 gettext_noop("yes"),
5144 gettext_noop("Deterministic?"));
5145
5146 if (verbose)
5148 ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
5149 gettext_noop("Description"));
5150
5152 "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
5153 "WHERE n.oid = c.collnamespace\n");
5154
5155 if (!showSystem && !pattern)
5156 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
5157 " AND n.nspname <> 'information_schema'\n");
5158
5159 /*
5160 * Hide collations that aren't usable in the current database's encoding.
5161 * If you think to change this, note that pg_collation_is_visible rejects
5162 * unusable collations, so you will need to hack name pattern processing
5163 * somehow to avoid inconsistent behavior.
5164 */
5165 appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
5166
5167 if (!validateSQLNamePattern(&buf, pattern, true, false,
5168 "n.nspname", "c.collname", NULL,
5169 "pg_catalog.pg_collation_is_visible(c.oid)",
5170 NULL, 3))
5171 {
5173 return false;
5174 }
5175
5176 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5177
5178 res = PSQLexec(buf.data);
5180 if (!res)
5181 return false;
5182
5183 myopt.title = _("List of collations");
5184 myopt.translate_header = true;
5185 myopt.translate_columns = translate_columns;
5186 myopt.n_translate_columns = lengthof(translate_columns);
5187
5188 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5189
5190 PQclear(res);
5191 return true;
5192}

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

Referenced by exec_command_d().

◆ listConversions()

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

Definition at line 4629 of file describe.c.

4630{
4632 PGresult *res;
4633 printQueryOpt myopt = pset.popt;
4634 static const bool translate_columns[] =
4635 {false, false, false, false, true, false};
4636
4638
4640 "SELECT n.nspname AS \"%s\",\n"
4641 " c.conname AS \"%s\",\n"
4642 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
4643 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
4644 " CASE WHEN c.condefault THEN '%s'\n"
4645 " ELSE '%s' END AS \"%s\"",
4646 gettext_noop("Schema"),
4647 gettext_noop("Name"),
4648 gettext_noop("Source"),
4649 gettext_noop("Destination"),
4650 gettext_noop("yes"), gettext_noop("no"),
4651 gettext_noop("Default?"));
4652
4653 if (verbose)
4655 ",\n d.description AS \"%s\"",
4656 gettext_noop("Description"));
4657
4659 "\nFROM pg_catalog.pg_conversion c\n"
4660 " JOIN pg_catalog.pg_namespace n "
4661 "ON n.oid = c.connamespace\n");
4662
4663 if (verbose)
4665 "LEFT JOIN pg_catalog.pg_description d "
4666 "ON d.classoid = c.tableoid\n"
4667 " AND d.objoid = c.oid "
4668 "AND d.objsubid = 0\n");
4669
4670 appendPQExpBufferStr(&buf, "WHERE true\n");
4671
4672 if (!showSystem && !pattern)
4673 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4674 " AND n.nspname <> 'information_schema'\n");
4675
4676 if (!validateSQLNamePattern(&buf, pattern, true, false,
4677 "n.nspname", "c.conname", NULL,
4678 "pg_catalog.pg_conversion_is_visible(c.oid)",
4679 NULL, 3))
4680 {
4682 return false;
4683 }
4684
4685 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4686
4687 res = PSQLexec(buf.data);
4689 if (!res)
4690 return false;
4691
4692 myopt.title = _("List of conversions");
4693 myopt.translate_header = true;
4694 myopt.translate_columns = translate_columns;
4695 myopt.n_translate_columns = lengthof(translate_columns);
4696
4697 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4698
4699 PQclear(res);
4700 return true;
4701}

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

Referenced by exec_command_d().

◆ listDbRoleSettings()

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

Definition at line 3857 of file describe.c.

3858{
3860 PGresult *res;
3861 printQueryOpt myopt = pset.popt;
3862 bool havewhere;
3863
3865
3866 printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
3867 "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
3868 "FROM pg_catalog.pg_db_role_setting s\n"
3869 "LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n"
3870 "LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n",
3871 gettext_noop("Role"),
3872 gettext_noop("Database"),
3873 gettext_noop("Settings"));
3874 if (!validateSQLNamePattern(&buf, pattern, false, false,
3875 NULL, "r.rolname", NULL, NULL, &havewhere, 1))
3876 goto error_return;
3877 if (!validateSQLNamePattern(&buf, pattern2, havewhere, false,
3878 NULL, "d.datname", NULL, NULL,
3879 NULL, 1))
3880 goto error_return;
3881 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3882
3883 res = PSQLexec(buf.data);
3885 if (!res)
3886 return false;
3887
3888 /*
3889 * Most functions in this file are content to print an empty table when
3890 * there are no matching objects. We intentionally deviate from that
3891 * here, but only in !quiet mode, because of the possibility that the user
3892 * is confused about what the two pattern arguments mean.
3893 */
3894 if (PQntuples(res) == 0 && !pset.quiet)
3895 {
3896 if (pattern && pattern2)
3897 pg_log_error("Did not find any settings for role \"%s\" and database \"%s\".",
3898 pattern, pattern2);
3899 else if (pattern)
3900 pg_log_error("Did not find any settings for role \"%s\".",
3901 pattern);
3902 else
3903 pg_log_error("Did not find any settings.");
3904 }
3905 else
3906 {
3907 myopt.title = _("List of settings");
3908 myopt.translate_header = true;
3909
3910 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3911 }
3912
3913 PQclear(res);
3914 return true;
3915
3916error_return:
3918 return false;
3919}

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

Referenced by exec_command_d().

◆ listDefaultACLs()

bool listDefaultACLs ( const char *  pattern)

Definition at line 1213 of file describe.c.

1214{
1216 PGresult *res;
1217 printQueryOpt myopt = pset.popt;
1218 static const bool translate_columns[] = {false, false, true, false};
1219
1221
1223 "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
1224 " n.nspname AS \"%s\",\n"
1225 " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
1226 " ",
1227 gettext_noop("Owner"),
1228 gettext_noop("Schema"),
1229 DEFACLOBJ_RELATION,
1230 gettext_noop("table"),
1231 DEFACLOBJ_SEQUENCE,
1232 gettext_noop("sequence"),
1233 DEFACLOBJ_FUNCTION,
1234 gettext_noop("function"),
1235 DEFACLOBJ_TYPE,
1236 gettext_noop("type"),
1237 DEFACLOBJ_NAMESPACE,
1238 gettext_noop("schema"),
1239 gettext_noop("Type"));
1240
1241 printACLColumn(&buf, "d.defaclacl");
1242
1243 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
1244 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
1245
1246 if (!validateSQLNamePattern(&buf, pattern, false, false,
1247 NULL,
1248 "n.nspname",
1249 "pg_catalog.pg_get_userbyid(d.defaclrole)",
1250 NULL,
1251 NULL, 3))
1252 goto error_return;
1253
1254 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1255
1256 res = PSQLexec(buf.data);
1257 if (!res)
1258 goto error_return;
1259
1260 printfPQExpBuffer(&buf, _("Default access privileges"));
1261 myopt.title = buf.data;
1262 myopt.translate_header = true;
1263 myopt.translate_columns = translate_columns;
1264 myopt.n_translate_columns = lengthof(translate_columns);
1265
1266 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1267
1269 PQclear(res);
1270 return true;
1271
1272error_return:
1274 return false;
1275}

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

Referenced by exec_command_d().

◆ listDomains()

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

Definition at line 4546 of file describe.c.

4547{
4549 PGresult *res;
4550 printQueryOpt myopt = pset.popt;
4551
4553
4555 "SELECT n.nspname as \"%s\",\n"
4556 " t.typname as \"%s\",\n"
4557 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
4558 " (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
4559 " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as \"%s\",\n"
4560 " CASE WHEN t.typnotnull THEN 'not null' END as \"%s\",\n"
4561 " t.typdefault as \"%s\",\n"
4562 " pg_catalog.array_to_string(ARRAY(\n"
4563 " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid AND r.contype = " CppAsString2(CONSTRAINT_CHECK) " ORDER BY r.conname\n"
4564 " ), ' ') as \"%s\"",
4565 gettext_noop("Schema"),
4566 gettext_noop("Name"),
4567 gettext_noop("Type"),
4568 gettext_noop("Collation"),
4569 gettext_noop("Nullable"),
4570 gettext_noop("Default"),
4571 gettext_noop("Check"));
4572
4573 if (verbose)
4574 {
4575 appendPQExpBufferStr(&buf, ",\n ");
4576 printACLColumn(&buf, "t.typacl");
4578 ",\n d.description as \"%s\"",
4579 gettext_noop("Description"));
4580 }
4581
4583 "\nFROM pg_catalog.pg_type t\n"
4584 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
4585
4586 if (verbose)
4588 " LEFT JOIN pg_catalog.pg_description d "
4589 "ON d.classoid = t.tableoid AND d.objoid = t.oid "
4590 "AND d.objsubid = 0\n");
4591
4592 appendPQExpBufferStr(&buf, "WHERE t.typtype = 'd'\n");
4593
4594 if (!showSystem && !pattern)
4595 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4596 " AND n.nspname <> 'information_schema'\n");
4597
4598 if (!validateSQLNamePattern(&buf, pattern, true, false,
4599 "n.nspname", "t.typname", NULL,
4600 "pg_catalog.pg_type_is_visible(t.oid)",
4601 NULL, 3))
4602 {
4604 return false;
4605 }
4606
4607 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4608
4609 res = PSQLexec(buf.data);
4611 if (!res)
4612 return false;
4613
4614 myopt.title = _("List of domains");
4615 myopt.translate_header = true;
4616
4617 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4618
4619 PQclear(res);
4620 return true;
4621}

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

Referenced by exec_command_d().

◆ listEventTriggers()

bool listEventTriggers ( const char *  pattern,
bool  verbose 
)

Definition at line 4777 of file describe.c.

4778{
4780 PGresult *res;
4781 printQueryOpt myopt = pset.popt;
4782 static const bool translate_columns[] =
4783 {false, false, false, true, false, false, false};
4784
4785 if (pset.sversion < 90300)
4786 {
4787 char sverbuf[32];
4788
4789 pg_log_error("The server (version %s) does not support event triggers.",
4791 sverbuf, sizeof(sverbuf)));
4792 return true;
4793 }
4794
4796
4798 "SELECT evtname as \"%s\", "
4799 "evtevent as \"%s\", "
4800 "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
4801 " case evtenabled when 'O' then '%s'"
4802 " when 'R' then '%s'"
4803 " when 'A' then '%s'"
4804 " when 'D' then '%s' end as \"%s\",\n"
4805 " e.evtfoid::pg_catalog.regproc as \"%s\", "
4806 "pg_catalog.array_to_string(array(select x"
4807 " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
4808 gettext_noop("Name"),
4809 gettext_noop("Event"),
4810 gettext_noop("Owner"),
4811 gettext_noop("enabled"),
4812 gettext_noop("replica"),
4813 gettext_noop("always"),
4814 gettext_noop("disabled"),
4815 gettext_noop("Enabled"),
4816 gettext_noop("Function"),
4817 gettext_noop("Tags"));
4818 if (verbose)
4820 ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
4821 gettext_noop("Description"));
4823 "\nFROM pg_catalog.pg_event_trigger e ");
4824
4825 if (!validateSQLNamePattern(&buf, pattern, false, false,
4826 NULL, "evtname", NULL, NULL,
4827 NULL, 1))
4828 {
4830 return false;
4831 }
4832
4833 appendPQExpBufferStr(&buf, "ORDER BY 1");
4834
4835 res = PSQLexec(buf.data);
4837 if (!res)
4838 return false;
4839
4840 myopt.title = _("List of event triggers");
4841 myopt.translate_header = true;
4842 myopt.translate_columns = translate_columns;
4843 myopt.n_translate_columns = lengthof(translate_columns);
4844
4845 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4846
4847 PQclear(res);
4848 return true;
4849}

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

Referenced by exec_command_d().

◆ listExtendedStats()

bool listExtendedStats ( const char *  pattern)

Definition at line 4857 of file describe.c.

4858{
4860 PGresult *res;
4861 printQueryOpt myopt = pset.popt;
4862
4863 if (pset.sversion < 100000)
4864 {
4865 char sverbuf[32];
4866
4867 pg_log_error("The server (version %s) does not support extended statistics.",
4869 sverbuf, sizeof(sverbuf)));
4870 return true;
4871 }
4872
4875 "SELECT \n"
4876 "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS \"%s\", \n"
4877 "es.stxname AS \"%s\", \n",
4878 gettext_noop("Schema"),
4879 gettext_noop("Name"));
4880
4881 if (pset.sversion >= 140000)
4883 "pg_catalog.format('%%s FROM %%s', \n"
4884 " pg_catalog.pg_get_statisticsobjdef_columns(es.oid), \n"
4885 " es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4886 gettext_noop("Definition"));
4887 else
4889 "pg_catalog.format('%%s FROM %%s', \n"
4890 " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n"
4891 " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n"
4892 " JOIN pg_catalog.pg_attribute a \n"
4893 " ON (es.stxrelid = a.attrelid \n"
4894 " AND a.attnum = s.attnum \n"
4895 " AND NOT a.attisdropped)), \n"
4896 "es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4897 gettext_noop("Definition"));
4898
4900 ",\nCASE WHEN " CppAsString2(STATS_EXT_NDISTINCT) " = any(es.stxkind) THEN 'defined' \n"
4901 "END AS \"%s\", \n"
4902 "CASE WHEN " CppAsString2(STATS_EXT_DEPENDENCIES) " = any(es.stxkind) THEN 'defined' \n"
4903 "END AS \"%s\"",
4904 gettext_noop("Ndistinct"),
4905 gettext_noop("Dependencies"));
4906
4907 /*
4908 * Include the MCV statistics kind.
4909 */
4910 if (pset.sversion >= 120000)
4911 {
4913 ",\nCASE WHEN " CppAsString2(STATS_EXT_MCV) " = any(es.stxkind) THEN 'defined' \n"
4914 "END AS \"%s\" ",
4915 gettext_noop("MCV"));
4916 }
4917
4919 " \nFROM pg_catalog.pg_statistic_ext es \n");
4920
4921 if (!validateSQLNamePattern(&buf, pattern,
4922 false, false,
4923 "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname",
4924 NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)",
4925 NULL, 3))
4926 {
4928 return false;
4929 }
4930
4931 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4932
4933 res = PSQLexec(buf.data);
4935 if (!res)
4936 return false;
4937
4938 myopt.title = _("List of extended statistics");
4939 myopt.translate_header = true;
4940
4941 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4942
4943 PQclear(res);
4944 return true;
4945}

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

Referenced by exec_command_d().

◆ listExtensionContents()

bool listExtensionContents ( const char *  pattern)

Definition at line 6227 of file describe.c.

6228{
6230 PGresult *res;
6231 int i;
6232
6235 "SELECT e.extname, e.oid\n"
6236 "FROM pg_catalog.pg_extension e\n");
6237
6238 if (!validateSQLNamePattern(&buf, pattern,
6239 false, false,
6240 NULL, "e.extname", NULL,
6241 NULL,
6242 NULL, 1))
6243 {
6245 return false;
6246 }
6247
6248 appendPQExpBufferStr(&buf, "ORDER BY 1;");
6249
6250 res = PSQLexec(buf.data);
6252 if (!res)
6253 return false;
6254
6255 if (PQntuples(res) == 0)
6256 {
6257 if (!pset.quiet)
6258 {
6259 if (pattern)
6260 pg_log_error("Did not find any extension named \"%s\".",
6261 pattern);
6262 else
6263 pg_log_error("Did not find any extensions.");
6264 }
6265 PQclear(res);
6266 return false;
6267 }
6268
6269 for (i = 0; i < PQntuples(res); i++)
6270 {
6271 const char *extname;
6272 const char *oid;
6273
6274 extname = PQgetvalue(res, i, 0);
6275 oid = PQgetvalue(res, i, 1);
6276
6277 if (!listOneExtensionContents(extname, oid))
6278 {
6279 PQclear(res);
6280 return false;
6281 }
6282 if (cancel_pressed)
6283 {
6284 PQclear(res);
6285 return false;
6286 }
6287 }
6288
6289 PQclear(res);
6290 return true;
6291}
static bool listOneExtensionContents(const char *extname, const char *oid)
Definition: describe.c:6294

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

Referenced by exec_command_d().

◆ listExtensions()

bool listExtensions ( const char *  pattern)

Definition at line 6176 of file describe.c.

6177{
6179 PGresult *res;
6180 printQueryOpt myopt = pset.popt;
6181
6184 "SELECT e.extname AS \"%s\", "
6185 "e.extversion AS \"%s\", n.nspname AS \"%s\", c.description AS \"%s\"\n"
6186 "FROM pg_catalog.pg_extension e "
6187 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
6188 "LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
6189 "AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass\n",
6190 gettext_noop("Name"),
6191 gettext_noop("Version"),
6192 gettext_noop("Schema"),
6193 gettext_noop("Description"));
6194
6195 if (!validateSQLNamePattern(&buf, pattern,
6196 false, false,
6197 NULL, "e.extname", NULL,
6198 NULL,
6199 NULL, 1))
6200 {
6202 return false;
6203 }
6204
6205 appendPQExpBufferStr(&buf, "ORDER BY 1;");
6206
6207 res = PSQLexec(buf.data);
6209 if (!res)
6210 return false;
6211
6212 myopt.title = _("List of installed extensions");
6213 myopt.translate_header = true;
6214
6215 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6216
6217 PQclear(res);
6218 return true;
6219}

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

Referenced by exec_command_d().

◆ listForeignDataWrappers()

bool listForeignDataWrappers ( const char *  pattern,
bool  verbose 
)

Definition at line 5902 of file describe.c.

5903{
5905 PGresult *res;
5906 printQueryOpt myopt = pset.popt;
5907
5910 "SELECT fdw.fdwname AS \"%s\",\n"
5911 " pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n"
5912 " fdw.fdwhandler::pg_catalog.regproc AS \"%s\",\n"
5913 " fdw.fdwvalidator::pg_catalog.regproc AS \"%s\"",
5914 gettext_noop("Name"),
5915 gettext_noop("Owner"),
5916 gettext_noop("Handler"),
5917 gettext_noop("Validator"));
5918
5919 if (verbose)
5920 {
5921 appendPQExpBufferStr(&buf, ",\n ");
5922 printACLColumn(&buf, "fdwacl");
5924 ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
5925 " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5926 " pg_catalog.quote_ident(option_name) || ' ' || "
5927 " pg_catalog.quote_literal(option_value) FROM "
5928 " pg_catalog.pg_options_to_table(fdwoptions)), ', ') || ')' "
5929 " END AS \"%s\""
5930 ",\n d.description AS \"%s\" ",
5931 gettext_noop("FDW options"),
5932 gettext_noop("Description"));
5933 }
5934
5935 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
5936
5937 if (verbose)
5939 "LEFT JOIN pg_catalog.pg_description d\n"
5940 " ON d.classoid = fdw.tableoid "
5941 "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
5942
5943 if (!validateSQLNamePattern(&buf, pattern, false, false,
5944 NULL, "fdwname", NULL, NULL,
5945 NULL, 1))
5946 {
5948 return false;
5949 }
5950
5951 appendPQExpBufferStr(&buf, "ORDER BY 1;");
5952
5953 res = PSQLexec(buf.data);
5955 if (!res)
5956 return false;
5957
5958 myopt.title = _("List of foreign-data wrappers");
5959 myopt.translate_header = true;
5960
5961 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5962
5963 PQclear(res);
5964 return true;
5965}

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

Referenced by exec_command_d().

◆ listForeignServers()

bool listForeignServers ( const char *  pattern,
bool  verbose 
)

Definition at line 5973 of file describe.c.

5974{
5976 PGresult *res;
5977 printQueryOpt myopt = pset.popt;
5978
5981 "SELECT s.srvname AS \"%s\",\n"
5982 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
5983 " f.fdwname AS \"%s\"",
5984 gettext_noop("Name"),
5985 gettext_noop("Owner"),
5986 gettext_noop("Foreign-data wrapper"));
5987
5988 if (verbose)
5989 {
5990 appendPQExpBufferStr(&buf, ",\n ");
5991 printACLColumn(&buf, "s.srvacl");
5993 ",\n"
5994 " s.srvtype AS \"%s\",\n"
5995 " s.srvversion AS \"%s\",\n"
5996 " CASE WHEN srvoptions IS NULL THEN '' ELSE "
5997 " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5998 " pg_catalog.quote_ident(option_name) || ' ' || "
5999 " pg_catalog.quote_literal(option_value) FROM "
6000 " pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')' "
6001 " END AS \"%s\",\n"
6002 " d.description AS \"%s\"",
6003 gettext_noop("Type"),
6004 gettext_noop("Version"),
6005 gettext_noop("FDW options"),
6006 gettext_noop("Description"));
6007 }
6008
6009