00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "postgres_fe.h"
00014
00015 #include <ctype.h>
00016
00017 #include "catalog/pg_default_acl.h"
00018
00019 #include "common.h"
00020 #include "describe.h"
00021 #include "dumputils.h"
00022 #include "mbprint.h"
00023 #include "print.h"
00024 #include "settings.h"
00025 #include "variables.h"
00026
00027
00028 static bool describeOneTableDetails(const char *schemaname,
00029 const char *relationname,
00030 const char *oid,
00031 bool verbose);
00032 static void add_tablespace_footer(printTableContent *const cont, char relkind,
00033 Oid tablespace, const bool newline);
00034 static void add_role_attribute(PQExpBuffer buf, const char *const str);
00035 static bool listTSParsersVerbose(const char *pattern);
00036 static bool describeOneTSParser(const char *oid, const char *nspname,
00037 const char *prsname);
00038 static bool listTSConfigsVerbose(const char *pattern);
00039 static bool describeOneTSConfig(const char *oid, const char *nspname,
00040 const char *cfgname,
00041 const char *pnspname, const char *prsname);
00042 static void printACLColumn(PQExpBuffer buf, const char *colname);
00043 static bool listOneExtensionContents(const char *extname, const char *oid);
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 bool
00059 describeAggregates(const char *pattern, bool verbose, bool showSystem)
00060 {
00061 PQExpBufferData buf;
00062 PGresult *res;
00063 printQueryOpt myopt = pset.popt;
00064
00065 initPQExpBuffer(&buf);
00066
00067 printfPQExpBuffer(&buf,
00068 "SELECT n.nspname as \"%s\",\n"
00069 " p.proname AS \"%s\",\n"
00070 " pg_catalog.format_type(p.prorettype, NULL) AS \"%s\",\n",
00071 gettext_noop("Schema"),
00072 gettext_noop("Name"),
00073 gettext_noop("Result data type"));
00074
00075 if (pset.sversion >= 80200)
00076 appendPQExpBuffer(&buf,
00077 " CASE WHEN p.pronargs = 0\n"
00078 " THEN CAST('*' AS pg_catalog.text)\n"
00079 " ELSE\n"
00080 " pg_catalog.array_to_string(ARRAY(\n"
00081 " SELECT\n"
00082 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
00083 " FROM\n"
00084 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
00085 " ), ', ')\n"
00086 " END AS \"%s\",\n",
00087 gettext_noop("Argument data types"));
00088 else
00089 appendPQExpBuffer(&buf,
00090 " pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
00091 gettext_noop("Argument data types"));
00092
00093 appendPQExpBuffer(&buf,
00094 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
00095 "FROM pg_catalog.pg_proc p\n"
00096 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
00097 "WHERE p.proisagg\n",
00098 gettext_noop("Description"));
00099
00100 if (!showSystem && !pattern)
00101 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
00102 " AND n.nspname <> 'information_schema'\n");
00103
00104 processSQLNamePattern(pset.db, &buf, pattern, true, false,
00105 "n.nspname", "p.proname", NULL,
00106 "pg_catalog.pg_function_is_visible(p.oid)");
00107
00108 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 4;");
00109
00110 res = PSQLexec(buf.data, false);
00111 termPQExpBuffer(&buf);
00112 if (!res)
00113 return false;
00114
00115 myopt.nullPrint = NULL;
00116 myopt.title = _("List of aggregate functions");
00117 myopt.translate_header = true;
00118
00119 printQuery(res, &myopt, pset.queryFout, pset.logfile);
00120
00121 PQclear(res);
00122 return true;
00123 }
00124
00125
00126
00127
00128 bool
00129 describeTablespaces(const char *pattern, bool verbose)
00130 {
00131 PQExpBufferData buf;
00132 PGresult *res;
00133 printQueryOpt myopt = pset.popt;
00134
00135 if (pset.sversion < 80000)
00136 {
00137 psql_error("The server (version %d.%d) does not support tablespaces.\n",
00138 pset.sversion / 10000, (pset.sversion / 100) % 100);
00139 return true;
00140 }
00141
00142 initPQExpBuffer(&buf);
00143
00144 if (pset.sversion >= 90200)
00145 printfPQExpBuffer(&buf,
00146 "SELECT spcname AS \"%s\",\n"
00147 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
00148 " pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
00149 gettext_noop("Name"),
00150 gettext_noop("Owner"),
00151 gettext_noop("Location"));
00152 else
00153 printfPQExpBuffer(&buf,
00154 "SELECT spcname AS \"%s\",\n"
00155 " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
00156 " spclocation AS \"%s\"",
00157 gettext_noop("Name"),
00158 gettext_noop("Owner"),
00159 gettext_noop("Location"));
00160
00161 if (verbose)
00162 {
00163 appendPQExpBuffer(&buf, ",\n ");
00164 printACLColumn(&buf, "spcacl");
00165 }
00166
00167 if (verbose && pset.sversion >= 80200)
00168 appendPQExpBuffer(&buf,
00169 ",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
00170 gettext_noop("Description"));
00171
00172 appendPQExpBuffer(&buf,
00173 "\nFROM pg_catalog.pg_tablespace\n");
00174
00175 processSQLNamePattern(pset.db, &buf, pattern, false, false,
00176 NULL, "spcname", NULL,
00177 NULL);
00178
00179 appendPQExpBuffer(&buf, "ORDER BY 1;");
00180
00181 res = PSQLexec(buf.data, false);
00182 termPQExpBuffer(&buf);
00183 if (!res)
00184 return false;
00185
00186 myopt.nullPrint = NULL;
00187 myopt.title = _("List of tablespaces");
00188 myopt.translate_header = true;
00189
00190 printQuery(res, &myopt, pset.queryFout, pset.logfile);
00191
00192 PQclear(res);
00193 return true;
00194 }
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 bool
00210 describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem)
00211 {
00212 bool showAggregate = strchr(functypes, 'a') != NULL;
00213 bool showNormal = strchr(functypes, 'n') != NULL;
00214 bool showTrigger = strchr(functypes, 't') != NULL;
00215 bool showWindow = strchr(functypes, 'w') != NULL;
00216 bool have_where;
00217 PQExpBufferData buf;
00218 PGresult *res;
00219 printQueryOpt myopt = pset.popt;
00220 static const bool translate_columns[] = {false, false, false, false, true, true, false, false, false, false};
00221
00222 if (strlen(functypes) != strspn(functypes, "antwS+"))
00223 {
00224 psql_error("\\df only takes [antwS+] as options\n");
00225 return true;
00226 }
00227
00228 if (showWindow && pset.sversion < 80400)
00229 {
00230 psql_error("\\df does not take a \"w\" option with server version %d.%d\n",
00231 pset.sversion / 10000, (pset.sversion / 100) % 100);
00232 return true;
00233 }
00234
00235 if (!showAggregate && !showNormal && !showTrigger && !showWindow)
00236 {
00237 showAggregate = showNormal = showTrigger = true;
00238 if (pset.sversion >= 80400)
00239 showWindow = true;
00240 }
00241
00242 initPQExpBuffer(&buf);
00243
00244 printfPQExpBuffer(&buf,
00245 "SELECT n.nspname as \"%s\",\n"
00246 " p.proname as \"%s\",\n",
00247 gettext_noop("Schema"),
00248 gettext_noop("Name"));
00249
00250 if (pset.sversion >= 80400)
00251 appendPQExpBuffer(&buf,
00252 " pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
00253 " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
00254 " CASE\n"
00255 " WHEN p.proisagg THEN '%s'\n"
00256 " WHEN p.proiswindow THEN '%s'\n"
00257 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
00258 " ELSE '%s'\n"
00259 " END as \"%s\"",
00260 gettext_noop("Result data type"),
00261 gettext_noop("Argument data types"),
00262
00263 gettext_noop("agg"),
00264 gettext_noop("window"),
00265 gettext_noop("trigger"),
00266 gettext_noop("normal"),
00267 gettext_noop("Type"));
00268 else if (pset.sversion >= 80100)
00269 appendPQExpBuffer(&buf,
00270 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
00271 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
00272 " CASE WHEN proallargtypes IS NOT NULL THEN\n"
00273 " pg_catalog.array_to_string(ARRAY(\n"
00274 " SELECT\n"
00275 " CASE\n"
00276 " WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
00277 " WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
00278 " WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
00279 " WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
00280 " END ||\n"
00281 " CASE\n"
00282 " WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
00283 " ELSE p.proargnames[s.i] || ' ' \n"
00284 " END ||\n"
00285 " pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
00286 " FROM\n"
00287 " pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
00288 " ), ', ')\n"
00289 " ELSE\n"
00290 " pg_catalog.array_to_string(ARRAY(\n"
00291 " SELECT\n"
00292 " CASE\n"
00293 " WHEN COALESCE(p.proargnames[s.i+1], '') = '' THEN ''\n"
00294 " ELSE p.proargnames[s.i+1] || ' '\n"
00295 " END ||\n"
00296 " pg_catalog.format_type(p.proargtypes[s.i], NULL)\n"
00297 " FROM\n"
00298 " pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
00299 " ), ', ')\n"
00300 " END AS \"%s\",\n"
00301 " CASE\n"
00302 " WHEN p.proisagg THEN '%s'\n"
00303 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
00304 " ELSE '%s'\n"
00305 " END AS \"%s\"",
00306 gettext_noop("Result data type"),
00307 gettext_noop("Argument data types"),
00308
00309 gettext_noop("agg"),
00310 gettext_noop("trigger"),
00311 gettext_noop("normal"),
00312 gettext_noop("Type"));
00313 else
00314 appendPQExpBuffer(&buf,
00315 " CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
00316 " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
00317 " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\",\n"
00318 " CASE\n"
00319 " WHEN p.proisagg THEN '%s'\n"
00320 " WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
00321 " ELSE '%s'\n"
00322 " END AS \"%s\"",
00323 gettext_noop("Result data type"),
00324 gettext_noop("Argument data types"),
00325
00326 gettext_noop("agg"),
00327 gettext_noop("trigger"),
00328 gettext_noop("normal"),
00329 gettext_noop("Type"));
00330
00331 if (verbose)
00332 appendPQExpBuffer(&buf,
00333 ",\n CASE WHEN prosecdef THEN '%s' ELSE '%s' END AS \"%s\""
00334 ",\n CASE\n"
00335 " WHEN p.provolatile = 'i' THEN '%s'\n"
00336 " WHEN p.provolatile = 's' THEN '%s'\n"
00337 " WHEN p.provolatile = 'v' THEN '%s'\n"
00338 " END as \"%s\""
00339 ",\n pg_catalog.pg_get_userbyid(p.proowner) as \"%s\",\n"
00340 " l.lanname as \"%s\",\n"
00341 " p.prosrc as \"%s\",\n"
00342 " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"",
00343 gettext_noop("definer"),
00344 gettext_noop("invoker"),
00345 gettext_noop("Security"),
00346 gettext_noop("immutable"),
00347 gettext_noop("stable"),
00348 gettext_noop("volatile"),
00349 gettext_noop("Volatility"),
00350 gettext_noop("Owner"),
00351 gettext_noop("Language"),
00352 gettext_noop("Source code"),
00353 gettext_noop("Description"));
00354
00355 appendPQExpBuffer(&buf,
00356 "\nFROM pg_catalog.pg_proc p"
00357 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
00358
00359 if (verbose)
00360 appendPQExpBuffer(&buf,
00361 " LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
00362
00363 have_where = false;
00364
00365
00366 if (showNormal && showAggregate && showTrigger && showWindow)
00367 ;
00368 else if (showNormal)
00369 {
00370 if (!showAggregate)
00371 {
00372 if (have_where)
00373 appendPQExpBuffer(&buf, " AND ");
00374 else
00375 {
00376 appendPQExpBuffer(&buf, "WHERE ");
00377 have_where = true;
00378 }
00379 appendPQExpBuffer(&buf, "NOT p.proisagg\n");
00380 }
00381 if (!showTrigger)
00382 {
00383 if (have_where)
00384 appendPQExpBuffer(&buf, " AND ");
00385 else
00386 {
00387 appendPQExpBuffer(&buf, "WHERE ");
00388 have_where = true;
00389 }
00390 appendPQExpBuffer(&buf, "p.prorettype <> 'pg_catalog.trigger'::pg_catalog.regtype\n");
00391 }
00392 if (!showWindow && pset.sversion >= 80400)
00393 {
00394 if (have_where)
00395 appendPQExpBuffer(&buf, " AND ");
00396 else
00397 {
00398 appendPQExpBuffer(&buf, "WHERE ");
00399 have_where = true;
00400 }
00401 appendPQExpBuffer(&buf, "NOT p.proiswindow\n");
00402 }
00403 }
00404 else
00405 {
00406 bool needs_or = false;
00407
00408 appendPQExpBuffer(&buf, "WHERE (\n ");
00409 have_where = true;
00410
00411 if (showAggregate)
00412 {
00413 appendPQExpBuffer(&buf, "p.proisagg\n");
00414 needs_or = true;
00415 }
00416 if (showTrigger)
00417 {
00418 if (needs_or)
00419 appendPQExpBuffer(&buf, " OR ");
00420 appendPQExpBuffer(&buf,
00421 "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n");
00422 needs_or = true;
00423 }
00424 if (showWindow)
00425 {
00426 if (needs_or)
00427 appendPQExpBuffer(&buf, " OR ");
00428 appendPQExpBuffer(&buf, "p.proiswindow\n");
00429 needs_or = true;
00430 }
00431 appendPQExpBuffer(&buf, " )\n");
00432 }
00433
00434 processSQLNamePattern(pset.db, &buf, pattern, have_where, false,
00435 "n.nspname", "p.proname", NULL,
00436 "pg_catalog.pg_function_is_visible(p.oid)");
00437
00438 if (!showSystem && !pattern)
00439 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
00440 " AND n.nspname <> 'information_schema'\n");
00441
00442 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 4;");
00443
00444 res = PSQLexec(buf.data, false);
00445 termPQExpBuffer(&buf);
00446 if (!res)
00447 return false;
00448
00449 myopt.nullPrint = NULL;
00450 myopt.title = _("List of functions");
00451 myopt.translate_header = true;
00452 myopt.translate_columns = translate_columns;
00453
00454 printQuery(res, &myopt, pset.queryFout, pset.logfile);
00455
00456 PQclear(res);
00457 return true;
00458 }
00459
00460
00461
00462
00463
00464
00465
00466 bool
00467 describeTypes(const char *pattern, bool verbose, bool showSystem)
00468 {
00469 PQExpBufferData buf;
00470 PGresult *res;
00471 printQueryOpt myopt = pset.popt;
00472
00473 initPQExpBuffer(&buf);
00474
00475 printfPQExpBuffer(&buf,
00476 "SELECT n.nspname as \"%s\",\n"
00477 " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n",
00478 gettext_noop("Schema"),
00479 gettext_noop("Name"));
00480 if (verbose)
00481 appendPQExpBuffer(&buf,
00482 " t.typname AS \"%s\",\n"
00483 " CASE WHEN t.typrelid != 0\n"
00484 " THEN CAST('tuple' AS pg_catalog.text)\n"
00485 " WHEN t.typlen < 0\n"
00486 " THEN CAST('var' AS pg_catalog.text)\n"
00487 " ELSE CAST(t.typlen AS pg_catalog.text)\n"
00488 " END AS \"%s\",\n",
00489 gettext_noop("Internal name"),
00490 gettext_noop("Size"));
00491 if (verbose && pset.sversion >= 80300)
00492 {
00493 appendPQExpBuffer(&buf,
00494 " pg_catalog.array_to_string(\n"
00495 " ARRAY(\n"
00496 " SELECT e.enumlabel\n"
00497 " FROM pg_catalog.pg_enum e\n"
00498 " WHERE e.enumtypid = t.oid\n");
00499
00500 if (pset.sversion >= 90100)
00501 appendPQExpBuffer(&buf,
00502 " ORDER BY e.enumsortorder\n");
00503 else
00504 appendPQExpBuffer(&buf,
00505 " ORDER BY e.oid\n");
00506
00507 appendPQExpBuffer(&buf,
00508 " ),\n"
00509 " E'\\n'\n"
00510 " ) AS \"%s\",\n",
00511 gettext_noop("Elements"));
00512 }
00513 if (verbose && pset.sversion >= 90200)
00514 {
00515 printACLColumn(&buf, "t.typacl");
00516 appendPQExpBuffer(&buf, ",\n ");
00517 }
00518
00519 appendPQExpBuffer(&buf,
00520 " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
00521 gettext_noop("Description"));
00522
00523 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n"
00524 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
00525
00526
00527
00528
00529
00530 appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 ");
00531 appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
00532 "WHERE c.oid = t.typrelid))\n");
00533
00534
00535
00536
00537
00538 if (pset.sversion >= 80300)
00539 appendPQExpBuffer(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
00540 else
00541 appendPQExpBuffer(&buf, " AND t.typname !~ '^_'\n");
00542
00543 if (!showSystem && !pattern)
00544 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
00545 " AND n.nspname <> 'information_schema'\n");
00546
00547
00548 processSQLNamePattern(pset.db, &buf, pattern, true, false,
00549 "n.nspname", "t.typname",
00550 "pg_catalog.format_type(t.oid, NULL)",
00551 "pg_catalog.pg_type_is_visible(t.oid)");
00552
00553 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
00554
00555 res = PSQLexec(buf.data, false);
00556 termPQExpBuffer(&buf);
00557 if (!res)
00558 return false;
00559
00560 myopt.nullPrint = NULL;
00561 myopt.title = _("List of data types");
00562 myopt.translate_header = true;
00563
00564 printQuery(res, &myopt, pset.queryFout, pset.logfile);
00565
00566 PQclear(res);
00567 return true;
00568 }
00569
00570
00571
00572
00573 bool
00574 describeOperators(const char *pattern, bool showSystem)
00575 {
00576 PQExpBufferData buf;
00577 PGresult *res;
00578 printQueryOpt myopt = pset.popt;
00579
00580 initPQExpBuffer(&buf);
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 printfPQExpBuffer(&buf,
00596 "SELECT n.nspname as \"%s\",\n"
00597 " o.oprname AS \"%s\",\n"
00598 " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
00599 " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
00600 " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n"
00601 " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n"
00602 " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n"
00603 "FROM pg_catalog.pg_operator o\n"
00604 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
00605 gettext_noop("Schema"),
00606 gettext_noop("Name"),
00607 gettext_noop("Left arg type"),
00608 gettext_noop("Right arg type"),
00609 gettext_noop("Result type"),
00610 gettext_noop("Description"));
00611
00612 if (!showSystem && !pattern)
00613 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
00614 " AND n.nspname <> 'information_schema'\n");
00615
00616 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, true,
00617 "n.nspname", "o.oprname", NULL,
00618 "pg_catalog.pg_operator_is_visible(o.oid)");
00619
00620 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;");
00621
00622 res = PSQLexec(buf.data, false);
00623 termPQExpBuffer(&buf);
00624 if (!res)
00625 return false;
00626
00627 myopt.nullPrint = NULL;
00628 myopt.title = _("List of operators");
00629 myopt.translate_header = true;
00630
00631 printQuery(res, &myopt, pset.queryFout, pset.logfile);
00632
00633 PQclear(res);
00634 return true;
00635 }
00636
00637
00638
00639
00640
00641
00642
00643 bool
00644 listAllDbs(const char *pattern, bool verbose)
00645 {
00646 PGresult *res;
00647 PQExpBufferData buf;
00648 printQueryOpt myopt = pset.popt;
00649
00650 initPQExpBuffer(&buf);
00651
00652 printfPQExpBuffer(&buf,
00653 "SELECT d.datname as \"%s\",\n"
00654 " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
00655 " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
00656 gettext_noop("Name"),
00657 gettext_noop("Owner"),
00658 gettext_noop("Encoding"));
00659 if (pset.sversion >= 80400)
00660 appendPQExpBuffer(&buf,
00661 " d.datcollate as \"%s\",\n"
00662 " d.datctype as \"%s\",\n",
00663 gettext_noop("Collate"),
00664 gettext_noop("Ctype"));
00665 appendPQExpBuffer(&buf, " ");
00666 printACLColumn(&buf, "d.datacl");
00667 if (verbose && pset.sversion >= 80200)
00668 appendPQExpBuffer(&buf,
00669 ",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
00670 " THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
00671 " ELSE 'No Access'\n"
00672 " END as \"%s\"",
00673 gettext_noop("Size"));
00674 if (verbose && pset.sversion >= 80000)
00675 appendPQExpBuffer(&buf,
00676 ",\n t.spcname as \"%s\"",
00677 gettext_noop("Tablespace"));
00678 if (verbose && pset.sversion >= 80200)
00679 appendPQExpBuffer(&buf,
00680 ",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
00681 gettext_noop("Description"));
00682 appendPQExpBuffer(&buf,
00683 "\nFROM pg_catalog.pg_database d\n");
00684 if (verbose && pset.sversion >= 80000)
00685 appendPQExpBuffer(&buf,
00686 " JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid\n");
00687
00688 if (pattern)
00689 processSQLNamePattern(pset.db, &buf, pattern, false, false,
00690 NULL, "d.datname", NULL, NULL);
00691
00692 appendPQExpBuffer(&buf, "ORDER BY 1;");
00693 res = PSQLexec(buf.data, false);
00694 termPQExpBuffer(&buf);
00695 if (!res)
00696 return false;
00697
00698 myopt.nullPrint = NULL;
00699 myopt.title = _("List of databases");
00700 myopt.translate_header = true;
00701
00702 printQuery(res, &myopt, pset.queryFout, pset.logfile);
00703
00704 PQclear(res);
00705 return true;
00706 }
00707
00708
00709
00710
00711
00712
00713 bool
00714 permissionsList(const char *pattern)
00715 {
00716 PQExpBufferData buf;
00717 PGresult *res;
00718 printQueryOpt myopt = pset.popt;
00719 static const bool translate_columns[] = {false, false, true, false, false};
00720
00721 initPQExpBuffer(&buf);
00722
00723
00724
00725
00726 printfPQExpBuffer(&buf,
00727 "SELECT n.nspname as \"%s\",\n"
00728 " c.relname as \"%s\",\n"
00729 " CASE c.relkind"
00730 " WHEN 'r' THEN '%s'"
00731 " WHEN 'v' THEN '%s'"
00732 " WHEN 'm' THEN '%s'"
00733 " WHEN 'S' THEN '%s'"
00734 " WHEN 'f' THEN '%s'"
00735 " END as \"%s\",\n"
00736 " ",
00737 gettext_noop("Schema"),
00738 gettext_noop("Name"),
00739 gettext_noop("table"),
00740 gettext_noop("view"),
00741 gettext_noop("materialized view"),
00742 gettext_noop("sequence"),
00743 gettext_noop("foreign table"),
00744 gettext_noop("Type"));
00745
00746 printACLColumn(&buf, "c.relacl");
00747
00748 if (pset.sversion >= 80400)
00749 appendPQExpBuffer(&buf,
00750 ",\n pg_catalog.array_to_string(ARRAY(\n"
00751 " SELECT attname || E':\\n ' || pg_catalog.array_to_string(attacl, E'\\n ')\n"
00752 " FROM pg_catalog.pg_attribute a\n"
00753 " WHERE attrelid = c.oid AND NOT attisdropped AND attacl IS NOT NULL\n"
00754 " ), E'\\n') AS \"%s\"",
00755 gettext_noop("Column access privileges"));
00756
00757 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_class c\n"
00758 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
00759 "WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f')\n");
00760
00761
00762
00763
00764
00765
00766
00767 processSQLNamePattern(pset.db, &buf, pattern, true, false,
00768 "n.nspname", "c.relname", NULL,
00769 "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)");
00770
00771 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
00772
00773 res = PSQLexec(buf.data, false);
00774 if (!res)
00775 {
00776 termPQExpBuffer(&buf);
00777 return false;
00778 }
00779
00780 myopt.nullPrint = NULL;
00781 printfPQExpBuffer(&buf, _("Access privileges"));
00782 myopt.title = buf.data;
00783 myopt.translate_header = true;
00784 myopt.translate_columns = translate_columns;
00785
00786 printQuery(res, &myopt, pset.queryFout, pset.logfile);
00787
00788 termPQExpBuffer(&buf);
00789 PQclear(res);
00790 return true;
00791 }
00792
00793
00794
00795
00796
00797
00798
00799 bool
00800 listDefaultACLs(const char *pattern)
00801 {
00802 PQExpBufferData buf;
00803 PGresult *res;
00804 printQueryOpt myopt = pset.popt;
00805 static const bool translate_columns[] = {false, false, true, false};
00806
00807 if (pset.sversion < 90000)
00808 {
00809 psql_error("The server (version %d.%d) does not support altering default privileges.\n",
00810 pset.sversion / 10000, (pset.sversion / 100) % 100);
00811 return true;
00812 }
00813
00814 initPQExpBuffer(&buf);
00815
00816 printfPQExpBuffer(&buf,
00817 "SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
00818 " n.nspname AS \"%s\",\n"
00819 " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
00820 " ",
00821 gettext_noop("Owner"),
00822 gettext_noop("Schema"),
00823 DEFACLOBJ_RELATION,
00824 gettext_noop("table"),
00825 DEFACLOBJ_SEQUENCE,
00826 gettext_noop("sequence"),
00827 DEFACLOBJ_FUNCTION,
00828 gettext_noop("function"),
00829 DEFACLOBJ_TYPE,
00830 gettext_noop("type"),
00831 gettext_noop("Type"));
00832
00833 printACLColumn(&buf, "d.defaclacl");
00834
00835 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
00836 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
00837
00838 processSQLNamePattern(pset.db, &buf, pattern, false, false,
00839 NULL,
00840 "n.nspname",
00841 "pg_catalog.pg_get_userbyid(d.defaclrole)",
00842 NULL);
00843
00844 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
00845
00846 res = PSQLexec(buf.data, false);
00847 if (!res)
00848 {
00849 termPQExpBuffer(&buf);
00850 return false;
00851 }
00852
00853 myopt.nullPrint = NULL;
00854 printfPQExpBuffer(&buf, _("Default access privileges"));
00855 myopt.title = buf.data;
00856 myopt.translate_header = true;
00857 myopt.translate_columns = translate_columns;
00858
00859 printQuery(res, &myopt, pset.queryFout, pset.logfile);
00860
00861 termPQExpBuffer(&buf);
00862 PQclear(res);
00863 return true;
00864 }
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878 bool
00879 objectDescription(const char *pattern, bool showSystem)
00880 {
00881 PQExpBufferData buf;
00882 PGresult *res;
00883 printQueryOpt myopt = pset.popt;
00884 static const bool translate_columns[] = {false, false, true, false};
00885
00886 initPQExpBuffer(&buf);
00887
00888 appendPQExpBuffer(&buf,
00889 "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n"
00890 "FROM (\n",
00891 gettext_noop("Schema"),
00892 gettext_noop("Name"),
00893 gettext_noop("Object"),
00894 gettext_noop("Description"));
00895
00896
00897 appendPQExpBuffer(&buf,
00898 " SELECT pgc.oid as oid, pgc.tableoid AS tableoid,\n"
00899 " n.nspname as nspname,\n"
00900 " CAST(pgc.conname AS pg_catalog.text) as name,"
00901 " CAST('%s' AS pg_catalog.text) as object\n"
00902 " FROM pg_catalog.pg_constraint pgc\n"
00903 " JOIN pg_catalog.pg_class c "
00904 "ON c.oid = pgc.conrelid\n"
00905 " LEFT JOIN pg_catalog.pg_namespace n "
00906 " ON n.oid = c.relnamespace\n",
00907 gettext_noop("constraint"));
00908
00909 if (!showSystem && !pattern)
00910 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
00911 " AND n.nspname <> 'information_schema'\n");
00912
00913 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern,
00914 false, "n.nspname", "pgc.conname", NULL,
00915 "pg_catalog.pg_table_is_visible(c.oid)");
00916
00917
00918
00919
00920 if (pset.sversion >= 80300)
00921 {
00922
00923 appendPQExpBuffer(&buf,
00924 "UNION ALL\n"
00925 " SELECT o.oid as oid, o.tableoid as tableoid,\n"
00926 " n.nspname as nspname,\n"
00927 " CAST(o.opcname AS pg_catalog.text) as name,\n"
00928 " CAST('%s' AS pg_catalog.text) as object\n"
00929 " FROM pg_catalog.pg_opclass o\n"
00930 " JOIN pg_catalog.pg_am am ON "
00931 "o.opcmethod = am.oid\n"
00932 " JOIN pg_catalog.pg_namespace n ON "
00933 "n.oid = o.opcnamespace\n",
00934 gettext_noop("operator class"));
00935
00936 if (!showSystem && !pattern)
00937 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
00938 " AND n.nspname <> 'information_schema'\n");
00939
00940 processSQLNamePattern(pset.db, &buf, pattern, true, false,
00941 "n.nspname", "o.opcname", NULL,
00942 "pg_catalog.pg_opclass_is_visible(o.oid)");
00943 }
00944
00945
00946
00947
00948
00949 if (pset.sversion >= 90200)
00950 {
00951
00952 appendPQExpBuffer(&buf,
00953 "UNION ALL\n"
00954 " SELECT opf.oid as oid, opf.tableoid as tableoid,\n"
00955 " n.nspname as nspname,\n"
00956 " CAST(opf.opfname AS pg_catalog.text) AS name,\n"
00957 " CAST('%s' AS pg_catalog.text) as object\n"
00958 " FROM pg_catalog.pg_opfamily opf\n"
00959 " JOIN pg_catalog.pg_am am "
00960 "ON opf.opfmethod = am.oid\n"
00961 " JOIN pg_catalog.pg_namespace n "
00962 "ON opf.opfnamespace = n.oid\n",
00963 gettext_noop("operator family"));
00964
00965 if (!showSystem && !pattern)
00966 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
00967 " AND n.nspname <> 'information_schema'\n");
00968
00969 processSQLNamePattern(pset.db, &buf, pattern, true, false,
00970 "n.nspname", "opf.opfname", NULL,
00971 "pg_catalog.pg_opfamily_is_visible(opf.oid)");
00972 }
00973
00974
00975 appendPQExpBuffer(&buf,
00976 "UNION ALL\n"
00977 " SELECT r.oid as oid, r.tableoid as tableoid,\n"
00978 " n.nspname as nspname,\n"
00979 " CAST(r.rulename AS pg_catalog.text) as name,"
00980 " CAST('%s' AS pg_catalog.text) as object\n"
00981 " FROM pg_catalog.pg_rewrite r\n"
00982 " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n"
00983 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
00984 " WHERE r.rulename != '_RETURN'\n",
00985 gettext_noop("rule"));
00986
00987 if (!showSystem && !pattern)
00988 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
00989 " AND n.nspname <> 'information_schema'\n");
00990
00991 processSQLNamePattern(pset.db, &buf, pattern, true, false,
00992 "n.nspname", "r.rulename", NULL,
00993 "pg_catalog.pg_table_is_visible(c.oid)");
00994
00995
00996 appendPQExpBuffer(&buf,
00997 "UNION ALL\n"
00998 " SELECT t.oid as oid, t.tableoid as tableoid,\n"
00999 " n.nspname as nspname,\n"
01000 " CAST(t.tgname AS pg_catalog.text) as name,"
01001 " CAST('%s' AS pg_catalog.text) as object\n"
01002 " FROM pg_catalog.pg_trigger t\n"
01003 " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n"
01004 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n",
01005 gettext_noop("trigger"));
01006
01007 if (!showSystem && !pattern)
01008 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
01009 " AND n.nspname <> 'information_schema'\n");
01010
01011 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
01012 "n.nspname", "t.tgname", NULL,
01013 "pg_catalog.pg_table_is_visible(c.oid)");
01014
01015 appendPQExpBuffer(&buf,
01016 ") AS tt\n"
01017 " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n");
01018
01019 appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
01020
01021 res = PSQLexec(buf.data, false);
01022 termPQExpBuffer(&buf);
01023 if (!res)
01024 return false;
01025
01026 myopt.nullPrint = NULL;
01027 myopt.title = _("Object descriptions");
01028 myopt.translate_header = true;
01029 myopt.translate_columns = translate_columns;
01030
01031 printQuery(res, &myopt, pset.queryFout, pset.logfile);
01032
01033 PQclear(res);
01034 return true;
01035 }
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046 bool
01047 describeTableDetails(const char *pattern, bool verbose, bool showSystem)
01048 {
01049 PQExpBufferData buf;
01050 PGresult *res;
01051 int i;
01052
01053 initPQExpBuffer(&buf);
01054
01055 printfPQExpBuffer(&buf,
01056 "SELECT c.oid,\n"
01057 " n.nspname,\n"
01058 " c.relname\n"
01059 "FROM pg_catalog.pg_class c\n"
01060 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n");
01061
01062 if (!showSystem && !pattern)
01063 appendPQExpBuffer(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
01064 " AND n.nspname <> 'information_schema'\n");
01065
01066 processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, false,
01067 "n.nspname", "c.relname", NULL,
01068 "pg_catalog.pg_table_is_visible(c.oid)");
01069
01070 appendPQExpBuffer(&buf, "ORDER BY 2, 3;");
01071
01072 res = PSQLexec(buf.data, false);
01073 termPQExpBuffer(&buf);
01074 if (!res)
01075 return false;
01076
01077 if (PQntuples(res) == 0)
01078 {
01079 if (!pset.quiet)
01080 psql_error("Did not find any relation named \"%s\".\n",
01081 pattern);
01082 PQclear(res);
01083 return false;
01084 }
01085
01086 for (i = 0; i < PQntuples(res); i++)
01087 {
01088 const char *oid;
01089 const char *nspname;
01090 const char *relname;
01091
01092 oid = PQgetvalue(res, i, 0);
01093 nspname = PQgetvalue(res, i, 1);
01094 relname = PQgetvalue(res, i, 2);
01095
01096 if (!describeOneTableDetails(nspname, relname, oid, verbose))
01097 {
01098 PQclear(res);
01099 return false;
01100 }
01101 if (cancel_pressed)
01102 {
01103 PQclear(res);
01104 return false;
01105 }
01106 }
01107
01108 PQclear(res);
01109 return true;
01110 }
01111
01112
01113
01114
01115
01116
01117
01118
01119 static bool
01120 describeOneTableDetails(const char *schemaname,
01121 const char *relationname,
01122 const char *oid,
01123 bool verbose)
01124 {
01125 PQExpBufferData buf;
01126 PGresult *res = NULL;
01127 printTableOpt myopt = pset.popt.topt;
01128 printTableContent cont;
01129 bool printTableInitialized = false;
01130 int i;
01131 char *view_def = NULL;
01132 char *headers[9];
01133 char **seq_values = NULL;
01134 char **modifiers = NULL;
01135 char **ptr;
01136 PQExpBufferData title;
01137 PQExpBufferData tmpbuf;
01138 int cols;
01139 int numrows = 0;
01140 struct
01141 {
01142 int16 checks;
01143 char relkind;
01144 bool hasindex;
01145 bool hasrules;
01146 bool hastriggers;
01147 bool hasoids;
01148 Oid tablespace;
01149 char *reloptions;
01150 char *reloftype;
01151 char relpersistence;
01152 } tableinfo;
01153 bool show_modifiers = false;
01154 bool retval;
01155
01156 retval = false;
01157
01158 myopt.default_footer = false;
01159
01160 myopt.expanded = false;
01161
01162 initPQExpBuffer(&buf);
01163 initPQExpBuffer(&title);
01164 initPQExpBuffer(&tmpbuf);
01165
01166
01167 if (pset.sversion >= 90100)
01168 {
01169 printfPQExpBuffer(&buf,
01170 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
01171 "c.relhastriggers, c.relhasoids, "
01172 "%s, c.reltablespace, "
01173 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
01174 "c.relpersistence\n"
01175 "FROM pg_catalog.pg_class c\n "
01176 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
01177 "WHERE c.oid = '%s';",
01178 (verbose ?
01179 "pg_catalog.array_to_string(c.reloptions || "
01180 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
01181 : "''"),
01182 oid);
01183 }
01184 else if (pset.sversion >= 90000)
01185 {
01186 printfPQExpBuffer(&buf,
01187 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
01188 "c.relhastriggers, c.relhasoids, "
01189 "%s, c.reltablespace, "
01190 "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END\n"
01191 "FROM pg_catalog.pg_class c\n "
01192 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
01193 "WHERE c.oid = '%s';",
01194 (verbose ?
01195 "pg_catalog.array_to_string(c.reloptions || "
01196 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
01197 : "''"),
01198 oid);
01199 }
01200 else if (pset.sversion >= 80400)
01201 {
01202 printfPQExpBuffer(&buf,
01203 "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
01204 "c.relhastriggers, c.relhasoids, "
01205 "%s, c.reltablespace\n"
01206 "FROM pg_catalog.pg_class c\n "
01207 "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
01208 "WHERE c.oid = '%s';",
01209 (verbose ?
01210 "pg_catalog.array_to_string(c.reloptions || "
01211 "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
01212 : "''"),
01213 oid);
01214 }
01215 else if (pset.sversion >= 80200)
01216 {
01217 printfPQExpBuffer(&buf,
01218 "SELECT relchecks, relkind, relhasindex, relhasrules, "
01219 "reltriggers <> 0, relhasoids, "
01220 "%s, reltablespace\n"
01221 "FROM pg_catalog.pg_class WHERE oid = '%s';",
01222 (verbose ?
01223 "pg_catalog.array_to_string(reloptions, E', ')" : "''"),
01224 oid);
01225 }
01226 else if (pset.sversion >= 80000)
01227 {
01228 printfPQExpBuffer(&buf,
01229 "SELECT relchecks, relkind, relhasindex, relhasrules, "
01230 "reltriggers <> 0, relhasoids, "
01231 "'', reltablespace\n"
01232 "FROM pg_catalog.pg_class WHERE oid = '%s';",
01233 oid);
01234 }
01235 else
01236 {
01237 printfPQExpBuffer(&buf,
01238 "SELECT relchecks, relkind, relhasindex, relhasrules, "
01239 "reltriggers <> 0, relhasoids, "
01240 "'', ''\n"
01241 "FROM pg_catalog.pg_class WHERE oid = '%s';",
01242 oid);
01243 }
01244
01245 res = PSQLexec(buf.data, false);
01246 if (!res)
01247 goto error_return;
01248
01249
01250 if (PQntuples(res) == 0)
01251 {
01252 if (!pset.quiet)
01253 psql_error("Did not find any relation with OID %s.\n", oid);
01254 goto error_return;
01255 }
01256
01257 tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
01258 tableinfo.relkind = *(PQgetvalue(res, 0, 1));
01259 tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
01260 tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
01261 tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
01262 tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
01263 tableinfo.reloptions = (pset.sversion >= 80200) ?
01264 pg_strdup(PQgetvalue(res, 0, 6)) : NULL;
01265 tableinfo.tablespace = (pset.sversion >= 80000) ?
01266 atooid(PQgetvalue(res, 0, 7)) : 0;
01267 tableinfo.reloftype = (pset.sversion >= 90000 &&
01268 strcmp(PQgetvalue(res, 0, 8), "") != 0) ?
01269 pg_strdup(PQgetvalue(res, 0, 8)) : NULL;
01270 tableinfo.relpersistence = (pset.sversion >= 90100) ?
01271 *(PQgetvalue(res, 0, 9)) : 0;
01272 PQclear(res);
01273 res = NULL;
01274
01275
01276
01277
01278
01279 if (tableinfo.relkind == 'S')
01280 {
01281 printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
01282
01283 appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
01284
01285 res = PSQLexec(buf.data, false);
01286 if (!res)
01287 goto error_return;
01288
01289 seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
01290
01291 for (i = 0; i < PQnfields(res); i++)
01292 seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
01293 seq_values[i] = NULL;
01294
01295 PQclear(res);
01296 res = NULL;
01297 }
01298
01299
01300
01301
01302
01303
01304
01305 printfPQExpBuffer(&buf, "SELECT a.attname,");
01306 appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod),"
01307 "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
01308 "\n FROM pg_catalog.pg_attrdef d"
01309 "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
01310 "\n a.attnotnull, a.attnum,");
01311 if (pset.sversion >= 90100)
01312 appendPQExpBuffer(&buf, "\n (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t\n"
01313 " WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation");
01314 else
01315 appendPQExpBuffer(&buf, "\n NULL AS attcollation");
01316 if (tableinfo.relkind == 'i')
01317 appendPQExpBuffer(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
01318 else
01319 appendPQExpBuffer(&buf, ",\n NULL AS indexdef");
01320 if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
01321 appendPQExpBuffer(&buf, ",\n CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
01322 " '(' || array_to_string(ARRAY(SELECT quote_ident(option_name) || ' ' || quote_literal(option_value) FROM "
01323 " pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
01324 else
01325 appendPQExpBuffer(&buf, ",\n NULL AS attfdwoptions");
01326 if (verbose)
01327 {
01328 appendPQExpBuffer(&buf, ",\n a.attstorage");
01329 appendPQExpBuffer(&buf, ",\n CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
01330
01331
01332
01333
01334
01335 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
01336 tableinfo.relkind == 'm' ||
01337 tableinfo.relkind == 'f' || tableinfo.relkind == 'c')
01338 appendPQExpBuffer(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)");
01339 }
01340
01341 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_attribute a");
01342 appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
01343 appendPQExpBuffer(&buf, "\nORDER BY a.attnum;");
01344
01345 res = PSQLexec(buf.data, false);
01346 if (!res)
01347 goto error_return;
01348 numrows = PQntuples(res);
01349
01350
01351 switch (tableinfo.relkind)
01352 {
01353 case 'r':
01354 if (tableinfo.relpersistence == 'u')
01355 printfPQExpBuffer(&title, _("Unlogged table \"%s.%s\""),
01356 schemaname, relationname);
01357 else
01358 printfPQExpBuffer(&title, _("Table \"%s.%s\""),
01359 schemaname, relationname);
01360 break;
01361 case 'v':
01362 printfPQExpBuffer(&title, _("View \"%s.%s\""),
01363 schemaname, relationname);
01364 break;
01365 case 'm':
01366 if (tableinfo.relpersistence == 'u')
01367 printfPQExpBuffer(&title, _("Unlogged materialized view \"%s.%s\""),
01368 schemaname, relationname);
01369 else
01370 printfPQExpBuffer(&title, _("Materialized view \"%s.%s\""),
01371 schemaname, relationname);
01372 break;
01373 case 'S':
01374 printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
01375 schemaname, relationname);
01376 break;
01377 case 'i':
01378 if (tableinfo.relpersistence == 'u')
01379 printfPQExpBuffer(&title, _("Unlogged index \"%s.%s\""),
01380 schemaname, relationname);
01381 else
01382 printfPQExpBuffer(&title, _("Index \"%s.%s\""),
01383 schemaname, relationname);
01384 break;
01385 case 's':
01386
01387 printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
01388 schemaname, relationname);
01389 break;
01390 case 't':
01391 printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
01392 schemaname, relationname);
01393 break;
01394 case 'c':
01395 printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
01396 schemaname, relationname);
01397 break;
01398 case 'f':
01399 printfPQExpBuffer(&title, _("Foreign table \"%s.%s\""),
01400 schemaname, relationname);
01401 break;
01402 default:
01403
01404 printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
01405 tableinfo.relkind, schemaname, relationname);
01406 break;
01407 }
01408
01409
01410 headers[0] = gettext_noop("Column");
01411 headers[1] = gettext_noop("Type");
01412 cols = 2;
01413
01414 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
01415 tableinfo.relkind == 'm' ||
01416 tableinfo.relkind == 'f' || tableinfo.relkind == 'c')
01417 {
01418 show_modifiers = true;
01419 headers[cols++] = gettext_noop("Modifiers");
01420 modifiers = pg_malloc0((numrows + 1) * sizeof(*modifiers));
01421 }
01422
01423 if (tableinfo.relkind == 'S')
01424 headers[cols++] = gettext_noop("Value");
01425
01426 if (tableinfo.relkind == 'i')
01427 headers[cols++] = gettext_noop("Definition");
01428
01429 if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
01430 headers[cols++] = gettext_noop("FDW Options");
01431
01432 if (verbose)
01433 {
01434 headers[cols++] = gettext_noop("Storage");
01435 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
01436 tableinfo.relkind == 'f')
01437 headers[cols++] = gettext_noop("Stats target");
01438
01439 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
01440 tableinfo.relkind == 'm' ||
01441 tableinfo.relkind == 'c' || tableinfo.relkind == 'f')
01442 headers[cols++] = gettext_noop("Description");
01443 }
01444
01445 printTableInit(&cont, &myopt, title.data, cols, numrows);
01446 printTableInitialized = true;
01447
01448 for (i = 0; i < cols; i++)
01449 printTableAddHeader(&cont, headers[i], true, 'l');
01450
01451
01452 if ((tableinfo.relkind == 'v' || tableinfo.relkind == 'm') && verbose)
01453 {
01454 PGresult *result;
01455
01456 printfPQExpBuffer(&buf,
01457 "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
01458 oid);
01459 result = PSQLexec(buf.data, false);
01460 if (!result)
01461 goto error_return;
01462
01463 if (PQntuples(result) > 0)
01464 view_def = pg_strdup(PQgetvalue(result, 0, 0));
01465
01466 PQclear(result);
01467 }
01468
01469
01470 for (i = 0; i < numrows; i++)
01471 {
01472
01473 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
01474
01475
01476 printTableAddCell(&cont, PQgetvalue(res, i, 1), false, false);
01477
01478
01479 if (show_modifiers)
01480 {
01481 resetPQExpBuffer(&tmpbuf);
01482
01483 if (!PQgetisnull(res, i, 5))
01484 {
01485 if (tmpbuf.len > 0)
01486 appendPQExpBufferStr(&tmpbuf, " ");
01487 appendPQExpBuffer(&tmpbuf, _("collate %s"),
01488 PQgetvalue(res, i, 5));
01489 }
01490
01491 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
01492 {
01493 if (tmpbuf.len > 0)
01494 appendPQExpBufferStr(&tmpbuf, " ");
01495 appendPQExpBufferStr(&tmpbuf, _("not null"));
01496 }
01497
01498
01499
01500 if (strlen(PQgetvalue(res, i, 2)) != 0)
01501 {
01502 if (tmpbuf.len > 0)
01503 appendPQExpBufferStr(&tmpbuf, " ");
01504
01505 appendPQExpBuffer(&tmpbuf, _("default %s"),
01506 PQgetvalue(res, i, 2));
01507 }
01508
01509 modifiers[i] = pg_strdup(tmpbuf.data);
01510 printTableAddCell(&cont, modifiers[i], false, false);
01511 }
01512
01513
01514 if (tableinfo.relkind == 'S')
01515 printTableAddCell(&cont, seq_values[i], false, false);
01516
01517
01518 if (tableinfo.relkind == 'i')
01519 printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
01520
01521
01522 if (tableinfo.relkind == 'f' && pset.sversion >= 90200)
01523 printTableAddCell(&cont, PQgetvalue(res, i, 7), false, false);
01524
01525
01526 if (verbose)
01527 {
01528 int firstvcol = 8;
01529 char *storage = PQgetvalue(res, i, firstvcol);
01530
01531
01532 printTableAddCell(&cont, (storage[0] == 'p' ? "plain" :
01533 (storage[0] == 'm' ? "main" :
01534 (storage[0] == 'x' ? "extended" :
01535 (storage[0] == 'e' ? "external" :
01536 "???")))),
01537 false, false);
01538
01539
01540 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
01541 tableinfo.relkind == 'f')
01542 {
01543 printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 1),
01544 false, false);
01545 }
01546
01547
01548 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v' ||
01549 tableinfo.relkind == 'm' ||
01550 tableinfo.relkind == 'c' || tableinfo.relkind == 'f')
01551 printTableAddCell(&cont, PQgetvalue(res, i, firstvcol + 2),
01552 false, false);
01553 }
01554 }
01555
01556
01557 if (tableinfo.relkind == 'i')
01558 {
01559
01560 PGresult *result;
01561
01562 printfPQExpBuffer(&buf,
01563 "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
01564 if (pset.sversion >= 80200)
01565 appendPQExpBuffer(&buf, "i.indisvalid,\n");
01566 else
01567 appendPQExpBuffer(&buf, "true AS indisvalid,\n");
01568 if (pset.sversion >= 90000)
01569 appendPQExpBuffer(&buf,
01570 " (NOT i.indimmediate) AND "
01571 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
01572 "WHERE conrelid = i.indrelid AND "
01573 "conindid = i.indexrelid AND "
01574 "contype IN ('p','u','x') AND "
01575 "condeferrable) AS condeferrable,\n"
01576 " (NOT i.indimmediate) AND "
01577 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
01578 "WHERE conrelid = i.indrelid AND "
01579 "conindid = i.indexrelid AND "
01580 "contype IN ('p','u','x') AND "
01581 "condeferred) AS condeferred,\n");
01582 else
01583 appendPQExpBuffer(&buf,
01584 " false AS condeferrable, false AS condeferred,\n");
01585 appendPQExpBuffer(&buf, " a.amname, c2.relname, "
01586 "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
01587 "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
01588 "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
01589 "AND i.indrelid = c2.oid;",
01590 oid);
01591
01592 result = PSQLexec(buf.data, false);
01593 if (!result)
01594 goto error_return;
01595 else if (PQntuples(result) != 1)
01596 {
01597 PQclear(result);
01598 goto error_return;
01599 }
01600 else
01601 {
01602 char *indisunique = PQgetvalue(result, 0, 0);
01603 char *indisprimary = PQgetvalue(result, 0, 1);
01604 char *indisclustered = PQgetvalue(result, 0, 2);
01605 char *indisvalid = PQgetvalue(result, 0, 3);
01606 char *deferrable = PQgetvalue(result, 0, 4);
01607 char *deferred = PQgetvalue(result, 0, 5);
01608 char *indamname = PQgetvalue(result, 0, 6);
01609 char *indtable = PQgetvalue(result, 0, 7);
01610 char *indpred = PQgetvalue(result, 0, 8);
01611
01612 if (strcmp(indisprimary, "t") == 0)
01613 printfPQExpBuffer(&tmpbuf, _("primary key, "));
01614 else if (strcmp(indisunique, "t") == 0)
01615 printfPQExpBuffer(&tmpbuf, _("unique, "));
01616 else
01617 resetPQExpBuffer(&tmpbuf);
01618 appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
01619
01620
01621 appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
01622 schemaname, indtable);
01623
01624 if (strlen(indpred))
01625 appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
01626
01627 if (strcmp(indisclustered, "t") == 0)
01628 appendPQExpBuffer(&tmpbuf, _(", clustered"));
01629
01630 if (strcmp(indisvalid, "t") != 0)
01631 appendPQExpBuffer(&tmpbuf, _(", invalid"));
01632
01633 if (strcmp(deferrable, "t") == 0)
01634 appendPQExpBuffer(&tmpbuf, _(", deferrable"));
01635
01636 if (strcmp(deferred, "t") == 0)
01637 appendPQExpBuffer(&tmpbuf, _(", initially deferred"));
01638
01639 printTableAddFooter(&cont, tmpbuf.data);
01640 add_tablespace_footer(&cont, tableinfo.relkind,
01641 tableinfo.tablespace, true);
01642 }
01643
01644 PQclear(result);
01645 }
01646 else if (tableinfo.relkind == 'S')
01647 {
01648
01649 PGresult *result = NULL;
01650
01651
01652 printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
01653 "\n pg_catalog.quote_ident(relname) || '.' ||"
01654 "\n pg_catalog.quote_ident(attname)"
01655 "\nFROM pg_catalog.pg_class c"
01656 "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
01657 "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
01658 "\nINNER JOIN pg_catalog.pg_attribute a ON ("
01659 "\n a.attrelid=c.oid AND"
01660 "\n a.attnum=d.refobjsubid)"
01661 "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
01662 "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
01663 "\n AND d.objid=%s"
01664 "\n AND d.deptype='a'",
01665 oid);
01666
01667 result = PSQLexec(buf.data, false);
01668 if (!result)
01669 goto error_return;
01670 else if (PQntuples(result) == 1)
01671 {
01672 printfPQExpBuffer(&buf, _("Owned by: %s"),
01673 PQgetvalue(result, 0, 0));
01674 printTableAddFooter(&cont, buf.data);
01675 }
01676
01677
01678
01679
01680
01681
01682 PQclear(result);
01683 }
01684 else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
01685 tableinfo.relkind == 'f')
01686 {
01687
01688 PGresult *result = NULL;
01689 int tuples = 0;
01690
01691
01692 if (tableinfo.hasindex)
01693 {
01694 printfPQExpBuffer(&buf,
01695 "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
01696 if (pset.sversion >= 80200)
01697 appendPQExpBuffer(&buf, "i.indisvalid, ");
01698 else
01699 appendPQExpBuffer(&buf, "true as indisvalid, ");
01700 appendPQExpBuffer(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n ");
01701 if (pset.sversion >= 90000)
01702 appendPQExpBuffer(&buf,
01703 "pg_catalog.pg_get_constraintdef(con.oid, true), "
01704 "contype, condeferrable, condeferred");
01705 else
01706 appendPQExpBuffer(&buf,
01707 "null AS constraintdef, null AS contype, "
01708 "false AS condeferrable, false AS condeferred");
01709 if (pset.sversion >= 80000)
01710 appendPQExpBuffer(&buf, ", c2.reltablespace");
01711 appendPQExpBuffer(&buf,
01712 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
01713 if (pset.sversion >= 90000)
01714 appendPQExpBuffer(&buf,
01715 " LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
01716 appendPQExpBuffer(&buf,
01717 "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
01718 "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname;",
01719 oid);
01720 result = PSQLexec(buf.data, false);
01721 if (!result)
01722 goto error_return;
01723 else
01724 tuples = PQntuples(result);
01725
01726 if (tuples > 0)
01727 {
01728 printTableAddFooter(&cont, _("Indexes:"));
01729 for (i = 0; i < tuples; i++)
01730 {
01731
01732 printfPQExpBuffer(&buf, " \"%s\"",
01733 PQgetvalue(result, i, 0));
01734
01735
01736 if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
01737 {
01738 appendPQExpBuffer(&buf, " %s",
01739 PQgetvalue(result, i, 6));
01740 }
01741 else
01742 {
01743 const char *indexdef;
01744 const char *usingpos;
01745
01746
01747 if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
01748 appendPQExpBuffer(&buf, " PRIMARY KEY,");
01749 else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
01750 {
01751 if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
01752 appendPQExpBuffer(&buf, " UNIQUE CONSTRAINT,");
01753 else
01754 appendPQExpBuffer(&buf, " UNIQUE,");
01755 }
01756
01757
01758 indexdef = PQgetvalue(result, i, 5);
01759 usingpos = strstr(indexdef, " USING ");
01760 if (usingpos)
01761 indexdef = usingpos + 7;
01762 appendPQExpBuffer(&buf, " %s", indexdef);
01763
01764
01765 if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
01766 appendPQExpBuffer(&buf, " DEFERRABLE");
01767
01768 if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
01769 appendPQExpBuffer(&buf, " INITIALLY DEFERRED");
01770 }
01771
01772
01773 if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
01774 appendPQExpBuffer(&buf, " CLUSTER");
01775
01776 if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
01777 appendPQExpBuffer(&buf, " INVALID");
01778
01779 printTableAddFooter(&cont, buf.data);
01780
01781
01782 if (pset.sversion >= 80000)
01783 add_tablespace_footer(&cont, 'i',
01784 atooid(PQgetvalue(result, i, 10)),
01785 false);
01786 }
01787 }
01788 PQclear(result);
01789 }
01790
01791
01792 if (tableinfo.checks)
01793 {
01794 printfPQExpBuffer(&buf,
01795 "SELECT r.conname, "
01796 "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
01797 "FROM pg_catalog.pg_constraint r\n"
01798 "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
01799 "ORDER BY 1;",
01800 oid);
01801 result = PSQLexec(buf.data, false);
01802 if (!result)
01803 goto error_return;
01804 else
01805 tuples = PQntuples(result);
01806
01807 if (tuples > 0)
01808 {
01809 printTableAddFooter(&cont, _("Check constraints:"));
01810 for (i = 0; i < tuples; i++)
01811 {
01812
01813 printfPQExpBuffer(&buf, " \"%s\" %s",
01814 PQgetvalue(result, i, 0),
01815 PQgetvalue(result, i, 1));
01816
01817 printTableAddFooter(&cont, buf.data);
01818 }
01819 }
01820 PQclear(result);
01821 }
01822
01823
01824 if (tableinfo.hastriggers)
01825 {
01826 printfPQExpBuffer(&buf,
01827 "SELECT conname,\n"
01828 " pg_catalog.pg_get_constraintdef(r.oid, true) as condef\n"
01829 "FROM pg_catalog.pg_constraint r\n"
01830 "WHERE r.conrelid = '%s' AND r.contype = 'f' ORDER BY 1;",
01831 oid);
01832 result = PSQLexec(buf.data, false);
01833 if (!result)
01834 goto error_return;
01835 else
01836 tuples = PQntuples(result);
01837
01838 if (tuples > 0)
01839 {
01840 printTableAddFooter(&cont, _("Foreign-key constraints:"));
01841 for (i = 0; i < tuples; i++)
01842 {
01843
01844 printfPQExpBuffer(&buf, " \"%s\" %s",
01845 PQgetvalue(result, i, 0),
01846 PQgetvalue(result, i, 1));
01847
01848 printTableAddFooter(&cont, buf.data);
01849 }
01850 }
01851 PQclear(result);
01852 }
01853
01854
01855 if (tableinfo.hastriggers)
01856 {
01857 printfPQExpBuffer(&buf,
01858 "SELECT conname, conrelid::pg_catalog.regclass,\n"
01859 " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n"
01860 "FROM pg_catalog.pg_constraint c\n"
01861 "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1;",
01862 oid);
01863 result = PSQLexec(buf.data, false);
01864 if (!result)
01865 goto error_return;
01866 else
01867 tuples = PQntuples(result);
01868
01869 if (tuples > 0)
01870 {
01871 printTableAddFooter(&cont, _("Referenced by:"));
01872 for (i = 0; i < tuples; i++)
01873 {
01874 printfPQExpBuffer(&buf, " TABLE \"%s\" CONSTRAINT \"%s\" %s",
01875 PQgetvalue(result, i, 1),
01876 PQgetvalue(result, i, 0),
01877 PQgetvalue(result, i, 2));
01878
01879 printTableAddFooter(&cont, buf.data);
01880 }
01881 }
01882 PQclear(result);
01883 }
01884
01885
01886 if (tableinfo.hasrules && tableinfo.relkind != 'm')
01887 {
01888 if (pset.sversion >= 80300)
01889 {
01890 printfPQExpBuffer(&buf,
01891 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
01892 "ev_enabled\n"
01893 "FROM pg_catalog.pg_rewrite r\n"
01894 "WHERE r.ev_class = '%s' ORDER BY 1;",
01895 oid);
01896 }
01897 else
01898 {
01899 printfPQExpBuffer(&buf,
01900 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
01901 "'O'::char AS ev_enabled\n"
01902 "FROM pg_catalog.pg_rewrite r\n"
01903 "WHERE r.ev_class = '%s' ORDER BY 1;",
01904 oid);
01905 }
01906 result = PSQLexec(buf.data, false);
01907 if (!result)
01908 goto error_return;
01909 else
01910 tuples = PQntuples(result);
01911
01912 if (tuples > 0)
01913 {
01914 bool have_heading;
01915 int category;
01916
01917 for (category = 0; category < 4; category++)
01918 {
01919 have_heading = false;
01920
01921 for (i = 0; i < tuples; i++)
01922 {
01923 const char *ruledef;
01924 bool list_rule = false;
01925
01926 switch (category)
01927 {
01928 case 0:
01929 if (*PQgetvalue(result, i, 2) == 'O')
01930 list_rule = true;
01931 break;
01932 case 1:
01933 if (*PQgetvalue(result, i, 2) == 'D')
01934 list_rule = true;
01935 break;
01936 case 2:
01937 if (*PQgetvalue(result, i, 2) == 'A')
01938 list_rule = true;
01939 break;
01940 case 3:
01941 if (*PQgetvalue(result, i, 2) == 'R')
01942 list_rule = true;
01943 break;
01944 }
01945 if (!list_rule)
01946 continue;
01947
01948 if (!have_heading)
01949 {
01950 switch (category)
01951 {
01952 case 0:
01953 printfPQExpBuffer(&buf, _("Rules:"));
01954 break;
01955 case 1:
01956 printfPQExpBuffer(&buf, _("Disabled rules:"));
01957 break;
01958 case 2:
01959 printfPQExpBuffer(&buf, _("Rules firing always:"));
01960 break;
01961 case 3:
01962 printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
01963 break;
01964 }
01965 printTableAddFooter(&cont, buf.data);
01966 have_heading = true;
01967 }
01968
01969
01970 ruledef = PQgetvalue(result, i, 1);
01971 ruledef += 12;
01972 printfPQExpBuffer(&buf, " %s", ruledef);
01973 printTableAddFooter(&cont, buf.data);
01974 }
01975 }
01976 }
01977 PQclear(result);
01978 }
01979 }
01980
01981 if (view_def)
01982 {
01983 PGresult *result = NULL;
01984
01985
01986 printTableAddFooter(&cont, _("View definition:"));
01987 printTableAddFooter(&cont, view_def);
01988
01989
01990 if (tableinfo.hasrules)
01991 {
01992 printfPQExpBuffer(&buf,
01993 "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n"
01994 "FROM pg_catalog.pg_rewrite r\n"
01995 "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1;",
01996 oid);
01997 result = PSQLexec(buf.data, false);
01998 if (!result)
01999 goto error_return;
02000
02001 if (PQntuples(result) > 0)
02002 {
02003 printTableAddFooter(&cont, _("Rules:"));
02004 for (i = 0; i < PQntuples(result); i++)
02005 {
02006 const char *ruledef;
02007
02008
02009 ruledef = PQgetvalue(result, i, 1);
02010 ruledef += 12;
02011
02012 printfPQExpBuffer(&buf, " %s", ruledef);
02013 printTableAddFooter(&cont, buf.data);
02014 }
02015 }
02016 PQclear(result);
02017 }
02018 }
02019
02020
02021
02022
02023
02024 if (tableinfo.hastriggers)
02025 {
02026 PGresult *result;
02027 int tuples;
02028
02029 printfPQExpBuffer(&buf,
02030 "SELECT t.tgname, "
02031 "pg_catalog.pg_get_triggerdef(t.oid%s), "
02032 "t.tgenabled\n"
02033 "FROM pg_catalog.pg_trigger t\n"
02034 "WHERE t.tgrelid = '%s' AND ",
02035 (pset.sversion >= 90000 ? ", true" : ""),
02036 oid);
02037 if (pset.sversion >= 90000)
02038 appendPQExpBuffer(&buf, "NOT t.tgisinternal");
02039 else if (pset.sversion >= 80300)
02040 appendPQExpBuffer(&buf, "t.tgconstraint = 0");
02041 else
02042 appendPQExpBuffer(&buf,
02043 "(NOT tgisconstraint "
02044 " OR NOT EXISTS"
02045 " (SELECT 1 FROM pg_catalog.pg_depend d "
02046 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
02047 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))");
02048 appendPQExpBuffer(&buf, "\nORDER BY 1;");
02049
02050 result = PSQLexec(buf.data, false);
02051 if (!result)
02052 goto error_return;
02053 else
02054 tuples = PQntuples(result);
02055
02056 if (tuples > 0)
02057 {
02058 bool have_heading;
02059 int category;
02060
02061
02062
02063
02064
02065
02066 for (category = 0; category < 4; category++)
02067 {
02068 have_heading = false;
02069 for (i = 0; i < tuples; i++)
02070 {
02071 bool list_trigger;
02072 const char *tgdef;
02073 const char *usingpos;
02074 const char *tgenabled;
02075
02076
02077
02078
02079 tgenabled = PQgetvalue(result, i, 2);
02080 list_trigger = false;
02081 switch (category)
02082 {
02083 case 0:
02084 if (*tgenabled == 'O' || *tgenabled == 't')
02085 list_trigger = true;
02086 break;
02087 case 1:
02088 if (*tgenabled == 'D' || *tgenabled == 'f')
02089 list_trigger = true;
02090 break;
02091 case 2:
02092 if (*tgenabled == 'A')
02093 list_trigger = true;
02094 break;
02095 case 3:
02096 if (*tgenabled == 'R')
02097 list_trigger = true;
02098 break;
02099 }
02100 if (list_trigger == false)
02101 continue;
02102
02103
02104 if (have_heading == false)
02105 {
02106 switch (category)
02107 {
02108 case 0:
02109 printfPQExpBuffer(&buf, _("Triggers:"));
02110 break;
02111 case 1:
02112 printfPQExpBuffer(&buf, _("Disabled triggers:"));
02113 break;
02114 case 2:
02115 printfPQExpBuffer(&buf, _("Triggers firing always:"));
02116 break;
02117 case 3:
02118 printfPQExpBuffer(&buf, _("Triggers firing on replica only:"));
02119 break;
02120
02121 }
02122 printTableAddFooter(&cont, buf.data);
02123 have_heading = true;
02124 }
02125
02126
02127 tgdef = PQgetvalue(result, i, 1);
02128 usingpos = strstr(tgdef, " TRIGGER ");
02129 if (usingpos)
02130 tgdef = usingpos + 9;
02131
02132 printfPQExpBuffer(&buf, " %s", tgdef);
02133 printTableAddFooter(&cont, buf.data);
02134 }
02135 }
02136 }
02137 PQclear(result);
02138 }
02139
02140
02141
02142
02143 if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
02144 tableinfo.relkind == 'f')
02145 {
02146 PGresult *result;
02147 int tuples;
02148
02149
02150 if (tableinfo.relkind == 'f')
02151 {
02152 char *ftoptions;
02153
02154
02155 printfPQExpBuffer(&buf,
02156 "SELECT s.srvname,\n"
02157 " array_to_string(ARRAY(SELECT "
02158 " quote_ident(option_name) || ' ' || "
02159 " quote_literal(option_value) FROM "
02160 " pg_options_to_table(ftoptions)), ', ') "
02161 "FROM pg_catalog.pg_foreign_table f,\n"
02162 " pg_catalog.pg_foreign_server s\n"
02163 "WHERE f.ftrelid = %s AND s.oid = f.ftserver;",
02164 oid);
02165 result = PSQLexec(buf.data, false);
02166 if (!result)
02167 goto error_return;
02168 else if (PQntuples(result) != 1)
02169 {
02170 PQclear(result);
02171 goto error_return;
02172 }
02173
02174
02175 printfPQExpBuffer(&buf, "Server: %s",
02176 PQgetvalue(result, 0, 0));
02177 printTableAddFooter(&cont, buf.data);
02178
02179
02180 ftoptions = PQgetvalue(result, 0, 1);
02181 if (ftoptions && ftoptions[0] != '\0')
02182 {
02183 printfPQExpBuffer(&buf, "FDW Options: (%s)", ftoptions);
02184 printTableAddFooter(&cont, buf.data);
02185 }
02186 PQclear(result);
02187 }
02188
02189
02190 printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhparent AND i.inhrelid = '%s' ORDER BY inhseqno;", oid);
02191
02192 result = PSQLexec(buf.data, false);
02193 if (!result)
02194 goto error_return;
02195 else
02196 {
02197 const char *s = _("Inherits");
02198 int sw = pg_wcswidth(s, strlen(s), pset.encoding);
02199
02200 tuples = PQntuples(result);
02201
02202 for (i = 0; i < tuples; i++)
02203 {
02204 if (i == 0)
02205 printfPQExpBuffer(&buf, "%s: %s",
02206 s, PQgetvalue(result, i, 0));
02207 else
02208 printfPQExpBuffer(&buf, "%*s %s",
02209 sw, "", PQgetvalue(result, i, 0));
02210 if (i < tuples - 1)
02211 appendPQExpBuffer(&buf, ",");
02212
02213 printTableAddFooter(&cont, buf.data);
02214 }
02215
02216 PQclear(result);
02217 }
02218
02219
02220 if (pset.sversion >= 80300)
02221 printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid);
02222 else
02223 printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.relname;", oid);
02224
02225 result = PSQLexec(buf.data, false);
02226 if (!result)
02227 goto error_return;
02228 else
02229 tuples = PQntuples(result);
02230
02231 if (!verbose)
02232 {
02233
02234 if (tuples > 0)
02235 {
02236 printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
02237 printTableAddFooter(&cont, buf.data);
02238 }
02239 }
02240 else
02241 {
02242
02243 const char *ct = _("Child tables");
02244 int ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
02245
02246 for (i = 0; i < tuples; i++)
02247 {
02248 if (i == 0)
02249 printfPQExpBuffer(&buf, "%s: %s",
02250 ct, PQgetvalue(result, i, 0));
02251 else
02252 printfPQExpBuffer(&buf, "%*s %s",
02253 ctw, "", PQgetvalue(result, i, 0));
02254 if (i < tuples - 1)
02255 appendPQExpBuffer(&buf, ",");
02256
02257 printTableAddFooter(&cont, buf.data);
02258 }
02259 }
02260 PQclear(result);
02261
02262
02263 if (tableinfo.reloftype)
02264 {
02265 printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
02266 printTableAddFooter(&cont, buf.data);
02267 }
02268
02269
02270 if (verbose && tableinfo.relkind != 'm')
02271 {
02272 const char *s = _("Has OIDs");
02273
02274 printfPQExpBuffer(&buf, "%s: %s", s,
02275 (tableinfo.hasoids ? _("yes") : _("no")));
02276 printTableAddFooter(&cont, buf.data);
02277 }
02278
02279
02280 add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
02281 true);
02282 }
02283
02284
02285 if (verbose &&
02286 tableinfo.reloptions && tableinfo.reloptions[0] != '\0')
02287 {
02288 const char *t = _("Options");
02289
02290 printfPQExpBuffer(&buf, "%s: %s", t, tableinfo.reloptions);
02291 printTableAddFooter(&cont, buf.data);
02292 }
02293
02294 printTable(&cont, pset.queryFout, pset.logfile);
02295 printTableCleanup(&cont);
02296
02297 retval = true;
02298
02299 error_return:
02300
02301
02302 if (printTableInitialized)
02303 printTableCleanup(&cont);
02304 termPQExpBuffer(&buf);
02305 termPQExpBuffer(&title);
02306 termPQExpBuffer(&tmpbuf);
02307
02308 if (seq_values)
02309 {
02310 for (ptr = seq_values; *ptr; ptr++)
02311 free(*ptr);
02312 free(seq_values);
02313 }
02314
02315 if (modifiers)
02316 {
02317 for (ptr = modifiers; *ptr; ptr++)
02318 free(*ptr);
02319 free(modifiers);
02320 }
02321
02322 if (view_def)
02323 free(view_def);
02324
02325 if (res)
02326 PQclear(res);
02327
02328 return retval;
02329 }
02330
02331
02332
02333
02334
02335
02336 static void
02337 add_tablespace_footer(printTableContent *const cont, char relkind,
02338 Oid tablespace, const bool newline)
02339 {
02340
02341 if (relkind == 'r' || relkind == 'm' || relkind == 'i')
02342 {
02343
02344
02345
02346
02347
02348 if (tablespace != 0)
02349 {
02350 PGresult *result = NULL;
02351 PQExpBufferData buf;
02352
02353 initPQExpBuffer(&buf);
02354 printfPQExpBuffer(&buf,
02355 "SELECT spcname FROM pg_catalog.pg_tablespace\n"
02356 "WHERE oid = '%u';", tablespace);
02357 result = PSQLexec(buf.data, false);
02358 if (!result)
02359 return;
02360
02361 if (PQntuples(result) > 0)
02362 {
02363 if (newline)
02364 {
02365
02366 printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
02367 PQgetvalue(result, 0, 0));
02368 printTableAddFooter(cont, buf.data);
02369 }
02370 else
02371 {
02372
02373 printfPQExpBuffer(&buf, "%s", cont->footer->data);
02374
02375
02376
02377
02378
02379 appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
02380 PQgetvalue(result, 0, 0));
02381 printTableSetFooter(cont, buf.data);
02382 }
02383 }
02384 PQclear(result);
02385 termPQExpBuffer(&buf);
02386 }
02387 }
02388 }
02389
02390
02391
02392
02393
02394
02395 bool
02396 describeRoles(const char *pattern, bool verbose)
02397 {
02398 PQExpBufferData buf;
02399 PGresult *res;
02400 printTableContent cont;
02401 printTableOpt myopt = pset.popt.topt;
02402 int ncols = 3;
02403 int nrows = 0;
02404 int i;
02405 int conns;
02406 const char align = 'l';
02407 char **attr;
02408
02409 myopt.default_footer = false;
02410
02411 initPQExpBuffer(&buf);
02412
02413 if (pset.sversion >= 80100)
02414 {
02415 printfPQExpBuffer(&buf,
02416 "SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
02417 " r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
02418 " r.rolconnlimit, r.rolvaliduntil,\n"
02419 " ARRAY(SELECT b.rolname\n"
02420 " FROM pg_catalog.pg_auth_members m\n"
02421 " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
02422 " WHERE m.member = r.oid) as memberof");
02423
02424 if (verbose && pset.sversion >= 80200)
02425 {
02426 appendPQExpBufferStr(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description");
02427 ncols++;
02428 }
02429 if (pset.sversion >= 90100)
02430 {
02431 appendPQExpBufferStr(&buf, "\n, r.rolreplication");
02432 }
02433
02434 appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_roles r\n");
02435
02436 processSQLNamePattern(pset.db, &buf, pattern, false, false,
02437 NULL, "r.rolname", NULL, NULL);
02438 }
02439 else
02440 {
02441 printfPQExpBuffer(&buf,
02442 "SELECT u.usename AS rolname,\n"
02443 " u.usesuper AS rolsuper,\n"
02444 " true AS rolinherit, false AS rolcreaterole,\n"
02445 " u.usecreatedb AS rolcreatedb, true AS rolcanlogin,\n"
02446 " -1 AS rolconnlimit,"
02447 " u.valuntil as rolvaliduntil,\n"
02448 " ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as memberof"
02449 "\nFROM pg_catalog.pg_user u\n");
02450
02451 processSQLNamePattern(pset.db, &buf, pattern, false, false,
02452 NULL, "u.usename", NULL, NULL);
02453 }
02454
02455 appendPQExpBuffer(&buf, "ORDER BY 1;");
02456
02457 res = PSQLexec(buf.data, false);
02458 if (!res)
02459 return false;
02460
02461 nrows = PQntuples(res);
02462 attr = pg_malloc0((nrows + 1) * sizeof(*attr));
02463
02464 printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
02465
02466 printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
02467 printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
02468 printTableAddHeader(&cont, gettext_noop("Member of"), true, align);
02469
02470 if (verbose && pset.sversion >= 80200)
02471 printTableAddHeader(&cont, gettext_noop("Description"), true, align);
02472
02473 for (i = 0; i < nrows; i++)
02474 {
02475 printTableAddCell(&cont, PQgetvalue(res, i, 0), false, false);
02476
02477 resetPQExpBuffer(&buf);
02478 if (strcmp(PQgetvalue(res, i, 1), "t") == 0)
02479 add_role_attribute(&buf, _("Superuser"));
02480
02481 if (strcmp(PQgetvalue(res, i, 2), "t") != 0)
02482 add_role_attribute(&buf, _("No inheritance"));
02483
02484 if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
02485 add_role_attribute(&buf, _("Create role"));
02486
02487 if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
02488 add_role_attribute(&buf, _("Create DB"));
02489
02490 if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
02491 add_role_attribute(&buf, _("Cannot login"));
02492
02493 if (pset.sversion >= 90100)
02494 if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
02495 add_role_attribute(&buf, _("Replication"));
02496
02497 conns = atoi(PQgetvalue(res, i, 6));
02498 if (conns >= 0)
02499 {
02500 if (buf.len > 0)
02501 appendPQExpBufferStr(&buf, "\n");
02502
02503 if (conns == 0)
02504 appendPQExpBuffer(&buf, _("No connections"));
02505 else
02506 appendPQExpBuffer(&buf, ngettext("%d connection",
02507 "%d connections",
02508 conns),
02509 conns);
02510 }
02511
02512 if (strcmp(PQgetvalue(res, i, 7), "") != 0)
02513 {
02514 if (buf.len > 0)
02515 appendPQExpBufferStr(&buf, "\n");
02516 appendPQExpBufferStr(&buf, _("Password valid until "));
02517 appendPQExpBufferStr(&buf, PQgetvalue(res, i, 7));
02518 }
02519
02520 attr[i] = pg_strdup(buf.data);
02521
02522 printTableAddCell(&cont, attr[i], false, false);
02523
02524 printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
02525
02526 if (verbose && pset.sversion >= 80200)
02527 printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
02528 }
02529 termPQExpBuffer(&buf);
02530
02531 printTable(&cont, pset.queryFout, pset.logfile);
02532 printTableCleanup(&cont);
02533
02534 for (i = 0; i < nrows; i++)
02535 free(attr[i]);
02536 free(attr);
02537
02538 PQclear(res);
02539 return true;
02540 }
02541
02542 static void
02543 add_role_attribute(PQExpBuffer buf, const char *const str)
02544 {
02545 if (buf->len > 0)
02546 appendPQExpBufferStr(buf, ", ");
02547
02548 appendPQExpBufferStr(buf, str);
02549 }
02550
02551
02552
02553
02554 bool
02555 listDbRoleSettings(const char *pattern, const char *pattern2)
02556 {
02557 PQExpBufferData buf;
02558 PGresult *res;
02559 printQueryOpt myopt = pset.popt;
02560
02561 initPQExpBuffer(&buf);
02562
02563 if (pset.sversion >= 90000)
02564 {
02565 bool havewhere;
02566
02567 printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
02568 "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
02569 "FROM pg_db_role_setting AS s\n"
02570 "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n"
02571 "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n",
02572 gettext_noop("Role"),
02573 gettext_noop("Database"),
02574 gettext_noop("Settings"));
02575 havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
02576 NULL, "pg_roles.rolname", NULL, NULL);
02577 processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
02578 NULL, "pg_database.datname", NULL, NULL);
02579 appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
02580 }
02581 else
02582 {
02583 fprintf(pset.queryFout,
02584 _("No per-database role settings support in this server version.\n"));
02585 return false;
02586 }
02587
02588 res = PSQLexec(buf.data, false);
02589 if (!res)
02590 return false;
02591
02592 if (PQntuples(res) == 0 && !pset.quiet)
02593 {
02594 if (pattern)
02595 fprintf(pset.queryFout, _("No matching settings found.\n"));
02596 else
02597 fprintf(pset.queryFout, _("No settings found.\n"));
02598 }
02599 else
02600 {
02601 myopt.nullPrint = NULL;
02602 myopt.title = _("List of settings");
02603 myopt.translate_header = true;
02604
02605 printQuery(res, &myopt, pset.queryFout, pset.logfile);
02606 }
02607
02608 PQclear(res);
02609 resetPQExpBuffer(&buf);
02610 return true;
02611 }
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626
02627
02628
02629 bool
02630 listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem)
02631 {
02632 bool showTables = strchr(tabtypes, 't') != NULL;
02633 bool showIndexes = strchr(tabtypes, 'i') != NULL;
02634 bool showViews = strchr(tabtypes, 'v') != NULL;
02635 bool showMatViews = strchr(tabtypes, 'm') != NULL;
02636 bool showSeq = strchr(tabtypes, 's') != NULL;
02637 bool showForeign = strchr(tabtypes, 'E') != NULL;
02638
02639 PQExpBufferData buf;
02640 PGresult *res;
02641 printQueryOpt myopt = pset.popt;
02642 static const bool translate_columns[] = {false, false, true, false, false, false, false};
02643
02644 if (!(showTables || showIndexes || showViews || showMatViews || showSeq || showForeign))
02645 showTables = showViews = showMatViews = showSeq = showForeign = true;
02646
02647 initPQExpBuffer(&buf);
02648
02649
02650
02651
02652
02653 printfPQExpBuffer(&buf,
02654 "SELECT n.nspname as \"%s\",\n"
02655 " c.relname as \"%s\",\n"
02656 " CASE c.relkind"
02657 " WHEN 'r' THEN '%s'"
02658 " WHEN 'v' THEN '%s'"
02659 " WHEN 'm' THEN '%s'"
02660 " WHEN 'i' THEN '%s'"
02661 " WHEN 'S' THEN '%s'"
02662 " WHEN 's' THEN '%s'"
02663 " WHEN 'f' THEN '%s'"
02664 " END as \"%s\",\n"
02665 " pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
02666 gettext_noop("Schema"),
02667 gettext_noop("Name"),
02668 gettext_noop("table"),
02669 gettext_noop("view"),
02670 gettext_noop("materialized view"),
02671 gettext_noop("index"),
02672 gettext_noop("sequence"),
02673 gettext_noop("special"),
02674 gettext_noop("foreign table"),
02675 gettext_noop("Type"),
02676 gettext_noop("Owner"));
02677
02678 if (showIndexes)
02679 appendPQExpBuffer(&buf,
02680 ",\n c2.relname as \"%s\"",
02681 gettext_noop("Table"));
02682
02683 if (verbose)
02684 {
02685
02686
02687
02688
02689 if (pset.sversion >= 90000)
02690 appendPQExpBuffer(&buf,
02691 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \"%s\"",
02692 gettext_noop("Size"));
02693 else if (pset.sversion >= 80100)
02694 appendPQExpBuffer(&buf,
02695 ",\n pg_catalog.pg_size_pretty(pg_catalog.pg_relation_size(c.oid)) as \"%s\"",
02696 gettext_noop("Size"));
02697
02698 appendPQExpBuffer(&buf,
02699 ",\n pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
02700 gettext_noop("Description"));
02701 }
02702
02703 appendPQExpBuffer(&buf,
02704 "\nFROM pg_catalog.pg_class c"
02705 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
02706 if (showIndexes)
02707 appendPQExpBuffer(&buf,
02708 "\n LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid"
02709 "\n LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid");
02710
02711 appendPQExpBuffer(&buf, "\nWHERE c.relkind IN (");
02712 if (showTables)
02713 appendPQExpBuffer(&buf, "'r',");
02714 if (showViews)
02715 appendPQExpBuffer(&buf, "'v',");
02716 if (showMatViews)
02717 appendPQExpBuffer(&buf, "'m',");
02718 if (showIndexes)
02719 appendPQExpBuffer(&buf, "'i',");
02720 if (showSeq)
02721 appendPQExpBuffer(&buf, "'S',");
02722 if (showSystem || pattern)
02723 appendPQExpBuffer(&buf, "'s',");
02724
02725 if (showForeign)
02726 appendPQExpBuffer(&buf, "'f',");
02727
02728 appendPQExpBuffer(&buf, "''");
02729 appendPQExpBuffer(&buf, ")\n");
02730
02731 if (!showSystem && !pattern)
02732 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
02733 " AND n.nspname <> 'information_schema'\n");
02734
02735
02736
02737
02738
02739
02740
02741 appendPQExpBuffer(&buf, " AND n.nspname !~ '^pg_toast'\n");
02742
02743 processSQLNamePattern(pset.db, &buf, pattern, true, false,
02744 "n.nspname", "c.relname", NULL,
02745 "pg_catalog.pg_table_is_visible(c.oid)");
02746
02747 appendPQExpBuffer(&buf, "ORDER BY 1,2;");
02748
02749 res = PSQLexec(buf.data, false);
02750 termPQExpBuffer(&buf);
02751 if (!res)
02752 return false;
02753
02754 if (PQntuples(res) == 0 && !pset.quiet)
02755 {
02756 if (pattern)
02757 fprintf(pset.queryFout, _("No matching relations found.\n"));
02758 else
02759 fprintf(pset.queryFout, _("No relations found.\n"));
02760 }
02761 else
02762 {
02763 myopt.nullPrint = NULL;
02764 myopt.title = _("List of relations");
02765 myopt.translate_header = true;
02766 myopt.translate_columns = translate_columns;
02767
02768 printQuery(res, &myopt, pset.queryFout, pset.logfile);
02769 }
02770
02771 PQclear(res);
02772 return true;
02773 }
02774
02775
02776
02777
02778
02779
02780
02781 bool
02782 listLanguages(const char *pattern, bool verbose, bool showSystem)
02783 {
02784 PQExpBufferData buf;
02785 PGresult *res;
02786 printQueryOpt myopt = pset.popt;
02787
02788 initPQExpBuffer(&buf);
02789
02790 printfPQExpBuffer(&buf,
02791 "SELECT l.lanname AS \"%s\",\n",
02792 gettext_noop("Name"));
02793 if (pset.sversion >= 80300)
02794 appendPQExpBuffer(&buf,
02795 " pg_catalog.pg_get_userbyid(l.lanowner) as \"%s\",\n",
02796 gettext_noop("Owner"));
02797
02798 appendPQExpBuffer(&buf,
02799 " l.lanpltrusted AS \"%s\"",
02800 gettext_noop("Trusted"));
02801
02802 if (verbose)
02803 {
02804 appendPQExpBuffer(&buf,
02805 ",\n NOT l.lanispl AS \"%s\",\n"
02806 " l.lanplcallfoid::regprocedure AS \"%s\",\n"
02807 " l.lanvalidator::regprocedure AS \"%s\",\n ",
02808 gettext_noop("Internal Language"),
02809 gettext_noop("Call Handler"),
02810 gettext_noop("Validator"));
02811 if (pset.sversion >= 90000)
02812 appendPQExpBuffer(&buf, "l.laninline::regprocedure AS \"%s\",\n ",
02813 gettext_noop("Inline Handler"));
02814 printACLColumn(&buf, "l.lanacl");
02815 }
02816
02817 appendPQExpBuffer(&buf,
02818 ",\n d.description AS \"%s\""
02819 "\nFROM pg_catalog.pg_language l\n"
02820 "LEFT JOIN pg_catalog.pg_description d\n"
02821 " ON d.classoid = l.tableoid AND d.objoid = l.oid\n"
02822 " AND d.objsubid = 0\n",
02823 gettext_noop("Description"));
02824
02825 if (pattern)
02826 processSQLNamePattern(pset.db, &buf, pattern, false, false,
02827 NULL, "l.lanname", NULL, NULL);
02828
02829 if (!showSystem && !pattern)
02830 appendPQExpBuffer(&buf, "WHERE l.lanplcallfoid != 0\n");
02831
02832
02833 appendPQExpBuffer(&buf, "ORDER BY 1;");
02834
02835 res = PSQLexec(buf.data, false);
02836 termPQExpBuffer(&buf);
02837 if (!res)
02838 return false;
02839
02840 myopt.nullPrint = NULL;
02841 myopt.title = _("List of languages");
02842 myopt.translate_header = true;
02843
02844 printQuery(res, &myopt, pset.queryFout, pset.logfile);
02845
02846 PQclear(res);
02847 return true;
02848 }
02849
02850
02851
02852
02853
02854
02855
02856 bool
02857 listDomains(const char *pattern, bool verbose, bool showSystem)
02858 {
02859 PQExpBufferData buf;
02860 PGresult *res;
02861 printQueryOpt myopt = pset.popt;
02862
02863 initPQExpBuffer(&buf);
02864
02865 printfPQExpBuffer(&buf,
02866 "SELECT n.nspname as \"%s\",\n"
02867 " t.typname as \"%s\",\n"
02868 " pg_catalog.format_type(t.typbasetype, t.typtypmod) as \"%s\",\n"
02869 " TRIM(LEADING\n",
02870 gettext_noop("Schema"),
02871 gettext_noop("Name"),
02872 gettext_noop("Type"));
02873
02874 if (pset.sversion >= 90100)
02875 appendPQExpBuffer(&buf,
02876 " COALESCE((SELECT ' collate ' || c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type bt\n"
02877 " WHERE c.oid = t.typcollation AND bt.oid = t.typbasetype AND t.typcollation <> bt.typcollation), '') ||\n");
02878 appendPQExpBuffer(&buf,
02879 " CASE WHEN t.typnotnull THEN ' not null' ELSE '' END ||\n"
02880 " CASE WHEN t.typdefault IS NOT NULL THEN ' default ' || t.typdefault ELSE '' END\n"
02881 " ) as \"%s\",\n"
02882 " pg_catalog.array_to_string(ARRAY(\n"
02883 " SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM pg_catalog.pg_constraint r WHERE t.oid = r.contypid\n"
02884 " ), ' ') as \"%s\"",
02885 gettext_noop("Modifier"),
02886 gettext_noop("Check"));
02887
02888 if (verbose)
02889 {
02890 if (pset.sversion >= 90200)
02891 {
02892 appendPQExpBuffer(&buf, ",\n ");
02893 printACLColumn(&buf, "t.typacl");
02894 }
02895 appendPQExpBuffer(&buf,
02896 ",\n d.description as \"%s\"",
02897 gettext_noop("Description"));
02898 }
02899
02900 appendPQExpBuffer(&buf,
02901 "\nFROM pg_catalog.pg_type t\n"
02902 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
02903
02904 if (verbose)
02905 appendPQExpBuffer(&buf,
02906 " LEFT JOIN pg_catalog.pg_description d "
02907 "ON d.classoid = t.tableoid AND d.objoid = t.oid "
02908 "AND d.objsubid = 0\n");
02909
02910 appendPQExpBuffer(&buf, "WHERE t.typtype = 'd'\n");
02911
02912 if (!showSystem && !pattern)
02913 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
02914 " AND n.nspname <> 'information_schema'\n");
02915
02916 processSQLNamePattern(pset.db, &buf, pattern, true, false,
02917 "n.nspname", "t.typname", NULL,
02918 "pg_catalog.pg_type_is_visible(t.oid)");
02919
02920 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
02921
02922 res = PSQLexec(buf.data, false);
02923 termPQExpBuffer(&buf);
02924 if (!res)
02925 return false;
02926
02927 myopt.nullPrint = NULL;
02928 myopt.title = _("List of domains");
02929 myopt.translate_header = true;
02930
02931 printQuery(res, &myopt, pset.queryFout, pset.logfile);
02932
02933 PQclear(res);
02934 return true;
02935 }
02936
02937
02938
02939
02940
02941
02942 bool
02943 listConversions(const char *pattern, bool verbose, bool showSystem)
02944 {
02945 PQExpBufferData buf;
02946 PGresult *res;
02947 printQueryOpt myopt = pset.popt;
02948 static const bool translate_columns[] = {false, false, false, false, true};
02949
02950 initPQExpBuffer(&buf);
02951
02952 printfPQExpBuffer(&buf,
02953 "SELECT n.nspname AS \"%s\",\n"
02954 " c.conname AS \"%s\",\n"
02955 " pg_catalog.pg_encoding_to_char(c.conforencoding) AS \"%s\",\n"
02956 " pg_catalog.pg_encoding_to_char(c.contoencoding) AS \"%s\",\n"
02957 " CASE WHEN c.condefault THEN '%s'\n"
02958 " ELSE '%s' END AS \"%s\"",
02959 gettext_noop("Schema"),
02960 gettext_noop("Name"),
02961 gettext_noop("Source"),
02962 gettext_noop("Destination"),
02963 gettext_noop("yes"), gettext_noop("no"),
02964 gettext_noop("Default?"));
02965
02966 if (verbose)
02967 appendPQExpBuffer(&buf,
02968 ",\n d.description AS \"%s\"",
02969 gettext_noop("Description"));
02970
02971 appendPQExpBuffer(&buf,
02972 "\nFROM pg_catalog.pg_conversion c\n"
02973 " JOIN pg_catalog.pg_namespace n "
02974 "ON n.oid = c.connamespace\n");
02975
02976 if (verbose)
02977 appendPQExpBuffer(&buf,
02978 "LEFT JOIN pg_catalog.pg_description d "
02979 "ON d.classoid = c.tableoid\n"
02980 " AND d.objoid = c.oid "
02981 "AND d.objsubid = 0\n");
02982
02983 appendPQExpBuffer(&buf, "WHERE true\n");
02984
02985 if (!showSystem && !pattern)
02986 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
02987 " AND n.nspname <> 'information_schema'\n");
02988
02989 processSQLNamePattern(pset.db, &buf, pattern, true, false,
02990 "n.nspname", "c.conname", NULL,
02991 "pg_catalog.pg_conversion_is_visible(c.oid)");
02992
02993 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
02994
02995 res = PSQLexec(buf.data, false);
02996 termPQExpBuffer(&buf);
02997 if (!res)
02998 return false;
02999
03000 myopt.nullPrint = NULL;
03001 myopt.title = _("List of conversions");
03002 myopt.translate_header = true;
03003 myopt.translate_columns = translate_columns;
03004
03005 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03006
03007 PQclear(res);
03008 return true;
03009 }
03010
03011
03012
03013
03014
03015
03016 bool
03017 listEventTriggers(const char *pattern, bool verbose)
03018 {
03019 PQExpBufferData buf;
03020 PGresult *res;
03021 printQueryOpt myopt = pset.popt;
03022 static const bool translate_columns[] =
03023 {false, false, false, true, false, false, false};
03024
03025 initPQExpBuffer(&buf);
03026
03027 printfPQExpBuffer(&buf,
03028 "select evtname as \"%s\", "
03029 "evtevent as \"%s\", "
03030 "pg_catalog.pg_get_userbyid(e.evtowner) AS \"%s\", "
03031 "case evtenabled when 'O' then 'enabled' "
03032 " when 'R' then 'replica' "
03033 " when 'A' then 'always' "
03034 " when 'D' then 'disabled' end as \"%s\", "
03035 "e.evtfoid::regproc as \"%s\", "
03036 "array_to_string(array(select x "
03037 " from unnest(evttags) as t(x)), ', ') as \"%s\" ",
03038 gettext_noop("Name"),
03039 gettext_noop("Event"),
03040 gettext_noop("Owner"),
03041 gettext_noop("Enabled"),
03042 gettext_noop("Procedure"),
03043 gettext_noop("Tags"));
03044 if (verbose)
03045 appendPQExpBuffer(&buf,
03046 ",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
03047 gettext_noop("Description"));
03048 appendPQExpBuffer(&buf,
03049 "\nFROM pg_event_trigger e ");
03050
03051 processSQLNamePattern(pset.db, &buf, pattern, false, false,
03052 NULL, "evtname", NULL, NULL);
03053
03054 appendPQExpBuffer(&buf, "ORDER BY 1");
03055
03056 res = PSQLexec(buf.data, false);
03057 termPQExpBuffer(&buf);
03058 if (!res)
03059 return false;
03060
03061 myopt.nullPrint = NULL;
03062 myopt.title = _("List of event triggers");
03063 myopt.translate_header = true;
03064 myopt.translate_columns = translate_columns;
03065
03066 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03067
03068 PQclear(res);
03069 return true;
03070 }
03071
03072
03073
03074
03075
03076
03077 bool
03078 listCasts(const char *pattern, bool verbose)
03079 {
03080 PQExpBufferData buf;
03081 PGresult *res;
03082 printQueryOpt myopt = pset.popt;
03083 static const bool translate_columns[] = {false, false, false, true};
03084
03085 initPQExpBuffer(&buf);
03086
03087
03088
03089
03090
03091
03092
03093 printfPQExpBuffer(&buf,
03094 "SELECT pg_catalog.format_type(castsource, NULL) AS \"%s\",\n"
03095 " pg_catalog.format_type(casttarget, NULL) AS \"%s\",\n"
03096 " CASE WHEN castfunc = 0 THEN '(binary coercible)'\n"
03097 " ELSE p.proname\n"
03098 " END as \"%s\",\n"
03099 " CASE WHEN c.castcontext = 'e' THEN '%s'\n"
03100 " WHEN c.castcontext = 'a' THEN '%s'\n"
03101 " ELSE '%s'\n"
03102 " END as \"%s\"",
03103 gettext_noop("Source type"),
03104 gettext_noop("Target type"),
03105 gettext_noop("Function"),
03106 gettext_noop("no"),
03107 gettext_noop("in assignment"),
03108 gettext_noop("yes"),
03109 gettext_noop("Implicit?"));
03110
03111 if (verbose)
03112 appendPQExpBuffer(&buf,
03113 ",\n d.description AS \"%s\"\n",
03114 gettext_noop("Description"));
03115
03116 appendPQExpBuffer(&buf,
03117 "FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p\n"
03118 " ON c.castfunc = p.oid\n"
03119 " LEFT JOIN pg_catalog.pg_type ts\n"
03120 " ON c.castsource = ts.oid\n"
03121 " LEFT JOIN pg_catalog.pg_namespace ns\n"
03122 " ON ns.oid = ts.typnamespace\n"
03123 " LEFT JOIN pg_catalog.pg_type tt\n"
03124 " ON c.casttarget = tt.oid\n"
03125 " LEFT JOIN pg_catalog.pg_namespace nt\n"
03126 " ON nt.oid = tt.typnamespace\n");
03127
03128 if (verbose)
03129 appendPQExpBuffer(&buf,
03130 " LEFT JOIN pg_catalog.pg_description d\n"
03131 " ON d.classoid = c.tableoid AND d.objoid = "
03132 "c.oid AND d.objsubid = 0\n");
03133
03134 appendPQExpBuffer(&buf, "WHERE ( (true");
03135
03136
03137
03138
03139
03140 processSQLNamePattern(pset.db, &buf, pattern, true, false,
03141 "ns.nspname", "ts.typname",
03142 "pg_catalog.format_type(ts.oid, NULL)",
03143 "pg_catalog.pg_type_is_visible(ts.oid)");
03144
03145 appendPQExpBuffer(&buf, ") OR (true");
03146
03147 processSQLNamePattern(pset.db, &buf, pattern, true, false,
03148 "nt.nspname", "tt.typname",
03149 "pg_catalog.format_type(tt.oid, NULL)",
03150 "pg_catalog.pg_type_is_visible(tt.oid)");
03151
03152 appendPQExpBuffer(&buf, ") )\nORDER BY 1, 2;");
03153
03154 res = PSQLexec(buf.data, false);
03155 termPQExpBuffer(&buf);
03156 if (!res)
03157 return false;
03158
03159 myopt.nullPrint = NULL;
03160 myopt.title = _("List of casts");
03161 myopt.translate_header = true;
03162 myopt.translate_columns = translate_columns;
03163
03164 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03165
03166 PQclear(res);
03167 return true;
03168 }
03169
03170
03171
03172
03173
03174
03175 bool
03176 listCollations(const char *pattern, bool verbose, bool showSystem)
03177 {
03178 PQExpBufferData buf;
03179 PGresult *res;
03180 printQueryOpt myopt = pset.popt;
03181 static const bool translate_columns[] = {false, false, false, false, false};
03182
03183 if (pset.sversion < 90100)
03184 {
03185 psql_error("The server (version %d.%d) does not support collations.\n",
03186 pset.sversion / 10000, (pset.sversion / 100) % 100);
03187 return true;
03188 }
03189
03190 initPQExpBuffer(&buf);
03191
03192 printfPQExpBuffer(&buf,
03193 "SELECT n.nspname AS \"%s\",\n"
03194 " c.collname AS \"%s\",\n"
03195 " c.collcollate AS \"%s\",\n"
03196 " c.collctype AS \"%s\"",
03197 gettext_noop("Schema"),
03198 gettext_noop("Name"),
03199 gettext_noop("Collate"),
03200 gettext_noop("Ctype"));
03201
03202 if (verbose)
03203 appendPQExpBuffer(&buf,
03204 ",\n pg_catalog.obj_description(c.oid, 'pg_collation') AS \"%s\"",
03205 gettext_noop("Description"));
03206
03207 appendPQExpBuffer(&buf,
03208 "\nFROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n\n"
03209 "WHERE n.oid = c.collnamespace\n");
03210
03211 if (!showSystem && !pattern)
03212 appendPQExpBuffer(&buf, " AND n.nspname <> 'pg_catalog'\n"
03213 " AND n.nspname <> 'information_schema'\n");
03214
03215
03216
03217
03218
03219
03220
03221 appendPQExpBuffer(&buf, " AND c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))\n");
03222
03223 processSQLNamePattern(pset.db, &buf, pattern, true, false,
03224 "n.nspname", "c.collname", NULL,
03225 "pg_catalog.pg_collation_is_visible(c.oid)");
03226
03227 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
03228
03229 res = PSQLexec(buf.data, false);
03230 termPQExpBuffer(&buf);
03231 if (!res)
03232 return false;
03233
03234 myopt.nullPrint = NULL;
03235 myopt.title = _("List of collations");
03236 myopt.translate_header = true;
03237 myopt.translate_columns = translate_columns;
03238
03239 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03240
03241 PQclear(res);
03242 return true;
03243 }
03244
03245
03246
03247
03248
03249
03250 bool
03251 listSchemas(const char *pattern, bool verbose, bool showSystem)
03252 {
03253 PQExpBufferData buf;
03254 PGresult *res;
03255 printQueryOpt myopt = pset.popt;
03256
03257 initPQExpBuffer(&buf);
03258 printfPQExpBuffer(&buf,
03259 "SELECT n.nspname AS \"%s\",\n"
03260 " pg_catalog.pg_get_userbyid(n.nspowner) AS \"%s\"",
03261 gettext_noop("Name"),
03262 gettext_noop("Owner"));
03263
03264 if (verbose)
03265 {
03266 appendPQExpBuffer(&buf, ",\n ");
03267 printACLColumn(&buf, "n.nspacl");
03268 appendPQExpBuffer(&buf,
03269 ",\n pg_catalog.obj_description(n.oid, 'pg_namespace') AS \"%s\"",
03270 gettext_noop("Description"));
03271 }
03272
03273 appendPQExpBuffer(&buf,
03274 "\nFROM pg_catalog.pg_namespace n\n");
03275
03276 if (!showSystem && !pattern)
03277 appendPQExpBuffer(&buf,
03278 "WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n");
03279
03280 processSQLNamePattern(pset.db, &buf, pattern,
03281 !showSystem && !pattern, false,
03282 NULL, "n.nspname", NULL,
03283 NULL);
03284
03285 appendPQExpBuffer(&buf, "ORDER BY 1;");
03286
03287 res = PSQLexec(buf.data, false);
03288 termPQExpBuffer(&buf);
03289 if (!res)
03290 return false;
03291
03292 myopt.nullPrint = NULL;
03293 myopt.title = _("List of schemas");
03294 myopt.translate_header = true;
03295
03296 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03297
03298 PQclear(res);
03299 return true;
03300 }
03301
03302
03303
03304
03305
03306
03307 bool
03308 listTSParsers(const char *pattern, bool verbose)
03309 {
03310 PQExpBufferData buf;
03311 PGresult *res;
03312 printQueryOpt myopt = pset.popt;
03313
03314 if (pset.sversion < 80300)
03315 {
03316 psql_error("The server (version %d.%d) does not support full text search.\n",
03317 pset.sversion / 10000, (pset.sversion / 100) % 100);
03318 return true;
03319 }
03320
03321 if (verbose)
03322 return listTSParsersVerbose(pattern);
03323
03324 initPQExpBuffer(&buf);
03325
03326 printfPQExpBuffer(&buf,
03327 "SELECT \n"
03328 " n.nspname as \"%s\",\n"
03329 " p.prsname as \"%s\",\n"
03330 " pg_catalog.obj_description(p.oid, 'pg_ts_parser') as \"%s\"\n"
03331 "FROM pg_catalog.pg_ts_parser p \n"
03332 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n",
03333 gettext_noop("Schema"),
03334 gettext_noop("Name"),
03335 gettext_noop("Description")
03336 );
03337
03338 processSQLNamePattern(pset.db, &buf, pattern, false, false,
03339 "n.nspname", "p.prsname", NULL,
03340 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
03341
03342 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
03343
03344 res = PSQLexec(buf.data, false);
03345 termPQExpBuffer(&buf);
03346 if (!res)
03347 return false;
03348
03349 myopt.nullPrint = NULL;
03350 myopt.title = _("List of text search parsers");
03351 myopt.translate_header = true;
03352
03353 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03354
03355 PQclear(res);
03356 return true;
03357 }
03358
03359
03360
03361
03362 static bool
03363 listTSParsersVerbose(const char *pattern)
03364 {
03365 PQExpBufferData buf;
03366 PGresult *res;
03367 int i;
03368
03369 initPQExpBuffer(&buf);
03370
03371 printfPQExpBuffer(&buf,
03372 "SELECT p.oid, \n"
03373 " n.nspname, \n"
03374 " p.prsname \n"
03375 "FROM pg_catalog.pg_ts_parser p\n"
03376 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.prsnamespace\n"
03377 );
03378
03379 processSQLNamePattern(pset.db, &buf, pattern, false, false,
03380 "n.nspname", "p.prsname", NULL,
03381 "pg_catalog.pg_ts_parser_is_visible(p.oid)");
03382
03383 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
03384
03385 res = PSQLexec(buf.data, false);
03386 termPQExpBuffer(&buf);
03387 if (!res)
03388 return false;
03389
03390 if (PQntuples(res) == 0)
03391 {
03392 if (!pset.quiet)
03393 psql_error("Did not find any text search parser named \"%s\".\n",
03394 pattern);
03395 PQclear(res);
03396 return false;
03397 }
03398
03399 for (i = 0; i < PQntuples(res); i++)
03400 {
03401 const char *oid;
03402 const char *nspname = NULL;
03403 const char *prsname;
03404
03405 oid = PQgetvalue(res, i, 0);
03406 if (!PQgetisnull(res, i, 1))
03407 nspname = PQgetvalue(res, i, 1);
03408 prsname = PQgetvalue(res, i, 2);
03409
03410 if (!describeOneTSParser(oid, nspname, prsname))
03411 {
03412 PQclear(res);
03413 return false;
03414 }
03415
03416 if (cancel_pressed)
03417 {
03418 PQclear(res);
03419 return false;
03420 }
03421 }
03422
03423 PQclear(res);
03424 return true;
03425 }
03426
03427 static bool
03428 describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
03429 {
03430 PQExpBufferData buf;
03431 PGresult *res;
03432 char title[1024];
03433 printQueryOpt myopt = pset.popt;
03434 static const bool translate_columns[] = {true, false, false};
03435
03436 initPQExpBuffer(&buf);
03437
03438 printfPQExpBuffer(&buf,
03439 "SELECT '%s' AS \"%s\", \n"
03440 " p.prsstart::pg_catalog.regproc AS \"%s\", \n"
03441 " pg_catalog.obj_description(p.prsstart, 'pg_proc') as \"%s\" \n"
03442 " FROM pg_catalog.pg_ts_parser p \n"
03443 " WHERE p.oid = '%s' \n"
03444 "UNION ALL \n"
03445 "SELECT '%s', \n"
03446 " p.prstoken::pg_catalog.regproc, \n"
03447 " pg_catalog.obj_description(p.prstoken, 'pg_proc') \n"
03448 " FROM pg_catalog.pg_ts_parser p \n"
03449 " WHERE p.oid = '%s' \n"
03450 "UNION ALL \n"
03451 "SELECT '%s', \n"
03452 " p.prsend::pg_catalog.regproc, \n"
03453 " pg_catalog.obj_description(p.prsend, 'pg_proc') \n"
03454 " FROM pg_catalog.pg_ts_parser p \n"
03455 " WHERE p.oid = '%s' \n"
03456 "UNION ALL \n"
03457 "SELECT '%s', \n"
03458 " p.prsheadline::pg_catalog.regproc, \n"
03459 " pg_catalog.obj_description(p.prsheadline, 'pg_proc') \n"
03460 " FROM pg_catalog.pg_ts_parser p \n"
03461 " WHERE p.oid = '%s' \n"
03462 "UNION ALL \n"
03463 "SELECT '%s', \n"
03464 " p.prslextype::pg_catalog.regproc, \n"
03465 " pg_catalog.obj_description(p.prslextype, 'pg_proc') \n"
03466 " FROM pg_catalog.pg_ts_parser p \n"
03467 " WHERE p.oid = '%s';",
03468 gettext_noop("Start parse"),
03469 gettext_noop("Method"),
03470 gettext_noop("Function"),
03471 gettext_noop("Description"),
03472 oid,
03473 gettext_noop("Get next token"),
03474 oid,
03475 gettext_noop("End parse"),
03476 oid,
03477 gettext_noop("Get headline"),
03478 oid,
03479 gettext_noop("Get token types"),
03480 oid);
03481
03482 res = PSQLexec(buf.data, false);
03483 termPQExpBuffer(&buf);
03484 if (!res)
03485 return false;
03486
03487 myopt.nullPrint = NULL;
03488 if (nspname)
03489 sprintf(title, _("Text search parser \"%s.%s\""), nspname, prsname);
03490 else
03491 sprintf(title, _("Text search parser \"%s\""), prsname);
03492 myopt.title = title;
03493 myopt.footers = NULL;
03494 myopt.topt.default_footer = false;
03495 myopt.translate_header = true;
03496 myopt.translate_columns = translate_columns;
03497
03498 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03499
03500 PQclear(res);
03501
03502 initPQExpBuffer(&buf);
03503
03504 printfPQExpBuffer(&buf,
03505 "SELECT t.alias as \"%s\", \n"
03506 " t.description as \"%s\" \n"
03507 "FROM pg_catalog.ts_token_type( '%s'::pg_catalog.oid ) as t \n"
03508 "ORDER BY 1;",
03509 gettext_noop("Token name"),
03510 gettext_noop("Description"),
03511 oid);
03512
03513 res = PSQLexec(buf.data, false);
03514 termPQExpBuffer(&buf);
03515 if (!res)
03516 return false;
03517
03518 myopt.nullPrint = NULL;
03519 if (nspname)
03520 sprintf(title, _("Token types for parser \"%s.%s\""), nspname, prsname);
03521 else
03522 sprintf(title, _("Token types for parser \"%s\""), prsname);
03523 myopt.title = title;
03524 myopt.footers = NULL;
03525 myopt.topt.default_footer = true;
03526 myopt.translate_header = true;
03527 myopt.translate_columns = NULL;
03528
03529 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03530
03531 PQclear(res);
03532 return true;
03533 }
03534
03535
03536
03537
03538
03539
03540 bool
03541 listTSDictionaries(const char *pattern, bool verbose)
03542 {
03543 PQExpBufferData buf;
03544 PGresult *res;
03545 printQueryOpt myopt = pset.popt;
03546
03547 if (pset.sversion < 80300)
03548 {
03549 psql_error("The server (version %d.%d) does not support full text search.\n",
03550 pset.sversion / 10000, (pset.sversion / 100) % 100);
03551 return true;
03552 }
03553
03554 initPQExpBuffer(&buf);
03555
03556 printfPQExpBuffer(&buf,
03557 "SELECT \n"
03558 " n.nspname as \"%s\",\n"
03559 " d.dictname as \"%s\",\n",
03560 gettext_noop("Schema"),
03561 gettext_noop("Name"));
03562
03563 if (verbose)
03564 {
03565 appendPQExpBuffer(&buf,
03566 " ( SELECT COALESCE(nt.nspname, '(null)')::pg_catalog.text || '.' || t.tmplname FROM \n"
03567 " pg_catalog.pg_ts_template t \n"
03568 " LEFT JOIN pg_catalog.pg_namespace nt ON nt.oid = t.tmplnamespace \n"
03569 " WHERE d.dicttemplate = t.oid ) AS \"%s\", \n"
03570 " d.dictinitoption as \"%s\", \n",
03571 gettext_noop("Template"),
03572 gettext_noop("Init options"));
03573 }
03574
03575 appendPQExpBuffer(&buf,
03576 " pg_catalog.obj_description(d.oid, 'pg_ts_dict') as \"%s\"\n",
03577 gettext_noop("Description"));
03578
03579 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_dict d\n"
03580 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.dictnamespace\n");
03581
03582 processSQLNamePattern(pset.db, &buf, pattern, false, false,
03583 "n.nspname", "d.dictname", NULL,
03584 "pg_catalog.pg_ts_dict_is_visible(d.oid)");
03585
03586 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
03587
03588 res = PSQLexec(buf.data, false);
03589 termPQExpBuffer(&buf);
03590 if (!res)
03591 return false;
03592
03593 myopt.nullPrint = NULL;
03594 myopt.title = _("List of text search dictionaries");
03595 myopt.translate_header = true;
03596
03597 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03598
03599 PQclear(res);
03600 return true;
03601 }
03602
03603
03604
03605
03606
03607
03608 bool
03609 listTSTemplates(const char *pattern, bool verbose)
03610 {
03611 PQExpBufferData buf;
03612 PGresult *res;
03613 printQueryOpt myopt = pset.popt;
03614
03615 if (pset.sversion < 80300)
03616 {
03617 psql_error("The server (version %d.%d) does not support full text search.\n",
03618 pset.sversion / 10000, (pset.sversion / 100) % 100);
03619 return true;
03620 }
03621
03622 initPQExpBuffer(&buf);
03623
03624 if (verbose)
03625 printfPQExpBuffer(&buf,
03626 "SELECT \n"
03627 " n.nspname AS \"%s\",\n"
03628 " t.tmplname AS \"%s\",\n"
03629 " t.tmplinit::pg_catalog.regproc AS \"%s\",\n"
03630 " t.tmpllexize::pg_catalog.regproc AS \"%s\",\n"
03631 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
03632 gettext_noop("Schema"),
03633 gettext_noop("Name"),
03634 gettext_noop("Init"),
03635 gettext_noop("Lexize"),
03636 gettext_noop("Description"));
03637 else
03638 printfPQExpBuffer(&buf,
03639 "SELECT \n"
03640 " n.nspname AS \"%s\",\n"
03641 " t.tmplname AS \"%s\",\n"
03642 " pg_catalog.obj_description(t.oid, 'pg_ts_template') AS \"%s\"\n",
03643 gettext_noop("Schema"),
03644 gettext_noop("Name"),
03645 gettext_noop("Description"));
03646
03647 appendPQExpBuffer(&buf, "FROM pg_catalog.pg_ts_template t\n"
03648 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.tmplnamespace\n");
03649
03650 processSQLNamePattern(pset.db, &buf, pattern, false, false,
03651 "n.nspname", "t.tmplname", NULL,
03652 "pg_catalog.pg_ts_template_is_visible(t.oid)");
03653
03654 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
03655
03656 res = PSQLexec(buf.data, false);
03657 termPQExpBuffer(&buf);
03658 if (!res)
03659 return false;
03660
03661 myopt.nullPrint = NULL;
03662 myopt.title = _("List of text search templates");
03663 myopt.translate_header = true;
03664
03665 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03666
03667 PQclear(res);
03668 return true;
03669 }
03670
03671
03672
03673
03674
03675
03676 bool
03677 listTSConfigs(const char *pattern, bool verbose)
03678 {
03679 PQExpBufferData buf;
03680 PGresult *res;
03681 printQueryOpt myopt = pset.popt;
03682
03683 if (pset.sversion < 80300)
03684 {
03685 psql_error("The server (version %d.%d) does not support full text search.\n",
03686 pset.sversion / 10000, (pset.sversion / 100) % 100);
03687 return true;
03688 }
03689
03690 if (verbose)
03691 return listTSConfigsVerbose(pattern);
03692
03693 initPQExpBuffer(&buf);
03694
03695 printfPQExpBuffer(&buf,
03696 "SELECT \n"
03697 " n.nspname as \"%s\",\n"
03698 " c.cfgname as \"%s\",\n"
03699 " pg_catalog.obj_description(c.oid, 'pg_ts_config') as \"%s\"\n"
03700 "FROM pg_catalog.pg_ts_config c\n"
03701 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace \n",
03702 gettext_noop("Schema"),
03703 gettext_noop("Name"),
03704 gettext_noop("Description")
03705 );
03706
03707 processSQLNamePattern(pset.db, &buf, pattern, false, false,
03708 "n.nspname", "c.cfgname", NULL,
03709 "pg_catalog.pg_ts_config_is_visible(c.oid)");
03710
03711 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
03712
03713 res = PSQLexec(buf.data, false);
03714 termPQExpBuffer(&buf);
03715 if (!res)
03716 return false;
03717
03718 myopt.nullPrint = NULL;
03719 myopt.title = _("List of text search configurations");
03720 myopt.translate_header = true;
03721
03722 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03723
03724 PQclear(res);
03725 return true;
03726 }
03727
03728 static bool
03729 listTSConfigsVerbose(const char *pattern)
03730 {
03731 PQExpBufferData buf;
03732 PGresult *res;
03733 int i;
03734
03735 initPQExpBuffer(&buf);
03736
03737 printfPQExpBuffer(&buf,
03738 "SELECT c.oid, c.cfgname,\n"
03739 " n.nspname, \n"
03740 " p.prsname, \n"
03741 " np.nspname as pnspname \n"
03742 "FROM pg_catalog.pg_ts_config c \n"
03743 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.cfgnamespace, \n"
03744 " pg_catalog.pg_ts_parser p \n"
03745 " LEFT JOIN pg_catalog.pg_namespace np ON np.oid = p.prsnamespace \n"
03746 "WHERE p.oid = c.cfgparser\n"
03747 );
03748
03749 processSQLNamePattern(pset.db, &buf, pattern, true, false,
03750 "n.nspname", "c.cfgname", NULL,
03751 "pg_catalog.pg_ts_config_is_visible(c.oid)");
03752
03753 appendPQExpBuffer(&buf, "ORDER BY 3, 2;");
03754
03755 res = PSQLexec(buf.data, false);
03756 termPQExpBuffer(&buf);
03757 if (!res)
03758 return false;
03759
03760 if (PQntuples(res) == 0)
03761 {
03762 if (!pset.quiet)
03763 psql_error("Did not find any text search configuration named \"%s\".\n",
03764 pattern);
03765 PQclear(res);
03766 return false;
03767 }
03768
03769 for (i = 0; i < PQntuples(res); i++)
03770 {
03771 const char *oid;
03772 const char *cfgname;
03773 const char *nspname = NULL;
03774 const char *prsname;
03775 const char *pnspname = NULL;
03776
03777 oid = PQgetvalue(res, i, 0);
03778 cfgname = PQgetvalue(res, i, 1);
03779 if (!PQgetisnull(res, i, 2))
03780 nspname = PQgetvalue(res, i, 2);
03781 prsname = PQgetvalue(res, i, 3);
03782 if (!PQgetisnull(res, i, 4))
03783 pnspname = PQgetvalue(res, i, 4);
03784
03785 if (!describeOneTSConfig(oid, nspname, cfgname, pnspname, prsname))
03786 {
03787 PQclear(res);
03788 return false;
03789 }
03790
03791 if (cancel_pressed)
03792 {
03793 PQclear(res);
03794 return false;
03795 }
03796 }
03797
03798 PQclear(res);
03799 return true;
03800 }
03801
03802 static bool
03803 describeOneTSConfig(const char *oid, const char *nspname, const char *cfgname,
03804 const char *pnspname, const char *prsname)
03805 {
03806 PQExpBufferData buf,
03807 title;
03808 PGresult *res;
03809 printQueryOpt myopt = pset.popt;
03810
03811 initPQExpBuffer(&buf);
03812
03813 printfPQExpBuffer(&buf,
03814 "SELECT \n"
03815 " ( SELECT t.alias FROM \n"
03816 " pg_catalog.ts_token_type(c.cfgparser) AS t \n"
03817 " WHERE t.tokid = m.maptokentype ) AS \"%s\", \n"
03818 " pg_catalog.btrim( \n"
03819 " ARRAY( SELECT mm.mapdict::pg_catalog.regdictionary \n"
03820 " FROM pg_catalog.pg_ts_config_map AS mm \n"
03821 " WHERE mm.mapcfg = m.mapcfg AND mm.maptokentype = m.maptokentype \n"
03822 " ORDER BY mapcfg, maptokentype, mapseqno \n"
03823 " ) :: pg_catalog.text , \n"
03824 " '{}') AS \"%s\" \n"
03825 "FROM pg_catalog.pg_ts_config AS c, pg_catalog.pg_ts_config_map AS m \n"
03826 "WHERE c.oid = '%s' AND m.mapcfg = c.oid \n"
03827 "GROUP BY m.mapcfg, m.maptokentype, c.cfgparser \n"
03828 "ORDER BY 1;",
03829 gettext_noop("Token"),
03830 gettext_noop("Dictionaries"),
03831 oid);
03832
03833 res = PSQLexec(buf.data, false);
03834 termPQExpBuffer(&buf);
03835 if (!res)
03836 return false;
03837
03838 initPQExpBuffer(&title);
03839
03840 if (nspname)
03841 appendPQExpBuffer(&title, _("Text search configuration \"%s.%s\""),
03842 nspname, cfgname);
03843 else
03844 appendPQExpBuffer(&title, _("Text search configuration \"%s\""),
03845 cfgname);
03846
03847 if (pnspname)
03848 appendPQExpBuffer(&title, _("\nParser: \"%s.%s\""),
03849 pnspname, prsname);
03850 else
03851 appendPQExpBuffer(&title, _("\nParser: \"%s\""),
03852 prsname);
03853
03854 myopt.nullPrint = NULL;
03855 myopt.title = title.data;
03856 myopt.footers = NULL;
03857 myopt.topt.default_footer = false;
03858 myopt.translate_header = true;
03859
03860 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03861
03862 termPQExpBuffer(&title);
03863
03864 PQclear(res);
03865 return true;
03866 }
03867
03868
03869
03870
03871
03872
03873
03874 bool
03875 listForeignDataWrappers(const char *pattern, bool verbose)
03876 {
03877 PQExpBufferData buf;
03878 PGresult *res;
03879 printQueryOpt myopt = pset.popt;
03880
03881 if (pset.sversion < 80400)
03882 {
03883 psql_error("The server (version %d.%d) does not support foreign-data wrappers.\n",
03884 pset.sversion / 10000, (pset.sversion / 100) % 100);
03885 return true;
03886 }
03887
03888 initPQExpBuffer(&buf);
03889 printfPQExpBuffer(&buf,
03890 "SELECT fdw.fdwname AS \"%s\",\n"
03891 " pg_catalog.pg_get_userbyid(fdw.fdwowner) AS \"%s\",\n",
03892 gettext_noop("Name"),
03893 gettext_noop("Owner"));
03894 if (pset.sversion >= 90100)
03895 appendPQExpBuffer(&buf,
03896 " fdw.fdwhandler::pg_catalog.regproc AS \"%s\",\n",
03897 gettext_noop("Handler"));
03898 appendPQExpBuffer(&buf,
03899 " fdw.fdwvalidator::pg_catalog.regproc AS \"%s\"",
03900 gettext_noop("Validator"));
03901
03902 if (verbose)
03903 {
03904 appendPQExpBuffer(&buf, ",\n ");
03905 printACLColumn(&buf, "fdwacl");
03906 appendPQExpBuffer(&buf,
03907 ",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
03908 " '(' || array_to_string(ARRAY(SELECT "
03909 " quote_ident(option_name) || ' ' || "
03910 " quote_literal(option_value) FROM "
03911 " pg_options_to_table(fdwoptions)), ', ') || ')' "
03912 " END AS \"%s\"",
03913 gettext_noop("FDW Options"));
03914
03915 if (pset.sversion >= 90100)
03916 appendPQExpBuffer(&buf,
03917 ",\n d.description AS \"%s\" ",
03918 gettext_noop("Description"));
03919 }
03920
03921 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper fdw\n");
03922
03923 if (verbose && pset.sversion >= 90100)
03924 appendPQExpBuffer(&buf,
03925 "LEFT JOIN pg_catalog.pg_description d\n"
03926 " ON d.classoid = fdw.tableoid "
03927 "AND d.objoid = fdw.oid AND d.objsubid = 0\n");
03928
03929 processSQLNamePattern(pset.db, &buf, pattern, false, false,
03930 NULL, "fdwname", NULL, NULL);
03931
03932 appendPQExpBuffer(&buf, "ORDER BY 1;");
03933
03934 res = PSQLexec(buf.data, false);
03935 termPQExpBuffer(&buf);
03936 if (!res)
03937 return false;
03938
03939 myopt.nullPrint = NULL;
03940 myopt.title = _("List of foreign-data wrappers");
03941 myopt.translate_header = true;
03942
03943 printQuery(res, &myopt, pset.queryFout, pset.logfile);
03944
03945 PQclear(res);
03946 return true;
03947 }
03948
03949
03950
03951
03952
03953
03954 bool
03955 listForeignServers(const char *pattern, bool verbose)
03956 {
03957 PQExpBufferData buf;
03958 PGresult *res;
03959 printQueryOpt myopt = pset.popt;
03960
03961 if (pset.sversion < 80400)
03962 {
03963 psql_error("The server (version %d.%d) does not support foreign servers.\n",
03964 pset.sversion / 10000, (pset.sversion / 100) % 100);
03965 return true;
03966 }
03967
03968 initPQExpBuffer(&buf);
03969 printfPQExpBuffer(&buf,
03970 "SELECT s.srvname AS \"%s\",\n"
03971 " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
03972 " f.fdwname AS \"%s\"",
03973 gettext_noop("Name"),
03974 gettext_noop("Owner"),
03975 gettext_noop("Foreign-data wrapper"));
03976
03977 if (verbose)
03978 {
03979 appendPQExpBuffer(&buf, ",\n ");
03980 printACLColumn(&buf, "s.srvacl");
03981 appendPQExpBuffer(&buf,
03982 ",\n"
03983 " s.srvtype AS \"%s\",\n"
03984 " s.srvversion AS \"%s\",\n"
03985 " CASE WHEN srvoptions IS NULL THEN '' ELSE "
03986 " '(' || array_to_string(ARRAY(SELECT "
03987 " quote_ident(option_name) || ' ' || "
03988 " quote_literal(option_value) FROM "
03989 " pg_options_to_table(srvoptions)), ', ') || ')' "
03990 " END AS \"%s\",\n"
03991 " d.description AS \"%s\"",
03992 gettext_noop("Type"),
03993 gettext_noop("Version"),
03994 gettext_noop("FDW Options"),
03995 gettext_noop("Description"));
03996 }
03997
03998 appendPQExpBuffer(&buf,
03999 "\nFROM pg_catalog.pg_foreign_server s\n"
04000 " JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
04001
04002 if (verbose)
04003 appendPQExpBuffer(&buf,
04004 "LEFT JOIN pg_description d\n "
04005 "ON d.classoid = s.tableoid AND d.objoid = s.oid "
04006 "AND d.objsubid = 0\n");
04007
04008 processSQLNamePattern(pset.db, &buf, pattern, false, false,
04009 NULL, "s.srvname", NULL, NULL);
04010
04011 appendPQExpBuffer(&buf, "ORDER BY 1;");
04012
04013 res = PSQLexec(buf.data, false);
04014 termPQExpBuffer(&buf);
04015 if (!res)
04016 return false;
04017
04018 myopt.nullPrint = NULL;
04019 myopt.title = _("List of foreign servers");
04020 myopt.translate_header = true;
04021
04022 printQuery(res, &myopt, pset.queryFout, pset.logfile);
04023
04024 PQclear(res);
04025 return true;
04026 }
04027
04028
04029
04030
04031
04032
04033 bool
04034 listUserMappings(const char *pattern, bool verbose)
04035 {
04036 PQExpBufferData buf;
04037 PGresult *res;
04038 printQueryOpt myopt = pset.popt;
04039
04040 if (pset.sversion < 80400)
04041 {
04042 psql_error("The server (version %d.%d) does not support user mappings.\n",
04043 pset.sversion / 10000, (pset.sversion / 100) % 100);
04044 return true;
04045 }
04046
04047 initPQExpBuffer(&buf);
04048 printfPQExpBuffer(&buf,
04049 "SELECT um.srvname AS \"%s\",\n"
04050 " um.usename AS \"%s\"",
04051 gettext_noop("Server"),
04052 gettext_noop("User name"));
04053
04054 if (verbose)
04055 appendPQExpBuffer(&buf,
04056 ",\n CASE WHEN umoptions IS NULL THEN '' ELSE "
04057 " '(' || array_to_string(ARRAY(SELECT "
04058 " quote_ident(option_name) || ' ' || "
04059 " quote_literal(option_value) FROM "
04060 " pg_options_to_table(umoptions)), ', ') || ')' "
04061 " END AS \"%s\"",
04062 gettext_noop("FDW Options"));
04063
04064 appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_user_mappings um\n");
04065
04066 processSQLNamePattern(pset.db, &buf, pattern, false, false,
04067 NULL, "um.srvname", "um.usename", NULL);
04068
04069 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
04070
04071 res = PSQLexec(buf.data, false);
04072 termPQExpBuffer(&buf);
04073 if (!res)
04074 return false;
04075
04076 myopt.nullPrint = NULL;
04077 myopt.title = _("List of user mappings");
04078 myopt.translate_header = true;
04079
04080 printQuery(res, &myopt, pset.queryFout, pset.logfile);
04081
04082 PQclear(res);
04083 return true;
04084 }
04085
04086
04087
04088
04089
04090
04091 bool
04092 listForeignTables(const char *pattern, bool verbose)
04093 {
04094 PQExpBufferData buf;
04095 PGresult *res;
04096 printQueryOpt myopt = pset.popt;
04097
04098 if (pset.sversion < 90100)
04099 {
04100 psql_error("The server (version %d.%d) does not support foreign tables.\n",
04101 pset.sversion / 10000, (pset.sversion / 100) % 100);
04102 return true;
04103 }
04104
04105 initPQExpBuffer(&buf);
04106 printfPQExpBuffer(&buf,
04107 "SELECT n.nspname AS \"%s\",\n"
04108 " c.relname AS \"%s\",\n"
04109 " s.srvname AS \"%s\"",
04110 gettext_noop("Schema"),
04111 gettext_noop("Table"),
04112 gettext_noop("Server"));
04113
04114 if (verbose)
04115 appendPQExpBuffer(&buf,
04116 ",\n CASE WHEN ftoptions IS NULL THEN '' ELSE "
04117 " '(' || array_to_string(ARRAY(SELECT "
04118 " quote_ident(option_name) || ' ' || "
04119 " quote_literal(option_value) FROM "
04120 " pg_options_to_table(ftoptions)), ', ') || ')' "
04121 " END AS \"%s\",\n"
04122 " d.description AS \"%s\"",
04123 gettext_noop("FDW Options"),
04124 gettext_noop("Description"));
04125
04126 appendPQExpBuffer(&buf,
04127 "\nFROM pg_catalog.pg_foreign_table ft\n"
04128 " INNER JOIN pg_catalog.pg_class c"
04129 " ON c.oid = ft.ftrelid\n"
04130 " INNER JOIN pg_catalog.pg_namespace n"
04131 " ON n.oid = c.relnamespace\n"
04132 " INNER JOIN pg_catalog.pg_foreign_server s"
04133 " ON s.oid = ft.ftserver\n");
04134 if (verbose)
04135 appendPQExpBuffer(&buf,
04136 " LEFT JOIN pg_catalog.pg_description d\n"
04137 " ON d.classoid = c.tableoid AND "
04138 "d.objoid = c.oid AND d.objsubid = 0\n");
04139
04140 processSQLNamePattern(pset.db, &buf, pattern, false, false,
04141 NULL, "n.nspname", "c.relname", NULL);
04142
04143 appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
04144
04145 res = PSQLexec(buf.data, false);
04146 termPQExpBuffer(&buf);
04147 if (!res)
04148 return false;
04149
04150 myopt.nullPrint = NULL;
04151 myopt.title = _("List of foreign tables");
04152 myopt.translate_header = true;
04153
04154 printQuery(res, &myopt, pset.queryFout, pset.logfile);
04155
04156 PQclear(res);
04157 return true;
04158 }
04159
04160
04161
04162
04163
04164
04165 bool
04166 listExtensions(const char *pattern)
04167 {
04168 PQExpBufferData buf;
04169 PGresult *res;
04170 printQueryOpt myopt = pset.popt;
04171
04172 if (pset.sversion < 90100)
04173 {
04174 psql_error("The server (version %d.%d) does not support extensions.\n",
04175 pset.sversion / 10000, (pset.sversion / 100) % 100);
04176 return true;
04177 }
04178
04179 initPQExpBuffer(&buf);
04180 printfPQExpBuffer(&buf,
04181 "SELECT e.extname AS \"%s\", "
04182 "e.extversion AS \"%s\", n.nspname AS \"%s\", c.description AS \"%s\"\n"
04183 "FROM pg_catalog.pg_extension e "
04184 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace "
04185 "LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid "
04186 "AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass\n",
04187 gettext_noop("Name"),
04188 gettext_noop("Version"),
04189 gettext_noop("Schema"),
04190 gettext_noop("Description"));
04191
04192 processSQLNamePattern(pset.db, &buf, pattern,
04193 false, false,
04194 NULL, "e.extname", NULL,
04195 NULL);
04196
04197 appendPQExpBuffer(&buf, "ORDER BY 1;");
04198
04199 res = PSQLexec(buf.data, false);
04200 termPQExpBuffer(&buf);
04201 if (!res)
04202 return false;
04203
04204 myopt.nullPrint = NULL;
04205 myopt.title = _("List of installed extensions");
04206 myopt.translate_header = true;
04207
04208 printQuery(res, &myopt, pset.queryFout, pset.logfile);
04209
04210 PQclear(res);
04211 return true;
04212 }
04213
04214
04215
04216
04217
04218
04219 bool
04220 listExtensionContents(const char *pattern)
04221 {
04222 PQExpBufferData buf;
04223 PGresult *res;
04224 int i;
04225
04226 if (pset.sversion < 90100)
04227 {
04228 psql_error("The server (version %d.%d) does not support extensions.\n",
04229 pset.sversion / 10000, (pset.sversion / 100) % 100);
04230 return true;
04231 }
04232
04233 initPQExpBuffer(&buf);
04234 printfPQExpBuffer(&buf,
04235 "SELECT e.extname, e.oid\n"
04236 "FROM pg_catalog.pg_extension e\n");
04237
04238 processSQLNamePattern(pset.db, &buf, pattern,
04239 false, false,
04240 NULL, "e.extname", NULL,
04241 NULL);
04242
04243 appendPQExpBuffer(&buf, "ORDER BY 1;");
04244
04245 res = PSQLexec(buf.data, false);
04246 termPQExpBuffer(&buf);
04247 if (!res)
04248 return false;
04249
04250 if (PQntuples(res) == 0)
04251 {
04252 if (!pset.quiet)
04253 {
04254 if (pattern)
04255 psql_error("Did not find any extension named \"%s\".\n",
04256 pattern);
04257 else
04258 psql_error("Did not find any extensions.\n");
04259 }
04260 PQclear(res);
04261 return false;
04262 }
04263
04264 for (i = 0; i < PQntuples(res); i++)
04265 {
04266 const char *extname;
04267 const char *oid;
04268
04269 extname = PQgetvalue(res, i, 0);
04270 oid = PQgetvalue(res, i, 1);
04271
04272 if (!listOneExtensionContents(extname, oid))
04273 {
04274 PQclear(res);
04275 return false;
04276 }
04277 if (cancel_pressed)
04278 {
04279 PQclear(res);
04280 return false;
04281 }
04282 }
04283
04284 PQclear(res);
04285 return true;
04286 }
04287
04288 static bool
04289 listOneExtensionContents(const char *extname, const char *oid)
04290 {
04291 PQExpBufferData buf;
04292 PGresult *res;
04293 char title[1024];
04294 printQueryOpt myopt = pset.popt;
04295
04296 initPQExpBuffer(&buf);
04297 printfPQExpBuffer(&buf,
04298 "SELECT pg_catalog.pg_describe_object(classid, objid, 0) AS \"%s\"\n"
04299 "FROM pg_catalog.pg_depend\n"
04300 "WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass AND refobjid = '%s' AND deptype = 'e'\n"
04301 "ORDER BY 1;",
04302 gettext_noop("Object Description"),
04303 oid);
04304
04305 res = PSQLexec(buf.data, false);
04306 termPQExpBuffer(&buf);
04307 if (!res)
04308 return false;
04309
04310 myopt.nullPrint = NULL;
04311 snprintf(title, sizeof(title), _("Objects in extension \"%s\""), extname);
04312 myopt.title = title;
04313 myopt.translate_header = true;
04314
04315 printQuery(res, &myopt, pset.queryFout, pset.logfile);
04316
04317 PQclear(res);
04318 return true;
04319 }
04320
04321
04322
04323
04324
04325
04326
04327
04328 static void
04329 printACLColumn(PQExpBuffer buf, const char *colname)
04330 {
04331 if (pset.sversion >= 80100)
04332 appendPQExpBuffer(buf,
04333 "pg_catalog.array_to_string(%s, E'\\n') AS \"%s\"",
04334 colname, gettext_noop("Access privileges"));
04335 else
04336 appendPQExpBuffer(buf,
04337 "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"",
04338 colname, gettext_noop("Access privileges"));
04339 }