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 492a960247..77ce39766c 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 f01adb1fd2..92e5c50300 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 079f4a1a76..db071d561f 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 3f1b3802c2..797ef233c9 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 fd6079679c..7872c71f58 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 b3971bce64..1d3601e594 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 a2df39d0c1..8f163fb7ba 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 bca50ec6de..1c61840462 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 185c505312..8e11ebbcaa 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 8f49a5f347..bf372c37a5 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*