v1-psql-df-pick-function-by-type.patch
application/x-patch
Filename: v1-psql-df-pick-function-by-type.patch
Type: application/x-patch
Part: 0
Patch
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| doc/src/sgml/ref/psql-ref.sgml | 3 | 2 |
| src/bin/psql/command.c | 5 | 1 |
| src/bin/psql/describe.c | 45 | 1 |
| src/bin/psql/describe.h | 1 | 1 |
| src/bin/psql/tab-complete.c | 2 | 0 |
| src/test/regress/expected/psql.out | 107 | 0 |
| src/test/regress/sql/psql.sql | 50 | 0 |
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index ee3fc09577..c63255cebc 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1548,7 +1548,7 @@ testdb=>
<varlistentry>
- <term><literal>\df[anptwS+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
+ <term><literal>\df[anptwS+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ] [ types ]</literal></term>
<listitem>
<para>
@@ -1561,6 +1561,7 @@ testdb=>
If <replaceable
class="parameter">pattern</replaceable> is specified, only
functions whose names match the pattern are shown.
+ Any additional words are considered type arguments to help narrow the list of returned functions.
By default, only user-created
objects are shown; supply a pattern or the <literal>S</literal>
modifier to include system objects.
@@ -1572,7 +1573,7 @@ testdb=>
<tip>
<para>
- To look up functions taking arguments or returning values of a specific
+ To look up functions returning values of a specific
data type, use your pager's search capability to scroll through the
<literal>\df</literal> output.
</para>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index d4aa0976b5..72354a5d37 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -783,6 +783,8 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
case 'f': /* function subsystem */
switch (cmd[2])
{
+ char *funcargs;
+
case '\0':
case '+':
case 'S':
@@ -791,7 +793,9 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
case 'p':
case 't':
case 'w':
- success = describeFunctions(&cmd[2], pattern, show_verbose, show_system);
+ funcargs = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, true);
+ success = describeFunctions(&cmd[2], pattern, show_verbose, show_system, funcargs);
+ free(funcargs);
break;
default:
status = PSQL_CMD_UNKNOWN;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 6bb0316bd9..52a266acad 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -26,6 +26,7 @@
#include "fe_utils/print.h"
#include "fe_utils/string_utils.h"
#include "settings.h"
+#include "stringutils.h"
#include "variables.h"
static bool describeOneTableDetails(const char *schemaname,
@@ -312,7 +313,7 @@ describeTablespaces(const char *pattern, bool verbose)
* and you can mix and match these in any order.
*/
bool
-describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem)
+describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem, const char *funcargs)
{
bool showAggregate = strchr(functypes, 'a') != NULL;
bool showNormal = strchr(functypes, 'n') != NULL;
@@ -626,6 +627,49 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
"n.nspname", "p.proname", NULL,
"pg_catalog.pg_function_is_visible(p.oid)");
+ /*
+ * Check for any additional arguments to narrow down which functions are
+ * desired
+ */
+ if (funcargs)
+ {
+
+ int x = 0;
+ int argoffset = 0;
+ char *functoken;
+
+ while ((functoken = strtokx(x++ ? NULL : funcargs, " \t\n\r", ".,();", "\"", 0, false, true, pset.encoding)))
+ {
+ if (isalpha(functoken[0]))
+ {
+ appendPQExpBuffer(&buf, " AND p.proargtypes[%d]::regtype::text = LOWER(%s)::text\n",
+ argoffset++,
+
+ /*
+ * This is not a comprehensive list - just a little help
+ */
+ pg_strcasecmp(functoken, "bool") == 0 ? "'boolean'"
+ : pg_strcasecmp(functoken, "char") == 0 ? "'character'"
+ : pg_strcasecmp(functoken, "double") == 0 ? "'double precision'"
+ : pg_strcasecmp(functoken, "float") == 0 ? "'double precision'"
+ : pg_strcasecmp(functoken, "int") == 0 ? "'integer'"
+ : pg_strcasecmp(functoken, "time") == 0 ? "'time without time zone'"
+ : pg_strcasecmp(functoken, "timetz") == 0 ? "'time with time zone'"
+ : pg_strcasecmp(functoken, "timestamp") == 0 ? "'timestamp without time zone'"
+ : pg_strcasecmp(functoken, "timestamptz") == 0 ? "'timestamp with time zone'"
+ : pg_strcasecmp(functoken, "varbit") == 0 ? "'bit varying'"
+ : pg_strcasecmp(functoken, "varchar") == 0 ? "'character varying'"
+ : PQescapeLiteral(pset.db, functoken, strlen(functoken)));
+
+ }
+ else if (functoken[0] == ')' && argoffset)
+ { /* Force limit the number of args */
+ appendPQExpBuffer(&buf, " AND p.pronargs = %d\n", argoffset);
+ break;
+ }
+ }
+ }
+
if (!showSystem && !pattern)
appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
" AND n.nspname <> 'information_schema'\n");
diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h
index f0e3ec957c..a3400afb8c 100644
--- a/src/bin/psql/describe.h
+++ b/src/bin/psql/describe.h
@@ -19,7 +19,7 @@ extern bool describeAccessMethods(const char *pattern, bool verbose);
extern bool describeTablespaces(const char *pattern, bool verbose);
/* \df, \dfa, \dfn, \dft, \dfw, etc. */
-extern bool describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem);
+extern bool describeFunctions(const char *functypes, const char *pattern, bool verbose, bool showSystem, const char *funcargs);
/* \dT */
extern bool describeTypes(const char *pattern, bool verbose, bool showSystem);
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 561fe1dff9..8c51cf6e37 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3786,6 +3786,8 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
else if (TailMatchesCS("\\df*"))
COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+ else if (HeadMatches("\\df", MatchAny))
+ COMPLETE_WITH_FUNCTION_ARG(previous_words[previous_words_count - 2]);
else if (TailMatchesCS("\\dFd*"))
COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index daac0ff49d..fd69956d07 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -5072,3 +5072,110 @@ List of access methods
hash | uuid_ops | uuid | uuid | 2 | uuid_hash_extended
(5 rows)
+-- list specific functions of the same name but different args
+create function mtest(int) returns int as $$ select 1; $$ language sql;
+create function mtest(int,text) returns int as $$ select 1; $$ language sql;
+create function mtest(bool,character(10),varchar(10)) returns int as $$ select 1; $$ language sql;
+create function mtest(float,float,int) returns int as $$ select 1; $$ language sql;
+create function mtest(time,timetz) returns int as $$ select 1; $$ language sql;
+create function mtest(timestamp,timestamptz) returns int as $$ select 1; $$ language sql;
+create function mtest(varbit) returns int as $$ select 1; $$ language sql;
+-- With no arguments, all functions are shown
+\df mtest
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+-------------------------------------------------------+------
+ public | mtest | integer | bit varying | func
+ public | mtest | integer | boolean, character, character varying | func
+ public | mtest | integer | double precision, double precision, integer | func
+ public | mtest | integer | integer | func
+ public | mtest | integer | integer, text | func
+ public | mtest | integer | timestamp without time zone, timestamp with time zone | func
+ public | mtest | integer | time without time zone, time with time zone | func
+(7 rows)
+
+-- An invalid argument type matches nothing
+\df mtest mint
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+------+------------------+---------------------+------
+(0 rows)
+
+-- A single argument type matches all functions starting with that type
+\df mtest integer
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+---------------------+------
+ public | mtest | integer | integer | func
+ public | mtest | integer | integer, text | func
+(2 rows)
+
+-- Two argument types match up
+\df mtest integer text
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+---------------------+------
+ public | mtest | integer | integer, text | func
+(1 row)
+
+-- A single argument type only matches a single argument if a closing paren is added
+\df mtest (integer)
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+---------------------+------
+ public | mtest | integer | integer | func
+(1 row)
+
+-- Allowed abbreviations: bool->boolean, char -> character, varchar -> character varying
+\df mtest bool,char,varchar
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+---------------------------------------+------
+ public | mtest | integer | boolean, character, character varying | func
+(1 row)
+
+-- Allowed abbreviations: double -> double precision, float - double precision, int -> integer
+\df mtest double float int
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+---------------------------------------------+------
+ public | mtest | integer | double precision, double precision, integer | func
+(1 row)
+
+-- Allowed abbreviations: time -> time without time zone, timetz -> time with time zone
+\df mtest (time timetz)
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+---------------------------------------------+------
+ public | mtest | integer | time without time zone, time with time zone | func
+(1 row)
+
+-- Allowed abbreviations: timestamp -> timestamp without time zone, timestamptz -> timestampt with time zone
+\df mtest timestamp timestamptz
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+-------------------------------------------------------+------
+ public | mtest | integer | timestamp without time zone, timestamp with time zone | func
+(1 row)
+
+-- Allowed abbreviation: varbit -> bit varying
+\df mtest varbit
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+-------+------------------+---------------------+------
+ public | mtest | integer | bit varying | func
+(1 row)
+
+drop function mtest(int);
+drop function mtest(int,text);
+drop function mtest(bool,char,varchar);
+drop function mtest(float,float,int);
+drop function mtest(time,timetz);
+drop function mtest(timestamp,timestamptz);
+drop function mtest(varbit);
+\df mtest
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+------+------------------+---------------------+------
+(0 rows)
+
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index 47b28d2a07..73f4d7cf90 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -1225,3 +1225,53 @@ drop role regress_partitioning_role;
\dAo * pg_catalog.jsonb_path_ops
\dAp+ btree float_ops
\dAp * pg_catalog.uuid_ops
+
+-- list specific functions of the same name but different args
+
+create function mtest(int) returns int as $$ select 1; $$ language sql;
+create function mtest(int,text) returns int as $$ select 1; $$ language sql;
+create function mtest(bool,character(10),varchar(10)) returns int as $$ select 1; $$ language sql;
+create function mtest(float,float,int) returns int as $$ select 1; $$ language sql;
+create function mtest(time,timetz) returns int as $$ select 1; $$ language sql;
+create function mtest(timestamp,timestamptz) returns int as $$ select 1; $$ language sql;
+create function mtest(varbit) returns int as $$ select 1; $$ language sql;
+
+-- With no arguments, all functions are shown
+\df mtest
+
+-- An invalid argument type matches nothing
+\df mtest mint
+
+-- A single argument type matches all functions starting with that type
+\df mtest integer
+
+-- Two argument types match up
+\df mtest integer text
+
+-- A single argument type only matches a single argument if a closing paren is added
+\df mtest (integer)
+
+-- Allowed abbreviations: bool->boolean, char -> character, varchar -> character varying
+\df mtest bool,char,varchar
+
+-- Allowed abbreviations: double -> double precision, float - double precision, int -> integer
+\df mtest double float int
+
+-- Allowed abbreviations: time -> time without time zone, timetz -> time with time zone
+\df mtest (time timetz)
+
+-- Allowed abbreviations: timestamp -> timestamp without time zone, timestamptz -> timestampt with time zone
+\df mtest timestamp timestamptz
+
+-- Allowed abbreviation: varbit -> bit varying
+\df mtest varbit
+
+drop function mtest(int);
+drop function mtest(int,text);
+drop function mtest(bool,char,varchar);
+drop function mtest(float,float,int);
+drop function mtest(time,timetz);
+drop function mtest(timestamp,timestamptz);
+drop function mtest(varbit);
+
+\df mtest