diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index b17039d60f..eb9d93a168 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1423,16 +1423,16 @@ testdb=> - \df[antwS+] [ pattern ] + \df[anptwS+] [ pattern ] Lists functions, together with their result data types, argument data types, and function types, which are classified as agg - (aggregate), normal, trigger, or window. + (aggregate), normal, procedure, trigger, or window. To display only functions of specific type(s), add the corresponding letters a, - n, t, or w to the command. + n, p, t, or w to the command. If pattern is specified, only functions whose names match the pattern are shown. diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 4c85f43f09..f82f361fd8 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -754,6 +754,7 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) case 'S': case 'a': case 'n': + case 'p': case 't': case 'w': success = describeFunctions(&cmd[2], pattern, show_verbose, show_system); diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index c3bdf8555d..80d8338b96 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -312,6 +312,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool { bool showAggregate = strchr(functypes, 'a') != NULL; bool showNormal = strchr(functypes, 'n') != NULL; + bool showProcedure = strchr(functypes, 'p') != NULL; bool showTrigger = strchr(functypes, 't') != NULL; bool showWindow = strchr(functypes, 'w') != NULL; bool have_where; @@ -323,9 +324,20 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool /* No "Parallel" column before 9.6 */ static const bool translate_columns_pre_96[] = {false, false, false, false, true, true, false, true, false, false, false, false}; - if (strlen(functypes) != strspn(functypes, "antwS+")) + if (strlen(functypes) != strspn(functypes, "anptwS+")) { - psql_error("\\df only takes [antwS+] as options\n"); + psql_error("\\df only takes [anptwS+] as options\n"); + return true; + } + + if (showProcedure && pset.sversion < 110000) + { + char sverbuf[32]; + + psql_error("\\df does not take a \"%c\" option with server version %s\n", + 'p', + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -333,15 +345,18 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool { char sverbuf[32]; - psql_error("\\df does not take a \"w\" option with server version %s\n", + psql_error("\\df does not take a \"%c\" option with server version %s\n", + 'w', formatPGVersionNumber(pset.sversion, false, sverbuf, sizeof(sverbuf))); return true; } - if (!showAggregate && !showNormal && !showTrigger && !showWindow) + if (!showAggregate && !showNormal && !showProcedure && !showTrigger && !showWindow) { showAggregate = showNormal = showTrigger = true; + if (pset.sversion >= 110000) + showProcedure = true; if (pset.sversion >= 80400) showWindow = true; } @@ -505,7 +520,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool have_where = false; /* filter by function type, if requested */ - if (showNormal && showAggregate && showTrigger && showWindow) + if (showNormal && showAggregate && showProcedure && showTrigger && showWindow) /* Do nothing */ ; else if (showNormal) { @@ -523,6 +538,17 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool else appendPQExpBufferStr(&buf, "NOT p.proisagg\n"); } + if (!showProcedure && pset.sversion >= 110000) + { + if (have_where) + appendPQExpBufferStr(&buf, " AND "); + else + { + appendPQExpBufferStr(&buf, "WHERE "); + have_where = true; + } + appendPQExpBufferStr(&buf, "p.prokind <> 'p'\n"); + } if (!showTrigger) { if (have_where) @@ -572,6 +598,13 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool "p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype\n"); needs_or = true; } + if (showProcedure) + { + if (needs_or) + appendPQExpBufferStr(&buf, " OR "); + appendPQExpBufferStr(&buf, "p.prokind = 'p'\n"); + needs_or = true; + } if (showWindow) { if (needs_or) diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 702e742af4..316030d358 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -235,7 +235,7 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\des[+] [PATTERN] list foreign servers\n")); fprintf(output, _(" \\deu[+] [PATTERN] list user mappings\n")); fprintf(output, _(" \\dew[+] [PATTERN] list foreign-data wrappers\n")); - fprintf(output, _(" \\df[antw][S+] [PATRN] list [only agg/normal/trigger/window] functions\n")); + fprintf(output, _(" \\df[anptw][S+] [PATRN] list [only agg/normal/procedures/trigger/window] functions\n")); fprintf(output, _(" \\dF[+] [PATTERN] list text search configurations\n")); fprintf(output, _(" \\dFd[+] [PATTERN] list text search dictionaries\n")); fprintf(output, _(" \\dFp[+] [PATTERN] list text search parsers\n")); diff --git a/src/test/regress/expected/create_procedure.out b/src/test/regress/expected/create_procedure.out index 90e8f3c5ff..5b9b83839c 100644 --- a/src/test/regress/expected/create_procedure.out +++ b/src/test/regress/expected/create_procedure.out @@ -15,14 +15,6 @@ LANGUAGE SQL AS $$ INSERT INTO cp_test VALUES (1, x); $$; -SELECT ptest1('x'); -- error -ERROR: ptest1(unknown) is a procedure -LINE 1: SELECT ptest1('x'); - ^ -HINT: To call a procedure, use CALL. -CALL ptest1('a'); -- ok -CALL ptest1('xy' || 'zzy'); -- ok, constant-folded arg -CALL ptest1(substring(random()::numeric(20,15)::text, 1, 1)); -- ok, volatile arg \df ptest1 List of functions Schema | Name | Result data type | Argument data types | Type @@ -41,6 +33,30 @@ SELECT pg_get_functiondef('ptest1'::regproc); (1 row) +-- show only normal functions +\dfn public.*test*1 + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+--------------+------------------+---------------------+------ + public | cp_testfunc1 | integer | a integer | func +(1 row) + +-- show only procedures +\dfp public.*test*1 + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+--------+------------------+---------------------+------ + public | ptest1 | | x text | proc +(1 row) + +SELECT ptest1('x'); -- error +ERROR: ptest1(unknown) is a procedure +LINE 1: SELECT ptest1('x'); + ^ +HINT: To call a procedure, use CALL. +CALL ptest1('a'); -- ok +CALL ptest1('xy' || 'zzy'); -- ok, constant-folded arg +CALL ptest1(substring(random()::numeric(20,15)::text, 1, 1)); -- ok, volatile arg SELECT * FROM cp_test ORDER BY b COLLATE "C"; a | b ---+------- diff --git a/src/test/regress/sql/create_procedure.sql b/src/test/regress/sql/create_procedure.sql index 0a9af8c906..b64293ed66 100644 --- a/src/test/regress/sql/create_procedure.sql +++ b/src/test/regress/sql/create_procedure.sql @@ -11,14 +11,20 @@ AS $$ INSERT INTO cp_test VALUES (1, x); $$; +\df ptest1 +SELECT pg_get_functiondef('ptest1'::regproc); + +-- show only normal functions +\dfn public.*test*1 + +-- show only procedures +\dfp public.*test*1 + SELECT ptest1('x'); -- error CALL ptest1('a'); -- ok CALL ptest1('xy' || 'zzy'); -- ok, constant-folded arg CALL ptest1(substring(random()::numeric(20,15)::text, 1, 1)); -- ok, volatile arg -\df ptest1 -SELECT pg_get_functiondef('ptest1'::regproc); - SELECT * FROM cp_test ORDER BY b COLLATE "C";