📄 describe.c
字号:
" 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.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", _("function")); processNamePattern(&buf, pattern, true, false, "n.nspname", "p.proname", NULL, "pg_catalog.pg_function_is_visible(p.oid)"); /* Operator descriptions (only if operator has its own comment) */ appendPQExpBuffer(&buf, "UNION ALL\n" " SELECT o.oid as oid, o.tableoid as tableoid,\n" " n.nspname as nspname,\n" " CAST(o.oprname AS pg_catalog.text) as name," " CAST('%s' AS pg_catalog.text) as object\n" " FROM pg_catalog.pg_operator o\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n", _("operator")); processNamePattern(&buf, pattern, false, false, "n.nspname", "o.oprname", NULL, "pg_catalog.pg_operator_is_visible(o.oid)"); /* Type description */ appendPQExpBuffer(&buf, "UNION ALL\n" " SELECT t.oid as oid, t.tableoid as tableoid,\n" " n.nspname as nspname,\n" " pg_catalog.format_type(t.oid, NULL) as name," " CAST('%s' AS pg_catalog.text) as object\n" " FROM pg_catalog.pg_type t\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n", _("data type")); processNamePattern(&buf, pattern, false, false, "n.nspname", "pg_catalog.format_type(t.oid, NULL)", NULL, "pg_catalog.pg_type_is_visible(t.oid)"); /* Relation (tables, views, indexes, sequences) descriptions */ appendPQExpBuffer(&buf, "UNION ALL\n" " SELECT c.oid as oid, c.tableoid as tableoid,\n" " n.nspname as nspname,\n" " CAST(c.relname AS pg_catalog.text) as name,\n" " CAST(\n" " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'i' THEN '%s' WHEN 'S' THEN '%s' END" " AS pg_catalog.text) as object\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', 'i', 'S')\n", _("table"), _("view"), _("index"), _("sequence")); processNamePattern(&buf, pattern, true, false, "n.nspname", "c.relname", NULL, "pg_catalog.pg_table_is_visible(c.oid)"); /* Rule description (ignore rules for views) */ appendPQExpBuffer(&buf, "UNION ALL\n" " SELECT r.oid as oid, r.tableoid as tableoid,\n" " n.nspname as nspname,\n" " CAST(r.rulename AS pg_catalog.text) as name," " CAST('%s' AS pg_catalog.text) as object\n" " FROM pg_catalog.pg_rewrite r\n" " JOIN pg_catalog.pg_class c ON c.oid = r.ev_class\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" " WHERE r.rulename != '_RETURN'\n", _("rule")); /* XXX not sure what to do about visibility rule here? */ processNamePattern(&buf, pattern, true, false, "n.nspname", "r.rulename", NULL, "pg_catalog.pg_table_is_visible(c.oid)"); /* Trigger description */ appendPQExpBuffer(&buf, "UNION ALL\n" " SELECT t.oid as oid, t.tableoid as tableoid,\n" " n.nspname as nspname,\n" " CAST(t.tgname AS pg_catalog.text) as name," " CAST('%s' AS pg_catalog.text) as object\n" " FROM pg_catalog.pg_trigger t\n" " JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n", _("trigger")); /* XXX not sure what to do about visibility rule here? */ processNamePattern(&buf, pattern, false, false, "n.nspname", "t.tgname", NULL, "pg_catalog.pg_table_is_visible(c.oid)"); appendPQExpBuffer(&buf, ") AS tt\n" " JOIN pg_catalog.pg_description d ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)\n"); appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;"); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = _("Object descriptions"); printQuery(res, &myopt, pset.queryFout, pset.logfile); PQclear(res); return true;}/* * describeTableDetails (for \d) * * This routine finds the tables to be displayed, and calls * describeOneTableDetails for each one. * * verbose: if true, this is \d+ */booldescribeTableDetails(const char *pattern, bool verbose){ PQExpBufferData buf; PGresult *res; int i; initPQExpBuffer(&buf); printfPQExpBuffer(&buf, "SELECT c.oid,\n" " n.nspname,\n" " c.relname\n" "FROM pg_catalog.pg_class c\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"); processNamePattern(&buf, pattern, false, false, "n.nspname", "c.relname", NULL, "pg_catalog.pg_table_is_visible(c.oid)"); appendPQExpBuffer(&buf, "ORDER BY 2, 3;"); res = PSQLexec(buf.data, false); termPQExpBuffer(&buf); if (!res) return false; if (PQntuples(res) == 0) { if (!QUIET()) fprintf(stderr, _("Did not find any relation named \"%s\".\n"), pattern); PQclear(res); return false; } for (i = 0; i < PQntuples(res); i++) { const char *oid; const char *nspname; const char *relname; oid = PQgetvalue(res, i, 0); nspname = PQgetvalue(res, i, 1); relname = PQgetvalue(res, i, 2); if (!describeOneTableDetails(nspname, relname, oid, verbose)) { PQclear(res); return false; } } PQclear(res); return true;}/* * describeOneTableDetails (for \d) * * Unfortunately, the information presented here is so complicated that it * cannot be done in a single query. So we have to assemble the printed table * by hand and pass it to the underlying printTable() function. */static booldescribeOneTableDetails(const char *schemaname, const char *relationname, const char *oid, bool verbose){ PQExpBufferData buf; PGresult *res = NULL; printTableOpt myopt = pset.popt.topt; int i; char *view_def = NULL; const char *headers[5]; char **cells = NULL; char **footers = NULL; char **ptr; PQExpBufferData title; PQExpBufferData tmpbuf; int cols = 0; int numrows = 0; struct { int16 checks; int16 triggers; char relkind; bool hasindex; bool hasrules; bool hasoids; Oid tablespace; } tableinfo; bool show_modifiers = false; bool retval; retval = false; /* This output looks confusing in expanded mode. */ myopt.expanded = false; initPQExpBuffer(&buf); initPQExpBuffer(&title); initPQExpBuffer(&tmpbuf); /* Get general table info */ printfPQExpBuffer(&buf, "SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules, \n" "relhasoids %s \n" "FROM pg_catalog.pg_class WHERE oid = '%s'", pset.sversion >= 80000 ? ", reltablespace" : "", oid); res = PSQLexec(buf.data, false); if (!res) goto error_return; /* Did we get anything? */ if (PQntuples(res) == 0) { if (!QUIET()) fprintf(stderr, _("Did not find any relation with OID %s.\n"), oid); goto error_return; } /* FIXME: check for null pointers here? */ tableinfo.checks = atoi(PQgetvalue(res, 0, 2)); tableinfo.triggers = atoi(PQgetvalue(res, 0, 3)); tableinfo.relkind = *(PQgetvalue(res, 0, 1)); tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 0), "t") == 0; tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 4), "t") == 0; tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 5), "t") == 0; tableinfo.tablespace = (pset.sversion >= 80000) ? atooid(PQgetvalue(res, 0, 6)) : 0; PQclear(res); headers[0] = _("Column"); headers[1] = _("Type"); cols = 2; if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v') { show_modifiers = true; cols++; headers[cols - 1] = _("Modifiers"); } if (verbose) { cols++; headers[cols - 1] = _("Description"); } headers[cols] = NULL; /* Get column info (index requires additional checks) */ printfPQExpBuffer(&buf, "SELECT a.attname,"); appendPQExpBuffer(&buf, "\n pg_catalog.format_type(a.atttypid, a.atttypmod)," "\n (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)" "\n FROM pg_catalog.pg_attrdef d" "\n WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)," "\n a.attnotnull, a.attnum"); if (verbose) appendPQExpBuffer(&buf, ", pg_catalog.col_description(a.attrelid, a.attnum)"); appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_attribute a"); if (tableinfo.relkind == 'i') appendPQExpBuffer(&buf, ", pg_catalog.pg_index i"); appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid); if (tableinfo.relkind == 'i') appendPQExpBuffer(&buf, " AND a.attrelid = i.indexrelid"); appendPQExpBuffer(&buf, "\nORDER BY a.attnum"); res = PSQLexec(buf.data, false); if (!res) goto error_return; numrows = PQntuples(res); /* Check if table is a view */ if (tableinfo.relkind == 'v') { PGresult *result; printfPQExpBuffer(&buf, "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true)", oid); result = PSQLexec(buf.data, false); if (!result) goto error_return; if (PQntuples(result) > 0) view_def = pg_strdup(PQgetvalue(result, 0, 0)); PQclear(result); } /* Generate table cells to be printed */ /* note: initialize all cells[] to NULL in case of error exit */ cells = pg_malloc_zero((numrows * cols + 1) * sizeof(*cells)); for (i = 0; i < numrows; i++) { /* Name */#ifdef WIN32 cells[i * cols + 0] = mbvalidate(PQgetvalue(res, i, 0), myopt.encoding);#else cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this * afterwards */#endif /* Type */#ifdef WIN32 cells[i * cols + 1] = mbvalidate(PQgetvalue(res, i, 1), myopt.encoding);#else cells[i * cols + 1] = PQgetvalue(res, i, 1); /* don't free this * either */#endif /* Extra: not null and default */ if (show_modifiers) { resetPQExpBuffer(&tmpbuf); if (strcmp(PQgetvalue(res, i, 3), "t") == 0) appendPQExpBufferStr(&tmpbuf, "not null"); /* handle "default" here */ /* (note: above we cut off the 'default' string at 128) */ if (strlen(PQgetvalue(res, i, 2)) != 0) { if (tmpbuf.len > 0) appendPQExpBufferStr(&tmpbuf, " "); appendPQExpBuffer(&tmpbuf, "default %s", PQgetvalue(res, i, 2)); }#ifdef WIN32 cells[i * cols + 2] = pg_strdup(mbvalidate(tmpbuf.data, myopt.encoding));#else cells[i * cols + 2] = pg_strdup(tmpbuf.data);#endif } /* Description */ if (verbose)#ifdef WIN32 cells[i * cols + cols - 1] = mbvalidate(PQgetvalue(res, i, 5), myopt.encoding);#else cells[i * cols + cols - 1] = PQgetvalue(res, i, 5);#endif } /* Make title */ switch (tableinfo.relkind) { case 'r': printfPQExpBuffer(&title, _("Table \"%s.%s\""), schemaname, relationname); break; case 'v': printfPQExpBuffer(&title, _("View \"%s.%s\""), schemaname, relationname); break; case 'S': printfPQExpBuffer(&title, _("Sequence \"%s.%s\""), schemaname, relationname); break; case 'i': printfPQExpBuffer(&title, _("Index \"%s.%s\""), schemaname, relationname); break; case 's': printfPQExpBuffer(&title, _("Special relation \"%s.%s\""), schemaname, relationname); break; case 't': printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""), schemaname, relationname); break; case 'c': printfPQExpBuffer(&title, _("Composite type \"%s.%s\""), schemaname, relationname); break; default: printfPQExpBuffer(&title, _("?%c? \"%s.%s\""), tableinfo.relkind, schemaname, relationname); break; } /* Make footers */ if (tableinfo.relkind == 'i') { /* Footer information about an index */ PGresult *result; printfPQExpBuffer(&buf, "SELECT i.indisunique, i.indisprimary, i.indisclustered, a.amname, c2.relname,\n" " pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n" "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n" "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n" "AND i.indrelid = c2.oid", oid); result = PSQLexec(buf.data, false); if (!result) goto error_return; else if (PQntuples(result) != 1) { PQclear(result); goto error_return; } else { char *indisunique = PQgetvalue(result, 0, 0); char *indisprimary = PQgetvalue(result, 0, 1); char *indisclustered = PQgetvalue(result, 0, 2); char *indamname = PQgetvalue(result, 0, 3); char *indtable = PQgetvalue(result, 0, 4); char *indpred = PQgetvalue(result, 0, 5); int count_footers = 0; if (strcmp(indisprimary, "t") == 0) printfPQExpBuffer(&tmpbuf, _("primary key, ")); else if (strcmp(indisunique, "t") == 0) printfPQExpBuffer(&tmpbuf, _("unique, ")); else resetPQExpBuffer(&tmpbuf); appendPQExpBuffer(&tmpbuf, "%s, ", indamname); /* we assume here that index and table are in same schema */ appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""), schemaname, indtable); if (strlen(indpred)) appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred); if (strcmp(indisclustered, "t") == 0) appendPQExpBuffer(&tmpbuf, _(", clustered")); footers = pg_malloc_zero(4 * sizeof(*footers)); footers[count_footers++] = pg_strdup(tmpbuf.data); add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace, footers, &count_footers, tmpbuf, true); footers[count_footers] = NULL; } PQclear(result); } else if (view_def) { PGresult *result = NULL; int rule_count = 0; int count_footers = 0; /* count rules other than the view rule */ if (tableinfo.hasrules) { printfPQExpBuffer(&buf, "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))\n" "FROM pg_catalog.pg_rewrite r\n" "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN' ORDER BY 1", oid);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -