From c8be51a52a381a6e9c7be62022f5fc48b5915bd0 Mon Sep 17 00:00:00 2001 From: Tatsuro Yamada Date: Thu, 7 Jan 2021 14:28:20 +0900 Subject: [PATCH] Add \dX command on psql This patch includes the version check in the logic building query. --- doc/src/sgml/ref/psql-ref.sgml | 14 ++++ src/bin/psql/command.c | 3 + src/bin/psql/describe.c | 141 +++++++++++++++++++++++++++++++++++++++++ src/bin/psql/describe.h | 3 + src/bin/psql/help.c | 1 + src/bin/psql/tab-complete.c | 4 +- 6 files changed, 165 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 221a967bfe..fd860776af 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1918,6 +1918,20 @@ testdb=> + + + \dX [ pattern ] + + + Lists extended statistics. + If pattern + is specified, only those extended statistics whose names match the pattern + are listed. + If + is appended to the command name, each extended statistics + is listed with its size. + + + \dy[+] [ pattern ] diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 303e7c3ad8..c5ebc1c3f4 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -928,6 +928,9 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) else success = listExtensions(pattern); break; + case 'X': /* Extended Statistics */ + success = listExtendedStats(pattern, show_verbose); + break; case 'y': /* Event Triggers */ success = listEventTriggers(pattern, show_verbose); break; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 52c6de51b6..0ccd9ed286 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -4401,6 +4401,147 @@ listEventTriggers(const char *pattern, bool verbose) return true; } +/* + * \dX + * + * Briefly describes extended statistics. + */ +bool +listExtendedStats(const char *pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + if (pset.sversion < 100000) + { + char sverbuf[32]; + + pg_log_error("The server (version %s) does not support extended statistics.", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); + return true; + } + + initPQExpBuffer(&buf); + printfPQExpBuffer(&buf, + "SELECT \n" + "es.stxnamespace::pg_catalog.regnamespace::text AS \"%s\", \n" + "es.stxname AS \"%s\", \n" + "pg_catalog.format('%%s FROM %%s', \n" + " (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(a.attname),', ') \n" + " FROM pg_catalog.unnest(es.stxkeys) s(attnum) \n" + " JOIN pg_catalog.pg_attribute a \n" + " ON (es.stxrelid = a.attrelid \n" + " AND a.attnum = s.attnum \n" + " AND NOT a.attisdropped)), \n" + "es.stxrelid::regclass) AS \"%s\"", + gettext_noop("Schema"), + gettext_noop("Name"), + gettext_noop("Definition")); + + if (pset.sversion < 120000) + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN es.stxndistinct IS NOT NULL THEN 'built' \n" + " WHEN 'd' = any(es.stxkind) THEN 'defined' \n" + "END AS \"%s\", \n" + "CASE WHEN es.stxdependencies IS NOT NULL THEN 'built' \n" + " WHEN 'f' = any(es.stxkind) THEN 'defined' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct"), + gettext_noop("Dependencies")); + } + else + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN esd.stxdndistinct IS NOT NULL THEN 'built' \n" + " WHEN 'd' = any(es.stxkind) THEN 'defined' \n" + "END AS \"%s\", \n" + "CASE WHEN esd.stxddependencies IS NOT NULL THEN 'built' \n" + " WHEN 'f' = any(es.stxkind) THEN 'defined' \n" + "END AS \"%s\", \n" + "CASE WHEN esd.stxdmcv IS NOT NULL THEN 'built' \n" + " WHEN 'm' = any(es.stxkind) THEN 'defined' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct"), + gettext_noop("Dependencies"), + gettext_noop("MCV")); + } + + if (verbose && pset.sversion < 120000) + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN es.stxndistinct IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(es.stxndistinct)::bigint) \n" + " WHEN 'd' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\", \n" + "CASE WHEN es.stxdependencies IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(es.stxdependencies)::bigint) \n" + " WHEN 'f' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct_size"), + gettext_noop("Dependencies_size")); + } + else if (verbose) + { + appendPQExpBuffer(&buf, + ",\nCASE WHEN esd.stxdndistinct IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxdndistinct)::bigint) \n" + " WHEN 'd' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\", \n" + "CASE WHEN esd.stxddependencies IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxddependencies)::bigint) \n" + " WHEN 'f' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\", \n" + "CASE WHEN esd.stxdmcv IS NOT NULL THEN \n" + " pg_catalog.pg_size_pretty(pg_catalog.length(esd.stxdmcv)::bigint) \n" + " WHEN 'm' = any(es.stxkind) THEN '0 bytes' \n" + "END AS \"%s\"", + gettext_noop("Ndistinct_size"), + gettext_noop("Dependencies_size"), + gettext_noop("MCV_size")); + } + + if (pset.sversion < 120000) + { + appendPQExpBufferStr(&buf, + " \nFROM pg_catalog.pg_statistic_ext es \n" + "INNER JOIN pg_catalog.pg_class c \n" + "ON es.stxrelid = c.oid \n"); + } + else + { + appendPQExpBufferStr(&buf, + " \nFROM pg_catalog.pg_statistic_ext es \n" + "LEFT JOIN pg_catalog.pg_statistic_ext_data esd \n" + "ON es.oid = esd.stxoid \n" + "INNER JOIN pg_catalog.pg_class c \n" + "ON es.stxrelid = c.oid \n"); + } + + processSQLNamePattern(pset.db, &buf, pattern, false, + false, NULL, + "stxname", NULL, + NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of extended statistics"); + myopt.translate_header = true; + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + /* * \dC * diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 6044e3a082..867e57d851 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -102,6 +102,9 @@ extern bool listExtensions(const char *pattern); /* \dx+ */ extern bool listExtensionContents(const char *pattern); +/* \dX */ +extern bool listExtendedStats(const char *pattern, bool verbose); + /* \dy */ extern bool listEventTriggers(const char *pattern, bool verbose); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 9ec1c4e810..e42bc8c54e 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -267,6 +267,7 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\du[S+] [PATTERN] list roles\n")); fprintf(output, _(" \\dv[S+] [PATTERN] list views\n")); fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n")); + fprintf(output, _(" \\dX[+] [PATTERN] list extended statistics\n")); fprintf(output, _(" \\dy [PATTERN] list event triggers\n")); fprintf(output, _(" \\l[+] [PATTERN] list databases\n")); fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n")); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 9dcab0d2fa..611f1efb15 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1500,7 +1500,7 @@ psql_completion(const char *text, int start, int end) "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", "\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt", "\\drds", "\\dRs", "\\dRp", "\\ds", "\\dS", - "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy", + "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy", "\\e", "\\echo", "\\ef", "\\elif", "\\else", "\\encoding", "\\endif", "\\errverbose", "\\ev", "\\f", @@ -3910,6 +3910,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); else if (TailMatchesCS("\\dx*")) COMPLETE_WITH_QUERY(Query_for_list_of_extensions); + else if (TailMatchesCS("\\dX*")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_statistics, NULL); else if (TailMatchesCS("\\dm*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); else if (TailMatchesCS("\\dE*")) -- 2.16.5