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

Reply via email to