📄 describe.c
字号:
/* * psql - the PostgreSQL interactive terminal * * Copyright (c) 2000-2005, PostgreSQL Global Development Group * * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.129.2.2 2006/03/02 19:40:29 momjian Exp $ */#include "postgres_fe.h"#include "describe.h"#include "libpq-fe.h"#include "pqexpbuffer.h"#include "common.h"#include "settings.h"#include "print.h"#include "variables.h"#include <ctype.h>#ifdef WIN32/* * mbvalidate() is used in function describeOneTableDetails() to make sure * all characters of the cells will be printed to the DOS console in a * correct way */#include "mbprint.h"#endifstatic bool describeOneTableDetails(const char *schemaname, const char *relationname, const char *oid, bool verbose);static void processNamePattern(PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule);static bool add_tablespace_footer(char relkind, Oid tablespace, char **footers, int *count, PQExpBufferData buf, bool newline);/*---------------- * Handlers for various slash commands displaying some sort of list * of things in the database. * * If you add something here, try to format the query to look nice in -E output. *---------------- *//* \da * Takes an optional regexp to select particular aggregates */booldescribeAggregates(const char *pattern, bool verbose){ PQExpBufferData buf; PGresult *res; printQueryOpt myopt = pset.popt; initPQExpBuffer(&buf); /* * There are two kinds of aggregates: ones that work on particular types * and ones that work on all (denoted by input type = "any") */ printfPQExpBuffer(&buf, "SELECT n.nspname as \"%s\",\n" " p.proname AS \"%s\",\n" " CASE p.proargtypes[0]\n" " WHEN 'pg_catalog.\"any\"'::pg_catalog.regtype\n" " THEN CAST('%s' AS pg_catalog.text)\n" " ELSE pg_catalog.format_type(p.proargtypes[0], NULL)\n" " END AS \"%s\",\n" " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n" "FROM pg_catalog.pg_proc p\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n" "WHERE p.proisagg\n", _("Schema"), _("Name"), _("(all types)"), _("Data type"), _("Description")); processNamePattern(&buf, pattern, true, false, "n.nspname", "p.proname", NULL, "pg_catalog.pg_function_is_visible(p.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;"); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = _("List of aggregate functions"); printQuery(res, &myopt, pset.queryFout, pset.logfile); PQclear(res); return true;}/* \db * Takes an optional regexp to select particular tablespaces */booldescribeTablespaces(const char *pattern, bool verbose){ PQExpBufferData buf; PGresult *res; printQueryOpt myopt = pset.popt; if (pset.sversion < 80000) { fprintf(stderr, _("The server version (%d) does not support tablespaces.\n"), pset.sversion); return true; } initPQExpBuffer(&buf); printfPQExpBuffer(&buf, "SELECT spcname AS \"%s\",\n" " pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n" " spclocation AS \"%s\"", _("Name"), _("Owner"), _("Location")); if (verbose) appendPQExpBuffer(&buf, ",\n spcacl as \"%s\"", _("Access privileges")); appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_tablespace\n"); processNamePattern(&buf, pattern, false, false, NULL, "spcname", NULL, NULL); appendPQExpBuffer(&buf, "ORDER BY 1;"); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = _("List of tablespaces"); printQuery(res, &myopt, pset.queryFout, pset.logfile); PQclear(res); return true;}/* \df * Takes an optional regexp to select particular functions */booldescribeFunctions(const char *pattern, bool verbose){ PQExpBufferData buf; PGresult *res; printQueryOpt myopt = pset.popt; initPQExpBuffer(&buf); printfPQExpBuffer(&buf, "SELECT n.nspname as \"%s\",\n" " p.proname as \"%s\",\n" " CASE WHEN p.proretset THEN 'setof ' ELSE '' END ||\n" " pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n" " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\"", _("Schema"), _("Name"), _("Result data type"), _("Argument data types")); if (verbose) appendPQExpBuffer(&buf, ",\n r.rolname as \"%s\",\n" " l.lanname as \"%s\",\n" " p.prosrc as \"%s\",\n" " pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"", _("Owner"), _("Language"), _("Source code"), _("Description")); if (!verbose) appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_proc p" "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"); else appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_proc p" "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace" "\n LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang" "\n JOIN pg_catalog.pg_roles r ON r.oid = p.proowner\n"); /* * we skip in/out funcs by excluding functions that take or return cstring */ appendPQExpBuffer(&buf, "WHERE p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype\n" " AND (p.proargtypes[0] IS NULL\n" " OR p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype)\n" " AND NOT p.proisagg\n"); processNamePattern(&buf, pattern, true, false, "n.nspname", "p.proname", NULL, "pg_catalog.pg_function_is_visible(p.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;"); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = _("List of functions"); printQuery(res, &myopt, pset.queryFout, pset.logfile); PQclear(res); return true;}/* * \dT * describe types */booldescribeTypes(const char *pattern, bool verbose){ PQExpBufferData buf; PGresult *res; printQueryOpt myopt = pset.popt; initPQExpBuffer(&buf); printfPQExpBuffer(&buf, "SELECT n.nspname as \"%s\",\n" " pg_catalog.format_type(t.oid, NULL) AS \"%s\",\n", _("Schema"), _("Name")); if (verbose) appendPQExpBuffer(&buf, " t.typname AS \"%s\",\n" " CASE WHEN t.typrelid != 0\n" " THEN CAST('tuple' AS pg_catalog.text)\n" " WHEN t.typlen < 0\n" " THEN CAST('var' AS pg_catalog.text)\n" " ELSE CAST(t.typlen AS pg_catalog.text)\n" " END AS \"%s\",\n", _("Internal name"), _("Size")); appendPQExpBuffer(&buf, " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n", _("Description")); appendPQExpBuffer(&buf, "FROM pg_catalog.pg_type t\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n"); /* * do not include array types (start with underscore); do not include * complex types (typrelid!=0) unless they are standalone composite types */ appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 "); appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c " "WHERE c.oid = t.typrelid)) "); appendPQExpBuffer(&buf, "AND t.typname !~ '^_'\n"); /* Match name pattern against either internal or external name */ processNamePattern(&buf, pattern, true, false, "n.nspname", "t.typname", "pg_catalog.format_type(t.oid, NULL)", "pg_catalog.pg_type_is_visible(t.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = _("List of data types"); printQuery(res, &myopt, pset.queryFout, pset.logfile); PQclear(res); return true;}/* \do */booldescribeOperators(const char *pattern){ PQExpBufferData buf; PGresult *res; printQueryOpt myopt = pset.popt; initPQExpBuffer(&buf); printfPQExpBuffer(&buf, "SELECT n.nspname as \"%s\",\n" " o.oprname AS \"%s\",\n" " CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n" " CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n" " pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n" " coalesce(pg_catalog.obj_description(o.oid, 'pg_operator'),\n" " pg_catalog.obj_description(o.oprcode, 'pg_proc')) AS \"%s\"\n" "FROM pg_catalog.pg_operator o\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n", _("Schema"), _("Name"), _("Left arg type"), _("Right arg type"), _("Result type"), _("Description")); processNamePattern(&buf, pattern, false, true, "n.nspname", "o.oprname", NULL, "pg_catalog.pg_operator_is_visible(o.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;"); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = _("List of operators"); printQuery(res, &myopt, pset.queryFout, pset.logfile); PQclear(res); return true;}/* * listAllDbs * * for \l, \list, and -l switch */boollistAllDbs(bool verbose){ PGresult *res; PQExpBufferData buf; printQueryOpt myopt = pset.popt; initPQExpBuffer(&buf); printfPQExpBuffer(&buf, "SELECT d.datname as \"%s\",\n" " r.rolname as \"%s\"", _("Name"), _("Owner")); appendPQExpBuffer(&buf, ",\n pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\"", _("Encoding")); if (verbose) appendPQExpBuffer(&buf, ",\n pg_catalog.obj_description(d.oid, 'pg_database') as \"%s\"", _("Description")); appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_database d" "\n JOIN pg_catalog.pg_roles r ON d.datdba = r.oid\n" "ORDER BY 1;"); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = _("List of databases"); printQuery(res, &myopt, pset.queryFout, pset.logfile); PQclear(res); return true;}/* * List Tables Grant/Revoke Permissions * \z (now also \dp -- perhaps more mnemonic) */boolpermissionsList(const char *pattern){ PQExpBufferData buf; PGresult *res; printQueryOpt myopt = pset.popt; initPQExpBuffer(&buf); /* * we ignore indexes and toast tables since they have no meaningful rights */ printfPQExpBuffer(&buf, "SELECT n.nspname as \"%s\",\n" " c.relname as \"%s\",\n" " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \"%s\",\n" " c.relacl as \"%s\"\n" "FROM pg_catalog.pg_class c\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" "WHERE c.relkind IN ('r', 'v', 'S')\n", _("Schema"), _("Name"), _("table"), _("view"), _("sequence"), _("Type"), _("Access privileges")); /* * Unless a schema pattern is specified, we suppress system and temp * tables, since they normally aren't very interesting from a permissions * point of view. You can see 'em by explicit request though, eg with \z * pg_catalog.* */ processNamePattern(&buf, pattern, true, false, "n.nspname", "c.relname", NULL, "n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)"); appendPQExpBuffer(&buf, "ORDER BY 1, 2;"); res = PSQLexec(buf.data, false); if (!res) { termPQExpBuffer(&buf); return false; } myopt.nullPrint = NULL; printfPQExpBuffer(&buf, _("Access privileges for database \"%s\""), PQdb(pset.db)); myopt.title = buf.data; printQuery(res, &myopt, pset.queryFout, pset.logfile); termPQExpBuffer(&buf); PQclear(res); return true;}/* * Get object comments * * \dd [foo] * * Note: This only lists things that actually have a description. For complete * lists of things, there are other \d? commands. */boolobjectDescription(const char *pattern){ PQExpBufferData buf; PGresult *res; printQueryOpt myopt = pset.popt; initPQExpBuffer(&buf); appendPQExpBuffer(&buf, "SELECT DISTINCT tt.nspname AS \"%s\", tt.name AS \"%s\", tt.object AS \"%s\", d.description AS \"%s\"\n" "FROM (\n", _("Schema"), _("Name"), _("Object"), _("Description")); /* Aggregate descriptions */ appendPQExpBuffer(&buf, " SELECT p.oid as oid, p.tableoid as tableoid,\n" " n.nspname as nspname,\n" " CAST(p.proname AS pg_catalog.text) as name," " CAST('%s' AS pg_catalog.text) as object\n" " FROM pg_catalog.pg_proc p\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n" " WHERE p.proisagg\n", _("aggregate")); processNamePattern(&buf, pattern, true, false, "n.nspname", "p.proname", NULL, "pg_catalog.pg_function_is_visible(p.oid)"); /* Function descriptions (except in/outs for datatypes) */ appendPQExpBuffer(&buf, "UNION ALL\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -