While looking at this report

http://archives.postgresql.org/pgsql-bugs/2009-08/msg00083.php

I spotted another error message which could use improvement:

CREATE TABLE foo(a int PRIMARY KEY DEFERRABLE);
CREATE TABLE bar(a int REFERENCES foo(a));

ERROR:  there is no unique constraint matching given keys for
referenced table "foo"

Whereas if you define the FK slightly differently so that it goes
through transformFkeyGetPrimaryKey() instead, you get a much better
error message:

CREATE TABLE bar(a int REFERENCES foo);

ERROR:  cannot use a deferrable primary key for referenced table "foo"

The attached patch to transformFkeyCheckAttrs() makes the former case
generate a similar error to the latter.

 - Dean
*** ./src/backend/commands/tablecmds.c.orig	2009-08-12 09:47:34.000000000 +0100
--- ./src/backend/commands/tablecmds.c	2009-08-12 10:08:13.000000000 +0100
***************
*** 5117,5122 ****
--- 5117,5123 ----
  {
  	Oid			indexoid = InvalidOid;
  	bool		found = false;
+ 	bool		found_deferrable = false;
  	List	   *indexoidlist;
  	ListCell   *indexoidscan;
  
***************
*** 5148,5154 ****
  		 * expressions, too
  		 */
  		if (indexStruct->indnatts == numattrs &&
! 			indexStruct->indisunique && indexStruct->indimmediate &&
  			heap_attisnull(indexTuple, Anum_pg_index_indpred) &&
  			heap_attisnull(indexTuple, Anum_pg_index_indexprs))
  		{
--- 5149,5155 ----
  		 * expressions, too
  		 */
  		if (indexStruct->indnatts == numattrs &&
! 			indexStruct->indisunique &&
  			heap_attisnull(indexTuple, Anum_pg_index_indpred) &&
  			heap_attisnull(indexTuple, Anum_pg_index_indexprs))
  		{
***************
*** 5198,5203 ****
--- 5199,5219 ----
  						break;
  				}
  			}
+ 
+ 			/*
+ 			 * Refuse to use a deferrable unique/primary key.  This is per
+ 			 * SQL spec, and there would be a lot of interesting semantic
+ 			 * problems if we tried to allow it.
+ 			 */
+ 			if (found && !indexStruct->indimmediate)
+ 			{
+ 				/*
+ 				 * Remember that we found an otherwise matching index, so
+ 				 * that we can generate a more appropriate error message.
+ 				 */
+ 				found_deferrable = true;
+ 				found = false;
+ 			}
  		}
  		ReleaseSysCache(indexTuple);
  		if (found)
***************
*** 5205,5214 ****
  	}
  
  	if (!found)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_FOREIGN_KEY),
! 				 errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
! 						RelationGetRelationName(pkrel))));
  
  	list_free(indexoidlist);
  
--- 5221,5238 ----
  	}
  
  	if (!found)
! 	{
! 		if (found_deferrable)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! 					 errmsg("cannot use a deferrable unique constraint for referenced table \"%s\"",
! 							RelationGetRelationName(pkrel))));
! 		else
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_FOREIGN_KEY),
! 					 errmsg("there is no unique constraint matching given keys for referenced table \"%s\"",
! 							RelationGetRelationName(pkrel))));
! 	}
  
  	list_free(indexoidlist);
  
-- 
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