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