Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * psql - the PostgreSQL interactive terminal
3 : : *
4 : : * Support for the various \d ("describe") commands. Note that the current
5 : : * expectation is that all functions in this file will succeed when working
6 : : * with servers of versions 9.2 and up. It's okay to omit irrelevant
7 : : * information for an old server, but not to fail outright. (But failing
8 : : * against a pre-9.2 server is allowed.)
9 : : *
10 : : * Copyright (c) 2000-2024, PostgreSQL Global Development Group
11 : : *
12 : : * src/bin/psql/describe.c
13 : : */
14 : : #include "postgres_fe.h"
15 : :
16 : : #include <ctype.h>
17 : :
18 : : #include "catalog/pg_am.h"
19 : : #include "catalog/pg_attribute_d.h"
20 : : #include "catalog/pg_cast_d.h"
21 : : #include "catalog/pg_class_d.h"
22 : : #include "catalog/pg_default_acl_d.h"
23 : : #include "common.h"
24 : : #include "common/logging.h"
25 : : #include "describe.h"
26 : : #include "fe_utils/mbprint.h"
27 : : #include "fe_utils/print.h"
28 : : #include "fe_utils/string_utils.h"
29 : : #include "settings.h"
30 : : #include "variables.h"
31 : :
32 : : static const char *map_typename_pattern(const char *pattern);
33 : : static bool describeOneTableDetails(const char *schemaname,
34 : : const char *relationname,
35 : : const char *oid,
36 : : bool verbose);
37 : : static void add_tablespace_footer(printTableContent *const cont, char relkind,
38 : : Oid tablespace, const bool newline);
39 : : static void add_role_attribute(PQExpBuffer buf, const char *const str);
40 : : static bool listTSParsersVerbose(const char *pattern);
41 : : static bool describeOneTSParser(const char *oid, const char *nspname,
42 : : const char *prsname);
43 : : static bool listTSConfigsVerbose(const char *pattern);
44 : : static bool describeOneTSConfig(const char *oid, const char *nspname,
45 : : const char *cfgname,
46 : : const char *pnspname, const char *prsname);
47 : : static void printACLColumn(PQExpBuffer buf, const char *colname);
48 : : static bool listOneExtensionContents(const char *extname, const char *oid);
49 : : static bool validateSQLNamePattern(PQExpBuffer buf, const char *pattern,
50 : : bool have_where, bool force_escape,
51 : : const char *schemavar, const char *namevar,
52 : : const char *altnamevar,
53 : : const char *visibilityrule,
54 : : bool *added_clause, int maxparts);
55 : :
56 : :
57 : : /*----------------
58 : : * Handlers for various slash commands displaying some sort of list
59 : : * of things in the database.
60 : : *
61 : : * Note: try to format the queries to look nice in -E output.
62 : : *----------------
63 : : */
64 : :
65 : :
66 : : /*
67 : : * \da
68 : : * Takes an optional regexp to select particular aggregates
69 : : */
70 : : bool
5577 bruce@momjian.us 71 :CBC 24 : describeAggregates(const char *pattern, bool verbose, bool showSystem)
72 : : {
73 : : PQExpBufferData buf;
74 : : PGresult *res;
8857 peter_e@gmx.net 75 : 24 : printQueryOpt myopt = pset.popt;
76 : :
8026 77 : 24 : initPQExpBuffer(&buf);
78 : :
79 : 24 : printfPQExpBuffer(&buf,
80 : : "SELECT n.nspname as \"%s\",\n"
81 : : " p.proname AS \"%s\",\n"
82 : : " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n"
83 : : " CASE WHEN p.pronargs = 0\n"
84 : : " THEN CAST('*' AS pg_catalog.text)\n"
85 : : " ELSE pg_catalog.pg_get_function_arguments(p.oid)\n"
86 : : " END AS \"%s\",\n",
87 : : gettext_noop("Schema"),
88 : : gettext_noop("Name"),
89 : : gettext_noop("Result data type"),
90 : : gettext_noop("Argument data types"));
91 : :
2235 92 [ + - ]: 24 : if (pset.sversion >= 110000)
93 : 24 : appendPQExpBuffer(&buf,
94 : : " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
95 : : "FROM pg_catalog.pg_proc p\n"
96 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
97 : : "WHERE p.prokind = 'a'\n",
98 : : gettext_noop("Description"));
99 : : else
2235 peter_e@gmx.net 100 :UBC 0 : appendPQExpBuffer(&buf,
101 : : " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
102 : : "FROM pg_catalog.pg_proc p\n"
103 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
104 : : "WHERE p.proisagg\n",
105 : : gettext_noop("Description"));
106 : :
5421 bruce@momjian.us 107 [ + - - + ]:CBC 24 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 108 :UBC 0 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
109 : : " AND n.nspname <> 'information_schema'\n");
110 : :
725 rhaas@postgresql.org 111 [ + + ]:CBC 24 : if (!validateSQLNamePattern(&buf, pattern, true, false,
112 : : "n.nspname", "p.proname", NULL,
113 : : "pg_catalog.pg_function_is_visible(p.oid)",
114 : : NULL, 3))
115 : : {
633 michael@paquier.xyz 116 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 117 : 12 : return false;
118 : : }
119 : :
3800 heikki.linnakangas@i 120 : 12 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
121 : :
3461 fujii@postgresql.org 122 : 12 : res = PSQLexec(buf.data);
8026 peter_e@gmx.net 123 : 12 : termPQExpBuffer(&buf);
8928 bruce@momjian.us 124 [ - + ]: 12 : if (!res)
8928 bruce@momjian.us 125 :UBC 0 : return false;
126 : :
8324 peter_e@gmx.net 127 :CBC 12 : myopt.title = _("List of aggregate functions");
5753 bruce@momjian.us 128 : 12 : myopt.translate_header = true;
129 : :
3056 tgl@sss.pgh.pa.us 130 : 12 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
131 : :
8928 bruce@momjian.us 132 : 12 : PQclear(res);
133 : 12 : return true;
134 : : }
135 : :
136 : : /*
137 : : * \dA
138 : : * Takes an optional regexp to select particular access methods
139 : : */
140 : : bool
2868 alvherre@alvh.no-ip. 141 : 39 : describeAccessMethods(const char *pattern, bool verbose)
142 : : {
143 : : PQExpBufferData buf;
144 : : PGresult *res;
145 : 39 : printQueryOpt myopt = pset.popt;
146 : : static const bool translate_columns[] = {false, true, false, false};
147 : :
148 [ - + ]: 39 : if (pset.sversion < 90600)
149 : : {
150 : : char sverbuf[32];
151 : :
1840 peter@eisentraut.org 152 :UBC 0 : pg_log_error("The server (version %s) does not support access methods.",
153 : : formatPGVersionNumber(pset.sversion, false,
154 : : sverbuf, sizeof(sverbuf)));
2868 alvherre@alvh.no-ip. 155 : 0 : return true;
156 : : }
157 : :
2868 alvherre@alvh.no-ip. 158 :CBC 39 : initPQExpBuffer(&buf);
159 : :
160 : 39 : printfPQExpBuffer(&buf,
161 : : "SELECT amname AS \"%s\",\n"
162 : : " CASE amtype"
163 : : " WHEN 'i' THEN '%s'"
164 : : " WHEN 't' THEN '%s'"
165 : : " END AS \"%s\"",
166 : : gettext_noop("Name"),
167 : : gettext_noop("Index"),
168 : : gettext_noop("Table"),
169 : : gettext_noop("Type"));
170 : :
171 [ + + ]: 39 : if (verbose)
172 : : {
173 : 12 : appendPQExpBuffer(&buf,
174 : : ",\n amhandler AS \"%s\",\n"
175 : : " pg_catalog.obj_description(oid, 'pg_am') AS \"%s\"",
176 : : gettext_noop("Handler"),
177 : : gettext_noop("Description"));
178 : : }
179 : :
180 : 39 : appendPQExpBufferStr(&buf,
181 : : "\nFROM pg_catalog.pg_am\n");
182 : :
725 rhaas@postgresql.org 183 [ + + ]: 39 : if (!validateSQLNamePattern(&buf, pattern, false, false,
184 : : NULL, "amname", NULL,
185 : : NULL,
186 : : NULL, 1))
187 : : {
633 michael@paquier.xyz 188 : 9 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 189 : 9 : return false;
190 : : }
191 : :
2868 alvherre@alvh.no-ip. 192 : 30 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
193 : :
194 : 30 : res = PSQLexec(buf.data);
195 : 30 : termPQExpBuffer(&buf);
196 [ - + ]: 30 : if (!res)
2868 alvherre@alvh.no-ip. 197 :UBC 0 : return false;
198 : :
2868 alvherre@alvh.no-ip. 199 :CBC 30 : myopt.title = _("List of access methods");
200 : 30 : myopt.translate_header = true;
201 : 30 : myopt.translate_columns = translate_columns;
202 : 30 : myopt.n_translate_columns = lengthof(translate_columns);
203 : :
204 : 30 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
205 : :
206 : 30 : PQclear(res);
207 : 30 : return true;
208 : : }
209 : :
210 : : /*
211 : : * \db
212 : : * Takes an optional regexp to select particular tablespaces
213 : : */
214 : : bool
7213 bruce@momjian.us 215 : 12 : describeTablespaces(const char *pattern, bool verbose)
216 : : {
217 : : PQExpBufferData buf;
218 : : PGresult *res;
7240 tgl@sss.pgh.pa.us 219 : 12 : printQueryOpt myopt = pset.popt;
220 : :
221 : 12 : initPQExpBuffer(&buf);
222 : :
850 223 : 12 : printfPQExpBuffer(&buf,
224 : : "SELECT spcname AS \"%s\",\n"
225 : : " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
226 : : " pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
227 : : gettext_noop("Name"),
228 : : gettext_noop("Owner"),
229 : : gettext_noop("Location"));
230 : :
7213 bruce@momjian.us 231 [ - + ]: 12 : if (verbose)
232 : : {
3800 heikki.linnakangas@i 233 :UBC 0 : appendPQExpBufferStr(&buf, ",\n ");
5583 tgl@sss.pgh.pa.us 234 : 0 : printACLColumn(&buf, "spcacl");
3731 magnus@hagander.net 235 : 0 : appendPQExpBuffer(&buf,
236 : : ",\n spcoptions AS \"%s\""
237 : : ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS \"%s\""
238 : : ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
239 : : gettext_noop("Options"),
240 : : gettext_noop("Size"),
241 : : gettext_noop("Description"));
242 : : }
243 : :
3800 heikki.linnakangas@i 244 :CBC 12 : appendPQExpBufferStr(&buf,
245 : : "\nFROM pg_catalog.pg_tablespace\n");
246 : :
725 rhaas@postgresql.org 247 [ + + ]: 12 : if (!validateSQLNamePattern(&buf, pattern, false, false,
248 : : NULL, "spcname", NULL,
249 : : NULL,
250 : : NULL, 1))
251 : : {
633 michael@paquier.xyz 252 : 9 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 253 : 9 : return false;
254 : : }
255 : :
3800 heikki.linnakangas@i 256 : 3 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
257 : :
3461 fujii@postgresql.org 258 : 3 : res = PSQLexec(buf.data);
7240 tgl@sss.pgh.pa.us 259 : 3 : termPQExpBuffer(&buf);
260 [ - + ]: 3 : if (!res)
7240 tgl@sss.pgh.pa.us 261 :UBC 0 : return false;
262 : :
7240 tgl@sss.pgh.pa.us 263 :CBC 3 : myopt.title = _("List of tablespaces");
5753 bruce@momjian.us 264 : 3 : myopt.translate_header = true;
265 : :
3056 tgl@sss.pgh.pa.us 266 : 3 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
267 : :
7240 268 : 3 : PQclear(res);
269 : 3 : return true;
270 : : }
271 : :
272 : :
273 : : /*
274 : : * \df
275 : : * Takes an optional regexp to select particular functions.
276 : : *
277 : : * As with \d, you can specify the kinds of functions you want:
278 : : *
279 : : * a for aggregates
280 : : * n for normal
281 : : * p for procedure
282 : : * t for trigger
283 : : * w for window
284 : : *
285 : : * and you can mix and match these in any order.
286 : : */
287 : : bool
1103 288 : 146 : describeFunctions(const char *functypes, const char *func_pattern,
289 : : char **arg_patterns, int num_arg_patterns,
290 : : bool verbose, bool showSystem)
291 : : {
5458 292 : 146 : bool showAggregate = strchr(functypes, 'a') != NULL;
293 : 146 : bool showNormal = strchr(functypes, 'n') != NULL;
2101 peter_e@gmx.net 294 : 146 : bool showProcedure = strchr(functypes, 'p') != NULL;
5458 tgl@sss.pgh.pa.us 295 : 146 : bool showTrigger = strchr(functypes, 't') != NULL;
296 : 146 : bool showWindow = strchr(functypes, 'w') != NULL;
297 : : bool have_where;
298 : : PQExpBufferData buf;
299 : : PGresult *res;
8857 peter_e@gmx.net 300 : 146 : printQueryOpt myopt = pset.popt;
301 : : static const bool translate_columns[] = {false, false, false, false, true, true, true, false, true, false, false, false, false};
302 : :
303 : : /* No "Parallel" column before 9.6 */
304 : : static const bool translate_columns_pre_96[] = {false, false, false, false, true, true, false, true, false, false, false, false};
305 : :
2101 306 [ - + ]: 146 : if (strlen(functypes) != strspn(functypes, "anptwS+"))
307 : : {
1840 peter@eisentraut.org 308 :UBC 0 : pg_log_error("\\df only takes [anptwS+] as options");
2101 peter_e@gmx.net 309 : 0 : return true;
310 : : }
311 : :
2101 peter_e@gmx.net 312 [ + + - + ]:CBC 146 : if (showProcedure && pset.sversion < 110000)
313 : : {
314 : : char sverbuf[32];
315 : :
1840 peter@eisentraut.org 316 :UBC 0 : pg_log_error("\\df does not take a \"%c\" option with server version %s",
317 : : 'p',
318 : : formatPGVersionNumber(pset.sversion, false,
319 : : sverbuf, sizeof(sverbuf)));
5472 bruce@momjian.us 320 : 0 : return true;
321 : : }
322 : :
2101 peter_e@gmx.net 323 [ + + + + :CBC 146 : if (!showAggregate && !showNormal && !showProcedure && !showTrigger && !showWindow)
+ + + - +
- ]
324 : : {
850 tgl@sss.pgh.pa.us 325 : 137 : showAggregate = showNormal = showTrigger = showWindow = true;
2101 peter_e@gmx.net 326 [ + - ]: 137 : if (pset.sversion >= 110000)
327 : 137 : showProcedure = true;
328 : : }
329 : :
8026 330 : 146 : initPQExpBuffer(&buf);
331 : :
332 : 146 : printfPQExpBuffer(&buf,
333 : : "SELECT n.nspname as \"%s\",\n"
334 : : " p.proname as \"%s\",\n",
335 : : gettext_noop("Schema"),
336 : : gettext_noop("Name"));
337 : :
2235 338 [ + - ]: 146 : if (pset.sversion >= 110000)
339 : 146 : appendPQExpBuffer(&buf,
340 : : " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
341 : : " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
342 : : " CASE p.prokind\n"
343 : : " WHEN 'a' THEN '%s'\n"
344 : : " WHEN 'w' THEN '%s'\n"
345 : : " WHEN 'p' THEN '%s'\n"
346 : : " ELSE '%s'\n"
347 : : " END as \"%s\"",
348 : : gettext_noop("Result data type"),
349 : : gettext_noop("Argument data types"),
350 : : /* translator: "agg" is short for "aggregate" */
351 : : gettext_noop("agg"),
352 : : gettext_noop("window"),
353 : : gettext_noop("proc"),
354 : : gettext_noop("func"),
355 : : gettext_noop("Type"));
356 : : else
5749 tgl@sss.pgh.pa.us 357 :UBC 0 : appendPQExpBuffer(&buf,
358 : : " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
359 : : " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
360 : : " CASE\n"
361 : : " WHEN p.proisagg THEN '%s'\n"
362 : : " WHEN p.proiswindow THEN '%s'\n"
363 : : " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
364 : : " ELSE '%s'\n"
365 : : " END as \"%s\"",
366 : : gettext_noop("Result data type"),
367 : : gettext_noop("Argument data types"),
368 : : /* translator: "agg" is short for "aggregate" */
369 : : gettext_noop("agg"),
370 : : gettext_noop("window"),
371 : : gettext_noop("trigger"),
372 : : gettext_noop("func"),
373 : : gettext_noop("Type"));
374 : :
8768 bruce@momjian.us 375 [ + + ]:CBC 146 : if (verbose)
376 : : {
8026 peter_e@gmx.net 377 : 6 : appendPQExpBuffer(&buf,
378 : : ",\n CASE\n"
379 : : " WHEN p.provolatile = 'i' THEN '%s'\n"
380 : : " WHEN p.provolatile = 's' THEN '%s'\n"
381 : : " WHEN p.provolatile = 'v' THEN '%s'\n"
382 : : " END as \"%s\"",
383 : : gettext_noop("immutable"),
384 : : gettext_noop("stable"),
385 : : gettext_noop("volatile"),
386 : : gettext_noop("Volatility"));
2834 tgl@sss.pgh.pa.us 387 [ + - ]: 6 : if (pset.sversion >= 90600)
388 : 6 : appendPQExpBuffer(&buf,
389 : : ",\n CASE\n"
390 : : " WHEN p.proparallel = 'r' THEN '%s'\n"
391 : : " WHEN p.proparallel = 's' THEN '%s'\n"
392 : : " WHEN p.proparallel = 'u' THEN '%s'\n"
393 : : " END as \"%s\"",
394 : : gettext_noop("restricted"),
395 : : gettext_noop("safe"),
396 : : gettext_noop("unsafe"),
397 : : gettext_noop("Parallel"));
398 : 6 : appendPQExpBuffer(&buf,
399 : : ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\""
400 : : ",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\"",
401 : : gettext_noop("Owner"),
402 : : gettext_noop("definer"),
403 : : gettext_noop("invoker"),
404 : : gettext_noop("Security"));
405 : 6 : appendPQExpBufferStr(&buf, ",\n ");
406 : 6 : printACLColumn(&buf, "p.proacl");
407 : 6 : appendPQExpBuffer(&buf,
408 : : ",\n l.lanname as \"%s\"",
409 : : gettext_noop("Language"));
409 410 : 6 : appendPQExpBuffer(&buf,
411 : : ",\n CASE WHEN l.lanname IN ('internal', 'c') THEN p.prosrc END as \"%s\"",
412 : : gettext_noop("Internal name"));
1103 peter@eisentraut.org 413 : 6 : appendPQExpBuffer(&buf,
414 : : ",\n pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
415 : : gettext_noop("Description"));
416 : : }
417 : :
3800 heikki.linnakangas@i 418 : 146 : appendPQExpBufferStr(&buf,
419 : : "\nFROM pg_catalog.pg_proc p"
420 : : "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
421 : :
1103 tgl@sss.pgh.pa.us 422 [ + + ]: 179 : for (int i = 0; i < num_arg_patterns; i++)
423 : : {
424 : 33 : appendPQExpBuffer(&buf,
425 : : " LEFT JOIN pg_catalog.pg_type t%d ON t%d.oid = p.proargtypes[%d]\n"
426 : : " LEFT JOIN pg_catalog.pg_namespace nt%d ON nt%d.oid = t%d.typnamespace\n",
427 : : i, i, i, i, i, i);
428 : : }
429 : :
5764 430 [ + + ]: 146 : if (verbose)
3800 heikki.linnakangas@i 431 : 6 : appendPQExpBufferStr(&buf,
432 : : " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
433 : :
5458 tgl@sss.pgh.pa.us 434 : 146 : have_where = false;
435 : :
436 : : /* filter by function type, if requested */
2101 peter_e@gmx.net 437 [ + + + + : 146 : if (showNormal && showAggregate && showProcedure && showTrigger && showWindow)
+ - + - +
- ]
438 : : /* Do nothing */ ;
5472 bruce@momjian.us 439 [ + + ]: 9 : else if (showNormal)
440 : : {
441 [ + - ]: 3 : if (!showAggregate)
442 : : {
5458 tgl@sss.pgh.pa.us 443 [ - + ]: 3 : if (have_where)
3800 heikki.linnakangas@i 444 :UBC 0 : appendPQExpBufferStr(&buf, " AND ");
445 : : else
446 : : {
3800 heikki.linnakangas@i 447 :CBC 3 : appendPQExpBufferStr(&buf, "WHERE ");
5458 tgl@sss.pgh.pa.us 448 : 3 : have_where = true;
449 : : }
2235 peter_e@gmx.net 450 [ + - ]: 3 : if (pset.sversion >= 110000)
451 : 3 : appendPQExpBufferStr(&buf, "p.prokind <> 'a'\n");
452 : : else
2235 peter_e@gmx.net 453 :UBC 0 : appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
454 : : }
2101 peter_e@gmx.net 455 [ + - + - ]:CBC 3 : if (!showProcedure && pset.sversion >= 110000)
456 : : {
457 [ + - ]: 3 : if (have_where)
458 : 3 : appendPQExpBufferStr(&buf, " AND ");
459 : : else
460 : : {
2101 peter_e@gmx.net 461 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE ");
462 : 0 : have_where = true;
463 : : }
2101 peter_e@gmx.net 464 :CBC 3 : appendPQExpBufferStr(&buf, "p.prokind <> 'p'\n");
465 : : }
5472 bruce@momjian.us 466 [ + - ]: 3 : if (!showTrigger)
467 : : {
5458 tgl@sss.pgh.pa.us 468 [ + - ]: 3 : if (have_where)
3800 heikki.linnakangas@i 469 : 3 : appendPQExpBufferStr(&buf, " AND ");
470 : : else
471 : : {
3800 heikki.linnakangas@i 472 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE ");
5458 tgl@sss.pgh.pa.us 473 : 0 : have_where = true;
474 : : }
3800 heikki.linnakangas@i 475 :CBC 3 : appendPQExpBufferStr(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
476 : : }
850 tgl@sss.pgh.pa.us 477 [ + - ]: 3 : if (!showWindow)
478 : : {
5458 479 [ + - ]: 3 : if (have_where)
3800 heikki.linnakangas@i 480 : 3 : appendPQExpBufferStr(&buf, " AND ");
481 : : else
482 : : {
3800 heikki.linnakangas@i 483 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE ");
5458 tgl@sss.pgh.pa.us 484 : 0 : have_where = true;
485 : : }
2235 peter_e@gmx.net 486 [ + - ]:CBC 3 : if (pset.sversion >= 110000)
487 : 3 : appendPQExpBufferStr(&buf, "p.prokind <> 'w'\n");
488 : : else
2235 peter_e@gmx.net 489 :UBC 0 : appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
490 : : }
491 : : }
492 : : else
493 : : {
5421 bruce@momjian.us 494 :CBC 6 : bool needs_or = false;
495 : :
3800 heikki.linnakangas@i 496 : 6 : appendPQExpBufferStr(&buf, "WHERE (\n ");
5458 tgl@sss.pgh.pa.us 497 : 6 : have_where = true;
498 : : /* Note: at least one of these must be true ... */
5472 bruce@momjian.us 499 [ + + ]: 6 : if (showAggregate)
500 : : {
2235 peter_e@gmx.net 501 [ + - ]: 3 : if (pset.sversion >= 110000)
502 : 3 : appendPQExpBufferStr(&buf, "p.prokind = 'a'\n");
503 : : else
2235 peter_e@gmx.net 504 :UBC 0 : appendPQExpBufferStr(&buf, "p.proisagg\n");
5472 bruce@momjian.us 505 :CBC 3 : needs_or = true;
506 : : }
507 [ - + ]: 6 : if (showTrigger)
508 : : {
5472 bruce@momjian.us 509 [ # # ]:UBC 0 : if (needs_or)
3800 heikki.linnakangas@i 510 : 0 : appendPQExpBufferStr(&buf, " OR ");
511 : 0 : appendPQExpBufferStr(&buf,
512 : : "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n");
5472 bruce@momjian.us 513 : 0 : needs_or = true;
514 : : }
2101 peter_e@gmx.net 515 [ + + ]:CBC 6 : if (showProcedure)
516 : : {
517 [ - + ]: 3 : if (needs_or)
2101 peter_e@gmx.net 518 :UBC 0 : appendPQExpBufferStr(&buf, " OR ");
2101 peter_e@gmx.net 519 :CBC 3 : appendPQExpBufferStr(&buf, "p.prokind = 'p'\n");
520 : 3 : needs_or = true;
521 : : }
5472 bruce@momjian.us 522 [ - + ]: 6 : if (showWindow)
523 : : {
5472 bruce@momjian.us 524 [ # # ]:UBC 0 : if (needs_or)
3800 heikki.linnakangas@i 525 : 0 : appendPQExpBufferStr(&buf, " OR ");
2235 peter_e@gmx.net 526 [ # # ]: 0 : if (pset.sversion >= 110000)
527 : 0 : appendPQExpBufferStr(&buf, "p.prokind = 'w'\n");
528 : : else
529 : 0 : appendPQExpBufferStr(&buf, "p.proiswindow\n");
530 : : }
3800 heikki.linnakangas@i 531 :CBC 6 : appendPQExpBufferStr(&buf, " )\n");
532 : : }
533 : :
725 rhaas@postgresql.org 534 [ + + ]: 146 : if (!validateSQLNamePattern(&buf, func_pattern, have_where, false,
535 : : "n.nspname", "p.proname", NULL,
536 : : "pg_catalog.pg_function_is_visible(p.oid)",
537 : : NULL, 3))
633 michael@paquier.xyz 538 : 12 : goto error_return;
539 : :
1103 tgl@sss.pgh.pa.us 540 [ + + ]: 167 : for (int i = 0; i < num_arg_patterns; i++)
541 : : {
542 [ + + ]: 33 : if (strcmp(arg_patterns[i], "-") != 0)
543 : : {
544 : : /*
545 : : * Match type-name patterns against either internal or external
546 : : * name, like \dT. Unlike \dT, there seems no reason to
547 : : * discriminate against arrays or composite types.
548 : : */
549 : : char nspname[64];
550 : : char typname[64];
551 : : char ft[64];
552 : : char tiv[64];
553 : :
554 : 30 : snprintf(nspname, sizeof(nspname), "nt%d.nspname", i);
555 : 30 : snprintf(typname, sizeof(typname), "t%d.typname", i);
556 : 30 : snprintf(ft, sizeof(ft),
557 : : "pg_catalog.format_type(t%d.oid, NULL)", i);
558 : 30 : snprintf(tiv, sizeof(tiv),
559 : : "pg_catalog.pg_type_is_visible(t%d.oid)", i);
725 rhaas@postgresql.org 560 [ - + ]: 30 : if (!validateSQLNamePattern(&buf,
561 : 30 : map_typename_pattern(arg_patterns[i]),
562 : : true, false,
563 : : nspname, typname, ft, tiv,
564 : : NULL, 3))
633 michael@paquier.xyz 565 :UBC 0 : goto error_return;
566 : : }
567 : : else
568 : : {
569 : : /* "-" pattern specifies no such parameter */
1103 tgl@sss.pgh.pa.us 570 :CBC 3 : appendPQExpBuffer(&buf, " AND t%d.typname IS NULL\n", i);
571 : : }
572 : : }
573 : :
574 [ + - + + ]: 134 : if (!showSystem && !func_pattern)
3800 heikki.linnakangas@i 575 : 1 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
576 : : " AND n.nspname <> 'information_schema'\n");
577 : :
578 : 134 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
579 : :
3461 fujii@postgresql.org 580 : 134 : res = PSQLexec(buf.data);
8026 peter_e@gmx.net 581 : 134 : termPQExpBuffer(&buf);
8928 bruce@momjian.us 582 [ - + ]: 134 : if (!res)
8928 bruce@momjian.us 583 :UBC 0 : return false;
584 : :
8324 peter_e@gmx.net 585 :CBC 134 : myopt.title = _("List of functions");
5753 bruce@momjian.us 586 : 134 : myopt.translate_header = true;
2834 tgl@sss.pgh.pa.us 587 [ + - ]: 134 : if (pset.sversion >= 90600)
588 : : {
589 : 134 : myopt.translate_columns = translate_columns;
590 : 134 : myopt.n_translate_columns = lengthof(translate_columns);
591 : : }
592 : : else
593 : : {
2834 tgl@sss.pgh.pa.us 594 :UBC 0 : myopt.translate_columns = translate_columns_pre_96;
595 : 0 : myopt.n_translate_columns = lengthof(translate_columns_pre_96);
596 : : }
597 : :
3056 tgl@sss.pgh.pa.us 598 :CBC 134 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
599 : :
8928 bruce@momjian.us 600 : 134 : PQclear(res);
601 : 134 : return true;
602 : :
633 michael@paquier.xyz 603 : 12 : error_return:
604 : 12 : termPQExpBuffer(&buf);
605 : 12 : return false;
606 : : }
607 : :
608 : :
609 : :
610 : : /*
611 : : * \dT
612 : : * describe types
613 : : */
614 : : bool
5577 bruce@momjian.us 615 : 34 : describeTypes(const char *pattern, bool verbose, bool showSystem)
616 : : {
617 : : PQExpBufferData buf;
618 : : PGresult *res;
8857 peter_e@gmx.net 619 : 34 : printQueryOpt myopt = pset.popt;
620 : :
8026 621 : 34 : initPQExpBuffer(&buf);
622 : :
623 : 34 : printfPQExpBuffer(&buf,
624 : : "SELECT n.nspname as \"%s\",\n"
625 : : " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
626 : : gettext_noop("Schema"),
627 : : gettext_noop("Name"));
8768 bruce@momjian.us 628 [ + + ]: 34 : if (verbose)
629 : : {
8026 peter_e@gmx.net 630 :GBC 6 : appendPQExpBuffer(&buf,
631 : : " t.typname AS \"%s\",\n"
632 : : " CASE WHEN t.typrelid != 0\n"
633 : : " THEN CAST('tuple' AS pg_catalog.text)\n"
634 : : " WHEN t.typlen < 0\n"
635 : : " THEN CAST('var' AS pg_catalog.text)\n"
636 : : " ELSE CAST(t.typlen AS pg_catalog.text)\n"
637 : : " END AS \"%s\",\n"
638 : : " pg_catalog.array_to_string(\n"
639 : : " ARRAY(\n"
640 : : " SELECT e.enumlabel\n"
641 : : " FROM pg_catalog.pg_enum e\n"
642 : : " WHERE e.enumtypid = t.oid\n"
643 : : " ORDER BY e.enumsortorder\n"
644 : : " ),\n"
645 : : " E'\\n'\n"
646 : : " ) AS \"%s\",\n"
647 : : " pg_catalog.pg_get_userbyid(t.typowner) AS \"%s\",\n",
648 : : gettext_noop("Internal name"),
649 : : gettext_noop("Size"),
650 : : gettext_noop("Elements"),
651 : : gettext_noop("Owner"));
4499 652 : 6 : printACLColumn(&buf, "t.typacl");
3800 heikki.linnakangas@i 653 : 6 : appendPQExpBufferStr(&buf, ",\n ");
654 : : }
655 : :
8026 peter_e@gmx.net 656 :CBC 34 : appendPQExpBuffer(&buf,
657 : : " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
658 : : gettext_noop("Description"));
659 : :
3800 heikki.linnakangas@i 660 : 34 : appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_type t\n"
661 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
662 : :
663 : : /*
664 : : * do not include complex types (typrelid!=0) unless they are standalone
665 : : * composite types
666 : : */
667 : 34 : appendPQExpBufferStr(&buf, "WHERE (t.typrelid = 0 ");
2593 tgl@sss.pgh.pa.us 668 : 34 : appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
669 : : " FROM pg_catalog.pg_class c "
670 : : "WHERE c.oid = t.typrelid))\n");
671 : :
672 : : /*
673 : : * do not include array types unless the pattern contains []
674 : : */
1103 675 [ + + + - ]: 34 : if (pattern == NULL || strstr(pattern, "[]") == NULL)
850 676 : 34 : appendPQExpBufferStr(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
677 : :
5421 bruce@momjian.us 678 [ + - + + ]: 34 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 679 : 3 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
680 : : " AND n.nspname <> 'information_schema'\n");
681 : :
682 : : /* Match name pattern against either internal or external name */
725 rhaas@postgresql.org 683 [ + + ]: 34 : if (!validateSQLNamePattern(&buf, map_typename_pattern(pattern),
684 : : true, false,
685 : : "n.nspname", "t.typname",
686 : : "pg_catalog.format_type(t.oid, NULL)",
687 : : "pg_catalog.pg_type_is_visible(t.oid)",
688 : : NULL, 3))
689 : : {
633 michael@paquier.xyz 690 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 691 : 12 : return false;
692 : : }
693 : :
3800 heikki.linnakangas@i 694 : 22 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
695 : :
3461 fujii@postgresql.org 696 : 22 : res = PSQLexec(buf.data);
8026 peter_e@gmx.net 697 : 22 : termPQExpBuffer(&buf);
8928 bruce@momjian.us 698 [ - + ]: 22 : if (!res)
8928 bruce@momjian.us 699 :UBC 0 : return false;
700 : :
8324 peter_e@gmx.net 701 :CBC 22 : myopt.title = _("List of data types");
5753 bruce@momjian.us 702 : 22 : myopt.translate_header = true;
703 : :
3056 tgl@sss.pgh.pa.us 704 : 22 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
705 : :
8928 bruce@momjian.us 706 : 22 : PQclear(res);
707 : 22 : return true;
708 : : }
709 : :
710 : : /*
711 : : * Map some variant type names accepted by the backend grammar into
712 : : * canonical type names.
713 : : *
714 : : * Helper for \dT and other functions that take typename patterns.
715 : : * This doesn't completely mask the fact that these names are special;
716 : : * for example, a pattern of "dec*" won't magically match "numeric".
717 : : * But it goes a long way to reduce the surprise factor.
718 : : */
719 : : static const char *
1103 tgl@sss.pgh.pa.us 720 : 73 : map_typename_pattern(const char *pattern)
721 : : {
722 : : static const char *const typename_map[] = {
723 : : /*
724 : : * These names are accepted by gram.y, although they are neither the
725 : : * "real" name seen in pg_type nor the canonical name printed by
726 : : * format_type().
727 : : */
728 : : "decimal", "numeric",
729 : : "float", "double precision",
730 : : "int", "integer",
731 : :
732 : : /*
733 : : * We also have to map the array names for cases where the canonical
734 : : * name is different from what pg_type says.
735 : : */
736 : : "bool[]", "boolean[]",
737 : : "decimal[]", "numeric[]",
738 : : "float[]", "double precision[]",
739 : : "float4[]", "real[]",
740 : : "float8[]", "double precision[]",
741 : : "int[]", "integer[]",
742 : : "int2[]", "smallint[]",
743 : : "int4[]", "integer[]",
744 : : "int8[]", "bigint[]",
745 : : "time[]", "time without time zone[]",
746 : : "timetz[]", "time with time zone[]",
747 : : "timestamp[]", "timestamp without time zone[]",
748 : : "timestamptz[]", "timestamp with time zone[]",
749 : : "varbit[]", "bit varying[]",
750 : : "varchar[]", "character varying[]",
751 : : NULL
752 : : };
753 : :
754 [ + + ]: 73 : if (pattern == NULL)
755 : 3 : return NULL;
756 [ + + ]: 1330 : for (int i = 0; typename_map[i] != NULL; i += 2)
757 : : {
758 [ - + ]: 1260 : if (pg_strcasecmp(pattern, typename_map[i]) == 0)
1103 tgl@sss.pgh.pa.us 759 :UBC 0 : return typename_map[i + 1];
760 : : }
1103 tgl@sss.pgh.pa.us 761 :CBC 70 : return pattern;
762 : : }
763 : :
764 : :
765 : : /*
766 : : * \do
767 : : * Describe operators
768 : : */
769 : : bool
770 : 31 : describeOperators(const char *oper_pattern,
771 : : char **arg_patterns, int num_arg_patterns,
772 : : bool verbose, bool showSystem)
773 : : {
774 : : PQExpBufferData buf;
775 : : PGresult *res;
8857 peter_e@gmx.net 776 : 31 : printQueryOpt myopt = pset.popt;
777 : :
8026 778 : 31 : initPQExpBuffer(&buf);
779 : :
780 : : /*
781 : : * Note: before Postgres 9.1, we did not assign comments to any built-in
782 : : * operators, preferring to let the comment on the underlying function
783 : : * suffice. The coalesce() on the obj_description() calls below supports
784 : : * this convention by providing a fallback lookup of a comment on the
785 : : * operator's function. Since 9.1 there is a policy that every built-in
786 : : * operator should have a comment; so the coalesce() is no longer
787 : : * necessary so far as built-in operators are concerned. We keep it
788 : : * anyway, for now, because third-party modules may still be following the
789 : : * old convention.
790 : : *
791 : : * The support for postfix operators in this query is dead code as of
792 : : * Postgres 14, but we need to keep it for as long as we support talking
793 : : * to pre-v14 servers.
794 : : */
795 : :
796 : 31 : printfPQExpBuffer(&buf,
797 : : "SELECT n.nspname as \"%s\",\n"
798 : : " o.oprname AS \"%s\",\n"
799 : : " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
800 : : " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
801 : : " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
802 : : gettext_noop("Schema"),
803 : : gettext_noop("Name"),
804 : : gettext_noop("Left arg type"),
805 : : gettext_noop("Right arg type"),
806 : : gettext_noop("Result type"));
807 : :
3741 tgl@sss.pgh.pa.us 808 [ - + ]: 31 : if (verbose)
3741 tgl@sss.pgh.pa.us 809 :UBC 0 : appendPQExpBuffer(&buf,
810 : : " o.oprcode AS \"%s\",\n",
811 : : gettext_noop("Function"));
812 : :
3741 tgl@sss.pgh.pa.us 813 :CBC 31 : appendPQExpBuffer(&buf,
814 : : " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
815 : : " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
816 : : "FROM pg_catalog.pg_operator o\n"
817 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
818 : : gettext_noop("Description"));
819 : :
1103 820 [ + + ]: 31 : if (num_arg_patterns >= 2)
821 : : {
822 : 3 : num_arg_patterns = 2; /* ignore any additional arguments */
823 : 3 : appendPQExpBufferStr(&buf,
824 : : " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprleft\n"
825 : : " LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n"
826 : : " LEFT JOIN pg_catalog.pg_type t1 ON t1.oid = o.oprright\n"
827 : : " LEFT JOIN pg_catalog.pg_namespace nt1 ON nt1.oid = t1.typnamespace\n");
828 : : }
829 [ + + ]: 28 : else if (num_arg_patterns == 1)
830 : : {
831 : 3 : appendPQExpBufferStr(&buf,
832 : : " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprright\n"
833 : : " LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n");
834 : : }
835 : :
836 [ + - + + ]: 31 : if (!showSystem && !oper_pattern)
3800 heikki.linnakangas@i 837 : 1 : appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
838 : : " AND n.nspname <> 'information_schema'\n");
839 : :
725 rhaas@postgresql.org 840 [ + + ]: 31 : if (!validateSQLNamePattern(&buf, oper_pattern,
841 [ + - + + ]: 31 : !showSystem && !oper_pattern, true,
842 : : "n.nspname", "o.oprname", NULL,
843 : : "pg_catalog.pg_operator_is_visible(o.oid)",
725 rhaas@postgresql.org 844 :ECB (31) : NULL, 3))
633 michael@paquier.xyz 845 :CBC 12 : goto error_return;
846 : :
1103 tgl@sss.pgh.pa.us 847 [ + + ]: 19 : if (num_arg_patterns == 1)
848 : 3 : appendPQExpBufferStr(&buf, " AND o.oprleft = 0\n");
849 : :
850 [ + + ]: 28 : for (int i = 0; i < num_arg_patterns; i++)
851 : : {
852 [ + - ]: 9 : if (strcmp(arg_patterns[i], "-") != 0)
853 : : {
854 : : /*
855 : : * Match type-name patterns against either internal or external
856 : : * name, like \dT. Unlike \dT, there seems no reason to
857 : : * discriminate against arrays or composite types.
858 : : */
859 : : char nspname[64];
860 : : char typname[64];
861 : : char ft[64];
862 : : char tiv[64];
863 : :
864 : 9 : snprintf(nspname, sizeof(nspname), "nt%d.nspname", i);
865 : 9 : snprintf(typname, sizeof(typname), "t%d.typname", i);
866 : 9 : snprintf(ft, sizeof(ft),
867 : : "pg_catalog.format_type(t%d.oid, NULL)", i);
868 : 9 : snprintf(tiv, sizeof(tiv),
869 : : "pg_catalog.pg_type_is_visible(t%d.oid)", i);
725 rhaas@postgresql.org 870 [ - + ]: 9 : if (!validateSQLNamePattern(&buf,
871 : 9 : map_typename_pattern(arg_patterns[i]),
872 : : true, false,
873 : : nspname, typname, ft, tiv,
874 : : NULL, 3))
633 michael@paquier.xyz 875 :UBC 0 : goto error_return;
876 : : }
877 : : else
878 : : {
879 : : /* "-" pattern specifies no such parameter */
1103 tgl@sss.pgh.pa.us 880 : 0 : appendPQExpBuffer(&buf, " AND t%d.typname IS NULL\n", i);
881 : : }
882 : : }
883 : :
3800 heikki.linnakangas@i 884 :CBC 19 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4;");
885 : :
3461 fujii@postgresql.org 886 : 19 : res = PSQLexec(buf.data);
8026 peter_e@gmx.net 887 : 19 : termPQExpBuffer(&buf);
8928 bruce@momjian.us 888 [ - + ]: 19 : if (!res)
8928 bruce@momjian.us 889 :UBC 0 : return false;
890 : :
8324 peter_e@gmx.net 891 :CBC 19 : myopt.title = _("List of operators");
5753 bruce@momjian.us 892 : 19 : myopt.translate_header = true;
893 : :
3056 tgl@sss.pgh.pa.us 894 : 19 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
895 : :
8928 bruce@momjian.us 896 : 19 : PQclear(res);
897 : 19 : return true;
898 : :
633 michael@paquier.xyz 899 : 12 : error_return:
900 : 12 : termPQExpBuffer(&buf);
901 : 12 : return false;
902 : : }
903 : :
904 : :
905 : : /*
906 : : * listAllDbs
907 : : *
908 : : * for \l, \list, and -l switch
909 : : */
910 : : bool
4060 peter_e@gmx.net 911 :UBC 0 : listAllDbs(const char *pattern, bool verbose)
912 : : {
913 : : PGresult *res;
914 : : PQExpBufferData buf;
8857 915 : 0 : printQueryOpt myopt = pset.popt;
916 : :
8026 917 : 0 : initPQExpBuffer(&buf);
918 : :
919 : 0 : printfPQExpBuffer(&buf,
920 : : "SELECT\n"
921 : : " d.datname as \"%s\",\n"
922 : : " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
923 : : " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
924 : : gettext_noop("Name"),
925 : : gettext_noop("Owner"),
926 : : gettext_noop("Encoding"));
759 peter@eisentraut.org 927 [ # # ]: 0 : if (pset.sversion >= 150000)
928 : 0 : appendPQExpBuffer(&buf,
929 : : " CASE d.datlocprovider WHEN 'b' THEN 'builtin' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"%s\",\n",
930 : : gettext_noop("Locale Provider"));
931 : : else
932 : 0 : appendPQExpBuffer(&buf,
933 : : " 'libc' AS \"%s\",\n",
934 : : gettext_noop("Locale Provider"));
403 935 : 0 : appendPQExpBuffer(&buf,
936 : : " d.datcollate as \"%s\",\n"
937 : : " d.datctype as \"%s\",\n",
938 : : gettext_noop("Collate"),
939 : : gettext_noop("Ctype"));
36 jdavis@postgresql.or 940 [ # # ]:UNC 0 : if (pset.sversion >= 170000)
941 : 0 : appendPQExpBuffer(&buf,
942 : : " d.datlocale as \"%s\",\n",
943 : : gettext_noop("Locale"));
944 [ # # ]: 0 : else if (pset.sversion >= 150000)
403 peter@eisentraut.org 945 :UBC 0 : appendPQExpBuffer(&buf,
946 : : " d.daticulocale as \"%s\",\n",
947 : : gettext_noop("Locale"));
948 : : else
949 : 0 : appendPQExpBuffer(&buf,
950 : : " NULL as \"%s\",\n",
951 : : gettext_noop("Locale"));
952 [ # # ]: 0 : if (pset.sversion >= 160000)
953 : 0 : appendPQExpBuffer(&buf,
954 : : " d.daticurules as \"%s\",\n",
955 : : gettext_noop("ICU Rules"));
956 : : else
957 : 0 : appendPQExpBuffer(&buf,
958 : : " NULL as \"%s\",\n",
959 : : gettext_noop("ICU Rules"));
960 : 0 : appendPQExpBufferStr(&buf, " ");
5583 tgl@sss.pgh.pa.us 961 : 0 : printACLColumn(&buf, "d.datacl");
850 962 [ # # ]: 0 : if (verbose)
5859 963 : 0 : appendPQExpBuffer(&buf,
964 : : ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
965 : : " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
966 : : " ELSE 'No Access'\n"
967 : : " END as \"%s\""
968 : : ",\n t.spcname as \"%s\""
969 : : ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
970 : : gettext_noop("Size"),
971 : : gettext_noop("Tablespace"),
972 : : gettext_noop("Description"));
3800 heikki.linnakangas@i 973 : 0 : appendPQExpBufferStr(&buf,
974 : : "\nFROM pg_catalog.pg_database d\n");
850 tgl@sss.pgh.pa.us 975 [ # # ]: 0 : if (verbose)
3800 heikki.linnakangas@i 976 : 0 : appendPQExpBufferStr(&buf,
977 : : " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
978 : :
4060 peter_e@gmx.net 979 [ # # ]: 0 : if (pattern)
980 : : {
725 rhaas@postgresql.org 981 [ # # ]: 0 : if (!validateSQLNamePattern(&buf, pattern, false, false,
982 : : NULL, "d.datname", NULL, NULL,
983 : : NULL, 1))
984 : : {
633 michael@paquier.xyz 985 : 0 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 986 : 0 : return false;
987 : : }
988 : : }
989 : :
3800 heikki.linnakangas@i 990 : 0 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
3461 fujii@postgresql.org 991 : 0 : res = PSQLexec(buf.data);
8026 peter_e@gmx.net 992 : 0 : termPQExpBuffer(&buf);
8928 bruce@momjian.us 993 [ # # ]: 0 : if (!res)
994 : 0 : return false;
995 : :
8324 peter_e@gmx.net 996 : 0 : myopt.title = _("List of databases");
5753 bruce@momjian.us 997 : 0 : myopt.translate_header = true;
998 : :
3056 tgl@sss.pgh.pa.us 999 : 0 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1000 : :
8928 bruce@momjian.us 1001 : 0 : PQclear(res);
1002 : 0 : return true;
1003 : : }
1004 : :
1005 : :
1006 : : /*
1007 : : * List Tables' Grant/Revoke Permissions
1008 : : * \z (now also \dp -- perhaps more mnemonic)
1009 : : */
1010 : : bool
463 dean.a.rasheed@gmail 1011 :CBC 45 : permissionsList(const char *pattern, bool showSystem)
1012 : : {
1013 : : PQExpBufferData buf;
1014 : : PGresult *res;
8857 peter_e@gmx.net 1015 : 45 : printQueryOpt myopt = pset.popt;
1016 : : static const bool translate_columns[] = {false, false, true, false, false, false};
1017 : :
8026 1018 : 45 : initPQExpBuffer(&buf);
1019 : :
1020 : : /*
1021 : : * we ignore indexes and toast tables since they have no meaningful rights
1022 : : */
1023 : 45 : printfPQExpBuffer(&buf,
1024 : : "SELECT n.nspname as \"%s\",\n"
1025 : : " c.relname as \"%s\",\n"
1026 : : " CASE c.relkind"
1027 : : " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
1028 : : " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
1029 : : " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
1030 : : " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
1031 : : " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
1032 : : " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
1033 : : " END as \"%s\",\n"
1034 : : " ",
1035 : : gettext_noop("Schema"),
1036 : : gettext_noop("Name"),
1037 : : gettext_noop("table"),
1038 : : gettext_noop("view"),
1039 : : gettext_noop("materialized view"),
1040 : : gettext_noop("sequence"),
1041 : : gettext_noop("foreign table"),
1042 : : gettext_noop("partitioned table"),
1043 : : gettext_noop("Type"));
1044 : :
5583 tgl@sss.pgh.pa.us 1045 : 45 : printACLColumn(&buf, "c.relacl");
1046 : :
1047 : : /*
1048 : : * The formatting of attacl should match printACLColumn(). However, we
1049 : : * need no special case for an empty attacl, because the backend always
1050 : : * optimizes that back to NULL.
1051 : : */
850 1052 : 45 : appendPQExpBuffer(&buf,
1053 : : ",\n pg_catalog.array_to_string(ARRAY(\n"
1054 : : " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
1055 : : " FROM pg_catalog.pg_attribute a\n"
1056 : : " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
1057 : : " ), E'\\n') AS \"%s\"",
1058 : : gettext_noop("Column privileges"));
1059 : :
2687 sfrost@snowman.net 1060 [ + - - + ]: 45 : if (pset.sversion >= 90500 && pset.sversion < 100000)
2687 sfrost@snowman.net 1061 :UBC 0 : appendPQExpBuffer(&buf,
1062 : : ",\n pg_catalog.array_to_string(ARRAY(\n"
1063 : : " SELECT polname\n"
1064 : : " || CASE WHEN polcmd != '*' THEN\n"
1065 : : " E' (' || polcmd::pg_catalog.text || E'):'\n"
1066 : : " ELSE E':'\n"
1067 : : " END\n"
1068 : : " || CASE WHEN polqual IS NOT NULL THEN\n"
1069 : : " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
1070 : : " ELSE E''\n"
1071 : : " END\n"
1072 : : " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
1073 : : " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
1074 : : " ELSE E''\n"
1075 : : " END"
1076 : : " || CASE WHEN polroles <> '{0}' THEN\n"
1077 : : " E'\\n to: ' || pg_catalog.array_to_string(\n"
1078 : : " ARRAY(\n"
1079 : : " SELECT rolname\n"
1080 : : " FROM pg_catalog.pg_roles\n"
1081 : : " WHERE oid = ANY (polroles)\n"
1082 : : " ORDER BY 1\n"
1083 : : " ), E', ')\n"
1084 : : " ELSE E''\n"
1085 : : " END\n"
1086 : : " FROM pg_catalog.pg_policy pol\n"
1087 : : " WHERE polrelid = c.oid), E'\\n')\n"
1088 : : " AS \"%s\"",
1089 : : gettext_noop("Policies"));
1090 : :
2687 sfrost@snowman.net 1091 [ + - ]:CBC 45 : if (pset.sversion >= 100000)
3495 1092 : 45 : appendPQExpBuffer(&buf,
1093 : : ",\n pg_catalog.array_to_string(ARRAY(\n"
1094 : : " SELECT polname\n"
1095 : : " || CASE WHEN NOT polpermissive THEN\n"
1096 : : " E' (RESTRICTIVE)'\n"
1097 : : " ELSE '' END\n"
1098 : : " || CASE WHEN polcmd != '*' THEN\n"
1099 : : " E' (' || polcmd::pg_catalog.text || E'):'\n"
1100 : : " ELSE E':'\n"
1101 : : " END\n"
1102 : : " || CASE WHEN polqual IS NOT NULL THEN\n"
1103 : : " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n"
1104 : : " ELSE E''\n"
1105 : : " END\n"
1106 : : " || CASE WHEN polwithcheck IS NOT NULL THEN\n"
1107 : : " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n"
1108 : : " ELSE E''\n"
1109 : : " END"
1110 : : " || CASE WHEN polroles <> '{0}' THEN\n"
1111 : : " E'\\n to: ' || pg_catalog.array_to_string(\n"
1112 : : " ARRAY(\n"
1113 : : " SELECT rolname\n"
1114 : : " FROM pg_catalog.pg_roles\n"
1115 : : " WHERE oid = ANY (polroles)\n"
1116 : : " ORDER BY 1\n"
1117 : : " ), E', ')\n"
1118 : : " ELSE E''\n"
1119 : : " END\n"
1120 : : " FROM pg_catalog.pg_policy pol\n"
1121 : : " WHERE polrelid = c.oid), E'\\n')\n"
1122 : : " AS \"%s\"",
1123 : : gettext_noop("Policies"));
1124 : :
3800 heikki.linnakangas@i 1125 : 45 : appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_class c\n"
1126 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
1127 : : "WHERE c.relkind IN ("
1128 : : CppAsString2(RELKIND_RELATION) ","
1129 : : CppAsString2(RELKIND_VIEW) ","
1130 : : CppAsString2(RELKIND_MATVIEW) ","
1131 : : CppAsString2(RELKIND_SEQUENCE) ","
1132 : : CppAsString2(RELKIND_FOREIGN_TABLE) ","
1133 : : CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
1134 : :
463 dean.a.rasheed@gmail 1135 [ + - + + ]: 45 : if (!showSystem && !pattern)
1136 : 3 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1137 : : " AND n.nspname <> 'information_schema'\n");
1138 : :
725 rhaas@postgresql.org 1139 [ + + ]: 45 : if (!validateSQLNamePattern(&buf, pattern, true, false,
1140 : : "n.nspname", "c.relname", NULL,
1141 : : "pg_catalog.pg_table_is_visible(c.oid)",
1142 : : NULL, 3))
633 michael@paquier.xyz 1143 : 12 : goto error_return;
1144 : :
3800 heikki.linnakangas@i 1145 : 33 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
1146 : :
3461 fujii@postgresql.org 1147 : 33 : res = PSQLexec(buf.data);
8928 bruce@momjian.us 1148 [ - + ]: 33 : if (!res)
633 michael@paquier.xyz 1149 :UBC 0 : goto error_return;
1150 : :
5764 peter_e@gmx.net 1151 :CBC 33 : printfPQExpBuffer(&buf, _("Access privileges"));
8026 1152 : 33 : myopt.title = buf.data;
5753 bruce@momjian.us 1153 : 33 : myopt.translate_header = true;
1154 : 33 : myopt.translate_columns = translate_columns;
3753 tgl@sss.pgh.pa.us 1155 : 33 : myopt.n_translate_columns = lengthof(translate_columns);
1156 : :
3056 1157 : 33 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1158 : :
8026 peter_e@gmx.net 1159 : 33 : termPQExpBuffer(&buf);
8928 bruce@momjian.us 1160 : 33 : PQclear(res);
1161 : 33 : return true;
1162 : :
633 michael@paquier.xyz 1163 : 12 : error_return:
331 tgl@sss.pgh.pa.us 1164 : 12 : termPQExpBuffer(&buf);
1165 : 12 : return false;
1166 : : }
1167 : :
1168 : :
1169 : : /*
1170 : : * \ddp
1171 : : *
1172 : : * List Default ACLs. The pattern can match either schema or role name.
1173 : : */
1174 : : bool
5305 1175 : 18 : listDefaultACLs(const char *pattern)
1176 : : {
1177 : : PQExpBufferData buf;
1178 : : PGresult *res;
1179 : 18 : printQueryOpt myopt = pset.popt;
1180 : : static const bool translate_columns[] = {false, false, true, false};
1181 : :
1182 : 18 : initPQExpBuffer(&buf);
1183 : :
1184 : 18 : printfPQExpBuffer(&buf,
1185 : : "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
1186 : : " n.nspname AS \"%s\",\n"
1187 : : " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
1188 : : " ",
1189 : : gettext_noop("Owner"),
1190 : : gettext_noop("Schema"),
1191 : : DEFACLOBJ_RELATION,
1192 : : gettext_noop("table"),
1193 : : DEFACLOBJ_SEQUENCE,
1194 : : gettext_noop("sequence"),
1195 : : DEFACLOBJ_FUNCTION,
1196 : : gettext_noop("function"),
1197 : : DEFACLOBJ_TYPE,
1198 : : gettext_noop("type"),
1199 : : DEFACLOBJ_NAMESPACE,
1200 : : gettext_noop("schema"),
1201 : : gettext_noop("Type"));
1202 : :
1203 : 18 : printACLColumn(&buf, "d.defaclacl");
1204 : :
3800 heikki.linnakangas@i 1205 : 18 : appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
1206 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
1207 : :
725 rhaas@postgresql.org 1208 [ + + ]: 18 : if (!validateSQLNamePattern(&buf, pattern, false, false,
1209 : : NULL,
1210 : : "n.nspname",
1211 : : "pg_catalog.pg_get_userbyid(d.defaclrole)",
1212 : : NULL,
1213 : : NULL, 3))
633 michael@paquier.xyz 1214 : 12 : goto error_return;
1215 : :
3800 heikki.linnakangas@i 1216 : 6 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1217 : :
3461 fujii@postgresql.org 1218 : 6 : res = PSQLexec(buf.data);
5305 tgl@sss.pgh.pa.us 1219 [ - + ]: 6 : if (!res)
633 michael@paquier.xyz 1220 :UBC 0 : goto error_return;
1221 : :
5305 tgl@sss.pgh.pa.us 1222 :CBC 6 : printfPQExpBuffer(&buf, _("Default access privileges"));
1223 : 6 : myopt.title = buf.data;
1224 : 6 : myopt.translate_header = true;
1225 : 6 : myopt.translate_columns = translate_columns;
3753 1226 : 6 : myopt.n_translate_columns = lengthof(translate_columns);
1227 : :
3056 1228 : 6 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1229 : :
5305 1230 : 6 : termPQExpBuffer(&buf);
1231 : 6 : PQclear(res);
1232 : 6 : return true;
1233 : :
633 michael@paquier.xyz 1234 : 12 : error_return:
1235 : 12 : termPQExpBuffer(&buf);
1236 : 12 : return false;
1237 : : }
1238 : :
1239 : :
1240 : : /*
1241 : : * Get object comments
1242 : : *
1243 : : * \dd [foo]
1244 : : *
1245 : : * Note: This command only lists comments for object types which do not have
1246 : : * their comments displayed by their own backslash commands. The following
1247 : : * types of objects will be displayed: constraint, operator class,
1248 : : * operator family, rule, and trigger.
1249 : : *
1250 : : */
1251 : : bool
5577 bruce@momjian.us 1252 : 21 : objectDescription(const char *pattern, bool showSystem)
1253 : : {
1254 : : PQExpBufferData buf;
1255 : : PGresult *res;
8857 peter_e@gmx.net 1256 : 21 : printQueryOpt myopt = pset.popt;
1257 : : static const bool translate_columns[] = {false, false, true, false};
1258 : :
8026 1259 : 21 : initPQExpBuffer(&buf);
1260 : :
7918 tgl@sss.pgh.pa.us 1261 : 21 : appendPQExpBuffer(&buf,
1262 : : "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
1263 : : "FROM (\n",
1264 : : gettext_noop("Schema"),
1265 : : gettext_noop("Name"),
1266 : : gettext_noop("Object"),
1267 : : gettext_noop("Description"));
1268 : :
1269 : : /* Table constraint descriptions */
1270 : 21 : appendPQExpBuffer(&buf,
1271 : : " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1272 : : " n.nspname as nspname,\n"
1273 : : " CAST(pgc.conname AS pg_catalog.text) as name,"
1274 : : " CAST('%s' AS pg_catalog.text) as object\n"
1275 : : " FROM pg_catalog.pg_constraint pgc\n"
1276 : : " JOIN pg_catalog.pg_class c "
1277 : : "ON c.oid = pgc.conrelid\n"
1278 : : " LEFT JOIN pg_catalog.pg_namespace n "
1279 : : " ON n.oid = c.relnamespace\n",
1280 : : gettext_noop("table constraint"));
1281 : :
5421 bruce@momjian.us 1282 [ + - - + ]: 21 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 1283 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1284 : : " AND n.nspname <> 'information_schema'\n");
1285 : :
725 rhaas@postgresql.org 1286 [ + - - + :CBC 21 : if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern,
+ + ]
1287 : : false, "n.nspname", "pgc.conname", NULL,
1288 : : "pg_catalog.pg_table_is_visible(c.oid)",
725 rhaas@postgresql.org 1289 :ECB (21) : NULL, 3))
633 michael@paquier.xyz 1290 :CBC 12 : goto error_return;
1291 : :
1292 : : /* Domain constraint descriptions */
3400 alvherre@alvh.no-ip. 1293 : 9 : appendPQExpBuffer(&buf,
1294 : : "UNION ALL\n"
1295 : : " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
1296 : : " n.nspname as nspname,\n"
1297 : : " CAST(pgc.conname AS pg_catalog.text) as name,"
1298 : : " CAST('%s' AS pg_catalog.text) as object\n"
1299 : : " FROM pg_catalog.pg_constraint pgc\n"
1300 : : " JOIN pg_catalog.pg_type t "
1301 : : "ON t.oid = pgc.contypid\n"
1302 : : " LEFT JOIN pg_catalog.pg_namespace n "
1303 : : " ON n.oid = t.typnamespace\n",
1304 : : gettext_noop("domain constraint"));
1305 : :
1306 [ + - - + ]: 9 : if (!showSystem && !pattern)
3400 alvherre@alvh.no-ip. 1307 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1308 : : " AND n.nspname <> 'information_schema'\n");
1309 : :
725 rhaas@postgresql.org 1310 [ + - - + :CBC 9 : if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern,
- + ]
1311 : : false, "n.nspname", "pgc.conname", NULL,
1312 : : "pg_catalog.pg_type_is_visible(t.oid)",
725 rhaas@postgresql.org 1313 :ECB (9) : NULL, 3))
633 michael@paquier.xyz 1314 :UBC 0 : goto error_return;
1315 : :
1316 : : /* Operator class descriptions */
850 tgl@sss.pgh.pa.us 1317 :CBC 9 : appendPQExpBuffer(&buf,
1318 : : "UNION ALL\n"
1319 : : " SELECT o.oid as oid, o.tableoid as tableoid,\n"
1320 : : " n.nspname as nspname,\n"
1321 : : " CAST(o.opcname AS pg_catalog.text) as name,\n"
1322 : : " CAST('%s' AS pg_catalog.text) as object\n"
1323 : : " FROM pg_catalog.pg_opclass o\n"
1324 : : " JOIN pg_catalog.pg_am am ON "
1325 : : "o.opcmethod = am.oid\n"
1326 : : " JOIN pg_catalog.pg_namespace n ON "
1327 : : "n.oid = o.opcnamespace\n",
1328 : : gettext_noop("operator class"));
1329 : :
1330 [ + - - + ]: 9 : if (!showSystem && !pattern)
850 tgl@sss.pgh.pa.us 1331 :UBC 0 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1332 : : " AND n.nspname <> 'information_schema'\n");
1333 : :
725 rhaas@postgresql.org 1334 [ - + ]:CBC 9 : if (!validateSQLNamePattern(&buf, pattern, true, false,
1335 : : "n.nspname", "o.opcname", NULL,
1336 : : "pg_catalog.pg_opclass_is_visible(o.oid)",
1337 : : NULL, 3))
633 michael@paquier.xyz 1338 :UBC 0 : goto error_return;
1339 : :
1340 : : /* Operator family descriptions */
850 tgl@sss.pgh.pa.us 1341 :CBC 9 : appendPQExpBuffer(&buf,
1342 : : "UNION ALL\n"
1343 : : " SELECT opf.oid as oid, opf.tableoid as tableoid,\n"
1344 : : " n.nspname as nspname,\n"
1345 : : " CAST(opf.opfname AS pg_catalog.text) AS name,\n"
1346 : : " CAST('%s' AS pg_catalog.text) as object\n"
1347 : : " FROM pg_catalog.pg_opfamily opf\n"
1348 : : " JOIN pg_catalog.pg_am am "
1349 : : "ON opf.opfmethod = am.oid\n"
1350 : : " JOIN pg_catalog.pg_namespace n "
1351 : : "ON opf.opfnamespace = n.oid\n",
1352 : : gettext_noop("operator family"));
1353 : :
1354 [ + - - + ]: 9 : if (!showSystem && !pattern)
850 tgl@sss.pgh.pa.us 1355 :UBC 0 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1356 : : " AND n.nspname <> 'information_schema'\n");
1357 : :
725 rhaas@postgresql.org 1358 [ - + ]:CBC 9 : if (!validateSQLNamePattern(&buf, pattern, true, false,
1359 : : "n.nspname", "opf.opfname", NULL,
1360 : : "pg_catalog.pg_opfamily_is_visible(opf.oid)",
1361 : : NULL, 3))
633 michael@paquier.xyz 1362 :UBC 0 : goto error_return;
1363 : :
1364 : : /* Rule descriptions (ignore rules for views) */
7918 tgl@sss.pgh.pa.us 1365 :CBC 9 : appendPQExpBuffer(&buf,
1366 : : "UNION ALL\n"
1367 : : " SELECT r.oid as oid, r.tableoid as tableoid,\n"
1368 : : " n.nspname as nspname,\n"
1369 : : " CAST(r.rulename AS pg_catalog.text) as name,"
1370 : : " CAST('%s' AS pg_catalog.text) as object\n"
1371 : : " FROM pg_catalog.pg_rewrite r\n"
1372 : : " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
1373 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
1374 : : " WHERE r.rulename != '_RETURN'\n",
1375 : : gettext_noop("rule"));
1376 : :
5421 bruce@momjian.us 1377 [ + - - + ]: 9 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 1378 :UBC 0 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
1379 : : " AND n.nspname <> 'information_schema'\n");
1380 : :
725 rhaas@postgresql.org 1381 [ - + ]:CBC 9 : if (!validateSQLNamePattern(&buf, pattern, true, false,
1382 : : "n.nspname", "r.rulename", NULL,
1383 : : "pg_catalog.pg_table_is_visible(c.oid)",
1384 : : NULL, 3))
633 michael@paquier.xyz 1385 :UBC 0 : goto error_return;
1386 : :
1387 : : /* Trigger descriptions */
7918 tgl@sss.pgh.pa.us 1388 :CBC 9 : appendPQExpBuffer(&buf,
1389 : : "UNION ALL\n"
1390 : : " SELECT t.oid as oid, t.tableoid as tableoid,\n"
1391 : : " n.nspname as nspname,\n"
1392 : : " CAST(t.tgname AS pg_catalog.text) as name,"
1393 : : " CAST('%s' AS pg_catalog.text) as object\n"
1394 : : " FROM pg_catalog.pg_trigger t\n"
1395 : : " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
1396 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
1397 : : gettext_noop("trigger"));
1398 : :
5421 bruce@momjian.us 1399 [ + - - + ]: 9 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 1400 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1401 : : " AND n.nspname <> 'information_schema'\n");
1402 : :
725 rhaas@postgresql.org 1403 [ + - - + :CBC 9 : if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, false,
- + ]
1404 : : "n.nspname", "t.tgname", NULL,
1405 : : "pg_catalog.pg_table_is_visible(c.oid)",
725 rhaas@postgresql.org 1406 :ECB (9) : NULL, 3))
633 michael@paquier.xyz 1407 :UBC 0 : goto error_return;
1408 : :
3800 heikki.linnakangas@i 1409 :CBC 9 : appendPQExpBufferStr(&buf,
1410 : : ") AS tt\n"
1411 : : " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
1412 : :
1413 : 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
1414 : :
3461 fujii@postgresql.org 1415 : 9 : res = PSQLexec(buf.data);
8026 peter_e@gmx.net 1416 : 9 : termPQExpBuffer(&buf);
8928 bruce@momjian.us 1417 [ - + ]: 9 : if (!res)
8928 bruce@momjian.us 1418 :UBC 0 : return false;
1419 : :
8324 peter_e@gmx.net 1420 :CBC 9 : myopt.title = _("Object descriptions");
5753 bruce@momjian.us 1421 : 9 : myopt.translate_header = true;
1422 : 9 : myopt.translate_columns = translate_columns;
3753 tgl@sss.pgh.pa.us 1423 : 9 : myopt.n_translate_columns = lengthof(translate_columns);
1424 : :
3056 1425 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1426 : :
8928 bruce@momjian.us 1427 : 9 : PQclear(res);
1428 : 9 : return true;
1429 : :
633 michael@paquier.xyz 1430 : 12 : error_return:
1431 : 12 : termPQExpBuffer(&buf);
1432 : 12 : return false;
1433 : : }
1434 : :
1435 : :
1436 : : /*
1437 : : * describeTableDetails (for \d)
1438 : : *
1439 : : * This routine finds the tables to be displayed, and calls
1440 : : * describeOneTableDetails for each one.
1441 : : *
1442 : : * verbose: if true, this is \d+
1443 : : */
1444 : : bool
5563 bruce@momjian.us 1445 : 1786 : describeTableDetails(const char *pattern, bool verbose, bool showSystem)
1446 : : {
1447 : : PQExpBufferData buf;
1448 : : PGresult *res;
1449 : : int i;
1450 : :
7918 tgl@sss.pgh.pa.us 1451 : 1786 : initPQExpBuffer(&buf);
1452 : :
1453 : 1786 : printfPQExpBuffer(&buf,
1454 : : "SELECT c.oid,\n"
1455 : : " n.nspname,\n"
1456 : : " c.relname\n"
1457 : : "FROM pg_catalog.pg_class c\n"
1458 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
1459 : :
5421 bruce@momjian.us 1460 [ + - - + ]: 1786 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 1461 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
1462 : : " AND n.nspname <> 'information_schema'\n");
1463 : :
725 rhaas@postgresql.org 1464 [ + - - + :CBC 1786 : if (!validateSQLNamePattern(&buf, pattern, !showSystem && !pattern, false,
- + ]
1465 : : "n.nspname", "c.relname", NULL,
1466 : : "pg_catalog.pg_table_is_visible(c.oid)",
725 rhaas@postgresql.org 1467 :ECB (1558) : NULL, 3))
1468 : : {
633 michael@paquier.xyz 1469 :UBC 0 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 1470 : 0 : return false;
1471 : : }
1472 : :
3800 heikki.linnakangas@i 1473 :CBC 1786 : appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
1474 : :
3461 fujii@postgresql.org 1475 : 1786 : res = PSQLexec(buf.data);
7918 tgl@sss.pgh.pa.us 1476 : 1786 : termPQExpBuffer(&buf);
1477 [ - + ]: 1786 : if (!res)
7918 tgl@sss.pgh.pa.us 1478 :UBC 0 : return false;
1479 : :
7918 tgl@sss.pgh.pa.us 1480 [ + + ]:CBC 1786 : if (PQntuples(res) == 0)
1481 : : {
6438 1482 [ - + ]: 13 : if (!pset.quiet)
1483 : : {
2453 tgl@sss.pgh.pa.us 1484 [ # # ]:UBC 0 : if (pattern)
1840 peter@eisentraut.org 1485 : 0 : pg_log_error("Did not find any relation named \"%s\".",
1486 : : pattern);
1487 : : else
1488 : 0 : pg_log_error("Did not find any relations.");
1489 : : }
7918 tgl@sss.pgh.pa.us 1490 :CBC 13 : PQclear(res);
1491 : 13 : return false;
1492 : : }
1493 : :
1494 [ + + ]: 3582 : for (i = 0; i < PQntuples(res); i++)
1495 : : {
1496 : : const char *oid;
1497 : : const char *nspname;
1498 : : const char *relname;
1499 : :
1500 : 1809 : oid = PQgetvalue(res, i, 0);
1501 : 1809 : nspname = PQgetvalue(res, i, 1);
1502 : 1809 : relname = PQgetvalue(res, i, 2);
1503 : :
1504 [ - + ]: 1809 : if (!describeOneTableDetails(nspname, relname, oid, verbose))
1505 : : {
7918 tgl@sss.pgh.pa.us 1506 :UBC 0 : PQclear(res);
1507 : 0 : return false;
1508 : : }
6514 tgl@sss.pgh.pa.us 1509 [ - + ]:CBC 1809 : if (cancel_pressed)
1510 : : {
6514 tgl@sss.pgh.pa.us 1511 :UBC 0 : PQclear(res);
1512 : 0 : return false;
1513 : : }
1514 : : }
1515 : :
7918 tgl@sss.pgh.pa.us 1516 :CBC 1773 : PQclear(res);
1517 : 1773 : return true;
1518 : : }
1519 : :
1520 : : /*
1521 : : * describeOneTableDetails (for \d)
1522 : : *
1523 : : * Unfortunately, the information presented here is so complicated that it
1524 : : * cannot be done in a single query. So we have to assemble the printed table
1525 : : * by hand and pass it to the underlying printTable() function.
1526 : : */
1527 : : static bool
1528 : 1809 : describeOneTableDetails(const char *schemaname,
1529 : : const char *relationname,
1530 : : const char *oid,
1531 : : bool verbose)
1532 : : {
2096 1533 : 1809 : bool retval = false;
1534 : : PQExpBufferData buf;
8906 bruce@momjian.us 1535 : 1809 : PGresult *res = NULL;
8857 peter_e@gmx.net 1536 : 1809 : printTableOpt myopt = pset.popt.topt;
1537 : : printTableContent cont;
5421 bruce@momjian.us 1538 : 1809 : bool printTableInitialized = false;
1539 : : int i;
7893 1540 : 1809 : char *view_def = NULL;
1541 : : char *headers[12];
1542 : : PQExpBufferData title;
1543 : : PQExpBufferData tmpbuf;
1544 : : int cols;
2096 tgl@sss.pgh.pa.us 1545 : 1809 : int attname_col = -1, /* column indexes in "res" */
1546 : 1809 : atttype_col = -1,
1547 : 1809 : attrdef_col = -1,
1548 : 1809 : attnotnull_col = -1,
1549 : 1809 : attcoll_col = -1,
1550 : 1809 : attidentity_col = -1,
1842 peter@eisentraut.org 1551 : 1809 : attgenerated_col = -1,
2096 tgl@sss.pgh.pa.us 1552 : 1809 : isindexkey_col = -1,
1553 : 1809 : indexdef_col = -1,
1554 : 1809 : fdwopts_col = -1,
1555 : 1809 : attstorage_col = -1,
1053 1556 : 1809 : attcompression_col = -1,
2096 1557 : 1809 : attstattarget_col = -1,
1053 1558 : 1809 : attdescr_col = -1;
1559 : : int numrows;
1560 : : struct
1561 : : {
1562 : : int16 checks;
1563 : : char relkind;
1564 : : bool hasindex;
1565 : : bool hasrules;
1566 : : bool hastriggers;
1567 : : bool rowsecurity;
1568 : : bool forcerowsecurity;
1569 : : bool hasoids;
1570 : : bool ispartition;
1571 : : Oid tablespace;
1572 : : char *reloptions;
1573 : : char *reloftype;
1574 : : char relpersistence;
1575 : : char relreplident;
1576 : : char *relam;
1577 : : } tableinfo;
2719 peter_e@gmx.net 1578 : 1809 : bool show_column_details = false;
1579 : :
4366 rhaas@postgresql.org 1580 : 1809 : myopt.default_footer = false;
1581 : : /* This output looks confusing in expanded mode. */
6744 bruce@momjian.us 1582 : 1809 : myopt.expanded = false;
1583 : :
8026 peter_e@gmx.net 1584 : 1809 : initPQExpBuffer(&buf);
1585 : 1809 : initPQExpBuffer(&title);
7785 tgl@sss.pgh.pa.us 1586 : 1809 : initPQExpBuffer(&tmpbuf);
1587 : :
1588 : : /* Get general table info */
1972 andres@anarazel.de 1589 [ + - ]: 1809 : if (pset.sversion >= 120000)
1590 : : {
1591 [ + + ]: 1809 : printfPQExpBuffer(&buf,
1592 : : "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1593 : : "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
1594 : : "false AS relhasoids, c.relispartition, %s, c.reltablespace, "
1595 : : "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1596 : : "c.relpersistence, c.relreplident, am.amname\n"
1597 : : "FROM pg_catalog.pg_class c\n "
1598 : : "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1599 : : "LEFT JOIN pg_catalog.pg_am am ON (c.relam = am.oid)\n"
1600 : : "WHERE c.oid = '%s';",
1601 : : (verbose ?
1602 : : "pg_catalog.array_to_string(c.reloptions || "
1603 : : "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1604 : : : "''"),
1605 : : oid);
1606 : : }
1846 alvherre@alvh.no-ip. 1607 [ # # ]:UBC 0 : else if (pset.sversion >= 100000)
1608 : : {
1609 [ # # ]: 0 : printfPQExpBuffer(&buf,
1610 : : "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1611 : : "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
1612 : : "c.relhasoids, c.relispartition, %s, c.reltablespace, "
1613 : : "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1614 : : "c.relpersistence, c.relreplident\n"
1615 : : "FROM pg_catalog.pg_class c\n "
1616 : : "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1617 : : "WHERE c.oid = '%s';",
1618 : : (verbose ?
1619 : : "pg_catalog.array_to_string(c.reloptions || "
1620 : : "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1621 : : : "''"),
1622 : : oid);
1623 : : }
1972 andres@anarazel.de 1624 [ # # ]: 0 : else if (pset.sversion >= 90500)
1625 : : {
3810 rhaas@postgresql.org 1626 [ # # ]: 0 : printfPQExpBuffer(&buf,
1627 : : "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1628 : : "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
1629 : : "c.relhasoids, false as relispartition, %s, c.reltablespace, "
1630 : : "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1631 : : "c.relpersistence, c.relreplident\n"
1632 : : "FROM pg_catalog.pg_class c\n "
1633 : : "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1634 : : "WHERE c.oid = '%s';",
1635 : : (verbose ?
1636 : : "pg_catalog.array_to_string(c.reloptions || "
1637 : : "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1638 : : : "''"),
1639 : : oid);
1640 : : }
3495 sfrost@snowman.net 1641 [ # # ]: 0 : else if (pset.sversion >= 90400)
1642 : : {
1643 [ # # ]: 0 : printfPQExpBuffer(&buf,
1644 : : "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1645 : : "c.relhastriggers, false, false, c.relhasoids, "
1646 : : "false as relispartition, %s, c.reltablespace, "
1647 : : "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1648 : : "c.relpersistence, c.relreplident\n"
1649 : : "FROM pg_catalog.pg_class c\n "
1650 : : "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1651 : : "WHERE c.oid = '%s';",
1652 : : (verbose ?
1653 : : "pg_catalog.array_to_string(c.reloptions || "
1654 : : "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1655 : : : "''"),
1656 : : oid);
1657 : : }
1658 : : else
1659 : : {
4855 rhaas@postgresql.org 1660 [ # # ]: 0 : printfPQExpBuffer(&buf,
1661 : : "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
1662 : : "c.relhastriggers, false, false, c.relhasoids, "
1663 : : "false as relispartition, %s, c.reltablespace, "
1664 : : "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
1665 : : "c.relpersistence\n"
1666 : : "FROM pg_catalog.pg_class c\n "
1667 : : "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
1668 : : "WHERE c.oid = '%s';",
1669 : : (verbose ?
1670 : : "pg_catalog.array_to_string(c.reloptions || "
1671 : : "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
1672 : : : "''"),
1673 : : oid);
1674 : : }
1675 : :
3461 fujii@postgresql.org 1676 :CBC 1809 : res = PSQLexec(buf.data);
8768 bruce@momjian.us 1677 [ - + ]: 1809 : if (!res)
8026 peter_e@gmx.net 1678 :UBC 0 : goto error_return;
1679 : :
1680 : : /* Did we get anything? */
8928 bruce@momjian.us 1681 [ - + ]:CBC 1809 : if (PQntuples(res) == 0)
1682 : : {
6438 tgl@sss.pgh.pa.us 1683 [ # # ]:UBC 0 : if (!pset.quiet)
1840 peter@eisentraut.org 1684 : 0 : pg_log_error("Did not find any relation with OID %s.", oid);
8026 peter_e@gmx.net 1685 : 0 : goto error_return;
1686 : : }
1687 : :
5635 tgl@sss.pgh.pa.us 1688 :CBC 1809 : tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
7297 neilc@samurai.com 1689 : 1809 : tableinfo.relkind = *(PQgetvalue(res, 0, 1));
5635 tgl@sss.pgh.pa.us 1690 : 1809 : tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
1691 : 1809 : tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
1692 : 1809 : tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
3490 sfrost@snowman.net 1693 : 1809 : tableinfo.rowsecurity = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
3115 1694 : 1809 : tableinfo.forcerowsecurity = strcmp(PQgetvalue(res, 0, 6), "t") == 0;
1695 : 1809 : tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 7), "t") == 0;
1846 alvherre@alvh.no-ip. 1696 : 1809 : tableinfo.ispartition = strcmp(PQgetvalue(res, 0, 8), "t") == 0;
850 tgl@sss.pgh.pa.us 1697 : 1809 : tableinfo.reloptions = pg_strdup(PQgetvalue(res, 0, 9));
1698 : 1809 : tableinfo.tablespace = atooid(PQgetvalue(res, 0, 10));
1699 : 1809 : tableinfo.reloftype = (strcmp(PQgetvalue(res, 0, 11), "") != 0) ?
1846 alvherre@alvh.no-ip. 1700 [ + + ]: 1809 : pg_strdup(PQgetvalue(res, 0, 11)) : NULL;
850 tgl@sss.pgh.pa.us 1701 : 1809 : tableinfo.relpersistence = *(PQgetvalue(res, 0, 12));
3810 rhaas@postgresql.org 1702 [ + - ]: 3618 : tableinfo.relreplident = (pset.sversion >= 90400) ?
1846 alvherre@alvh.no-ip. 1703 : 1809 : *(PQgetvalue(res, 0, 13)) : 'd';
1866 andres@anarazel.de 1704 [ + - ]: 1809 : if (pset.sversion >= 120000)
1846 alvherre@alvh.no-ip. 1705 : 3618 : tableinfo.relam = PQgetisnull(res, 0, 14) ?
1706 [ + + ]: 1809 : (char *) NULL : pg_strdup(PQgetvalue(res, 0, 14));
1707 : : else
1866 andres@anarazel.de 1708 :UBC 0 : tableinfo.relam = NULL;
8768 bruce@momjian.us 1709 :CBC 1809 : PQclear(res);
5641 tgl@sss.pgh.pa.us 1710 : 1809 : res = NULL;
1711 : :
1712 : : /*
1713 : : * If it's a sequence, deal with it here separately.
1714 : : */
2593 1715 [ + + ]: 1809 : if (tableinfo.relkind == RELKIND_SEQUENCE)
1716 : : {
2393 peter_e@gmx.net 1717 : 96 : PGresult *result = NULL;
738 tomas.vondra@postgre 1718 : 96 : printQueryOpt myopt = pset.popt;
1719 : 96 : char *footers[2] = {NULL, NULL};
1720 : :
2393 peter_e@gmx.net 1721 [ + - ]: 96 : if (pset.sversion >= 100000)
1722 : : {
1723 : 96 : printfPQExpBuffer(&buf,
1724 : : "SELECT pg_catalog.format_type(seqtypid, NULL) AS \"%s\",\n"
1725 : : " seqstart AS \"%s\",\n"
1726 : : " seqmin AS \"%s\",\n"
1727 : : " seqmax AS \"%s\",\n"
1728 : : " seqincrement AS \"%s\",\n"
1729 : : " CASE WHEN seqcycle THEN '%s' ELSE '%s' END AS \"%s\",\n"
1730 : : " seqcache AS \"%s\"\n",
1731 : : gettext_noop("Type"),
1732 : : gettext_noop("Start"),
1733 : : gettext_noop("Minimum"),
1734 : : gettext_noop("Maximum"),
1735 : : gettext_noop("Increment"),
1736 : : gettext_noop("yes"),
1737 : : gettext_noop("no"),
1738 : : gettext_noop("Cycles?"),
1739 : : gettext_noop("Cache"));
1740 : 96 : appendPQExpBuffer(&buf,
1741 : : "FROM pg_catalog.pg_sequence\n"
1742 : : "WHERE seqrelid = '%s';",
1743 : : oid);
1744 : : }
1745 : : else
1746 : : {
2393 peter_e@gmx.net 1747 :UBC 0 : printfPQExpBuffer(&buf,
1748 : : "SELECT 'bigint' AS \"%s\",\n"
1749 : : " start_value AS \"%s\",\n"
1750 : : " min_value AS \"%s\",\n"
1751 : : " max_value AS \"%s\",\n"
1752 : : " increment_by AS \"%s\",\n"
1753 : : " CASE WHEN is_cycled THEN '%s' ELSE '%s' END AS \"%s\",\n"
1754 : : " cache_value AS \"%s\"\n",
1755 : : gettext_noop("Type"),
1756 : : gettext_noop("Start"),
1757 : : gettext_noop("Minimum"),
1758 : : gettext_noop("Maximum"),
1759 : : gettext_noop("Increment"),
1760 : : gettext_noop("yes"),
1761 : : gettext_noop("no"),
1762 : : gettext_noop("Cycles?"),
1763 : : gettext_noop("Cache"));
1764 : 0 : appendPQExpBuffer(&buf, "FROM %s", fmtId(schemaname));
1765 : : /* must be separate because fmtId isn't reentrant */
1766 : 0 : appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
1767 : : }
1768 : :
3461 fujii@postgresql.org 1769 :CBC 96 : res = PSQLexec(buf.data);
5382 tgl@sss.pgh.pa.us 1770 [ - + ]: 96 : if (!res)
5752 bruce@momjian.us 1771 :UBC 0 : goto error_return;
1772 : :
1773 : : /* Get the column that owns this sequence */
2393 peter_e@gmx.net 1774 :CBC 96 : printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
1775 : : "\n pg_catalog.quote_ident(relname) || '.' ||"
1776 : : "\n pg_catalog.quote_ident(attname),"
1777 : : "\n d.deptype"
1778 : : "\nFROM pg_catalog.pg_class c"
1779 : : "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
1780 : : "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
1781 : : "\nINNER JOIN pg_catalog.pg_attribute a ON ("
1782 : : "\n a.attrelid=c.oid AND"
1783 : : "\n a.attnum=d.refobjsubid)"
1784 : : "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
1785 : : "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
1786 : : "\n AND d.objid='%s'"
1787 : : "\n AND d.deptype IN ('a', 'i')",
1788 : : oid);
1789 : :
1790 : 96 : result = PSQLexec(buf.data);
1791 : :
1792 : : /*
1793 : : * If we get no rows back, don't show anything (obviously). We should
1794 : : * never get more than one row back, but if we do, just ignore it and
1795 : : * don't print anything.
1796 : : */
1797 [ - + ]: 96 : if (!result)
2393 peter_e@gmx.net 1798 :UBC 0 : goto error_return;
2393 peter_e@gmx.net 1799 [ + + ]:CBC 96 : else if (PQntuples(result) == 1)
1800 : : {
1801 [ + + - ]: 87 : switch (PQgetvalue(result, 0, 1)[0])
1802 : : {
1803 : 60 : case 'a':
738 tomas.vondra@postgre 1804 : 60 : footers[0] = psprintf(_("Owned by: %s"),
1805 : : PQgetvalue(result, 0, 0));
2393 peter_e@gmx.net 1806 : 60 : break;
1807 : 27 : case 'i':
738 tomas.vondra@postgre 1808 : 27 : footers[0] = psprintf(_("Sequence for identity column: %s"),
1809 : : PQgetvalue(result, 0, 0));
2393 peter_e@gmx.net 1810 : 27 : break;
1811 : : }
1812 : : }
1813 : 96 : PQclear(result);
1814 : :
738 tomas.vondra@postgre 1815 [ + + ]: 96 : if (tableinfo.relpersistence == 'u')
1816 : 15 : printfPQExpBuffer(&title, _("Unlogged sequence \"%s.%s\""),
1817 : : schemaname, relationname);
1818 : : else
1819 : 81 : printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
1820 : : schemaname, relationname);
1821 : :
1822 : 96 : myopt.footers = footers;
1823 : 96 : myopt.topt.default_footer = false;
1824 : 96 : myopt.title = title.data;
1825 : 96 : myopt.translate_header = true;
1826 : :
1827 : 96 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
1828 : :
668 peter@eisentraut.org 1829 : 96 : free(footers[0]);
1830 : :
2393 peter_e@gmx.net 1831 : 96 : retval = true;
1832 : 96 : goto error_return; /* not an error, just return early */
1833 : : }
1834 : :
1835 : : /* Identify whether we should print collation, nullable, default vals */
2096 tgl@sss.pgh.pa.us 1836 [ + + ]: 1713 : if (tableinfo.relkind == RELKIND_RELATION ||
1837 [ + + ]: 657 : tableinfo.relkind == RELKIND_VIEW ||
1838 [ + + ]: 482 : tableinfo.relkind == RELKIND_MATVIEW ||
1839 [ + + ]: 452 : tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1840 [ + + ]: 359 : tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
1841 [ + + ]: 320 : tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1842 : 1516 : show_column_details = true;
1843 : :
1844 : : /*
1845 : : * Get per-column info
1846 : : *
1847 : : * Since the set of query columns we need varies depending on relkind and
1848 : : * server version, we compute all the column numbers on-the-fly. Column
1849 : : * number variables for columns not fetched are left as -1; this avoids
1850 : : * duplicative test logic below.
1851 : : */
1852 : 1713 : cols = 0;
1853 : 1713 : printfPQExpBuffer(&buf, "SELECT a.attname");
1854 : 1713 : attname_col = cols++;
1855 : 1713 : appendPQExpBufferStr(&buf, ",\n pg_catalog.format_type(a.atttypid, a.atttypmod)");
1856 : 1713 : atttype_col = cols++;
1857 : :
1858 [ + + ]: 1713 : if (show_column_details)
1859 : : {
1860 : : /* use "pretty" mode for expression to avoid excessive parentheses */
1861 : 1516 : appendPQExpBufferStr(&buf,
1862 : : ",\n (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid, true)"
1863 : : "\n FROM pg_catalog.pg_attrdef d"
1864 : : "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)"
1865 : : ",\n a.attnotnull");
1866 : 1516 : attrdef_col = cols++;
1867 : 1516 : attnotnull_col = cols++;
850 1868 : 1516 : appendPQExpBufferStr(&buf, ",\n (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
1869 : : " WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
2096 1870 : 1516 : attcoll_col = cols++;
1871 [ + - ]: 1516 : if (pset.sversion >= 100000)
1872 : 1516 : appendPQExpBufferStr(&buf, ",\n a.attidentity");
1873 : : else
2096 tgl@sss.pgh.pa.us 1874 :UBC 0 : appendPQExpBufferStr(&buf, ",\n ''::pg_catalog.char AS attidentity");
2096 tgl@sss.pgh.pa.us 1875 :CBC 1516 : attidentity_col = cols++;
1842 peter@eisentraut.org 1876 [ + - ]: 1516 : if (pset.sversion >= 120000)
1877 : 1516 : appendPQExpBufferStr(&buf, ",\n a.attgenerated");
1878 : : else
1842 peter@eisentraut.org 1879 :UBC 0 : appendPQExpBufferStr(&buf, ",\n ''::pg_catalog.char AS attgenerated");
1842 peter@eisentraut.org 1880 :CBC 1516 : attgenerated_col = cols++;
1881 : : }
2277 alvherre@alvh.no-ip. 1882 [ + + ]: 1713 : if (tableinfo.relkind == RELKIND_INDEX ||
1883 [ + + ]: 1585 : tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
1884 : : {
2096 tgl@sss.pgh.pa.us 1885 [ + - ]: 194 : if (pset.sversion >= 110000)
1886 : : {
1887 : 194 : appendPQExpBuffer(&buf, ",\n CASE WHEN a.attnum <= (SELECT i.indnkeyatts FROM pg_catalog.pg_index i WHERE i.indexrelid = '%s') THEN '%s' ELSE '%s' END AS is_key",
1888 : : oid,
1889 : : gettext_noop("yes"),
1890 : : gettext_noop("no"));
1891 : 194 : isindexkey_col = cols++;
1892 : : }
3800 heikki.linnakangas@i 1893 : 194 : appendPQExpBufferStr(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
2096 tgl@sss.pgh.pa.us 1894 : 194 : indexdef_col = cols++;
1895 : : }
1896 : : /* FDW options for foreign table column */
850 1897 [ + + ]: 1713 : if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
1898 : : {
3800 heikki.linnakangas@i 1899 : 93 : appendPQExpBufferStr(&buf, ",\n CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
1900 : : " '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM "
1901 : : " pg_catalog.pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
2096 tgl@sss.pgh.pa.us 1902 : 93 : fdwopts_col = cols++;
1903 : : }
7918 1904 [ + + ]: 1713 : if (verbose)
1905 : : {
3800 heikki.linnakangas@i 1906 : 737 : appendPQExpBufferStr(&buf, ",\n a.attstorage");
2096 tgl@sss.pgh.pa.us 1907 : 737 : attstorage_col = cols++;
1908 : :
1909 : : /* compression info, if relevant to relkind */
1122 rhaas@postgresql.org 1910 [ + - ]: 737 : if (pset.sversion >= 140000 &&
1911 [ + + ]: 737 : !pset.hide_compression &&
1912 [ + + ]: 39 : (tableinfo.relkind == RELKIND_RELATION ||
1913 [ + - ]: 6 : tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
1914 [ + - ]: 6 : tableinfo.relkind == RELKIND_MATVIEW))
1915 : : {
1916 : 39 : appendPQExpBufferStr(&buf, ",\n a.attcompression AS attcompression");
1917 : 39 : attcompression_col = cols++;
1918 : : }
1919 : :
1920 : : /* stats target, if relevant to relkind */
2096 tgl@sss.pgh.pa.us 1921 [ + + ]: 737 : if (tableinfo.relkind == RELKIND_RELATION ||
1922 [ + + ]: 340 : tableinfo.relkind == RELKIND_INDEX ||
1923 [ + + ]: 323 : tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
1924 [ + + ]: 320 : tableinfo.relkind == RELKIND_MATVIEW ||
1925 [ + + ]: 290 : tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1926 [ + + ]: 221 : tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1927 : : {
1928 : 570 : appendPQExpBufferStr(&buf, ",\n CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
1929 : 570 : attstattarget_col = cols++;
1930 : : }
1931 : :
1932 : : /*
1933 : : * In 9.0+, we have column comments for: relations, views, composite
1934 : : * types, and foreign tables (cf. CommentObject() in comment.c).
1935 : : */
2593 1936 [ + + ]: 737 : if (tableinfo.relkind == RELKIND_RELATION ||
1937 [ + + ]: 340 : tableinfo.relkind == RELKIND_VIEW ||
1938 [ + + ]: 173 : tableinfo.relkind == RELKIND_MATVIEW ||
1939 [ + + ]: 143 : tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1940 [ + - ]: 74 : tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
1941 [ + + ]: 74 : tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
1942 : : {
2096 1943 : 717 : appendPQExpBufferStr(&buf, ",\n pg_catalog.col_description(a.attrelid, a.attnum)");
1944 : 717 : attdescr_col = cols++;
1945 : : }
1946 : : }
1947 : :
3800 heikki.linnakangas@i 1948 : 1713 : appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_attribute a");
7918 tgl@sss.pgh.pa.us 1949 : 1713 : appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
3800 heikki.linnakangas@i 1950 : 1713 : appendPQExpBufferStr(&buf, "\nORDER BY a.attnum;");
1951 : :
3461 fujii@postgresql.org 1952 : 1713 : res = PSQLexec(buf.data);
8906 bruce@momjian.us 1953 [ - + ]: 1713 : if (!res)
8026 peter_e@gmx.net 1954 :UBC 0 : goto error_return;
7785 tgl@sss.pgh.pa.us 1955 :CBC 1713 : numrows = PQntuples(res);
1956 : :
1957 : : /* Make title */
5815 alvherre@alvh.no-ip. 1958 [ + + + + : 1713 : switch (tableinfo.relkind)
+ + + + +
- ]
1959 : : {
2593 tgl@sss.pgh.pa.us 1960 : 1056 : case RELKIND_RELATION:
4855 rhaas@postgresql.org 1961 [ + + ]: 1056 : if (tableinfo.relpersistence == 'u')
4799 itagaki.takahiro@gma 1962 : 9 : printfPQExpBuffer(&title, _("Unlogged table \"%s.%s\""),
1963 : : schemaname, relationname);
1964 : : else
4855 rhaas@postgresql.org 1965 : 1047 : printfPQExpBuffer(&title, _("Table \"%s.%s\""),
1966 : : schemaname, relationname);
5815 alvherre@alvh.no-ip. 1967 : 1056 : break;
2593 tgl@sss.pgh.pa.us 1968 : 175 : case RELKIND_VIEW:
5815 alvherre@alvh.no-ip. 1969 : 175 : printfPQExpBuffer(&title, _("View \"%s.%s\""),
1970 : : schemaname, relationname);
1971 : 175 : break;
2593 tgl@sss.pgh.pa.us 1972 : 30 : case RELKIND_MATVIEW:
4060 kgrittn@postgresql.o 1973 [ - + ]: 30 : if (tableinfo.relpersistence == 'u')
4060 kgrittn@postgresql.o 1974 :UBC 0 : printfPQExpBuffer(&title, _("Unlogged materialized view \"%s.%s\""),
1975 : : schemaname, relationname);
1976 : : else
4060 kgrittn@postgresql.o 1977 :CBC 30 : printfPQExpBuffer(&title, _("Materialized view \"%s.%s\""),
1978 : : schemaname, relationname);
1979 : 30 : break;
2593 tgl@sss.pgh.pa.us 1980 : 128 : case RELKIND_INDEX:
4855 rhaas@postgresql.org 1981 [ - + ]: 128 : if (tableinfo.relpersistence == 'u')
4799 itagaki.takahiro@gma 1982 :UBC 0 : printfPQExpBuffer(&title, _("Unlogged index \"%s.%s\""),
1983 : : schemaname, relationname);
1984 : : else
4855 rhaas@postgresql.org 1985 :CBC 128 : printfPQExpBuffer(&title, _("Index \"%s.%s\""),
1986 : : schemaname, relationname);
5815 alvherre@alvh.no-ip. 1987 : 128 : break;
1973 1988 : 66 : case RELKIND_PARTITIONED_INDEX:
1989 [ - + ]: 66 : if (tableinfo.relpersistence == 'u')
1973 alvherre@alvh.no-ip. 1990 :UBC 0 : printfPQExpBuffer(&title, _("Unlogged partitioned index \"%s.%s\""),
1991 : : schemaname, relationname);
1992 : : else
1973 alvherre@alvh.no-ip. 1993 :CBC 66 : printfPQExpBuffer(&title, _("Partitioned index \"%s.%s\""),
1994 : : schemaname, relationname);
1995 : 66 : break;
2593 tgl@sss.pgh.pa.us 1996 : 3 : case RELKIND_TOASTVALUE:
5815 alvherre@alvh.no-ip. 1997 : 3 : printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
1998 : : schemaname, relationname);
1999 : 3 : break;
2593 tgl@sss.pgh.pa.us 2000 : 39 : case RELKIND_COMPOSITE_TYPE:
5815 alvherre@alvh.no-ip. 2001 : 39 : printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
2002 : : schemaname, relationname);
2003 : 39 : break;
2593 tgl@sss.pgh.pa.us 2004 : 93 : case RELKIND_FOREIGN_TABLE:
4852 rhaas@postgresql.org 2005 : 93 : printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""),
2006 : : schemaname, relationname);
2007 : 93 : break;
2593 tgl@sss.pgh.pa.us 2008 : 123 : case RELKIND_PARTITIONED_TABLE:
2685 rhaas@postgresql.org 2009 [ - + ]: 123 : if (tableinfo.relpersistence == 'u')
1973 alvherre@alvh.no-ip. 2010 :UBC 0 : printfPQExpBuffer(&title, _("Unlogged partitioned table \"%s.%s\""),
2011 : : schemaname, relationname);
2012 : : else
1973 alvherre@alvh.no-ip. 2013 :CBC 123 : printfPQExpBuffer(&title, _("Partitioned table \"%s.%s\""),
2014 : : schemaname, relationname);
2685 rhaas@postgresql.org 2015 : 123 : break;
5815 alvherre@alvh.no-ip. 2016 :UBC 0 : default:
2017 : : /* untranslated unknown relkind */
2018 : 0 : printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
2019 : 0 : tableinfo.relkind, schemaname, relationname);
2020 : 0 : break;
2021 : : }
2022 : :
2023 : : /* Fill headers[] with the names of the columns we will output */
2096 tgl@sss.pgh.pa.us 2024 :CBC 1713 : cols = 0;
2025 : 1713 : headers[cols++] = gettext_noop("Column");
2026 : 1713 : headers[cols++] = gettext_noop("Type");
2027 [ + + ]: 1713 : if (show_column_details)
2028 : : {
2719 peter_e@gmx.net 2029 : 1516 : headers[cols++] = gettext_noop("Collation");
2030 : 1516 : headers[cols++] = gettext_noop("Nullable");
2031 : 1516 : headers[cols++] = gettext_noop("Default");
2032 : : }
2096 tgl@sss.pgh.pa.us 2033 [ + + ]: 1713 : if (isindexkey_col >= 0)
2034 : 194 : headers[cols++] = gettext_noop("Key?");
2035 [ + + ]: 1713 : if (indexdef_col >= 0)
5396 peter_e@gmx.net 2036 : 194 : headers[cols++] = gettext_noop("Definition");
2096 tgl@sss.pgh.pa.us 2037 [ + + ]: 1713 : if (fdwopts_col >= 0)
2497 peter_e@gmx.net 2038 : 93 : headers[cols++] = gettext_noop("FDW options");
2096 tgl@sss.pgh.pa.us 2039 [ + + ]: 1713 : if (attstorage_col >= 0)
5753 bruce@momjian.us 2040 : 737 : headers[cols++] = gettext_noop("Storage");
1122 rhaas@postgresql.org 2041 [ + + ]: 1713 : if (attcompression_col >= 0)
2042 : 39 : headers[cols++] = gettext_noop("Compression");
2096 tgl@sss.pgh.pa.us 2043 [ + + ]: 1713 : if (attstattarget_col >= 0)
2044 : 570 : headers[cols++] = gettext_noop("Stats target");
2045 [ + + ]: 1713 : if (attdescr_col >= 0)
2046 : 717 : headers[cols++] = gettext_noop("Description");
2047 : :
2048 [ - + ]: 1713 : Assert(cols <= lengthof(headers));
2049 : :
5816 alvherre@alvh.no-ip. 2050 : 1713 : printTableInit(&cont, &myopt, title.data, cols, numrows);
5641 tgl@sss.pgh.pa.us 2051 : 1713 : printTableInitialized = true;
2052 : :
5816 alvherre@alvh.no-ip. 2053 [ + + ]: 12231 : for (i = 0; i < cols; i++)
2054 : 10518 : printTableAddHeader(&cont, headers[i], true, 'l');
2055 : :
2056 : : /* Generate table cells to be printed */
7785 tgl@sss.pgh.pa.us 2057 [ + + ]: 5707 : for (i = 0; i < numrows; i++)
2058 : : {
2059 : : /* Column */
2096 2060 : 3994 : printTableAddCell(&cont, PQgetvalue(res, i, attname_col), false, false);
2061 : :
2062 : : /* Type */
2063 : 3994 : printTableAddCell(&cont, PQgetvalue(res, i, atttype_col), false, false);
2064 : :
2065 : : /* Collation, Nullable, Default */
2719 peter_e@gmx.net 2066 [ + + ]: 3994 : if (show_column_details)
2067 : : {
2068 : : char *identity;
2069 : : char *generated;
2070 : : char *default_str;
1236 tgl@sss.pgh.pa.us 2071 : 3760 : bool mustfree = false;
2072 : :
2096 2073 : 3760 : printTableAddCell(&cont, PQgetvalue(res, i, attcoll_col), false, false);
2074 : :
2075 : 3760 : printTableAddCell(&cont,
2076 [ + + ]: 3760 : strcmp(PQgetvalue(res, i, attnotnull_col), "t") == 0 ? "not null" : "",
2077 : : false, false);
2078 : :
2079 : 3760 : identity = PQgetvalue(res, i, attidentity_col);
1842 peter@eisentraut.org 2080 : 3760 : generated = PQgetvalue(res, i, attgenerated_col);
2081 : :
2082 [ + + ]: 3760 : if (identity[0] == ATTRIBUTE_IDENTITY_ALWAYS)
2565 peter_e@gmx.net 2083 : 30 : default_str = "generated always as identity";
2084 [ + + ]: 3730 : else if (identity[0] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
2085 : 9 : default_str = "generated by default as identity";
1842 peter@eisentraut.org 2086 [ + + ]: 3721 : else if (generated[0] == ATTRIBUTE_GENERATED_STORED)
2087 : : {
1236 tgl@sss.pgh.pa.us 2088 : 110 : default_str = psprintf("generated always as (%s) stored",
2089 : : PQgetvalue(res, i, attrdef_col));
2090 : 110 : mustfree = true;
2091 : : }
2092 : : else
1842 peter@eisentraut.org 2093 : 3611 : default_str = PQgetvalue(res, i, attrdef_col);
2094 : :
1236 tgl@sss.pgh.pa.us 2095 : 3760 : printTableAddCell(&cont, default_str, false, mustfree);
2096 : : }
2097 : :
2098 : : /* Info for index columns */
2096 2099 [ + + ]: 3994 : if (isindexkey_col >= 0)
2100 : 225 : printTableAddCell(&cont, PQgetvalue(res, i, isindexkey_col), true, false);
2101 [ + + ]: 3994 : if (indexdef_col >= 0)
2102 : 225 : printTableAddCell(&cont, PQgetvalue(res, i, indexdef_col), false, false);
2103 : :
2104 : : /* FDW options for foreign table columns */
2105 [ + + ]: 3994 : if (fdwopts_col >= 0)
2106 : 345 : printTableAddCell(&cont, PQgetvalue(res, i, fdwopts_col), false, false);
2107 : :
2108 : : /* Storage mode, if relevant */
2109 [ + + ]: 3994 : if (attstorage_col >= 0)
2110 : : {
2111 : 1808 : char *storage = PQgetvalue(res, i, attstorage_col);
2112 : :
2113 : : /* these strings are literal in our syntax, so not translated. */
5421 bruce@momjian.us 2114 [ + + ]: 2388 : printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
2115 [ + + ]: 1091 : (storage[0] == 'm' ? "main" :
2116 [ + + ]: 532 : (storage[0] == 'x' ? "extended" :
2117 [ + - ]: 21 : (storage[0] == 'e' ? "external" :
2118 : : "???")))),
2119 : : false, false);
2120 : : }
2121 : :
2122 : : /* Column compression, if relevant */
1122 rhaas@postgresql.org 2123 [ + + ]: 3994 : if (attcompression_col >= 0)
2124 : : {
2125 : 39 : char *compression = PQgetvalue(res, i, attcompression_col);
2126 : :
2127 : : /* these strings are literal in our syntax, so not translated. */
2128 [ + + ]: 69 : printTableAddCell(&cont, (compression[0] == 'p' ? "pglz" :
2129 [ + + ]: 48 : (compression[0] == 'l' ? "lz4" :
2130 [ + - ]: 18 : (compression[0] == '\0' ? "" :
2131 : : "???"))),
2132 : : false, false);
2133 : : }
2134 : :
2135 : : /* Statistics target, if the relkind supports this feature */
2096 tgl@sss.pgh.pa.us 2136 [ + + ]: 3994 : if (attstattarget_col >= 0)
2137 : 1369 : printTableAddCell(&cont, PQgetvalue(res, i, attstattarget_col),
2138 : : false, false);
2139 : :
2140 : : /* Column comments, if the relkind supports this feature */
2141 [ + + ]: 3994 : if (attdescr_col >= 0)
2142 : 1772 : printTableAddCell(&cont, PQgetvalue(res, i, attdescr_col),
2143 : : false, false);
2144 : : }
2145 : :
2146 : : /* Make footers */
2147 : :
1726 2148 [ + + ]: 1713 : if (tableinfo.ispartition)
2149 : : {
2150 : : /* Footer information for a partition child table */
2151 : : PGresult *result;
2152 : :
2454 2153 : 222 : printfPQExpBuffer(&buf,
2154 : : "SELECT inhparent::pg_catalog.regclass,\n"
2155 : : " pg_catalog.pg_get_expr(c.relpartbound, c.oid),\n ");
2156 : :
586 drowley@postgresql.o 2157 :UBC 0 : appendPQExpBufferStr(&buf,
586 drowley@postgresql.o 2158 [ + - ]:CBC 222 : pset.sversion >= 140000 ? "inhdetachpending" :
2159 : : "false as inhdetachpending");
2160 : :
2161 : : /* If verbose, also request the partition constraint definition */
2528 rhaas@postgresql.org 2162 [ + + ]: 222 : if (verbose)
1746 drowley@postgresql.o 2163 : 78 : appendPQExpBufferStr(&buf,
2164 : : ",\n pg_catalog.pg_get_partition_constraintdef(c.oid)");
2454 tgl@sss.pgh.pa.us 2165 : 222 : appendPQExpBuffer(&buf,
2166 : : "\nFROM pg_catalog.pg_class c"
2167 : : " JOIN pg_catalog.pg_inherits i"
2168 : : " ON c.oid = inhrelid"
2169 : : "\nWHERE c.oid = '%s';", oid);
2685 rhaas@postgresql.org 2170 : 222 : result = PSQLexec(buf.data);
2171 [ - + ]: 222 : if (!result)
2685 rhaas@postgresql.org 2172 :UBC 0 : goto error_return;
2173 : :
2685 rhaas@postgresql.org 2174 [ + - ]:CBC 222 : if (PQntuples(result) > 0)
2175 : : {
1726 tgl@sss.pgh.pa.us 2176 : 222 : char *parent_name = PQgetvalue(result, 0, 0);
2177 : 222 : char *partdef = PQgetvalue(result, 0, 1);
1116 alvherre@alvh.no-ip. 2178 : 222 : char *detached = PQgetvalue(result, 0, 2);
2179 : :
1116 alvherre@alvh.no-ip. 2180 :UBC 0 : printfPQExpBuffer(&tmpbuf, _("Partition of: %s %s%s"), parent_name,
2181 : : partdef,
1116 alvherre@alvh.no-ip. 2182 [ - + ]:CBC 222 : strcmp(detached, "t") == 0 ? " DETACH PENDING" : "");
2685 rhaas@postgresql.org 2183 : 222 : printTableAddFooter(&cont, tmpbuf.data);
2184 : :
2389 2185 [ + + ]: 222 : if (verbose)
2186 : : {
1726 tgl@sss.pgh.pa.us 2187 : 78 : char *partconstraintdef = NULL;
2188 : :
1116 alvherre@alvh.no-ip. 2189 [ + + ]: 78 : if (!PQgetisnull(result, 0, 3))
2190 : 69 : partconstraintdef = PQgetvalue(result, 0, 3);
2191 : : /* If there isn't any constraint, show that explicitly */
2389 rhaas@postgresql.org 2192 [ + + - + ]: 78 : if (partconstraintdef == NULL || partconstraintdef[0] == '\0')
2193 : 9 : printfPQExpBuffer(&tmpbuf, _("No partition constraint"));
2194 : : else
2195 : 69 : printfPQExpBuffer(&tmpbuf, _("Partition constraint: %s"),
2196 : : partconstraintdef);
2197 : 78 : printTableAddFooter(&cont, tmpbuf.data);
2198 : : }
2199 : : }
1726 tgl@sss.pgh.pa.us 2200 : 222 : PQclear(result);
2201 : : }
2202 : :
2593 2203 [ + + ]: 1713 : if (tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
2204 : : {
2205 : : /* Footer information for a partitioned table (partitioning parent) */
2206 : : PGresult *result;
2207 : :
2685 rhaas@postgresql.org 2208 : 123 : printfPQExpBuffer(&buf,
2209 : : "SELECT pg_catalog.pg_get_partkeydef('%s'::pg_catalog.oid);",
2210 : : oid);
2211 : 123 : result = PSQLexec(buf.data);
1726 tgl@sss.pgh.pa.us 2212 [ - + ]: 123 : if (!result)
2685 rhaas@postgresql.org 2213 :UBC 0 : goto error_return;
2214 : :
1726 tgl@sss.pgh.pa.us 2215 [ + - ]:CBC 123 : if (PQntuples(result) == 1)
2216 : : {
2217 : 123 : char *partkeydef = PQgetvalue(result, 0, 0);
2218 : :
2219 : 123 : printfPQExpBuffer(&tmpbuf, _("Partition key: %s"), partkeydef);
2220 : 123 : printTableAddFooter(&cont, tmpbuf.data);
2221 : : }
2685 rhaas@postgresql.org 2222 : 123 : PQclear(result);
2223 : : }
2224 : :
1727 tgl@sss.pgh.pa.us 2225 [ + + ]: 1713 : if (tableinfo.relkind == RELKIND_TOASTVALUE)
2226 : : {
2227 : : /* For a TOAST table, print name of owning table */
2228 : : PGresult *result;
2229 : :
2230 : 3 : printfPQExpBuffer(&buf,
2231 : : "SELECT n.nspname, c.relname\n"
2232 : : "FROM pg_catalog.pg_class c"
2233 : : " JOIN pg_catalog.pg_namespace n"
2234 : : " ON n.oid = c.relnamespace\n"
2235 : : "WHERE reltoastrelid = '%s';", oid);
2236 : 3 : result = PSQLexec(buf.data);
2237 [ - + ]: 3 : if (!result)
1727 tgl@sss.pgh.pa.us 2238 :UBC 0 : goto error_return;
2239 : :
1727 tgl@sss.pgh.pa.us 2240 [ + - ]:CBC 3 : if (PQntuples(result) == 1)
2241 : : {
2242 : 3 : char *schemaname = PQgetvalue(result, 0, 0);
2243 : 3 : char *relname = PQgetvalue(result, 0, 1);
2244 : :
2245 : 3 : printfPQExpBuffer(&tmpbuf, _("Owning table: \"%s.%s\""),
2246 : : schemaname, relname);
2247 : 3 : printTableAddFooter(&cont, tmpbuf.data);
2248 : : }
2249 : 3 : PQclear(result);
2250 : : }
2251 : :
2277 alvherre@alvh.no-ip. 2252 [ + + ]: 1713 : if (tableinfo.relkind == RELKIND_INDEX ||
2253 [ + + ]: 1585 : tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
8768 bruce@momjian.us 2254 : 194 : {
2255 : : /* Footer information about an index */
2256 : : PGresult *result;
2257 : :
8026 peter_e@gmx.net 2258 : 194 : printfPQExpBuffer(&buf,
2259 : : "SELECT i.indisunique, i.indisprimary, i.indisclustered, "
2260 : : "i.indisvalid,\n"
2261 : : " (NOT i.indimmediate) AND "
2262 : : "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
2263 : : "WHERE conrelid = i.indrelid AND "
2264 : : "conindid = i.indexrelid AND "
2265 : : "contype IN ('p','u','x') AND "
2266 : : "condeferrable) AS condeferrable,\n"
2267 : : " (NOT i.indimmediate) AND "
2268 : : "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
2269 : : "WHERE conrelid = i.indrelid AND "
2270 : : "conindid = i.indexrelid AND "
2271 : : "contype IN ('p','u','x') AND "
2272 : : "condeferred) AS condeferred,\n");
2273 : :
3810 rhaas@postgresql.org 2274 [ + - ]: 194 : if (pset.sversion >= 90400)
1746 drowley@postgresql.o 2275 : 194 : appendPQExpBufferStr(&buf, "i.indisreplident,\n");
2276 : : else
1746 drowley@postgresql.o 2277 :UBC 0 : appendPQExpBufferStr(&buf, "false AS indisreplident,\n");
2278 : :
801 peter@eisentraut.org 2279 [ + - ]:CBC 194 : if (pset.sversion >= 150000)
2280 : 194 : appendPQExpBufferStr(&buf, "i.indnullsnotdistinct,\n");
2281 : : else
801 peter@eisentraut.org 2282 :UBC 0 : appendPQExpBufferStr(&buf, "false AS indnullsnotdistinct,\n");
2283 : :
5373 tgl@sss.pgh.pa.us 2284 :CBC 194 : appendPQExpBuffer(&buf, " a.amname, c2.relname, "
2285 : : "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
2286 : : "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
2287 : : "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
2288 : : "AND i.indrelid = c2.oid;",
2289 : : oid);
2290 : :
3461 fujii@postgresql.org 2291 : 194 : result = PSQLexec(buf.data);
8026 peter_e@gmx.net 2292 [ - + ]: 194 : if (!result)
8026 peter_e@gmx.net 2293 :UBC 0 : goto error_return;
8026 peter_e@gmx.net 2294 [ - + ]:CBC 194 : else if (PQntuples(result) != 1)
2295 : : {
8026 peter_e@gmx.net 2296 :UBC 0 : PQclear(result);
2297 : 0 : goto error_return;
2298 : : }
2299 : : else
2300 : : {
8207 bruce@momjian.us 2301 :CBC 194 : char *indisunique = PQgetvalue(result, 0, 0);
2302 : 194 : char *indisprimary = PQgetvalue(result, 0, 1);
7313 2303 : 194 : char *indisclustered = PQgetvalue(result, 0, 2);
6442 tgl@sss.pgh.pa.us 2304 : 194 : char *indisvalid = PQgetvalue(result, 0, 3);
5373 2305 : 194 : char *deferrable = PQgetvalue(result, 0, 4);
2306 : 194 : char *deferred = PQgetvalue(result, 0, 5);
3804 2307 : 194 : char *indisreplident = PQgetvalue(result, 0, 6);
801 peter@eisentraut.org 2308 : 194 : char *indnullsnotdistinct = PQgetvalue(result, 0, 7);
2309 : 194 : char *indamname = PQgetvalue(result, 0, 8);
2310 : 194 : char *indtable = PQgetvalue(result, 0, 9);
2311 : 194 : char *indpred = PQgetvalue(result, 0, 10);
2312 : :
8026 peter_e@gmx.net 2313 [ + + ]: 194 : if (strcmp(indisprimary, "t") == 0)
7124 2314 : 42 : printfPQExpBuffer(&tmpbuf, _("primary key, "));
8026 2315 [ + + ]: 152 : else if (strcmp(indisunique, "t") == 0)
2316 : : {
801 peter@eisentraut.org 2317 : 51 : printfPQExpBuffer(&tmpbuf, _("unique"));
2318 [ + + ]: 51 : if (strcmp(indnullsnotdistinct, "t") == 0)
2319 : 3 : appendPQExpBufferStr(&tmpbuf, _(" nulls not distinct"));
586 drowley@postgresql.o 2320 : 51 : appendPQExpBufferStr(&tmpbuf, _(", "));
2321 : : }
2322 : : else
8026 peter_e@gmx.net 2323 : 101 : resetPQExpBuffer(&tmpbuf);
2324 : 194 : appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
2325 : :
2326 : : /* we assume here that index and table are in same schema */
7918 tgl@sss.pgh.pa.us 2327 : 194 : appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
2328 : : schemaname, indtable);
2329 : :
8026 peter_e@gmx.net 2330 [ - + ]: 194 : if (strlen(indpred))
7399 db@zigo.dhs.org 2331 :UBC 0 : appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
2332 : :
7313 bruce@momjian.us 2333 [ - + ]:CBC 194 : if (strcmp(indisclustered, "t") == 0)
3800 heikki.linnakangas@i 2334 :UBC 0 : appendPQExpBufferStr(&tmpbuf, _(", clustered"));
2335 : :
6442 tgl@sss.pgh.pa.us 2336 [ - + ]:CBC 194 : if (strcmp(indisvalid, "t") != 0)
3800 heikki.linnakangas@i 2337 :UBC 0 : appendPQExpBufferStr(&tmpbuf, _(", invalid"));
2338 : :
5373 tgl@sss.pgh.pa.us 2339 [ - + ]:CBC 194 : if (strcmp(deferrable, "t") == 0)
3800 heikki.linnakangas@i 2340 :UBC 0 : appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
2341 : :
5373 tgl@sss.pgh.pa.us 2342 [ - + ]:CBC 194 : if (strcmp(deferred, "t") == 0)
3800 heikki.linnakangas@i 2343 :UBC 0 : appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
2344 : :
3804 tgl@sss.pgh.pa.us 2345 [ - + ]:CBC 194 : if (strcmp(indisreplident, "t") == 0)
1746 drowley@postgresql.o 2346 :UBC 0 : appendPQExpBufferStr(&tmpbuf, _(", replica identity"));
2347 : :
5816 alvherre@alvh.no-ip. 2348 :CBC 194 : printTableAddFooter(&cont, tmpbuf.data);
2349 : :
2350 : : /*
2351 : : * If it's a partitioned index, we'll print the tablespace below
2352 : : */
1727 tgl@sss.pgh.pa.us 2353 [ + + ]: 194 : if (tableinfo.relkind == RELKIND_INDEX)
2354 : 128 : add_tablespace_footer(&cont, tableinfo.relkind,
2355 : : tableinfo.tablespace, true);
2356 : : }
2357 : :
8272 2358 : 194 : PQclear(result);
2359 : : }
2360 : : /* If you add relkinds here, see also "Finish printing..." stanza below */
2593 2361 [ + + ]: 1519 : else if (tableinfo.relkind == RELKIND_RELATION ||
2362 [ + + ]: 463 : tableinfo.relkind == RELKIND_MATVIEW ||
2363 [ + + ]: 433 : tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1727 2364 [ + + ]: 340 : tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
2365 [ + - ]: 217 : tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
2366 [ + + ]: 217 : tableinfo.relkind == RELKIND_TOASTVALUE)
2367 : : {
2368 : : /* Footer information about a table */
5816 alvherre@alvh.no-ip. 2369 : 1305 : PGresult *result = NULL;
2370 : 1305 : int tuples = 0;
2371 : :
2372 : : /* print indexes */
8026 peter_e@gmx.net 2373 [ + + ]: 1305 : if (tableinfo.hasindex)
2374 : : {
2375 : 429 : printfPQExpBuffer(&buf,
2376 : : "SELECT c2.relname, i.indisprimary, i.indisunique, "
2377 : : "i.indisclustered, i.indisvalid, "
2378 : : "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n "
2379 : : "pg_catalog.pg_get_constraintdef(con.oid, true), "
2380 : : "contype, condeferrable, condeferred");
3810 rhaas@postgresql.org 2381 [ + - ]: 429 : if (pset.sversion >= 90400)
3800 heikki.linnakangas@i 2382 : 429 : appendPQExpBufferStr(&buf, ", i.indisreplident");
2383 : : else
3800 heikki.linnakangas@i 2384 :UBC 0 : appendPQExpBufferStr(&buf, ", false AS indisreplident");
850 tgl@sss.pgh.pa.us 2385 :CBC 429 : appendPQExpBufferStr(&buf, ", c2.reltablespace");
81 peter@eisentraut.org 2386 [ + - ]:GNC 429 : if (pset.sversion >= 170000)
40 2387 : 429 : appendPQExpBufferStr(&buf, ", con.conperiod");
2388 : : else
40 peter@eisentraut.org 2389 :UNC 0 : appendPQExpBufferStr(&buf, ", false AS conperiod");
5148 tgl@sss.pgh.pa.us 2390 :CBC 429 : appendPQExpBuffer(&buf,
2391 : : "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
2392 : : " LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n"
2393 : : "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
2394 : : "ORDER BY i.indisprimary DESC, c2.relname;",
2395 : : oid);
3461 fujii@postgresql.org 2396 : 429 : result = PSQLexec(buf.data);
5816 alvherre@alvh.no-ip. 2397 [ - + ]: 429 : if (!result)
8026 peter_e@gmx.net 2398 :UBC 0 : goto error_return;
2399 : : else
5816 alvherre@alvh.no-ip. 2400 :CBC 429 : tuples = PQntuples(result);
2401 : :
2402 [ + + ]: 429 : if (tuples > 0)
2403 : : {
2404 : 414 : printTableAddFooter(&cont, _("Indexes:"));
2405 [ + + ]: 1101 : for (i = 0; i < tuples; i++)
2406 : : {
2407 : : /* untranslated index name */
2408 : 687 : printfPQExpBuffer(&buf, " \"%s\"",
2409 : : PQgetvalue(result, i, 0));
2410 : :
2411 : : /*
2412 : : * If exclusion constraint or PK/UNIQUE constraint WITHOUT
2413 : : * OVERLAPS, print the constraintdef
2414 : : */
81 peter@eisentraut.org 2415 [ + + ]:GNC 687 : if (strcmp(PQgetvalue(result, i, 7), "x") == 0 ||
2416 [ + + ]: 660 : strcmp(PQgetvalue(result, i, 12), "t") == 0)
2417 : : {
5148 tgl@sss.pgh.pa.us 2418 :CBC 62 : appendPQExpBuffer(&buf, " %s",
2419 : : PQgetvalue(result, i, 6));
2420 : : }
2421 : : else
2422 : : {
2423 : : const char *indexdef;
2424 : : const char *usingpos;
2425 : :
2426 : : /* Label as primary key or unique (but not both) */
2427 [ + + ]: 625 : if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
3800 heikki.linnakangas@i 2428 : 178 : appendPQExpBufferStr(&buf, " PRIMARY KEY,");
5148 tgl@sss.pgh.pa.us 2429 [ + + ]: 447 : else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
2430 : : {
5005 rhaas@postgresql.org 2431 [ + + ]: 165 : if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
3800 heikki.linnakangas@i 2432 : 72 : appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
2433 : : else
2434 : 93 : appendPQExpBufferStr(&buf, " UNIQUE,");
2435 : : }
2436 : :
2437 : : /* Everything after "USING" is echoed verbatim */
5148 tgl@sss.pgh.pa.us 2438 : 625 : indexdef = PQgetvalue(result, i, 5);
2439 : 625 : usingpos = strstr(indexdef, " USING ");
2440 [ + - ]: 625 : if (usingpos)
2441 : 625 : indexdef = usingpos + 7;
2442 : 625 : appendPQExpBuffer(&buf, " %s", indexdef);
2443 : :
2444 : : /* Need these for deferrable PK/UNIQUE indexes */
2445 [ + + ]: 625 : if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
3800 heikki.linnakangas@i 2446 : 27 : appendPQExpBufferStr(&buf, " DEFERRABLE");
2447 : :
5148 tgl@sss.pgh.pa.us 2448 [ + + ]: 625 : if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
3800 heikki.linnakangas@i 2449 :GBC 9 : appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
2450 : : }
2451 : :
2452 : : /* Add these for all cases */
5816 alvherre@alvh.no-ip. 2453 [ - + ]:CBC 687 : if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
3800 heikki.linnakangas@i 2454 :UBC 0 : appendPQExpBufferStr(&buf, " CLUSTER");
2455 : :
5816 alvherre@alvh.no-ip. 2456 [ + + ]:CBC 687 : if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
3800 heikki.linnakangas@i 2457 : 21 : appendPQExpBufferStr(&buf, " INVALID");
2458 : :
3810 rhaas@postgresql.org 2459 [ + + ]: 687 : if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
1746 drowley@postgresql.o 2460 : 27 : appendPQExpBufferStr(&buf, " REPLICA IDENTITY");
2461 : :
5816 alvherre@alvh.no-ip. 2462 : 687 : printTableAddFooter(&cont, buf.data);
2463 : :
2464 : : /* Print tablespace of the index on the same line */
850 tgl@sss.pgh.pa.us 2465 : 687 : add_tablespace_footer(&cont, RELKIND_INDEX,
2466 : 687 : atooid(PQgetvalue(result, i, 11)),
2467 : : false);
2468 : : }
2469 : : }
5816 alvherre@alvh.no-ip. 2470 : 429 : PQclear(result);
2471 : : }
2472 : :
2473 : : /* print table (and column) check constraints */
8026 peter_e@gmx.net 2474 [ + + ]: 1305 : if (tableinfo.checks)
2475 : : {
2476 : 195 : printfPQExpBuffer(&buf,
2477 : : "SELECT r.conname, "
2478 : : "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
2479 : : "FROM pg_catalog.pg_constraint r\n"
2480 : : "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
2481 : : "ORDER BY 1;",
2482 : : oid);
3461 fujii@postgresql.org 2483 : 195 : result = PSQLexec(buf.data);
5816 alvherre@alvh.no-ip. 2484 [ - + ]: 195 : if (!result)
8026 peter_e@gmx.net 2485 :UBC 0 : goto error_return;
2486 : : else
5816 alvherre@alvh.no-ip. 2487 :CBC 195 : tuples = PQntuples(result);
2488 : :
2489 [ + - ]: 195 : if (tuples > 0)
2490 : : {
2491 : 195 : printTableAddFooter(&cont, _("Check constraints:"));
2492 [ + + ]: 489 : for (i = 0; i < tuples; i++)
2493 : : {
2494 : : /* untranslated constraint name and def */
4377 2495 : 294 : printfPQExpBuffer(&buf, " \"%s\" %s",
2496 : : PQgetvalue(result, i, 0),
2497 : : PQgetvalue(result, i, 1));
2498 : :
5816 2499 : 294 : printTableAddFooter(&cont, buf.data);
2500 : : }
2501 : : }
2502 : 195 : PQclear(result);
2503 : : }
2504 : :
2505 : : /*
2506 : : * Print foreign-key constraints (there are none if no triggers,
2507 : : * except if the table is partitioned, in which case the triggers
2508 : : * appear in the partitions)
2509 : : */
2162 2510 [ + + ]: 1305 : if (tableinfo.hastriggers ||
2511 [ + + ]: 1172 : tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
2512 : : {
1846 2513 [ + - ]: 244 : if (pset.sversion >= 120000 &&
2514 [ + + + + ]: 244 : (tableinfo.ispartition || tableinfo.relkind == RELKIND_PARTITIONED_TABLE))
2515 : : {
2516 : : /*
2517 : : * Put the constraints defined in this table first, followed
2518 : : * by the constraints defined in ancestor partitioned tables.
2519 : : */
2520 : 150 : printfPQExpBuffer(&buf,
2521 : : "SELECT conrelid = '%s'::pg_catalog.regclass AS sametable,\n"
2522 : : " conname,\n"
2523 : : " pg_catalog.pg_get_constraintdef(oid, true) AS condef,\n"
2524 : : " conrelid::pg_catalog.regclass AS ontable\n"
2525 : : " FROM pg_catalog.pg_constraint,\n"
2526 : : " pg_catalog.pg_partition_ancestors('%s')\n"
2527 : : " WHERE conrelid = relid AND contype = 'f' AND conparentid = 0\n"
2528 : : "ORDER BY sametable DESC, conname;",
2529 : : oid, oid);
2530 : : }
2531 : : else
2532 : : {
2533 : 94 : printfPQExpBuffer(&buf,
2534 : : "SELECT true as sametable, conname,\n"
2535 : : " pg_catalog.pg_get_constraintdef(r.oid, true) as condef,\n"
2536 : : " conrelid::pg_catalog.regclass AS ontable\n"
2537 : : "FROM pg_catalog.pg_constraint r\n"
2538 : : "WHERE r.conrelid = '%s' AND r.contype = 'f'\n",
2539 : : oid);
2540 : :
1838 2541 [ + - ]: 94 : if (pset.sversion >= 120000)
1746 drowley@postgresql.o 2542 : 94 : appendPQExpBufferStr(&buf, " AND conparentid = 0\n");
2543 : 94 : appendPQExpBufferStr(&buf, "ORDER BY conname");
2544 : : }
2545 : :
3461 fujii@postgresql.org 2546 : 244 : result = PSQLexec(buf.data);
5816 alvherre@alvh.no-ip. 2547 [ - + ]: 244 : if (!result)
7912 tgl@sss.pgh.pa.us 2548 :UBC 0 : goto error_return;
2549 : : else
5816 alvherre@alvh.no-ip. 2550 :CBC 244 : tuples = PQntuples(result);
2551 : :
2552 [ + + ]: 244 : if (tuples > 0)
2553 : : {
1846 2554 : 82 : int i_sametable = PQfnumber(result, "sametable"),
2555 : 82 : i_conname = PQfnumber(result, "conname"),
2556 : 82 : i_condef = PQfnumber(result, "condef"),
2557 : 82 : i_ontable = PQfnumber(result, "ontable");
2558 : :
5816 2559 : 82 : printTableAddFooter(&cont, _("Foreign-key constraints:"));
2560 [ + + ]: 182 : for (i = 0; i < tuples; i++)
2561 : : {
2562 : : /*
2563 : : * Print untranslated constraint name and definition. Use
2564 : : * a "TABLE tab" prefix when the constraint is defined in
2565 : : * a parent partitioned table.
2566 : : */
1846 2567 [ + + ]: 100 : if (strcmp(PQgetvalue(result, i, i_sametable), "f") == 0)
2568 : 39 : printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
2569 : : PQgetvalue(result, i, i_ontable),
2570 : : PQgetvalue(result, i, i_conname),
2571 : : PQgetvalue(result, i, i_condef));
2572 : : else
2573 : 61 : printfPQExpBuffer(&buf, " \"%s\" %s",
2574 : : PQgetvalue(result, i, i_conname),
2575 : : PQgetvalue(result, i, i_condef));
2576 : :
5816 2577 : 100 : printTableAddFooter(&cont, buf.data);
2578 : : }
2579 : : }
2580 : 244 : PQclear(result);
2581 : : }
2582 : :
2583 : : /* print incoming foreign-key references */
1846 2584 [ + + ]: 1305 : if (tableinfo.hastriggers ||
2585 [ + + ]: 1172 : tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
2586 : : {
2587 [ + - ]: 244 : if (pset.sversion >= 120000)
2588 : : {
2589 : 244 : printfPQExpBuffer(&buf,
2590 : : "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
2591 : : " pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
2592 : : " FROM pg_catalog.pg_constraint c\n"
2593 : : " WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('%s')\n"
2594 : : " UNION ALL VALUES ('%s'::pg_catalog.regclass))\n"
2595 : : " AND contype = 'f' AND conparentid = 0\n"
2596 : : "ORDER BY conname;",
2597 : : oid, oid);
2598 : : }
2599 : : else
2600 : : {
1846 alvherre@alvh.no-ip. 2601 :UBC 0 : printfPQExpBuffer(&buf,
2602 : : "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
2603 : : " pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
2604 : : " FROM pg_catalog.pg_constraint\n"
2605 : : " WHERE confrelid = %s AND contype = 'f'\n"
2606 : : "ORDER BY conname;",
2607 : : oid);
2608 : : }
2609 : :
3461 fujii@postgresql.org 2610 :CBC 244 : result = PSQLexec(buf.data);
5816 alvherre@alvh.no-ip. 2611 [ - + ]: 244 : if (!result)
5859 tgl@sss.pgh.pa.us 2612 :UBC 0 : goto error_return;
2613 : : else
5816 alvherre@alvh.no-ip. 2614 :CBC 244 : tuples = PQntuples(result);
2615 : :
2616 [ + + ]: 244 : if (tuples > 0)
2617 : : {
1846 2618 : 30 : int i_conname = PQfnumber(result, "conname"),
2619 : 30 : i_ontable = PQfnumber(result, "ontable"),
2620 : 30 : i_condef = PQfnumber(result, "condef");
2621 : :
5816 2622 : 30 : printTableAddFooter(&cont, _("Referenced by:"));
2623 [ + + ]: 60 : for (i = 0; i < tuples; i++)
2624 : : {
5419 peter_e@gmx.net 2625 : 30 : printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
2626 : : PQgetvalue(result, i, i_ontable),
2627 : : PQgetvalue(result, i, i_conname),
2628 : : PQgetvalue(result, i, i_condef));
2629 : :
5816 alvherre@alvh.no-ip. 2630 : 30 : printTableAddFooter(&cont, buf.data);
2631 : : }
2632 : : }
2633 : 244 : PQclear(result);
2634 : : }
2635 : :
2636 : : /* print any row-level policies */
3495 sfrost@snowman.net 2637 [ + - ]: 1305 : if (pset.sversion >= 90500)
2638 : : {
2454 tgl@sss.pgh.pa.us 2639 : 1305 : printfPQExpBuffer(&buf, "SELECT pol.polname,");
2687 sfrost@snowman.net 2640 [ + - ]: 1305 : if (pset.sversion >= 100000)
1746 drowley@postgresql.o 2641 : 1305 : appendPQExpBufferStr(&buf,
2642 : : " pol.polpermissive,\n");
2643 : : else
1746 drowley@postgresql.o 2644 :UBC 0 : appendPQExpBufferStr(&buf,
2645 : : " 't' as polpermissive,\n");
2454 tgl@sss.pgh.pa.us 2646 :CBC 1305 : appendPQExpBuffer(&buf,
2647 : : " CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
2648 : : " pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
2649 : : " pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
2650 : : " CASE pol.polcmd\n"
2651 : : " WHEN 'r' THEN 'SELECT'\n"
2652 : : " WHEN 'a' THEN 'INSERT'\n"
2653 : : " WHEN 'w' THEN 'UPDATE'\n"
2654 : : " WHEN 'd' THEN 'DELETE'\n"
2655 : : " END AS cmd\n"
2656 : : "FROM pg_catalog.pg_policy pol\n"
2657 : : "WHERE pol.polrelid = '%s' ORDER BY 1;",
2658 : : oid);
2659 : :
3461 fujii@postgresql.org 2660 : 1305 : result = PSQLexec(buf.data);
3495 sfrost@snowman.net 2661 [ - + ]: 1305 : if (!result)
3495 sfrost@snowman.net 2662 :UBC 0 : goto error_return;
2663 : : else
3495 sfrost@snowman.net 2664 :CBC 1305 : tuples = PQntuples(result);
2665 : :
2666 : : /*
2667 : : * Handle cases where RLS is enabled and there are policies, or
2668 : : * there aren't policies, or RLS isn't enabled but there are
2669 : : * policies
2670 : : */
3115 2671 [ + + + - : 1305 : if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
+ - ]
3495 2672 : 6 : printTableAddFooter(&cont, _("Policies:"));
2673 : :
3115 2674 [ + + - + : 1305 : if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
- - ]
3038 peter_e@gmx.net 2675 :UBC 0 : printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
2676 : :
3115 sfrost@snowman.net 2677 [ + + + - :CBC 1305 : if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
- + ]
3038 peter_e@gmx.net 2678 :UBC 0 : printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
2679 : :
3115 sfrost@snowman.net 2680 [ + + - + :CBC 1305 : if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
- - ]
3038 peter_e@gmx.net 2681 :UBC 0 : printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
2682 : :
3490 sfrost@snowman.net 2683 [ + + - + ]:CBC 1305 : if (!tableinfo.rowsecurity && tuples > 0)
3038 peter_e@gmx.net 2684 :UBC 0 : printTableAddFooter(&cont, _("Policies (row security disabled):"));
2685 : :
2686 : : /* Might be an empty set - that's ok */
3490 sfrost@snowman.net 2687 [ + + ]:CBC 1320 : for (i = 0; i < tuples; i++)
2688 : : {
2689 : 15 : printfPQExpBuffer(&buf, " POLICY \"%s\"",
2690 : : PQgetvalue(result, i, 0));
2691 : :
2687 2692 [ + + ]: 15 : if (*(PQgetvalue(result, i, 1)) == 'f')
1746 drowley@postgresql.o 2693 : 9 : appendPQExpBufferStr(&buf, " AS RESTRICTIVE");
2694 : :
2687 sfrost@snowman.net 2695 [ - + ]: 15 : if (!PQgetisnull(result, i, 5))
3481 sfrost@snowman.net 2696 :UBC 0 : appendPQExpBuffer(&buf, " FOR %s",
2697 : : PQgetvalue(result, i, 5));
2698 : :
2687 sfrost@snowman.net 2699 [ + + ]:CBC 15 : if (!PQgetisnull(result, i, 2))
2700 : : {
3481 2701 : 9 : appendPQExpBuffer(&buf, "\n TO %s",
2702 : : PQgetvalue(result, i, 2));
2703 : : }
2704 : :
2687 2705 [ + - ]: 15 : if (!PQgetisnull(result, i, 3))
3177 mail@joeconway.com 2706 : 15 : appendPQExpBuffer(&buf, "\n USING (%s)",
2707 : : PQgetvalue(result, i, 3));
2708 : :
2687 sfrost@snowman.net 2709 [ - + ]: 15 : if (!PQgetisnull(result, i, 4))
3177 mail@joeconway.com 2710 :UBC 0 : appendPQExpBuffer(&buf, "\n WITH CHECK (%s)",
2711 : : PQgetvalue(result, i, 4));
2712 : :
3490 sfrost@snowman.net 2713 :CBC 15 : printTableAddFooter(&cont, buf.data);
2714 : : }
3495 2715 : 1305 : PQclear(result);
2716 : : }
2717 : :
2718 : : /* print any extended statistics */
1115 tomas.vondra@postgre 2719 [ + - ]: 1305 : if (pset.sversion >= 140000)
2720 : : {
2721 : 1305 : printfPQExpBuffer(&buf,
2722 : : "SELECT oid, "
2723 : : "stxrelid::pg_catalog.regclass, "
2724 : : "stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS nsp, "
2725 : : "stxname,\n"
2726 : : "pg_catalog.pg_get_statisticsobjdef_columns(oid) AS columns,\n"
2727 : : " 'd' = any(stxkind) AS ndist_enabled,\n"
2728 : : " 'f' = any(stxkind) AS deps_enabled,\n"
2729 : : " 'm' = any(stxkind) AS mcv_enabled,\n"
2730 : : "stxstattarget\n"
2731 : : "FROM pg_catalog.pg_statistic_ext\n"
2732 : : "WHERE stxrelid = '%s'\n"
2733 : : "ORDER BY nsp, stxname;",
2734 : : oid);
2735 : :
2736 : 1305 : result = PSQLexec(buf.data);
2737 [ - + ]: 1305 : if (!result)
1115 tomas.vondra@postgre 2738 :UBC 0 : goto error_return;
2739 : : else
1115 tomas.vondra@postgre 2740 :CBC 1305 : tuples = PQntuples(result);
2741 : :
2742 [ + + ]: 1305 : if (tuples > 0)
2743 : : {
2744 : 18 : printTableAddFooter(&cont, _("Statistics objects:"));
2745 : :
2746 [ + + ]: 45 : for (i = 0; i < tuples; i++)
2747 : : {
2748 : 27 : bool gotone = false;
2749 : : bool has_ndistinct;
2750 : : bool has_dependencies;
2751 : : bool has_mcv;
2752 : : bool has_all;
2753 : : bool has_some;
2754 : :
2755 : 27 : has_ndistinct = (strcmp(PQgetvalue(result, i, 5), "t") == 0);
2756 : 27 : has_dependencies = (strcmp(PQgetvalue(result, i, 6), "t") == 0);
2757 : 27 : has_mcv = (strcmp(PQgetvalue(result, i, 7), "t") == 0);
2758 : :
2759 : 27 : printfPQExpBuffer(&buf, " ");
2760 : :
2761 : : /* statistics object name (qualified with namespace) */
958 alvherre@alvh.no-ip. 2762 : 27 : appendPQExpBuffer(&buf, "\"%s.%s\"",
2763 : : PQgetvalue(result, i, 2),
2764 : : PQgetvalue(result, i, 3));
2765 : :
2766 : : /*
2767 : : * When printing kinds we ignore expression statistics,
2768 : : * which are used only internally and can't be specified
2769 : : * by user. We don't print the kinds when none are
2770 : : * specified (in which case it has to be statistics on a
2771 : : * single expr) or when all are specified (in which case
2772 : : * we assume it's expanded by CREATE STATISTICS).
2773 : : */
1115 tomas.vondra@postgre 2774 [ + + + - : 27 : has_all = (has_ndistinct && has_dependencies && has_mcv);
+ - ]
2775 [ + + + - : 27 : has_some = (has_ndistinct || has_dependencies || has_mcv);
- + ]
2776 : :
2777 [ + + - + ]: 27 : if (has_some && !has_all)
2778 : : {
1046 drowley@postgresql.o 2779 :UBC 0 : appendPQExpBufferStr(&buf, " (");
2780 : :
2781 : : /* options */
1115 tomas.vondra@postgre 2782 [ # # ]: 0 : if (has_ndistinct)
2783 : : {
2784 : 0 : appendPQExpBufferStr(&buf, "ndistinct");
2785 : 0 : gotone = true;
2786 : : }
2787 : :
2788 [ # # ]: 0 : if (has_dependencies)
2789 : : {
2790 [ # # ]: 0 : appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
2791 : 0 : gotone = true;
2792 : : }
2793 : :
2794 [ # # ]: 0 : if (has_mcv)
2795 : : {
2796 [ # # ]: 0 : appendPQExpBuffer(&buf, "%smcv", gotone ? ", " : "");
2797 : : }
2798 : :
1046 drowley@postgresql.o 2799 : 0 : appendPQExpBufferChar(&buf, ')');
2800 : : }
2801 : :
1115 tomas.vondra@postgre 2802 :CBC 27 : appendPQExpBuffer(&buf, " ON %s FROM %s",
2803 : : PQgetvalue(result, i, 4),
2804 : : PQgetvalue(result, i, 1));
2805 : :
2806 : : /* Show the stats target if it's not default */
28 peter@eisentraut.org 2807 [ + + ]:GNC 27 : if (!PQgetisnull(result, i, 8) &&
2808 [ + - ]: 3 : strcmp(PQgetvalue(result, i, 8), "-1") != 0)
1115 tomas.vondra@postgre 2809 :CBC 3 : appendPQExpBuffer(&buf, "; STATISTICS %s",
2810 : : PQgetvalue(result, i, 8));
2811 : :
2812 : 27 : printTableAddFooter(&cont, buf.data);
2813 : : }
2814 : : }
2815 : 1305 : PQclear(result);
2816 : : }
1115 tomas.vondra@postgre 2817 [ # # ]:UBC 0 : else if (pset.sversion >= 100000)
2818 : : {
2578 alvherre@alvh.no-ip. 2819 : 0 : printfPQExpBuffer(&buf,
2820 : : "SELECT oid, "
2821 : : "stxrelid::pg_catalog.regclass, "
2822 : : "stxnamespace::pg_catalog.regnamespace AS nsp, "
2823 : : "stxname,\n"
2824 : : " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(attname),', ')\n"
2825 : : " FROM pg_catalog.unnest(stxkeys) s(attnum)\n"
2826 : : " JOIN pg_catalog.pg_attribute a ON (stxrelid = a.attrelid AND\n"
2827 : : " a.attnum = s.attnum AND NOT attisdropped)) AS columns,\n"
2828 : : " 'd' = any(stxkind) AS ndist_enabled,\n"
2829 : : " 'f' = any(stxkind) AS deps_enabled,\n"
2830 : : " 'm' = any(stxkind) AS mcv_enabled,\n");
2831 : :
1311 2832 [ # # ]: 0 : if (pset.sversion >= 130000)
2833 : 0 : appendPQExpBufferStr(&buf, " stxstattarget\n");
2834 : : else
2835 : 0 : appendPQExpBufferStr(&buf, " -1 AS stxstattarget\n");
827 michael@paquier.xyz 2836 : 0 : appendPQExpBuffer(&buf, "FROM pg_catalog.pg_statistic_ext\n"
2837 : : "WHERE stxrelid = '%s'\n"
2838 : : "ORDER BY 1;",
2839 : : oid);
2840 : :
2578 alvherre@alvh.no-ip. 2841 : 0 : result = PSQLexec(buf.data);
2842 [ # # ]: 0 : if (!result)
2843 : 0 : goto error_return;
2844 : : else
2845 : 0 : tuples = PQntuples(result);
2846 : :
2847 [ # # ]: 0 : if (tuples > 0)
2848 : : {
2527 tgl@sss.pgh.pa.us 2849 : 0 : printTableAddFooter(&cont, _("Statistics objects:"));
2850 : :
2578 alvherre@alvh.no-ip. 2851 [ # # ]: 0 : for (i = 0; i < tuples; i++)
2852 : : {
2566 simon@2ndQuadrant.co 2853 : 0 : bool gotone = false;
2854 : :
2578 alvherre@alvh.no-ip. 2855 : 0 : printfPQExpBuffer(&buf, " ");
2856 : :
2857 : : /* statistics object name (qualified with namespace) */
958 2858 : 0 : appendPQExpBuffer(&buf, "\"%s.%s\" (",
2859 : : PQgetvalue(result, i, 2),
2860 : : PQgetvalue(result, i, 3));
2861 : :
2862 : : /* options */
2578 2863 [ # # ]: 0 : if (strcmp(PQgetvalue(result, i, 5), "t") == 0)
2864 : : {
2865 : 0 : appendPQExpBufferStr(&buf, "ndistinct");
2566 simon@2ndQuadrant.co 2866 : 0 : gotone = true;
2867 : : }
2868 : :
2869 [ # # ]: 0 : if (strcmp(PQgetvalue(result, i, 6), "t") == 0)
2870 : : {
2871 [ # # ]: 0 : appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
1845 tomas.vondra@postgre 2872 : 0 : gotone = true;
2873 : : }
2874 : :
2875 [ # # ]: 0 : if (strcmp(PQgetvalue(result, i, 7), "t") == 0)
2876 : : {
2877 [ # # ]: 0 : appendPQExpBuffer(&buf, "%smcv", gotone ? ", " : "");
2878 : : }
2879 : :
2529 alvherre@alvh.no-ip. 2880 : 0 : appendPQExpBuffer(&buf, ") ON %s FROM %s",
2881 : : PQgetvalue(result, i, 4),
2882 : : PQgetvalue(result, i, 1));
2883 : :
2884 : : /* Show the stats target if it's not default */
1311 2885 [ # # ]: 0 : if (strcmp(PQgetvalue(result, i, 8), "-1") != 0)
2886 : 0 : appendPQExpBuffer(&buf, "; STATISTICS %s",
2887 : : PQgetvalue(result, i, 8));
2888 : :
2578 2889 : 0 : printTableAddFooter(&cont, buf.data);
2890 : : }
2891 : : }
2892 : 0 : PQclear(result);
2893 : : }
2894 : :
2895 : : /* print rules */
2593 tgl@sss.pgh.pa.us 2896 [ + + + + ]:CBC 1305 : if (tableinfo.hasrules && tableinfo.relkind != RELKIND_MATVIEW)
2897 : : {
850 2898 : 18 : printfPQExpBuffer(&buf,
2899 : : "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
2900 : : "ev_enabled\n"
2901 : : "FROM pg_catalog.pg_rewrite r\n"
2902 : : "WHERE r.ev_class = '%s' ORDER BY 1;",
2903 : : oid);
3461 fujii@postgresql.org 2904 : 18 : result = PSQLexec(buf.data);
5816 alvherre@alvh.no-ip. 2905 [ - + ]: 18 : if (!result)
5816 alvherre@alvh.no-ip. 2906 :UBC 0 : goto error_return;
2907 : : else
5816 alvherre@alvh.no-ip. 2908 :CBC 18 : tuples = PQntuples(result);
2909 : :
2910 [ + - ]: 18 : if (tuples > 0)
2911 : : {
2912 : : bool have_heading;
2913 : : int category;
2914 : :
2915 [ + + ]: 90 : for (category = 0; category < 4; category++)
2916 : : {
2917 : 72 : have_heading = false;
2918 : :
2919 [ + + ]: 264 : for (i = 0; i < tuples; i++)
2920 : : {
2921 : : const char *ruledef;
2922 : 192 : bool list_rule = false;
2923 : :
6236 JanWieck@Yahoo.com 2924 [ + + + + : 192 : switch (category)
- ]
2925 : : {
2926 : 48 : case 0:
5816 alvherre@alvh.no-ip. 2927 [ + - ]: 48 : if (*PQgetvalue(result, i, 2) == 'O')
2928 : 48 : list_rule = true;
6236 JanWieck@Yahoo.com 2929 : 48 : break;
2930 : 48 : case 1:
5816 alvherre@alvh.no-ip. 2931 [ - + ]: 48 : if (*PQgetvalue(result, i, 2) == 'D')
5816 alvherre@alvh.no-ip. 2932 :UBC 0 : list_rule = true;
6236 JanWieck@Yahoo.com 2933 :CBC 48 : break;
2934 : 48 : case 2:
5816 alvherre@alvh.no-ip. 2935 [ - + ]: 48 : if (*PQgetvalue(result, i, 2) == 'A')
5816 alvherre@alvh.no-ip. 2936 :UBC 0 : list_rule = true;
6236 JanWieck@Yahoo.com 2937 :CBC 48 : break;
2938 : 48 : case 3:
5816 alvherre@alvh.no-ip. 2939 [ - + ]: 48 : if (*PQgetvalue(result, i, 2) == 'R')
5816 alvherre@alvh.no-ip. 2940 :UBC 0 : list_rule = true;
6236 JanWieck@Yahoo.com 2941 :CBC 48 : break;
2942 : : }
5816 alvherre@alvh.no-ip. 2943 [ + + ]: 192 : if (!list_rule)
2944 : 144 : continue;
2945 : :
2946 [ + + ]: 48 : if (!have_heading)
2947 : : {
2948 [ + - - - : 18 : switch (category)
- ]
2949 : : {
2950 : 18 : case 0:
2951 : 18 : printfPQExpBuffer(&buf, _("Rules:"));
2952 : 18 : break;
5816 alvherre@alvh.no-ip. 2953 :UBC 0 : case 1:
2954 : 0 : printfPQExpBuffer(&buf, _("Disabled rules:"));
2955 : 0 : break;
2956 : 0 : case 2:
2957 : 0 : printfPQExpBuffer(&buf, _("Rules firing always:"));
2958 : 0 : break;
2959 : 0 : case 3:
2960 : 0 : printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
2961 : 0 : break;
2962 : : }
5816 alvherre@alvh.no-ip. 2963 :CBC 18 : printTableAddFooter(&cont, buf.data);
2964 : 18 : have_heading = true;
2965 : : }
2966 : :
2967 : : /* Everything after "CREATE RULE" is echoed verbatim */
2968 : 48 : ruledef = PQgetvalue(result, i, 1);
2969 : 48 : ruledef += 12;
2970 : 48 : printfPQExpBuffer(&buf, " %s", ruledef);
2971 : 48 : printTableAddFooter(&cont, buf.data);
2972 : : }
2973 : : }
2974 : : }
2975 : 18 : PQclear(result);
2976 : : }
2977 : :
2978 : : /* print any publications */
2642 peter_e@gmx.net 2979 [ + - ]: 1305 : if (pset.sversion >= 100000)
2980 : : {
900 akapila@postgresql.o 2981 [ + - ]: 1305 : if (pset.sversion >= 150000)
2982 : : {
2983 : 1305 : printfPQExpBuffer(&buf,
2984 : : "SELECT pubname\n"
2985 : : " , NULL\n"
2986 : : " , NULL\n"
2987 : : "FROM pg_catalog.pg_publication p\n"
2988 : : " JOIN pg_catalog.pg_publication_namespace pn ON p.oid = pn.pnpubid\n"
2989 : : " JOIN pg_catalog.pg_class pc ON pc.relnamespace = pn.pnnspid\n"
2990 : : "WHERE pc.oid ='%s' and pg_catalog.pg_relation_is_publishable('%s')\n"
2991 : : "UNION\n"
2992 : : "SELECT pubname\n"
2993 : : " , pg_get_expr(pr.prqual, c.oid)\n"
2994 : : " , (CASE WHEN pr.prattrs IS NOT NULL THEN\n"
2995 : : " (SELECT string_agg(attname, ', ')\n"
2996 : : " FROM pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
2997 : : " pg_catalog.pg_attribute\n"
2998 : : " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
2999 : : " ELSE NULL END) "
3000 : : "FROM pg_catalog.pg_publication p\n"
3001 : : " JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
3002 : : " JOIN pg_catalog.pg_class c ON c.oid = pr.prrelid\n"
3003 : : "WHERE pr.prrelid = '%s'\n"
3004 : : "UNION\n"
3005 : : "SELECT pubname\n"
3006 : : " , NULL\n"
3007 : : " , NULL\n"
3008 : : "FROM pg_catalog.pg_publication p\n"
3009 : : "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
3010 : : "ORDER BY 1;",
3011 : : oid, oid, oid, oid);
3012 : : }
3013 : : else
3014 : : {
900 akapila@postgresql.o 3015 :UBC 0 : printfPQExpBuffer(&buf,
3016 : : "SELECT pubname\n"
3017 : : " , NULL\n"
3018 : : " , NULL\n"
3019 : : "FROM pg_catalog.pg_publication p\n"
3020 : : "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
3021 : : "WHERE pr.prrelid = '%s'\n"
3022 : : "UNION ALL\n"
3023 : : "SELECT pubname\n"
3024 : : " , NULL\n"
3025 : : " , NULL\n"
3026 : : "FROM pg_catalog.pg_publication p\n"
3027 : : "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
3028 : : "ORDER BY 1;",
3029 : : oid, oid);
3030 : : }
3031 : :
2642 peter_e@gmx.net 3032 :CBC 1305 : result = PSQLexec(buf.data);
3033 [ - + ]: 1305 : if (!result)
2642 peter_e@gmx.net 3034 :UBC 0 : goto error_return;
3035 : : else
2642 peter_e@gmx.net 3036 :CBC 1305 : tuples = PQntuples(result);
3037 : :
3038 [ + + ]: 1305 : if (tuples > 0)
3039 : 36 : printTableAddFooter(&cont, _("Publications:"));
3040 : :
3041 : : /* Might be an empty set - that's ok */
3042 [ + + ]: 1359 : for (i = 0; i < tuples; i++)
3043 : : {
3044 : 54 : printfPQExpBuffer(&buf, " \"%s\"",
3045 : : PQgetvalue(result, i, 0));
3046 : :
3047 : : /* column list (if any) */
750 tomas.vondra@postgre 3048 [ + + ]: 54 : if (!PQgetisnull(result, i, 2))
3049 : 12 : appendPQExpBuffer(&buf, " (%s)",
3050 : : PQgetvalue(result, i, 2));
3051 : :
3052 : : /* row filter (if any) */
782 akapila@postgresql.o 3053 [ + + ]: 54 : if (!PQgetisnull(result, i, 1))
3054 : 12 : appendPQExpBuffer(&buf, " WHERE %s",
3055 : : PQgetvalue(result, i, 1));
3056 : :
2642 peter_e@gmx.net 3057 : 54 : printTableAddFooter(&cont, buf.data);
3058 : : }
3059 : 1305 : PQclear(result);
3060 : : }
3061 : :
3062 : : /* If verbose, print NOT NULL constraints */
233 alvherre@alvh.no-ip. 3063 [ + + ]:GNC 1305 : if (verbose)
3064 : : {
3065 : 550 : printfPQExpBuffer(&buf,
3066 : : "SELECT co.conname, at.attname, co.connoinherit, co.conislocal,\n"
3067 : : "co.coninhcount <> 0\n"
3068 : : "FROM pg_catalog.pg_constraint co JOIN\n"
3069 : : "pg_catalog.pg_attribute at ON\n"
3070 : : "(at.attnum = co.conkey[1])\n"
3071 : : "WHERE co.contype = 'n' AND\n"
3072 : : "co.conrelid = '%s'::pg_catalog.regclass AND\n"
3073 : : "at.attrelid = '%s'::pg_catalog.regclass\n"
3074 : : "ORDER BY at.attnum",
3075 : : oid,
3076 : : oid);
3077 : :
3078 : 550 : result = PSQLexec(buf.data);
3079 [ - + ]: 550 : if (!result)
233 alvherre@alvh.no-ip. 3080 :UNC 0 : goto error_return;
3081 : : else
233 alvherre@alvh.no-ip. 3082 :GNC 550 : tuples = PQntuples(result);
3083 : :
3084 [ + + ]: 550 : if (tuples > 0)
3085 : 271 : printTableAddFooter(&cont, _("Not-null constraints:"));
3086 : :
3087 : : /* Might be an empty set - that's ok */
3088 [ + + ]: 894 : for (i = 0; i < tuples; i++)
3089 : : {
3090 : 344 : bool islocal = PQgetvalue(result, i, 3)[0] == 't';
3091 : 344 : bool inherited = PQgetvalue(result, i, 4)[0] == 't';
3092 : :
3093 : 344 : printfPQExpBuffer(&buf, " \"%s\" NOT NULL \"%s\"%s",
3094 : : PQgetvalue(result, i, 0),
3095 : : PQgetvalue(result, i, 1),
3096 [ + + ]: 344 : PQgetvalue(result, i, 2)[0] == 't' ?
3097 : : " NO INHERIT" :
3098 [ + + + + ]: 616 : islocal && inherited ? _(" (local, inherited)") :
3099 [ + + ]: 275 : inherited ? _(" (inherited)") : "");
3100 : :
3101 : 344 : printTableAddFooter(&cont, buf.data);
3102 : : }
3103 : 550 : PQclear(result);
3104 : : }
3105 : : }
3106 : :
3107 : : /* Get view_def if table is a view or materialized view */
2096 tgl@sss.pgh.pa.us 3108 [ + + ]:CBC 1713 : if ((tableinfo.relkind == RELKIND_VIEW ||
3109 [ + + + + ]: 1713 : tableinfo.relkind == RELKIND_MATVIEW) && verbose)
3110 : : {
3111 : : PGresult *result;
3112 : :
3113 : 197 : printfPQExpBuffer(&buf,
3114 : : "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
3115 : : oid);
3116 : 197 : result = PSQLexec(buf.data);
3117 [ - + ]: 197 : if (!result)
2096 tgl@sss.pgh.pa.us 3118 :UBC 0 : goto error_return;
3119 : :
2096 tgl@sss.pgh.pa.us 3120 [ + - ]:CBC 197 : if (PQntuples(result) > 0)
3121 : 197 : view_def = pg_strdup(PQgetvalue(result, 0, 0));
3122 : :
3123 : 197 : PQclear(result);
3124 : : }
3125 : :
4060 kgrittn@postgresql.o 3126 [ + + ]: 1713 : if (view_def)
3127 : : {
3128 : 197 : PGresult *result = NULL;
3129 : :
3130 : : /* Footer information about a view */
3131 : 197 : printTableAddFooter(&cont, _("View definition:"));
3132 : 197 : printTableAddFooter(&cont, view_def);
3133 : :
3134 : : /* print rules */
3135 [ + - ]: 197 : if (tableinfo.hasrules)
3136 : : {
3137 : 197 : printfPQExpBuffer(&buf,
3138 : : "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
3139 : : "FROM pg_catalog.pg_rewrite r\n"
3140 : : "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1;",
3141 : : oid);
3461 fujii@postgresql.org 3142 : 197 : result = PSQLexec(buf.data);
4060 kgrittn@postgresql.o 3143 [ - + ]: 197 : if (!result)
4060 kgrittn@postgresql.o 3144 :UBC 0 : goto error_return;
3145 : :
4060 kgrittn@postgresql.o 3146 [ + + ]:CBC 197 : if (PQntuples(result) > 0)
3147 : : {
3148 : 6 : printTableAddFooter(&cont, _("Rules:"));
3149 [ + + ]: 12 : for (i = 0; i < PQntuples(result); i++)
3150 : : {
3151 : : const char *ruledef;
3152 : :
3153 : : /* Everything after "CREATE RULE" is echoed verbatim */
3154 : 6 : ruledef = PQgetvalue(result, i, 1);
3155 : 6 : ruledef += 12;
3156 : :
3157 : 6 : printfPQExpBuffer(&buf, " %s", ruledef);
3158 : 6 : printTableAddFooter(&cont, buf.data);
3159 : : }
3160 : : }
3161 : 197 : PQclear(result);
3162 : : }
3163 : : }
3164 : :
3165 : : /*
3166 : : * Print triggers next, if any (but only user-defined triggers). This
3167 : : * could apply to either a table or a view.
3168 : : */
4935 tgl@sss.pgh.pa.us 3169 [ + + ]: 1713 : if (tableinfo.hastriggers)
3170 : : {
3171 : : PGresult *result;
3172 : : int tuples;
3173 : :
4753 bruce@momjian.us 3174 : 139 : printfPQExpBuffer(&buf,
3175 : : "SELECT t.tgname, "
3176 : : "pg_catalog.pg_get_triggerdef(t.oid, true), "
3177 : : "t.tgenabled, t.tgisinternal,\n");
3178 : :
3179 : : /*
3180 : : * Detect whether each trigger is inherited, and if so, get the name
3181 : : * of the topmost table it's inherited from. We have no easy way to
3182 : : * do that pre-v13, for lack of the tgparentid column. Even with
3183 : : * tgparentid, a straightforward search for the topmost parent would
3184 : : * require a recursive CTE, which seems unduly expensive. We cheat a
3185 : : * bit by assuming parent triggers will match by tgname; then, joining
3186 : : * with pg_partition_ancestors() allows the planner to make use of
3187 : : * pg_trigger_tgrelid_tgname_index if it wishes. We ensure we find
3188 : : * the correct topmost parent by stopping at the first-in-partition-
3189 : : * ancestry-order trigger that has tgparentid = 0. (There might be
3190 : : * unrelated, non-inherited triggers with the same name further up the
3191 : : * stack, so this is important.)
3192 : : */
818 tgl@sss.pgh.pa.us 3193 [ + - ]: 139 : if (pset.sversion >= 130000)
3194 : 139 : appendPQExpBufferStr(&buf,
3195 : : " CASE WHEN t.tgparentid != 0 THEN\n"
3196 : : " (SELECT u.tgrelid::pg_catalog.regclass\n"
3197 : : " FROM pg_catalog.pg_trigger AS u,\n"
3198 : : " pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)\n"
3199 : : " WHERE u.tgname = t.tgname AND u.tgrelid = a.relid\n"
3200 : : " AND u.tgparentid = 0\n"
3201 : : " ORDER BY a.depth LIMIT 1)\n"
3202 : : " END AS parent\n");
3203 : : else
818 tgl@sss.pgh.pa.us 3204 :UBC 0 : appendPQExpBufferStr(&buf, " NULL AS parent\n");
3205 : :
818 tgl@sss.pgh.pa.us 3206 :CBC 139 : appendPQExpBuffer(&buf,
3207 : : "FROM pg_catalog.pg_trigger t\n"
3208 : : "WHERE t.tgrelid = '%s' AND ",
3209 : : oid);
3210 : :
3211 : : /*
3212 : : * tgisinternal is set true for inherited triggers of partitions in
3213 : : * servers between v11 and v14, though these must still be shown to
3214 : : * the user. So we use another property that is true for such
3215 : : * inherited triggers to avoid them being hidden, which is their
3216 : : * dependence on another trigger.
3217 : : */
830 alvherre@alvh.no-ip. 3218 [ + - - + ]: 139 : if (pset.sversion >= 110000 && pset.sversion < 150000)
1746 drowley@postgresql.o 3219 :UBC 0 : appendPQExpBufferStr(&buf, "(NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D') \n"
3220 : : " OR EXISTS (SELECT 1 FROM pg_catalog.pg_depend WHERE objid = t.oid \n"
3221 : : " AND refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass))");
3222 : : else
3223 : : /* display/warn about disabled internal triggers */
1746 drowley@postgresql.o 3224 :CBC 139 : appendPQExpBufferStr(&buf, "(NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))");
3800 heikki.linnakangas@i 3225 : 139 : appendPQExpBufferStr(&buf, "\nORDER BY 1;");
3226 : :
3461 fujii@postgresql.org 3227 : 139 : result = PSQLexec(buf.data);
4753 bruce@momjian.us 3228 [ - + ]: 139 : if (!result)
4753 bruce@momjian.us 3229 :UBC 0 : goto error_return;
3230 : : else
4753 bruce@momjian.us 3231 :CBC 139 : tuples = PQntuples(result);
3232 : :
3233 [ + + ]: 139 : if (tuples > 0)
3234 : : {
3235 : : bool have_heading;
3236 : : int category;
3237 : :
3238 : : /*
3239 : : * split the output into 4 different categories. Enabled triggers,
3240 : : * disabled triggers and the two special ALWAYS and REPLICA
3241 : : * configurations.
3242 : : */
3702 3243 [ + + ]: 108 : for (category = 0; category <= 4; category++)
3244 : : {
4753 3245 : 90 : have_heading = false;
3246 [ + + ]: 405 : for (i = 0; i < tuples; i++)
3247 : : {
3248 : : bool list_trigger;
3249 : : const char *tgdef;
3250 : : const char *usingpos;
3251 : : const char *tgenabled;
3252 : : const char *tgisinternal;
3253 : :
3254 : : /*
3255 : : * Check if this trigger falls into the current category
3256 : : */
3257 : 315 : tgenabled = PQgetvalue(result, i, 2);
3702 3258 : 315 : tgisinternal = PQgetvalue(result, i, 3);
4753 3259 : 315 : list_trigger = false;
3260 [ + + + + : 315 : switch (category)
+ - ]
3261 : : {
3262 : 63 : case 0:
3263 [ - + - - ]: 63 : if (*tgenabled == 'O' || *tgenabled == 't')
3264 : 63 : list_trigger = true;
3265 : 63 : break;
3266 : 63 : case 1:
3702 3267 [ + - - + ]: 63 : if ((*tgenabled == 'D' || *tgenabled == 'f') &&
3702 bruce@momjian.us 3268 [ # # ]:UBC 0 : *tgisinternal == 'f')
4753 3269 : 0 : list_trigger = true;
4753 bruce@momjian.us 3270 :CBC 63 : break;
3271 : 63 : case 2:
3702 3272 [ + - - + ]: 63 : if ((*tgenabled == 'D' || *tgenabled == 'f') &&
3702 bruce@momjian.us 3273 [ # # ]:UBC 0 : *tgisinternal == 't')
4753 3274 : 0 : list_trigger = true;
4753 bruce@momjian.us 3275 :CBC 63 : break;
3276 : 63 : case 3:
3702 3277 [ - + ]: 63 : if (*tgenabled == 'A')
3702 bruce@momjian.us 3278 :UBC 0 : list_trigger = true;
3702 bruce@momjian.us 3279 :CBC 63 : break;
3280 : 63 : case 4:
4753 3281 [ - + ]: 63 : if (*tgenabled == 'R')
4753 bruce@momjian.us 3282 :UBC 0 : list_trigger = true;
4753 bruce@momjian.us 3283 :CBC 63 : break;
3284 : : }
3285 [ + + ]: 315 : if (list_trigger == false)
3286 : 252 : continue;
3287 : :
3288 : : /* Print the category heading once */
3289 [ + + ]: 63 : if (have_heading == false)
3290 : : {
6236 JanWieck@Yahoo.com 3291 [ + - - - : 18 : switch (category)
- - ]
3292 : : {
3293 : 18 : case 0:
4753 bruce@momjian.us 3294 : 18 : printfPQExpBuffer(&buf, _("Triggers:"));
6236 JanWieck@Yahoo.com 3295 : 18 : break;
6236 JanWieck@Yahoo.com 3296 :UBC 0 : case 1:
850 tgl@sss.pgh.pa.us 3297 : 0 : printfPQExpBuffer(&buf, _("Disabled user triggers:"));
6236 JanWieck@Yahoo.com 3298 : 0 : break;
3299 : 0 : case 2:
3631 bruce@momjian.us 3300 : 0 : printfPQExpBuffer(&buf, _("Disabled internal triggers:"));
6236 JanWieck@Yahoo.com 3301 : 0 : break;
3302 : 0 : case 3:
3702 bruce@momjian.us 3303 : 0 : printfPQExpBuffer(&buf, _("Triggers firing always:"));
3304 : 0 : break;
3305 : 0 : case 4:
4753 3306 : 0 : printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
6236 JanWieck@Yahoo.com 3307 : 0 : break;
3308 : : }
5816 alvherre@alvh.no-ip. 3309 :CBC 18 : printTableAddFooter(&cont, buf.data);
4753 bruce@momjian.us 3310 : 18 : have_heading = true;
3311 : : }
3312 : :
3313 : : /* Everything after "TRIGGER" is echoed verbatim */
3314 : 63 : tgdef = PQgetvalue(result, i, 1);
3315 : 63 : usingpos = strstr(tgdef, " TRIGGER ");
3316 [ + - ]: 63 : if (usingpos)
3317 : 63 : tgdef = usingpos + 9;
3318 : :
3319 : 63 : printfPQExpBuffer(&buf, " %s", tgdef);
3320 : :
3321 : : /* Visually distinguish inherited triggers */
1454 alvherre@alvh.no-ip. 3322 [ + + ]: 63 : if (!PQgetisnull(result, i, 4))
3323 : 6 : appendPQExpBuffer(&buf, ", ON TABLE %s",
3324 : : PQgetvalue(result, i, 4));
3325 : :
4753 bruce@momjian.us 3326 : 63 : printTableAddFooter(&cont, buf.data);
3327 : : }
3328 : : }
3329 : : }
3330 : 139 : PQclear(result);
3331 : : }
3332 : :
3333 : : /*
3334 : : * Finish printing the footer information about a table.
3335 : : */
2593 tgl@sss.pgh.pa.us 3336 [ + + ]: 1713 : if (tableinfo.relkind == RELKIND_RELATION ||
3337 [ + + ]: 657 : tableinfo.relkind == RELKIND_MATVIEW ||
3338 [ + + ]: 627 : tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
1727 3339 [ + + ]: 534 : tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
3340 [ + + ]: 411 : tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
3341 [ + + ]: 345 : tableinfo.relkind == RELKIND_TOASTVALUE)
3342 : : {
3343 : : bool is_partitioned;
3344 : : PGresult *result;
3345 : : int tuples;
3346 : :
3347 : : /* simplify some repeated tests below */
3348 [ + + ]: 2619 : is_partitioned = (tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
3349 [ + + ]: 1248 : tableinfo.relkind == RELKIND_PARTITIONED_INDEX);
3350 : :
3351 : : /* print foreign server name */
2593 3352 [ + + ]: 1371 : if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
3353 : : {
3354 : : char *ftoptions;
3355 : :
3356 : : /* Footer information about foreign table */
4852 rhaas@postgresql.org 3357 : 93 : printfPQExpBuffer(&buf,
3358 : : "SELECT s.srvname,\n"
3359 : : " pg_catalog.array_to_string(ARRAY(\n"
3360 : : " SELECT pg_catalog.quote_ident(option_name)"
3361 : : " || ' ' || pg_catalog.quote_literal(option_value)\n"
3362 : : " FROM pg_catalog.pg_options_to_table(ftoptions)), ', ')\n"
3363 : : "FROM pg_catalog.pg_foreign_table f,\n"
3364 : : " pg_catalog.pg_foreign_server s\n"
3365 : : "WHERE f.ftrelid = '%s' AND s.oid = f.ftserver;",
3366 : : oid);
3461 fujii@postgresql.org 3367 : 93 : result = PSQLexec(buf.data);
4852 rhaas@postgresql.org 3368 [ - + ]: 93 : if (!result)
4852 rhaas@postgresql.org 3369 :UBC 0 : goto error_return;
4852 rhaas@postgresql.org 3370 [ - + ]:CBC 93 : else if (PQntuples(result) != 1)
3371 : : {
4852 rhaas@postgresql.org 3372 :UBC 0 : PQclear(result);
3373 : 0 : goto error_return;
3374 : : }
3375 : :
3376 : : /* Print server name */
2531 peter_e@gmx.net 3377 :CBC 93 : printfPQExpBuffer(&buf, _("Server: %s"),
3378 : : PQgetvalue(result, 0, 0));
4852 rhaas@postgresql.org 3379 : 93 : printTableAddFooter(&cont, buf.data);
3380 : :
3381 : : /* Print per-table FDW options, if any */
4630 3382 : 93 : ftoptions = PQgetvalue(result, 0, 1);
3383 [ + - + + ]: 93 : if (ftoptions && ftoptions[0] != '\0')
3384 : : {
2497 peter_e@gmx.net 3385 : 87 : printfPQExpBuffer(&buf, _("FDW options: (%s)"), ftoptions);
4630 rhaas@postgresql.org 3386 : 87 : printTableAddFooter(&cont, buf.data);
3387 : : }
4852 3388 : 93 : PQclear(result);
3389 : : }
3390 : :
3391 : : /* print tables inherited from (exclude partitioned parents) */
2685 3392 : 1371 : printfPQExpBuffer(&buf,
3393 : : "SELECT c.oid::pg_catalog.regclass\n"
3394 : : "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
3395 : : "WHERE c.oid = i.inhparent AND i.inhrelid = '%s'\n"
3396 : : " AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_TABLE)
3397 : : " AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_INDEX)
3398 : : "\nORDER BY inhseqno;",
3399 : : oid);
3400 : :
3461 fujii@postgresql.org 3401 : 1371 : result = PSQLexec(buf.data);
5816 alvherre@alvh.no-ip. 3402 [ - + ]: 1371 : if (!result)
5816 alvherre@alvh.no-ip. 3403 :UBC 0 : goto error_return;
3404 : : else
3405 : : {
5995 bruce@momjian.us 3406 :CBC 1371 : const char *s = _("Inherits");
4421 tgl@sss.pgh.pa.us 3407 : 1371 : int sw = pg_wcswidth(s, strlen(s), pset.encoding);
3408 : :
3409 : 1371 : tuples = PQntuples(result);
3410 : :
3411 [ + + ]: 1686 : for (i = 0; i < tuples; i++)
3412 : : {
3413 [ + + ]: 315 : if (i == 0)
3414 : 240 : printfPQExpBuffer(&buf, "%s: %s",
3415 : : s, PQgetvalue(result, i, 0));
3416 : : else
3417 : 75 : printfPQExpBuffer(&buf, "%*s %s",
3418 : : sw, "", PQgetvalue(result, i, 0));
3419 [ + + ]: 315 : if (i < tuples - 1)
3209 heikki.linnakangas@i 3420 : 75 : appendPQExpBufferChar(&buf, ',');
3421 : :
4421 tgl@sss.pgh.pa.us 3422 : 315 : printTableAddFooter(&cont, buf.data);
3423 : : }
3424 : :
3425 : 1371 : PQclear(result);
3426 : : }
3427 : :
3428 : : /* print child tables (with additional info if partitions) */
1116 alvherre@alvh.no-ip. 3429 [ + - ]: 1371 : if (pset.sversion >= 140000)
3430 : 1371 : printfPQExpBuffer(&buf,
3431 : : "SELECT c.oid::pg_catalog.regclass, c.relkind,"
3432 : : " inhdetachpending,"
3433 : : " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
3434 : : "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
3435 : : "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
3436 : : "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
3437 : : " c.oid::pg_catalog.regclass::pg_catalog.text;",
3438 : : oid);
1116 alvherre@alvh.no-ip. 3439 [ # # ]:UBC 0 : else if (pset.sversion >= 100000)
2685 rhaas@postgresql.org 3440 : 0 : printfPQExpBuffer(&buf,
3441 : : "SELECT c.oid::pg_catalog.regclass, c.relkind,"
3442 : : " false AS inhdetachpending,"
3443 : : " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
3444 : : "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
3445 : : "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
3446 : : "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
3447 : : " c.oid::pg_catalog.regclass::pg_catalog.text;",
3448 : : oid);
3449 : : else
2454 tgl@sss.pgh.pa.us 3450 : 0 : printfPQExpBuffer(&buf,
3451 : : "SELECT c.oid::pg_catalog.regclass, c.relkind,"
3452 : : " false AS inhdetachpending, NULL\n"
3453 : : "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
3454 : : "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
3455 : : "ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;",
3456 : : oid);
3457 : :
3461 fujii@postgresql.org 3458 :CBC 1371 : result = PSQLexec(buf.data);
5399 peter_e@gmx.net 3459 [ - + ]: 1371 : if (!result)
5399 peter_e@gmx.net 3460 :UBC 0 : goto error_return;
1727 tgl@sss.pgh.pa.us 3461 :CBC 1371 : tuples = PQntuples(result);
3462 : :
3463 : : /*
3464 : : * For a partitioned table with no partitions, always print the number
3465 : : * of partitions as zero, even when verbose output is expected.
3466 : : * Otherwise, we will not print "Partitions" section for a partitioned
3467 : : * table without any partitions.
3468 : : */
3469 [ + + + + ]: 1371 : if (is_partitioned && tuples == 0)
3470 : : {
2334 simon@2ndQuadrant.co 3471 : 33 : printfPQExpBuffer(&buf, _("Number of partitions: %d"), tuples);
3472 : 33 : printTableAddFooter(&cont, buf.data);
3473 : : }
3474 [ + + ]: 1338 : else if (!verbose)
3475 : : {
3476 : : /* print the number of child tables, if any */
5399 peter_e@gmx.net 3477 [ + + ]: 803 : if (tuples > 0)
3478 : : {
1727 tgl@sss.pgh.pa.us 3479 [ + + ]: 162 : if (is_partitioned)
2685 rhaas@postgresql.org 3480 : 117 : printfPQExpBuffer(&buf, _("Number of partitions: %d (Use \\d+ to list them.)"), tuples);
3481 : : else
1727 tgl@sss.pgh.pa.us 3482 : 45 : printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
5399 peter_e@gmx.net 3483 : 162 : printTableAddFooter(&cont, buf.data);
3484 : : }
3485 : : }
3486 : : else
3487 : : {
3488 : : /* display the list of child tables */
1727 tgl@sss.pgh.pa.us 3489 [ + + ]: 535 : const char *ct = is_partitioned ? _("Partitions") : _("Child tables");
4421 3490 : 535 : int ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
3491 : :
5399 peter_e@gmx.net 3492 [ + + ]: 778 : for (i = 0; i < tuples; i++)
3493 : : {
1727 tgl@sss.pgh.pa.us 3494 : 243 : char child_relkind = *PQgetvalue(result, i, 1);
3495 : :
3496 [ + + ]: 243 : if (i == 0)
3497 : 144 : printfPQExpBuffer(&buf, "%s: %s",
3498 : : ct, PQgetvalue(result, i, 0));
3499 : : else
3500 : 99 : printfPQExpBuffer(&buf, "%*s %s",
3501 : : ctw, "", PQgetvalue(result, i, 0));
1116 alvherre@alvh.no-ip. 3502 [ + + ]: 243 : if (!PQgetisnull(result, i, 3))
3503 : 96 : appendPQExpBuffer(&buf, " %s", PQgetvalue(result, i, 3));
1727 tgl@sss.pgh.pa.us 3504 [ + + - + ]: 243 : if (child_relkind == RELKIND_PARTITIONED_TABLE ||
3505 : : child_relkind == RELKIND_PARTITIONED_INDEX)
3506 : 12 : appendPQExpBufferStr(&buf, ", PARTITIONED");
523 michael@paquier.xyz 3507 [ + + ]: 231 : else if (child_relkind == RELKIND_FOREIGN_TABLE)
3508 : 54 : appendPQExpBufferStr(&buf, ", FOREIGN");
1116 alvherre@alvh.no-ip. 3509 [ - + ]: 243 : if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
1046 drowley@postgresql.o 3510 :UBC 0 : appendPQExpBufferStr(&buf, " (DETACH PENDING)");
5395 tgl@sss.pgh.pa.us 3511 [ + + ]:CBC 243 : if (i < tuples - 1)
3800 heikki.linnakangas@i 3512 : 99 : appendPQExpBufferChar(&buf, ',');
3513 : :
5395 tgl@sss.pgh.pa.us 3514 : 243 : printTableAddFooter(&cont, buf.data);
3515 : : }
3516 : : }
5399 peter_e@gmx.net 3517 : 1371 : PQclear(result);
3518 : :
3519 : : /* Table type */
5190 3520 [ + + ]: 1371 : if (tableinfo.reloftype)
3521 : : {
3522 : 30 : printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
3523 : 30 : printTableAddFooter(&cont, buf.data);
3524 : : }
3525 : :
2593 tgl@sss.pgh.pa.us 3526 [ + + ]: 1371 : if (verbose &&
3527 [ + + ]: 553 : (tableinfo.relkind == RELKIND_RELATION ||
3528 [ + + ]: 156 : tableinfo.relkind == RELKIND_MATVIEW) &&
3529 : :
3530 : : /*
3531 : : * No need to display default values; we already display a REPLICA
3532 : : * IDENTITY marker on indexes.
3533 : : */
3652 bruce@momjian.us 3534 [ + + ]: 427 : tableinfo.relreplident != 'i' &&
3535 [ + - + + ]: 424 : ((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
3536 [ - + - - ]: 421 : (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
3537 : : {
3810 rhaas@postgresql.org 3538 : 3 : const char *s = _("Replica Identity");
3539 : :
3810 rhaas@postgresql.org 3540 :UBC 0 : printfPQExpBuffer(&buf, "%s: %s",
3541 : : s,
3672 bruce@momjian.us 3542 [ - + ]:CBC 3 : tableinfo.relreplident == 'f' ? "FULL" :
3672 bruce@momjian.us 3543 [ # # ]:UBC 0 : tableinfo.relreplident == 'n' ? "NOTHING" :
3544 : : "???");
3545 : :
3810 rhaas@postgresql.org 3546 :CBC 3 : printTableAddFooter(&cont, buf.data);
3547 : : }
3548 : :
3549 : : /* OIDs, if verbose and not a materialized view */
2593 tgl@sss.pgh.pa.us 3550 [ + + + + : 1371 : if (verbose && tableinfo.relkind != RELKIND_MATVIEW && tableinfo.hasoids)
- + ]
3652 bruce@momjian.us 3551 :UBC 0 : printTableAddFooter(&cont, _("Has OIDs: yes"));
3552 : :
3553 : : /* Tablespace info */
5816 alvherre@alvh.no-ip. 3554 :CBC 1371 : add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
3555 : : true);
3556 : :
3557 : : /* Access method info */
1866 andres@anarazel.de 3558 [ + + + + : 1371 : if (verbose && tableinfo.relam != NULL && !pset.hide_tableam)
+ + ]
3559 : : {
3560 : 6 : printfPQExpBuffer(&buf, _("Access method: %s"), tableinfo.relam);
3561 : 6 : printTableAddFooter(&cont, buf.data);
3562 : : }
3563 : : }
3564 : :
3565 : : /* reloptions, if verbose */
4241 tgl@sss.pgh.pa.us 3566 [ + + ]: 1713 : if (verbose &&
3567 [ + - + + ]: 737 : tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
3568 : : {
3569 : 17 : const char *t = _("Options");
3570 : :
3571 : 17 : printfPQExpBuffer(&buf, "%s: %s", t, tableinfo.reloptions);
3572 : 17 : printTableAddFooter(&cont, buf.data);
3573 : : }
3574 : :
3056 3575 : 1713 : printTable(&cont, pset.queryFout, false, pset.logfile);
3576 : :
8026 peter_e@gmx.net 3577 : 1713 : retval = true;
3578 : :
3579 : 1809 : error_return:
3580 : :
3581 : : /* clean up */
5641 tgl@sss.pgh.pa.us 3582 [ + + ]: 1809 : if (printTableInitialized)
3583 : 1713 : printTableCleanup(&cont);
8026 peter_e@gmx.net 3584 : 1809 : termPQExpBuffer(&buf);
3585 : 1809 : termPQExpBuffer(&title);
7785 tgl@sss.pgh.pa.us 3586 : 1809 : termPQExpBuffer(&tmpbuf);
3587 : :
668 peter@eisentraut.org 3588 : 1809 : free(view_def);
3589 : :
651 3590 : 1809 : PQclear(res);
3591 : :
8026 peter_e@gmx.net 3592 : 1809 : return retval;
3593 : : }
3594 : :
3595 : : /*
3596 : : * Add a tablespace description to a footer. If 'newline' is true, it is added
3597 : : * in a new line; otherwise it's appended to the current value of the last
3598 : : * footer.
3599 : : */
3600 : : static void
5816 alvherre@alvh.no-ip. 3601 : 2186 : add_tablespace_footer(printTableContent *const cont, char relkind,
3602 : : Oid tablespace, const bool newline)
3603 : : {
3604 : : /* relkinds for which we support tablespaces */
2593 tgl@sss.pgh.pa.us 3605 [ + + + + ]: 2186 : if (relkind == RELKIND_RELATION ||
3606 [ + + ]: 1100 : relkind == RELKIND_MATVIEW ||
3607 [ + + ]: 285 : relkind == RELKIND_INDEX ||
1824 alvherre@alvh.no-ip. 3608 [ + + ]: 162 : relkind == RELKIND_PARTITIONED_TABLE ||
1727 tgl@sss.pgh.pa.us 3609 [ + + ]: 96 : relkind == RELKIND_PARTITIONED_INDEX ||
3610 : : relkind == RELKIND_TOASTVALUE)
3611 : : {
3612 : : /*
3613 : : * We ignore the database default tablespace so that users not using
3614 : : * tablespaces don't need to know about them.
3615 : : */
7168 bruce@momjian.us 3616 [ + + ]: 2093 : if (tablespace != 0)
3617 : : {
5816 alvherre@alvh.no-ip. 3618 : 102 : PGresult *result = NULL;
3619 : : PQExpBufferData buf;
3620 : :
3621 : 102 : initPQExpBuffer(&buf);
5764 tgl@sss.pgh.pa.us 3622 : 102 : printfPQExpBuffer(&buf,
3623 : : "SELECT spcname FROM pg_catalog.pg_tablespace\n"
3624 : : "WHERE oid = '%u';", tablespace);
3461 fujii@postgresql.org 3625 : 102 : result = PSQLexec(buf.data);
5816 alvherre@alvh.no-ip. 3626 [ - + ]: 102 : if (!result)
3627 : : {
2453 tgl@sss.pgh.pa.us 3628 :UBC 0 : termPQExpBuffer(&buf);
5816 alvherre@alvh.no-ip. 3629 : 0 : return;
3630 : : }
3631 : : /* Should always be the case, but.... */
5816 alvherre@alvh.no-ip. 3632 [ + - ]:CBC 102 : if (PQntuples(result) > 0)
3633 : : {
3634 [ + + ]: 102 : if (newline)
3635 : : {
3636 : : /* Add the tablespace as a new footer */
3637 : 87 : printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
3638 : : PQgetvalue(result, 0, 0));
3639 : 87 : printTableAddFooter(cont, buf.data);
3640 : : }
3641 : : else
3642 : : {
3643 : : /* Append the tablespace to the latest footer */
3644 : 15 : printfPQExpBuffer(&buf, "%s", cont->footer->data);
3645 : :
3646 : : /*-------
3647 : : translator: before this string there's an index description like
3648 : : '"foo_pkey" PRIMARY KEY, btree (a)' */
3649 : 15 : appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
3650 : : PQgetvalue(result, 0, 0));
3651 : 15 : printTableSetFooter(cont, buf.data);
3652 : : }
3653 : : }
3654 : 102 : PQclear(result);
3655 : 102 : termPQExpBuffer(&buf);
3656 : : }
3657 : : }
3658 : : }
3659 : :
3660 : : /*
3661 : : * \du or \dg
3662 : : *
3663 : : * Describes roles. Any schema portion of the pattern is ignored.
3664 : : */
3665 : : bool
2928 sfrost@snowman.net 3666 : 15 : describeRoles(const char *pattern, bool verbose, bool showSystem)
3667 : : {
3668 : : PQExpBufferData buf;
3669 : : PGresult *res;
3670 : : printTableContent cont;
5815 alvherre@alvh.no-ip. 3671 : 15 : printTableOpt myopt = pset.popt.topt;
270 tgl@sss.pgh.pa.us 3672 : 15 : int ncols = 2;
5815 alvherre@alvh.no-ip. 3673 : 15 : int nrows = 0;
3674 : : int i;
3675 : : int conns;
3676 : 15 : const char align = 'l';
3677 : : char **attr;
3678 : :
4366 rhaas@postgresql.org 3679 : 15 : myopt.default_footer = false;
3680 : :
8026 peter_e@gmx.net 3681 : 15 : initPQExpBuffer(&buf);
3682 : :
850 tgl@sss.pgh.pa.us 3683 : 15 : printfPQExpBuffer(&buf,
3684 : : "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
3685 : : " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
3686 : : " r.rolconnlimit, r.rolvaliduntil");
3687 : :
3688 [ - + ]: 15 : if (verbose)
3689 : : {
850 tgl@sss.pgh.pa.us 3690 :UBC 0 : appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
3691 : 0 : ncols++;
3692 : : }
850 tgl@sss.pgh.pa.us 3693 :CBC 15 : appendPQExpBufferStr(&buf, "\n, r.rolreplication");
3694 : :
3695 [ + - ]: 15 : if (pset.sversion >= 90500)
3696 : : {
3697 : 15 : appendPQExpBufferStr(&buf, "\n, r.rolbypassrls");
3698 : : }
3699 : :
3700 : 15 : appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
3701 : :
3702 [ + - - + ]: 15 : if (!showSystem && !pattern)
850 tgl@sss.pgh.pa.us 3703 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE r.rolname !~ '^pg_'\n");
3704 : :
725 rhaas@postgresql.org 3705 [ + + ]:CBC 15 : if (!validateSQLNamePattern(&buf, pattern, false, false,
3706 : : NULL, "r.rolname", NULL, NULL,
3707 : : NULL, 1))
3708 : : {
633 michael@paquier.xyz 3709 : 9 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 3710 : 9 : return false;
3711 : : }
3712 : :
3800 heikki.linnakangas@i 3713 : 6 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
3714 : :
3461 fujii@postgresql.org 3715 : 6 : res = PSQLexec(buf.data);
7440 bruce@momjian.us 3716 [ - + ]: 6 : if (!res)
7440 bruce@momjian.us 3717 :UBC 0 : return false;
3718 : :
5815 alvherre@alvh.no-ip. 3719 :CBC 6 : nrows = PQntuples(res);
4212 tgl@sss.pgh.pa.us 3720 : 6 : attr = pg_malloc0((nrows + 1) * sizeof(*attr));
3721 : :
5815 alvherre@alvh.no-ip. 3722 : 6 : printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
3723 : :
3724 : 6 : printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
3725 : 6 : printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
3726 : :
850 tgl@sss.pgh.pa.us 3727 [ - + ]: 6 : if (verbose)
5815 alvherre@alvh.no-ip. 3728 :UBC 0 : printTableAddHeader(&cont, gettext_noop("Description"), true, align);
3729 : :
5815 alvherre@alvh.no-ip. 3730 [ + + ]:CBC 15 : for (i = 0; i < nrows; i++)
3731 : : {
5158 heikki.linnakangas@i 3732 : 9 : printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
3733 : :
5815 alvherre@alvh.no-ip. 3734 : 9 : resetPQExpBuffer(&buf);
3735 [ - + ]: 9 : if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
5815 alvherre@alvh.no-ip. 3736 :UBC 0 : add_role_attribute(&buf, _("Superuser"));
3737 : :
5815 alvherre@alvh.no-ip. 3738 [ - + ]:CBC 9 : if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
5815 alvherre@alvh.no-ip. 3739 :UBC 0 : add_role_attribute(&buf, _("No inheritance"));
3740 : :
5815 alvherre@alvh.no-ip. 3741 [ - + ]:CBC 9 : if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
5815 alvherre@alvh.no-ip. 3742 :UBC 0 : add_role_attribute(&buf, _("Create role"));
3743 : :
5815 alvherre@alvh.no-ip. 3744 [ - + ]:CBC 9 : if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
5815 alvherre@alvh.no-ip. 3745 :UBC 0 : add_role_attribute(&buf, _("Create DB"));
3746 : :
5815 alvherre@alvh.no-ip. 3747 [ + - ]:CBC 9 : if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
3748 : 9 : add_role_attribute(&buf, _("Cannot login"));
3749 : :
270 tgl@sss.pgh.pa.us 3750 [ - + - + ]: 9 : if (strcmp(PQgetvalue(res, i, (verbose ? 9 : 8)), "t") == 0)
850 tgl@sss.pgh.pa.us 3751 :UBC 0 : add_role_attribute(&buf, _("Replication"));
3752 : :
3490 sfrost@snowman.net 3753 [ + - ]:CBC 9 : if (pset.sversion >= 90500)
270 tgl@sss.pgh.pa.us 3754 [ - + - + ]: 9 : if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
3490 sfrost@snowman.net 3755 :UBC 0 : add_role_attribute(&buf, _("Bypass RLS"));
3756 : :
5815 alvherre@alvh.no-ip. 3757 :CBC 9 : conns = atoi(PQgetvalue(res, i, 6));
3758 [ - + ]: 9 : if (conns >= 0)
3759 : : {
5815 alvherre@alvh.no-ip. 3760 [ # # ]:UBC 0 : if (buf.len > 0)
3800 heikki.linnakangas@i 3761 : 0 : appendPQExpBufferChar(&buf, '\n');
3762 : :
5815 alvherre@alvh.no-ip. 3763 [ # # ]: 0 : if (conns == 0)
3800 heikki.linnakangas@i 3764 : 0 : appendPQExpBufferStr(&buf, _("No connections"));
3765 : : else
5428 tgl@sss.pgh.pa.us 3766 : 0 : appendPQExpBuffer(&buf, ngettext("%d connection",
3767 : : "%d connections",
3768 : : conns),
3769 : : conns);
3770 : : }
3771 : :
4406 tgl@sss.pgh.pa.us 3772 [ - + ]:CBC 9 : if (strcmp(PQgetvalue(res, i, 7), "") != 0)
3773 : : {
4406 tgl@sss.pgh.pa.us 3774 [ # # ]:UBC 0 : if (buf.len > 0)
2434 peter_e@gmx.net 3775 : 0 : appendPQExpBufferChar(&buf, '\n');
4406 tgl@sss.pgh.pa.us 3776 : 0 : appendPQExpBufferStr(&buf, _("Password valid until "));
3777 : 0 : appendPQExpBufferStr(&buf, PQgetvalue(res, i, 7));
3778 : : }
3779 : :
5815 alvherre@alvh.no-ip. 3780 :CBC 9 : attr[i] = pg_strdup(buf.data);
3781 : :
5158 heikki.linnakangas@i 3782 : 9 : printTableAddCell(&cont, attr[i], false, false);
3783 : :
850 tgl@sss.pgh.pa.us 3784 [ - + ]: 9 : if (verbose)
270 tgl@sss.pgh.pa.us 3785 :UBC 0 : printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
3786 : : }
5815 alvherre@alvh.no-ip. 3787 :CBC 6 : termPQExpBuffer(&buf);
3788 : :
3056 tgl@sss.pgh.pa.us 3789 : 6 : printTable(&cont, pset.queryFout, false, pset.logfile);
5815 alvherre@alvh.no-ip. 3790 : 6 : printTableCleanup(&cont);
3791 : :
3792 [ + + ]: 15 : for (i = 0; i < nrows; i++)
3793 : 9 : free(attr[i]);
3794 : 6 : free(attr);
3795 : :
7440 bruce@momjian.us 3796 : 6 : PQclear(res);
3797 : 6 : return true;
3798 : : }
3799 : :
3800 : : static void
5815 alvherre@alvh.no-ip. 3801 : 9 : add_role_attribute(PQExpBuffer buf, const char *const str)
3802 : : {
3803 [ - + ]: 9 : if (buf->len > 0)
5268 peter_e@gmx.net 3804 :UBC 0 : appendPQExpBufferStr(buf, ", ");
3805 : :
5815 alvherre@alvh.no-ip. 3806 :CBC 9 : appendPQExpBufferStr(buf, str);
3807 : 9 : }
3808 : :
3809 : : /*
3810 : : * \drds
3811 : : */
3812 : : bool
5303 3813 : 12 : listDbRoleSettings(const char *pattern, const char *pattern2)
3814 : : {
3815 : : PQExpBufferData buf;
3816 : : PGresult *res;
3817 : 12 : printQueryOpt myopt = pset.popt;
3818 : : bool havewhere;
3819 : :
2453 tgl@sss.pgh.pa.us 3820 : 12 : initPQExpBuffer(&buf);
3821 : :
3822 : 12 : printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
3823 : : "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
3824 : : "FROM pg_catalog.pg_db_role_setting s\n"
3825 : : "LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n"
3826 : : "LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n",
3827 : : gettext_noop("Role"),
3828 : : gettext_noop("Database"),
3829 : : gettext_noop("Settings"));
725 rhaas@postgresql.org 3830 [ + + ]: 12 : if (!validateSQLNamePattern(&buf, pattern, false, false,
3831 : : NULL, "r.rolname", NULL, NULL, &havewhere, 1))
633 michael@paquier.xyz 3832 : 9 : goto error_return;
725 rhaas@postgresql.org 3833 [ - + ]: 3 : if (!validateSQLNamePattern(&buf, pattern2, havewhere, false,
3834 : : NULL, "d.datname", NULL, NULL,
3835 : : NULL, 1))
633 michael@paquier.xyz 3836 :UBC 0 : goto error_return;
2453 tgl@sss.pgh.pa.us 3837 :CBC 3 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
3838 : :
3461 fujii@postgresql.org 3839 : 3 : res = PSQLexec(buf.data);
2453 tgl@sss.pgh.pa.us 3840 : 3 : termPQExpBuffer(&buf);
5303 alvherre@alvh.no-ip. 3841 [ - + ]: 3 : if (!res)
5303 alvherre@alvh.no-ip. 3842 :UBC 0 : return false;
3843 : :
3844 : : /*
3845 : : * Most functions in this file are content to print an empty table when
3846 : : * there are no matching objects. We intentionally deviate from that
3847 : : * here, but only in !quiet mode, because of the possibility that the user
3848 : : * is confused about what the two pattern arguments mean.
3849 : : */
5303 alvherre@alvh.no-ip. 3850 [ + - - + ]:CBC 3 : if (PQntuples(res) == 0 && !pset.quiet)
3851 : : {
2453 tgl@sss.pgh.pa.us 3852 [ # # # # ]:UBC 0 : if (pattern && pattern2)
1840 peter@eisentraut.org 3853 : 0 : pg_log_error("Did not find any settings for role \"%s\" and database \"%s\".",
3854 : : pattern, pattern2);
2453 tgl@sss.pgh.pa.us 3855 [ # # ]: 0 : else if (pattern)
1840 peter@eisentraut.org 3856 : 0 : pg_log_error("Did not find any settings for role \"%s\".",
3857 : : pattern);
3858 : : else
3859 : 0 : pg_log_error("Did not find any settings.");
3860 : : }
3861 : : else
3862 : : {
5303 alvherre@alvh.no-ip. 3863 :CBC 3 : myopt.title = _("List of settings");
3864 : 3 : myopt.translate_header = true;
3865 : :
3056 tgl@sss.pgh.pa.us 3866 : 3 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3867 : : }
3868 : :
5303 alvherre@alvh.no-ip. 3869 : 3 : PQclear(res);
3870 : 3 : return true;
3871 : :
633 michael@paquier.xyz 3872 : 9 : error_return:
3873 : 9 : termPQExpBuffer(&buf);
3874 : 9 : return false;
3875 : : }
3876 : :
3877 : : /*
3878 : : * \drg
3879 : : * Describes role grants.
3880 : : */
3881 : : bool
270 tgl@sss.pgh.pa.us 3882 : 3 : describeRoleGrants(const char *pattern, bool showSystem)
3883 : : {
3884 : : PQExpBufferData buf;
3885 : : PGresult *res;
3886 : 3 : printQueryOpt myopt = pset.popt;
3887 : :
3888 : 3 : initPQExpBuffer(&buf);
3889 : 3 : printfPQExpBuffer(&buf,
3890 : : "SELECT m.rolname AS \"%s\", r.rolname AS \"%s\",\n"
3891 : : " pg_catalog.concat_ws(', ',\n",
3892 : : gettext_noop("Role name"),
3893 : : gettext_noop("Member of"));
3894 : :
3895 [ + - ]: 3 : if (pset.sversion >= 160000)
3896 : 3 : appendPQExpBufferStr(&buf,
3897 : : " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
3898 : : " CASE WHEN pam.inherit_option THEN 'INHERIT' END,\n"
3899 : : " CASE WHEN pam.set_option THEN 'SET' END\n");
3900 : : else
270 tgl@sss.pgh.pa.us 3901 :UBC 0 : appendPQExpBufferStr(&buf,
3902 : : " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
3903 : : " CASE WHEN m.rolinherit THEN 'INHERIT' END,\n"
3904 : : " 'SET'\n");
3905 : :
270 tgl@sss.pgh.pa.us 3906 :CBC 3 : appendPQExpBuffer(&buf,
3907 : : " ) AS \"%s\",\n"
3908 : : " g.rolname AS \"%s\"\n",
3909 : : gettext_noop("Options"),
3910 : : gettext_noop("Grantor"));
3911 : :
3912 : 3 : appendPQExpBufferStr(&buf,
3913 : : "FROM pg_catalog.pg_roles m\n"
3914 : : " JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)\n"
3915 : : " LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)\n"
3916 : : " LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)\n");
3917 : :
3918 [ + - - + ]: 3 : if (!showSystem && !pattern)
270 tgl@sss.pgh.pa.us 3919 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE m.rolname !~ '^pg_'\n");
3920 : :
270 tgl@sss.pgh.pa.us 3921 [ - + ]:CBC 3 : if (!validateSQLNamePattern(&buf, pattern, false, false,
3922 : : NULL, "m.rolname", NULL, NULL,
3923 : : NULL, 1))
3924 : : {
270 tgl@sss.pgh.pa.us 3925 :UBC 0 : termPQExpBuffer(&buf);
3926 : 0 : return false;
3927 : : }
3928 : :
270 tgl@sss.pgh.pa.us 3929 :CBC 3 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;\n");
3930 : :
3931 : 3 : res = PSQLexec(buf.data);
3932 : 3 : termPQExpBuffer(&buf);
3933 [ - + ]: 3 : if (!res)
270 tgl@sss.pgh.pa.us 3934 :UBC 0 : return false;
3935 : :
270 tgl@sss.pgh.pa.us 3936 :CBC 3 : myopt.title = _("List of role grants");
3937 : 3 : myopt.translate_header = true;
3938 : :
3939 : 3 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
3940 : :
3941 : 3 : PQclear(res);
3942 : 3 : return true;
3943 : : }
3944 : :
3945 : :
3946 : : /*
3947 : : * listTables()
3948 : : *
3949 : : * handler for \dt, \di, etc.
3950 : : *
3951 : : * tabtypes is an array of characters, specifying what info is desired:
3952 : : * t - tables
3953 : : * i - indexes
3954 : : * v - views
3955 : : * m - materialized views
3956 : : * s - sequences
3957 : : * E - foreign table (Note: different from 'f', the relkind value)
3958 : : * (any order of the above is fine)
3959 : : */
3960 : : bool
5577 bruce@momjian.us 3961 : 153 : listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
3962 : : {
7918 tgl@sss.pgh.pa.us 3963 : 153 : bool showTables = strchr(tabtypes, 't') != NULL;
3964 : 153 : bool showIndexes = strchr(tabtypes, 'i') != NULL;
3965 : 153 : bool showViews = strchr(tabtypes, 'v') != NULL;
4060 kgrittn@postgresql.o 3966 : 153 : bool showMatViews = strchr(tabtypes, 'm') != NULL;
7918 tgl@sss.pgh.pa.us 3967 : 153 : bool showSeq = strchr(tabtypes, 's') != NULL;
4852 rhaas@postgresql.org 3968 : 153 : bool showForeign = strchr(tabtypes, 'E') != NULL;
3969 : :
3970 : : PQExpBufferData buf;
3971 : : PGresult *res;
8857 peter_e@gmx.net 3972 : 153 : printQueryOpt myopt = pset.popt;
3973 : : int cols_so_far;
1320 michael@paquier.xyz 3974 : 153 : bool translate_columns[] = {false, false, true, false, false, false, false, false, false};
3975 : :
3976 : : /* If tabtypes is empty, we default to \dtvmsE (but see also command.c) */
4060 kgrittn@postgresql.o 3977 [ + + + + : 153 : if (!(showTables || showIndexes || showViews || showMatViews || showSeq || showForeign))
+ + + + +
+ - + ]
4060 kgrittn@postgresql.o 3978 :UBC 0 : showTables = showViews = showMatViews = showSeq = showForeign = true;
3979 : :
8026 peter_e@gmx.net 3980 :CBC 153 : initPQExpBuffer(&buf);
3981 : :
3982 : 153 : printfPQExpBuffer(&buf,
3983 : : "SELECT n.nspname as \"%s\",\n"
3984 : : " c.relname as \"%s\",\n"
3985 : : " CASE c.relkind"
3986 : : " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
3987 : : " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
3988 : : " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
3989 : : " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'"
3990 : : " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
3991 : : " WHEN " CppAsString2(RELKIND_TOASTVALUE) " THEN '%s'"
3992 : : " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
3993 : : " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
3994 : : " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
3995 : : " END as \"%s\",\n"
3996 : : " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
3997 : : gettext_noop("Schema"),
3998 : : gettext_noop("Name"),
3999 : : gettext_noop("table"),
4000 : : gettext_noop("view"),
4001 : : gettext_noop("materialized view"),
4002 : : gettext_noop("index"),
4003 : : gettext_noop("sequence"),
4004 : : gettext_noop("TOAST table"),
4005 : : gettext_noop("foreign table"),
4006 : : gettext_noop("partitioned table"),
4007 : : gettext_noop("partitioned index"),
4008 : : gettext_noop("Type"),
4009 : : gettext_noop("Owner"));
1747 tgl@sss.pgh.pa.us 4010 : 153 : cols_so_far = 4;
4011 : :
7156 neilc@samurai.com 4012 [ + + ]: 153 : if (showIndexes)
4013 : : {
4014 : 21 : appendPQExpBuffer(&buf,
4015 : : ",\n c2.relname as \"%s\"",
4016 : : gettext_noop("Table"));
1747 tgl@sss.pgh.pa.us 4017 : 21 : cols_so_far++;
4018 : : }
4019 : :
5764 4020 [ + + ]: 153 : if (verbose)
4021 : : {
4022 : : /*
4023 : : * Show whether a relation is permanent, temporary, or unlogged.
4024 : : */
850 4025 : 15 : appendPQExpBuffer(&buf,
4026 : : ",\n CASE c.relpersistence WHEN 'p' THEN '%s' WHEN 't' THEN '%s' WHEN 'u' THEN '%s' END as \"%s\"",
4027 : : gettext_noop("permanent"),
4028 : : gettext_noop("temporary"),
4029 : : gettext_noop("unlogged"),
4030 : : gettext_noop("Persistence"));
4031 : 15 : translate_columns[cols_so_far] = true;
4032 : :
4033 : : /*
4034 : : * We don't bother to count cols_so_far below here, as there's no need
4035 : : * to; this might change with future additions to the output columns.
4036 : : */
4037 : :
4038 : : /*
4039 : : * Access methods exist for tables, materialized views and indexes.
4040 : : * This has been introduced in PostgreSQL 12 for tables.
4041 : : */
1320 michael@paquier.xyz 4042 [ + - + + : 15 : if (pset.sversion >= 120000 && !pset.hide_tableam &&
+ + ]
4043 [ + + - + ]: 6 : (showTables || showMatViews || showIndexes))
4044 : 9 : appendPQExpBuffer(&buf,
4045 : : ",\n am.amname as \"%s\"",
4046 : : gettext_noop("Access method"));
4047 : :
8026 peter_e@gmx.net 4048 : 15 : appendPQExpBuffer(&buf,
4049 : : ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \"%s\""
4050 : : ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
4051 : : gettext_noop("Size"),
4052 : : gettext_noop("Description"));
4053 : : }
4054 : :
3800 heikki.linnakangas@i 4055 : 153 : appendPQExpBufferStr(&buf,
4056 : : "\nFROM pg_catalog.pg_class c"
4057 : : "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
4058 : :
1320 michael@paquier.xyz 4059 [ + - + + : 153 : if (pset.sversion >= 120000 && !pset.hide_tableam &&
+ + ]
4060 [ + + - + ]: 6 : (showTables || showMatViews || showIndexes))
4061 : 9 : appendPQExpBufferStr(&buf,
4062 : : "\n LEFT JOIN pg_catalog.pg_am am ON am.oid = c.relam");
4063 : :
7893 bruce@momjian.us 4064 [ + + ]: 153 : if (showIndexes)
3800 heikki.linnakangas@i 4065 : 21 : appendPQExpBufferStr(&buf,
4066 : : "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
4067 : : "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
4068 : :
4069 : 153 : appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
8324 peter_e@gmx.net 4070 [ + + ]: 153 : if (showTables)
4071 : : {
2593 tgl@sss.pgh.pa.us 4072 : 54 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_RELATION) ","
4073 : : CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
4074 : : /* with 'S' or a pattern, allow 't' to match TOAST tables too */
1195 4075 [ + - + + ]: 54 : if (showSystem || pattern)
4076 : 45 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_TOASTVALUE) ",");
4077 : : }
8928 bruce@momjian.us 4078 [ + + ]: 153 : if (showViews)
2593 tgl@sss.pgh.pa.us 4079 : 30 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_VIEW) ",");
4060 kgrittn@postgresql.o 4080 [ + + ]: 153 : if (showMatViews)
2593 tgl@sss.pgh.pa.us 4081 : 30 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_MATVIEW) ",");
8324 peter_e@gmx.net 4082 [ + + ]: 153 : if (showIndexes)
2277 alvherre@alvh.no-ip. 4083 : 21 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_INDEX) ","
4084 : : CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
8324 peter_e@gmx.net 4085 [ + + ]: 153 : if (showSeq)
2593 tgl@sss.pgh.pa.us 4086 : 27 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_SEQUENCE) ",");
5491 bruce@momjian.us 4087 [ + - + + ]: 153 : if (showSystem || pattern)
2489 tgl@sss.pgh.pa.us 4088 : 138 : appendPQExpBufferStr(&buf, "'s',"); /* was RELKIND_SPECIAL */
4852 rhaas@postgresql.org 4089 [ + + ]: 153 : if (showForeign)
2593 tgl@sss.pgh.pa.us 4090 : 15 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_FOREIGN_TABLE) ",");
4091 : :
3631 bruce@momjian.us 4092 : 153 : appendPQExpBufferStr(&buf, "''"); /* dummy */
3800 heikki.linnakangas@i 4093 : 153 : appendPQExpBufferStr(&buf, ")\n");
4094 : :
5421 bruce@momjian.us 4095 [ + - + + ]: 153 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 4096 : 15 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4097 : : " AND n.nspname !~ '^pg_toast'\n"
4098 : : " AND n.nspname <> 'information_schema'\n");
4099 : :
725 rhaas@postgresql.org 4100 [ + + ]: 153 : if (!validateSQLNamePattern(&buf, pattern, true, false,
4101 : : "n.nspname", "c.relname", NULL,
4102 : : "pg_catalog.pg_table_is_visible(c.oid)",
4103 : : NULL, 3))
4104 : : {
633 michael@paquier.xyz 4105 : 81 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 4106 : 81 : return false;
4107 : : }
4108 : :
3800 heikki.linnakangas@i 4109 : 72 : appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
4110 : :
3461 fujii@postgresql.org 4111 : 72 : res = PSQLexec(buf.data);
8026 peter_e@gmx.net 4112 : 72 : termPQExpBuffer(&buf);
8928 bruce@momjian.us 4113 [ - + ]: 72 : if (!res)
8928 bruce@momjian.us 4114 :UBC 0 : return false;
4115 : :
4116 : : /*
4117 : : * Most functions in this file are content to print an empty table when
4118 : : * there are no matching objects. We intentionally deviate from that
4119 : : * here, but only in !quiet mode, for historical reasons.
4120 : : */
6438 tgl@sss.pgh.pa.us 4121 [ + + - + ]:CBC 72 : if (PQntuples(res) == 0 && !pset.quiet)
4122 : : {
7918 tgl@sss.pgh.pa.us 4123 [ # # ]:UBC 0 : if (pattern)
1840 peter@eisentraut.org 4124 : 0 : pg_log_error("Did not find any relation named \"%s\".",
4125 : : pattern);
4126 : : else
4127 : 0 : pg_log_error("Did not find any relations.");
4128 : : }
4129 : : else
4130 : : {
8324 peter_e@gmx.net 4131 :CBC 72 : myopt.title = _("List of relations");
5753 bruce@momjian.us 4132 : 72 : myopt.translate_header = true;
4133 : 72 : myopt.translate_columns = translate_columns;
3753 tgl@sss.pgh.pa.us 4134 : 72 : myopt.n_translate_columns = lengthof(translate_columns);
4135 : :
3056 4136 : 72 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4137 : : }
4138 : :
8928 bruce@momjian.us 4139 : 72 : PQclear(res);
4140 : 72 : return true;
4141 : : }
4142 : :
4143 : : /*
4144 : : * \dP
4145 : : * Takes an optional regexp to select particular relations
4146 : : *
4147 : : * As with \d, you can specify the kinds of relations you want:
4148 : : *
4149 : : * t for tables
4150 : : * i for indexes
4151 : : *
4152 : : * And there's additional flags:
4153 : : *
4154 : : * n to list non-leaf partitioned tables
4155 : : *
4156 : : * and you can mix and match these in any order.
4157 : : */
4158 : : bool
1834 alvherre@alvh.no-ip. 4159 : 54 : listPartitionedTables(const char *reltypes, const char *pattern, bool verbose)
4160 : : {
4161 : 54 : bool showTables = strchr(reltypes, 't') != NULL;
4162 : 54 : bool showIndexes = strchr(reltypes, 'i') != NULL;
4163 : 54 : bool showNested = strchr(reltypes, 'n') != NULL;
4164 : : PQExpBufferData buf;
4165 : : PQExpBufferData title;
4166 : : PGresult *res;
4167 : 54 : printQueryOpt myopt = pset.popt;
1789 tgl@sss.pgh.pa.us 4168 : 54 : bool translate_columns[] = {false, false, false, false, false, false, false, false, false};
4169 : : const char *tabletitle;
1834 alvherre@alvh.no-ip. 4170 : 54 : bool mixed_output = false;
4171 : :
4172 : : /*
4173 : : * Note: Declarative table partitioning is only supported as of Pg 10.0.
4174 : : */
4175 [ - + ]: 54 : if (pset.sversion < 100000)
4176 : : {
4177 : : char sverbuf[32];
4178 : :
1834 alvherre@alvh.no-ip. 4179 :UBC 0 : pg_log_error("The server (version %s) does not support declarative table partitioning.",
4180 : : formatPGVersionNumber(pset.sversion, false,
4181 : : sverbuf, sizeof(sverbuf)));
4182 : 0 : return true;
4183 : : }
4184 : :
4185 : : /* If no relation kind was selected, show them all */
1834 alvherre@alvh.no-ip. 4186 [ + + + + ]:CBC 54 : if (!showTables && !showIndexes)
4187 : 36 : showTables = showIndexes = true;
4188 : :
4189 [ + + + + ]: 54 : if (showIndexes && !showTables)
4190 : 9 : tabletitle = _("List of partitioned indexes"); /* \dPi */
4191 [ + - + + ]: 45 : else if (showTables && !showIndexes)
4192 : 9 : tabletitle = _("List of partitioned tables"); /* \dPt */
4193 : : else
4194 : : {
4195 : : /* show all kinds */
4196 : 36 : tabletitle = _("List of partitioned relations");
4197 : 36 : mixed_output = true;
4198 : : }
4199 : :
4200 : 54 : initPQExpBuffer(&buf);
4201 : :
4202 : 54 : printfPQExpBuffer(&buf,
4203 : : "SELECT n.nspname as \"%s\",\n"
4204 : : " c.relname as \"%s\",\n"
4205 : : " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
4206 : : gettext_noop("Schema"),
4207 : : gettext_noop("Name"),
4208 : : gettext_noop("Owner"));
4209 : :
4210 [ + + ]: 54 : if (mixed_output)
4211 : : {
4212 : 36 : appendPQExpBuffer(&buf,
4213 : : ",\n CASE c.relkind"
4214 : : " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
4215 : : " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
4216 : : " END as \"%s\"",
4217 : : gettext_noop("partitioned table"),
4218 : : gettext_noop("partitioned index"),
4219 : : gettext_noop("Type"));
4220 : :
4221 : 36 : translate_columns[3] = true;
4222 : : }
4223 : :
4224 [ + + + + ]: 54 : if (showNested || pattern)
4225 : 45 : appendPQExpBuffer(&buf,
4226 : : ",\n inh.inhparent::pg_catalog.regclass as \"%s\"",
4227 : : gettext_noop("Parent name"));
4228 : :
4229 [ + + ]: 54 : if (showIndexes)
4230 : 45 : appendPQExpBuffer(&buf,
4231 : : ",\n c2.oid::pg_catalog.regclass as \"%s\"",
4232 : : gettext_noop("Table"));
4233 : :
4234 [ - + ]: 54 : if (verbose)
4235 : : {
1834 alvherre@alvh.no-ip. 4236 [ # # ]:UBC 0 : if (showNested)
4237 : : {
4238 : 0 : appendPQExpBuffer(&buf,
4239 : : ",\n s.dps as \"%s\"",
4240 : : gettext_noop("Leaf partition size"));
4241 : 0 : appendPQExpBuffer(&buf,
4242 : : ",\n s.tps as \"%s\"",
4243 : : gettext_noop("Total size"));
4244 : : }
4245 : : else
4246 : : /* Sizes of all partitions are considered in this case. */
4247 : 0 : appendPQExpBuffer(&buf,
4248 : : ",\n s.tps as \"%s\"",
4249 : : gettext_noop("Total size"));
4250 : :
4251 : 0 : appendPQExpBuffer(&buf,
4252 : : ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
4253 : : gettext_noop("Description"));
4254 : : }
4255 : :
1834 alvherre@alvh.no-ip. 4256 :CBC 54 : appendPQExpBufferStr(&buf,
4257 : : "\nFROM pg_catalog.pg_class c"
4258 : : "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
4259 : :
4260 [ + + ]: 54 : if (showIndexes)
4261 : 45 : appendPQExpBufferStr(&buf,
4262 : : "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
4263 : : "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
4264 : :
4265 [ + + + + ]: 54 : if (showNested || pattern)
4266 : 45 : appendPQExpBufferStr(&buf,
4267 : : "\n LEFT JOIN pg_catalog.pg_inherits inh ON c.oid = inh.inhrelid");
4268 : :
4269 [ - + ]: 54 : if (verbose)
4270 : : {
1834 alvherre@alvh.no-ip. 4271 [ # # ]:UBC 0 : if (pset.sversion < 120000)
4272 : : {
1746 drowley@postgresql.o 4273 : 0 : appendPQExpBufferStr(&buf,
4274 : : ",\n LATERAL (WITH RECURSIVE d\n"
4275 : : " AS (SELECT inhrelid AS oid, 1 AS level\n"
4276 : : " FROM pg_catalog.pg_inherits\n"
4277 : : " WHERE inhparent = c.oid\n"
4278 : : " UNION ALL\n"
4279 : : " SELECT inhrelid, level + 1\n"
4280 : : " FROM pg_catalog.pg_inherits i\n"
4281 : : " JOIN d ON i.inhparent = d.oid)\n"
4282 : : " SELECT pg_catalog.pg_size_pretty(sum(pg_catalog.pg_table_size("
4283 : : "d.oid))) AS tps,\n"
4284 : : " pg_catalog.pg_size_pretty(sum("
4285 : : "\n CASE WHEN d.level = 1"
4286 : : " THEN pg_catalog.pg_table_size(d.oid) ELSE 0 END)) AS dps\n"
4287 : : " FROM d) s");
4288 : : }
4289 : : else
4290 : : {
4291 : : /* PostgreSQL 12 has pg_partition_tree function */
4292 : 0 : appendPQExpBufferStr(&buf,
4293 : : ",\n LATERAL (SELECT pg_catalog.pg_size_pretty(sum("
4294 : : "\n CASE WHEN ppt.isleaf AND ppt.level = 1"
4295 : : "\n THEN pg_catalog.pg_table_size(ppt.relid)"
4296 : : " ELSE 0 END)) AS dps"
4297 : : ",\n pg_catalog.pg_size_pretty(sum("
4298 : : "pg_catalog.pg_table_size(ppt.relid))) AS tps"
4299 : : "\n FROM pg_catalog.pg_partition_tree(c.oid) ppt) s");
4300 : : }
4301 : : }
4302 : :
1834 alvherre@alvh.no-ip. 4303 :CBC 54 : appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
4304 [ + + ]: 54 : if (showTables)
4305 : 45 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
4306 [ + + ]: 54 : if (showIndexes)
4307 : 45 : appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
4308 : 54 : appendPQExpBufferStr(&buf, "''"); /* dummy */
4309 : 54 : appendPQExpBufferStr(&buf, ")\n");
4310 : :
4311 [ + + + + ]: 54 : appendPQExpBufferStr(&buf, !showNested && !pattern ?
4312 : : " AND NOT c.relispartition\n" : "");
4313 : :
4314 [ + + ]: 54 : if (!pattern)
4315 : 18 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4316 : : " AND n.nspname !~ '^pg_toast'\n"
4317 : : " AND n.nspname <> 'information_schema'\n");
4318 : :
725 rhaas@postgresql.org 4319 [ + + ]: 54 : if (!validateSQLNamePattern(&buf, pattern, true, false,
4320 : : "n.nspname", "c.relname", NULL,
4321 : : "pg_catalog.pg_table_is_visible(c.oid)",
4322 : : NULL, 3))
4323 : : {
633 michael@paquier.xyz 4324 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 4325 : 12 : return false;
4326 : : }
4327 : :
1834 alvherre@alvh.no-ip. 4328 [ + + + + ]: 72 : appendPQExpBuffer(&buf, "ORDER BY \"Schema\", %s%s\"Name\";",
4329 : : mixed_output ? "\"Type\" DESC, " : "",
4330 [ + + ]: 30 : showNested || pattern ? "\"Parent name\" NULLS FIRST, " : "");
4331 : :
4332 : 42 : res = PSQLexec(buf.data);
4333 : 42 : termPQExpBuffer(&buf);
4334 [ - + ]: 42 : if (!res)
1834 alvherre@alvh.no-ip. 4335 :UBC 0 : return false;
4336 : :
1834 alvherre@alvh.no-ip. 4337 :CBC 42 : initPQExpBuffer(&title);
1746 drowley@postgresql.o 4338 : 42 : appendPQExpBufferStr(&title, tabletitle);
4339 : :
1834 alvherre@alvh.no-ip. 4340 : 42 : myopt.title = title.data;
4341 : 42 : myopt.translate_header = true;
4342 : 42 : myopt.translate_columns = translate_columns;
4343 : 42 : myopt.n_translate_columns = lengthof(translate_columns);
4344 : :
4345 : 42 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4346 : :
4347 : 42 : termPQExpBuffer(&title);
4348 : :
4349 : 42 : PQclear(res);
4350 : 42 : return true;
4351 : : }
4352 : :
4353 : : /*
4354 : : * \dL
4355 : : *
4356 : : * Describes languages.
4357 : : */
4358 : : bool
4833 rhaas@postgresql.org 4359 : 15 : listLanguages(const char *pattern, bool verbose, bool showSystem)
4360 : : {
4361 : : PQExpBufferData buf;
4362 : : PGresult *res;
4363 : 15 : printQueryOpt myopt = pset.popt;
4364 : :
4365 : 15 : initPQExpBuffer(&buf);
4366 : :
4367 : 15 : printfPQExpBuffer(&buf,
4368 : : "SELECT l.lanname AS \"%s\",\n"
4369 : : " pg_catalog.pg_get_userbyid(l.lanowner) as \"%s\",\n"
4370 : : " l.lanpltrusted AS \"%s\"",
4371 : : gettext_noop("Name"),
4372 : : gettext_noop("Owner"),
4373 : : gettext_noop("Trusted"));
4374 : :
4375 [ - + ]: 15 : if (verbose)
4376 : : {
4753 bruce@momjian.us 4377 :UBC 0 : appendPQExpBuffer(&buf,
4378 : : ",\n NOT l.lanispl AS \"%s\",\n"
4379 : : " l.lanplcallfoid::pg_catalog.regprocedure AS \"%s\",\n"
4380 : : " l.lanvalidator::pg_catalog.regprocedure AS \"%s\",\n "
4381 : : "l.laninline::pg_catalog.regprocedure AS \"%s\",\n ",
4382 : : gettext_noop("Internal language"),
4383 : : gettext_noop("Call handler"),
4384 : : gettext_noop("Validator"),
4385 : : gettext_noop("Inline handler"));
4386 : 0 : printACLColumn(&buf, "l.lanacl");
4387 : : }
4388 : :
4833 rhaas@postgresql.org 4389 :CBC 15 : appendPQExpBuffer(&buf,
4390 : : ",\n d.description AS \"%s\""
4391 : : "\nFROM pg_catalog.pg_language l\n"
4392 : : "LEFT JOIN pg_catalog.pg_description d\n"
4393 : : " ON d.classoid = l.tableoid AND d.objoid = l.oid\n"
4394 : : " AND d.objsubid = 0\n",
4395 : : gettext_noop("Description"));
4396 : :
4637 4397 [ + - ]: 15 : if (pattern)
4398 : : {
725 4399 [ + + ]: 15 : if (!validateSQLNamePattern(&buf, pattern, false, false,
4400 : : NULL, "l.lanname", NULL, NULL,
4401 : : NULL, 2))
4402 : : {
633 michael@paquier.xyz 4403 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 4404 : 12 : return false;
4405 : : }
4406 : : }
4407 : :
4833 4408 [ + - - + ]: 3 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 4409 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n");
4410 : :
4411 : :
3800 heikki.linnakangas@i 4412 :CBC 3 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
4413 : :
3461 fujii@postgresql.org 4414 : 3 : res = PSQLexec(buf.data);
4833 rhaas@postgresql.org 4415 : 3 : termPQExpBuffer(&buf);
4416 [ - + ]: 3 : if (!res)
4833 rhaas@postgresql.org 4417 :UBC 0 : return false;
4418 : :
4833 rhaas@postgresql.org 4419 :CBC 3 : myopt.title = _("List of languages");
4420 : 3 : myopt.translate_header = true;
4421 : :
3056 tgl@sss.pgh.pa.us 4422 : 3 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4423 : :
4833 rhaas@postgresql.org 4424 : 3 : PQclear(res);
4425 : 3 : return true;
4426 : : }
4427 : :
4428 : :
4429 : : /*
4430 : : * \dD
4431 : : *
4432 : : * Describes domains.
4433 : : */
4434 : : bool
4633 4435 : 24 : listDomains(const char *pattern, bool verbose, bool showSystem)
4436 : : {
4437 : : PQExpBufferData buf;
4438 : : PGresult *res;
8062 bruce@momjian.us 4439 : 24 : printQueryOpt myopt = pset.popt;
4440 : :
8026 peter_e@gmx.net 4441 : 24 : initPQExpBuffer(&buf);
4442 : :
4443 : 24 : printfPQExpBuffer(&buf,
4444 : : "SELECT n.nspname as \"%s\",\n"
4445 : : " t.typname as \"%s\",\n"
4446 : : " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
4447 : : " (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
4448 : : " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation) as \"%s\",\n"
4449 : : " CASE WHEN t.typnotnull THEN 'not null' END as \"%s\",\n"
4450 : : " t.typdefault as \"%s\",\n"
4451 : : " pg_catalog.array_to_string(ARRAY(\n"
4452 : : " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
4453 : : " ), ' ') as \"%s\"",
4454 : : gettext_noop("Schema"),
4455 : : gettext_noop("Name"),
4456 : : gettext_noop("Type"),
4457 : : gettext_noop("Collation"),
4458 : : gettext_noop("Nullable"),
4459 : : gettext_noop("Default"),
4460 : : gettext_noop("Check"));
4461 : :
4633 rhaas@postgresql.org 4462 [ + + ]: 24 : if (verbose)
4463 : : {
850 tgl@sss.pgh.pa.us 4464 :GBC 3 : appendPQExpBufferStr(&buf, ",\n ");
4465 : 3 : printACLColumn(&buf, "t.typacl");
4633 rhaas@postgresql.org 4466 : 3 : appendPQExpBuffer(&buf,
4467 : : ",\n d.description as \"%s\"",
4468 : : gettext_noop("Description"));
4469 : : }
4470 : :
3800 heikki.linnakangas@i 4471 :CBC 24 : appendPQExpBufferStr(&buf,
4472 : : "\nFROM pg_catalog.pg_type t\n"
4473 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
4474 : :
4633 rhaas@postgresql.org 4475 [ + + ]: 24 : if (verbose)
3800 heikki.linnakangas@i 4476 :GBC 3 : appendPQExpBufferStr(&buf,
4477 : : " LEFT JOIN pg_catalog.pg_description d "
4478 : : "ON d.classoid = t.tableoid AND d.objoid = t.oid "
4479 : : "AND d.objsubid = 0\n");
4480 : :
3800 heikki.linnakangas@i 4481 :CBC 24 : appendPQExpBufferStr(&buf, "WHERE t.typtype = 'd'\n");
4482 : :
5421 bruce@momjian.us 4483 [ + - - + ]: 24 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 4484 :UBC 0 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4485 : : " AND n.nspname <> 'information_schema'\n");
4486 : :
725 rhaas@postgresql.org 4487 [ + + ]:CBC 24 : if (!validateSQLNamePattern(&buf, pattern, true, false,
4488 : : "n.nspname", "t.typname", NULL,
4489 : : "pg_catalog.pg_type_is_visible(t.oid)",
4490 : : NULL, 3))
4491 : : {
633 michael@paquier.xyz 4492 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 4493 : 12 : return false;
4494 : : }
4495 : :
3800 heikki.linnakangas@i 4496 : 12 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4497 : :
3461 fujii@postgresql.org 4498 : 12 : res = PSQLexec(buf.data);
8026 peter_e@gmx.net 4499 : 12 : termPQExpBuffer(&buf);
8062 bruce@momjian.us 4500 [ - + ]: 12 : if (!res)
8062 bruce@momjian.us 4501 :UBC 0 : return false;
4502 : :
8026 peter_e@gmx.net 4503 :CBC 12 : myopt.title = _("List of domains");
5753 bruce@momjian.us 4504 : 12 : myopt.translate_header = true;
4505 : :
3056 tgl@sss.pgh.pa.us 4506 : 12 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4507 : :
8062 bruce@momjian.us 4508 : 12 : PQclear(res);
4509 : 12 : return true;
4510 : : }
4511 : :
4512 : : /*
4513 : : * \dc
4514 : : *
4515 : : * Describes conversions.
4516 : : */
4517 : : bool
4633 rhaas@postgresql.org 4518 : 21 : listConversions(const char *pattern, bool verbose, bool showSystem)
4519 : : {
4520 : : PQExpBufferData buf;
4521 : : PGresult *res;
7794 bruce@momjian.us 4522 : 21 : printQueryOpt myopt = pset.popt;
4523 : : static const bool translate_columns[] =
4524 : : {false, false, false, false, true, false};
4525 : :
4526 : 21 : initPQExpBuffer(&buf);
4527 : :
4528 : 21 : printfPQExpBuffer(&buf,
4529 : : "SELECT n.nspname AS \"%s\",\n"
4530 : : " c.conname AS \"%s\",\n"
4531 : : " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
4532 : : " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
4533 : : " CASE WHEN c.condefault THEN '%s'\n"
4534 : : " ELSE '%s' END AS \"%s\"",
4535 : : gettext_noop("Schema"),
4536 : : gettext_noop("Name"),
4537 : : gettext_noop("Source"),
4538 : : gettext_noop("Destination"),
4539 : : gettext_noop("yes"), gettext_noop("no"),
4540 : : gettext_noop("Default?"));
4541 : :
4633 rhaas@postgresql.org 4542 [ - + ]: 21 : if (verbose)
4633 rhaas@postgresql.org 4543 :UBC 0 : appendPQExpBuffer(&buf,
4544 : : ",\n d.description AS \"%s\"",
4545 : : gettext_noop("Description"));
4546 : :
3800 heikki.linnakangas@i 4547 :CBC 21 : appendPQExpBufferStr(&buf,
4548 : : "\nFROM pg_catalog.pg_conversion c\n"
4549 : : " JOIN pg_catalog.pg_namespace n "
4550 : : "ON n.oid = c.connamespace\n");
4551 : :
4633 rhaas@postgresql.org 4552 [ - + ]: 21 : if (verbose)
3800 heikki.linnakangas@i 4553 :UBC 0 : appendPQExpBufferStr(&buf,
4554 : : "LEFT JOIN pg_catalog.pg_description d "
4555 : : "ON d.classoid = c.tableoid\n"
4556 : : " AND d.objoid = c.oid "
4557 : : "AND d.objsubid = 0\n");
4558 : :
3800 heikki.linnakangas@i 4559 :CBC 21 : appendPQExpBufferStr(&buf, "WHERE true\n");
4560 : :
5421 bruce@momjian.us 4561 [ + - - + ]: 21 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 4562 :UBC 0 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
4563 : : " AND n.nspname <> 'information_schema'\n");
4564 : :
725 rhaas@postgresql.org 4565 [ + + ]:CBC 21 : if (!validateSQLNamePattern(&buf, pattern, true, false,
4566 : : "n.nspname", "c.conname", NULL,
4567 : : "pg_catalog.pg_conversion_is_visible(c.oid)",
4568 : : NULL, 3))
4569 : : {
633 michael@paquier.xyz 4570 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 4571 : 12 : return false;
4572 : : }
4573 : :
3800 heikki.linnakangas@i 4574 : 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4575 : :
3461 fujii@postgresql.org 4576 : 9 : res = PSQLexec(buf.data);
7794 bruce@momjian.us 4577 : 9 : termPQExpBuffer(&buf);
4578 [ - + ]: 9 : if (!res)
7794 bruce@momjian.us 4579 :UBC 0 : return false;
4580 : :
7794 bruce@momjian.us 4581 :CBC 9 : myopt.title = _("List of conversions");
5753 4582 : 9 : myopt.translate_header = true;
4583 : 9 : myopt.translate_columns = translate_columns;
3753 tgl@sss.pgh.pa.us 4584 : 9 : myopt.n_translate_columns = lengthof(translate_columns);
4585 : :
3056 4586 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4587 : :
7794 bruce@momjian.us 4588 : 9 : PQclear(res);
4589 : 9 : return true;
4590 : : }
4591 : :
4592 : : /*
4593 : : * \dconfig
4594 : : *
4595 : : * Describes configuration parameters.
4596 : : */
4597 : : bool
738 tgl@sss.pgh.pa.us 4598 : 6 : describeConfigurationParameters(const char *pattern, bool verbose,
4599 : : bool showSystem)
4600 : : {
4601 : : PQExpBufferData buf;
4602 : : PGresult *res;
4603 : 6 : printQueryOpt myopt = pset.popt;
4604 : :
4605 : 6 : initPQExpBuffer(&buf);
4606 : 6 : printfPQExpBuffer(&buf,
4607 : : "SELECT s.name AS \"%s\", "
4608 : : "pg_catalog.current_setting(s.name) AS \"%s\"",
4609 : : gettext_noop("Parameter"),
4610 : : gettext_noop("Value"));
4611 : :
4612 [ + + ]: 6 : if (verbose)
4613 : : {
4614 : 3 : appendPQExpBuffer(&buf,
4615 : : ", s.vartype AS \"%s\", s.context AS \"%s\", ",
4616 : : gettext_noop("Type"),
4617 : : gettext_noop("Context"));
4618 [ + - ]: 3 : if (pset.sversion >= 150000)
4619 : 3 : printACLColumn(&buf, "p.paracl");
4620 : : else
738 tgl@sss.pgh.pa.us 4621 :UBC 0 : appendPQExpBuffer(&buf, "NULL AS \"%s\"",
4622 : : gettext_noop("Access privileges"));
4623 : : }
4624 : :
738 tgl@sss.pgh.pa.us 4625 :CBC 6 : appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_settings s\n");
4626 : :
4627 [ + + + - ]: 6 : if (verbose && pset.sversion >= 150000)
4628 : 3 : appendPQExpBufferStr(&buf,
4629 : : " LEFT JOIN pg_catalog.pg_parameter_acl p\n"
4630 : : " ON pg_catalog.lower(s.name) = p.parname\n");
4631 : :
734 4632 [ + - ]: 6 : if (pattern)
4633 : 6 : processSQLNamePattern(pset.db, &buf, pattern,
4634 : : false, false,
4635 : : NULL, "pg_catalog.lower(s.name)", NULL,
4636 : : NULL, NULL, NULL);
4637 : : else
732 tgl@sss.pgh.pa.us 4638 :UBC 0 : appendPQExpBufferStr(&buf, "WHERE s.source <> 'default' AND\n"
4639 : : " s.setting IS DISTINCT FROM s.boot_val\n");
4640 : :
738 tgl@sss.pgh.pa.us 4641 :CBC 6 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
4642 : :
4643 : 6 : res = PSQLexec(buf.data);
4644 : 6 : termPQExpBuffer(&buf);
4645 [ - + ]: 6 : if (!res)
738 tgl@sss.pgh.pa.us 4646 :UBC 0 : return false;
4647 : :
734 tgl@sss.pgh.pa.us 4648 [ + - ]:CBC 6 : if (pattern)
4649 : 6 : myopt.title = _("List of configuration parameters");
4650 : : else
734 tgl@sss.pgh.pa.us 4651 :UBC 0 : myopt.title = _("List of non-default configuration parameters");
738 tgl@sss.pgh.pa.us 4652 :CBC 6 : myopt.translate_header = true;
4653 : :
4654 : 6 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4655 : :
4656 : 6 : PQclear(res);
4657 : 6 : return true;
4658 : : }
4659 : :
4660 : : /*
4661 : : * \dy
4662 : : *
4663 : : * Describes Event Triggers.
4664 : : */
4665 : : bool
4288 rhaas@postgresql.org 4666 : 12 : listEventTriggers(const char *pattern, bool verbose)
4667 : : {
4668 : : PQExpBufferData buf;
4669 : : PGresult *res;
4670 : 12 : printQueryOpt myopt = pset.popt;
4671 : : static const bool translate_columns[] =
4672 : : {false, false, false, true, false, false, false};
4673 : :
850 tgl@sss.pgh.pa.us 4674 [ - + ]: 12 : if (pset.sversion < 90300)
4675 : : {
4676 : : char sverbuf[32];
4677 : :
850 tgl@sss.pgh.pa.us 4678 :UBC 0 : pg_log_error("The server (version %s) does not support event triggers.",
4679 : : formatPGVersionNumber(pset.sversion, false,
4680 : : sverbuf, sizeof(sverbuf)));
4681 : 0 : return true;
4682 : : }
4683 : :
4288 rhaas@postgresql.org 4684 :CBC 12 : initPQExpBuffer(&buf);
4685 : :
4686 : 12 : printfPQExpBuffer(&buf,
4687 : : "SELECT evtname as \"%s\", "
4688 : : "evtevent as \"%s\", "
4689 : : "pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
4690 : : " case evtenabled when 'O' then '%s'"
4691 : : " when 'R' then '%s'"
4692 : : " when 'A' then '%s'"
4693 : : " when 'D' then '%s' end as \"%s\",\n"
4694 : : " e.evtfoid::pg_catalog.regproc as \"%s\", "
4695 : : "pg_catalog.array_to_string(array(select x"
4696 : : " from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
4697 : : gettext_noop("Name"),
4698 : : gettext_noop("Event"),
4699 : : gettext_noop("Owner"),
4700 : : gettext_noop("enabled"),
4701 : : gettext_noop("replica"),
4702 : : gettext_noop("always"),
4703 : : gettext_noop("disabled"),
4704 : : gettext_noop("Enabled"),
4705 : : gettext_noop("Function"),
4706 : : gettext_noop("Tags"));
4707 [ - + ]: 12 : if (verbose)
4288 rhaas@postgresql.org 4708 :UBC 0 : appendPQExpBuffer(&buf,
4709 : : ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
4710 : : gettext_noop("Description"));
3800 heikki.linnakangas@i 4711 :CBC 12 : appendPQExpBufferStr(&buf,
4712 : : "\nFROM pg_catalog.pg_event_trigger e ");
4713 : :
725 rhaas@postgresql.org 4714 [ + + ]: 12 : if (!validateSQLNamePattern(&buf, pattern, false, false,
4715 : : NULL, "evtname", NULL, NULL,
4716 : : NULL, 1))
4717 : : {
633 michael@paquier.xyz 4718 : 9 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 4719 : 9 : return false;
4720 : : }
4721 : :
3800 heikki.linnakangas@i 4722 : 3 : appendPQExpBufferStr(&buf, "ORDER BY 1");
4723 : :
3461 fujii@postgresql.org 4724 : 3 : res = PSQLexec(buf.data);
4288 rhaas@postgresql.org 4725 : 3 : termPQExpBuffer(&buf);
4726 [ - + ]: 3 : if (!res)
4288 rhaas@postgresql.org 4727 :UBC 0 : return false;
4728 : :
4288 rhaas@postgresql.org 4729 :CBC 3 : myopt.title = _("List of event triggers");
4730 : 3 : myopt.translate_header = true;
4731 : 3 : myopt.translate_columns = translate_columns;
3753 tgl@sss.pgh.pa.us 4732 : 3 : myopt.n_translate_columns = lengthof(translate_columns);
4733 : :
3056 4734 : 3 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4735 : :
4288 rhaas@postgresql.org 4736 : 3 : PQclear(res);
4737 : 3 : return true;
4738 : : }
4739 : :
4740 : : /*
4741 : : * \dX
4742 : : *
4743 : : * Describes extended statistics.
4744 : : */
4745 : : bool
1180 tomas.vondra@postgre 4746 : 51 : listExtendedStats(const char *pattern)
4747 : : {
4748 : : PQExpBufferData buf;
4749 : : PGresult *res;
4750 : 51 : printQueryOpt myopt = pset.popt;
4751 : :
4752 [ - + ]: 51 : if (pset.sversion < 100000)
4753 : : {
4754 : : char sverbuf[32];
4755 : :
1180 tomas.vondra@postgre 4756 :UBC 0 : pg_log_error("The server (version %s) does not support extended statistics.",
4757 : : formatPGVersionNumber(pset.sversion, false,
4758 : : sverbuf, sizeof(sverbuf)));
4759 : 0 : return true;
4760 : : }
4761 : :
1180 tomas.vondra@postgre 4762 :CBC 51 : initPQExpBuffer(&buf);
4763 : 51 : printfPQExpBuffer(&buf,
4764 : : "SELECT \n"
4765 : : "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text AS \"%s\", \n"
4766 : : "es.stxname AS \"%s\", \n",
4767 : : gettext_noop("Schema"),
4768 : : gettext_noop("Name"));
4769 : :
1115 4770 [ + - ]: 51 : if (pset.sversion >= 140000)
4771 : 51 : appendPQExpBuffer(&buf,
4772 : : "pg_catalog.format('%%s FROM %%s', \n"
4773 : : " pg_catalog.pg_get_statisticsobjdef_columns(es.oid), \n"
4774 : : " es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4775 : : gettext_noop("Definition"));
4776 : : else
1115 tomas.vondra@postgre 4777 :UBC 0 : appendPQExpBuffer(&buf,
4778 : : "pg_catalog.format('%%s FROM %%s', \n"
4779 : : " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n"
4780 : : " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n"
4781 : : " JOIN pg_catalog.pg_attribute a \n"
4782 : : " ON (es.stxrelid = a.attrelid \n"
4783 : : " AND a.attnum = s.attnum \n"
4784 : : " AND NOT a.attisdropped)), \n"
4785 : : "es.stxrelid::pg_catalog.regclass) AS \"%s\"",
4786 : : gettext_noop("Definition"));
4787 : :
1180 tomas.vondra@postgre 4788 :CBC 51 : appendPQExpBuffer(&buf,
4789 : : ",\nCASE WHEN 'd' = any(es.stxkind) THEN 'defined' \n"
4790 : : "END AS \"%s\", \n"
4791 : : "CASE WHEN 'f' = any(es.stxkind) THEN 'defined' \n"
4792 : : "END AS \"%s\"",
4793 : : gettext_noop("Ndistinct"),
4794 : : gettext_noop("Dependencies"));
4795 : :
4796 : : /*
4797 : : * Include the MCV statistics kind.
4798 : : */
4799 [ + - ]: 51 : if (pset.sversion >= 120000)
4800 : : {
4801 : 51 : appendPQExpBuffer(&buf,
4802 : : ",\nCASE WHEN 'm' = any(es.stxkind) THEN 'defined' \n"
4803 : : "END AS \"%s\" ",
4804 : : gettext_noop("MCV"));
4805 : : }
4806 : :
4807 : 51 : appendPQExpBufferStr(&buf,
4808 : : " \nFROM pg_catalog.pg_statistic_ext es \n");
4809 : :
725 rhaas@postgresql.org 4810 [ + + ]: 51 : if (!validateSQLNamePattern(&buf, pattern,
4811 : : false, false,
4812 : : "es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname",
4813 : : NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)",
4814 : : NULL, 3))
4815 : : {
633 michael@paquier.xyz 4816 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 4817 : 12 : return false;
4818 : : }
4819 : :
1180 tomas.vondra@postgre 4820 : 39 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
4821 : :
4822 : 39 : res = PSQLexec(buf.data);
4823 : 39 : termPQExpBuffer(&buf);
4824 [ - + ]: 39 : if (!res)
1180 tomas.vondra@postgre 4825 :UBC 0 : return false;
4826 : :
1180 tomas.vondra@postgre 4827 :CBC 39 : myopt.title = _("List of extended statistics");
4828 : 39 : myopt.translate_header = true;
4829 : :
4830 : 39 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4831 : :
4832 : 39 : PQclear(res);
4833 : 39 : return true;
4834 : : }
4835 : :
4836 : : /*
4837 : : * \dC
4838 : : *
4839 : : * Describes casts.
4840 : : */
4841 : : bool
4637 rhaas@postgresql.org 4842 : 21 : listCasts(const char *pattern, bool verbose)
4843 : : {
4844 : : PQExpBufferData buf;
4845 : : PGresult *res;
7794 bruce@momjian.us 4846 : 21 : printQueryOpt myopt = pset.popt;
4847 : : static const bool translate_columns[] = {false, false, false, true, false};
4848 : :
4849 : 21 : initPQExpBuffer(&buf);
4850 : :
4851 : 21 : printfPQExpBuffer(&buf,
4852 : : "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
4853 : : " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n",
4854 : : gettext_noop("Source type"),
4855 : : gettext_noop("Target type"));
4856 : :
4857 : : /*
4858 : : * We don't attempt to localize '(binary coercible)' or '(with inout)',
4859 : : * because there's too much risk of gettext translating a function name
4860 : : * that happens to match some string in the PO database.
4861 : : */
850 tgl@sss.pgh.pa.us 4862 : 21 : appendPQExpBuffer(&buf,
4863 : : " CASE WHEN c.castmethod = '%c' THEN '(binary coercible)'\n"
4864 : : " WHEN c.castmethod = '%c' THEN '(with inout)'\n"
4865 : : " ELSE p.proname\n"
4866 : : " END AS \"%s\",\n",
4867 : : COERCION_METHOD_BINARY,
4868 : : COERCION_METHOD_INOUT,
4869 : : gettext_noop("Function"));
4870 : :
2053 4871 : 21 : appendPQExpBuffer(&buf,
4872 : : " CASE WHEN c.castcontext = '%c' THEN '%s'\n"
4873 : : " WHEN c.castcontext = '%c' THEN '%s'\n"
4874 : : " ELSE '%s'\n"
4875 : : " END AS \"%s\"",
4876 : : COERCION_CODE_EXPLICIT,
4877 : : gettext_noop("no"),
4878 : : COERCION_CODE_ASSIGNMENT,
4879 : : gettext_noop("in assignment"),
4880 : : gettext_noop("yes"),
4881 : : gettext_noop("Implicit?"));
4882 : :
4637 rhaas@postgresql.org 4883 [ - + ]: 21 : if (verbose)
4637 rhaas@postgresql.org 4884 :UBC 0 : appendPQExpBuffer(&buf,
4885 : : ",\n d.description AS \"%s\"",
4886 : : gettext_noop("Description"));
4887 : :
4888 : : /*
4889 : : * We need a left join to pg_proc for binary casts; the others are just
4890 : : * paranoia.
4891 : : */
3800 heikki.linnakangas@i 4892 :CBC 21 : appendPQExpBufferStr(&buf,
4893 : : "\nFROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
4894 : : " ON c.castfunc = p.oid\n"
4895 : : " LEFT JOIN pg_catalog.pg_type ts\n"
4896 : : " ON c.castsource = ts.oid\n"
4897 : : " LEFT JOIN pg_catalog.pg_namespace ns\n"
4898 : : " ON ns.oid = ts.typnamespace\n"
4899 : : " LEFT JOIN pg_catalog.pg_type tt\n"
4900 : : " ON c.casttarget = tt.oid\n"
4901 : : " LEFT JOIN pg_catalog.pg_namespace nt\n"
4902 : : " ON nt.oid = tt.typnamespace\n");
4903 : :
4637 rhaas@postgresql.org 4904 [ - + ]: 21 : if (verbose)
3800 heikki.linnakangas@i 4905 :UBC 0 : appendPQExpBufferStr(&buf,
4906 : : " LEFT JOIN pg_catalog.pg_description d\n"
4907 : : " ON d.classoid = c.tableoid AND d.objoid = "
4908 : : "c.oid AND d.objsubid = 0\n");
4909 : :
3800 heikki.linnakangas@i 4910 :CBC 21 : appendPQExpBufferStr(&buf, "WHERE ( (true");
4911 : :
4912 : : /*
4913 : : * Match name pattern against either internal or external name of either
4914 : : * castsource or casttarget
4915 : : */
725 rhaas@postgresql.org 4916 [ + + ]: 21 : if (!validateSQLNamePattern(&buf, pattern, true, false,
4917 : : "ns.nspname", "ts.typname",
4918 : : "pg_catalog.format_type(ts.oid, NULL)",
4919 : : "pg_catalog.pg_type_is_visible(ts.oid)",
4920 : : NULL, 3))
633 michael@paquier.xyz 4921 : 12 : goto error_return;
4922 : :
3800 heikki.linnakangas@i 4923 : 9 : appendPQExpBufferStr(&buf, ") OR (true");
4924 : :
725 rhaas@postgresql.org 4925 [ - + ]: 9 : if (!validateSQLNamePattern(&buf, pattern, true, false,
4926 : : "nt.nspname", "tt.typname",
4927 : : "pg_catalog.format_type(tt.oid, NULL)",
4928 : : "pg_catalog.pg_type_is_visible(tt.oid)",
4929 : : NULL, 3))
633 michael@paquier.xyz 4930 :UBC 0 : goto error_return;
4931 : :
3800 heikki.linnakangas@i 4932 :CBC 9 : appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
4933 : :
3461 fujii@postgresql.org 4934 : 9 : res = PSQLexec(buf.data);
7794 bruce@momjian.us 4935 : 9 : termPQExpBuffer(&buf);
4936 [ - + ]: 9 : if (!res)
7794 bruce@momjian.us 4937 :UBC 0 : return false;
4938 : :
7794 bruce@momjian.us 4939 :CBC 9 : myopt.title = _("List of casts");
5753 4940 : 9 : myopt.translate_header = true;
4941 : 9 : myopt.translate_columns = translate_columns;
3753 tgl@sss.pgh.pa.us 4942 : 9 : myopt.n_translate_columns = lengthof(translate_columns);
4943 : :
3056 4944 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
4945 : :
7794 bruce@momjian.us 4946 : 9 : PQclear(res);
4947 : 9 : return true;
4948 : :
633 michael@paquier.xyz 4949 : 12 : error_return:
4950 : 12 : termPQExpBuffer(&buf);
4951 : 12 : return false;
4952 : : }
4953 : :
4954 : : /*
4955 : : * \dO
4956 : : *
4957 : : * Describes collations.
4958 : : */
4959 : : bool
4810 peter_e@gmx.net 4960 : 21 : listCollations(const char *pattern, bool verbose, bool showSystem)
4961 : : {
4962 : : PQExpBufferData buf;
4963 : : PGresult *res;
4964 : 21 : printQueryOpt myopt = pset.popt;
4965 : : static const bool translate_columns[] = {false, false, false, false, false, false, false, true, false};
4966 : :
4967 : 21 : initPQExpBuffer(&buf);
4968 : :
4969 : 21 : printfPQExpBuffer(&buf,
4970 : : "SELECT\n"
4971 : : " n.nspname AS \"%s\",\n"
4972 : : " c.collname AS \"%s\",\n",
4973 : : gettext_noop("Schema"),
4974 : : gettext_noop("Name"));
4975 : :
403 peter@eisentraut.org 4976 [ + - ]: 21 : if (pset.sversion >= 100000)
4977 : 21 : appendPQExpBuffer(&buf,
4978 : : " CASE c.collprovider WHEN 'd' THEN 'default' WHEN 'b' THEN 'builtin' WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS \"%s\",\n",
4979 : : gettext_noop("Provider"));
4980 : : else
403 peter@eisentraut.org 4981 :UBC 0 : appendPQExpBuffer(&buf,
4982 : : " 'libc' AS \"%s\",\n",
4983 : : gettext_noop("Provider"));
4984 : :
403 peter@eisentraut.org 4985 :CBC 21 : appendPQExpBuffer(&buf,
4986 : : " c.collcollate AS \"%s\",\n"
4987 : : " c.collctype AS \"%s\",\n",
4988 : : gettext_noop("Collate"),
4989 : : gettext_noop("Ctype"));
4990 : :
36 jdavis@postgresql.or 4991 [ + - ]:GNC 21 : if (pset.sversion >= 170000)
4992 : 21 : appendPQExpBuffer(&buf,
4993 : : " c.colllocale AS \"%s\",\n",
4994 : : gettext_noop("Locale"));
36 jdavis@postgresql.or 4995 [ # # ]:UNC 0 : else if (pset.sversion >= 150000)
759 peter@eisentraut.org 4996 :LBC (21) : appendPQExpBuffer(&buf,
4997 : : " c.colliculocale AS \"%s\",\n",
4998 : : gettext_noop("Locale"));
4999 : : else
759 peter@eisentraut.org 5000 :UBC 0 : appendPQExpBuffer(&buf,
5001 : : " c.collcollate AS \"%s\",\n",
5002 : : gettext_noop("Locale"));
5003 : :
403 peter@eisentraut.org 5004 [ + - ]:CBC 21 : if (pset.sversion >= 160000)
2579 peter_e@gmx.net 5005 : 21 : appendPQExpBuffer(&buf,
5006 : : " c.collicurules AS \"%s\",\n",
5007 : : gettext_noop("ICU Rules"));
5008 : : else
1850 peter@eisentraut.org 5009 :UBC 0 : appendPQExpBuffer(&buf,
5010 : : " NULL AS \"%s\",\n",
5011 : : gettext_noop("ICU Rules"));
5012 : :
1850 peter@eisentraut.org 5013 [ + - ]:CBC 21 : if (pset.sversion >= 120000)
5014 : 21 : appendPQExpBuffer(&buf,
5015 : : " CASE WHEN c.collisdeterministic THEN '%s' ELSE '%s' END AS \"%s\"",
5016 : : gettext_noop("yes"), gettext_noop("no"),
5017 : : gettext_noop("Deterministic?"));
5018 : : else
1850 peter@eisentraut.org 5019 :UBC 0 : appendPQExpBuffer(&buf,
5020 : : " '%s' AS \"%s\"",
5021 : : gettext_noop("yes"),
5022 : : gettext_noop("Deterministic?"));
5023 : :
4810 peter_e@gmx.net 5024 [ - + ]:CBC 21 : if (verbose)
4810 peter_e@gmx.net 5025 :UBC 0 : appendPQExpBuffer(&buf,
5026 : : ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
5027 : : gettext_noop("Description"));
5028 : :
3800 heikki.linnakangas@i 5029 :CBC 21 : appendPQExpBufferStr(&buf,
5030 : : "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
5031 : : "WHERE n.oid = c.collnamespace\n");
5032 : :
4810 peter_e@gmx.net 5033 [ + - - + ]: 21 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 5034 :UBC 0 : appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
5035 : : " AND n.nspname <> 'information_schema'\n");
5036 : :
5037 : : /*
5038 : : * Hide collations that aren't usable in the current database's encoding.
5039 : : * If you think to change this, note that pg_collation_is_visible rejects
5040 : : * unusable collations, so you will need to hack name pattern processing
5041 : : * somehow to avoid inconsistent behavior.
5042 : : */
3800 heikki.linnakangas@i 5043 :CBC 21 : appendPQExpBufferStr(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
5044 : :
725 rhaas@postgresql.org 5045 [ + + ]: 21 : if (!validateSQLNamePattern(&buf, pattern, true, false,
5046 : : "n.nspname", "c.collname", NULL,
5047 : : "pg_catalog.pg_collation_is_visible(c.oid)",
5048 : : NULL, 3))
5049 : : {
633 michael@paquier.xyz 5050 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5051 : 12 : return false;
5052 : : }
5053 : :
3800 heikki.linnakangas@i 5054 : 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5055 : :
3461 fujii@postgresql.org 5056 : 9 : res = PSQLexec(buf.data);
4810 peter_e@gmx.net 5057 : 9 : termPQExpBuffer(&buf);
5058 [ - + ]: 9 : if (!res)
4810 peter_e@gmx.net 5059 :UBC 0 : return false;
5060 : :
4810 peter_e@gmx.net 5061 :CBC 9 : myopt.title = _("List of collations");
5062 : 9 : myopt.translate_header = true;
5063 : 9 : myopt.translate_columns = translate_columns;
3753 tgl@sss.pgh.pa.us 5064 : 9 : myopt.n_translate_columns = lengthof(translate_columns);
5065 : :
3056 5066 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5067 : :
4810 peter_e@gmx.net 5068 : 9 : PQclear(res);
5069 : 9 : return true;
5070 : : }
5071 : :
5072 : : /*
5073 : : * \dn
5074 : : *
5075 : : * Describes schemas (namespaces)
5076 : : */
5077 : : bool
4908 tgl@sss.pgh.pa.us 5078 : 12 : listSchemas(const char *pattern, bool verbose, bool showSystem)
5079 : : {
5080 : : PQExpBufferData buf;
5081 : : PGresult *res;
7768 5082 : 12 : printQueryOpt myopt = pset.popt;
900 akapila@postgresql.o 5083 : 12 : int pub_schema_tuples = 0;
5084 : 12 : char **footers = NULL;
5085 : :
7768 tgl@sss.pgh.pa.us 5086 : 12 : initPQExpBuffer(&buf);
5087 : 12 : printfPQExpBuffer(&buf,
5088 : : "SELECT n.nspname AS \"%s\",\n"
5089 : : " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
5090 : : gettext_noop("Name"),
5091 : : gettext_noop("Owner"));
5092 : :
7215 bruce@momjian.us 5093 [ - + ]: 12 : if (verbose)
5094 : : {
3800 heikki.linnakangas@i 5095 :UBC 0 : appendPQExpBufferStr(&buf, ",\n ");
5583 tgl@sss.pgh.pa.us 5096 : 0 : printACLColumn(&buf, "n.nspacl");
7215 bruce@momjian.us 5097 : 0 : appendPQExpBuffer(&buf,
5098 : : ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
5099 : : gettext_noop("Description"));
5100 : : }
5101 : :
1746 drowley@postgresql.o 5102 :CBC 12 : appendPQExpBufferStr(&buf,
5103 : : "\nFROM pg_catalog.pg_namespace n\n");
5104 : :
4908 tgl@sss.pgh.pa.us 5105 [ + - - + ]: 12 : if (!showSystem && !pattern)
3800 heikki.linnakangas@i 5106 :UBC 0 : appendPQExpBufferStr(&buf,
5107 : : "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
5108 : :
725 rhaas@postgresql.org 5109 [ + + ]:CBC 12 : if (!validateSQLNamePattern(&buf, pattern,
5110 [ + - - + ]: 12 : !showSystem && !pattern, false,
5111 : : NULL, "n.nspname", NULL,
5112 : : NULL,
725 rhaas@postgresql.org 5113 :ECB (12) : NULL, 2))
633 michael@paquier.xyz 5114 :CBC 9 : goto error_return;
5115 : :
3800 heikki.linnakangas@i 5116 : 3 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
5117 : :
3461 fujii@postgresql.org 5118 : 3 : res = PSQLexec(buf.data);
7768 tgl@sss.pgh.pa.us 5119 [ - + ]: 3 : if (!res)
633 michael@paquier.xyz 5120 :UBC 0 : goto error_return;
5121 : :
7768 tgl@sss.pgh.pa.us 5122 :CBC 3 : myopt.title = _("List of schemas");
5753 bruce@momjian.us 5123 : 3 : myopt.translate_header = true;
5124 : :
900 akapila@postgresql.o 5125 [ + - + - ]: 3 : if (pattern && pset.sversion >= 150000)
5126 : : {
5127 : : PGresult *result;
5128 : : int i;
5129 : :
5130 : 3 : printfPQExpBuffer(&buf,
5131 : : "SELECT pubname \n"
5132 : : "FROM pg_catalog.pg_publication p\n"
5133 : : " JOIN pg_catalog.pg_publication_namespace pn ON p.oid = pn.pnpubid\n"
5134 : : " JOIN pg_catalog.pg_namespace n ON n.oid = pn.pnnspid \n"
5135 : : "WHERE n.nspname = '%s'\n"
5136 : : "ORDER BY 1",
5137 : : pattern);
5138 : 3 : result = PSQLexec(buf.data);
5139 [ - + ]: 3 : if (!result)
633 michael@paquier.xyz 5140 :UBC 0 : goto error_return;
5141 : : else
900 akapila@postgresql.o 5142 :CBC 3 : pub_schema_tuples = PQntuples(result);
5143 : :
5144 [ - + ]: 3 : if (pub_schema_tuples > 0)
5145 : : {
5146 : : /*
5147 : : * Allocate memory for footers. Size of footers will be 1 (for
5148 : : * storing "Publications:" string) + publication schema mapping
5149 : : * count + 1 (for storing NULL).
5150 : : */
900 akapila@postgresql.o 5151 :UBC 0 : footers = (char **) pg_malloc((1 + pub_schema_tuples + 1) * sizeof(char *));
5152 : 0 : footers[0] = pg_strdup(_("Publications:"));
5153 : :
5154 : : /* Might be an empty set - that's ok */
5155 [ # # ]: 0 : for (i = 0; i < pub_schema_tuples; i++)
5156 : : {
738 tomas.vondra@postgre 5157 : 0 : printfPQExpBuffer(&buf, " \"%s\"",
5158 : : PQgetvalue(result, i, 0));
5159 : :
900 akapila@postgresql.o 5160 : 0 : footers[i + 1] = pg_strdup(buf.data);
5161 : : }
5162 : :
5163 : 0 : footers[i + 1] = NULL;
5164 : 0 : myopt.footers = footers;
5165 : : }
5166 : :
900 akapila@postgresql.o 5167 :CBC 3 : PQclear(result);
5168 : : }
5169 : :
3056 tgl@sss.pgh.pa.us 5170 : 3 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5171 : :
900 akapila@postgresql.o 5172 : 3 : termPQExpBuffer(&buf);
7768 tgl@sss.pgh.pa.us 5173 : 3 : PQclear(res);
5174 : :
5175 : : /* Free the memory allocated for the footer */
900 akapila@postgresql.o 5176 [ - + ]: 3 : if (footers)
5177 : : {
900 akapila@postgresql.o 5178 :UBC 0 : char **footer = NULL;
5179 : :
5180 [ # # ]: 0 : for (footer = footers; *footer; footer++)
5181 : 0 : pg_free(*footer);
5182 : :
5183 : 0 : pg_free(footers);
5184 : : }
5185 : :
7768 tgl@sss.pgh.pa.us 5186 :CBC 3 : return true;
5187 : :
633 michael@paquier.xyz 5188 : 9 : error_return:
5189 : 9 : termPQExpBuffer(&buf);
5190 : 9 : return false;
5191 : : }
5192 : :
5193 : :
5194 : : /*
5195 : : * \dFp
5196 : : * list text search parsers
5197 : : */
5198 : : bool
6081 tgl@sss.pgh.pa.us 5199 : 21 : listTSParsers(const char *pattern, bool verbose)
5200 : : {
5201 : : PQExpBufferData buf;
5202 : : PGresult *res;
5203 : 21 : printQueryOpt myopt = pset.popt;
5204 : :
5205 [ - + ]: 21 : if (verbose)
6081 tgl@sss.pgh.pa.us 5206 :UBC 0 : return listTSParsersVerbose(pattern);
5207 : :
6081 tgl@sss.pgh.pa.us 5208 :CBC 21 : initPQExpBuffer(&buf);
5209 : :
5210 : 21 : printfPQExpBuffer(&buf,
5211 : : "SELECT\n"
5212 : : " n.nspname as \"%s\",\n"
5213 : : " p.prsname as \"%s\",\n"
5214 : : " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
5215 : : "FROM pg_catalog.pg_ts_parser p\n"
5216 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
5217 : : gettext_noop("Schema"),
5218 : : gettext_noop("Name"),
5219 : : gettext_noop("Description")
5220 : : );
5221 : :
725 rhaas@postgresql.org 5222 [ + + ]: 21 : if (!validateSQLNamePattern(&buf, pattern, false, false,
5223 : : "n.nspname", "p.prsname", NULL,
5224 : : "pg_catalog.pg_ts_parser_is_visible(p.oid)",
5225 : : NULL, 3))
5226 : : {
633 michael@paquier.xyz 5227 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5228 : 12 : return false;
5229 : : }
5230 : :
3800 heikki.linnakangas@i 5231 : 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5232 : :
3461 fujii@postgresql.org 5233 : 9 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5234 : 9 : termPQExpBuffer(&buf);
5235 [ - + ]: 9 : if (!res)
6081 tgl@sss.pgh.pa.us 5236 :UBC 0 : return false;
5237 : :
6081 tgl@sss.pgh.pa.us 5238 :CBC 9 : myopt.title = _("List of text search parsers");
5753 bruce@momjian.us 5239 : 9 : myopt.translate_header = true;
5240 : :
3056 tgl@sss.pgh.pa.us 5241 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5242 : :
6081 5243 : 9 : PQclear(res);
5244 : 9 : return true;
5245 : : }
5246 : :
5247 : : /*
5248 : : * full description of parsers
5249 : : */
5250 : : static bool
6081 tgl@sss.pgh.pa.us 5251 :UBC 0 : listTSParsersVerbose(const char *pattern)
5252 : : {
5253 : : PQExpBufferData buf;
5254 : : PGresult *res;
5255 : : int i;
5256 : :
5257 : 0 : initPQExpBuffer(&buf);
5258 : :
5259 : 0 : printfPQExpBuffer(&buf,
5260 : : "SELECT p.oid,\n"
5261 : : " n.nspname,\n"
5262 : : " p.prsname\n"
5263 : : "FROM pg_catalog.pg_ts_parser p\n"
5264 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
5265 : : );
5266 : :
725 rhaas@postgresql.org 5267 [ # # ]: 0 : if (!validateSQLNamePattern(&buf, pattern, false, false,
5268 : : "n.nspname", "p.prsname", NULL,
5269 : : "pg_catalog.pg_ts_parser_is_visible(p.oid)",
5270 : : NULL, 3))
5271 : : {
633 michael@paquier.xyz 5272 : 0 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5273 : 0 : return false;
5274 : : }
5275 : :
3800 heikki.linnakangas@i 5276 : 0 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5277 : :
3461 fujii@postgresql.org 5278 : 0 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5279 : 0 : termPQExpBuffer(&buf);
5280 [ # # ]: 0 : if (!res)
5281 : 0 : return false;
5282 : :
5283 [ # # ]: 0 : if (PQntuples(res) == 0)
5284 : : {
5285 [ # # ]: 0 : if (!pset.quiet)
5286 : : {
2453 5287 [ # # ]: 0 : if (pattern)
1840 peter@eisentraut.org 5288 : 0 : pg_log_error("Did not find any text search parser named \"%s\".",
5289 : : pattern);
5290 : : else
5291 : 0 : pg_log_error("Did not find any text search parsers.");
5292 : : }
6081 tgl@sss.pgh.pa.us 5293 : 0 : PQclear(res);
5294 : 0 : return false;
5295 : : }
5296 : :
5297 [ # # ]: 0 : for (i = 0; i < PQntuples(res); i++)
5298 : : {
5299 : : const char *oid;
5300 : 0 : const char *nspname = NULL;
5301 : : const char *prsname;
5302 : :
5303 : 0 : oid = PQgetvalue(res, i, 0);
5304 [ # # ]: 0 : if (!PQgetisnull(res, i, 1))
5305 : 0 : nspname = PQgetvalue(res, i, 1);
5306 : 0 : prsname = PQgetvalue(res, i, 2);
5307 : :
5308 [ # # ]: 0 : if (!describeOneTSParser(oid, nspname, prsname))
5309 : : {
5310 : 0 : PQclear(res);
5311 : 0 : return false;
5312 : : }
5313 : :
5314 [ # # ]: 0 : if (cancel_pressed)
5315 : : {
5316 : 0 : PQclear(res);
5317 : 0 : return false;
5318 : : }
5319 : : }
5320 : :
5321 : 0 : PQclear(res);
5322 : 0 : return true;
5323 : : }
5324 : :
5325 : : static bool
5326 : 0 : describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
5327 : : {
5328 : : PQExpBufferData buf;
5329 : : PGresult *res;
5330 : : PQExpBufferData title;
5331 : 0 : printQueryOpt myopt = pset.popt;
5332 : : static const bool translate_columns[] = {true, false, false};
5333 : :
5334 : 0 : initPQExpBuffer(&buf);
5335 : :
5336 : 0 : printfPQExpBuffer(&buf,
5337 : : "SELECT '%s' AS \"%s\",\n"
5338 : : " p.prsstart::pg_catalog.regproc AS \"%s\",\n"
5339 : : " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\"\n"
5340 : : " FROM pg_catalog.pg_ts_parser p\n"
5341 : : " WHERE p.oid = '%s'\n"
5342 : : "UNION ALL\n"
5343 : : "SELECT '%s',\n"
5344 : : " p.prstoken::pg_catalog.regproc,\n"
5345 : : " pg_catalog.obj_description(p.prstoken, 'pg_proc')\n"
5346 : : " FROM pg_catalog.pg_ts_parser p\n"
5347 : : " WHERE p.oid = '%s'\n"
5348 : : "UNION ALL\n"
5349 : : "SELECT '%s',\n"
5350 : : " p.prsend::pg_catalog.regproc,\n"
5351 : : " pg_catalog.obj_description(p.prsend, 'pg_proc')\n"
5352 : : " FROM pg_catalog.pg_ts_parser p\n"
5353 : : " WHERE p.oid = '%s'\n"
5354 : : "UNION ALL\n"
5355 : : "SELECT '%s',\n"
5356 : : " p.prsheadline::pg_catalog.regproc,\n"
5357 : : " pg_catalog.obj_description(p.prsheadline, 'pg_proc')\n"
5358 : : " FROM pg_catalog.pg_ts_parser p\n"
5359 : : " WHERE p.oid = '%s'\n"
5360 : : "UNION ALL\n"
5361 : : "SELECT '%s',\n"
5362 : : " p.prslextype::pg_catalog.regproc,\n"
5363 : : " pg_catalog.obj_description(p.prslextype, 'pg_proc')\n"
5364 : : " FROM pg_catalog.pg_ts_parser p\n"
5365 : : " WHERE p.oid = '%s';",
5366 : : gettext_noop("Start parse"),
5367 : : gettext_noop("Method"),
5368 : : gettext_noop("Function"),
5369 : : gettext_noop("Description"),
5370 : : oid,
5371 : : gettext_noop("Get next token"),
5372 : : oid,
5373 : : gettext_noop("End parse"),
5374 : : oid,
5375 : : gettext_noop("Get headline"),
5376 : : oid,
5377 : : gettext_noop("Get token types"),
5378 : : oid);
5379 : :
3461 fujii@postgresql.org 5380 : 0 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5381 : 0 : termPQExpBuffer(&buf);
5382 [ # # ]: 0 : if (!res)
5383 : 0 : return false;
5384 : :
2453 5385 : 0 : initPQExpBuffer(&title);
6081 5386 [ # # ]: 0 : if (nspname)
2453 5387 : 0 : printfPQExpBuffer(&title, _("Text search parser \"%s.%s\""),
5388 : : nspname, prsname);
5389 : : else
5390 : 0 : printfPQExpBuffer(&title, _("Text search parser \"%s\""), prsname);
5391 : 0 : myopt.title = title.data;
6081 5392 : 0 : myopt.footers = NULL;
4366 rhaas@postgresql.org 5393 : 0 : myopt.topt.default_footer = false;
5753 bruce@momjian.us 5394 : 0 : myopt.translate_header = true;
5395 : 0 : myopt.translate_columns = translate_columns;
3753 tgl@sss.pgh.pa.us 5396 : 0 : myopt.n_translate_columns = lengthof(translate_columns);
5397 : :
3056 5398 : 0 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5399 : :
6081 5400 : 0 : PQclear(res);
5401 : :
5402 : 0 : initPQExpBuffer(&buf);
5403 : :
5404 : 0 : printfPQExpBuffer(&buf,
5405 : : "SELECT t.alias as \"%s\",\n"
5406 : : " t.description as \"%s\"\n"
5407 : : "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t\n"
5408 : : "ORDER BY 1;",
5409 : : gettext_noop("Token name"),
5410 : : gettext_noop("Description"),
5411 : : oid);
5412 : :
3461 fujii@postgresql.org 5413 : 0 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5414 : 0 : termPQExpBuffer(&buf);
5415 [ # # ]: 0 : if (!res)
5416 : : {
633 michael@paquier.xyz 5417 : 0 : termPQExpBuffer(&title);
6081 tgl@sss.pgh.pa.us 5418 : 0 : return false;
5419 : : }
5420 : :
5421 [ # # ]: 0 : if (nspname)
2453 5422 : 0 : printfPQExpBuffer(&title, _("Token types for parser \"%s.%s\""),
5423 : : nspname, prsname);
5424 : : else
5425 : 0 : printfPQExpBuffer(&title, _("Token types for parser \"%s\""), prsname);
5426 : 0 : myopt.title = title.data;
6081 5427 : 0 : myopt.footers = NULL;
4366 rhaas@postgresql.org 5428 : 0 : myopt.topt.default_footer = true;
5753 bruce@momjian.us 5429 : 0 : myopt.translate_header = true;
5430 : 0 : myopt.translate_columns = NULL;
3753 tgl@sss.pgh.pa.us 5431 : 0 : myopt.n_translate_columns = 0;
5432 : :
3056 5433 : 0 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5434 : :
2453 5435 : 0 : termPQExpBuffer(&title);
6081 5436 : 0 : PQclear(res);
5437 : 0 : return true;
5438 : : }
5439 : :
5440 : :
5441 : : /*
5442 : : * \dFd
5443 : : * list text search dictionaries
5444 : : */
5445 : : bool
6081 tgl@sss.pgh.pa.us 5446 :CBC 21 : listTSDictionaries(const char *pattern, bool verbose)
5447 : : {
5448 : : PQExpBufferData buf;
5449 : : PGresult *res;
5450 : 21 : printQueryOpt myopt = pset.popt;
5451 : :
5452 : 21 : initPQExpBuffer(&buf);
5453 : :
5454 : 21 : printfPQExpBuffer(&buf,
5455 : : "SELECT\n"
5456 : : " n.nspname as \"%s\",\n"
5457 : : " d.dictname as \"%s\",\n",
5458 : : gettext_noop("Schema"),
5459 : : gettext_noop("Name"));
5460 : :
5461 [ - + ]: 21 : if (verbose)
5462 : : {
6081 tgl@sss.pgh.pa.us 5463 :UBC 0 : appendPQExpBuffer(&buf,
5464 : : " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM\n"
5465 : : " pg_catalog.pg_ts_template t\n"
5466 : : " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace\n"
5467 : : " WHERE d.dicttemplate = t.oid ) AS \"%s\",\n"
5468 : : " d.dictinitoption as \"%s\",\n",
5469 : : gettext_noop("Template"),
5470 : : gettext_noop("Init options"));
5471 : : }
5472 : :
6081 tgl@sss.pgh.pa.us 5473 :CBC 21 : appendPQExpBuffer(&buf,
5474 : : " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
5475 : : gettext_noop("Description"));
5476 : :
3800 heikki.linnakangas@i 5477 : 21 : appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_dict d\n"
5478 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
5479 : :
725 rhaas@postgresql.org 5480 [ + + ]: 21 : if (!validateSQLNamePattern(&buf, pattern, false, false,
5481 : : "n.nspname", "d.dictname", NULL,
5482 : : "pg_catalog.pg_ts_dict_is_visible(d.oid)",
5483 : : NULL, 3))
5484 : : {
633 michael@paquier.xyz 5485 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5486 : 12 : return false;
5487 : : }
5488 : :
3800 heikki.linnakangas@i 5489 : 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5490 : :
3461 fujii@postgresql.org 5491 : 9 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5492 : 9 : termPQExpBuffer(&buf);
5493 [ - + ]: 9 : if (!res)
6081 tgl@sss.pgh.pa.us 5494 :UBC 0 : return false;
5495 : :
6081 tgl@sss.pgh.pa.us 5496 :CBC 9 : myopt.title = _("List of text search dictionaries");
5753 bruce@momjian.us 5497 : 9 : myopt.translate_header = true;
5498 : :
3056 tgl@sss.pgh.pa.us 5499 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5500 : :
6081 5501 : 9 : PQclear(res);
5502 : 9 : return true;
5503 : : }
5504 : :
5505 : :
5506 : : /*
5507 : : * \dFt
5508 : : * list text search templates
5509 : : */
5510 : : bool
5511 : 21 : listTSTemplates(const char *pattern, bool verbose)
5512 : : {
5513 : : PQExpBufferData buf;
5514 : : PGresult *res;
5515 : 21 : printQueryOpt myopt = pset.popt;
5516 : :
5517 : 21 : initPQExpBuffer(&buf);
5518 : :
6080 5519 [ - + ]: 21 : if (verbose)
6080 tgl@sss.pgh.pa.us 5520 :UBC 0 : printfPQExpBuffer(&buf,
5521 : : "SELECT\n"
5522 : : " n.nspname AS \"%s\",\n"
5523 : : " t.tmplname AS \"%s\",\n"
5524 : : " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
5525 : : " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
5526 : : " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
5527 : : gettext_noop("Schema"),
5528 : : gettext_noop("Name"),
5529 : : gettext_noop("Init"),
5530 : : gettext_noop("Lexize"),
5531 : : gettext_noop("Description"));
5532 : : else
6080 tgl@sss.pgh.pa.us 5533 :CBC 21 : printfPQExpBuffer(&buf,
5534 : : "SELECT\n"
5535 : : " n.nspname AS \"%s\",\n"
5536 : : " t.tmplname AS \"%s\",\n"
5537 : : " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
5538 : : gettext_noop("Schema"),
5539 : : gettext_noop("Name"),
5540 : : gettext_noop("Description"));
5541 : :
3800 heikki.linnakangas@i 5542 : 21 : appendPQExpBufferStr(&buf, "FROM pg_catalog.pg_ts_template t\n"
5543 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
5544 : :
725 rhaas@postgresql.org 5545 [ + + ]: 21 : if (!validateSQLNamePattern(&buf, pattern, false, false,
5546 : : "n.nspname", "t.tmplname", NULL,
5547 : : "pg_catalog.pg_ts_template_is_visible(t.oid)",
5548 : : NULL, 3))
5549 : : {
633 michael@paquier.xyz 5550 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5551 : 12 : return false;
5552 : : }
5553 : :
3800 heikki.linnakangas@i 5554 : 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5555 : :
3461 fujii@postgresql.org 5556 : 9 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5557 : 9 : termPQExpBuffer(&buf);
5558 [ - + ]: 9 : if (!res)
6081 tgl@sss.pgh.pa.us 5559 :UBC 0 : return false;
5560 : :
6081 tgl@sss.pgh.pa.us 5561 :CBC 9 : myopt.title = _("List of text search templates");
5753 bruce@momjian.us 5562 : 9 : myopt.translate_header = true;
5563 : :
3056 tgl@sss.pgh.pa.us 5564 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5565 : :
6081 5566 : 9 : PQclear(res);
5567 : 9 : return true;
5568 : : }
5569 : :
5570 : :
5571 : : /*
5572 : : * \dF
5573 : : * list text search configurations
5574 : : */
5575 : : bool
5576 : 21 : listTSConfigs(const char *pattern, bool verbose)
5577 : : {
5578 : : PQExpBufferData buf;
5579 : : PGresult *res;
5580 : 21 : printQueryOpt myopt = pset.popt;
5581 : :
5582 [ - + ]: 21 : if (verbose)
6081 tgl@sss.pgh.pa.us 5583 :UBC 0 : return listTSConfigsVerbose(pattern);
5584 : :
6081 tgl@sss.pgh.pa.us 5585 :CBC 21 : initPQExpBuffer(&buf);
5586 : :
5587 : 21 : printfPQExpBuffer(&buf,
5588 : : "SELECT\n"
5589 : : " n.nspname as \"%s\",\n"
5590 : : " c.cfgname as \"%s\",\n"
5591 : : " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
5592 : : "FROM pg_catalog.pg_ts_config c\n"
5593 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace\n",
5594 : : gettext_noop("Schema"),
5595 : : gettext_noop("Name"),
5596 : : gettext_noop("Description")
5597 : : );
5598 : :
725 rhaas@postgresql.org 5599 [ + + ]: 21 : if (!validateSQLNamePattern(&buf, pattern, false, false,
5600 : : "n.nspname", "c.cfgname", NULL,
5601 : : "pg_catalog.pg_ts_config_is_visible(c.oid)",
5602 : : NULL, 3))
5603 : : {
633 michael@paquier.xyz 5604 : 12 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5605 : 12 : return false;
5606 : : }
5607 : :
3800 heikki.linnakangas@i 5608 : 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5609 : :
3461 fujii@postgresql.org 5610 : 9 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5611 : 9 : termPQExpBuffer(&buf);
5612 [ - + ]: 9 : if (!res)
6081 tgl@sss.pgh.pa.us 5613 :UBC 0 : return false;
5614 : :
6081 tgl@sss.pgh.pa.us 5615 :CBC 9 : myopt.title = _("List of text search configurations");
5753 bruce@momjian.us 5616 : 9 : myopt.translate_header = true;
5617 : :
3056 tgl@sss.pgh.pa.us 5618 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5619 : :
6081 5620 : 9 : PQclear(res);
5621 : 9 : return true;
5622 : : }
5623 : :
5624 : : static bool
6081 tgl@sss.pgh.pa.us 5625 :UBC 0 : listTSConfigsVerbose(const char *pattern)
5626 : : {
5627 : : PQExpBufferData buf;
5628 : : PGresult *res;
5629 : : int i;
5630 : :
5631 : 0 : initPQExpBuffer(&buf);
5632 : :
5633 : 0 : printfPQExpBuffer(&buf,
5634 : : "SELECT c.oid, c.cfgname,\n"
5635 : : " n.nspname,\n"
5636 : : " p.prsname,\n"
5637 : : " np.nspname as pnspname\n"
5638 : : "FROM pg_catalog.pg_ts_config c\n"
5639 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace,\n"
5640 : : " pg_catalog.pg_ts_parser p\n"
5641 : : " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace\n"
5642 : : "WHERE p.oid = c.cfgparser\n"
5643 : : );
5644 : :
725 rhaas@postgresql.org 5645 [ # # ]: 0 : if (!validateSQLNamePattern(&buf, pattern, true, false,
5646 : : "n.nspname", "c.cfgname", NULL,
5647 : : "pg_catalog.pg_ts_config_is_visible(c.oid)",
5648 : : NULL, 3))
5649 : : {
633 michael@paquier.xyz 5650 : 0 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5651 : 0 : return false;
5652 : : }
5653 : :
3800 heikki.linnakangas@i 5654 : 0 : appendPQExpBufferStr(&buf, "ORDER BY 3, 2;");
5655 : :
3461 fujii@postgresql.org 5656 : 0 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5657 : 0 : termPQExpBuffer(&buf);
5658 [ # # ]: 0 : if (!res)
5659 : 0 : return false;
5660 : :
5661 [ # # ]: 0 : if (PQntuples(res) == 0)
5662 : : {
5663 [ # # ]: 0 : if (!pset.quiet)
5664 : : {
2453 5665 [ # # ]: 0 : if (pattern)
1840 peter@eisentraut.org 5666 : 0 : pg_log_error("Did not find any text search configuration named \"%s\".",
5667 : : pattern);
5668 : : else
5669 : 0 : pg_log_error("Did not find any text search configurations.");
5670 : : }
6081 tgl@sss.pgh.pa.us 5671 : 0 : PQclear(res);
5672 : 0 : return false;
5673 : : }
5674 : :
5675 [ # # ]: 0 : for (i = 0; i < PQntuples(res); i++)
5676 : : {
5677 : : const char *oid;
5678 : : const char *cfgname;
5679 : 0 : const char *nspname = NULL;
5680 : : const char *prsname;
5681 : 0 : const char *pnspname = NULL;
5682 : :
5683 : 0 : oid = PQgetvalue(res, i, 0);
5684 : 0 : cfgname = PQgetvalue(res, i, 1);
5685 [ # # ]: 0 : if (!PQgetisnull(res, i, 2))
5686 : 0 : nspname = PQgetvalue(res, i, 2);
5687 : 0 : prsname = PQgetvalue(res, i, 3);
5688 [ # # ]: 0 : if (!PQgetisnull(res, i, 4))
5689 : 0 : pnspname = PQgetvalue(res, i, 4);
5690 : :
5691 [ # # ]: 0 : if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname))
5692 : : {
5693 : 0 : PQclear(res);
5694 : 0 : return false;
5695 : : }
5696 : :
5697 [ # # ]: 0 : if (cancel_pressed)
5698 : : {
5699 : 0 : PQclear(res);
5700 : 0 : return false;
5701 : : }
5702 : : }
5703 : :
5704 : 0 : PQclear(res);
5705 : 0 : return true;
5706 : : }
5707 : :
5708 : : static bool
5709 : 0 : describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
5710 : : const char *pnspname, const char *prsname)
5711 : : {
5712 : : PQExpBufferData buf,
5713 : : title;
5714 : : PGresult *res;
5715 : 0 : printQueryOpt myopt = pset.popt;
5716 : :
5717 : 0 : initPQExpBuffer(&buf);
5718 : :
5719 : 0 : printfPQExpBuffer(&buf,
5720 : : "SELECT\n"
5721 : : " ( SELECT t.alias FROM\n"
5722 : : " pg_catalog.ts_token_type(c.cfgparser) AS t\n"
5723 : : " WHERE t.tokid = m.maptokentype ) AS \"%s\",\n"
5724 : : " pg_catalog.btrim(\n"
5725 : : " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary\n"
5726 : : " FROM pg_catalog.pg_ts_config_map AS mm\n"
5727 : : " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype\n"
5728 : : " ORDER BY mapcfg, maptokentype, mapseqno\n"
5729 : : " ) :: pg_catalog.text,\n"
5730 : : " '{}') AS \"%s\"\n"
5731 : : "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m\n"
5732 : : "WHERE c.oid = '%s' AND m.mapcfg = c.oid\n"
5733 : : "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser\n"
5734 : : "ORDER BY 1;",
5735 : : gettext_noop("Token"),
5736 : : gettext_noop("Dictionaries"),
5737 : : oid);
5738 : :
3461 fujii@postgresql.org 5739 : 0 : res = PSQLexec(buf.data);
6081 tgl@sss.pgh.pa.us 5740 : 0 : termPQExpBuffer(&buf);
5741 [ # # ]: 0 : if (!res)
5742 : 0 : return false;
5743 : :
5744 : 0 : initPQExpBuffer(&title);
5745 : :
5746 [ # # ]: 0 : if (nspname)
5968 5747 : 0 : appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
5748 : : nspname, cfgname);
5749 : : else
5750 : 0 : appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
5751 : : cfgname);
5752 : :
6081 5753 [ # # ]: 0 : if (pnspname)
5968 5754 : 0 : appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
5755 : : pnspname, prsname);
5756 : : else
5757 : 0 : appendPQExpBuffer(&title, _("\nParser: \"%s\""),
5758 : : prsname);
5759 : :
6081 5760 : 0 : myopt.title = title.data;
5761 : 0 : myopt.footers = NULL;
4366 rhaas@postgresql.org 5762 : 0 : myopt.topt.default_footer = false;
5753 bruce@momjian.us 5763 : 0 : myopt.translate_header = true;
5764 : :
3056 tgl@sss.pgh.pa.us 5765 : 0 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5766 : :
6081 5767 : 0 : termPQExpBuffer(&title);
5768 : :
5769 : 0 : PQclear(res);
5770 : 0 : return true;
5771 : : }
5772 : :
5773 : :
5774 : : /*
5775 : : * \dew
5776 : : *
5777 : : * Describes foreign-data wrappers
5778 : : */
5779 : : bool
5595 peter_e@gmx.net 5780 :CBC 57 : listForeignDataWrappers(const char *pattern, bool verbose)
5781 : : {
5782 : : PQExpBufferData buf;
5783 : : PGresult *res;
5784 : 57 : printQueryOpt myopt = pset.popt;
5785 : :
5786 : 57 : initPQExpBuffer(&buf);
5787 : 57 : printfPQExpBuffer(&buf,
5788 : : "SELECT fdw.fdwname AS \"%s\",\n"
5789 : : " pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n"
5790 : : " fdw.fdwhandler::pg_catalog.regproc AS \"%s\",\n"
5791 : : " fdw.fdwvalidator::pg_catalog.regproc AS \"%s\"",
5792 : : gettext_noop("Name"),
5793 : : gettext_noop("Owner"),
5794 : : gettext_noop("Handler"),
5795 : : gettext_noop("Validator"));
5796 : :
5797 [ + + ]: 57 : if (verbose)
5798 : : {
3800 heikki.linnakangas@i 5799 : 42 : appendPQExpBufferStr(&buf, ",\n ");
5583 tgl@sss.pgh.pa.us 5800 : 42 : printACLColumn(&buf, "fdwacl");
5595 peter_e@gmx.net 5801 : 42 : appendPQExpBuffer(&buf,
5802 : : ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
5803 : : " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5804 : : " pg_catalog.quote_ident(option_name) || ' ' || "
5805 : : " pg_catalog.quote_literal(option_value) FROM "
5806 : : " pg_catalog.pg_options_to_table(fdwoptions)), ', ') || ')' "
5807 : : " END AS \"%s\""
5808 : : ",\n d.description AS \"%s\" ",
5809 : : gettext_noop("FDW options"),
5810 : : gettext_noop("Description"));
5811 : : }
5812 : :
3800 heikki.linnakangas@i 5813 : 57 : appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
5814 : :
850 tgl@sss.pgh.pa.us 5815 [ + + ]: 57 : if (verbose)
3800 heikki.linnakangas@i 5816 : 42 : appendPQExpBufferStr(&buf,
5817 : : "LEFT JOIN pg_catalog.pg_description d\n"
5818 : : " ON d.classoid = fdw.tableoid "
5819 : : "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
5820 : :
725 rhaas@postgresql.org 5821 [ + + ]: 57 : if (!validateSQLNamePattern(&buf, pattern, false, false,
5822 : : NULL, "fdwname", NULL, NULL,
5823 : : NULL, 1))
5824 : : {
633 michael@paquier.xyz 5825 : 9 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5826 : 9 : return false;
5827 : : }
5828 : :
3800 heikki.linnakangas@i 5829 : 48 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
5830 : :
3461 fujii@postgresql.org 5831 : 48 : res = PSQLexec(buf.data);
5595 peter_e@gmx.net 5832 : 48 : termPQExpBuffer(&buf);
5833 [ - + ]: 48 : if (!res)
5595 peter_e@gmx.net 5834 :UBC 0 : return false;
5835 : :
5595 peter_e@gmx.net 5836 :CBC 48 : myopt.title = _("List of foreign-data wrappers");
5837 : 48 : myopt.translate_header = true;
5838 : :
3056 tgl@sss.pgh.pa.us 5839 : 48 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5840 : :
5595 peter_e@gmx.net 5841 : 48 : PQclear(res);
5842 : 48 : return true;
5843 : : }
5844 : :
5845 : : /*
5846 : : * \des
5847 : : *
5848 : : * Describes foreign servers.
5849 : : */
5850 : : bool
5851 : 60 : listForeignServers(const char *pattern, bool verbose)
5852 : : {
5853 : : PQExpBufferData buf;
5854 : : PGresult *res;
5855 : 60 : printQueryOpt myopt = pset.popt;
5856 : :
5857 : 60 : initPQExpBuffer(&buf);
5858 : 60 : printfPQExpBuffer(&buf,
5859 : : "SELECT s.srvname AS \"%s\",\n"
5860 : : " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
5861 : : " f.fdwname AS \"%s\"",
5862 : : gettext_noop("Name"),
5863 : : gettext_noop("Owner"),
5864 : : gettext_noop("Foreign-data wrapper"));
5865 : :
5866 [ + + ]: 60 : if (verbose)
5867 : : {
3800 heikki.linnakangas@i 5868 : 24 : appendPQExpBufferStr(&buf, ",\n ");
5583 tgl@sss.pgh.pa.us 5869 : 24 : printACLColumn(&buf, "s.srvacl");
5595 peter_e@gmx.net 5870 : 24 : appendPQExpBuffer(&buf,
5871 : : ",\n"
5872 : : " s.srvtype AS \"%s\",\n"
5873 : : " s.srvversion AS \"%s\",\n"
5874 : : " CASE WHEN srvoptions IS NULL THEN '' ELSE "
5875 : : " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5876 : : " pg_catalog.quote_ident(option_name) || ' ' || "
5877 : : " pg_catalog.quote_literal(option_value) FROM "
5878 : : " pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')' "
5879 : : " END AS \"%s\",\n"
5880 : : " d.description AS \"%s\"",
5881 : : gettext_noop("Type"),
5882 : : gettext_noop("Version"),
5883 : : gettext_noop("FDW options"),
5884 : : gettext_noop("Description"));
5885 : : }
5886 : :
3800 heikki.linnakangas@i 5887 : 60 : appendPQExpBufferStr(&buf,
5888 : : "\nFROM pg_catalog.pg_foreign_server s\n"
5889 : : " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
5890 : :
4633 rhaas@postgresql.org 5891 [ + + ]: 60 : if (verbose)
3800 heikki.linnakangas@i 5892 : 24 : appendPQExpBufferStr(&buf,
5893 : : "LEFT JOIN pg_catalog.pg_description d\n "
5894 : : "ON d.classoid = s.tableoid AND d.objoid = s.oid "
5895 : : "AND d.objsubid = 0\n");
5896 : :
725 rhaas@postgresql.org 5897 [ + + ]: 60 : if (!validateSQLNamePattern(&buf, pattern, false, false,
5898 : : NULL, "s.srvname", NULL, NULL,
5899 : : NULL, 1))
5900 : : {
633 michael@paquier.xyz 5901 : 21 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5902 : 21 : return false;
5903 : : }
5904 : :
3800 heikki.linnakangas@i 5905 : 39 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
5906 : :
3461 fujii@postgresql.org 5907 : 39 : res = PSQLexec(buf.data);
5595 peter_e@gmx.net 5908 : 39 : termPQExpBuffer(&buf);
5909 [ - + ]: 39 : if (!res)
5595 peter_e@gmx.net 5910 :UBC 0 : return false;
5911 : :
5595 peter_e@gmx.net 5912 :CBC 39 : myopt.title = _("List of foreign servers");
5913 : 39 : myopt.translate_header = true;
5914 : :
3056 tgl@sss.pgh.pa.us 5915 : 39 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5916 : :
5595 peter_e@gmx.net 5917 : 39 : PQclear(res);
5918 : 39 : return true;
5919 : : }
5920 : :
5921 : : /*
5922 : : * \deu
5923 : : *
5924 : : * Describes user mappings.
5925 : : */
5926 : : bool
5927 : 30 : listUserMappings(const char *pattern, bool verbose)
5928 : : {
5929 : : PQExpBufferData buf;
5930 : : PGresult *res;
5931 : 30 : printQueryOpt myopt = pset.popt;
5932 : :
5933 : 30 : initPQExpBuffer(&buf);
5934 : 30 : printfPQExpBuffer(&buf,
5935 : : "SELECT um.srvname AS \"%s\",\n"
5936 : : " um.usename AS \"%s\"",
5937 : : gettext_noop("Server"),
5938 : : gettext_noop("User name"));
5939 : :
5940 [ + + ]: 30 : if (verbose)
5941 : 18 : appendPQExpBuffer(&buf,
5942 : : ",\n CASE WHEN umoptions IS NULL THEN '' ELSE "
5943 : : " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
5944 : : " pg_catalog.quote_ident(option_name) || ' ' || "
5945 : : " pg_catalog.quote_literal(option_value) FROM "
5946 : : " pg_catalog.pg_options_to_table(umoptions)), ', ') || ')' "
5947 : : " END AS \"%s\"",
5948 : : gettext_noop("FDW options"));
5949 : :
3800 heikki.linnakangas@i 5950 : 30 : appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
5951 : :
725 rhaas@postgresql.org 5952 [ - + ]: 30 : if (!validateSQLNamePattern(&buf, pattern, false, false,
5953 : : NULL, "um.srvname", "um.usename", NULL,
5954 : : NULL, 1))
5955 : : {
633 michael@paquier.xyz 5956 :UBC 0 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 5957 : 0 : return false;
5958 : : }
5959 : :
3800 heikki.linnakangas@i 5960 :CBC 30 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
5961 : :
3461 fujii@postgresql.org 5962 : 30 : res = PSQLexec(buf.data);
5595 peter_e@gmx.net 5963 : 30 : termPQExpBuffer(&buf);
5964 [ - + ]: 30 : if (!res)
5595 peter_e@gmx.net 5965 :UBC 0 : return false;
5966 : :
5595 peter_e@gmx.net 5967 :CBC 30 : myopt.title = _("List of user mappings");
5968 : 30 : myopt.translate_header = true;
5969 : :
3056 tgl@sss.pgh.pa.us 5970 : 30 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
5971 : :
5595 peter_e@gmx.net 5972 : 30 : PQclear(res);
5973 : 30 : return true;
5974 : : }
5975 : :
5976 : : /*
5977 : : * \det
5978 : : *
5979 : : * Describes foreign tables.
5980 : : */
5981 : : bool
4852 rhaas@postgresql.org 5982 : 9 : listForeignTables(const char *pattern, bool verbose)
5983 : : {
5984 : : PQExpBufferData buf;
5985 : : PGresult *res;
5986 : 9 : printQueryOpt myopt = pset.popt;
5987 : :
5988 : 9 : initPQExpBuffer(&buf);
5989 : 9 : printfPQExpBuffer(&buf,
5990 : : "SELECT n.nspname AS \"%s\",\n"
5991 : : " c.relname AS \"%s\",\n"
5992 : : " s.srvname AS \"%s\"",
5993 : : gettext_noop("Schema"),
5994 : : gettext_noop("Table"),
5995 : : gettext_noop("Server"));
5996 : :
5997 [ + - ]: 9 : if (verbose)
5998 : 9 : appendPQExpBuffer(&buf,
5999 : : ",\n CASE WHEN ftoptions IS NULL THEN '' ELSE "
6000 : : " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
6001 : : " pg_catalog.quote_ident(option_name) || ' ' || "
6002 : : " pg_catalog.quote_literal(option_value) FROM "
6003 : : " pg_catalog.pg_options_to_table(ftoptions)), ', ') || ')' "
6004 : : " END AS \"%s\",\n"
6005 : : " d.description AS \"%s\"",
6006 : : gettext_noop("FDW options"),
6007 : : gettext_noop("Description"));
6008 : :
3800 heikki.linnakangas@i 6009 : 9 : appendPQExpBufferStr(&buf,
6010 : : "\nFROM pg_catalog.pg_foreign_table ft\n"
6011 : : " INNER JOIN pg_catalog.pg_class c"
6012 : : " ON c.oid = ft.ftrelid\n"
6013 : : " INNER JOIN pg_catalog.pg_namespace n"
6014 : : " ON n.oid = c.relnamespace\n"
6015 : : " INNER JOIN pg_catalog.pg_foreign_server s"
6016 : : " ON s.oid = ft.ftserver\n");
4633 rhaas@postgresql.org 6017 [ + - ]: 9 : if (verbose)
3800 heikki.linnakangas@i 6018 : 9 : appendPQExpBufferStr(&buf,
6019 : : " LEFT JOIN pg_catalog.pg_description d\n"
6020 : : " ON d.classoid = c.tableoid AND "
6021 : : "d.objoid = c.oid AND d.objsubid = 0\n");
6022 : :
725 rhaas@postgresql.org 6023 [ - + ]: 9 : if (!validateSQLNamePattern(&buf, pattern, false, false,
6024 : : "n.nspname", "c.relname", NULL,
6025 : : "pg_catalog.pg_table_is_visible(c.oid)",
6026 : : NULL, 3))
6027 : : {
633 michael@paquier.xyz 6028 :UBC 0 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 6029 : 0 : return false;
6030 : : }
6031 : :
3800 heikki.linnakangas@i 6032 :CBC 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
6033 : :
3461 fujii@postgresql.org 6034 : 9 : res = PSQLexec(buf.data);
4852 rhaas@postgresql.org 6035 : 9 : termPQExpBuffer(&buf);
6036 [ - + ]: 9 : if (!res)
4852 rhaas@postgresql.org 6037 :UBC 0 : return false;
6038 : :
4852 rhaas@postgresql.org 6039 :CBC 9 : myopt.title = _("List of foreign tables");
6040 : 9 : myopt.translate_header = true;
6041 : :
3056 tgl@sss.pgh.pa.us 6042 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6043 : :
4852 rhaas@postgresql.org 6044 : 9 : PQclear(res);
6045 : 9 : return true;
6046 : : }
6047 : :
6048 : : /*
6049 : : * \dx
6050 : : *
6051 : : * Briefly describes installed extensions.
6052 : : */
6053 : : bool
4814 tgl@sss.pgh.pa.us 6054 : 12 : listExtensions(const char *pattern)
6055 : : {
6056 : : PQExpBufferData buf;
6057 : : PGresult *res;
6058 : 12 : printQueryOpt myopt = pset.popt;
6059 : :
6060 : 12 : initPQExpBuffer(&buf);
6061 : 12 : printfPQExpBuffer(&buf,
6062 : : "SELECT e.extname AS \"%s\", "
6063 : : "e.extversion AS \"%s\", n.nspname AS \"%s\", c.description AS \"%s\"\n"
6064 : : "FROM pg_catalog.pg_extension e "
6065 : : "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
6066 : : "LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
6067 : : "AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass\n",
6068 : : gettext_noop("Name"),
6069 : : gettext_noop("Version"),
6070 : : gettext_noop("Schema"),
6071 : : gettext_noop("Description"));
6072 : :
725 rhaas@postgresql.org 6073 [ + + ]: 12 : if (!validateSQLNamePattern(&buf, pattern,
6074 : : false, false,
6075 : : NULL, "e.extname", NULL,
6076 : : NULL,
6077 : : NULL, 1))
6078 : : {
633 michael@paquier.xyz 6079 : 9 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 6080 : 9 : return false;
6081 : : }
6082 : :
3800 heikki.linnakangas@i 6083 : 3 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
6084 : :
3461 fujii@postgresql.org 6085 : 3 : res = PSQLexec(buf.data);
4814 tgl@sss.pgh.pa.us 6086 : 3 : termPQExpBuffer(&buf);
6087 [ - + ]: 3 : if (!res)
4814 tgl@sss.pgh.pa.us 6088 :UBC 0 : return false;
6089 : :
4814 tgl@sss.pgh.pa.us 6090 :CBC 3 : myopt.title = _("List of installed extensions");
6091 : 3 : myopt.translate_header = true;
6092 : :
3056 6093 : 3 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6094 : :
4814 6095 : 3 : PQclear(res);
6096 : 3 : return true;
6097 : : }
6098 : :
6099 : : /*
6100 : : * \dx+
6101 : : *
6102 : : * List contents of installed extensions.
6103 : : */
6104 : : bool
6105 : 15 : listExtensionContents(const char *pattern)
6106 : : {
6107 : : PQExpBufferData buf;
6108 : : PGresult *res;
6109 : : int i;
6110 : :
6111 : 15 : initPQExpBuffer(&buf);
6112 : 15 : printfPQExpBuffer(&buf,
6113 : : "SELECT e.extname, e.oid\n"
6114 : : "FROM pg_catalog.pg_extension e\n");
6115 : :
725 rhaas@postgresql.org 6116 [ - + ]: 15 : if (!validateSQLNamePattern(&buf, pattern,
6117 : : false, false,
6118 : : NULL, "e.extname", NULL,
6119 : : NULL,
6120 : : NULL, 1))
6121 : : {
633 michael@paquier.xyz 6122 :UBC 0 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 6123 : 0 : return false;
6124 : : }
6125 : :
3800 heikki.linnakangas@i 6126 :CBC 15 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
6127 : :
3461 fujii@postgresql.org 6128 : 15 : res = PSQLexec(buf.data);
4814 tgl@sss.pgh.pa.us 6129 : 15 : termPQExpBuffer(&buf);
6130 [ - + ]: 15 : if (!res)
4814 tgl@sss.pgh.pa.us 6131 :UBC 0 : return false;
6132 : :
4814 tgl@sss.pgh.pa.us 6133 [ - + ]:CBC 15 : if (PQntuples(res) == 0)
6134 : : {
4814 tgl@sss.pgh.pa.us 6135 [ # # ]:UBC 0 : if (!pset.quiet)
6136 : : {
6137 [ # # ]: 0 : if (pattern)
1840 peter@eisentraut.org 6138 : 0 : pg_log_error("Did not find any extension named \"%s\".",
6139 : : pattern);
6140 : : else
6141 : 0 : pg_log_error("Did not find any extensions.");
6142 : : }
4814 tgl@sss.pgh.pa.us 6143 : 0 : PQclear(res);
6144 : 0 : return false;
6145 : : }
6146 : :
4814 tgl@sss.pgh.pa.us 6147 [ + + ]:CBC 30 : for (i = 0; i < PQntuples(res); i++)
6148 : : {
6149 : : const char *extname;
6150 : : const char *oid;
6151 : :
6152 : 15 : extname = PQgetvalue(res, i, 0);
6153 : 15 : oid = PQgetvalue(res, i, 1);
6154 : :
6155 [ - + ]: 15 : if (!listOneExtensionContents(extname, oid))
6156 : : {
4814 tgl@sss.pgh.pa.us 6157 :UBC 0 : PQclear(res);
6158 : 0 : return false;
6159 : : }
4814 tgl@sss.pgh.pa.us 6160 [ - + ]:CBC 15 : if (cancel_pressed)
6161 : : {
4814 tgl@sss.pgh.pa.us 6162 :UBC 0 : PQclear(res);
6163 : 0 : return false;
6164 : : }
6165 : : }
6166 : :
4814 tgl@sss.pgh.pa.us 6167 :CBC 15 : PQclear(res);
6168 : 15 : return true;
6169 : : }
6170 : :
6171 : : static bool
6172 : 15 : listOneExtensionContents(const char *extname, const char *oid)
6173 : : {
6174 : : PQExpBufferData buf;
6175 : : PGresult *res;
6176 : : PQExpBufferData title;
6177 : 15 : printQueryOpt myopt = pset.popt;
6178 : :
6179 : 15 : initPQExpBuffer(&buf);
6180 : 15 : printfPQExpBuffer(&buf,
6181 : : "SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS \"%s\"\n"
6182 : : "FROM pg_catalog.pg_depend\n"
6183 : : "WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '%s' AND deptype = 'e'\n"
6184 : : "ORDER BY 1;",
6185 : : gettext_noop("Object description"),
6186 : : oid);
6187 : :
3461 fujii@postgresql.org 6188 : 15 : res = PSQLexec(buf.data);
4814 tgl@sss.pgh.pa.us 6189 : 15 : termPQExpBuffer(&buf);
6190 [ - + ]: 15 : if (!res)
4814 tgl@sss.pgh.pa.us 6191 :UBC 0 : return false;
6192 : :
2453 tgl@sss.pgh.pa.us 6193 :CBC 15 : initPQExpBuffer(&title);
6194 : 15 : printfPQExpBuffer(&title, _("Objects in extension \"%s\""), extname);
6195 : 15 : myopt.title = title.data;
4814 6196 : 15 : myopt.translate_header = true;
6197 : :
3056 6198 : 15 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6199 : :
2453 6200 : 15 : termPQExpBuffer(&title);
4814 6201 : 15 : PQclear(res);
6202 : 15 : return true;
6203 : : }
6204 : :
6205 : : /*
6206 : : * validateSQLNamePattern
6207 : : *
6208 : : * Wrapper around string_utils's processSQLNamePattern which also checks the
6209 : : * pattern's validity. In addition to that function's parameters, takes a
6210 : : * 'maxparts' parameter specifying the maximum number of dotted names the
6211 : : * pattern is allowed to have, and a 'added_clause' parameter that returns by
6212 : : * reference whether a clause was added to 'buf'. Returns whether the pattern
6213 : : * passed validation, after logging any errors.
6214 : : */
6215 : : static bool
725 rhaas@postgresql.org 6216 : 3263 : validateSQLNamePattern(PQExpBuffer buf, const char *pattern, bool have_where,
6217 : : bool force_escape, const char *schemavar,
6218 : : const char *namevar, const char *altnamevar,
6219 : : const char *visibilityrule, bool *added_clause,
6220 : : int maxparts)
6221 : : {
6222 : : PQExpBufferData dbbuf;
6223 : : int dotcnt;
6224 : : bool added;
6225 : :
6226 : 3263 : initPQExpBuffer(&dbbuf);
6227 : 3263 : added = processSQLNamePattern(pset.db, buf, pattern, have_where, force_escape,
6228 : : schemavar, namevar, altnamevar,
6229 : : visibilityrule, &dbbuf, &dotcnt);
6230 [ + + ]: 3263 : if (added_clause != NULL)
6231 : 81 : *added_clause = added;
6232 : :
6233 [ + + ]: 3263 : if (dotcnt >= maxparts)
6234 : : {
6235 : 219 : pg_log_error("improper qualified name (too many dotted names): %s",
6236 : : pattern);
633 michael@paquier.xyz 6237 : 219 : goto error_return;
6238 : : }
6239 : :
703 tgl@sss.pgh.pa.us 6240 [ + + + + ]: 3044 : if (maxparts > 1 && dotcnt == maxparts - 1)
6241 : : {
725 rhaas@postgresql.org 6242 [ - + ]: 309 : if (PQdb(pset.db) == NULL)
6243 : : {
725 rhaas@postgresql.org 6244 :UBC 0 : pg_log_error("You are currently not connected to a database.");
633 michael@paquier.xyz 6245 : 0 : goto error_return;
6246 : : }
725 rhaas@postgresql.org 6247 [ + + ]:CBC 309 : if (strcmp(PQdb(pset.db), dbbuf.data) != 0)
6248 : : {
6249 : 225 : pg_log_error("cross-database references are not implemented: %s",
6250 : : pattern);
633 michael@paquier.xyz 6251 : 225 : goto error_return;
6252 : : }
6253 : : }
6254 : 2819 : termPQExpBuffer(&dbbuf);
725 rhaas@postgresql.org 6255 : 2819 : return true;
6256 : :
633 michael@paquier.xyz 6257 : 444 : error_return:
6258 : 444 : termPQExpBuffer(&dbbuf);
6259 : 444 : return false;
6260 : : }
6261 : :
6262 : : /*
6263 : : * \dRp
6264 : : * Lists publications.
6265 : : *
6266 : : * Takes an optional regexp to select particular publications
6267 : : */
6268 : : bool
2642 peter_e@gmx.net 6269 : 24 : listPublications(const char *pattern)
6270 : : {
6271 : : PQExpBufferData buf;
6272 : : PGresult *res;
6273 : 24 : printQueryOpt myopt = pset.popt;
6274 : : static const bool translate_columns[] = {false, false, false, false, false, false, false, false};
6275 : :
6276 [ - + ]: 24 : if (pset.sversion < 100000)
6277 : : {
6278 : : char sverbuf[32];
6279 : :
1840 peter@eisentraut.org 6280 :UBC 0 : pg_log_error("The server (version %s) does not support publications.",
6281 : : formatPGVersionNumber(pset.sversion, false,
6282 : : sverbuf, sizeof(sverbuf)));
2642 peter_e@gmx.net 6283 : 0 : return true;
6284 : : }
6285 : :
2642 peter_e@gmx.net 6286 :CBC 24 : initPQExpBuffer(&buf);
6287 : :
738 tomas.vondra@postgre 6288 : 24 : printfPQExpBuffer(&buf,
6289 : : "SELECT pubname AS \"%s\",\n"
6290 : : " pg_catalog.pg_get_userbyid(pubowner) AS \"%s\",\n"
6291 : : " puballtables AS \"%s\",\n"
6292 : : " pubinsert AS \"%s\",\n"
6293 : : " pubupdate AS \"%s\",\n"
6294 : : " pubdelete AS \"%s\"",
6295 : : gettext_noop("Name"),
6296 : : gettext_noop("Owner"),
6297 : : gettext_noop("All tables"),
6298 : : gettext_noop("Inserts"),
6299 : : gettext_noop("Updates"),
6300 : : gettext_noop("Deletes"));
2199 peter_e@gmx.net 6301 [ + - ]: 24 : if (pset.sversion >= 110000)
6302 : 24 : appendPQExpBuffer(&buf,
6303 : : ",\n pubtruncate AS \"%s\"",
6304 : : gettext_noop("Truncates"));
1467 peter@eisentraut.org 6305 [ + - ]: 24 : if (pset.sversion >= 130000)
6306 : 24 : appendPQExpBuffer(&buf,
6307 : : ",\n pubviaroot AS \"%s\"",
6308 : : gettext_noop("Via root"));
6309 : :
2642 peter_e@gmx.net 6310 : 24 : appendPQExpBufferStr(&buf,
6311 : : "\nFROM pg_catalog.pg_publication\n");
6312 : :
725 rhaas@postgresql.org 6313 [ + + ]: 24 : if (!validateSQLNamePattern(&buf, pattern, false, false,
6314 : : NULL, "pubname", NULL,
6315 : : NULL,
6316 : : NULL, 1))
6317 : : {
633 michael@paquier.xyz 6318 : 9 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 6319 : 9 : return false;
6320 : : }
6321 : :
2642 peter_e@gmx.net 6322 : 15 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
6323 : :
6324 : 15 : res = PSQLexec(buf.data);
6325 : 15 : termPQExpBuffer(&buf);
6326 [ - + ]: 15 : if (!res)
2642 peter_e@gmx.net 6327 :UBC 0 : return false;
6328 : :
2642 peter_e@gmx.net 6329 :CBC 15 : myopt.title = _("List of publications");
6330 : 15 : myopt.translate_header = true;
6331 : 15 : myopt.translate_columns = translate_columns;
6332 : 15 : myopt.n_translate_columns = lengthof(translate_columns);
6333 : :
6334 : 15 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6335 : :
6336 : 15 : PQclear(res);
6337 : :
6338 : 15 : return true;
6339 : : }
6340 : :
6341 : : /*
6342 : : * Add footer to publication description.
6343 : : */
6344 : : static bool
737 peter@eisentraut.org 6345 : 282 : addFooterToPublicationDesc(PQExpBuffer buf, const char *footermsg,
6346 : : bool as_schema, printTableContent *const cont)
6347 : : {
6348 : : PGresult *res;
900 akapila@postgresql.o 6349 : 282 : int count = 0;
6350 : 282 : int i = 0;
6351 : :
6352 : 282 : res = PSQLexec(buf->data);
6353 [ - + ]: 282 : if (!res)
900 akapila@postgresql.o 6354 :UBC 0 : return false;
6355 : : else
900 akapila@postgresql.o 6356 :CBC 282 : count = PQntuples(res);
6357 : :
6358 [ + + ]: 282 : if (count > 0)
737 peter@eisentraut.org 6359 : 150 : printTableAddFooter(cont, footermsg);
6360 : :
900 akapila@postgresql.o 6361 [ + + ]: 495 : for (i = 0; i < count; i++)
6362 : : {
750 tomas.vondra@postgre 6363 [ + + ]: 213 : if (as_schema)
6364 : 117 : printfPQExpBuffer(buf, " \"%s\"", PQgetvalue(res, i, 0));
6365 : : else
6366 : : {
900 akapila@postgresql.o 6367 : 96 : printfPQExpBuffer(buf, " \"%s.%s\"", PQgetvalue(res, i, 0),
6368 : : PQgetvalue(res, i, 1));
6369 : :
750 tomas.vondra@postgre 6370 [ + + ]: 96 : if (!PQgetisnull(res, i, 3))
6371 : 6 : appendPQExpBuffer(buf, " (%s)", PQgetvalue(res, i, 3));
6372 : :
782 akapila@postgresql.o 6373 [ + + ]: 96 : if (!PQgetisnull(res, i, 2))
6374 : 27 : appendPQExpBuffer(buf, " WHERE %s", PQgetvalue(res, i, 2));
6375 : : }
6376 : :
900 6377 : 213 : printTableAddFooter(cont, buf->data);
6378 : : }
6379 : :
6380 : 282 : PQclear(res);
6381 : 282 : return true;
6382 : : }
6383 : :
6384 : : /*
6385 : : * \dRp+
6386 : : * Describes publications including the contents.
6387 : : *
6388 : : * Takes an optional regexp to select particular publications
6389 : : */
6390 : : bool
2642 peter_e@gmx.net 6391 : 144 : describePublications(const char *pattern)
6392 : : {
6393 : : PQExpBufferData buf;
6394 : : int i;
6395 : : PGresult *res;
6396 : : bool has_pubtruncate;
6397 : : bool has_pubviaroot;
6398 : :
6399 : : PQExpBufferData title;
6400 : : printTableContent cont;
6401 : :
6402 [ - + ]: 144 : if (pset.sversion < 100000)
6403 : : {
6404 : : char sverbuf[32];
6405 : :
1840 peter@eisentraut.org 6406 :UBC 0 : pg_log_error("The server (version %s) does not support publications.",
6407 : : formatPGVersionNumber(pset.sversion, false,
6408 : : sverbuf, sizeof(sverbuf)));
2642 peter_e@gmx.net 6409 : 0 : return true;
6410 : : }
6411 : :
2199 peter_e@gmx.net 6412 :CBC 144 : has_pubtruncate = (pset.sversion >= 110000);
1467 peter@eisentraut.org 6413 : 144 : has_pubviaroot = (pset.sversion >= 130000);
6414 : :
2642 peter_e@gmx.net 6415 : 144 : initPQExpBuffer(&buf);
6416 : :
6417 : 144 : printfPQExpBuffer(&buf,
6418 : : "SELECT oid, pubname,\n"
6419 : : " pg_catalog.pg_get_userbyid(pubowner) AS owner,\n"
6420 : : " puballtables, pubinsert, pubupdate, pubdelete");
2199 6421 [ + - ]: 144 : if (has_pubtruncate)
1746 drowley@postgresql.o 6422 : 144 : appendPQExpBufferStr(&buf,
6423 : : ", pubtruncate");
1467 peter@eisentraut.org 6424 [ + - ]: 144 : if (has_pubviaroot)
6425 : 144 : appendPQExpBufferStr(&buf,
6426 : : ", pubviaroot");
1746 drowley@postgresql.o 6427 : 144 : appendPQExpBufferStr(&buf,
6428 : : "\nFROM pg_catalog.pg_publication\n");
6429 : :
725 rhaas@postgresql.org 6430 [ - + ]: 144 : if (!validateSQLNamePattern(&buf, pattern, false, false,
6431 : : NULL, "pubname", NULL,
6432 : : NULL,
6433 : : NULL, 1))
6434 : : {
633 michael@paquier.xyz 6435 :UBC 0 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 6436 : 0 : return false;
6437 : : }
6438 : :
2642 peter_e@gmx.net 6439 :CBC 144 : appendPQExpBufferStr(&buf, "ORDER BY 2;");
6440 : :
6441 : 144 : res = PSQLexec(buf.data);
6442 [ - + ]: 144 : if (!res)
6443 : : {
2642 peter_e@gmx.net 6444 :UBC 0 : termPQExpBuffer(&buf);
6445 : 0 : return false;
6446 : : }
6447 : :
2453 tgl@sss.pgh.pa.us 6448 [ - + ]:CBC 144 : if (PQntuples(res) == 0)
6449 : : {
2453 tgl@sss.pgh.pa.us 6450 [ # # ]:UBC 0 : if (!pset.quiet)
6451 : : {
6452 [ # # ]: 0 : if (pattern)
1840 peter@eisentraut.org 6453 : 0 : pg_log_error("Did not find any publication named \"%s\".",
6454 : : pattern);
6455 : : else
6456 : 0 : pg_log_error("Did not find any publications.");
6457 : : }
6458 : :
2453 tgl@sss.pgh.pa.us 6459 : 0 : termPQExpBuffer(&buf);
6460 : 0 : PQclear(res);
6461 : 0 : return false;
6462 : : }
6463 : :
2642 peter_e@gmx.net 6464 [ + + ]:CBC 288 : for (i = 0; i < PQntuples(res); i++)
6465 : : {
6466 : 144 : const char align = 'l';
2452 tgl@sss.pgh.pa.us 6467 : 144 : int ncols = 5;
2642 peter_e@gmx.net 6468 : 144 : int nrows = 1;
6469 : 144 : char *pubid = PQgetvalue(res, i, 0);
6470 : 144 : char *pubname = PQgetvalue(res, i, 1);
2452 tgl@sss.pgh.pa.us 6471 : 144 : bool puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
2642 peter_e@gmx.net 6472 : 144 : printTableOpt myopt = pset.popt.topt;
6473 : :
2199 6474 [ + - ]: 144 : if (has_pubtruncate)
6475 : 144 : ncols++;
1467 peter@eisentraut.org 6476 [ + - ]: 144 : if (has_pubviaroot)
6477 : 144 : ncols++;
6478 : :
2642 peter_e@gmx.net 6479 : 144 : initPQExpBuffer(&title);
6480 : 144 : printfPQExpBuffer(&title, _("Publication %s"), pubname);
6481 : 144 : printTableInit(&cont, &myopt, title.data, ncols, nrows);
6482 : :
2452 tgl@sss.pgh.pa.us 6483 : 144 : printTableAddHeader(&cont, gettext_noop("Owner"), true, align);
2495 peter_e@gmx.net 6484 : 144 : printTableAddHeader(&cont, gettext_noop("All tables"), true, align);
2642 6485 : 144 : printTableAddHeader(&cont, gettext_noop("Inserts"), true, align);
6486 : 144 : printTableAddHeader(&cont, gettext_noop("Updates"), true, align);
6487 : 144 : printTableAddHeader(&cont, gettext_noop("Deletes"), true, align);
2199 6488 [ + - ]: 144 : if (has_pubtruncate)
6489 : 144 : printTableAddHeader(&cont, gettext_noop("Truncates"), true, align);
1467 peter@eisentraut.org 6490 [ + - ]: 144 : if (has_pubviaroot)
6491 : 144 : printTableAddHeader(&cont, gettext_noop("Via root"), true, align);
6492 : :
738 tomas.vondra@postgre 6493 : 144 : printTableAddCell(&cont, PQgetvalue(res, i, 2), false, false);
6494 : 144 : printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false);
6495 : 144 : printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false);
6496 : 144 : printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
6497 : 144 : printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
2199 peter_e@gmx.net 6498 [ + - ]: 144 : if (has_pubtruncate)
738 tomas.vondra@postgre 6499 : 144 : printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
1467 peter@eisentraut.org 6500 [ + - ]: 144 : if (has_pubviaroot)
738 tomas.vondra@postgre 6501 : 144 : printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
6502 : :
2495 peter_e@gmx.net 6503 [ + + ]: 144 : if (!puballtables)
6504 : : {
6505 : : /* Get the tables for the specified publication */
2642 6506 : 141 : printfPQExpBuffer(&buf,
6507 : : "SELECT n.nspname, c.relname");
782 akapila@postgresql.o 6508 [ + - ]: 141 : if (pset.sversion >= 150000)
6509 : : {
6510 : 141 : appendPQExpBufferStr(&buf,
6511 : : ", pg_get_expr(pr.prqual, c.oid)");
750 tomas.vondra@postgre 6512 : 141 : appendPQExpBufferStr(&buf,
6513 : : ", (CASE WHEN pr.prattrs IS NOT NULL THEN\n"
6514 : : " pg_catalog.array_to_string("
6515 : : " ARRAY(SELECT attname\n"
6516 : : " FROM\n"
6517 : : " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
6518 : : " pg_catalog.pg_attribute\n"
6519 : : " WHERE attrelid = c.oid AND attnum = prattrs[s]), ', ')\n"
6520 : : " ELSE NULL END)");
6521 : : }
6522 : : else
782 akapila@postgresql.o 6523 :UBC 0 : appendPQExpBufferStr(&buf,
6524 : : ", NULL, NULL");
782 akapila@postgresql.o 6525 :CBC 141 : appendPQExpBuffer(&buf,
6526 : : "\nFROM pg_catalog.pg_class c,\n"
6527 : : " pg_catalog.pg_namespace n,\n"
6528 : : " pg_catalog.pg_publication_rel pr\n"
6529 : : "WHERE c.relnamespace = n.oid\n"
6530 : : " AND c.oid = pr.prrelid\n"
6531 : : " AND pr.prpubid = '%s'\n"
6532 : : "ORDER BY 1,2", pubid);
737 peter@eisentraut.org 6533 [ - + ]: 141 : if (!addFooterToPublicationDesc(&buf, _("Tables:"), false, &cont))
900 akapila@postgresql.o 6534 :UBC 0 : goto error_return;
6535 : :
900 akapila@postgresql.o 6536 [ + - ]:CBC 141 : if (pset.sversion >= 150000)
6537 : : {
6538 : : /* Get the schemas for the specified publication */
6539 : 141 : printfPQExpBuffer(&buf,
6540 : : "SELECT n.nspname\n"
6541 : : "FROM pg_catalog.pg_namespace n\n"
6542 : : " JOIN pg_catalog.pg_publication_namespace pn ON n.oid = pn.pnnspid\n"
6543 : : "WHERE pn.pnpubid = '%s'\n"
6544 : : "ORDER BY 1", pubid);
737 peter@eisentraut.org 6545 [ - + ]: 141 : if (!addFooterToPublicationDesc(&buf, _("Tables from schemas:"),
6546 : : true, &cont))
900 akapila@postgresql.o 6547 :UBC 0 : goto error_return;
6548 : : }
6549 : : }
6550 : :
2642 peter_e@gmx.net 6551 :CBC 144 : printTable(&cont, pset.queryFout, false, pset.logfile);
6552 : 144 : printTableCleanup(&cont);
6553 : :
6554 : 144 : termPQExpBuffer(&title);
6555 : : }
6556 : :
6557 : 144 : termPQExpBuffer(&buf);
6558 : 144 : PQclear(res);
6559 : :
6560 : 144 : return true;
6561 : :
900 akapila@postgresql.o 6562 :UBC 0 : error_return:
6563 : 0 : printTableCleanup(&cont);
6564 : 0 : PQclear(res);
6565 : 0 : termPQExpBuffer(&buf);
6566 : 0 : termPQExpBuffer(&title);
6567 : 0 : return false;
6568 : : }
6569 : :
6570 : : /*
6571 : : * \dRs
6572 : : * Describes subscriptions.
6573 : : *
6574 : : * Takes an optional regexp to select particular subscriptions
6575 : : */
6576 : : bool
2642 peter_e@gmx.net 6577 :CBC 75 : describeSubscriptions(const char *pattern, bool verbose)
6578 : : {
6579 : : PQExpBufferData buf;
6580 : : PGresult *res;
6581 : 75 : printQueryOpt myopt = pset.popt;
6582 : : static const bool translate_columns[] = {false, false, false, false,
6583 : : false, false, false, false, false, false, false, false, false, false,
6584 : : false};
6585 : :
6586 [ - + ]: 75 : if (pset.sversion < 100000)
6587 : : {
6588 : : char sverbuf[32];
6589 : :
1840 peter@eisentraut.org 6590 :UBC 0 : pg_log_error("The server (version %s) does not support subscriptions.",
6591 : : formatPGVersionNumber(pset.sversion, false,
6592 : : sverbuf, sizeof(sverbuf)));
2642 peter_e@gmx.net 6593 : 0 : return true;
6594 : : }
6595 : :
2642 peter_e@gmx.net 6596 :CBC 75 : initPQExpBuffer(&buf);
6597 : :
6598 : 75 : printfPQExpBuffer(&buf,
6599 : : "SELECT subname AS \"%s\"\n"
6600 : : ", pg_catalog.pg_get_userbyid(subowner) AS \"%s\"\n"
6601 : : ", subenabled AS \"%s\"\n"
6602 : : ", subpublications AS \"%s\"\n",
6603 : : gettext_noop("Name"),
6604 : : gettext_noop("Owner"),
6605 : : gettext_noop("Enabled"),
6606 : : gettext_noop("Publication"));
6607 : :
6608 [ + + ]: 75 : if (verbose)
6609 : : {
6610 : : /* Binary mode and streaming are only supported in v14 and higher */
1366 tgl@sss.pgh.pa.us 6611 [ + - ]: 57 : if (pset.sversion >= 140000)
6612 : : {
6613 : 57 : appendPQExpBuffer(&buf,
6614 : : ", subbinary AS \"%s\"\n",
6615 : : gettext_noop("Binary"));
6616 : :
461 akapila@postgresql.o 6617 [ + - ]: 57 : if (pset.sversion >= 160000)
6618 : 57 : appendPQExpBuffer(&buf,
6619 : : ", (CASE substream\n"
6620 : : " WHEN 'f' THEN 'off'\n"
6621 : : " WHEN 't' THEN 'on'\n"
6622 : : " WHEN 'p' THEN 'parallel'\n"
6623 : : " END) AS \"%s\"\n",
6624 : : gettext_noop("Streaming"));
6625 : : else
461 akapila@postgresql.o 6626 :UBC 0 : appendPQExpBuffer(&buf,
6627 : : ", substream AS \"%s\"\n",
6628 : : gettext_noop("Streaming"));
6629 : : }
6630 : :
6631 : : /* Two_phase and disable_on_error are only supported in v15 and higher */
1005 akapila@postgresql.o 6632 [ + - ]:CBC 57 : if (pset.sversion >= 150000)
6633 : 57 : appendPQExpBuffer(&buf,
6634 : : ", subtwophasestate AS \"%s\"\n"
6635 : : ", subdisableonerr AS \"%s\"\n",
6636 : : gettext_noop("Two-phase commit"),
6637 : : gettext_noop("Disable on error"));
6638 : :
633 6639 [ + - ]: 57 : if (pset.sversion >= 160000)
6640 : 57 : appendPQExpBuffer(&buf,
6641 : : ", suborigin AS \"%s\"\n"
6642 : : ", subpasswordrequired AS \"%s\"\n"
6643 : : ", subrunasowner AS \"%s\"\n",
6644 : : gettext_noop("Origin"),
6645 : : gettext_noop("Password required"),
6646 : : gettext_noop("Run as owner?"));
6647 : :
75 akapila@postgresql.o 6648 [ + - ]:GNC 57 : if (pset.sversion >= 170000)
6649 : 57 : appendPQExpBuffer(&buf,
6650 : : ", subfailover AS \"%s\"\n",
6651 : : gettext_noop("Failover"));
6652 : :
2642 peter_e@gmx.net 6653 :CBC 57 : appendPQExpBuffer(&buf,
6654 : : ", subsynccommit AS \"%s\"\n"
6655 : : ", subconninfo AS \"%s\"\n",
6656 : : gettext_noop("Synchronous commit"),
6657 : : gettext_noop("Conninfo"));
6658 : :
6659 : : /* Skip LSN is only supported in v15 and higher */
754 akapila@postgresql.o 6660 [ + - ]: 57 : if (pset.sversion >= 150000)
6661 : 57 : appendPQExpBuffer(&buf,
6662 : : ", subskiplsn AS \"%s\"\n",
6663 : : gettext_noop("Skip LSN"));
6664 : : }
6665 : :
6666 : : /* Only display subscriptions in current database. */
2642 peter_e@gmx.net 6667 : 75 : appendPQExpBufferStr(&buf,
6668 : : "FROM pg_catalog.pg_subscription\n"
6669 : : "WHERE subdbid = (SELECT oid\n"
6670 : : " FROM pg_catalog.pg_database\n"
6671 : : " WHERE datname = pg_catalog.current_database())");
6672 : :
725 rhaas@postgresql.org 6673 [ + + ]: 75 : if (!validateSQLNamePattern(&buf, pattern, true, false,
6674 : : NULL, "subname", NULL,
6675 : : NULL,
6676 : : NULL, 1))
6677 : : {
633 michael@paquier.xyz 6678 : 9 : termPQExpBuffer(&buf);
725 rhaas@postgresql.org 6679 : 9 : return false;
6680 : : }
6681 : :
2642 peter_e@gmx.net 6682 : 66 : appendPQExpBufferStr(&buf, "ORDER BY 1;");
6683 : :
6684 : 66 : res = PSQLexec(buf.data);
6685 : 66 : termPQExpBuffer(&buf);
6686 [ - + ]: 66 : if (!res)
2642 peter_e@gmx.net 6687 :UBC 0 : return false;
6688 : :
2642 peter_e@gmx.net 6689 :CBC 66 : myopt.title = _("List of subscriptions");
6690 : 66 : myopt.translate_header = true;
6691 : 66 : myopt.translate_columns = translate_columns;
6692 : 66 : myopt.n_translate_columns = lengthof(translate_columns);
6693 : :
6694 : 66 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6695 : :
6696 : 66 : PQclear(res);
6697 : 66 : return true;
6698 : : }
6699 : :
6700 : : /*
6701 : : * printACLColumn
6702 : : *
6703 : : * Helper function for consistently formatting ACL (privilege) columns.
6704 : : * The proper targetlist entry is appended to buf. Note lack of any
6705 : : * whitespace or comma decoration.
6706 : : *
6707 : : * If you change this, see also the handling of attacl in permissionsList(),
6708 : : * which can't conveniently use this code.
6709 : : */
6710 : : static void
5583 tgl@sss.pgh.pa.us 6711 : 150 : printACLColumn(PQExpBuffer buf, const char *colname)
6712 : : {
850 6713 : 150 : appendPQExpBuffer(buf,
6714 : : "CASE"
6715 : : " WHEN pg_catalog.cardinality(%s) = 0 THEN '%s'"
6716 : : " ELSE pg_catalog.array_to_string(%s, E'\\n')"
6717 : : " END AS \"%s\"",
6718 : : colname, gettext_noop("(none)"),
6719 : : colname, gettext_noop("Access privileges"));
5583 6720 : 150 : }
6721 : :
6722 : : /*
6723 : : * \dAc
6724 : : * Lists operator classes
6725 : : *
6726 : : * Takes optional regexps to filter by index access method and input data type.
6727 : : */
6728 : : bool
1498 akorotkov@postgresql 6729 : 15 : listOperatorClasses(const char *access_method_pattern,
6730 : : const char *type_pattern, bool verbose)
6731 : : {
6732 : : PQExpBufferData buf;
6733 : : PGresult *res;
6734 : 15 : printQueryOpt myopt = pset.popt;
6735 : 15 : bool have_where = false;
6736 : : static const bool translate_columns[] = {false, false, false, false, false, false, false};
6737 : :
6738 : 15 : initPQExpBuffer(&buf);
6739 : :
6740 : 15 : printfPQExpBuffer(&buf,
6741 : : "SELECT\n"
6742 : : " am.amname AS \"%s\",\n"
6743 : : " pg_catalog.format_type(c.opcintype, NULL) AS \"%s\",\n"
6744 : : " CASE\n"
6745 : : " WHEN c.opckeytype <> 0 AND c.opckeytype <> c.opcintype\n"
6746 : : " THEN pg_catalog.format_type(c.opckeytype, NULL)\n"
6747 : : " ELSE NULL\n"
6748 : : " END AS \"%s\",\n"
6749 : : " CASE\n"
6750 : : " WHEN pg_catalog.pg_opclass_is_visible(c.oid)\n"
6751 : : " THEN pg_catalog.format('%%I', c.opcname)\n"
6752 : : " ELSE pg_catalog.format('%%I.%%I', n.nspname, c.opcname)\n"
6753 : : " END AS \"%s\",\n"
6754 : : " (CASE WHEN c.opcdefault\n"
6755 : : " THEN '%s'\n"
6756 : : " ELSE '%s'\n"
6757 : : " END) AS \"%s\"",
6758 : : gettext_noop("AM"),
6759 : : gettext_noop("Input type"),
6760 : : gettext_noop("Storage type"),
6761 : : gettext_noop("Operator class"),
6762 : : gettext_noop("yes"),
6763 : : gettext_noop("no"),
6764 : : gettext_noop("Default?"));
6765 [ - + ]: 15 : if (verbose)
1498 akorotkov@postgresql 6766 :UBC 0 : appendPQExpBuffer(&buf,
6767 : : ",\n CASE\n"
6768 : : " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
6769 : : " THEN pg_catalog.format('%%I', of.opfname)\n"
6770 : : " ELSE pg_catalog.format('%%I.%%I', ofn.nspname, of.opfname)\n"
6771 : : " END AS \"%s\",\n"
6772 : : " pg_catalog.pg_get_userbyid(c.opcowner) AS \"%s\"\n",
6773 : : gettext_noop("Operator family"),
6774 : : gettext_noop("Owner"));
1277 drowley@postgresql.o 6775 :CBC 15 : appendPQExpBufferStr(&buf,
6776 : : "\nFROM pg_catalog.pg_opclass c\n"
6777 : : " LEFT JOIN pg_catalog.pg_am am on am.oid = c.opcmethod\n"
6778 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.opcnamespace\n"
6779 : : " LEFT JOIN pg_catalog.pg_type t ON t.oid = c.opcintype\n"
6780 : : " LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n");
1498 akorotkov@postgresql 6781 [ - + ]: 15 : if (verbose)
1277 drowley@postgresql.o 6782 :UBC 0 : appendPQExpBufferStr(&buf,
6783 : : " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = c.opcfamily\n"
6784 : : " LEFT JOIN pg_catalog.pg_namespace ofn ON ofn.oid = of.opfnamespace\n");
6785 : :
1498 akorotkov@postgresql 6786 [ + - ]:CBC 15 : if (access_method_pattern)
725 rhaas@postgresql.org 6787 [ + + ]: 15 : if (!validateSQLNamePattern(&buf, access_method_pattern,
6788 : : false, false, NULL, "am.amname", NULL, NULL,
6789 : : &have_where, 1))
633 michael@paquier.xyz 6790 : 9 : goto error_return;
1498 akorotkov@postgresql 6791 [ + + ]: 6 : if (type_pattern)
6792 : : {
6793 : : /* Match type name pattern against either internal or external name */
725 rhaas@postgresql.org 6794 [ - + ]: 3 : if (!validateSQLNamePattern(&buf, type_pattern, have_where, false,
6795 : : "tn.nspname", "t.typname",
6796 : : "pg_catalog.format_type(t.oid, NULL)",
6797 : : "pg_catalog.pg_type_is_visible(t.oid)",
6798 : : NULL, 3))
633 michael@paquier.xyz 6799 :UBC 0 : goto error_return;
6800 : : }
6801 : :
1498 akorotkov@postgresql 6802 :CBC 6 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
6803 : 6 : res = PSQLexec(buf.data);
6804 : 6 : termPQExpBuffer(&buf);
6805 [ - + ]: 6 : if (!res)
1498 akorotkov@postgresql 6806 :UBC 0 : return false;
6807 : :
1498 akorotkov@postgresql 6808 :CBC 6 : myopt.title = _("List of operator classes");
6809 : 6 : myopt.translate_header = true;
6810 : 6 : myopt.translate_columns = translate_columns;
6811 : 6 : myopt.n_translate_columns = lengthof(translate_columns);
6812 : :
6813 : 6 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6814 : :
6815 : 6 : PQclear(res);
6816 : 6 : return true;
6817 : :
633 michael@paquier.xyz 6818 : 9 : error_return:
6819 : 9 : termPQExpBuffer(&buf);
6820 : 9 : return false;
6821 : : }
6822 : :
6823 : : /*
6824 : : * \dAf
6825 : : * Lists operator families
6826 : : *
6827 : : * Takes optional regexps to filter by index access method and input data type.
6828 : : */
6829 : : bool
1498 akorotkov@postgresql 6830 : 18 : listOperatorFamilies(const char *access_method_pattern,
6831 : : const char *type_pattern, bool verbose)
6832 : : {
6833 : : PQExpBufferData buf;
6834 : : PGresult *res;
6835 : 18 : printQueryOpt myopt = pset.popt;
6836 : 18 : bool have_where = false;
6837 : : static const bool translate_columns[] = {false, false, false, false};
6838 : :
6839 : 18 : initPQExpBuffer(&buf);
6840 : :
6841 : 18 : printfPQExpBuffer(&buf,
6842 : : "SELECT\n"
6843 : : " am.amname AS \"%s\",\n"
6844 : : " CASE\n"
6845 : : " WHEN pg_catalog.pg_opfamily_is_visible(f.oid)\n"
6846 : : " THEN pg_catalog.format('%%I', f.opfname)\n"
6847 : : " ELSE pg_catalog.format('%%I.%%I', n.nspname, f.opfname)\n"
6848 : : " END AS \"%s\",\n"
6849 : : " (SELECT\n"
6850 : : " pg_catalog.string_agg(pg_catalog.format_type(oc.opcintype, NULL), ', ')\n"
6851 : : " FROM pg_catalog.pg_opclass oc\n"
6852 : : " WHERE oc.opcfamily = f.oid) \"%s\"",
6853 : : gettext_noop("AM"),
6854 : : gettext_noop("Operator family"),
6855 : : gettext_noop("Applicable types"));
6856 [ - + ]: 18 : if (verbose)
1498 akorotkov@postgresql 6857 :UBC 0 : appendPQExpBuffer(&buf,
6858 : : ",\n pg_catalog.pg_get_userbyid(f.opfowner) AS \"%s\"\n",
6859 : : gettext_noop("Owner"));
1277 drowley@postgresql.o 6860 :CBC 18 : appendPQExpBufferStr(&buf,
6861 : : "\nFROM pg_catalog.pg_opfamily f\n"
6862 : : " LEFT JOIN pg_catalog.pg_am am on am.oid = f.opfmethod\n"
6863 : : " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace\n");
6864 : :
1498 akorotkov@postgresql 6865 [ + - ]: 18 : if (access_method_pattern)
725 rhaas@postgresql.org 6866 [ + + ]: 18 : if (!validateSQLNamePattern(&buf, access_method_pattern,
6867 : : false, false, NULL, "am.amname", NULL, NULL,
6868 : : &have_where, 1))
633 michael@paquier.xyz 6869 : 9 : goto error_return;
1498 akorotkov@postgresql 6870 [ + + ]: 9 : if (type_pattern)
6871 : : {
1498 akorotkov@postgresql 6872 :UBC 0 : appendPQExpBuffer(&buf,
6873 : : " %s EXISTS (\n"
6874 : : " SELECT 1\n"
6875 : : " FROM pg_catalog.pg_type t\n"
6876 : : " JOIN pg_catalog.pg_opclass oc ON oc.opcintype = t.oid\n"
6877 : : " LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace\n"
6878 : : " WHERE oc.opcfamily = f.oid\n",
1498 akorotkov@postgresql 6879 [ + - ]:CBC 3 : have_where ? "AND" : "WHERE");
6880 : : /* Match type name pattern against either internal or external name */
725 rhaas@postgresql.org 6881 [ - + ]: 3 : if (!validateSQLNamePattern(&buf, type_pattern, true, false,
6882 : : "tn.nspname", "t.typname",
6883 : : "pg_catalog.format_type(t.oid, NULL)",
6884 : : "pg_catalog.pg_type_is_visible(t.oid)",
6885 : : NULL, 3))
633 michael@paquier.xyz 6886 :UBC 0 : goto error_return;
1277 drowley@postgresql.o 6887 :CBC 3 : appendPQExpBufferStr(&buf, " )\n");
6888 : : }
6889 : :
1498 akorotkov@postgresql 6890 : 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
6891 : 9 : res = PSQLexec(buf.data);
6892 : 9 : termPQExpBuffer(&buf);
6893 [ - + ]: 9 : if (!res)
1498 akorotkov@postgresql 6894 :UBC 0 : return false;
6895 : :
1498 akorotkov@postgresql 6896 :CBC 9 : myopt.title = _("List of operator families");
6897 : 9 : myopt.translate_header = true;
6898 : 9 : myopt.translate_columns = translate_columns;
6899 : 9 : myopt.n_translate_columns = lengthof(translate_columns);
6900 : :
6901 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
6902 : :
6903 : 9 : PQclear(res);
6904 : 9 : return true;
6905 : :
633 michael@paquier.xyz 6906 : 9 : error_return:
6907 : 9 : termPQExpBuffer(&buf);
6908 : 9 : return false;
6909 : : }
6910 : :
6911 : : /*
6912 : : * \dAo
6913 : : * Lists operators of operator families
6914 : : *
6915 : : * Takes optional regexps to filter by index access method and operator
6916 : : * family.
6917 : : */
6918 : : bool
1498 akorotkov@postgresql 6919 : 18 : listOpFamilyOperators(const char *access_method_pattern,
6920 : : const char *family_pattern, bool verbose)
6921 : : {
6922 : : PQExpBufferData buf;
6923 : : PGresult *res;
6924 : 18 : printQueryOpt myopt = pset.popt;
6925 : 18 : bool have_where = false;
6926 : :
6927 : : static const bool translate_columns[] = {false, false, false, false, false, false};
6928 : :
6929 : 18 : initPQExpBuffer(&buf);
6930 : :
6931 : 18 : printfPQExpBuffer(&buf,
6932 : : "SELECT\n"
6933 : : " am.amname AS \"%s\",\n"
6934 : : " CASE\n"
6935 : : " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
6936 : : " THEN pg_catalog.format('%%I', of.opfname)\n"
6937 : : " ELSE pg_catalog.format('%%I.%%I', nsf.nspname, of.opfname)\n"
6938 : : " END AS \"%s\",\n"
6939 : : " o.amopopr::pg_catalog.regoperator AS \"%s\"\n,"
6940 : : " o.amopstrategy AS \"%s\",\n"
6941 : : " CASE o.amoppurpose\n"
6942 : : " WHEN 'o' THEN '%s'\n"
6943 : : " WHEN 's' THEN '%s'\n"
6944 : : " END AS \"%s\"\n",
6945 : : gettext_noop("AM"),
6946 : : gettext_noop("Operator family"),
6947 : : gettext_noop("Operator"),
6948 : : gettext_noop("Strategy"),
6949 : : gettext_noop("ordering"),
6950 : : gettext_noop("search"),
6951 : : gettext_noop("Purpose"));
6952 : :
6953 [ + + ]: 18 : if (verbose)
6954 : 3 : appendPQExpBuffer(&buf,
6955 : : ", ofs.opfname AS \"%s\"\n",
6956 : : gettext_noop("Sort opfamily"));
1277 drowley@postgresql.o 6957 : 18 : appendPQExpBufferStr(&buf,
6958 : : "FROM pg_catalog.pg_amop o\n"
6959 : : " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\n"
6960 : : " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod AND am.oid = o.amopmethod\n"
6961 : : " LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n");
1498 akorotkov@postgresql 6962 [ + + ]: 18 : if (verbose)
1277 drowley@postgresql.o 6963 : 3 : appendPQExpBufferStr(&buf,
6964 : : " LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n");
6965 : :
1498 akorotkov@postgresql 6966 [ + - ]: 18 : if (access_method_pattern)
6967 : : {
725 rhaas@postgresql.org 6968 [ + + ]: 18 : if (!validateSQLNamePattern(&buf, access_method_pattern,
6969 : : false, false, NULL, "am.amname",
6970 : : NULL, NULL,
6971 : : &have_where, 1))
633 michael@paquier.xyz 6972 : 9 : goto error_return;
6973 : : }
6974 : :
1498 akorotkov@postgresql 6975 [ + + ]: 9 : if (family_pattern)
6976 : : {
725 rhaas@postgresql.org 6977 [ - + ]: 6 : if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
6978 : : "nsf.nspname", "of.opfname", NULL, NULL,
6979 : : NULL, 3))
633 michael@paquier.xyz 6980 :UBC 0 : goto error_return;
6981 : : }
6982 : :
1428 akorotkov@postgresql 6983 :CBC 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
6984 : : " o.amoplefttype = o.amoprighttype DESC,\n"
6985 : : " pg_catalog.format_type(o.amoplefttype, NULL),\n"
6986 : : " pg_catalog.format_type(o.amoprighttype, NULL),\n"
6987 : : " o.amopstrategy;");
6988 : :
1498 6989 : 9 : res = PSQLexec(buf.data);
6990 : 9 : termPQExpBuffer(&buf);
6991 [ - + ]: 9 : if (!res)
1498 akorotkov@postgresql 6992 :UBC 0 : return false;
6993 : :
1498 akorotkov@postgresql 6994 :CBC 9 : myopt.title = _("List of operators of operator families");
6995 : 9 : myopt.translate_header = true;
6996 : 9 : myopt.translate_columns = translate_columns;
6997 : 9 : myopt.n_translate_columns = lengthof(translate_columns);
6998 : :
6999 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7000 : :
7001 : 9 : PQclear(res);
7002 : 9 : return true;
7003 : :
633 michael@paquier.xyz 7004 : 9 : error_return:
7005 : 9 : termPQExpBuffer(&buf);
7006 : 9 : return false;
7007 : : }
7008 : :
7009 : : /*
7010 : : * \dAp
7011 : : * Lists support functions of operator families
7012 : : *
7013 : : * Takes optional regexps to filter by index access method and operator
7014 : : * family.
7015 : : */
7016 : : bool
1410 peter@eisentraut.org 7017 : 18 : listOpFamilyFunctions(const char *access_method_pattern,
7018 : : const char *family_pattern, bool verbose)
7019 : : {
7020 : : PQExpBufferData buf;
7021 : : PGresult *res;
1498 akorotkov@postgresql 7022 : 18 : printQueryOpt myopt = pset.popt;
7023 : 18 : bool have_where = false;
7024 : : static const bool translate_columns[] = {false, false, false, false, false, false};
7025 : :
7026 : 18 : initPQExpBuffer(&buf);
7027 : :
7028 : 18 : printfPQExpBuffer(&buf,
7029 : : "SELECT\n"
7030 : : " am.amname AS \"%s\",\n"
7031 : : " CASE\n"
7032 : : " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n"
7033 : : " THEN pg_catalog.format('%%I', of.opfname)\n"
7034 : : " ELSE pg_catalog.format('%%I.%%I', ns.nspname, of.opfname)\n"
7035 : : " END AS \"%s\",\n"
7036 : : " pg_catalog.format_type(ap.amproclefttype, NULL) AS \"%s\",\n"
7037 : : " pg_catalog.format_type(ap.amprocrighttype, NULL) AS \"%s\",\n"
7038 : : " ap.amprocnum AS \"%s\"\n",
7039 : : gettext_noop("AM"),
7040 : : gettext_noop("Operator family"),
7041 : : gettext_noop("Registered left type"),
7042 : : gettext_noop("Registered right type"),
7043 : : gettext_noop("Number"));
7044 : :
1373 7045 [ + + ]: 18 : if (!verbose)
7046 : 15 : appendPQExpBuffer(&buf,
7047 : : ", p.proname AS \"%s\"\n",
7048 : : gettext_noop("Function"));
7049 : : else
7050 : 3 : appendPQExpBuffer(&buf,
7051 : : ", ap.amproc::pg_catalog.regprocedure AS \"%s\"\n",
7052 : : gettext_noop("Function"));
7053 : :
1277 drowley@postgresql.o 7054 : 18 : appendPQExpBufferStr(&buf,
7055 : : "FROM pg_catalog.pg_amproc ap\n"
7056 : : " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = ap.amprocfamily\n"
7057 : : " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod\n"
7058 : : " LEFT JOIN pg_catalog.pg_namespace ns ON of.opfnamespace = ns.oid\n"
7059 : : " LEFT JOIN pg_catalog.pg_proc p ON ap.amproc = p.oid\n");
7060 : :
1498 akorotkov@postgresql 7061 [ + - ]: 18 : if (access_method_pattern)
7062 : : {
725 rhaas@postgresql.org 7063 [ + + ]: 18 : if (!validateSQLNamePattern(&buf, access_method_pattern,
7064 : : false, false, NULL, "am.amname",
7065 : : NULL, NULL,
7066 : : &have_where, 1))
633 michael@paquier.xyz 7067 : 9 : goto error_return;
7068 : : }
1498 akorotkov@postgresql 7069 [ + + ]: 9 : if (family_pattern)
7070 : : {
725 rhaas@postgresql.org 7071 [ - + ]: 6 : if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
7072 : : "ns.nspname", "of.opfname", NULL, NULL,
7073 : : NULL, 3))
633 michael@paquier.xyz 7074 :UBC 0 : goto error_return;
7075 : : }
7076 : :
1428 akorotkov@postgresql 7077 :CBC 9 : appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
7078 : : " ap.amproclefttype = ap.amprocrighttype DESC,\n"
7079 : : " 3, 4, 5;");
7080 : :
1498 7081 : 9 : res = PSQLexec(buf.data);
7082 : 9 : termPQExpBuffer(&buf);
7083 [ - + ]: 9 : if (!res)
1498 akorotkov@postgresql 7084 :UBC 0 : return false;
7085 : :
1410 peter@eisentraut.org 7086 :CBC 9 : myopt.title = _("List of support functions of operator families");
1498 akorotkov@postgresql 7087 : 9 : myopt.translate_header = true;
7088 : 9 : myopt.translate_columns = translate_columns;
7089 : 9 : myopt.n_translate_columns = lengthof(translate_columns);
7090 : :
7091 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7092 : :
7093 : 9 : PQclear(res);
7094 : 9 : return true;
7095 : :
633 michael@paquier.xyz 7096 : 9 : error_return:
7097 : 9 : termPQExpBuffer(&buf);
7098 : 9 : return false;
7099 : : }
7100 : :
7101 : : /*
7102 : : * \dl or \lo_list
7103 : : * Lists large objects
7104 : : */
7105 : : bool
829 tgl@sss.pgh.pa.us 7106 : 9 : listLargeObjects(bool verbose)
7107 : : {
7108 : : PQExpBufferData buf;
7109 : : PGresult *res;
7110 : 9 : printQueryOpt myopt = pset.popt;
7111 : :
7112 : 9 : initPQExpBuffer(&buf);
7113 : :
7114 : 9 : printfPQExpBuffer(&buf,
7115 : : "SELECT oid as \"%s\",\n"
7116 : : " pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n ",
7117 : : gettext_noop("ID"),
7118 : : gettext_noop("Owner"));
7119 : :
7120 [ + + ]: 9 : if (verbose)
7121 : : {
7122 : 3 : printACLColumn(&buf, "lomacl");
7123 : 3 : appendPQExpBufferStr(&buf, ",\n ");
7124 : : }
7125 : :
7126 : 9 : appendPQExpBuffer(&buf,
7127 : : "pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n"
7128 : : "FROM pg_catalog.pg_largeobject_metadata\n"
7129 : : "ORDER BY oid",
7130 : : gettext_noop("Description"));
7131 : :
7132 : 9 : res = PSQLexec(buf.data);
7133 : 9 : termPQExpBuffer(&buf);
7134 [ - + ]: 9 : if (!res)
829 tgl@sss.pgh.pa.us 7135 :UBC 0 : return false;
7136 : :
829 tgl@sss.pgh.pa.us 7137 :CBC 9 : myopt.title = _("Large objects");
7138 : 9 : myopt.translate_header = true;
7139 : :
7140 : 9 : printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
7141 : :
7142 : 9 : PQclear(res);
7143 : 9 : return true;
7144 : : }
|