Commit a3027e1e authored by Tom Lane's avatar Tom Lane

Allow psql's \df and \do commands to specify argument types.

When dealing with overloaded function or operator names, having
to look through a long list of matches is tedious.  Let's extend
these commands to allow specification of (input) argument types
to let such results be trimmed down.  Each additional argument
is treated the same as the pattern argument of \dT and matched
against the appropriate argument's type name.

While at it, fix \dT (and these new options) to recognize the
usual notation of "foo[]" for "the array type over foo", and
to handle the special abbreviations allowed by the backend
grammar, such as "int" for "integer".

Greg Sabino Mullane, revised rather significantly by me

Discussion: https://postgr.es/m/CAKAnmmLF9Hhu02N+s7uAyLc5J1xZReg72HQUoiKhNiJV3_jACQ@mail.gmail.com
parent f57a2f5e
...@@ -1567,7 +1567,7 @@ testdb=> ...@@ -1567,7 +1567,7 @@ testdb=>
<varlistentry> <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> [ <replaceable class="parameter">arg_pattern</replaceable> ... ] ]</literal></term>
<listitem> <listitem>
<para> <para>
...@@ -1580,6 +1580,11 @@ testdb=&gt; ...@@ -1580,6 +1580,11 @@ testdb=&gt;
If <replaceable If <replaceable
class="parameter">pattern</replaceable> is specified, only class="parameter">pattern</replaceable> is specified, only
functions whose names match the pattern are shown. 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 <literal>-</literal> as
the last <replaceable class="parameter">arg_pattern</replaceable>.)
By default, only user-created By default, only user-created
objects are shown; supply a pattern or the <literal>S</literal> objects are shown; supply a pattern or the <literal>S</literal>
modifier to include system objects. modifier to include system objects.
...@@ -1589,14 +1594,6 @@ testdb=&gt; ...@@ -1589,14 +1594,6 @@ testdb=&gt;
language, source code and description. language, source code and description.
</para> </para>
<tip>
<para>
To look up functions taking arguments or returning values of a specific
data type, use your pager's search capability to scroll through the
<literal>\df</literal> output.
</para>
</tip>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1721,12 +1718,19 @@ testdb=&gt; ...@@ -1721,12 +1718,19 @@ testdb=&gt;
<varlistentry> <varlistentry>
<term><literal>\do[S+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term> <term><literal>\do[S+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> [ <replaceable class="parameter">arg_pattern</replaceable> [ <replaceable class="parameter">arg_pattern</replaceable> ] ] ]</literal></term>
<listitem> <listitem>
<para> <para>
Lists operators with their operand and result types. Lists operators with their operand and result types.
If <replaceable class="parameter">pattern</replaceable> is If <replaceable class="parameter">pattern</replaceable> is
specified, only operators whose names match the pattern are listed. specified, only operators whose names match the pattern are listed.
If one <replaceable class="parameter">arg_pattern</replaceable> is
specified, only prefix operators whose right argument's type name
matches that pattern are listed.
If two <replaceable class="parameter">arg_pattern</replaceable>s
are specified, only binary operators whose argument type names match
those patterns are listed. (Alternatively, write <literal>-</literal>
for the unused argument of a unary operator.)
By default, only user-created objects are shown; supply a By default, only user-created objects are shown; supply a
pattern or the <literal>S</literal> modifier to include system pattern or the <literal>S</literal> modifier to include system
objects. objects.
...@@ -4986,6 +4990,22 @@ second | four ...@@ -4986,6 +4990,22 @@ second | four
</programlisting> </programlisting>
</para> </para>
<para>
Here is an example of using the <command>\df</command> command to
find only functions with names matching <literal>int*pl</literal>
and whose second argument is of type <type>bigint</type>:
<programlisting>
testdb=&gt; <userinput>\df int*pl * bigint</userinput>
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)
</programlisting>
</para>
<para> <para>
When suitable, query results can be shown in a crosstab representation When suitable, query results can be shown in a crosstab representation
with the <command>\crosstabview</command> command: with the <command>\crosstabview</command> command:
......
...@@ -72,6 +72,9 @@ static backslashResult exec_command_copyright(PsqlScanState scan_state, bool act ...@@ -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_crosstabview(PsqlScanState scan_state, bool active_branch);
static backslashResult exec_command_d(PsqlScanState scan_state, bool active_branch, static backslashResult exec_command_d(PsqlScanState scan_state, bool active_branch,
const char *cmd); 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, static backslashResult exec_command_edit(PsqlScanState scan_state, bool active_branch,
PQExpBuffer query_buf, PQExpBuffer previous_buf); PQExpBuffer query_buf, PQExpBuffer previous_buf);
static backslashResult exec_command_ef_ev(PsqlScanState scan_state, bool active_branch, 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) ...@@ -790,7 +793,8 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
case 'p': case 'p':
case 't': case 't':
case 'w': case 'w':
success = describeFunctions(&cmd[2], pattern, show_verbose, show_system); success = exec_command_dfo(scan_state, cmd, pattern,
show_verbose, show_system);
break; break;
default: default:
status = PSQL_CMD_UNKNOWN; status = PSQL_CMD_UNKNOWN;
...@@ -811,7 +815,8 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) ...@@ -811,7 +815,8 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
success = listSchemas(pattern, show_verbose, show_system); success = listSchemas(pattern, show_verbose, show_system);
break; break;
case 'o': case 'o':
success = describeOperators(pattern, show_verbose, show_system); success = exec_command_dfo(scan_state, cmd, pattern,
show_verbose, show_system);
break; break;
case 'O': case 'O':
success = listCollations(pattern, show_verbose, show_system); success = listCollations(pattern, show_verbose, show_system);
...@@ -951,6 +956,45 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) ...@@ -951,6 +956,45 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
return status; 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 * \e or \edit -- edit the current query buffer, or edit a file and
* make it the query buffer * make it the query buffer
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "settings.h" #include "settings.h"
#include "variables.h" #include "variables.h"
static const char *map_typename_pattern(const char *pattern);
static bool describeOneTableDetails(const char *schemaname, static bool describeOneTableDetails(const char *schemaname,
const char *relationname, const char *relationname,
const char *oid, const char *oid,
...@@ -312,7 +313,9 @@ describeTablespaces(const char *pattern, bool verbose) ...@@ -312,7 +313,9 @@ describeTablespaces(const char *pattern, bool verbose)
* and you can mix and match these in any order. * and you can mix and match these in any order.
*/ */
bool 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 showAggregate = strchr(functypes, 'a') != NULL;
bool showNormal = strchr(functypes, 'n') != NULL; bool showNormal = strchr(functypes, 'n') != NULL;
...@@ -524,6 +527,14 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool ...@@ -524,6 +527,14 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
"\nFROM pg_catalog.pg_proc p" "\nFROM pg_catalog.pg_proc p"
"\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"); "\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) if (verbose)
appendPQExpBufferStr(&buf, appendPQExpBufferStr(&buf,
" LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n"); " 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 ...@@ -629,11 +640,43 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
appendPQExpBufferStr(&buf, " )\n"); 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, "n.nspname", "p.proname", NULL,
"pg_catalog.pg_function_is_visible(p.oid)"); "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" appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
" AND n.nspname <> 'information_schema'\n"); " AND n.nspname <> 'information_schema'\n");
...@@ -746,20 +789,24 @@ describeTypes(const char *pattern, bool verbose, bool showSystem) ...@@ -746,20 +789,24 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
"WHERE c.oid = t.typrelid))\n"); "WHERE c.oid = t.typrelid))\n");
/* /*
* do not include array types (before 8.3 we have to use the assumption * do not include array types unless the pattern contains [] (before 8.3
* that their names start with underscore) * we have to use the assumption that their names start with underscore)
*/ */
if (pset.sversion >= 80300) if (pattern == NULL || strstr(pattern, "[]") == NULL)
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 if (pset.sversion >= 80300)
appendPQExpBufferStr(&buf, " AND t.typname !~ '^_'\n"); 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) if (!showSystem && !pattern)
appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n" appendPQExpBufferStr(&buf, " AND n.nspname <> 'pg_catalog'\n"
" AND n.nspname <> 'information_schema'\n"); " AND n.nspname <> 'information_schema'\n");
/* Match name pattern against either internal or external name */ /* 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", "n.nspname", "t.typname",
"pg_catalog.format_type(t.oid, NULL)", "pg_catalog.format_type(t.oid, NULL)",
"pg_catalog.pg_type_is_visible(t.oid)"); "pg_catalog.pg_type_is_visible(t.oid)");
...@@ -781,13 +828,69 @@ describeTypes(const char *pattern, bool verbose, bool showSystem) ...@@ -781,13 +828,69 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
return true; 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 * \do
* Describe operators * Describe operators
*/ */
bool 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; PQExpBufferData buf;
PGresult *res; PGresult *res;
...@@ -836,14 +939,66 @@ describeOperators(const char *pattern, bool verbose, bool showSystem) ...@@ -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", " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = o.oprnamespace\n",
gettext_noop("Description")); 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" appendPQExpBufferStr(&buf, "WHERE n.nspname <> 'pg_catalog'\n"
" AND n.nspname <> 'information_schema'\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, "n.nspname", "o.oprname", NULL,
"pg_catalog.pg_operator_is_visible(o.oid)"); "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;"); appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4;");
res = PSQLexec(buf.data); res = PSQLexec(buf.data);
......
...@@ -19,13 +19,17 @@ extern bool describeAccessMethods(const char *pattern, bool verbose); ...@@ -19,13 +19,17 @@ extern bool describeAccessMethods(const char *pattern, bool verbose);
extern bool describeTablespaces(const char *pattern, bool verbose); extern bool describeTablespaces(const char *pattern, bool verbose);
/* \df, \dfa, \dfn, \dft, \dfw, etc. */ /* \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 */ /* \dT */
extern bool describeTypes(const char *pattern, bool verbose, bool showSystem); extern bool describeTypes(const char *pattern, bool verbose, bool showSystem);
/* \do */ /* \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 */ /* \du, \dg */
extern bool describeRoles(const char *pattern, bool verbose, bool showSystem); extern bool describeRoles(const char *pattern, bool verbose, bool showSystem);
......
...@@ -166,7 +166,7 @@ slashUsage(unsigned short int pager) ...@@ -166,7 +166,7 @@ slashUsage(unsigned short int pager)
* Use "psql --help=commands | wc" to count correctly. It's okay to count * Use "psql --help=commands | wc" to count correctly. It's okay to count
* the USE_READLINE line even in builds without that. * 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, _("General\n"));
fprintf(output, _(" \\copyright show PostgreSQL usage and distribution terms\n")); fprintf(output, _(" \\copyright show PostgreSQL usage and distribution terms\n"));
...@@ -240,7 +240,8 @@ slashUsage(unsigned short int pager) ...@@ -240,7 +240,8 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\des[+] [PATTERN] list foreign servers\n")); fprintf(output, _(" \\des[+] [PATTERN] list foreign servers\n"));
fprintf(output, _(" \\deu[+] [PATTERN] list user mappings\n")); fprintf(output, _(" \\deu[+] [PATTERN] list user mappings\n"));
fprintf(output, _(" \\dew[+] [PATTERN] list foreign-data wrappers\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, _(" \\dF[+] [PATTERN] list text search configurations\n"));
fprintf(output, _(" \\dFd[+] [PATTERN] list text search dictionaries\n")); fprintf(output, _(" \\dFd[+] [PATTERN] list text search dictionaries\n"));
fprintf(output, _(" \\dFp[+] [PATTERN] list text search parsers\n")); fprintf(output, _(" \\dFp[+] [PATTERN] list text search parsers\n"));
...@@ -251,7 +252,7 @@ slashUsage(unsigned short int pager) ...@@ -251,7 +252,7 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\dL[S+] [PATTERN] list procedural languages\n")); fprintf(output, _(" \\dL[S+] [PATTERN] list procedural languages\n"));
fprintf(output, _(" \\dm[S+] [PATTERN] list materialized views\n")); fprintf(output, _(" \\dm[S+] [PATTERN] list materialized views\n"));
fprintf(output, _(" \\dn[S+] [PATTERN] list schemas\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, _(" \\dO[S+] [PATTERN] list collations\n"));
fprintf(output, _(" \\dp [PATTERN] list table, view, and sequence access privileges\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")); fprintf(output, _(" \\dP[itn+] [PATTERN] list [only index/table] partitioned relations [n=nested]\n"));
......
...@@ -1062,10 +1062,16 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf, ...@@ -1062,10 +1062,16 @@ patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf,
* regexp errors. Outside quotes, however, let them pass through * regexp errors. Outside quotes, however, let them pass through
* as-is; this lets knowledgeable users build regexp expressions * as-is; this lets knowledgeable users build regexp expressions
* that are more powerful than shell-style patterns. * 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) && if ((inquotes || force_escape) &&
strchr("|*+?()[]{}.^$\\", ch)) strchr("|*+?()[]{}.^$\\", ch))
appendPQExpBufferChar(curbuf, '\\'); appendPQExpBufferChar(curbuf, '\\');
else if (ch == '[' && cp[1] == ']')
appendPQExpBufferChar(curbuf, '\\');
i = PQmblen(cp, encoding); i = PQmblen(cp, encoding);
while (i-- && *cp) while (i-- && *cp)
{ {
......
...@@ -5078,6 +5078,107 @@ List of access methods ...@@ -5078,6 +5078,107 @@ List of access methods
hash | uuid_ops | uuid | uuid | 2 | uuid_hash_extended hash | uuid_ops | uuid | uuid | 2 | uuid_hash_extended
(5 rows) (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 -- combined queries
-- --
......
...@@ -1229,6 +1229,19 @@ drop role regress_partitioning_role; ...@@ -1229,6 +1229,19 @@ drop role regress_partitioning_role;
\dAp+ btree float_ops \dAp+ btree float_ops
\dAp * pg_catalog.uuid_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 -- combined queries
-- --
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment