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