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

3882{
3883 if (buf->len > 0)
3885
3887}
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 3681 of file describe.c.

3683{
3684 /* relkinds for which we support tablespaces */
3685 if (relkind == RELKIND_RELATION ||
3686 relkind == RELKIND_MATVIEW ||
3687 relkind == RELKIND_INDEX ||
3688 relkind == RELKIND_PARTITIONED_TABLE ||
3689 relkind == RELKIND_PARTITIONED_INDEX ||
3690 relkind == RELKIND_TOASTVALUE)
3691 {
3692 /*
3693 * We ignore the database default tablespace so that users not using
3694 * tablespaces don't need to know about them.
3695 */
3696 if (tablespace != 0)
3697 {
3698 PGresult *result = NULL;
3700
3703 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
3704 "WHERE oid = '%u';", tablespace);
3705 result = PSQLexec(buf.data);
3706 if (!result)
3707 {
3709 return;
3710 }
3711 /* Should always be the case, but.... */
3712 if (PQntuples(result) > 0)
3713 {
3714 if (newline)
3715 {
3716 /* Add the tablespace as a new footer */
3717 printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
3718 PQgetvalue(result, 0, 0));
3719 printTableAddFooter(cont, buf.data);
3720 }
3721 else
3722 {
3723 /* Append the tablespace to the latest footer */
3724 printfPQExpBuffer(&buf, "%s", cont->footer->data);
3725
3726 /*-------
3727 translator: before this string there's an index description like
3728 '"foo_pkey" PRIMARY KEY, btree (a)' */
3729 appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
3730 PQgetvalue(result, 0, 0));
3731 printTableSetFooter(cont, buf.data);
3732 }
3733 }
3734 PQclear(result);
3736 }
3737 }
3738}
PGresult * PSQLexec(const char *query)
Definition: common.c:655
#define _(x)
Definition: elog.c:91
void printTableSetFooter(printTableContent *const content, const char *footer)
Definition: print.c:3354
void printTableAddFooter(printTableContent *const content, const char *footer)
Definition: print.c:3329
#define newline
Definition: indent_codes.h:35
#define PQgetvalue
Definition: libpq-be-fe.h:253
#define PQclear
Definition: libpq-be-fe.h:245
#define PQntuples
Definition: libpq-be-fe.h:251
static char * tablespace
Definition: pgbench.c:217
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 6522 of file describe.c.

6524{
6525 PGresult *res;
6526 int count = 0;
6527 int i = 0;
6528
6529 res = PSQLexec(buf->data);
6530 if (!res)
6531 return false;
6532 else
6533 count = PQntuples(res);
6534
6535 if (count > 0)
6536 printTableAddFooter(cont, footermsg);
6537
6538 for (i = 0; i < count; i++)
6539 {
6540 if (as_schema)
6541 printfPQExpBuffer(buf, " \"%s\"", PQgetvalue(res, i, 0));
6542 else
6543 {
6544 printfPQExpBuffer(buf, " \"%s.%s\"", PQgetvalue(res, i, 0),
6545 PQgetvalue(res, i, 1));
6546
6547 if (!PQgetisnull(res, i, 3))
6548 appendPQExpBuffer(buf, " (%s)", PQgetvalue(res, i, 3));
6549
6550 if (!PQgetisnull(res, i, 2))
6551 appendPQExpBuffer(buf, " WHERE %s", PQgetvalue(res, i, 2));
6552 }
6553
6554 printTableAddFooter(cont, buf->data);
6555 }
6556
6557 PQclear(res);
6558 return true;
6559}
int i
Definition: isn.c:77
#define PQgetisnull
Definition: libpq-be-fe.h:255

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

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:1184
#define CppAsString2(x)
Definition: c.h:423
#define lengthof(array)
Definition: c.h:790
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:6377
void printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, bool is_pager, FILE *flog)
Definition: print.c:3742
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:313
printQueryOpt popt
Definition: settings.h:112
FILE * logfile
Definition: settings.h:149
FILE * queryFout
Definition: settings.h:105
const bool * translate_columns
Definition: print.h:192
char * title
Definition: print.h:189
bool translate_header
Definition: print.h:191
int n_translate_columns
Definition: print.h:194

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, _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{
81 PGresult *res;
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, _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 4745 of file describe.c.

4747{
4749 PGresult *res;
4750 printQueryOpt myopt = pset.popt;
4751
4754 "SELECT s.name AS \"%s\", "
4755 "pg_catalog.current_setting(s.name) AS \"%s\"",
4756 gettext_noop("Parameter"),
4757 gettext_noop("Value"));
4758
4759 if (verbose)
4760 {
4762 ", s.vartype AS \"%s\", s.context AS \"%s\", ",
4763 gettext_noop("Type"),
4764 gettext_noop("Context"));
4765 if (pset.sversion >= 150000)
4766 printACLColumn(&buf, "p.paracl");
4767 else
4768 appendPQExpBuffer(&buf, "NULL AS \"%s\"",
4769 gettext_noop("Access privileges"));
4770 }
4771
4772 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_settings s\n");
4773
4774 if (verbose && pset.sversion >= 150000)
4776 " LEFT JOIN pg_catalog.pg_parameter_acl p\n"
4777 " ON pg_catalog.lower(s.name) = p.parname\n");
4778
4779 if (pattern)
4780 processSQLNamePattern(pset.db, &buf, pattern,
4781 false, false,
4782 NULL, "pg_catalog.lower(s.name)", NULL,
4783 NULL, NULL, NULL);
4784 else
4785 appendPQExpBufferStr(&buf, "WHERE s.source <> 'default' AND\n"
4786 " s.setting IS DISTINCT FROM s.boot_val\n");
4787
4788 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4789
4790 res = PSQLexec(buf.data);
4792 if (!res)
4793 return false;
4794
4795 if (pattern)
4796 myopt.title = _("List of configuration parameters");
4797 else
4798 myopt.title = _("List of non-default configuration parameters");
4799 myopt.translate_header = true;
4800
4801 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4802
4803 PQclear(res);
4804 return true;
4805}
static void printACLColumn(PQExpBuffer buf, const char *colname)
Definition: describe.c:6950
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)
PGconn * db
Definition: settings.h:103

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

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

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

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

5869{
5871 title;
5872 PGresult *res;
5873 printQueryOpt myopt = pset.popt;
5874
5876
5878 "SELECT\n"
5879 " ( SELECT t.alias FROM\n"
5880 " pg_catalog.ts_token_type(c.cfgparser) AS t\n"
5881 " WHERE t.tokid = m.maptokentype ) AS \"%s\",\n"
5882 " pg_catalog.btrim(\n"
5883 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary\n"
5884 " FROM pg_catalog.pg_ts_config_map AS mm\n"
5885 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype\n"
5886 " ORDER BY mapcfg, maptokentype, mapseqno\n"
5887 " ) :: pg_catalog.text,\n"
5888 " '{}') AS \"%s\"\n"
5889 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m\n"
5890 "WHERE c.oid = '%s' AND m.mapcfg = c.oid\n"
5891 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser\n"
5892 "ORDER BY 1;",
5893 gettext_noop("Token"),
5894 gettext_noop("Dictionaries"),
5895 oid);
5896
5897 res = PSQLexec(buf.data);
5899 if (!res)
5900 return false;
5901
5902 initPQExpBuffer(&title);
5903
5904 if (nspname)
5905 appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
5906 nspname, cfgname);
5907 else
5908 appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
5909 cfgname);
5910
5911 if (pnspname)
5912 appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
5913 pnspname, prsname);
5914 else
5915 appendPQExpBuffer(&title, _("\nParser: \"%s\""),
5916 prsname);
5917
5918 myopt.title = title.data;
5919 myopt.footers = NULL;
5920 myopt.topt.default_footer = false;
5921 myopt.translate_header = true;
5922
5923 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5924
5925 termPQExpBuffer(&title);
5926
5927 PQclear(res);
5928 return true;
5929}

References _, appendPQExpBuffer(), buf, PQExpBufferData::data, printTableOpt::default_footer, printQueryOpt::footers, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, _psqlSettings::popt, PQclear, printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, 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 5484 of file describe.c.

5485{
5487 PGresult *res;
5488 PQExpBufferData title;
5489 printQueryOpt myopt = pset.popt;
5490 static const bool translate_columns[] = {true, false, false};
5491
5493
5495 "SELECT '%s' AS \"%s\",\n"
5496 " p.prsstart::pg_catalog.regproc AS \"%s\",\n"
5497 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\"\n"
5498 " FROM pg_catalog.pg_ts_parser p\n"
5499 " WHERE p.oid = '%s'\n"
5500 "UNION ALL\n"
5501 "SELECT '%s',\n"
5502 " p.prstoken::pg_catalog.regproc,\n"
5503 " pg_catalog.obj_description(p.prstoken, 'pg_proc')\n"
5504 " FROM pg_catalog.pg_ts_parser p\n"
5505 " WHERE p.oid = '%s'\n"
5506 "UNION ALL\n"
5507 "SELECT '%s',\n"
5508 " p.prsend::pg_catalog.regproc,\n"
5509 " pg_catalog.obj_description(p.prsend, 'pg_proc')\n"
5510 " FROM pg_catalog.pg_ts_parser p\n"
5511 " WHERE p.oid = '%s'\n"
5512 "UNION ALL\n"
5513 "SELECT '%s',\n"
5514 " p.prsheadline::pg_catalog.regproc,\n"
5515 " pg_catalog.obj_description(p.prsheadline, 'pg_proc')\n"
5516 " FROM pg_catalog.pg_ts_parser p\n"
5517 " WHERE p.oid = '%s'\n"
5518 "UNION ALL\n"
5519 "SELECT '%s',\n"
5520 " p.prslextype::pg_catalog.regproc,\n"
5521 " pg_catalog.obj_description(p.prslextype, 'pg_proc')\n"
5522 " FROM pg_catalog.pg_ts_parser p\n"
5523 " WHERE p.oid = '%s';",
5524 gettext_noop("Start parse"),
5525 gettext_noop("Method"),
5526 gettext_noop("Function"),
5527 gettext_noop("Description"),
5528 oid,
5529 gettext_noop("Get next token"),
5530 oid,
5531 gettext_noop("End parse"),
5532 oid,
5533 gettext_noop("Get headline"),
5534 oid,
5535 gettext_noop("Get token types"),
5536 oid);
5537
5538 res = PSQLexec(buf.data);
5540 if (!res)
5541 return false;
5542
5543 initPQExpBuffer(&title);
5544 if (nspname)
5545 printfPQExpBuffer(&title, _("Text search parser \"%s.%s\""),
5546 nspname, prsname);
5547 else
5548 printfPQExpBuffer(&title, _("Text search parser \"%s\""), prsname);
5549 myopt.title = title.data;
5550 myopt.footers = NULL;
5551 myopt.topt.default_footer = false;
5552 myopt.translate_header = true;
5553 myopt.translate_columns = translate_columns;
5554 myopt.n_translate_columns = lengthof(translate_columns);
5555
5556 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5557
5558 PQclear(res);
5559
5561
5563 "SELECT t.alias as \"%s\",\n"
5564 " t.description as \"%s\"\n"
5565 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t\n"
5566 "ORDER BY 1;",
5567 gettext_noop("Token name"),
5568 gettext_noop("Description"),
5569 oid);
5570
5571 res = PSQLexec(buf.data);
5573 if (!res)
5574 {
5575 termPQExpBuffer(&title);
5576 return false;
5577 }
5578
5579 if (nspname)
5580 printfPQExpBuffer(&title, _("Token types for parser \"%s.%s\""),
5581 nspname, prsname);
5582 else
5583 printfPQExpBuffer(&title, _("Token types for parser \"%s\""), prsname);
5584 myopt.title = title.data;
5585 myopt.footers = NULL;
5586 myopt.topt.default_footer = true;
5587 myopt.translate_header = true;
5588 myopt.translate_columns = NULL;
5589 myopt.n_translate_columns = 0;
5590
5591 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5592
5593 termPQExpBuffer(&title);
5594 PQclear(res);
5595 return true;
5596}

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

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

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

6569{
6571 int i;
6572 PGresult *res;
6573 bool has_pubtruncate;
6574 bool has_pubgencols;
6575 bool has_pubviaroot;
6576 bool has_pubsequence;
6577
6578 PQExpBufferData title;
6579 printTableContent cont;
6580
6581 if (pset.sversion < 100000)
6582 {
6583 char sverbuf[32];
6584
6585 pg_log_error("The server (version %s) does not support publications.",
6587 sverbuf, sizeof(sverbuf)));
6588 return true;
6589 }
6590
6591 has_pubsequence = (pset.sversion >= 190000);
6592 has_pubtruncate = (pset.sversion >= 110000);
6593 has_pubgencols = (pset.sversion >= 180000);
6594 has_pubviaroot = (pset.sversion >= 130000);
6595
6597
6599 "SELECT oid, pubname,\n"
6600 " pg_catalog.pg_get_userbyid(pubowner) AS owner,\n"
6601 " puballtables");
6602
6603 if (has_pubsequence)
6605 ", puballsequences");
6606 else
6608 ", false AS puballsequences");
6609
6611 ", pubinsert, pubupdate, pubdelete");
6612
6613 if (has_pubtruncate)
6615 ", pubtruncate");
6616 else
6618 ", false AS pubtruncate");
6619
6620 if (has_pubgencols)
6622 ", (CASE pubgencols\n"
6623 " WHEN '%c' THEN 'none'\n"
6624 " WHEN '%c' THEN 'stored'\n"
6625 " END) AS \"%s\"\n",
6626 PUBLISH_GENCOLS_NONE,
6627 PUBLISH_GENCOLS_STORED,
6628 gettext_noop("Generated columns"));
6629 else
6631 ", 'none' AS pubgencols");
6632
6633 if (has_pubviaroot)
6635 ", pubviaroot");
6636 else
6638 ", false AS pubviaroot");
6639
6641 "\nFROM pg_catalog.pg_publication\n");
6642
6643 if (!validateSQLNamePattern(&buf, pattern, false, false,
6644 NULL, "pubname", NULL,
6645 NULL,
6646 NULL, 1))
6647 {
6649 return false;
6650 }
6651
6652 appendPQExpBufferStr(&buf, "ORDER BY 2;");
6653
6654 res = PSQLexec(buf.data);
6655 if (!res)
6656 {
6658 return false;
6659 }
6660
6661 if (PQntuples(res) == 0)
6662 {
6663 if (!pset.quiet)
6664 {
6665 if (pattern)
6666 pg_log_error("Did not find any publication named \"%s\".",
6667 pattern);
6668 else
6669 pg_log_error("Did not find any publications.");
6670 }
6671
6673 PQclear(res);
6674 return false;
6675 }
6676
6677 for (i = 0; i < PQntuples(res); i++)
6678 {
6679 const char align = 'l';
6680 int ncols = 5;
6681 int nrows = 1;
6682 char *pubid = PQgetvalue(res, i, 0);
6683 char *pubname = PQgetvalue(res, i, 1);
6684 bool puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
6685 printTableOpt myopt = pset.popt.topt;
6686
6687 if (has_pubsequence)
6688 ncols++;
6689 if (has_pubtruncate)
6690 ncols++;
6691 if (has_pubgencols)
6692 ncols++;
6693 if (has_pubviaroot)
6694 ncols++;
6695
6696 initPQExpBuffer(&title);
6697 printfPQExpBuffer(&title, _("Publication %s"), pubname);
6698 printTableInit(&cont, &myopt, title.data, ncols, nrows);
6699
6700 printTableAddHeader(&cont, gettext_noop("Owner"), true, align);
6701 printTableAddHeader(&cont, gettext_noop("All tables"), true, align);
6702 if (has_pubsequence)
6703 printTableAddHeader(&cont, gettext_noop("All sequences"), true, align);
6704 printTableAddHeader(&cont, gettext_noop("Inserts"), true, align);
6705 printTableAddHeader(&cont, gettext_noop("Updates"), true, align);
6706 printTableAddHeader(&cont, gettext_noop("Deletes"), true, align);
6707 if (has_pubtruncate)
6708 printTableAddHeader(&cont, gettext_noop("Truncates"), true, align);
6709 if (has_pubgencols)
6710 printTableAddHeader(&cont, gettext_noop("Generated columns"), true, align);
6711 if (has_pubviaroot)
6712 printTableAddHeader(&cont, gettext_noop("Via root"), true, align);
6713
6714 printTableAddCell(&cont, PQgetvalue(res, i, 2), false, false);
6715 printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false);
6716 if (has_pubsequence)
6717 printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false);
6718 printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
6719 printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
6720 printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
6721 if (has_pubtruncate)
6722 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
6723 if (has_pubgencols)
6724 printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
6725 if (has_pubviaroot)
6726 printTableAddCell(&cont, PQgetvalue(res, i, 10), false, false);
6727
6728 if (!puballtables)
6729 {
6730 /* Get the tables for the specified publication */
6732 "SELECT n.nspname, c.relname");
6733 if (pset.sversion >= 150000)
6734 {
6736 ", pg_get_expr(pr.prqual, c.oid)");
6738 ", (CASE WHEN pr.prattrs IS NOT NULL THEN\n"
6739 " pg_catalog.array_to_string("
6740 " ARRAY(SELECT attname\n"
6741 " FROM\n"
6742 " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
6743 " pg_catalog.pg_attribute\n"
6744 " WHERE attrelid = c.oid AND attnum = prattrs[s]), ', ')\n"
6745 " ELSE NULL END)");
6746 }
6747 else
6749 ", NULL, NULL");
6751 "\nFROM pg_catalog.pg_class c,\n"
6752 " pg_catalog.pg_namespace n,\n"
6753 " pg_catalog.pg_publication_rel pr\n"
6754 "WHERE c.relnamespace = n.oid\n"
6755 " AND c.oid = pr.prrelid\n"
6756 " AND pr.prpubid = '%s'\n"
6757 "ORDER BY 1,2", pubid);
6758 if (!addFooterToPublicationDesc(&buf, _("Tables:"), false, &cont))
6759 goto error_return;
6760
6761 if (pset.sversion >= 150000)
6762 {
6763 /* Get the schemas for the specified publication */
6765 "SELECT n.nspname\n"
6766 "FROM pg_catalog.pg_namespace n\n"
6767 " JOIN pg_catalog.pg_publication_namespace pn ON n.oid = pn.pnnspid\n"
6768 "WHERE pn.pnpubid = '%s'\n"
6769 "ORDER BY 1", pubid);
6770 if (!addFooterToPublicationDesc(&buf, _("Tables from schemas:"),
6771 true, &cont))
6772 goto error_return;
6773 }
6774 }
6775
6776 printTable(&cont, pset.queryFout, false, pset.logfile);
6777 printTableCleanup(&cont);
6778
6779 termPQExpBuffer(&title);
6780 }
6781
6783 PQclear(res);
6784
6785 return true;
6786
6787error_return:
6788 printTableCleanup(&cont);
6789 PQclear(res);
6791 termPQExpBuffer(&title);
6792 return false;
6793}
static bool addFooterToPublicationDesc(PQExpBuffer buf, const char *footermsg, bool as_schema, printTableContent *const cont)
Definition: describe.c:6522

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, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::topt, and validateSQLNamePattern().

Referenced by exec_command_d().

◆ describeRoleGrants()

bool describeRoleGrants ( const char *  pattern,
bool  showSystem 
)

Definition at line 3962 of file describe.c.

3963{
3965 PGresult *res;
3966 printQueryOpt myopt = pset.popt;
3967
3970 "SELECT m.rolname AS \"%s\", r.rolname AS \"%s\",\n"
3971 " pg_catalog.concat_ws(', ',\n",
3972 gettext_noop("Role name"),
3973 gettext_noop("Member of"));
3974
3975 if (pset.sversion >= 160000)
3977 " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
3978 " CASE WHEN pam.inherit_option THEN 'INHERIT' END,\n"
3979 " CASE WHEN pam.set_option THEN 'SET' END\n");
3980 else
3982 " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
3983 " CASE WHEN m.rolinherit THEN 'INHERIT' END,\n"
3984 " 'SET'\n");
3985
3987 " ) AS \"%s\",\n"
3988 " g.rolname AS \"%s\"\n",
3989 gettext_noop("Options"),
3990 gettext_noop("Grantor"));
3991
3993 "FROM pg_catalog.pg_roles m\n"
3994 " JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)\n"
3995 " LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)\n"
3996 " LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)\n");
3997
3998 if (!showSystem && !pattern)
3999 appendPQExpBufferStr(&buf, "WHERE m.rolname !~ '^pg_'\n");
4000
4001 if (!validateSQLNamePattern(&buf, pattern, false, false,
4002 NULL, "m.rolname", NULL, NULL,
4003 NULL, 1))
4004 {
4006 return false;
4007 }
4008
4009 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;\n");
4010
4011 res = PSQLexec(buf.data);
4013 if (!res)
4014 return false;
4015
4016 myopt.title = _("List of role grants");
4017 myopt.translate_header = true;
4018
4019 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4020
4021 PQclear(res);
4022 return true;
4023}

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, _psqlSettings::popt, PQclear, printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, _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 3746 of file describe.c.

3747{
3749 PGresult *res;
3750 printTableContent cont;
3751 printTableOpt myopt = pset.popt.topt;
3752 int ncols = 2;
3753 int nrows = 0;
3754 int i;
3755 int conns;
3756 const char align = 'l';
3757 char **attr;
3758
3759 myopt.default_footer = false;
3760
3762
3764 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
3765 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
3766 " r.rolconnlimit, r.rolvaliduntil");
3767
3768 if (verbose)
3769 {
3770 appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
3771 ncols++;
3772 }
3773 appendPQExpBufferStr(&buf, "\n, r.rolreplication");
3774
3775 if (pset.sversion >= 90500)
3776 {
3777 appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
3778 }
3779
3780 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
3781
3782 if (!showSystem && !pattern)
3783 appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
3784
3785 if (!validateSQLNamePattern(&buf, pattern, false, false,
3786 NULL, "r.rolname", NULL, NULL,
3787 NULL, 1))
3788 {
3790 return false;
3791 }
3792
3793 appendPQExpBufferStr(&buf, "ORDER BY 1;");
3794
3795 res = PSQLexec(buf.data);
3796 if (!res)
3797 return false;
3798
3799 nrows = PQntuples(res);
3800 attr = pg_malloc0((nrows + 1) * sizeof(*attr));
3801
3802 printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
3803
3804 printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
3805 printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
3806
3807 if (verbose)
3808 printTableAddHeader(&cont, gettext_noop("Description"), true, align);
3809
3810 for (i = 0; i < nrows; i++)
3811 {
3812 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
3813
3815 if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
3816 add_role_attribute(&buf, _("Superuser"));
3817
3818 if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
3819 add_role_attribute(&buf, _("No inheritance"));
3820
3821 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
3822 add_role_attribute(&buf, _("Create role"));
3823
3824 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
3825 add_role_attribute(&buf, _("Create DB"));
3826
3827 if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
3828 add_role_attribute(&buf, _("Cannot login"));
3829
3830 if (strcmp(PQgetvalue(res, i, (verbose ? 9 : 8)), "t") == 0)
3831 add_role_attribute(&buf, _("Replication"));
3832
3833 if (pset.sversion >= 90500)
3834 if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
3835 add_role_attribute(&buf, _("Bypass RLS"));
3836
3837 conns = atoi(PQgetvalue(res, i, 6));
3838 if (conns >= 0)
3839 {
3840 if (buf.len > 0)
3841 appendPQExpBufferChar(&buf, '\n');
3842
3843 if (conns == 0)
3844 appendPQExpBufferStr(&buf, _("No connections"));
3845 else
3846 appendPQExpBuffer(&buf, ngettext("%d connection",
3847 "%d connections",
3848 conns),
3849 conns);
3850 }
3851
3852 if (strcmp(PQgetvalue(res, i, 7), "") != 0)
3853 {
3854 if (buf.len > 0)
3855 appendPQExpBufferChar(&buf, '\n');
3856 appendPQExpBufferStr(&buf, _("Password valid until "));
3858 }
3859
3860 attr[i] = pg_strdup(buf.data);
3861
3862 printTableAddCell(&cont, attr[i], false, false);
3863
3864 if (verbose)
3865 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
3866 }
3868
3869 printTable(&cont, pset.queryFout, false, pset.logfile);
3870 printTableCleanup(&cont);
3871
3872 for (i = 0; i < nrows; i++)
3873 free(attr[i]);
3874 free(attr);
3875
3876 PQclear(res);
3877 return true;
3878}
#define ngettext(s, p, n)
Definition: c.h:1169
static void add_role_attribute(PQExpBuffer buf, const char *const str)
Definition: describe.c:3881
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, 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 6802 of file describe.c.

6803{
6805 PGresult *res;
6806 printQueryOpt myopt = pset.popt;
6807 static const bool translate_columns[] = {false, false, false, false,
6808 false, false, false, false, false, false, false, false, false, false,
6809 false, false, false, false};
6810
6811 if (pset.sversion < 100000)
6812 {
6813 char sverbuf[32];
6814
6815 pg_log_error("The server (version %s) does not support subscriptions.",
6817 sverbuf, sizeof(sverbuf)));
6818 return true;
6819 }
6820
6822
6824 "SELECT subname AS \"%s\"\n"
6825 ", pg_catalog.pg_get_userbyid(subowner) AS \"%s\"\n"
6826 ", subenabled AS \"%s\"\n"
6827 ", subpublications AS \"%s\"\n",
6828 gettext_noop("Name"),
6829 gettext_noop("Owner"),
6830 gettext_noop("Enabled"),
6831 gettext_noop("Publication"));
6832
6833 if (verbose)
6834 {
6835 /* Binary mode and streaming are only supported in v14 and higher */
6836 if (pset.sversion >= 140000)
6837 {
6839 ", subbinary AS \"%s\"\n",
6840 gettext_noop("Binary"));
6841
6842 if (pset.sversion >= 160000)
6844 ", (CASE substream\n"
6845 " WHEN " CppAsString2(LOGICALREP_STREAM_OFF) " THEN 'off'\n"
6846 " WHEN " CppAsString2(LOGICALREP_STREAM_ON) " THEN 'on'\n"
6847 " WHEN " CppAsString2(LOGICALREP_STREAM_PARALLEL) " THEN 'parallel'\n"
6848 " END) AS \"%s\"\n",
6849 gettext_noop("Streaming"));
6850 else
6852 ", substream AS \"%s\"\n",
6853 gettext_noop("Streaming"));
6854 }
6855
6856 /* Two_phase and disable_on_error are only supported in v15 and higher */
6857 if (pset.sversion >= 150000)
6859 ", subtwophasestate AS \"%s\"\n"
6860 ", subdisableonerr AS \"%s\"\n",
6861 gettext_noop("Two-phase commit"),
6862 gettext_noop("Disable on error"));
6863
6864 if (pset.sversion >= 160000)
6866 ", suborigin AS \"%s\"\n"
6867 ", subpasswordrequired AS \"%s\"\n"
6868 ", subrunasowner AS \"%s\"\n",
6869 gettext_noop("Origin"),
6870 gettext_noop("Password required"),
6871 gettext_noop("Run as owner?"));
6872
6873 if (pset.sversion >= 170000)
6875 ", subfailover AS \"%s\"\n",
6876 gettext_noop("Failover"));
6877 if (pset.sversion >= 190000)
6878 {
6880 ", subretaindeadtuples AS \"%s\"\n",
6881 gettext_noop("Retain dead tuples"));
6882
6884 ", submaxretention AS \"%s\"\n",
6885 gettext_noop("Max retention duration"));
6886
6888 ", subretentionactive AS \"%s\"\n",
6889 gettext_noop("Retention active"));
6890 }
6891
6893 ", subsynccommit AS \"%s\"\n"
6894 ", subconninfo AS \"%s\"\n",
6895 gettext_noop("Synchronous commit"),
6896 gettext_noop("Conninfo"));
6897
6898 /* Skip LSN is only supported in v15 and higher */
6899 if (pset.sversion >= 150000)
6901 ", subskiplsn AS \"%s\"\n",
6902 gettext_noop("Skip LSN"));
6903 }
6904
6905 /* Only display subscriptions in current database. */
6907 "FROM pg_catalog.pg_subscription\n"
6908 "WHERE subdbid = (SELECT oid\n"
6909 " FROM pg_catalog.pg_database\n"
6910 " WHERE datname = pg_catalog.current_database())");
6911
6912 if (!validateSQLNamePattern(&buf, pattern, true, false,
6913 NULL, "subname", NULL,
6914 NULL,
6915 NULL, 1))
6916 {
6918 return false;
6919 }
6920
6921 appendPQExpBufferStr(&buf, "ORDER BY 1;");
6922
6923 res = PSQLexec(buf.data);
6925 if (!res)
6926 return false;
6927
6928 myopt.title = _("List of subscriptions");
6929 myopt.translate_header = true;
6930 myopt.translate_columns = translate_columns;
6931 myopt.n_translate_columns = lengthof(translate_columns);
6932
6933 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6934
6935 PQclear(res);
6936 return true;
6937}

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, _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 1488 of file describe.c.

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

References appendPQExpBufferStr(), buf, cancel_pressed, describeOneTableDetails(), i, initPQExpBuffer(), pg_log_error, PQclear, PQgetvalue, PQntuples, printfPQExpBuffer(), pset, PSQLexec(), _psqlSettings::quiet, relname, 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, 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 639 of file describe.c.

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

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, CppAsString2, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, map_typename_pattern(), _psqlSettings::popt, PQclear, printACLColumn(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, 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 946 of file describe.c.

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

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, CppAsString2, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, _psqlSettings::popt, PQclear, printACLColumn(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, _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 4989 of file describe.c.

4990{
4992 PGresult *res;
4993 printQueryOpt myopt = pset.popt;
4994 static const bool translate_columns[] = {false, false, false, true, true, false};
4995
4997
4999 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
5000 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n",
5001 gettext_noop("Source type"),
5002 gettext_noop("Target type"));
5003
5004 /*
5005 * We don't attempt to localize '(binary coercible)' or '(with inout)',
5006 * because there's too much risk of gettext translating a function name
5007 * that happens to match some string in the PO database.
5008 */
5010 " CASE WHEN c.castmethod = '%c' THEN '(binary coercible)'\n"
5011 " WHEN c.castmethod = '%c' THEN '(with inout)'\n"
5012 " ELSE p.proname\n"
5013 " END AS \"%s\",\n",
5014 COERCION_METHOD_BINARY,
5015 COERCION_METHOD_INOUT,
5016 gettext_noop("Function"));
5017
5019 " CASE WHEN c.castcontext = '%c' THEN '%s'\n"
5020 " WHEN c.castcontext = '%c' THEN '%s'\n"
5021 " ELSE '%s'\n"
5022 " END AS \"%s\"",
5023 COERCION_CODE_EXPLICIT,
5024 gettext_noop("no"),
5025 COERCION_CODE_ASSIGNMENT,
5026 gettext_noop("in assignment"),
5027 gettext_noop("yes"),
5028 gettext_noop("Implicit?"));
5029
5030 if (verbose)
5032 ",\n CASE WHEN p.proleakproof THEN '%s'\n"
5033 " ELSE '%s'\n"
5034 " END AS \"%s\",\n"
5035 " d.description AS \"%s\"",
5036 gettext_noop("yes"),
5037 gettext_noop("no"),
5038 gettext_noop("Leakproof?"),
5039 gettext_noop("Description"));
5040
5041 /*
5042 * We need a left join to pg_proc for binary casts; the others are just
5043 * paranoia.
5044 */
5046 "\nFROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
5047 " ON c.castfunc = p.oid\n"
5048 " LEFT JOIN pg_catalog.pg_type ts\n"
5049 " ON c.castsource = ts.oid\n"
5050 " LEFT JOIN pg_catalog.pg_namespace ns\n"
5051 " ON ns.oid = ts.typnamespace\n"
5052 " LEFT JOIN pg_catalog.pg_type tt\n"
5053 " ON c.casttarget = tt.oid\n"
5054 " LEFT JOIN pg_catalog.pg_namespace nt\n"
5055 " ON nt.oid = tt.typnamespace\n");
5056
5057 if (verbose)
5059 " LEFT JOIN pg_catalog.pg_description d\n"
5060 " ON d.classoid = c.tableoid AND d.objoid = "
5061 "c.oid AND d.objsubid = 0\n");
5062
5063 appendPQExpBufferStr(&buf, "WHERE ( (true");
5064
5065 /*
5066 * Match name pattern against either internal or external name of either
5067 * castsource or casttarget
5068 */
5069 if (!validateSQLNamePattern(&buf, pattern, true, false,
5070 "ns.nspname", "ts.typname",
5071 "pg_catalog.format_type(ts.oid, NULL)",
5072 "pg_catalog.pg_type_is_visible(ts.oid)",
5073 NULL, 3))
5074 goto error_return;
5075
5076 appendPQExpBufferStr(&buf, ") OR (true");
5077
5078 if (!validateSQLNamePattern(&buf, pattern, true, false,
5079 "nt.nspname", "tt.typname",
5080 "pg_catalog.format_type(tt.oid, NULL)",
5081 "pg_catalog.pg_type_is_visible(tt.oid)",
5082 NULL, 3))
5083 goto error_return;
5084
5085 appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
5086
5087 res = PSQLexec(buf.data);
5089 if (!res)
5090 return false;
5091
5092 myopt.title = _("List of casts");
5093 myopt.translate_header = true;
5094 myopt.translate_columns = translate_columns;
5095 myopt.n_translate_columns = lengthof(translate_columns);
5096
5097 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5098
5099 PQclear(res);
5100 return true;
5101
5102error_return:
5104 return false;
5105}

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, _psqlSettings::popt, PQclear, printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, 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 5113 of file describe.c.

5114{
5116 PGresult *res;
5117 printQueryOpt myopt = pset.popt;
5118 static const bool translate_columns[] = {false, false, false, false, false, false, false, true, false};
5119
5121
5123 "SELECT\n"
5124 " n.nspname AS \"%s\",\n"
5125 " c.collname AS \"%s\",\n",
5126 gettext_noop("Schema"),
5127 gettext_noop("Name"));
5128
5129 if (pset.sversion >= 100000)
5131 " CASE c.collprovider "
5132 "WHEN " CppAsString2(COLLPROVIDER_DEFAULT) " THEN 'default' "
5133 "WHEN " CppAsString2(COLLPROVIDER_BUILTIN) " THEN 'builtin' "
5134 "WHEN " CppAsString2(COLLPROVIDER_LIBC) " THEN 'libc' "
5135 "WHEN " CppAsString2(COLLPROVIDER_ICU) " THEN 'icu' "
5136 "END AS \"%s\",\n",
5137 gettext_noop("Provider"));
5138 else
5140 " 'libc' AS \"%s\",\n",
5141 gettext_noop("Provider"));
5142
5144 " c.collcollate AS \"%s\",\n"
5145 " c.collctype AS \"%s\",\n",
5146 gettext_noop("Collate"),
5147 gettext_noop("Ctype"));
5148
5149 if (pset.sversion >= 170000)
5151 " c.colllocale AS \"%s\",\n",
5152 gettext_noop("Locale"));
5153 else if (pset.sversion >= 150000)
5155 " c.colliculocale AS \"%s\",\n",
5156 gettext_noop("Locale"));
5157 else
5159 " c.collcollate AS \"%s\",\n",
5160 gettext_noop("Locale"));
5161
5162 if (pset.sversion >= 160000)
5164 " c.collicurules AS \"%s\",\n",
5165 gettext_noop("ICU Rules"));
5166 else
5168 " NULL AS \"%s\",\n",
5169 gettext_noop("ICU Rules"));
5170
5171 if (pset.sversion >= 120000)
5173 " CASE WHEN c.collisdeterministic THEN '%s' ELSE '%s' END AS \"%s\"",
5174 gettext_noop("yes"), gettext_noop("no"),
5175 gettext_noop("Deterministic?"));
5176 else
5178 " '%s' AS \"%s\"",
5179 gettext_noop("yes"),
5180 gettext_noop("Deterministic?"));
5181
5182 if (verbose)
5184 ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
5185 gettext_noop("Description"));
5186
5188 "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
5189 "WHERE n.oid = c.collnamespace\n");
5190
5191 if (!showSystem && !pattern)
5192 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
5193 " AND n.nspname <> 'information_schema'\n");
5194
5195 /*
5196 * Hide collations that aren't usable in the current database's encoding.
5197 * If you think to change this, note that pg_collation_is_visible rejects
5198 * unusable collations, so you will need to hack name pattern processing
5199 * somehow to avoid inconsistent behavior.
5200 */
5201 appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
5202
5203 if (!validateSQLNamePattern(&buf, pattern, true, false,
5204 "n.nspname", "c.collname", NULL,
5205 "pg_catalog.pg_collation_is_visible(c.oid)",
5206 NULL, 3))
5207 {
5209 return false;
5210 }
5211
5212 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5213
5214 res = PSQLexec(buf.data);
5216 if (!res)
5217 return false;
5218
5219 myopt.title = _("List of collations");
5220 myopt.translate_header = true;
5221 myopt.translate_columns = translate_columns;
5222 myopt.n_translate_columns = lengthof(translate_columns);
5223
5224 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5225
5226 PQclear(res);
5227 return true;
5228}

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, CppAsString2, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, _psqlSettings::popt, PQclear, printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, _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 4665 of file describe.c.

4666{
4668 PGresult *res;
4669 printQueryOpt myopt = pset.popt;
4670 static const bool translate_columns[] =
4671 {false, false, false, false, true, false};
4672
4674
4676 "SELECT n.nspname AS \"%s\",\n"
4677 " c.conname AS \"%s\",\n"
4678 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
4679 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
4680 " CASE WHEN c.condefault THEN '%s'\n"
4681 " ELSE '%s' END AS \"%s\"",
4682 gettext_noop("Schema"),
4683 gettext_noop("Name"),
4684 gettext_noop("Source"),
4685 gettext_noop("Destination"),
4686 gettext_noop("yes"), gettext_noop("no"),
4687 gettext_noop("Default?"));
4688
4689 if (verbose)
4691 ",\n d.description AS \"%s\"",
4692 gettext_noop("Description"));
4693
4695 "\nFROM pg_catalog.pg_conversion c\n"
4696 " JOIN pg_catalog.pg_namespace n "
4697 "ON n.oid = c.connamespace\n");
4698
4699 if (verbose)
4701 "LEFT JOIN pg_catalog.pg_description d "
4702 "ON d.classoid = c.tableoid\n"
4703 " AND d.objoid = c.oid "
4704 "AND d.objsubid = 0\n");
4705
4706 appendPQExpBufferStr(&buf, "WHERE true\n");
4707
4708 if (!showSystem && !pattern)
4709 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4710 " AND n.nspname <> 'information_schema'\n");
4711
4712 if (!validateSQLNamePattern(&buf, pattern, true, false,
4713 "n.nspname", "c.conname", NULL,
4714 "pg_catalog.pg_conversion_is_visible(c.oid)",
4715 NULL, 3))
4716 {
4718 return false;
4719 }
4720
4721 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4722
4723 res = PSQLexec(buf.data);
4725 if (!res)
4726 return false;
4727
4728 myopt.title = _("List of conversions");
4729 myopt.translate_header = true;
4730 myopt.translate_columns = translate_columns;
4731 myopt.n_translate_columns = lengthof(translate_columns);
4732
4733 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4734
4735 PQclear(res);
4736 return true;
4737}

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, _psqlSettings::popt, PQclear, printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, 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 3893 of file describe.c.

3894{
3896 PGresult *res;
3897 printQueryOpt myopt = pset.popt;
3898 bool havewhere;
3899
3901
3902 printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
3903 "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
3904 "FROM pg_catalog.pg_db_role_setting s\n"
3905 "LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n"
3906 "LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n",
3907 gettext_noop("Role"),
3908 gettext_noop("Database"),
3909 gettext_noop("Settings"));
3910 if (!validateSQLNamePattern(&buf, pattern, false, false,
3911 NULL, "r.rolname", NULL, NULL, &havewhere, 1))
3912 goto error_return;
3913 if (!validateSQLNamePattern(&buf, pattern2, havewhere, false,
3914 NULL, "d.datname", NULL, NULL,
3915 NULL, 1))
3916 goto error_return;
3917 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3918
3919 res = PSQLexec(buf.data);
3921 if (!res)
3922 return false;
3923
3924 /*
3925 * Most functions in this file are content to print an empty table when
3926 * there are no matching objects. We intentionally deviate from that
3927 * here, but only in !quiet mode, because of the possibility that the user
3928 * is confused about what the two pattern arguments mean.
3929 */
3930 if (PQntuples(res) == 0 && !pset.quiet)
3931 {
3932 if (pattern && pattern2)
3933 pg_log_error("Did not find any settings for role \"%s\" and database \"%s\".",
3934 pattern, pattern2);
3935 else if (pattern)
3936 pg_log_error("Did not find any settings for role \"%s\".",
3937 pattern);
3938 else
3939 pg_log_error("Did not find any settings.");
3940 }
3941 else
3942 {
3943 myopt.title = _("List of settings");
3944 myopt.translate_header = true;
3945
3946 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3947 }
3948
3949 PQclear(res);
3950 return true;
3951
3952error_return:
3954 return false;
3955}

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

Referenced by exec_command_d().

◆ listDefaultACLs()

bool listDefaultACLs ( const char *  pattern)

Definition at line 1214 of file describe.c.

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

References _, appendPQExpBufferStr(), buf, gettext_noop, initPQExpBuffer(), lengthof, _psqlSettings::logfile, printQueryOpt::n_translate_columns, _psqlSettings::popt, PQclear, printACLColumn(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, 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 4582 of file describe.c.

4583{
4585 PGresult *res;
4586 printQueryOpt myopt = pset.popt;
4587
4589
4591 "SELECT n.nspname as \"%s\",\n"
4592 " t.typname as \"%s\",\n"
4593 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
4594 " (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
4595 " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as \"%s\",\n"
4596 " CASE WHEN t.typnotnull THEN 'not null' END as \"%s\",\n"
4597 " t.typdefault as \"%s\",\n"
4598 " pg_catalog.array_to_string(ARRAY(\n"
4599 " 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"
4600 " ), ' ') as \"%s\"",
4601 gettext_noop("Schema"),
4602 gettext_noop("Name"),
4603 gettext_noop("Type"),
4604 gettext_noop("Collation"),
4605 gettext_noop("Nullable"),
4606 gettext_noop("Default"),
4607 gettext_noop("Check"));
4608
4609 if (verbose)
4610 {
4611 appendPQExpBufferStr(&buf, ",\n ");
4612 printACLColumn(&buf, "t.typacl");
4614 ",\n d.description as \"%s\"",
4615 gettext_noop("Description"));
4616 }
4617
4619 "\nFROM pg_catalog.pg_type t\n"
4620 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
4621
4622 if (verbose)
4624 " LEFT JOIN pg_catalog.pg_description d "
4625 "ON d.classoid = t.tableoid AND d.objoid = t.oid "
4626 "AND d.objsubid = 0\n");
4627
4628 appendPQExpBufferStr(&buf, "WHERE t.typtype = 'd'\n");
4629
4630 if (!showSystem && !pattern)
4631 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4632 " AND n.nspname <> 'information_schema'\n");
4633
4634 if (!validateSQLNamePattern(&buf, pattern, true, false,
4635 "n.nspname", "t.typname", NULL,
4636 "pg_catalog.pg_type_is_visible(t.oid)",
4637 NULL, 3))
4638 {
4640 return false;
4641 }
4642
4643 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4644
4645 res = PSQLexec(buf.data);
4647 if (!res)
4648 return false;
4649
4650 myopt.title = _("List of domains");
4651 myopt.translate_header = true;
4652
4653 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4654
4655 PQclear(res);
4656 return true;
4657}

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, CppAsString2, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, _psqlSettings::popt, PQclear, printACLColumn(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, 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 4813 of file describe.c.

4814{
4816 PGresult *res;
4817 printQueryOpt myopt = pset.popt;
4818 static const bool translate_columns[] =
4819 {false, false, false, true, false, false, false};
4820
4821 if (pset.sversion < 90300)
4822 {
4823 char sverbuf[32];
4824
4825 pg_log_error("The server (version %s) does not support event triggers.",
4827 sverbuf, sizeof(sverbuf)));
4828 return true;
4829 }
4830
4832
4834 "SELECT evtname as \"%s\", "
4835 "evtevent as \"%s\", "
4836 "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
4837 " case evtenabled when 'O' then '%s'"
4838 " when 'R' then '%s'"
4839 " when 'A' then '%s'"
4840 " when 'D' then '%s' end as \"%s\",\n"
4841 " e.evtfoid::pg_catalog.regproc as \"%s\", "
4842 "pg_catalog.array_to_string(array(select x"
4843 " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
4844 gettext_noop("Name"),
4845 gettext_noop("Event"),
4846 gettext_noop("Owner"),
4847 gettext_noop("enabled"),
4848 gettext_noop("replica"),
4849 gettext_noop("always"),
4850 gettext_noop("disabled"),
4851 gettext_noop("Enabled"),
4852 gettext_noop("Function"),
4853 gettext_noop("Tags"));
4854 if (verbose)
4856 ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
4857 gettext_noop("Description"));
4859 "\nFROM pg_catalog.pg_event_trigger e ");
4860
4861 if (!validateSQLNamePattern(&buf, pattern, false, false,
4862 NULL, "evtname", NULL, NULL,
4863 NULL, 1))
4864 {
4866 return false;
4867 }
4868
4869 appendPQExpBufferStr(&buf, "ORDER BY 1");
4870
4871 res = PSQLexec(buf.data);
4873 if (!res)
4874 return false;
4875
4876 myopt.title = _("List of event triggers");
4877 myopt.translate_header = true;
4878 myopt.translate_columns = translate_columns;
4879 myopt.n_translate_columns = lengthof(translate_columns);
4880
4881 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4882
4883 PQclear(res);
4884 return true;
4885}

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, _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 4893 of file describe.c.

4894{
4896 PGresult *res;
4897 printQueryOpt myopt = pset.popt;
4898
4899 if (pset.sversion < 100000)
4900 {
4901 char sverbuf[32];
4902
4903 pg_log_error("The server (version %s) does not support extended statistics.",
4905 sverbuf, sizeof(sverbuf)));
4906 return true;
4907 }
4908
4911 "SELECT \n"
4912 "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS \"%s\", \n"
4913 "es.stxname AS \"%s\", \n",
4914 gettext_noop("Schema"),
4915 gettext_noop("Name"));
4916
4917 if (pset.sversion >= 140000)
4919 "pg_catalog.format('%%s FROM %%s', \n"
4920 " pg_catalog.pg_get_statisticsobjdef_columns(es.oid), \n"
4921 " es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4922 gettext_noop("Definition"));
4923 else
4925 "pg_catalog.format('%%s FROM %%s', \n"
4926 " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n"
4927 " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n"
4928 " JOIN pg_catalog.pg_attribute a \n"
4929 " ON (es.stxrelid = a.attrelid \n"
4930 " AND a.attnum = s.attnum \n"
4931 " AND NOT a.attisdropped)), \n"
4932 "es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4933 gettext_noop("Definition"));
4934
4936 ",\nCASE WHEN " CppAsString2(STATS_EXT_NDISTINCT) " = any(es.stxkind) THEN 'defined' \n"
4937 "END AS \"%s\", \n"
4938 "CASE WHEN " CppAsString2(STATS_EXT_DEPENDENCIES) " = any(es.stxkind) THEN 'defined' \n"
4939 "END AS \"%s\"",
4940 gettext_noop("Ndistinct"),
4941 gettext_noop("Dependencies"));
4942
4943 /*
4944 * Include the MCV statistics kind.
4945 */
4946 if (pset.sversion >= 120000)
4947 {
4949 ",\nCASE WHEN " CppAsString2(STATS_EXT_MCV) " = any(es.stxkind) THEN 'defined' \n"
4950 "END AS \"%s\" ",
4951 gettext_noop("MCV"));
4952 }
4953
4955 " \nFROM pg_catalog.pg_statistic_ext es \n");
4956
4957 if (!validateSQLNamePattern(&buf, pattern,
4958 false, false,
4959 "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname",
4960 NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)",
4961 NULL, 3))
4962 {
4964 return false;
4965 }
4966
4967 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4968
4969 res = PSQLexec(buf.data);
4971 if (!res)
4972 return false;
4973
4974 myopt.title = _("List of extended statistics");
4975 myopt.translate_header = true;
4976
4977 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4978
4979 PQclear(res);
4980 return true;
4981}

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

Referenced by exec_command_d().

◆ listExtensionContents()

bool listExtensionContents ( const char *  pattern)

Definition at line 6266 of file describe.c.

6267{
6269 PGresult *res;
6270 int i;
6271
6274 "SELECT e.extname, e.oid\n"
6275 "FROM pg_catalog.pg_extension e\n");
6276
6277 if (!validateSQLNamePattern(&buf, pattern,
6278 false, false,
6279 NULL, "e.extname", NULL,
6280 NULL,
6281 NULL, 1))
6282 {
6284 return false;
6285 }
6286
6287 appendPQExpBufferStr(&buf, "ORDER BY 1;");
6288
6289 res = PSQLexec(buf.data);
6291 if (!res)
6292 return false;
6293
6294 if (PQntuples(res) == 0)
6295 {
6296 if (!pset.quiet)
6297 {
6298 if (pattern)
6299 pg_log_error("Did not find any extension named \"%s\".",
6300 pattern);
6301 else
6302 pg_log_error("Did not find any extensions.");
6303 }
6304 PQclear(res);
6305 return false;
6306 }
6307
6308 for (i = 0; i < PQntuples(res); i++)
6309 {
6310 const char *extname;
6311 const char *oid;
6312
6313 extname = PQgetvalue(res, i, 0);
6314 oid = PQgetvalue(res, i, 1);
6315
6316 if (!listOneExtensionContents(extname, oid))
6317 {
6318 PQclear(res);
6319 return false;
6320 }
6321 if (cancel_pressed)
6322 {
6323 PQclear(res);
6324 return false;
6325 }
6326 }
6327
6328 PQclear(res);
6329 return true;
6330}
static bool listOneExtensionContents(const char *extname, const char *oid)
Definition: describe.c:6333

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

Referenced by exec_command_d().

◆ listExtensions()

bool listExtensions ( const char *  pattern)

Definition at line 6212 of file describe.c.

6213{
6215 PGresult *res;
6216 printQueryOpt myopt = pset.popt;
6217
6220 "SELECT e.extname AS \"%s\", "
6221 "e.extversion AS \"%s\", ae.default_version AS \"%s\","
6222 "n.nspname AS \"%s\", d.description AS \"%s\"\n"
6223 "FROM pg_catalog.pg_extension e "
6224 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
6225 "LEFT JOIN pg_catalog.pg_description d ON d.objoid = e.oid "
6226 "AND d.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
6227 "LEFT JOIN pg_catalog.pg_available_extensions() ae(name, default_version, comment) ON ae.name = e.extname\n",
6228 gettext_noop("Name"),
6229 gettext_noop("Version"),
6230 gettext_noop("Default version"),
6231 gettext_noop("Schema"),
6232 gettext_noop("Description"));
6233
6234 if (!validateSQLNamePattern(&buf, pattern,
6235 false, false,
6236 NULL, "e.extname", NULL,
6237 NULL,
6238 NULL, 1))
6239 {
6241 return false;
6242 }
6243
6244 appendPQExpBufferStr(&buf, "ORDER BY 1;");
6245
6246 res = PSQLexec(buf.data);
6248 if (!res)
6249 return false;
6250
6251 myopt.title = _("List of installed extensions");
6252 myopt.translate_header = true;
6253
6254 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6255
6256 PQclear(res);
6257 return true;
6258}

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

Referenced by exec_command_d().

◆ listForeignDataWrappers()

bool listForeignDataWrappers ( const char *  pattern,
bool  verbose 
)

Definition at line 5938 of file describe.c.

5939{
5941 PGresult *res;
5942 printQueryOpt myopt = pset.popt;
5943
5946 "SELECT fdw.fdwname AS \"%s\",\n"
5947 " pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n"
5948 " fdw.fdwhandler::pg_catalog.regproc AS \"%s\",\n"
5949 " fdw.fdwvalidator::pg_catalog.regproc AS \"%s\"",
5950 gettext_noop("Name"),
5951 gettext_noop("Owner"),
5952 gettext_noop("Handler"),
5953 gettext_noop("Validator"));
5954
5955 if (verbose)
5956 {
5957 appendPQExpBufferStr(&buf, ",\n ");
5958 printACLColumn(&buf, "fdwacl");
5960 ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
5961 " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5962 " pg_catalog.quote_ident(option_name) || ' ' || "
5963 " pg_catalog.quote_literal(option_value) FROM "
5964 " pg_catalog.pg_options_to_table(fdwoptions)), ', ') || ')' "
5965 " END AS \"%s\""
5966 ",\n d.description AS \"%s\" ",
5967 gettext_noop("FDW options"),
5968 gettext_noop("Description"));
5969 }
5970
5971 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
5972
5973 if (verbose)
5975 "LEFT JOIN pg_catalog.pg_description d\n"
5976 " ON d.classoid = fdw.tableoid "
5977 "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
5978
5979 if (!validateSQLNamePattern(&buf, pattern, false, false,
5980 NULL, "fdwname", NULL, NULL,
5981 NULL, 1))
5982 {
5984 return false;
5985 }
5986
5987 appendPQExpBufferStr(&buf, "ORDER BY 1;");
5988
5989 res = PSQLexec(buf.data);
5991 if (!res)
5992 return false;
5993
5994 myopt.title = _("List of foreign-data wrappers");
5995 myopt.translate_header = true;
5996
5997 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5998
5999 PQclear(res);
6000 return true;
6001}

References _, appendPQExpBuffer(), appendPQExpBufferStr(), buf, gettext_noop, initPQExpBuffer(), _psqlSettings::logfile, _psqlSettings::popt, PQclear, printACLColumn(), printfPQExpBuffer(), printQuery(), pset, PSQLexec(), _psqlSettings::queryFout, 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 6009 of file describe.c.

6010{
6012 PGresult *res;
6013 printQueryOpt myopt = pset.popt;
6014
6017 "SELECT s.srvname AS \"%s\",\n"
6018 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
6019 " f.fdwname AS \"%s\"",
6020 gettext_noop("Name"),
6021 gettext_noop("Owner"),
6022 gettext_noop("Foreign-data wrapper"));
6023
6024 if (verbose)
6025 {
6026 appendPQExpBufferStr(&buf, ",\n ");
6027 printACLColumn(&buf, "s.srvacl");
6029 ",\n"
6030 " s.srvtype AS \"%s\",\n"
6031 " s.srvversion AS \"%s\",\n"
6032 " CASE WHEN srvoptions IS NULL THEN '' ELSE "
6033 " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
6034 " pg_catalog.quote_ident(option_name) || ' ' || "
6035 " pg_catalog.quote_literal(option_value) FROM "
6036 " pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')' "
6037 " END AS \"%s\",\n"
6038 " d.description AS \"%s\"",
6039 gettext_noop("Type"),
6040 gettext_noop("Version"),
6041 gettext_noop("FDW options"),
6042 gettext_noop("Description"));
6043 }
6044
6046 "\nFROM pg_catalog.pg_foreign_server s\n"
6047 " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
6048
6049 if (verbose)
6051 "LEFT JOIN pg_catalog.pg_description d\n "
6052 "ON d.classoid = s.tableoid AND d.objoid = s.oid "
6053 "AND d.objsubid = 0\n");
6054
6055 if (!validateSQLNamePattern(&buf, pattern, false, false,
6056 NULL, "s.srvname", NULL, NULL,
6057 NULL, 1))
6058 {
6060 return false;
6061 }
6062
6063 appendPQExpBufferStr(&buf, "ORDER BY 1;");
6064
6065 res = PSQLexec(buf.data);
6067 if (!res)
6068 return false;
6069
6070 myopt.title = _("List of foreign servers");
6071 myopt.translate_header = true;
6072
6073 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6074
6075 PQclear(res);
6076 return true;
6077}

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

Referenced by exec_command_d().

◆ listForeignTables()

bool listForeignTables ( const char *  pattern,
bool  verbose 
)

Definition at line 6140 of file describe.c.

6141{
6143 PGresult *res;
6144 printQueryOpt myopt = pset.popt;
6145
6148 "SELECT n.nspname AS \"%s\",\n"
6149 " c.relname AS \"%s\",\n"
6150 " s.srvname AS \"%s\"",
6151 gettext_noop("Schema"),
6152 gettext_noop("Table"),
6153 gettext_noop("Server"));
6154
6155 if (verbose)
6157 ",\n CASE WHEN ftoptions IS NULL THEN '' ELSE "
6158 " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
6159 " pg_catalog.quote_ident(option_name) || ' ' || "
6160 " pg_catalog.quote_literal(option_value) FROM "
6161 " pg_catalog.pg_options_to_table(ftoptions)), ', ') || ')' "
6162 " END AS \"%s\",\n"
6163 " d.description AS \"%s\"",
6164 gettext_noop("FDW options"),
6165 gettext_noop("Description"));
6166
6168 "\nFROM pg_catalog.pg_foreign_table ft\n"
6169 " INNER JOIN pg_catalog.pg_class c"
6170 " ON c.oid = ft.ftrelid\n"
6171 " INNER JOIN pg_catalog.pg_namespace n"
6172 " ON n.oid = c.relnamespace\n"
6173 " INNER JOIN pg_catalog.pg_foreign_server s"
6174 " ON s.oid = ft.ftserver\n");
6175 if (verbose)
6177 " LEFT JOIN pg_catalog.pg_description d\n"
6178 " ON d.classoid = c.tableoid AND "
6179 "d.objoid = c.oid AND d.objsubid = 0\n");
6180
6181 if (!validateSQLNamePattern(&buf, pattern, false, false,
6182 "n.nspname", "c.relname", NULL,
6183 "pg_catalog.pg_table_is_visible(c.oid)",
6184 NULL, 3))
6185 {
6187 return false;
6188 }
6189
6190 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
6191
6192 res = PSQLexec(buf.data);
6194 if (!res)
6195 return false;
6196
6197 myopt.title = _("List of foreign tables");
6198 myopt.translate_header = true;
6199
6200 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6201
6202 PQclear(res);
6203 return true;
6204}

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

Referenced by exec_command_d().

◆ listLanguages()

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

Definition at line 4506 of file describe.c.

4507{
4509 PGresult *res;
4510 printQueryOpt myopt = pset.popt;
4511
4513
4515 "SELECT l.lanname AS \"%s\",\n"
4516 " pg_catalog.pg_get_userbyid(l.lanowner) as \"%s\",\n"
4517 " l.lanpltrusted AS \"%s\"",
4518 gettext_noop("Name"),
4519 gettext_noop("Owner"),
4520 gettext_noop("Trusted"));
4521
4522 if (verbose)
4523 {
4525 ",\n NOT l.lanispl AS \"%s\",\n"
4526 " l.lanplcallfoid::pg_catalog.regprocedure AS \"%s\",\n"
4527 " l.lanvalidator::pg_catalog.regprocedure AS \"%s\",\n "
4528 "l.laninline::pg_catalog.regprocedure AS \"%s\",\n ",
4529 gettext_noop("Internal language"),
4530 gettext_noop("Call handler"),
4531 gettext_noop("Validator"),
4532 gettext_noop("Inline handler"));
4533 printACLColumn(&buf, "l.lanacl");
4534 }
4535
4537 ",\n d.description AS \"%s\""
4538 "\nFROM pg_catalog.pg_language l\n"
4539 "LEFT JOIN pg_catalog.pg_description d\n"
4540 " ON d.classoid = l.tableoid AND d.objoid = l.oid\n"
4541 " AND d.objsubid = 0\n",
4542 gettext_noop("Description"));
4543
4544 if (pattern)
4545 {
4546 if (!validateSQLNamePattern(&buf, pattern, false, false,
4547 NULL, "l.lanname", NULL, NULL,
4548 NULL, 2))
4549 {
4551 return false;
4552 }
4553 }
4554
4555 if (!showSystem && !pattern)
4556 appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n");
4557
4558
4559 appendPQExpBufferStr(&buf, "ORDER BY 1;");
4560
4561 res = PSQLexec(buf.data);
4563 if (!res)
4564 return false;
4565
4566 myopt.title = _("List of languages");
4567 myopt.translate_header = true;
4568
4569 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4570
4571 PQclear(res);
4572 return true;
4573}

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

Referenced by exec_command_d().

◆ listLargeObjects()

bool listLargeObjects ( bool  verbose)

Definition at line 7354 of file describe.c.

7355{
7357 PGresult *res;
7358 printQueryOpt myopt = pset.popt;
7359
7361
7363 "SELECT oid as \"%s\",\n"
7364 " pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n ",
7365 gettext_noop("ID"),
7366 gettext_noop("Owner"));
7367
7368 if (verbose)
7369 {
7370 printACLColumn(&buf, "lomacl");
7371 appendPQExpBufferStr(&buf, ",\n ");
7372 }
7373
7375 "pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n"
7376 "FROM pg_catalog.pg_largeobject_metadata\n"
7377 "ORDER BY oid",
7378 gettext_noop("Description"));
7379
7380 res = PSQLexec(buf.data);
7382 if (!res)
7383 return false;
7384
7385 myopt.title = _("Large objects");
7386 myopt.translate_header = true;
7387
7388 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7389
7390 PQclear(res);
7391 return true;
7392}

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

Referenced by exec_command_d(), and exec_command_lo().

◆ listOneExtensionContents()

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

Definition at line 6333 of file describe.c.

6334{
6336 PGresult *res;
6337 PQExpBufferData title;
6338 printQueryOpt myopt = pset.popt;
6339
6342 "SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS \"%s\"\n"
6343 "FROM pg_catalog.pg_depend\n"
6344 "WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '%s' AND deptype = 'e'\n"
6345 "ORDER BY 1;",
6346 gettext_noop("Object description"),
6347 oid);
6348
6349 res = PSQLexec(buf.data);
6351 if (!res)
6352 return false;
6353
6354 initPQExpBuffer(&title);
6355 printfPQExpBuffer(&title, _("Objects in extension \"%s\""), extname);
6356 myopt.title = title.data;
6357 myopt.translate_header = true;
6358
6359 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6360
6361 termPQExpBuffer(&title);
6362 PQclear(res);
6363 return true;
6364}

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

Referenced by listExtensionContents().

◆ listOperatorClasses()

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

Definition at line 6968 of file describe.c.

6970{
6972 PGresult *res;
6973 printQueryOpt myopt = pset.popt;
6974 bool have_where = false;
6975 static const bool translate_columns[] = {false, false, false, false, false, false, false};
6976
6978
6980 "SELECT\n"
6981 " am.amname AS \"%s\",\n"
6982 " pg_catalog.format_type(c.opcintype, NULL) AS \"%s\",\n"
6983 " CASE\n"
6984 " WHEN c.opckeytype <> 0 AND c.opckeytype <> c.opcintype\n"
6985 " THEN pg_catalog.format_type(c.opckeytype, NULL)\n"
6986 " ELSE NULL\n"
6987 " END AS \"%s\",\n"
6988 " CASE\n"
6989 " WHEN pg_catalog.pg_opclass_is_visible(c.oid)\n"
6990 " THEN pg_catalog.format('%%I', c.opcname)\n"
6991 " ELSE pg_catalog.format('%%I.%%I', n.nspname, c.opcname)\n"
6992 " END AS \"%s\",\n"
6993 " (CASE WHEN c.opcdefault\n"
6994 " THEN '%s'\n"
6995 " ELSE '%s'\n"
6996 " END) AS \"%s\"",
6997 gettext_noop("AM"),
6998 gettext_noop("Input type"),
6999 gettext_noop("Storage type"),
7000 gettext_noop("Operator class"),
7001 gettext_noop("yes"),
7002 gettext_noop("no"),
7003 gettext_noop("Default?"));
7004 if (verbose)
7006 ",\n CASE\n"
7007 " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
7008 " THEN pg_catalog.format('%%I', of.opfname)\n"
7009 " ELSE pg_catalog.format('%%I.%%I', ofn.nspname, of.opfname)\n"
7010 " END AS \"%s\",\n"
7011 " pg_catalog.pg_get_userbyid(c.opcowner) AS \"%s\"\n",
7012 gettext_noop("Operator family"),
7013 gettext_noop("Owner"));
7015 "\nFROM pg_catalog.pg_opclass c\n"
7016 " LEFT JOIN pg_catalog.pg_am am on am.oid = c.opcmethod\n"
7017 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.opcnamespace\n"
7018 " LEFT JOIN pg_catalog.pg_type t ON t.oid = c.opcintype\n"
7019 " LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n");
7020 if (verbose)
7022 " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = c.opcfamily\n"
7023 " LEFT JOIN pg_catalog.pg_namespace ofn ON ofn.oid = of.opfnamespace\n");
7024
7025 if (access_method_pattern)
7026 if (!validateSQLNamePattern(&buf, access_method_pattern,
7027 false, false, NULL, "am.amname", NULL, NULL,
7028 &have_where, 1))
7029 goto error_return;
7030 if (type_pattern)
7031 {
7032 /* Match type name pattern against either internal or external name */
7033 if (!validateSQLNamePattern(&buf, type_pattern, have_where, false,
7034 "tn.nspname", "t.typname",
7035 "pg_catalog.format_type(t.oid, NULL)",
7036 "pg_catalog.pg_type_is_visible(t.oid)",
7037 NULL, 3))
7038 goto error_return;
7039 }
7040
7041 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
7042 res = PSQLexec(buf.data);
7044 if (!res)
7045 return false;
7046
7047 myopt.title = _("List of operator classes");
7048 myopt.translate_header = true;
7049 myopt.translate_columns = translate_columns;
7050 myopt.n_translate_columns = lengthof(translate_columns);
7051
7052 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7053
7054 PQclear(res);
7055 return true;
7056
7057error_return:
7059 return false;
7060}

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

Referenced by exec_command_d().

◆ listOperatorFamilies()

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

Definition at line 7069 of file describe.c.

7071{
7073 PGresult *res;
7074 printQueryOpt myopt = pset.popt;
7075 bool have_where = false;
7076 static const bool translate_columns[] = {false, false, false, false};
7077
7079
7081 "SELECT\n"
7082 " am.amname AS \"%s\",\n"
7083 " CASE\n"
7084 " WHEN pg_catalog.pg_opfamily_is_visible(f.oid)\n"
7085 " THEN pg_catalog.format('%%I', f.opfname)\n"
7086 " ELSE pg_catalog.format('%%I.%%I', n.nspname, f.opfname)\n"
7087 " END AS \"%s\",\n"
7088 " (SELECT\n"
7089 " pg_catalog.string_agg(pg_catalog.format_type(oc.opcintype, NULL), ', ')\n"
7090 " FROM pg_catalog.pg_opclass oc\n"
7091 " WHERE oc.opcfamily = f.oid) \"%s\"",
7092 gettext_noop("AM"),
7093 gettext_noop("Operator family"),
7094 gettext_noop("Applicable types"));
7095 if (verbose)
7097 ",\n pg_catalog.pg_get_userbyid(f.opfowner) AS \"%s\"\n",
7098 gettext_noop("Owner"));
7100 "\nFROM pg_catalog.pg_opfamily f\n"
7101 " LEFT JOIN pg_catalog.pg_am am on am.oid = f.opfmethod\n"
7102 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace\n");
7103
7104 if (access_method_pattern)
7105 if (!validateSQLNamePattern(&buf, access_method_pattern,
7106 false, false, NULL, "am.amname", NULL, NULL,
7107 &have_where, 1))
7108 goto error_return;
7109 if (type_pattern)
7110 {
7112 " %s EXISTS (\n"
7113 " SELECT 1\n"
7114 " FROM pg_catalog.pg_type t\n"
7115 " JOIN pg_catalog.pg_opclass oc ON oc.opcintype = t.oid\n"
7116 " LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n"
7117 " WHERE oc.opcfamily = f.oid\n",
7118 have_where ? "AND" : "WHERE");
7119 /* Match type name pattern against either internal or external name */
7120 if (!validateSQLNamePattern(&buf, type_pattern, true, false,
7121 "tn.nspname", "t.typname",
7122 "pg_catalog.format_type(t.oid, NULL)",
7123 "pg_catalog.pg_type_is_visible(t.oid)",
7124 NULL, 3))
7125 goto error_return;
7126 appendPQExpBufferStr(&buf, " )\n");
7127 }
7128
7129 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
7130 res = PSQLexec(buf.data);
7132 if (!res)
7133 return false;
7134
7135 myopt.title = _("List of operator families");
7136 myopt.translate_header = true;
7137 myopt.translate_columns = translate_columns;
7138 myopt.n_translate_columns = lengthof(translate_columns);
7139
7140 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7141
7142 PQclear(res);
7143 return true;
7144
7145error_return:
7147 return false;
7148}

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

Referenced by exec_command_d().

◆ listOpFamilyFunctions()

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

Definition at line 7265 of file describe.c.

7267{
7269 PGresult *res;
7270 printQueryOpt myopt = pset.popt;
7271 bool have_where = false;
7272 static const bool translate_columns[] = {false, false, false, false, false, false};
7273
7275
7277 "SELECT\n"
7278 " am.amname AS \"%s\",\n"
7279 " CASE\n"
7280 " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
7281 " THEN pg_catalog.format('%%I', of.opfname)\n"
7282 " ELSE pg_catalog.format('%%I.%%I', ns.nspname, of.opfname)\n"
7283 " END AS \"%s\",\n"
7284 " pg_catalog.format_type(ap.amproclefttype, NULL) AS \"%s\",\n"
7285 " pg_catalog.format_type(ap.amprocrighttype, NULL) AS \"%s\",\n"
7286 " ap.amprocnum AS \"%s\"\n",
7287 gettext_noop("AM"),
7288 gettext_noop("Operator family"),
7289 gettext_noop("Registered left type"),
7290 gettext_noop("Registered right type"),
7291 gettext_noop("Number"));
7292
7293 if (!verbose)
7295 ", p.proname AS \"%s\"\n",
7296 gettext_noop("Function"));
7297 else
7299 ", ap.amproc::pg_catalog.regprocedure AS \"%s\"\n",
7300 gettext_noop("Function"));
7301
7303 "FROM pg_catalog.pg_amproc ap\n"
7304 " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = ap.amprocfamily\n"
7305 " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod\n"
7306 " LEFT JOIN pg_catalog.pg_namespace ns ON of.opfnamespace = ns.oid\n"
7307 " LEFT JOIN pg_catalog.pg_proc p ON ap.amproc = p.oid\n");
7308
7309 if (access_method_pattern)
7310 {
7311 if (!validateSQLNamePattern(&buf, access_method_pattern,
7312 false, false, NULL, "am.amname",
7313 NULL, NULL,
7314 &have_where, 1))
7315 goto error_return;
7316 }
7317 if (family_pattern)
7318 {
7319 if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
7320 "ns.nspname", "of.opfname", NULL, NULL,
7321 NULL, 3))
7322 goto error_return;
7323 }
7324
7325 appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
7326 " ap.amproclefttype = ap.amprocrighttype DESC,\n"
7327 " 3, 4, 5;");
7328
7329 res = PSQLexec(buf.data);
7331 if (!res)
7332 return false;
7333
7334 myopt.title = _("List of support functions of operator families");
7335 myopt.translate_header = true;
7336 myopt.translate_columns = translate_columns;
7337 myopt.n_translate_columns = lengthof(translate_columns);
7338
7339 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7340
7341 PQclear(res);
7342 return true;
7343
7344error_return:
7346 return false;
7347}

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

Referenced by exec_command_d().

◆ listOpFamilyOperators()

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

Definition at line 7158 of file describe.c.

7160{
7162 PGresult *res;
7163 printQueryOpt myopt = pset.popt;
7164 bool have_where = false;
7165
7166 static const bool translate_columns[] = {false, false, false, false, false, false, true};
7167
7169
7171 "SELECT\n"
7172 " am.amname AS \"%s\",\n"
7173 " CASE\n"
7174 " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
7175 " THEN pg_catalog.format('%%I', of.opfname)\n"
7176 " ELSE pg_catalog.format('%%I.%%I', nsf.nspname, of.opfname)\n"
7177 " END AS \"%s\",\n"
7178 " o.amopopr::pg_catalog.regoperator AS \"%s\"\n,"
7179 " o.amopstrategy AS \"%s\",\n"
7180 " CASE o.amoppurpose\n"
7181 " WHEN " CppAsString2(AMOP_ORDER) " THEN '%s'\n"
7182 " WHEN " CppAsString2(AMOP_SEARCH) " THEN '%s'\n"
7183 " END AS \"%s\"\n",
7184 gettext_noop("AM"),
7185 gettext_noop("Operator family"),
7186 gettext_noop("Operator"),
7187 gettext_noop("Strategy"),
7188 gettext_noop("ordering"),
7189 gettext_noop("search"),
7190 gettext_noop("Purpose"));
7191
7192 if (verbose)
7194 ", ofs.opfname AS \"%s\",\n"
7195 " CASE\n"
7196 " WHEN p.proleakproof THEN '%s'\n"
7197 " ELSE '%s'\n"
7198 " END AS \"%s\"\n",
7199 gettext_noop("Sort opfamily"),
7200 gettext_noop("yes"),
7201 gettext_noop("no"),
7202 gettext_noop("Leakproof?"));
7204 "FROM pg_catalog.pg_amop o\n"
7205 " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\n"
7206 " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod AND am.oid = o.amopmethod\n"
7207 " LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n");
7208 if (verbose)
7210 " LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n"
7211 " LEFT JOIN pg_catalog.pg_operator op ON op.oid = o.amopopr\n"
7212 " LEFT JOIN pg_catalog.pg_proc p ON p.oid = op.oprcode\n");
7213
7214 if (access_method_pattern)
7215 {
7216 if (!validateSQLNamePattern(&buf, access_method_pattern,
7217 false, false, NULL, "am.amname",
7218 NULL, NULL,
7219 &have_where, 1))
7220 goto error_return;
7221 }
7222
7223 if (family_pattern)
7224 {
7225 if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
7226 "nsf.nspname", "of.opfname", NULL, NULL,
7227 NULL, 3))
7228 goto error_return;
7229 }
7230
7231 appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
7232 " o.amoplefttype = o.amoprighttype DESC,\n"
7233 " pg_catalog.format_type(o.amoplefttype, NULL),\n"
7234 " pg_catalog.format_type(o.amoprighttype, NULL),\n"
7235 " o.amopstrategy;");
7236
7237 res = PSQLexec(buf.data);
7239 if (!res)
7240 return false;
7241
7242 myopt.title = _("List of operators of operator families");
7243 myopt.translate_header = true;
7244 myopt.translate_columns = translate_columns;
7245 myopt.n_translate_columns = lengthof(translate_columns);
7246
7247 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7248
7249 PQclear(res);
7250 return true;
7251
7252error_return:
7254 return false;
7255}

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

Referenced by exec_command_d().

◆ listPartitionedTables()

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

Definition at line 4296 of file describe.c.

4297{
4298 bool showTables = strchr(reltypes, 't') != NULL;
4299 bool showIndexes = strchr(reltypes, 'i') != NULL;
4300 bool showNested = strchr(reltypes, 'n') != NULL;
4302 PQExpBufferData title;
4303 PGresult *res;
4304 printQueryOpt myopt = pset.popt;
4305 bool translate_columns[] = {false, false, false, false, false, false, false, false, false, false};
4306 const char *tabletitle;
4307 bool mixed_output = false;
4308
4309 /*
4310 * Note: Declarative table partitioning is only supported as of Pg 10.0.
4311 */
4312 if (pset.sversion < 100000)
4313 {
4314 char sverbuf[32];
4315
4316 pg_log_error("The server (version %s) does not support declarative table partitioning.",
4318 sverbuf, sizeof(sverbuf)));
4319 return true;
4320 }
4321
4322 /* If no relation kind was selected, show them all */
4323 if (!showTables && !showIndexes)
4324 showTables = showIndexes = true;
4325
4326 if (showIndexes && !showTables)
4327 tabletitle = _("List of partitioned indexes"); /* \dPi */
4328 else if (showTables && !showIndexes)
4329 tabletitle = _("List of partitioned tables"); /* \dPt */
4330 else
4331 {
4332 /* show all kinds */
4333 tabletitle = _("List of partitioned relations");
4334 mixed_output = true;
4335 }
4336
4338
4340 "SELECT n.nspname as \"%s\",\n"
4341 " c.relname as \"%s\",\n"
4342 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
4343 gettext_noop("Schema"),
4344 gettext_noop("Name"),
4345 gettext_noop("Owner"));
4346
4347 if (mixed_output)
4348 {
4350 ",\n CASE c.relkind"
4351 " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
4352 " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
4353 " END as \"%s\"",
4354 gettext_noop("partitioned table"),
4355 gettext_noop("partitioned index"),
4356 gettext_noop("Type"));
4357
4358 translate_columns[3] = true;
4359 }
4360
4361 if (showNested || pattern)
4363 ",\n inh.inhparent::pg_catalog.regclass as \"%s\"",
4364 gettext_noop("Parent name"));
4365
4366 if (showIndexes)
4368 ",\n c2.oid::pg_catalog.regclass as \"%s\"",
4369 gettext_noop("Table"));
4370
4371 if (verbose)
4372 {
4373 /*
4374 * Table access methods were introduced in v12, and can be set on
4375 * partitioned tables since v17.
4376 */
4377 appendPQExpBuffer(&buf, ",\n am.amname as \"%s\"",
4378 gettext_noop("Access method"));
4379
4380 if (showNested)
4381 {
4383 ",\n s.dps as \"%s\"",
4384 gettext_noop("Leaf partition size"));
4386 ",\n s.tps as \"%s\"",
4387 gettext_noop("Total size"));
4388 }
4389 else
4390 /* Sizes of all partitions are considered in this case. */
4392 ",\n s.tps as \"%s\"",
4393 gettext_noop("Total size"));
4394
4396 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
4397 gettext_noop("Description"));
4398 }
4399
4401 "\nFROM pg_catalog.pg_class c"
4402 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
4403
4404 if (showIndexes)
4406 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
4407 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
4408
4409 if (showNested || pattern)
4411 "\n LEFT JOIN pg_catalog.pg_inherits inh ON c.oid = inh.inhrelid");
4412
4413 if (verbose)
4414 {
4416 "\n LEFT JOIN pg_catalog.pg_am am ON c.relam = am.oid");
4417
4418 if (pset.sversion < 120000)
4419 {
4421 ",\n LATERAL (WITH RECURSIVE d\n"
4422 " AS (SELECT inhrelid AS oid, 1 AS level\n"
4423 " FROM pg_catalog.pg_inherits\n"
4424 " WHERE inhparent = c.oid\n"
4425 " UNION ALL\n"
4426 " SELECT inhrelid, level + 1\n"
4427 " FROM pg_catalog.pg_inherits i\n"
4428 " JOIN d ON i.inhparent = d.oid)\n"
4429 " SELECT pg_catalog.pg_size_pretty(sum(pg_catalog.pg_table_size("
4430 "d.oid))) AS tps,\n"
4431 " pg_catalog.pg_size_pretty(sum("
4432 "\n CASE WHEN d.level = 1"
4433 " THEN pg_catalog.pg_table_size(d.oid) ELSE 0 END)) AS dps\n"
4434 " FROM d) s");
4435 }
4436 else
4437 {
4438 /* PostgreSQL 12 has pg_partition_tree function */
4440 ",\n LATERAL (SELECT pg_catalog.pg_size_pretty(sum("
4441 "\n CASE WHEN ppt.isleaf AND ppt.level = 1"
4442 "\n THEN pg_catalog.pg_table_size(ppt.relid)"
4443 " ELSE 0 END)) AS dps"
4444 ",\n pg_catalog.pg_size_pretty(sum("
4445 "pg_catalog.pg_table_size(ppt.relid))) AS tps"
4446 "\n FROM pg_catalog.pg_partition_tree(c.oid) ppt) s");
4447 }
4448 }
4449
4450 appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
4451 if (showTables)
4452 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
4453 if (showIndexes)
4454 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
4455 appendPQExpBufferStr(&buf, "''"); /* dummy */
4456 appendPQExpBufferStr(&buf, ")\n");
4457
4458 appendPQExpBufferStr(&buf, !showNested && !pattern ?
4459 " AND NOT c.relispartition\n" : "");
4460
4461 if (!pattern)
4462 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4463 " AND n.nspname !~ '^pg_toast'\n"
4464 " AND n.nspname <> 'information_schema'\n");
4465
4466 if (!validateSQLNamePattern(&buf, pattern, true, false,
4467 "n.nspname", "c.relname", NULL,
4468 "pg_catalog.pg_table_is_visible(c.oid)",
4469 NULL, 3))
4470 {
4472 return false;
4473 }
4474
4475 appendPQExpBuffer(&buf, "ORDER BY \"Schema\", %s%s\"Name\";",
4476 mixed_output ? "\"Type\" DESC, " : "",
4477 showNested || pattern ? "\"Parent name\" NULLS FIRST, " : "");
4478
4479 res = PSQLexec(buf.data);
4481 if (!res)
4482 return false;
4483
4484 initPQExpBuffer(&title);
4485 appendPQExpBufferStr(&title, tabletitle);
4486
4487 myopt.title = title.data;
4488 myopt.translate_header = true;
4489 myopt.translate_columns = translate_columns;
4490 myopt.n_translate_columns = lengthof(translate_columns);
4491
4492 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4493
4494 termPQExpBuffer(&title);
4495
4496 PQclear(res);
4497 return true;
4498}

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

Referenced by exec_command_d().

◆ listPublications()

bool listPublications ( const char *  pattern)

Definition at line 6430 of file describe.c.

6431{
6433 PGresult *res;
6434 printQueryOpt myopt = pset.popt;
6435 static const bool translate_columns[] = {false, false, false, false, false, false, false, false, false, false};
6436
6437 if (pset.sversion < 100000)
6438 {
6439 char sverbuf[32];
6440
6441 pg_log_error("The server (version %s) does not support publications.",
6443 sverbuf, sizeof(sverbuf)));
6444 return true;
6445 }
6446
6448
6450 "SELECT pubname AS \"%s\",\n"
6451 " pg_catalog.pg_get_userbyid(pubowner) AS \"%s\",\n"
6452 " puballtables AS \"%s\"",
6453 gettext_noop("Name"),
6454 gettext_noop("Owner"),
6455 gettext_noop("All tables"));
6456
6457 if (pset.sversion >= 190000)
6459 ",\n puballsequences AS \"%s\"",
6460 gettext_noop("All sequences"));
6461
6463 ",\n pubinsert AS \"%s\",\n"
6464 " pubupdate AS \"%s\",\n"
6465 " pubdelete AS \"%s\"",
6466 gettext_noop("Inserts"),
6467 gettext_noop("Updates"),
6468 gettext_noop("Deletes"));
6469 if (pset.sversion >= 110000)
6471 ",\n pubtruncate AS \"%s\"",
6472 gettext_noop("Truncates"));
6473 if (pset.sversion >= 180000)
6475 ",\n (CASE pubgencols\n"
6476 " WHEN '%c' THEN 'none'\n"
6477 " WHEN '%c' THEN 'stored'\n"
6478 " END) AS \"%s\"",
6479 PUBLISH_GENCOLS_NONE,
6480 PUBLISH_GENCOLS_STORED,
6481 gettext_noop("Generated columns"));
6482 if (pset.sversion >= 130000)
6484 ",\n pubviaroot AS \"%s\"",
6485 gettext_noop("Via root"));
6486
6488 "\nFROM pg_catalog.pg_publication\n");
6489
6490 if (!validateSQLNamePattern(&buf, pattern, false, false,
6491 NULL, "pubname", NULL,
6492 NULL,
6493 NULL, 1))
6494 {
6496 return false;
6497 }
6498
6499 appendPQExpBufferStr(&buf, "ORDER BY 1;");
6500
6501 res = PSQLexec(buf.data);
6503 if (!res)
6504 return false;
6505
6506 myopt.title = _("List of publications");
6507 myopt.translate_header = true;
6508 myopt.translate_columns = translate_columns;
6509 myopt.n_translate_columns = lengthof(translate_columns);
6510
6511 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6512
6513 PQclear(res);
6514
6515 return true;
6516}

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, _psqlSettings::sversion, termPQExpBuffer(), printQueryOpt::title, printQueryOpt::translate_columns, printQueryOpt::translate_header, and validateSQLNamePattern().

Referenced by exec_command_d().

◆ listSchemas()

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

Definition at line 5236 of file describe.c.

5237{
5239 PGresult *res;
5240 printQueryOpt myopt = pset.popt;
5241 int pub_schema_tuples = 0;
5242 char **footers = NULL;
5243
5246 "SELECT n.nspname AS \"%s\",\n"
5247 " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
5248 gettext_noop("Name"),
5249 gettext_noop("Owner"));
5250
5251 if (verbose)
5252 {
5253 appendPQExpBufferStr(&buf, ",\n ");
5254 printACLColumn(&buf, "n.nspacl");
5256 ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
5257 gettext_noop("Description"));
5258 }
5259
5261 "\nFROM pg_catalog.pg_namespace n\n");
5262
5263 if (!showSystem && !pattern)
5265 "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
5266
5267 if (!validateSQLNamePattern(&buf, pattern,
5268 !showSystem && !pattern, false,
5269 NULL, "n.nspname", NULL,
5270 NULL,
5271 NULL, 2))
5272 goto error_return;
5273
5274 appendPQExpBufferStr(&buf, "ORDER BY 1;");
5275
5276 res = PSQLexec(buf.data);
5277 if (!res)
5278 goto error_return;
5279
5280 myopt.title = _("List of schemas");
5281 myopt.translate_header = true;
5282
5283 if (pattern && pset.sversion >= 150000)
5284 {
5285 PGresult *result;
5286 int i;
5287
5289 "SELECT pubname \n"
5290 "FROM pg_catalog.pg_publication p\n"
5291 " JOIN pg_catalog.pg_publication_namespace pn ON p.oid = pn.pnpubid\n"
5292 " JOIN pg_catalog.pg_namespace n ON n.oid = pn.pnnspid \n"
5293 "WHERE n.nspname = '%s'\n"
5294 "ORDER BY 1",
5295 pattern);
5296 result = PSQLexec(buf.data);
5297 if (!result)
5298 goto error_return;
5299 else
5300 pub_schema_tuples = PQntuples(result);
5301
5302 if (pub_schema_tuples > 0)
5303 {
5304 /*
5305 * Allocate memory for footers. Size of footers will be 1 (for
5306 * storing "Publications:" string) + publication schema mapping
5307 * count + 1 (for storing NULL).
5308 */
5309 footers = (char **) pg_malloc((1 + pub_schema_tuples + 1) * sizeof(char *));
5310 footers[0] = pg_strdup(_("Publications:"));
5311
5312 /* Might be an empty set - that's ok */
5313 for (i = 0; i < pub_schema_tuples; i++)
5314 {
5315 printfPQExpBuffer(&buf, " \"%s\"",
5316 PQgetvalue(result, i, 0));
5317
5318 footers[i + 1] = pg_strdup(buf.data);
5319 }
5320
5321 footers[i + 1] = NULL;
5322 myopt.footers = footers;
5323 }
5324
5325 PQclear(result);
5326 }
5327
5328 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5329
5331 PQclear(res);
5332
5333 /* Free the memory allocated for the footer */
5334 if (footers)
5335 {
5336 char **footer = NULL;
5337
5338 for (footer = footers; *footer; footer++)
5339 pg_free(*footer);
5340
5341 pg_free(footers);
5342 }
5343
5344 return true;
5345
5346error_return:
5348 return false;
5349}
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void pg_free(void *ptr)
Definition: fe_memutils.c:105

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

Referenced by exec_command_d().

◆ listTables()

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

Definition at line 4041 of file describe.c.

4042{
4043 bool showTables = strchr(tabtypes, 't') != NULL;
4044 bool showIndexes = strchr(tabtypes, 'i') != NULL;
4045 bool showViews = strchr(tabtypes, 'v') != NULL;
4046 bool showMatViews = strchr(tabtypes, 'm') != NULL;
4047 bool showSeq = strchr(tabtypes, 's') != NULL;
4048 bool showForeign = strchr(tabtypes, 'E') != NULL;
4049
4050 int ntypes;
4052 PGresult *res;
4053 printQueryOpt myopt = pset.popt;
4054 int cols_so_far;
4055 bool translate_columns[] = {false, false, true, false, false, false, false, false, false};
4056
4057 /* Count the number of explicitly-requested relation types */
4058 ntypes = showTables + showIndexes + showViews + showMatViews +
4059 showSeq + showForeign;
4060 /* If none, we default to \dtvmsE (but see also command.c) */
4061 if (ntypes == 0)
4062 showTables = showViews = showMatViews = showSeq = showForeign = true;
4063
4065
4067 "SELECT n.nspname as \"%s\",\n"
4068 " c.relname as \"%s\",\n"
4069 " CASE c.relkind"
4070 " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
4071 " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
4072 " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
4073 " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'"
4074 " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
4075 " WHEN " CppAsString2(RELKIND_TOASTVALUE) " THEN '%s'"
4076 " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
4077 " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
4078 " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
4079 " END as \"%s\",\n"
4080 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
4081 gettext_noop("Schema"),
4082 gettext_noop("Name"),
4083 gettext_noop("table"),
4084 gettext_noop("view"),
4085 gettext_noop("materialized view"),
4086 gettext_noop("index"),
4087 gettext_noop("sequence"),
4088 gettext_noop("TOAST table"),
4089 gettext_noop("foreign table"),
4090 gettext_noop("partitioned table"),
4091 gettext_noop("partitioned index"),
4092 gettext_noop("Type"),
4093 gettext_noop("Owner"));
4094 cols_so_far = 4;
4095
4096 if (showIndexes)
4097 {
4099 ",\n c2.relname as \"%s\"",
4100 gettext_noop("Table"));
4101 cols_so_far++;
4102 }
4103
4104 if (verbose)
4105 {
4106 /*
4107 * Show whether a relation is permanent, temporary, or unlogged.
4108 */
4110 ",\n CASE c.relpersistence "
4111 "WHEN " CppAsString2(RELPERSISTENCE_PERMANENT) " THEN '%s' "
4112 "WHEN " CppAsString2(RELPERSISTENCE_TEMP) " THEN '%s' "
4113 "WHEN " CppAsString2(RELPERSISTENCE_UNLOGGED) " THEN '%s' "
4114 "END as \"%s\"",
4115 gettext_noop("permanent"),
4116 gettext_noop("temporary"),
4117 gettext_noop("unlogged"),
4118 gettext_noop("Persistence"));
4119 translate_columns[cols_so_far] = true;
4120
4121 /*
4122 * We don't bother to count cols_so_far below here, as there's no need
4123 * to; this might change with future additions to the output columns.
4124 */
4125
4126 /*
4127 * Access methods exist for tables, materialized views and indexes.
4128 * This has been introduced in PostgreSQL 12 for tables.
4129 */
4130 if (pset.sversion >= 120000 && !pset.hide_tableam &&
4131 (showTables || showMatViews || showIndexes))
4133 ",\n am.amname as \"%s\"",
4134 gettext_noop("Access method"));
4135
4137 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \"%s\""
4138 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
4139 gettext_noop("Size"),
4140 gettext_noop("Description"));
4141 }
4142
4144 "\nFROM pg_catalog.pg_class c"
4145 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
4146
4147 if (pset.sversion >= 120000 && !pset.hide_tableam &&
4148 (showTables || showMatViews || showIndexes))
4150 "\n LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam");
4151
4152 if (showIndexes)
4154 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
4155 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
4156
4157 appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
4158 if (showTables)
4159 {
4160 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_RELATION) ","
4161 CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
4162 /* with 'S' or a pattern, allow 't' to match TOAST tables too */
4163 if (showSystem || pattern)
4164 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_TOASTVALUE) ",");
4165 }
4166 if (showViews)
4167 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_VIEW) ",");
4168 if (showMatViews)
4169 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_MATVIEW) ",");
4170 if (showIndexes)
4171 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_INDEX) ","
4172 CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
4173 if (showSeq)
4174 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_SEQUENCE) ",");
4175 if (showSystem || pattern)
4176 appendPQExpBufferStr(&buf, "'s',"); /* was RELKIND_SPECIAL */
4177 if (showForeign)
4178 appendPQExpBufferStr(&buf, CppAsString2(RELKIND_FOREIGN_TABLE) ",");
4179
4180 appendPQExpBufferStr(&buf, "''"); /* dummy */
4181 appendPQExpBufferStr(&buf, ")\n");
4182
4183 if (!showSystem && !pattern)
4184 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4185 " AND n.nspname !~ '^pg_toast'\n"
4186 " AND n.nspname <> 'information_schema'\n");
4187
4188 if (!validateSQLNamePattern(&buf, pattern, true, false,
4189 "n.nspname", "c.relname", NULL,
4190 "pg_catalog.pg_table_is_visible(c.oid)",
4191 NULL, 3))
4192 {
4194 return false;
4195 }
4196
4197 appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
4198
4199 res = PSQLexec(buf.data);
4201 if (!res)
4202 return false;
4203
4204 /*
4205 * Most functions in this file are content to print an empty table when
4206 * there are no matching objects. We intentionally deviate from that
4207 * here, but only in !quiet mode, for historical reasons.
4208 */
4209 if (PQntuples(res) == 0 && !pset.quiet)
4210 {
4211 if (pattern)
4212 {
4213 if (ntypes != 1)
4214 pg_log_error("Did not find any relations named \"%s\".",
4215 pattern);
4216 else if (showTables)
4217 pg_log_error("Did not find any tables named \"%s\".",
4218 pattern);
4219 else if (showIndexes)
4220 pg_log_error("Did not find any indexes named \"%s\".",
4221 pattern);
4222 else if (showViews)
4223 pg_log_error("Did not find any views named \"%s\".",
4224 pattern);
4225 else if (showMatViews)
4226 pg_log_error("Did not find any materialized views named \"%s\".",
4227 pattern);
4228 else if (showSeq)
4229 pg_log_error("Did not find any sequences named \"%s\".",
4230 pattern);
4231 else if (showForeign)
4232 pg_log_error("Did not find any foreign tables named \"%s\".",
4233 pattern);
4234 else /* should not get here */
4235 pg_log_error_internal("Did not find any ??? named \"%s\".",
4236 pattern);
4237 }
4238 else
4239 {
4240 if (ntypes != 1)
4241 pg_log_error("Did not find any relations.");
4242 else if (showTables)
4243 pg_log_error("Did not find any tables.");
4244 else if (showIndexes)
4245 pg_log_error("Did not find any indexes.");
4246 else if (showViews)
4247 pg_log_error("Did not find any views.");
4248 else if (showMatViews)
4249 pg_log_error("Did not find any materialized views.");
4250 else if (showSeq)
4251 pg_log_error("Did not find any sequences.");
4252 else if (showForeign)
4253 pg_log_error("Did not find any foreign tables.");
4254 else /* should not get here */
4255 pg_log_error_internal("Did not find any ??? relations.");
4256 }
4257 }
4258 else
4259 {
4260 myopt.title =
4261 (ntypes != 1) ? _("List of relations") :
4262 (showTables) ? _("List of tables") :
4263 (showIndexes) ? _("List of indexes") :
4264 (showViews) ? _("List of views") :
4265 (showMatViews) ? _("List of materialized views") :
4266 (showSeq) ? _("List of sequences") :
4267 (showForeign) ? _("List of foreign tables") :
4268 "List of ???"; /* should not get here */
4269 myopt.translate_header = true;
4270 myopt.translate_columns = translate_columns;
4271 myopt.n_translate_columns = lengthof(translate_columns);
4272
4273 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4274 }
4275
4276 PQclear(res);
4277 return true;
4278}
#define pg_log_error_internal(...)
Definition: logging.h:160

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

Referenced by exec_command_d().

◆ listTSConfigs()

bool listTSConfigs ( const char *  pattern,
bool  verbose 
)

Definition at line 5734 of file describe.c.

5735{
5737 PGresult *res;
5738 printQueryOpt myopt = pset.popt;
5739
5740 if (verbose)
5741 return listTSConfigsVerbose(pattern);
5742
5744
5746 "SELECT\n"
5747 " n.nspname as \"%s\",\n"
5748 " c.cfgname as \"%s\",\n"
5749 " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
5750 "FROM pg_catalog.pg_ts_config c\n"
5751 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace\n",
5752 gettext_noop("Schema"),
5753 gettext_noop("Name"),
5754 gettext_noop("Description")
5755 );
5756
5757 if (!validateSQLNamePattern(&buf, pattern, false, false,
5758 "n.nspname", "c.cfgname", NULL,
5759 "pg_catalog.pg_ts_config_is_visible(c.oid)",
5760 NULL, 3))
5761 {
5763 return false;
5764 }
5765
5766 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5767
5768 res = PSQLexec(buf.data);
5770 if (!res)
5771 return false;
5772
5773 myopt.title = _("List of text search configurations");
5774 myopt.translate_header = true;
5775
5776 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5777
5778 PQclear(res);
5779 return true;
5780}
static bool listTSConfigsVerbose(const char *pattern)
Definition: describe.c:5783

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

Referenced by exec_command_d().

◆ listTSConfigsVerbose()

static bool listTSConfigsVerbose ( const char *  pattern)
static

Definition at line 5783 of file describe.c.

5784{
5786 PGresult *res;
5787 int i;
5788
5790
5792 "SELECT c.oid, c.cfgname,\n"
5793 " n.nspname,\n"
5794 " p.prsname,\n"
5795 " np.nspname as pnspname\n"
5796 "FROM pg_catalog.pg_ts_config c\n"
5797 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace,\n"
5798 " pg_catalog.pg_ts_parser p\n"
5799 " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace\n"
5800 "WHERE p.oid = c.cfgparser\n"
5801 );
5802
5803 if (!validateSQLNamePattern(&buf, pattern, true, false,
5804 "n.nspname", "c.cfgname", NULL,
5805 "pg_catalog.pg_ts_config_is_visible(c.oid)",
5806 NULL, 3))
5807 {
5809 return false;
5810 }
5811
5812 appendPQExpBufferStr(&buf, "ORDER BY 3, 2;");
5813
5814 res = PSQLexec(buf.data);
5816 if (!res)
5817 return false;
5818
5819 if (PQntuples(res) == 0)
5820 {
5821 if (!pset.quiet)
5822 {
5823 if (pattern)
5824 pg_log_error("Did not find any text search configuration named \"%s\".",
5825 pattern);
5826 else
5827 pg_log_error("Did not find any text search configurations.");
5828 }
5829 PQclear(res);
5830 return false;
5831 }
5832
5833 for (i = 0; i < PQntuples(res); i++)
5834 {
5835 const char *oid;
5836 const char *cfgname;
5837 const char *nspname = NULL;
5838 const char *prsname;
5839 const char *pnspname = NULL;
5840
5841 oid = PQgetvalue(res, i, 0);
5842 cfgname = PQgetvalue(res, i, 1);
5843 if (!PQgetisnull(res, i, 2))
5844 nspname = PQgetvalue(res, i, 2);
5845 prsname = PQgetvalue(res, i, 3);
5846 if (!PQgetisnull(res, i, 4))
5847 pnspname = PQgetvalue(res, i, 4);
5848
5849 if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname))
5850 {
5851 PQclear(res);
5852 return false;
5853 }
5854
5855 if (cancel_pressed)
5856 {
5857 PQclear(res);
5858 return false;
5859 }
5860 }
5861
5862 PQclear(res);
5863 return true;
5864}
static bool describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname, const char *pnspname, const char *prsname)
Definition: describe.c:5867

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

Referenced by listTSConfigs().

◆ listTSDictionaries()

bool listTSDictionaries ( const char *  pattern,
bool  verbose 
)

Definition at line 5604 of file describe.c.

5605{
5607 PGresult *res;
5608 printQueryOpt myopt = pset.popt;
5609
5611
5613 "SELECT\n"
5614 " n.nspname as \"%s\",\n"
5615 " d.dictname as \"%s\",\n",
5616 gettext_noop("Schema"),
5617 gettext_noop("Name"));
5618
5619 if (verbose)
5620 {
5622 " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM\n"
5623 " pg_catalog.pg_ts_template t\n"
5624 " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace\n"
5625 " WHERE d.dicttemplate = t.oid ) AS \"%s\",\n"
5626 " d.dictinitoption as \"%s\",\n",
5627 gettext_noop("Template"),
5628 gettext_noop("Init options"));
5629 }
5630
5632 " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
5633 gettext_noop("Description"));
5634
5635 appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_dict d\n"
5636 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
5637
5638 if (!validateSQLNamePattern(&buf, pattern, false, false,
5639 "n.nspname", "d.dictname", NULL,
5640 "pg_catalog.pg_ts_dict_is_visible(d.oid)",
5641 NULL, 3))
5642 {
5644 return false;
5645 }
5646
5647 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5648
5649 res = PSQLexec(buf.data);
5651 if (!res)
5652 return false;
5653
5654 myopt.title = _("List of text search dictionaries");
5655 myopt.translate_header = true;
5656
5657 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5658
5659 PQclear(res);
5660 return true;
5661}

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

Referenced by exec_command_d().

◆ listTSParsers()

bool listTSParsers ( const char *  pattern,
bool  verbose 
)

Definition at line 5357 of file describe.c.

5358{
5360 PGresult *res;
5361 printQueryOpt myopt = pset.popt;
5362
5363 if (verbose)
5364 return listTSParsersVerbose(pattern);
5365
5367
5369 "SELECT\n"
5370 " n.nspname as \"%s\",\n"
5371 " p.prsname as \"%s\",\n"
5372 " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
5373 "FROM pg_catalog.pg_ts_parser p\n"
5374 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
5375 gettext_noop("Schema"),
5376 gettext_noop("Name"),
5377 gettext_noop("Description")
5378 );
5379
5380 if (!validateSQLNamePattern(&buf, pattern, false, false,
5381 "n.nspname", "p.prsname", NULL,
5382 "pg_catalog.pg_ts_parser_is_visible(p.oid)",
5383 NULL, 3))
5384 {
5386 return false;
5387 }
5388
5389 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5390
5391 res = PSQLexec(buf.data);
5393 if (!res)
5394 return false;
5395
5396 myopt.title = _("List of text search parsers");
5397 myopt.translate_header = true;
5398
5399 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5400
5401 PQclear(res);
5402 return true;
5403}
static bool listTSParsersVerbose(const char *pattern)
Definition: describe.c:5409

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

Referenced by exec_command_d().

◆ listTSParsersVerbose()

static bool listTSParsersVerbose ( const char *  pattern)
static

Definition at line 5409 of file describe.c.

5410{
5412 PGresult *res;
5413 int i;
5414
5416
5418 "SELECT p.oid,\n"
5419 " n.nspname,\n"
5420 " p.prsname\n"
5421 "FROM pg_catalog.pg_ts_parser p\n"
5422 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
5423 );
5424
5425 if (!validateSQLNamePattern(&buf, pattern, false, false,
5426 "n.nspname", "p.prsname", NULL,
5427 "pg_catalog.pg_ts_parser_is_visible(p.oid)",
5428 NULL, 3))
5429 {
5431 return false;
5432 }
5433
5434 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5435
5436 res = PSQLexec(buf.data);
5438 if (!res)
5439 return false;
5440
5441 if (PQntuples(res) == 0)
5442 {
5443 if (!pset.quiet)
5444 {
5445 if (pattern)
5446 pg_log_error("Did not find any text search parser named \"%s\".",
5447 pattern);
5448 else
5449 pg_log_error("Did not find any text search parsers.");
5450 }
5451 PQclear(res);
5452 return false;
5453 }
5454
5455 for (i = 0; i < PQntuples(res); i++)
5456 {
5457 const char *oid;
5458 const char *nspname = NULL;
5459 const char *prsname;
5460
5461 oid = PQgetvalue(res, i, 0);
5462 if (!PQgetisnull(res, i, 1))
5463 nspname = PQgetvalue(res, i, 1);
5464 prsname = PQgetvalue(res, i, 2);
5465
5466 if (!describeOneTSParser(oid, nspname, prsname))
5467 {
5468 PQclear(res);
5469 return false;
5470 }
5471
5472 if (cancel_pressed)
5473 {
5474 PQclear(res);
5475 return false;
5476 }
5477 }
5478
5479 PQclear(res);
5480 return true;
5481}
static bool describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
Definition: describe.c:5484

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

Referenced by listTSParsers().

◆ listTSTemplates()

bool listTSTemplates ( const char *  pattern,
bool  verbose 
)

Definition at line 5669 of file describe.c.

5670{
5672 PGresult *res;
5673 printQueryOpt myopt = pset.popt;
5674
5676
5677 if (verbose)
5679 "SELECT\n"
5680 " n.nspname AS \"%s\",\n"
5681 " t.tmplname AS \"%s\",\n"
5682 " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
5683 " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
5684 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
5685 gettext_noop("Schema"),
5686 gettext_noop("Name"),
5687 gettext_noop("Init"),
5688 gettext_noop("Lexize"),
5689 gettext_noop("Description"));
5690 else
5692 "SELECT\n"
5693 " n.nspname AS \"%s\",\n"
5694 " t.tmplname AS \"%s\",\n"
5695 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
5696 gettext_noop("Schema"),
5697 gettext_noop("Name"),
5698 gettext_noop("Description"));
5699
5700 appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_template t\n"
5701 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
5702
5703 if (!validateSQLNamePattern(&buf, pattern, false, false,
5704 "n.nspname", "t.tmplname", NULL,
5705 "pg_catalog.pg_ts_template_is_visible(t.oid)",
5706 NULL, 3))
5707 {
5709 return false;
5710 }
5711
5712 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5713
5714 res = PSQLexec(buf.data);
5716 if (!res)
5717 return false;
5718
5719 myopt.title = _("List of text search templates");
5720 myopt.translate_header = true;
5721
5722 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5723
5724 PQclear(res);
5725 return true;
5726}

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

Referenced by exec_command_d().

◆ listUserMappings()

bool listUserMappings ( const char *  pattern,
bool  verbose 
)

Definition at line 6085 of file describe.c.

6086{
6088 PGresult *res;
6089 printQueryOpt myopt = pset.popt;
6090
6093 "SELECT um.srvname AS \"%s\",\n"
6094 " um.usename AS \"%s\"",
6095 gettext_noop("Server"),
6096 gettext_noop("User name"));
6097
6098 if (verbose)
6100 ",\n CASE WHEN umoptions IS NULL THEN '' ELSE "
6101 " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
6102 " pg_catalog.quote_ident(option_name) || ' ' || "
6103 " pg_catalog.quote_literal(option_value) FROM "
6104 " pg_catalog.pg_options_to_table(umoptions)), ', ') || ')' "
6105 " END AS \"%s\"",
6106 gettext_noop("FDW options"));
6107
6108 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
6109
6110 if (!validateSQLNamePattern(&buf, pattern, false, false,
6111 NULL, "um.srvname", "um.usename", NULL,
6112 NULL, 1))
6113 {
6115 return false;
6116 }
6117
6118 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
6119
6120 res = PSQLexec(buf.data);
6122 if (!res)
6123 return false;
6124
6125 myopt.title = _("List of user mappings");
6126 myopt.translate_header = true;
6127
6128 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6129
6130 PQclear(res);
6131 return true;
6132}

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

Referenced by exec_command_d().

◆ map_typename_pattern()

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

Definition at line 744 of file describe.c.

745{
746 static const char *const typename_map[] = {
747 /*
748 * These names are accepted by gram.y, although they are neither the
749 * "real" name seen in pg_type nor the canonical name printed by
750 * format_type().
751 */
752 "decimal", "numeric",
753 "float", "double precision",
754 "int", "integer",
755
756 /*
757 * We also have to map the array names for cases where the canonical
758 * name is different from what pg_type says.
759 */
760 "bool[]", "boolean[]",
761 "decimal[]", "numeric[]",
762 "float[]", "double precision[]",
763 "float4[]", "real[]",
764 "float8[]", "double precision[]",
765 "int[]", "integer[]",
766 "int2[]", "smallint[]",
767 "int4[]", "integer[]",
768 "int8[]", "bigint[]",
769 "time[]", "time without time zone[]",
770 "timetz[]", "time with time zone[]",
771 "timestamp[]", "timestamp without time zone[]",
772 "timestamptz[]", "timestamp with time zone[]",
773 "varbit[]", "bit varying[]",
774 "varchar[]", "character varying[]",
775 NULL
776 };
777
778 if (pattern == NULL)
779 return NULL;
780 for (int i = 0; typename_map[i] != NULL; i += 2)
781 {
782 if (pg_strcasecmp(pattern, typename_map[i]) == 0)
783 return typename_map[i + 1];
784 }
785 return pattern;
786}
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:32

References i, and pg_strcasecmp().

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

◆ objectDescription()

bool objectDescription ( const char *  pattern,
bool  showSystem 
)

Definition at line 1295 of file describe.c.

1296{
1298 PGresult *res;
1299 printQueryOpt myopt = pset.popt;
1300 static const bool translate_columns[] = {false, false, true, false};
1301
1303
1305 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
1306 "FROM (\n",
1307 gettext_noop("Schema"),
1308 gettext_noop("Name"),
1309 gettext_noop("Object"),
1310 gettext_noop("Description"));
1311
1312 /* Table constraint descriptions */
1314 " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1315 " n.nspname as nspname,\n"
1316 " CAST(pgc.conname AS pg_catalog.text) as name,"
1317 " CAST('%s' AS pg_catalog.text) as object\n"
1318 " FROM pg_catalog.pg_constraint pgc\n"
1319 " JOIN pg_catalog.pg_class c "
1320 "ON c.oid = pgc.conrelid\n"
1321 " LEFT JOIN pg_catalog.pg_namespace n "
1322 " ON n.oid = c.relnamespace\n",
1323 gettext_noop("table constraint"));
1324
1325 if (!showSystem && !pattern)
1326 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1327 " AND n.nspname <> 'information_schema'\n");
1328
1329 if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern,
1330 false, "n.nspname", "pgc.conname", NULL,
1331 "pg_catalog.pg_table_is_visible(c.oid)",
1332 NULL, 3))
1333 goto error_return;
1334
1335 /* Domain constraint descriptions */
1337 "UNION ALL\n"
1338 " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1339 " n.nspname as nspname,\n"
1340 " CAST(pgc.conname AS pg_catalog.text) as name,"
1341 " CAST('%s' AS pg_catalog.text) as object\n"
1342 " FROM pg_catalog.pg_constraint pgc\n"
1343 " JOIN pg_catalog.pg_type t "
1344 "ON t.oid = pgc.contypid\n"
1345 " LEFT JOIN pg_catalog.pg_namespace n "
1346 " ON n.oid = t.typnamespace\n",
1347 gettext_noop("domain constraint"));
1348
1349 if (!showSystem && !pattern)
1350 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1351 " AND n.nspname <> 'information_schema'\n");
1352
1353 if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern,
1354 false, "n.nspname", "pgc.conname", NULL,
1355 "pg_catalog.pg_type_is_visible(t.oid)",
1356 NULL, 3))
1357 goto error_return;
1358
1359 /* Operator class descriptions */
1361 "UNION ALL\n"
1362 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
1363 " n.nspname as nspname,\n"
1364 " CAST(o.opcname AS pg_catalog.text) as name,\n"
1365 " CAST('%s' AS pg_catalog.text) as object\n"
1366 " FROM pg_catalog.pg_opclass o\n"
1367 " JOIN pg_catalog.pg_am am ON "
1368 "o.opcmethod = am.oid\n"
1369 " JOIN pg_catalog.pg_namespace n ON "
1370 "n.oid = o.opcnamespace\n",
1371 gettext_noop("operator class"));
1372
1373 if (!showSystem && !pattern)
1374 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1375 " AND n.nspname <> 'information_schema'\n");
1376
1377 if (!validateSQLNamePattern(&buf, pattern, true, false,
1378 "n.nspname", "o.opcname", NULL,
1379 "pg_catalog.pg_opclass_is_visible(o.oid)",
1380 NULL, 3))
1381 goto error_return;
1382
1383 /* Operator family descriptions */
1385 "UNION ALL\n"
1386 " SELECT opf.oid as oid, opf.tableoid as tableoid,\n"
1387 " n.nspname as nspname,\n"
1388 " CAST(opf.opfname AS pg_catalog.text) AS name,\n"
1389 " CAST('%s' AS pg_catalog.text) as object\n"
1390 " FROM pg_catalog.pg_opfamily opf\n"
1391 " JOIN pg_catalog.pg_am am "
1392 "ON opf.opfmethod = am.oid\n"
1393 " JOIN pg_catalog.pg_namespace n "
1394 "ON opf.opfnamespace = n.oid\n",
1395 gettext_noop("operator family"));
1396
1397 if (!showSystem && !pattern)
1398 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1399 " AND n.nspname <> 'information_schema'\n");
1400
1401 if (!validateSQLNamePattern(&buf, pattern, true, false,
1402 "n.nspname", "opf.opfname", NULL,
1403 "pg_catalog.pg_opfamily_is_visible(opf.oid)",
1404 NULL, 3))
1405 goto error_return;
1406
1407 /* Rule descriptions (ignore rules for views) */
1409 "UNION ALL\n"
1410 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
1411 " n.nspname as nspname,\n"
1412 " CAST(r.rulename AS pg_catalog.text) as name,"
1413 " CAST('%s' AS pg_catalog.text) as object\n"
1414 " FROM pg_catalog.pg_rewrite r\n"
1415 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
1416 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
1417 " WHERE r.rulename != '_RETURN'\n",
1418 gettext_noop("rule"));
1419
1420 if (!showSystem && !pattern)
1421 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1422 " AND n.nspname <> 'information_schema'\n");
1423
1424 if (!validateSQLNamePattern(&buf, pattern, true, false,
1425 "n.nspname", "r.rulename", NULL,
1426 "pg_catalog.pg_table_is_visible(c.oid)",
1427 NULL, 3))
1428 goto error_return;
1429
1430 /* Trigger descriptions */
1432 "UNION ALL\n"
1433 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
1434 " n.nspname as nspname,\n"
1435 " CAST(t.tgname AS pg_catalog.text) as name,"
1436 " CAST('%s' AS pg_catalog.text) as object\n"
1437 " FROM pg_catalog.pg_trigger t\n"
1438 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
1439 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
1440 gettext_noop("trigger"));
1441
1442 if (!showSystem && !pattern)
1443 appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1444 " AND n.nspname <> 'information_schema'\n");
1445
1446 if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, false,
1447 "n.nspname", "t.tgname", NULL,
1448 "pg_catalog.pg_table_is_visible(c.oid)",
1449 NULL, 3))
1450 goto error_return;
1451
1453 ") AS tt\n"
1454 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
1455
1456 appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1457
1458 res = PSQLexec(buf.data);
1460 if (!res)
1461 return false;
1462
1463 myopt.title = _("Object descriptions");
1464 myopt.translate_header = true;
1465 myopt.translate_columns = translate_columns;
1466 myopt.n_translate_columns = lengthof(translate_columns);
1467
1468 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1469
1470 PQclear(res);
1471 return true;
1472
1473error_return:
1475 return false;
1476}

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

Referenced by exec_command_d().

◆ permissionsList()

bool permissionsList ( const char *  pattern,
bool  showSystem 
)

Definition at line 1050 of file describe.c.

1051{
1053 PGresult *res;
1054 printQueryOpt myopt = pset.popt;
1055 static const bool translate_columns[] = {false, false, true, false, false, false};
1056
1058
1059 /*
1060 * we ignore indexes and toast tables since they have no meaningful rights
1061 */
1063 "SELECT n.nspname as \"%s\",\n"
1064 " c.relname as \"%s\",\n"
1065 " CASE c.relkind"
1066 " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
1067 " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
1068 " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
1069 " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
1070 " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
1071 " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
1072 " END as \"%s\",\n"
1073 " ",
1074 gettext_noop("Schema"),
1075 gettext_noop("Name"),
1076 gettext_noop("table"),
1077 gettext_noop("view"),
1078 gettext_noop("materialized view"),
1079 gettext_noop("sequence"),
1080 gettext_noop("foreign table"),
1081 gettext_noop("partitioned table"),
1082 gettext_noop("Type"));
1083
1084 printACLColumn(&buf, "c.relacl");
1085
1086 /*
1087 * The formatting of attacl should match printACLColumn(). However, we
1088 * need no special case for an empty attacl, because the backend always
1089 * optimizes that back to NULL.
1090 */
1092 ",\n pg_catalog.array_to_string(ARRAY(\n"
1093 " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
1094 " FROM pg_catalog.pg_attribute a\n"
1095 " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
1096 " ), E'\\n') AS \"%s\"",
1097 gettext_noop("Column privileges"));
1098
1099 if (pset.sversion >= 90500 && pset.sversion < 100000)
1101 ",\n pg_catalog.array_to_string(ARRAY(\n"
1102 " SELECT polname\n"
1103 " || CASE WHEN polcmd != '*' THEN\n"
1104 " E' (' || polcmd::pg_catalog.text || E'):'\n"
1105 " ELSE E':'\n"
1106 " END\n"
1107 " || CASE WHEN polqual IS NOT NULL THEN\n"
1108 " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
1109 " ELSE E''\n"
1110 " END\n"
1111 " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
1112 " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
1113 " ELSE E''\n"
1114 " END"
1115 " || CASE WHEN polroles <> '{0}' THEN\n"
1116 " E'\\n to: ' || pg_catalog.array_to_string(\n"
1117 " ARRAY(\n"
1118 " SELECT rolname\n"
1119 " FROM pg_catalog.pg_roles\n"
1120 " WHERE oid = ANY (polroles)\n"
1121 " ORDER BY 1\n"
1122 " ), E', ')\n"
1123 " ELSE E''\n"
1124 " END\n"
1125 " FROM pg_catalog.pg_policy pol\n"
1126 " WHERE polrelid = c.oid), E'\\n')\n"
1127 " AS \"%s\"",
1128 gettext_noop("Policies"));
1129
1130 if (pset.sversion >= 100000)
1132 ",\n pg_catalog.array_to_string(ARRAY(\n"
1133 " SELECT polname\n"
1134 " || CASE WHEN NOT polpermissive THEN\n"
1135 " E' (RESTRICTIVE)'\n"
1136 " ELSE '' END\n"
1137 " || CASE WHEN polcmd != '*' THEN\n"
1138 " E' (' || polcmd::pg_catalog.text || E'):'\n"
1139 " ELSE E':'\n"
1140 " END\n"
1141 " || CASE WHEN polqual IS NOT NULL THEN\n"
1142 " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
1143 " ELSE E''\n"
1144 " END\n"
1145 " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
1146 " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
1147 " ELSE E''\n"
1148 " END"
1149 " || CASE WHEN polroles <> '{0}' THEN\n"
1150 " E'\\n to: ' || pg_catalog.array_to_string(\n"
1151 " ARRAY(\n"
1152 " SELECT rolname\n"
1153 " FROM pg_catalog.pg_roles\n"
1154 " WHERE oid = ANY (polroles)\n"
1155 " ORDER BY 1\n"
1156 " ), E', ')\n"
1157 " ELSE E''\n"
1158 " END\n"
1159 " FROM pg_catalog.pg_policy pol\n"
1160 " WHERE polrelid = c.oid), E'\\n')\n"
1161 " AS \"%s\"",
1162 gettext_noop("Policies"));
1163
1164 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_class c\n"
1165 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
1166 "WHERE c.relkind IN ("
1167 CppAsString2(RELKIND_RELATION) ","
1168 CppAsString2(RELKIND_VIEW) ","
1169 CppAsString2(RELKIND_MATVIEW) ","
1170 CppAsString2(RELKIND_SEQUENCE) ","
1171 CppAsString2(RELKIND_FOREIGN_TABLE) ","
1172 CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
1173
1174 if (!showSystem && !pattern)
1175 appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1176 " AND n.nspname <> 'information_schema'\n");
1177
1178 if (!validateSQLNamePattern(&buf, pattern, true, false,
1179 "n.nspname", "c.relname", NULL,
1180 "pg_catalog.pg_table_is_visible(c.oid)",
1181 NULL, 3))
1182 goto error_return;
1183
1184 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
1185
1186 res = PSQLexec(buf.data);
1187 if (!res)
1188 goto error_return;
1189
1190 printfPQExpBuffer(&buf, _("Access privileges"));
1191 myopt.title = buf.data;
1192 myopt.translate_header = true;
1193 myopt.translate_columns = translate_columns;
1194 myopt.n_translate_columns = lengthof(translate_columns);
1195
1196 printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1197
1199 PQclear(res);
1200 return true;
1201
1202error_return:
1204 return false;
1205}

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

Referenced by exec_command_d(), and exec_command_z().

◆ printACLColumn()

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

Definition at line 6950 of file describe.c.

6951{
6953 "CASE"
6954 " WHEN pg_catalog.array_length(%s, 1) = 0 THEN '%s'"
6955 " ELSE pg_catalog.array_to_string(%s, E'\\n')"
6956 " END AS \"%s\"",
6957 colname, gettext_noop("(none)"),
6958 colname, gettext_noop("Access privileges"));
6959}

References appendPQExpBuffer(), buf, and gettext_noop.

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

◆ validateSQLNamePattern()

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

Definition at line 6377 of file describe.c.

6382{
6383 PQExpBufferData dbbuf;
6384 int dotcnt;
6385 bool added;
6386
6387 initPQExpBuffer(&dbbuf);
6388 added = processSQLNamePattern(pset.db, buf, pattern, have_where, force_escape,
6389 schemavar, namevar, altnamevar,
6390 visibilityrule, &dbbuf, &dotcnt);
6391 if (added_clause != NULL)
6392 *added_clause = added;
6393
6394 if (dotcnt >= maxparts)
6395 {
6396 pg_log_error("improper qualified name (too many dotted names): %s",
6397 pattern);
6398 goto error_return;
6399 }
6400
6401 if (maxparts > 1 && dotcnt == maxparts - 1)
6402 {
6403 if (PQdb(pset.db) == NULL)
6404 {
6405 pg_log_error("You are currently not connected to a database.");
6406 goto error_return;
6407 }
6408 if (strcmp(PQdb(pset.db), dbbuf.data) != 0)
6409 {
6410 pg_log_error("cross-database references are not implemented: %s",
6411 pattern);
6412 goto error_return;
6413 }
6414 }
6415 termPQExpBuffer(&dbbuf);
6416 return true;
6417
6418error_return:
6419 termPQExpBuffer(&dbbuf);
6420 return false;
6421}
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7538

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

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