diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index c1451c16727..ddb70433625 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1567,7 +1567,7 @@ testdb=>
- \df[anptwS+] [ pattern ]
+ \df[anptwS+] [ pattern [ arg_pattern ... ] ]
@@ -1580,6 +1580,11 @@ testdb=>
If pattern is specified, only
functions whose names match the pattern are shown.
+ Any additional arguments are type-name patterns, which are matched
+ to the type names of the first, second, and so on arguments of the
+ function. (Matching functions can have more arguments than what
+ you specify. To prevent that, write a dash - as
+ the last arg_pattern.)
By default, only user-created
objects are shown; supply a pattern or the S
modifier to include system objects.
@@ -1589,14 +1594,6 @@ testdb=>
language, source code and description.
-
-
- To look up functions taking arguments or returning values of a specific
- data type, use your pager's search capability to scroll through the
- \df output.
-
-
-
@@ -1721,12 +1718,19 @@ testdb=>
- \do[S+] [ pattern ]
+ \do[S+] [ pattern [ arg_pattern [ arg_pattern ] ] ]
Lists operators with their operand and result types.
If pattern is
specified, only operators whose names match the pattern are listed.
+ If one arg_pattern is
+ specified, only prefix operators whose right argument's type name
+ matches that pattern are listed.
+ If two arg_patterns
+ are specified, only binary operators whose argument type names match
+ those patterns are listed. (Alternatively, write -
+ for the unused argument of a unary operator.)
By default, only user-created objects are shown; supply a
pattern or the S modifier to include system
objects.
@@ -4986,6 +4990,22 @@ second | four
+
+ Here is an example of using the \df command to
+ find only functions with names matching int*pl
+ and whose second argument is of type bigint:
+
+testdb=> \df int*pl * bigint
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+---------+------------------+---------------------+------
+ pg_catalog | int28pl | bigint | smallint, bigint | func
+ pg_catalog | int48pl | bigint | integer, bigint | func
+ pg_catalog | int8pl | bigint | bigint, bigint | func
+(3 rows)
+
+
+
When suitable, query results can be shown in a crosstab representation
with the \crosstabview command:
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index e04ccc5b628..543401c6d6a 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -72,6 +72,9 @@ static backslashResult exec_command_copyright(PsqlScanState scan_state, bool act
static backslashResult exec_command_crosstabview(PsqlScanState scan_state, bool active_branch);
static backslashResult exec_command_d(PsqlScanState scan_state, bool active_branch,
const char *cmd);
+static bool exec_command_dfo(PsqlScanState scan_state, const char *cmd,
+ const char *pattern,
+ bool show_verbose, bool show_system);
static backslashResult exec_command_edit(PsqlScanState scan_state, bool active_branch,
PQExpBuffer query_buf, PQExpBuffer previous_buf);
static backslashResult exec_command_ef_ev(PsqlScanState scan_state, bool active_branch,
@@ -790,7 +793,8 @@ 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);
+ success = exec_command_dfo(scan_state, cmd, pattern,
+ show_verbose, show_system);
break;
default:
status = PSQL_CMD_UNKNOWN;
@@ -811,7 +815,8 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
success = listSchemas(pattern, show_verbose, show_system);
break;
case 'o':
- success = describeOperators(pattern, show_verbose, show_system);
+ success = exec_command_dfo(scan_state, cmd, pattern,
+ show_verbose, show_system);
break;
case 'O':
success = listCollations(pattern, show_verbose, show_system);
@@ -951,6 +956,45 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
return status;
}
+/* \df and \do; messy enough to split out of exec_command_d */
+static bool
+exec_command_dfo(PsqlScanState scan_state, const char *cmd,
+ const char *pattern,
+ bool show_verbose, bool show_system)
+{
+ bool success;
+ char *arg_patterns[FUNC_MAX_ARGS];
+ int num_arg_patterns = 0;
+
+ /* Collect argument-type patterns too */
+ if (pattern) /* otherwise it was just \df or \do */
+ {
+ char *ap;
+
+ while ((ap = psql_scan_slash_option(scan_state,
+ OT_NORMAL, NULL, true)) != NULL)
+ {
+ arg_patterns[num_arg_patterns++] = ap;
+ if (num_arg_patterns >= FUNC_MAX_ARGS)
+ break; /* protect limited-size array */
+ }
+ }
+
+ if (cmd[1] == 'f')
+ success = describeFunctions(&cmd[2], pattern,
+ arg_patterns, num_arg_patterns,
+ show_verbose, show_system);
+ else
+ success = describeOperators(pattern,
+ arg_patterns, num_arg_patterns,
+ show_verbose, show_system);
+
+ while (--num_arg_patterns >= 0)
+ free(arg_patterns[num_arg_patterns]);
+
+ return success;
+}
+
/*
* \e or \edit -- edit the current query buffer, or edit a file and
* make it the query buffer
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 52f7b2ce78c..fdc2a89085a 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -28,6 +28,7 @@
#include "settings.h"
#include "variables.h"
+static const char *map_typename_pattern(const char *pattern);
static bool describeOneTableDetails(const char *schemaname,
const char *relationname,
const char *oid,
@@ -312,7 +313,9 @@ 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 *func_pattern,
+ char **arg_patterns, int num_arg_patterns,
+ bool verbose, bool showSystem)
{
bool showAggregate = strchr(functypes, 'a') != NULL;
bool showNormal = strchr(functypes, 'n') != NULL;
@@ -524,6 +527,14 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
"\nFROM pg_catalog.pg_proc p"
"\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n");
+ for (int i = 0; i < num_arg_patterns; i++)
+ {
+ appendPQExpBuffer(&buf,
+ " LEFT JOIN pg_catalog.pg_type t%d ON t%d.oid = p.proargtypes[%d]\n"
+ " LEFT JOIN pg_catalog.pg_namespace nt%d ON nt%d.oid = t%d.typnamespace\n",
+ i, i, i, i, i, i);
+ }
+
if (verbose)
appendPQExpBufferStr(&buf,
" LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n");
@@ -629,11 +640,43 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
appendPQExpBufferStr(&buf, " )\n");
}
- processSQLNamePattern(pset.db, &buf, pattern, have_where, false,
+ processSQLNamePattern(pset.db, &buf, func_pattern, have_where, false,
"n.nspname", "p.proname", NULL,
"pg_catalog.pg_function_is_visible(p.oid)");
- if (!showSystem && !pattern)
+ for (int i = 0; i < num_arg_patterns; i++)
+ {
+ if (strcmp(arg_patterns[i], "-") != 0)
+ {
+ /*
+ * Match type-name patterns against either internal or external
+ * name, like \dT. Unlike \dT, there seems no reason to
+ * discriminate against arrays or composite types.
+ */
+ char nspname[64];
+ char typname[64];
+ char ft[64];
+ char tiv[64];
+
+ snprintf(nspname, sizeof(nspname), "nt%d.nspname", i);
+ snprintf(typname, sizeof(typname), "t%d.typname", i);
+ snprintf(ft, sizeof(ft),
+ "pg_catalog.format_type(t%d.oid, NULL)", i);
+ snprintf(tiv, sizeof(tiv),
+ "pg_catalog.pg_type_is_visible(t%d.oid)", i);
+ processSQLNamePattern(pset.db, &buf,
+ map_typename_pattern(arg_patterns[i]),
+ true, false,
+ nspname, typname, ft, tiv);
+ }
+ else
+ {
+ /* "-" pattern specifies no such parameter */
+ appendPQExpBuffer(&buf, " AND t%d.typname IS NULL\n", i);
+ }
+ }
+
+ if (!showSystem && !func_pattern)
appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
" AND n.nspname <> 'information_schema'\n");
@@ -746,20 +789,24 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
"WHERE c.oid = t.typrelid))\n");
/*
- * do not include array types (before 8.3 we have to use the assumption
- * that their names start with underscore)
+ * do not include array types unless the pattern contains [] (before 8.3
+ * we have to use the assumption that their names start with underscore)
*/
- if (pset.sversion >= 80300)
- appendPQExpBufferStr(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
- else
- appendPQExpBufferStr(&buf, " AND t.typname !~ '^_'\n");
+ if (pattern == NULL || strstr(pattern, "[]") == NULL)
+ {
+ if (pset.sversion >= 80300)
+ appendPQExpBufferStr(&buf, " AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)\n");
+ else
+ appendPQExpBufferStr(&buf, " AND t.typname !~ '^_'\n");
+ }
if (!showSystem && !pattern)
appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
" AND n.nspname <> 'information_schema'\n");
/* Match name pattern against either internal or external name */
- processSQLNamePattern(pset.db, &buf, pattern, true, false,
+ processSQLNamePattern(pset.db, &buf, map_typename_pattern(pattern),
+ true, false,
"n.nspname", "t.typname",
"pg_catalog.format_type(t.oid, NULL)",
"pg_catalog.pg_type_is_visible(t.oid)");
@@ -781,13 +828,69 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
return true;
}
+/*
+ * Map some variant type names accepted by the backend grammar into
+ * canonical type names.
+ *
+ * Helper for \dT and other functions that take typename patterns.
+ * This doesn't completely mask the fact that these names are special;
+ * for example, a pattern of "dec*" won't magically match "numeric".
+ * But it goes a long way to reduce the surprise factor.
+ */
+static const char *
+map_typename_pattern(const char *pattern)
+{
+ static const char *const typename_map[] = {
+ /*
+ * These names are accepted by gram.y, although they are neither the
+ * "real" name seen in pg_type nor the canonical name printed by
+ * format_type().
+ */
+ "decimal", "numeric",
+ "float", "double precision",
+ "int", "integer",
+
+ /*
+ * We also have to map the array names for cases where the canonical
+ * name is different from what pg_type says.
+ */
+ "bool[]", "boolean[]",
+ "decimal[]", "numeric[]",
+ "float[]", "double precision[]",
+ "float4[]", "real[]",
+ "float8[]", "double precision[]",
+ "int[]", "integer[]",
+ "int2[]", "smallint[]",
+ "int4[]", "integer[]",
+ "int8[]", "bigint[]",
+ "time[]", "time without time zone[]",
+ "timetz[]", "time with time zone[]",
+ "timestamp[]", "timestamp without time zone[]",
+ "timestamptz[]", "timestamp with time zone[]",
+ "varbit[]", "bit varying[]",
+ "varchar[]", "character varying[]",
+ NULL
+ };
+
+ if (pattern == NULL)
+ return NULL;
+ for (int i = 0; typename_map[i] != NULL; i += 2)
+ {
+ if (pg_strcasecmp(pattern, typename_map[i]) == 0)
+ return typename_map[i + 1];
+ }
+ return pattern;
+}
+
/*
* \do
* Describe operators
*/
bool
-describeOperators(const char *pattern, bool verbose, bool showSystem)
+describeOperators(const char *oper_pattern,
+ char **arg_patterns, int num_arg_patterns,
+ bool verbose, bool showSystem)
{
PQExpBufferData buf;
PGresult *res;
@@ -836,14 +939,66 @@ describeOperators(const char *pattern, bool verbose, bool showSystem)
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
gettext_noop("Description"));
- if (!showSystem && !pattern)
+ if (num_arg_patterns >= 2)
+ {
+ num_arg_patterns = 2; /* ignore any additional arguments */
+ appendPQExpBufferStr(&buf,
+ " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprleft\n"
+ " LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n"
+ " LEFT JOIN pg_catalog.pg_type t1 ON t1.oid = o.oprright\n"
+ " LEFT JOIN pg_catalog.pg_namespace nt1 ON nt1.oid = t1.typnamespace\n");
+ }
+ else if (num_arg_patterns == 1)
+ {
+ appendPQExpBufferStr(&buf,
+ " LEFT JOIN pg_catalog.pg_type t0 ON t0.oid = o.oprright\n"
+ " LEFT JOIN pg_catalog.pg_namespace nt0 ON nt0.oid = t0.typnamespace\n");
+ }
+
+ if (!showSystem && !oper_pattern)
appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
" AND n.nspname <> 'information_schema'\n");
- processSQLNamePattern(pset.db, &buf, pattern, !showSystem && !pattern, true,
+ processSQLNamePattern(pset.db, &buf, oper_pattern,
+ !showSystem && !oper_pattern, true,
"n.nspname", "o.oprname", NULL,
"pg_catalog.pg_operator_is_visible(o.oid)");
+ if (num_arg_patterns == 1)
+ appendPQExpBufferStr(&buf, " AND o.oprleft = 0\n");
+
+ for (int i = 0; i < num_arg_patterns; i++)
+ {
+ if (strcmp(arg_patterns[i], "-") != 0)
+ {
+ /*
+ * Match type-name patterns against either internal or external
+ * name, like \dT. Unlike \dT, there seems no reason to
+ * discriminate against arrays or composite types.
+ */
+ char nspname[64];
+ char typname[64];
+ char ft[64];
+ char tiv[64];
+
+ snprintf(nspname, sizeof(nspname), "nt%d.nspname", i);
+ snprintf(typname, sizeof(typname), "t%d.typname", i);
+ snprintf(ft, sizeof(ft),
+ "pg_catalog.format_type(t%d.oid, NULL)", i);
+ snprintf(tiv, sizeof(tiv),
+ "pg_catalog.pg_type_is_visible(t%d.oid)", i);
+ processSQLNamePattern(pset.db, &buf,
+ map_typename_pattern(arg_patterns[i]),
+ true, false,
+ nspname, typname, ft, tiv);
+ }
+ else
+ {
+ /* "-" pattern specifies no such parameter */
+ appendPQExpBuffer(&buf, " AND t%d.typname IS NULL\n", i);
+ }
+ }
+
appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4;");
res = PSQLexec(buf.data);
diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h
index 39856a0c7e8..71b320f1fc6 100644
--- a/src/bin/psql/describe.h
+++ b/src/bin/psql/describe.h
@@ -19,13 +19,17 @@ 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 *func_pattern,
+ char **arg_patterns, int num_arg_patterns,
+ bool verbose, bool showSystem);
/* \dT */
extern bool describeTypes(const char *pattern, bool verbose, bool showSystem);
/* \do */
-extern bool describeOperators(const char *pattern, bool verbose, bool showSystem);
+extern bool describeOperators(const char *oper_pattern,
+ char **arg_patterns, int num_arg_patterns,
+ bool verbose, bool showSystem);
/* \du, \dg */
extern bool describeRoles(const char *pattern, bool verbose, bool showSystem);
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index ac9a89a889b..36501d5e2b9 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(133, pager ? &(pset.popt.topt) : NULL);
+ output = PageOutput(135, pager ? &(pset.popt.topt) : NULL);
fprintf(output, _("General\n"));
fprintf(output, _(" \\copyright show PostgreSQL usage and distribution terms\n"));
@@ -240,7 +240,8 @@ 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[anptw][S+] [PATRN] list [only agg/normal/procedures/trigger/window] functions\n"));
+ fprintf(output, _(" \\df[anptw][S+] [FUNCPTRN [TYPEPTRN ...]]\n"));
+ fprintf(output, _(" list [only agg/normal/procedure/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"));
@@ -251,7 +252,7 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\dL[S+] [PATTERN] list procedural languages\n"));
fprintf(output, _(" \\dm[S+] [PATTERN] list materialized views\n"));
fprintf(output, _(" \\dn[S+] [PATTERN] list schemas\n"));
- fprintf(output, _(" \\do[S] [PATTERN] list operators\n"));
+ fprintf(output, _(" \\do[S] [OPPTRN [TYPEPTRN [TYPEPTRN]]] list operators\n"));
fprintf(output, _(" \\dO[S+] [PATTERN] list collations\n"));
fprintf(output, _(" \\dp [PATTERN] list table, view, and sequence access privileges\n"));
fprintf(output, _(" \\dP[itn+] [PATTERN] list [only index/table] partitioned relations [n=nested]\n"));
diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c
index 9a1ea9ab98b..5b206c7481d 100644
--- a/src/fe_utils/string_utils.c
+++ b/src/fe_utils/string_utils.c
@@ -1062,10 +1062,16 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf,
* regexp errors. Outside quotes, however, let them pass through
* as-is; this lets knowledgeable users build regexp expressions
* that are more powerful than shell-style patterns.
+ *
+ * As an exception to that, though, always quote "[]", as that's
+ * much more likely to be an attempt to write an array type name
+ * than it is to be the start of a regexp bracket expression.
*/
if ((inquotes || force_escape) &&
strchr("|*+?()[]{}.^$\\", ch))
appendPQExpBufferChar(curbuf, '\\');
+ else if (ch == '[' && cp[1] == ']')
+ appendPQExpBufferChar(curbuf, '\\');
i = PQmblen(cp, encoding);
while (i-- && *cp)
{
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 9a51940530a..672937b2f88 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -5078,6 +5078,107 @@ List of access methods
hash | uuid_ops | uuid | uuid | 2 | uuid_hash_extended
(5 rows)
+-- check \df, \do with argument specifications
+\df *sqrt
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+--------------+------------------+---------------------+------
+ pg_catalog | dsqrt | double precision | double precision | func
+ pg_catalog | numeric_sqrt | numeric | numeric | func
+ pg_catalog | sqrt | double precision | double precision | func
+ pg_catalog | sqrt | numeric | numeric | func
+(4 rows)
+
+\df *sqrt num*
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+--------------+------------------+---------------------+------
+ pg_catalog | numeric_sqrt | numeric | numeric | func
+ pg_catalog | sqrt | numeric | numeric | func
+(2 rows)
+
+\df int*pl
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+-------------+------------------+---------------------+------
+ pg_catalog | int24pl | integer | smallint, integer | func
+ pg_catalog | int28pl | bigint | smallint, bigint | func
+ pg_catalog | int2pl | smallint | smallint, smallint | func
+ pg_catalog | int42pl | integer | integer, smallint | func
+ pg_catalog | int48pl | bigint | integer, bigint | func
+ pg_catalog | int4pl | integer | integer, integer | func
+ pg_catalog | int82pl | bigint | bigint, smallint | func
+ pg_catalog | int84pl | bigint | bigint, integer | func
+ pg_catalog | int8pl | bigint | bigint, bigint | func
+ pg_catalog | interval_pl | interval | interval, interval | func
+(10 rows)
+
+\df int*pl int4
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+---------+------------------+---------------------+------
+ pg_catalog | int42pl | integer | integer, smallint | func
+ pg_catalog | int48pl | bigint | integer, bigint | func
+ pg_catalog | int4pl | integer | integer, integer | func
+(3 rows)
+
+\df int*pl * pg_catalog.int8
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+---------+------------------+---------------------+------
+ pg_catalog | int28pl | bigint | smallint, bigint | func
+ pg_catalog | int48pl | bigint | integer, bigint | func
+ pg_catalog | int8pl | bigint | bigint, bigint | func
+(3 rows)
+
+\df acl* aclitem[]
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+-------------+------------------+----------------------------------------------------------------------------------------------------+------
+ pg_catalog | aclcontains | boolean | aclitem[], aclitem | func
+ pg_catalog | aclexplode | SETOF record | acl aclitem[], OUT grantor oid, OUT grantee oid, OUT privilege_type text, OUT is_grantable boolean | func
+ pg_catalog | aclinsert | aclitem[] | aclitem[], aclitem | func
+ pg_catalog | aclremove | aclitem[] | aclitem[], aclitem | func
+(4 rows)
+
+\df has_database_privilege oid text
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+------------------------+------------------+---------------------+------
+ pg_catalog | has_database_privilege | boolean | oid, text | func
+ pg_catalog | has_database_privilege | boolean | oid, text, text | func
+(2 rows)
+
+\df has_database_privilege oid text -
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+------------------------+------------------+---------------------+------
+ pg_catalog | has_database_privilege | boolean | oid, text | func
+(1 row)
+
+\dfa bit* small*
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+------------+---------+------------------+---------------------+------
+ pg_catalog | bit_and | smallint | smallint | agg
+ pg_catalog | bit_or | smallint | smallint | agg
+ pg_catalog | bit_xor | smallint | smallint | agg
+(3 rows)
+
+\do - pg_catalog.int4
+ List of operators
+ Schema | Name | Left arg type | Right arg type | Result type | Description
+------------+------+---------------+----------------+-------------+-------------
+ pg_catalog | - | | integer | integer | negate
+(1 row)
+
+\do && anyarray *
+ List of operators
+ Schema | Name | Left arg type | Right arg type | Result type | Description
+------------+------+---------------+----------------+-------------+-------------
+ pg_catalog | && | anyarray | anyarray | boolean | overlaps
+(1 row)
+
--
-- combined queries
--
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index bf06bb87b50..f90a0270fc3 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -1229,6 +1229,19 @@ drop role regress_partitioning_role;
\dAp+ btree float_ops
\dAp * pg_catalog.uuid_ops
+-- check \df, \do with argument specifications
+\df *sqrt
+\df *sqrt num*
+\df int*pl
+\df int*pl int4
+\df int*pl * pg_catalog.int8
+\df acl* aclitem[]
+\df has_database_privilege oid text
+\df has_database_privilege oid text -
+\dfa bit* small*
+\do - pg_catalog.int4
+\do && anyarray *
+
--
-- combined queries
--