From eee92ee549e49d0b5aef438aff10236611db410e Mon Sep 17 00:00:00 2001 From: Tatsuro Yamada Date: Mon, 15 Nov 2021 17:58:31 +0900 Subject: [PATCH] Add psql command to list constraints POC3 - Fix help message s/constraint/constraints/ - s/Exclude/Exclusion/ - Remove unused modifier "+" - Add document for \dco --- doc/src/sgml/ref/psql-ref.sgml | 18 ++++++++ src/bin/psql/command.c | 18 +++++++- src/bin/psql/describe.c | 98 ++++++++++++++++++++++++++++++++++++++++++ src/bin/psql/describe.h | 3 ++ src/bin/psql/help.c | 1 + 5 files changed, 137 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 48248f7..c6704d7 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1388,6 +1388,24 @@ testdb=> + \dco[cfptuxS] [ pattern ] + + + Lists constraints. + If pattern + is specified, only entries whose name matches the pattern are listed. + The modifiers c (check), f (foreign key), + p (primary key), t (trigger), + u (unique), x (exclusion) can be + appended to the command, filtering the kind of constraints to list. + By default, only user-created constraints are shown; supply the + S modifier to include system objects. + + + + + + \dC[+] [ pattern ] diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 3de9d09..0379610 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -769,7 +769,23 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) success = describeTablespaces(pattern, show_verbose); break; case 'c': - success = listConversions(pattern, show_verbose, show_system); + if (strncmp(cmd, "dco", 3) == 0) /* Constraint */ + switch (cmd[3]) + { + case '\0': + case 'S': + case 'c': + case 'f': + case 'p': + case 'u': + case 't': + case 'x': + success = listConstraints(&cmd[2], pattern, show_system); + break; + default: + status = PSQL_CMD_UNKNOWN; + break; + } break; case 'C': success = listCasts(pattern, show_verbose); diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index ea721d9..4724d63 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -18,6 +18,7 @@ #include "catalog/pg_attribute_d.h" #include "catalog/pg_cast_d.h" #include "catalog/pg_class_d.h" +#include "catalog/pg_constraint_d.h" #include "catalog/pg_default_acl_d.h" #include "common.h" #include "common/logging.h" @@ -4816,6 +4817,103 @@ listExtendedStats(const char *pattern) } /* + * \dco + * + * Describes constraints + * + * As with \d, you can specify the kinds of constraints you want: + * + * c for check + * f for foreign key + * p for primary key + * t for trigger + * u for unique + * x for exclusion + * + * and you can mix and match these in any order. + */ +bool +listConstraints(const char *contypes, const char *pattern, bool showSystem) +{ + bool showCheck = strchr(contypes, CONSTRAINT_CHECK) != NULL; + bool showForeign = strchr(contypes, CONSTRAINT_FOREIGN) != NULL; + bool showPrimary = strchr(contypes, CONSTRAINT_PRIMARY) != NULL; + bool showTrigger = strchr(contypes, CONSTRAINT_TRIGGER) != NULL; + bool showUnique = strchr(contypes, CONSTRAINT_UNIQUE) != NULL; + bool showExclusion = strchr(contypes, CONSTRAINT_EXCLUSION) != NULL; + bool showAllkinds = false; + PQExpBufferData buf; + PGresult *res; + printQueryOpt myopt = pset.popt; + + /* If contype was not selected, show them all */ + if (!(showCheck || showForeign || showPrimary || showTrigger || showUnique || showExclusion)) + showAllkinds = true; + + initPQExpBuffer(&buf); + printfPQExpBuffer(&buf, + "SELECT \n" + " n.nspname AS \"%s\", \n" + " cst.conname AS \"%s\", \n" + " pg_catalog.pg_get_constraintdef(cst.oid) AS \"%s\", \n" + " conrelid::pg_catalog.regclass AS \"%s\" \n" + "FROM pg_catalog.pg_constraint cst \n" + " JOIN pg_catalog.pg_namespace n ON n.oid = cst.connamespace \n", + gettext_noop("Schema"), + gettext_noop("Name"), + gettext_noop("Definition"), + gettext_noop("Table") + ); + + if (!showSystem && !pattern) + appendPQExpBufferStr(&buf, + "WHERE n.nspname <> 'pg_catalog' \n" + " AND n.nspname <> 'information_schema' \n"); + + processSQLNamePattern(pset.db, &buf, pattern, + !showSystem && !pattern, false, + "n.nspname", "cst.conname", + NULL, "pg_catalog.pg_table_is_visible(cst.conrelid)"); + + if (!showAllkinds) + { + appendPQExpBufferStr(&buf, " AND cst.contype in ("); + + if (showCheck) + appendPQExpBufferStr(&buf, CppAsString2(CONSTRAINT_CHECK) ","); + if (showForeign) + appendPQExpBufferStr(&buf, CppAsString2(CONSTRAINT_FOREIGN) ","); + if (showPrimary) + appendPQExpBufferStr(&buf, CppAsString2(CONSTRAINT_PRIMARY) ","); + if (showTrigger) + appendPQExpBufferStr(&buf, CppAsString2(CONSTRAINT_TRIGGER) ","); + if (showUnique) + appendPQExpBufferStr(&buf, CppAsString2(CONSTRAINT_UNIQUE) ","); + if (showExclusion) + appendPQExpBufferStr(&buf, CppAsString2(CONSTRAINT_EXCLUSION) ","); + + appendPQExpBufferStr(&buf, "''"); /* dummy */ + appendPQExpBufferStr(&buf, ")\n"); + } + + appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;"); + + res = PSQLexec(buf.data); + termPQExpBuffer(&buf); + if (!res) + return false; + + myopt.nullPrint = NULL; + myopt.title = _("List of constraints"); + myopt.translate_header = true; + + printQuery(res, &myopt, pset.queryFout, false, pset.logfile); + + PQclear(res); + return true; +} + +/* * \dC * * Describes casts. diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 71b320f..083ca6c 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -76,6 +76,9 @@ extern bool listDomains(const char *pattern, bool verbose, bool showSystem); /* \dc */ extern bool listConversions(const char *pattern, bool verbose, bool showSystem); +/* \dco */ +extern bool listConstraints(const char *contypes, const char *pattern, bool showSystem); + /* \dC */ extern bool listCasts(const char *pattern, bool verbose); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index db12a8b..0804b9c 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -231,6 +231,7 @@ slashUsage(unsigned short int pager) fprintf(output, _(" \\dAp[+] [AMPTRN [OPFPTRN]] list support functions of operator families\n")); fprintf(output, _(" \\db[+] [PATTERN] list tablespaces\n")); fprintf(output, _(" \\dc[S+] [PATTERN] list conversions\n")); + fprintf(output, _(" \\dco[cfptuxS] [PATTERN] list constraints\n")); fprintf(output, _(" \\dC[+] [PATTERN] list casts\n")); fprintf(output, _(" \\dd[S] [PATTERN] show object descriptions not displayed elsewhere\n")); fprintf(output, _(" \\dD[S+] [PATTERN] list domains\n")); -- 1.8.3.1