Awhile back I wrote: > * I'm not too satisfied with the behavior of psql's \d:
> regression=# create table foo (f1 int primary key using index tablespace ts1, > regression(# f2 int, EXCLUDE USING btree (f2 WITH =) using index tablespace > ts1, > regression(# f3 int, EXCLUDE USING btree (f3 WITH =) DEFERRABLE INITIALLY > DEFERRED); > NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for > table "foo" > NOTICE: CREATE TABLE / EXCLUDE will create implicit index "foo_f2_exclusion" > for table "foo" > NOTICE: CREATE TABLE / EXCLUDE will create implicit index "foo_f3_exclusion" > for table "foo" > CREATE TABLE > regression=# \d foo > Table "public.foo" > Column | Type | Modifiers > --------+---------+----------- > f1 | integer | not null > f2 | integer | > f3 | integer | > Indexes: > "foo_pkey" PRIMARY KEY, btree (f1), tablespace "ts1" > "foo_f2_exclusion" btree (f2), tablespace "ts1" > "foo_f3_exclusion" btree (f3) DEFERRABLE INITIALLY DEFERRED > Exclusion constraints: > "foo_f2_exclusion" EXCLUDE USING btree (f2 WITH =) > "foo_f3_exclusion" EXCLUDE USING btree (f3 WITH =) DEFERRABLE INITIALLY > DEFERRED > regression=# > This might have been defensible back when the idea was to keep constraints > decoupled from indexes, but now it just looks bizarre. We should either > get rid of the "Exclusion constraints:" display and attach the info to > the index entries, or hide indexes that are attached to exclusion > constraints. I lean to the former on the grounds of the precedent for > unique/pkey indexes --- which is not totally arbitrary, since an index > is usable as a query index regardless of its function as a constraint. > It's probably a debatable point though. Attached is a patch against HEAD that folds exclusion constraints into \d's regular indexes list. With this, the above example produces Table "public.foo" Column | Type | Modifiers --------+---------+----------- f1 | integer | not null f2 | integer | f3 | integer | Indexes: "foo_pkey" PRIMARY KEY, btree (f1), tablespace "ts1" "foo_f2_exclusion" EXCLUDE USING btree (f2 WITH =), tablespace "ts1" "foo_f3_exclusion" EXCLUDE USING btree (f3 WITH =) DEFERRABLE INITIALLY DEFERRED Any objections? regards, tom lane
? psql Index: describe.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/describe.c,v retrieving revision 1.240 diff -c -r1.240 describe.c *** describe.c 11 Mar 2010 04:36:43 -0000 1.240 --- describe.c 11 Mar 2010 05:18:28 -0000 *************** *** 1105,1111 **** bool hasrules; bool hastriggers; bool hasoids; - bool hasexclusion; Oid tablespace; char *reloptions; char *reloftype; --- 1105,1110 ---- *************** *** 1128,1135 **** printfPQExpBuffer(&buf, "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, " "c.relhastriggers, c.relhasoids, " ! "%s, c.reltablespace, c.relhasexclusion, " ! "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::text END\n" "FROM pg_catalog.pg_class c\n " "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n" "WHERE c.oid = '%s'\n", --- 1127,1134 ---- printfPQExpBuffer(&buf, "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, " "c.relhastriggers, c.relhasoids, " ! "%s, c.reltablespace, " ! "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END\n" "FROM pg_catalog.pg_class c\n " "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n" "WHERE c.oid = '%s'\n", *************** *** 1207,1216 **** strdup(PQgetvalue(res, 0, 6)) : 0; tableinfo.tablespace = (pset.sversion >= 80000) ? atooid(PQgetvalue(res, 0, 7)) : 0; ! tableinfo.hasexclusion = (pset.sversion >= 90000) ? ! strcmp(PQgetvalue(res, 0, 8), "t") == 0 : false; ! tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 9), "") != 0) ? ! strdup(PQgetvalue(res, 0, 9)) : 0; PQclear(res); res = NULL; --- 1206,1213 ---- strdup(PQgetvalue(res, 0, 6)) : 0; tableinfo.tablespace = (pset.sversion >= 80000) ? atooid(PQgetvalue(res, 0, 7)) : 0; ! tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 8), "") != 0) ? ! strdup(PQgetvalue(res, 0, 8)) : 0; PQclear(res); res = NULL; *************** *** 1545,1571 **** appendPQExpBuffer(&buf, "i.indisvalid, "); else appendPQExpBuffer(&buf, "true as indisvalid, "); ! appendPQExpBuffer(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)"); if (pset.sversion >= 90000) appendPQExpBuffer(&buf, ! ",\n (NOT i.indimmediate) AND " ! "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint " ! "WHERE conrelid = i.indrelid AND " ! "conindid = i.indexrelid AND " ! "contype IN ('p','u','x') AND " ! "condeferrable) AS condeferrable" ! ",\n (NOT i.indimmediate) AND " ! "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint " ! "WHERE conrelid = i.indrelid AND " ! "conindid = i.indexrelid AND " ! "contype IN ('p','u','x') AND " ! "condeferred) AS condeferred"); else ! appendPQExpBuffer(&buf, ", false AS condeferrable, false AS condeferred"); if (pset.sversion >= 80000) appendPQExpBuffer(&buf, ", c2.reltablespace"); appendPQExpBuffer(&buf, ! "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n" "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n" "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname", oid); --- 1542,1564 ---- appendPQExpBuffer(&buf, "i.indisvalid, "); else appendPQExpBuffer(&buf, "true as indisvalid, "); ! appendPQExpBuffer(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n "); if (pset.sversion >= 90000) appendPQExpBuffer(&buf, ! "pg_catalog.pg_get_constraintdef(con.oid, true), " ! "contype, condeferrable, condeferred"); else ! appendPQExpBuffer(&buf, ! "null AS constraintdef, null AS contype, " ! "false AS condeferrable, false AS condeferred"); if (pset.sversion >= 80000) appendPQExpBuffer(&buf, ", c2.reltablespace"); appendPQExpBuffer(&buf, ! "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"); ! if (pset.sversion >= 90000) ! appendPQExpBuffer(&buf, ! " LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n"); ! appendPQExpBuffer(&buf, "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n" "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname", oid); *************** *** 1580,1625 **** printTableAddFooter(&cont, _("Indexes:")); for (i = 0; i < tuples; i++) { - const char *indexdef; - const char *usingpos; - /* untranslated index name */ printfPQExpBuffer(&buf, " \"%s\"", PQgetvalue(result, i, 0)); ! /* Label as primary key or unique (but not both) */ ! appendPQExpBuffer(&buf, ! strcmp(PQgetvalue(result, i, 1), "t") == 0 ! ? " PRIMARY KEY," : ! (strcmp(PQgetvalue(result, i, 2), "t") == 0 ! ? " UNIQUE," ! : "")); ! /* Everything after "USING" is echoed verbatim */ ! indexdef = PQgetvalue(result, i, 5); ! usingpos = strstr(indexdef, " USING "); ! if (usingpos) ! indexdef = usingpos + 7; ! appendPQExpBuffer(&buf, " %s", indexdef); if (strcmp(PQgetvalue(result, i, 3), "t") == 0) appendPQExpBuffer(&buf, " CLUSTER"); if (strcmp(PQgetvalue(result, i, 4), "t") != 0) appendPQExpBuffer(&buf, " INVALID"); - if (strcmp(PQgetvalue(result, i, 6), "t") == 0) - appendPQExpBuffer(&buf, " DEFERRABLE"); - - if (strcmp(PQgetvalue(result, i, 7), "t") == 0) - appendPQExpBuffer(&buf, " INITIALLY DEFERRED"); - printTableAddFooter(&cont, buf.data); /* Print tablespace of the index on the same line */ if (pset.sversion >= 80000) add_tablespace_footer(&cont, 'i', ! atooid(PQgetvalue(result, i, 8)), false); } } --- 1573,1627 ---- printTableAddFooter(&cont, _("Indexes:")); for (i = 0; i < tuples; i++) { /* untranslated index name */ printfPQExpBuffer(&buf, " \"%s\"", PQgetvalue(result, i, 0)); ! /* If exclusion constraint, print the constraintdef */ ! if (strcmp(PQgetvalue(result, i, 7), "x") == 0) ! { ! appendPQExpBuffer(&buf, " %s", ! PQgetvalue(result, i, 6)); ! } ! else ! { ! const char *indexdef; ! const char *usingpos; ! ! /* Label as primary key or unique (but not both) */ ! if (strcmp(PQgetvalue(result, i, 1), "t") == 0) ! appendPQExpBuffer(&buf, " PRIMARY KEY,"); ! else if (strcmp(PQgetvalue(result, i, 2), "t") == 0) ! appendPQExpBuffer(&buf, " UNIQUE,"); ! ! /* Everything after "USING" is echoed verbatim */ ! indexdef = PQgetvalue(result, i, 5); ! usingpos = strstr(indexdef, " USING "); ! if (usingpos) ! indexdef = usingpos + 7; ! appendPQExpBuffer(&buf, " %s", indexdef); ! /* Need these for deferrable PK/UNIQUE indexes */ ! if (strcmp(PQgetvalue(result, i, 8), "t") == 0) ! appendPQExpBuffer(&buf, " DEFERRABLE"); + if (strcmp(PQgetvalue(result, i, 9), "t") == 0) + appendPQExpBuffer(&buf, " INITIALLY DEFERRED"); + } + + /* Add these for all cases */ if (strcmp(PQgetvalue(result, i, 3), "t") == 0) appendPQExpBuffer(&buf, " CLUSTER"); if (strcmp(PQgetvalue(result, i, 4), "t") != 0) appendPQExpBuffer(&buf, " INVALID"); printTableAddFooter(&cont, buf.data); /* Print tablespace of the index on the same line */ if (pset.sversion >= 80000) add_tablespace_footer(&cont, 'i', ! atooid(PQgetvalue(result, i, 10)), false); } } *************** *** 1657,1694 **** PQclear(result); } - /* print exclusion constraints */ - if (tableinfo.hasexclusion) - { - printfPQExpBuffer(&buf, - "SELECT r.conname, " - "pg_catalog.pg_get_constraintdef(r.oid, true)\n" - "FROM pg_catalog.pg_constraint r\n" - "WHERE r.conrelid = '%s' AND r.contype = 'x'\n" - "ORDER BY 1", - oid); - result = PSQLexec(buf.data, false); - if (!result) - goto error_return; - else - tuples = PQntuples(result); - - if (tuples > 0) - { - printTableAddFooter(&cont, _("Exclusion constraints:")); - for (i = 0; i < tuples; i++) - { - /* untranslated contraint name and def */ - printfPQExpBuffer(&buf, " \"%s\" %s", - PQgetvalue(result, i, 0), - PQgetvalue(result, i, 1)); - - printTableAddFooter(&cont, buf.data); - } - } - PQclear(result); - } - /* print foreign-key constraints (there are none if no triggers) */ if (tableinfo.hastriggers) { --- 1659,1664 ----
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers