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