From 3e707fbb4009e9ac1d0e8b78b7af9f3f03f4cf1a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 7 Apr 2022 17:09:44 -0400 Subject: [PATCH] psql: add \dconfig command to show server's configuration parameters. Plain \dconfig is basically equivalent to SHOW except that you can give it a pattern with wildcards, either to match multiple GUCs or because you don't exactly remember the name you want. \dconfig+ adds type, context, and access-privilege information, mainly because every other kind of object privilege has a psql command to show it, so GUC privileges should too. (A form of this command was in some versions of the patch series leading up to commit a0ffa885e. We pulled it out then because of doubts that the design and code were up to snuff, but I think subsequent work has resolved that.) In passing, fix incorrect completion of GUC names in GRANT/REVOKE ON PARAMETER: a0ffa885e neglected to use the VERBATIM form of COMPLETE_WITH_QUERY, so it misbehaved for custom (qualified) GUC names. Mark Dilger and Tom Lane Discussion: https://postgr.es/m/3118455.1649267333@sss.pgh.pa.us --- doc/src/sgml/ddl.sgml | 2 +- doc/src/sgml/ref/psql-ref.sgml | 17 ++++++++ src/bin/psql/command.c | 9 ++++- src/bin/psql/describe.c | 62 ++++++++++++++++++++++++++++++ src/bin/psql/describe.h | 4 ++ src/bin/psql/help.c | 3 +- src/bin/psql/tab-complete.c | 7 +++- src/fe_utils/string_utils.c | 6 ++- src/test/regress/expected/psql.out | 17 ++++++++ src/test/regress/sql/psql.sql | 6 +++ 10 files changed, 127 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index 492a9602476..77ce39766c0 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -2205,7 +2205,7 @@ REVOKE ALL ON accounts FROM PUBLIC; PARAMETER sA none - none + \dconfig+ SCHEMA diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index f01adb1fd27..92e5c503003 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1380,6 +1380,23 @@ testdb=> + + \dconfig[+] [ pattern ] + + + Lists server configuration parameters and their values. + If pattern + is specified, only parameters whose names match the pattern are + listed. + If + is appended to the command name, each + parameter is listed with its data type, context in which the + parameter can be set, and access privileges (if non-default access + privileges have been granted). + + + + + \dC[+] [ pattern ] diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 079f4a1a76e..db071d561fe 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -780,7 +780,14 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) success = describeTablespaces(pattern, show_verbose); break; case 'c': - success = listConversions(pattern, show_verbose, show_system); + if (strncmp(cmd, "dconfig", 7) == 0) + success = describeConfigurationParameters(pattern, + show_verbose, + show_system); + else + success = listConversions(pattern, + show_verbose, + show_system); break; case 'C': success = listCasts(pattern, show_verbose); diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 3f1b3802c22..797ef233c90 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -4364,6 +4364,68 @@ listConversions(const char *pattern, bool verbose, bool showSystem) return true; } +/* + * \dconfig + * + * Describes configuration parameters. + */ +bool +describeConfigurationParameters(const char *pattern, bool verbose, + bool showSystem) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + initPQExpBuffer(&buf); + printfPQExpBuffer(&buf, + "SELECT s.name AS \"%s\", " + "pg_catalog.current_setting(s.name) AS \"%s\"", + gettext_noop("Parameter"), + gettext_noop("Value")); + + if (verbose) + { + appendPQExpBuffer(&buf, + ", s.vartype AS \"%s\", s.context AS \"%s\", ", + gettext_noop("Type"), + gettext_noop("Context")); + if (pset.sversion >= 150000) + printACLColumn(&buf, "p.paracl"); + else + appendPQExpBuffer(&buf, "NULL AS \"%s\"", + gettext_noop("Access privileges")); + } + + appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_settings s\n"); + + if (verbose && pset.sversion >= 150000) + appendPQExpBufferStr(&buf, + " LEFT JOIN pg_catalog.pg_parameter_acl p\n" + " ON pg_catalog.lower(s.name) = p.parname\n"); + + processSQLNamePattern(pset.db, &buf, pattern, + false, false, + NULL, "pg_catalog.lower(s.name)", NULL, + NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 1;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of configuration parameters"); + myopt.translate_header = true; + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + /* * \dy * diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index fd6079679c6..7872c71f58d 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -76,6 +76,10 @@ extern bool listDomains(const char *pattern, bool verbose, bool showSystem); /* \dc */ extern bool listConversions(const char *pattern, bool verbose, bool showSystem); +/* \dconfig */ +extern bool describeConfigurationParameters(const char *pattern, bool verbose, + bool showSystem); + /* \dC */ extern bool listCasts(const char *pattern, bool verbose); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index b3971bce64d..1d3601e5942 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -166,7 +166,7 @@ slashUsage(unsigned short int pager) * Use "psql --help=commands | wc" to count correctly. It's okay to count * the USE_READLINE line even in builds without that. */ - output = PageOutput(137, pager ? &(pset.popt.topt) : NULL); + output = PageOutput(138, pager ? &(pset.popt.topt) : NULL); fprintf(output, _("General\n")); fprintf(output, _(" \\copyright show PostgreSQL usage and distribution terms\n")); @@ -231,6 +231,7 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\dAp[+] [AMPTRN [OPFPTRN]] list support functions of operator families\n")); fprintf(output, _(" \\db[+] [PATTERN] list tablespaces\n")); fprintf(output, _(" \\dc[S+] [PATTERN] list conversions\n")); + fprintf(output, _(" \\dconfig[+] [PATTERN] list configuration parameters\n")); fprintf(output, _(" \\dC[+] [PATTERN] list casts\n")); fprintf(output, _(" \\dd[S] [PATTERN] show object descriptions not displayed elsewhere\n")); fprintf(output, _(" \\dD[S+] [PATTERN] list domains\n")); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index a2df39d0c1b..8f163fb7bac 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1004,6 +1004,7 @@ static const SchemaQuery Query_for_trigger_of_table = { "SELECT nspname FROM pg_catalog.pg_namespace "\ " WHERE nspname LIKE '%s'" +/* Use COMPLETE_WITH_QUERY_VERBATIM with these queries for GUC names: */ #define Query_for_list_of_alter_system_set_vars \ "SELECT name FROM "\ " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\ @@ -1690,7 +1691,7 @@ psql_completion(const char *text, int start, int end) "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright", "\\crosstabview", "\\d", "\\da", "\\dA", "\\dAc", "\\dAf", "\\dAo", "\\dAp", - "\\db", "\\dc", "\\dC", "\\dd", "\\ddp", "\\dD", + "\\db", "\\dc", "\\dconfig", "\\dC", "\\dd", "\\ddp", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\dE", "\\df", "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", "\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt", @@ -3780,7 +3781,7 @@ psql_completion(const char *text, int start, int end) TailMatches("GRANT|REVOKE", MatchAny, MatchAny, "ON", "PARAMETER") || TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "PARAMETER") || TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, MatchAny, "ON", "PARAMETER")) - COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars); + COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_alter_system_set_vars); else if (TailMatches("GRANT", MatchAny, "ON", "PARAMETER", MatchAny) || TailMatches("GRANT", MatchAny, MatchAny, "ON", "PARAMETER", MatchAny)) @@ -4532,6 +4533,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); else if (TailMatchesCS("\\db*")) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); + else if (TailMatchesCS("\\dconfig*")) + COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_show_vars); else if (TailMatchesCS("\\dD*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains); else if (TailMatchesCS("\\des*")) diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c index bca50ec6dec..1c618404627 100644 --- a/src/fe_utils/string_utils.c +++ b/src/fe_utils/string_utils.c @@ -918,8 +918,12 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, * Convert shell-style 'pattern' into the regular expression(s) we want to * execute. Quoting/escaping into SQL literal format will be done below * using appendStringLiteralConn(). + * + * If the caller provided a schemavar, we want to split the pattern on + * ".", otherwise not. */ - patternToSQLRegex(PQclientEncoding(conn), NULL, &schemabuf, &namebuf, + patternToSQLRegex(PQclientEncoding(conn), NULL, + (schemavar ? &schemabuf : NULL), &namebuf, pattern, force_escape); /* diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 185c5053121..8e11ebbcaa4 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -5090,6 +5090,23 @@ List of access methods hash | uuid_ops | uuid | uuid | 2 | uuid_hash_extended (5 rows) +-- check \dconfig +set work_mem = 10240; +\dconfig work_mem +List of configuration parameters + Parameter | Value +-----------+------- + work_mem | 10MB +(1 row) + +\dconfig+ work* + List of configuration parameters + Parameter | Value | Type | Context | Access privileges +-----------+-------+---------+---------+------------------- + work_mem | 10MB | integer | user | +(1 row) + +reset work_mem; -- check \df, \do with argument specifications \df *sqrt List of functions diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index 8f49a5f347a..bf372c37a56 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -1241,6 +1241,12 @@ drop role regress_partitioning_role; \dAp+ btree float_ops \dAp * pg_catalog.uuid_ops +-- check \dconfig +set work_mem = 10240; +\dconfig work_mem +\dconfig+ work* +reset work_mem; + -- check \df, \do with argument specifications \df *sqrt \df *sqrt num*