Thanks for the feedback, attached is version two of the patch. Major
changes:

* Use booleans not generic "int x"
* Build a quick list of abbreviations at the top of the function
* Add array mapping for all types
* Removed the tab-complete bit, it was too fragile and unhelpful

Cheers,
Greg
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 221a967bfe..cf3e8c7134 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1574,7 +1574,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>
@@ -1587,6 +1587,7 @@ testdb=&gt;
         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.
@@ -1598,7 +1599,7 @@ testdb=&gt;
 
         <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 c7a83d5dfc..426603b0cb 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 07d640021c..a8d3f3ba53 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,67 @@ 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)
+	{
+
+		bool		is_initial_run = true;
+		bool		found_abbreviation;
+		int			argoffset = 0;
+		char	   *functoken;
+
+		static const char *type_abbreviations[] = {
+			"bool", "boolean", "bool[]", "boolean[]",
+			"char", "character", "char[]", "character[]",
+			"double", "double precision", "double[]", "double precision[]",
+			"float", "double precision", "float[]", "double precision[]",
+			"int", "integer", "int[]", "integer[]",
+			"time", "time without time zone", "time[]", "time without time zone[]",
+			"timetz", "time with time zone", "timetz[]", "time with time zone[]",
+			"timestamp", "timestamp without timestamp zone", "timestamp[]", "timestamp without timestamp zone[]",
+			"timestamptz", "timestamp with timestamp zone", "timestamptz[]", "timestamp with timestamp zone[]",
+			"varbit", "bit varying", "varbit[]", "bit varying[]",
+			"varchar", "character varying", "varchar[]", "character varying[]",
+			NULL
+		};
+
+		while ((functoken = strtokx(is_initial_run ? funcargs : NULL, " \t\n\r", ".,();", "\"", 0, false, true, pset.encoding)))
+		{
+			is_initial_run = false;
+			found_abbreviation = false;
+
+			if (isalpha(functoken[0]))
+			{
+				appendPQExpBuffer(&buf, "  AND p.proargtypes[%d]::regtype::text = ", argoffset++);
+				for (int i = 0; NULL != *(type_abbreviations + i); i += 2)
+				{
+					const char *shortname = *(type_abbreviations + i);
+					const char *longname = *(type_abbreviations + i + 1);
+
+					if (pg_strcasecmp(functoken, shortname) == 0)
+					{
+						appendPQExpBuffer(&buf, "LOWER('%s')::text\n", longname);
+						found_abbreviation = true;
+						break;
+					}
+				}
+				if (!found_abbreviation)
+				{
+					appendPQExpBuffer(&buf, "LOWER(%s)::text\n", 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/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

Reply via email to