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