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