From b0b5e20cd8d1a58a8782d5dc806a5232db116e2f Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 8 Mar 2020 13:32:25 +0300 Subject: [PATCH] Show opclass and opfamily related information in psql This commit provides psql commands for listing operator classes, operator families and its contents in psql. New commands will be useful for exploring capabilities of both builtin opclasses/opfamilies as well as opclasses/opfamilies defined in extensions. Discussion: https://postgr.es/m/1529675324.14193.5.camel%40postgrespro.ru Author: Sergey Cherkashin, Nikita Glukhov, Alexander Korotkov Reviewed-by: Michael Paquier, Alvaro Herrera, Arthur Zakirov Reviewed-by: Kyotaro Horiguchi, Andres Freund --- doc/src/sgml/ref/psql-ref.sgml | 91 ++++++++ src/bin/psql/command.c | 33 ++- src/bin/psql/describe.c | 335 +++++++++++++++++++++++++++++ src/bin/psql/describe.h | 19 ++ src/bin/psql/help.c | 4 + src/bin/psql/tab-complete.c | 16 +- src/test/regress/expected/psql.out | 162 ++++++++++++++ src/test/regress/sql/psql.sql | 18 ++ 8 files changed, 676 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 20ba105160..67ecec27cf 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1231,6 +1231,97 @@ testdb=> + + + \dAc[+] + [access-method-pattern + [input-type-pattern]] + + + + + Lists operator classes + (see ). + If access-method-patttern + is specified, only operator classes associated with access methods whose + names match pattern are listed. + If input-type-pattern + is specified, only operator classes associated with input types whose + names match the pattern are listed. + If + is appended to the command name, each operator + class is listed with its associated operator family and owner. + + + + + + + \dAf[+] + [access-method-pattern + [input-type-pattern]] + + + + + Lists operator families + (see ). + If access-method-patttern + is specified, only operator families associated with access methods whose + names match pattern are listed. + If input-type-pattern + is specified, only operator families associated with input types whose + names match the pattern are listed. + If + is appended to the command name, each operator + family is listed with its owner. + + + + + + + \dAo[+] + [access-method-pattern + [operator-family-pattern]] + + + + + + Lists operators associated with operator families + (). + If access-method-patttern + is specified, only members of operator families associated with access + methods whose names match pattern are listed. + If input-type-pattern + is specified, only memeber of operator families whose names match the + pattern are listed. + If + is appended to the command name, each operator + is listed with its strategy number, purpose and sort operator family. + + + + + + + \dAp[+] + [access-method-pattern + [operator-family-pattern]] + + + + + Lists procedures associated with operator families + (). + If access-method-patttern + is specified, only members of operator families associated with access + methods whose names match pattern are listed. + If input-type-pattern + is specified, only memeber of operator families whose names match the + pattern are listed. + + + + \db[+] [ pattern ] diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index e111cee556..abb18a19c2 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -721,7 +721,38 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) success = listTables("tvmsE", NULL, show_verbose, show_system); break; case 'A': - success = describeAccessMethods(pattern, show_verbose); + { + char *pattern2 = NULL; + + if (pattern && cmd[2] != '\0' && cmd[2] != '+') + pattern2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); + + switch (cmd[2]) + { + case '\0': + case '+': + success = describeAccessMethods(pattern, show_verbose); + break; + case 'c': + success = listOperatorClasses(pattern, pattern2, show_verbose); + break; + case 'f': + success = listOperatorFamilies(pattern, pattern2, show_verbose); + break; + case 'o': + success = listOpFamilyOperators(pattern, pattern2, show_verbose); + break; + case 'p': + success = listOpFamilyProcedures(pattern, pattern2); + break; + default: + status = PSQL_CMD_UNKNOWN; + break; + } + + if (pattern2) + free(pattern2); + } break; case 'a': success = describeAggregates(pattern, show_verbose, show_system); diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index f3c7eb96fa..109245fea7 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -14,6 +14,7 @@ #include +#include "catalog/pg_am.h" #include "catalog/pg_attribute_d.h" #include "catalog/pg_cast_d.h" #include "catalog/pg_class_d.h" @@ -6015,3 +6016,337 @@ printACLColumn(PQExpBuffer buf, const char *colname) "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"", colname, gettext_noop("Access privileges")); } + +/* + * \dAc + * Lists operator classes + * + * Takes an optional regexps to filter by index access method and type. + */ +bool +listOperatorClasses(const char *access_method_pattern, + const char *type_pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + bool have_where = false; + static const bool translate_columns[] = {false, false, false, false, false, + false, false, false}; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT DISTINCT" + " am.amname AS \"%s\",\n" + " c.opcintype::pg_catalog.regtype AS \"%s\",\n" + " (CASE WHEN c.opckeytype <> 0 AND c.opckeytype <> c.opcintype\n" + " THEN c.opckeytype\n" + " ELSE NULL -- c.opcintype\n" + " END)::pg_catalog.regtype AS \"%s\",\n" + " CASE\n" + " WHEN pg_catalog.pg_opclass_is_visible(c.oid)\n" + " THEN format('%%I', c.opcname)\n" + " ELSE format('%%I.%%I', n.nspname, c.opcname)\n" + " END AS \"%s\",\n" + " (CASE WHEN c.opcdefault\n" + " THEN '%s'\n" + " ELSE '%s'\n" + " END) AS \"%s\"", + gettext_noop("AM"), + gettext_noop("Input type"), + gettext_noop("Storage type"), + gettext_noop("Operator class"), + gettext_noop("yes"), + gettext_noop("no"), + gettext_noop("Default?")); + if (verbose) + appendPQExpBuffer(&buf, + ",\n CASE\n" + " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n" + " THEN format('%%I', of.opfname)\n" + " ELSE format('%%I.%%I', ofn.nspname, of.opfname)\n" + " END AS \"%s\",\n" + " pg_catalog.pg_get_userbyid(c.opcowner) AS \"%s\"\n", + gettext_noop("Operator family"), + gettext_noop("Owner")); + appendPQExpBuffer(&buf, + "\nFROM pg_catalog.pg_opclass c\n" + " LEFT JOIN pg_catalog.pg_am am on am.oid = c.opcmethod\n" + " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.opcnamespace\n" + " LEFT JOIN pg_catalog.pg_type t1 ON t1.oid = c.opcintype\n" + ); + if (verbose) + appendPQExpBuffer(&buf, + " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = c.opcfamily\n" + " LEFT JOIN pg_catalog.pg_namespace ofn ON ofn.oid = of.opfnamespace\n"); + + if (access_method_pattern) + have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, + false, false, NULL, "am.amname", NULL, NULL); + if (type_pattern) + processSQLNamePattern(pset.db, &buf, type_pattern, have_where, false, + NULL, "t1.typname", NULL, NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;"); + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of operator classes"); + myopt.translate_header = true; + myopt.translate_columns = translate_columns; + myopt.n_translate_columns = lengthof(translate_columns); + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + +/* + * \dAf + * Lists operator families + * + * Takes an optional regexps to filter by index access method and type. + */ +bool +listOperatorFamilies(const char *access_method_pattern, + const char *type_pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + bool have_where = false; + static const bool translate_columns[] = {false, false, false, false, false, + false, false, false}; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT DISTINCT" + " am.amname AS \"%s\",\n" + " CASE\n" + " WHEN pg_catalog.pg_opfamily_is_visible(f.oid)\n" + " THEN format('%%I', f.opfname)\n" + " ELSE format('%%I.%%I', n.nspname, f.opfname)\n" + " END AS \"%s\",\n" + " (SELECT\n" + " string_agg(format_type(oc.opcintype, -1), ', ')\n" + " FROM pg_opclass oc\n" + " WHERE oc.opcfamily = f.oid) \"%s\"", + gettext_noop("AM"), + gettext_noop("Operator family"), + gettext_noop("Applicable types")); + if (verbose) + appendPQExpBuffer(&buf, + ",\n pg_catalog.pg_get_userbyid(f.opfowner) AS \"%s\"\n", + gettext_noop("Owner")); + appendPQExpBuffer(&buf, + "\nFROM pg_catalog.pg_opfamily f\n" + " LEFT JOIN pg_catalog.pg_am am on am.oid = f.opfmethod\n" + " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = f.opfnamespace\n" + ); + + if (access_method_pattern) + have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, + false, false, NULL, "am.amname", NULL, NULL); + if (type_pattern) + { + appendPQExpBuffer(&buf, + "\n %s EXISTS (\n" + " SELECT 1\n" + " FROM pg_type t\n" + " JOIN pg_opclass oc ON oc.opcintype = t.oid\n" + " WHERE oc.opcfamily = f.oid", + have_where ? "AND" : "WHERE"); + processSQLNamePattern(pset.db, &buf, type_pattern, true, false, + NULL, "t.typname", NULL, NULL); + appendPQExpBuffer(&buf, ")"); + } + + appendPQExpBufferStr(&buf, "ORDER BY 1, 2;"); + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of operator families"); + myopt.translate_header = true; + myopt.translate_columns = translate_columns; + myopt.n_translate_columns = lengthof(translate_columns); + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + +/* + * \dAo + * Lists operators of operator families + * + * Takes an optional regexps to filter by index access method and operator + * family. + */ +bool +listOpFamilyOperators(const char *access_method_pattern, + const char *family_pattern, bool verbose) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + bool have_where = false; + + static const bool translate_columns[] = {false, false, false, false, false, + false, false, true, false}; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT\n" + " am.amname AS \"%s\",\n" + " CASE\n" + " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n" + " THEN format('%%I', of.opfname)\n" + " ELSE format('%%I.%%I', nsf.nspname, of.opfname)\n" + " END AS \"%s\",\n" + " format ('%%s (%%s, %%s)',\n" + " CASE\n" + " WHEN pg_catalog.pg_operator_is_visible(op.oid) \n" + " THEN op.oprname::pg_catalog.text \n" + " ELSE o.amopopr::pg_catalog.regoper::pg_catalog.text \n" + " END,\n" + " pg_catalog.format_type(o.amoplefttype, NULL),\n" + " pg_catalog.format_type(o.amoprighttype, NULL)\n" + " ) AS \"%s\"\n", + gettext_noop("AM"), + gettext_noop("Opfamily Name"), + gettext_noop("Operator")); + + if (verbose) + appendPQExpBuffer(&buf, + ", o.amopstrategy AS \"%s\",\n" + " CASE o.amoppurpose\n" + " WHEN 'o' THEN '%s'\n" + " WHEN 's' THEN '%s'\n" + " END AS \"%s\",\n" + " ofs.opfname AS \"%s\"\n", + gettext_noop("Strategy"), + gettext_noop("ordering"), + gettext_noop("search"), + gettext_noop("Purpose"), + gettext_noop("Sort opfamily")); + appendPQExpBuffer(&buf, + "FROM pg_catalog.pg_amop o\n" + " LEFT JOIN pg_catalog.pg_operator op ON op.oid = o.amopopr\n" + " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = o.amopfamily\n" + " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod AND am.oid = o.amopmethod\n" + " LEFT JOIN pg_catalog.pg_namespace nsf ON of.opfnamespace = nsf.oid\n"); + if (verbose) + appendPQExpBuffer(&buf, + " LEFT JOIN pg_catalog.pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n"); + + if (access_method_pattern) + have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, + false, false, NULL, "am.amname", + NULL, NULL); + + if (family_pattern) + processSQLNamePattern(pset.db, &buf, family_pattern, have_where, false, + "nsf.nspname", "of.opfname", NULL, NULL); + + appendPQExpBufferStr(&buf, "ORDER BY 1, 2, o.amopstrategy, 3;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of operators of operator families"); + myopt.translate_header = true; + myopt.translate_columns = translate_columns; + myopt.n_translate_columns = lengthof(translate_columns); + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + +/* + * \dAp + * Lists procedures of operator families + * + * Takes an optional regexps to filter by index access method and operator + * family. + */ +bool +listOpFamilyProcedures(const char *access_method_pattern, + const char *family_pattern) +{ + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + bool have_where = false; + static const bool translate_columns[] = {false, false, false, false, false, false, false}; + + initPQExpBuffer(&buf); + + printfPQExpBuffer(&buf, + "SELECT DISTINCT\n" + " am.amname AS \"%s\",\n" + " CASE\n" + " WHEN pg_catalog.pg_opfamily_is_visible(of.oid)\n" + " THEN format('%%I', of.opfname)\n" + " ELSE format('%%I.%%I', ns.nspname, of.opfname)\n" + " END AS \"%s\",\n" + " pg_catalog.format_type(ap.amproclefttype, NULL) AS \"%s\",\n" + " pg_catalog.format_type(ap.amprocrighttype, NULL) AS \"%s\",\n" + " ap.amprocnum AS \"%s\"\n," + " p.proname AS \"%s\"\n", + gettext_noop("AM"), + gettext_noop("Operator family"), + gettext_noop("Left arg type"), + gettext_noop("Right arg type"), + gettext_noop("Number"), + gettext_noop("Proc name")); + + appendPQExpBuffer(&buf, + "FROM pg_catalog.pg_amproc ap\n" + " LEFT JOIN pg_catalog.pg_opfamily of ON of.oid = ap.amprocfamily\n" + " LEFT JOIN pg_catalog.pg_am am ON am.oid = of.opfmethod\n" + " LEFT JOIN pg_catalog.pg_namespace ns ON of.opfnamespace = ns.oid\n" + " LEFT JOIN pg_catalog.pg_proc p ON ap.amproc = p.oid\n"); + + if (access_method_pattern) + have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, + false, false, NULL, "am.amname", + NULL, NULL); + if (family_pattern) + processSQLNamePattern(pset.db, &buf, family_pattern, have_where, false, + "ns.nspname", "of.opfname", NULL, NULL); + + appendPQExpBufferStr(&buf, + "ORDER BY 1, 2, 3, 4, 5;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of procedures of operator families"); + myopt.translate_header = true; + myopt.translate_columns = translate_columns; + myopt.n_translate_columns = lengthof(translate_columns); + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 20dbfd20f0..35c50e3bcd 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -114,4 +114,23 @@ bool describePublications(const char *pattern); /* \dRs */ bool describeSubscriptions(const char *pattern, bool verbose); +/* \dAc */ +extern bool listOperatorClasses(const char *access_method_pattern, + const char *opclass_pattern, + bool verbose); + +/* \dAf */ +extern bool listOperatorFamilies(const char *access_method_pattern, + const char *opclass_pattern, + bool verbose); + +/* \dAo */ +extern bool listOpFamilyOperators(const char *accessMethod_pattern, + const char *family_pattern, bool verbose); + +/* \dAp */ +extern bool listOpFamilyProcedures(const char *access_method_pattern, + const char *family_pattern); + + #endif /* DESCRIBE_H */ diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 1f1f778426..9a18cb3059 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -227,6 +227,10 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\d[S+] NAME describe table, view, sequence, or index\n")); fprintf(output, _(" \\da[S] [PATTERN] list aggregates\n")); fprintf(output, _(" \\dA[+] [PATTERN] list access methods\n")); + fprintf(output, _(" \\dAc[+] [AMPTRN [TYPEPTRN]] list operator classes\n")); + fprintf(output, _(" \\dAf[+] [AMPTRN [TYPEPTRN]] list operator families\n")); + fprintf(output, _(" \\dAo[+] [AMPTRN [OPFPTRN]] list operators of operator families\n")); + fprintf(output, _(" \\dAp [AMPTRN [OPFPTRN]] list procedures of operator families\n")); fprintf(output, _(" \\db[+] [PATTERN] list tablespaces\n")); fprintf(output, _(" \\dc[S+] [PATTERN] list conversions\n")); fprintf(output, _(" \\dC[+] [PATTERN] list casts\n")); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 17b1f299b4..174c3db623 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -510,6 +510,13 @@ static const SchemaQuery Query_for_list_of_partitioned_relations = { .result = "pg_catalog.quote_ident(c.relname)", }; +static const SchemaQuery Query_for_list_of_operator_families = { + .catname = "pg_catalog.pg_opfamily c", + .viscondition = "pg_catalog.pg_opfamily_is_visible(c.oid)", + .namespace = "c.opfnamespace", + .result = "pg_catalog.quote_ident(c.opfname)", +}; + /* Relations supporting INSERT, UPDATE or DELETE */ static const SchemaQuery Query_for_list_of_updatables = { .catname = "pg_catalog.pg_class c", @@ -1462,7 +1469,8 @@ psql_completion(const char *text, int start, int end) "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright", "\\crosstabview", - "\\d", "\\da", "\\dA", "\\db", "\\dc", "\\dC", "\\dd", "\\ddp", "\\dD", + "\\d", "\\da", "\\dA", "\\dAc", "\\dAf", "\\dAo", "\\dAp", + "\\db", "\\dc", "\\dC", "\\dd", "\\ddp", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\dE", "\\df", "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", "\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt", @@ -3698,6 +3706,12 @@ psql_completion(const char *text, int start, int end) } else if (TailMatchesCS("\\da*")) COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL); + else if (TailMatchesCS("\\dAc*", MatchAny) || + TailMatchesCS("\\dAf*", MatchAny)) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL); + else if (TailMatchesCS("\\dAo*", MatchAny) || + TailMatchesCS("\\dAp*", MatchAny)) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_operator_families, NULL); else if (TailMatchesCS("\\dA*")) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); else if (TailMatchesCS("\\db*")) diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 242f817163..2423ae2f37 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -4809,3 +4809,165 @@ Owning table: "pg_catalog.pg_statistic" Indexes: "pg_toast_2619_index" PRIMARY KEY, btree (chunk_id, chunk_seq) +-- check printing info about access methods +\dA +List of access methods + Name | Type +--------+------- + brin | Index + btree | Index + gin | Index + gist | Index + hash | Index + heap | Table + heap2 | Table + spgist | Index +(8 rows) + +\dA * +List of access methods + Name | Type +--------+------- + brin | Index + btree | Index + gin | Index + gist | Index + hash | Index + heap | Table + heap2 | Table + spgist | Index +(8 rows) + +\dA h* +List of access methods + Name | Type +-------+------- + hash | Index + heap | Table + heap2 | Table +(3 rows) + +\dA foo +List of access methods + Name | Type +------+------ +(0 rows) + +\dA foo bar +List of access methods + Name | Type +------+------ +(0 rows) + +\dA: extra argument "bar" ignored +\dA+ + List of access methods + Name | Type | Handler | Description +--------+-------+----------------------+---------------------------------------- + brin | Index | brinhandler | block range index (BRIN) access method + btree | Index | bthandler | b-tree index access method + gin | Index | ginhandler | GIN index access method + gist | Index | gisthandler | GiST index access method + hash | Index | hashhandler | hash index access method + heap | Table | heap_tableam_handler | heap table access method + heap2 | Table | heap_tableam_handler | + spgist | Index | spghandler | SP-GiST index access method +(8 rows) + +\dA+ * + List of access methods + Name | Type | Handler | Description +--------+-------+----------------------+---------------------------------------- + brin | Index | brinhandler | block range index (BRIN) access method + btree | Index | bthandler | b-tree index access method + gin | Index | ginhandler | GIN index access method + gist | Index | gisthandler | GiST index access method + hash | Index | hashhandler | hash index access method + heap | Table | heap_tableam_handler | heap table access method + heap2 | Table | heap_tableam_handler | + spgist | Index | spghandler | SP-GiST index access method +(8 rows) + +\dA+ h* + List of access methods + Name | Type | Handler | Description +-------+-------+----------------------+-------------------------- + hash | Index | hashhandler | hash index access method + heap | Table | heap_tableam_handler | heap table access method + heap2 | Table | heap_tableam_handler | +(3 rows) + +\dA+ foo + List of access methods + Name | Type | Handler | Description +------+------+---------+------------- +(0 rows) + +\dAc brin pg*.oid* + List of operator classes + AM | Input type | Storage type | Operator class | Default? +------+------------+--------------+----------------+---------- + brin | oid | | oid_minmax_ops | yes +(1 row) + +\dAf spgist + List of operator families + AM | Operator family | Applicable types +--------+-----------------+------------------ + spgist | box_ops | box + spgist | kd_point_ops | point + spgist | network_ops | inet + spgist | poly_ops | polygon + spgist | quad_point_ops | point + spgist | range_ops | anyrange + spgist | text_ops | text +(7 rows) + +\dAf btree int4 + List of operator families + AM | Operator family | Applicable types +-------+-----------------+--------------------------- + btree | integer_ops | smallint, integer, bigint +(1 row) + +\dAo brin uuid_minmax_ops + List of operators of operator families + AM | Opfamily Name | Operator +------+-----------------+----------------- + brin | uuid_minmax_ops | < (uuid, uuid) + brin | uuid_minmax_ops | <= (uuid, uuid) + brin | uuid_minmax_ops | = (uuid, uuid) + brin | uuid_minmax_ops | >= (uuid, uuid) + brin | uuid_minmax_ops | > (uuid, uuid) +(5 rows) + +\dAo * pg_catalog.jsonb_path_ops + List of operators of operator families + AM | Opfamily Name | Operator +-----+----------------+---------------------- + gin | jsonb_path_ops | @> (jsonb, jsonb) + gin | jsonb_path_ops | @? (jsonb, jsonpath) + gin | jsonb_path_ops | @@ (jsonb, jsonpath) +(3 rows) + +\dAp brin uuid_minmax_ops + List of procedures of operator families + AM | Operator family | Left arg type | Right arg type | Number | Proc name +------+-----------------+---------------+----------------+--------+------------------------ + brin | uuid_minmax_ops | uuid | uuid | 1 | brin_minmax_opcinfo + brin | uuid_minmax_ops | uuid | uuid | 2 | brin_minmax_add_value + brin | uuid_minmax_ops | uuid | uuid | 3 | brin_minmax_consistent + brin | uuid_minmax_ops | uuid | uuid | 4 | brin_minmax_union +(4 rows) + +\dAp * pg_catalog.uuid_ops + List of procedures of operator families + AM | Operator family | Left arg type | Right arg type | Number | Proc name +-------+-----------------+---------------+----------------+--------+-------------------- + btree | uuid_ops | uuid | uuid | 1 | uuid_cmp + btree | uuid_ops | uuid | uuid | 2 | uuid_sortsupport + btree | uuid_ops | uuid | uuid | 4 | btequalimage + hash | uuid_ops | uuid | uuid | 1 | uuid_hash + hash | uuid_ops | uuid | uuid | 2 | uuid_hash_extended +(5 rows) + diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index 26a0bcf718..3c876d2699 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -1182,3 +1182,21 @@ drop role regress_partitioning_role; -- \d on toast table (use pg_statistic's toast table, which has a known name) \d pg_toast.pg_toast_2619 + +-- check printing info about access methods +\dA +\dA * +\dA h* +\dA foo +\dA foo bar +\dA+ +\dA+ * +\dA+ h* +\dA+ foo +\dAc brin pg*.oid* +\dAf spgist +\dAf btree int4 +\dAo brin uuid_minmax_ops +\dAo * pg_catalog.jsonb_path_ops +\dAp brin uuid_minmax_ops +\dAp * pg_catalog.uuid_ops