From: Tom Lane Date: Wed, 12 Aug 2009 23:00:12 +0000 (+0000) Subject: Improve error message for the case where a requested foreign key constraint X-Git-Tag: REL8_5_ALPHA1~32 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b6bde524af5573f3db43c4b150fab0cbbf928670;p=postgresql Improve error message for the case where a requested foreign key constraint does match some unique index on the referenced table, but that index is only deferrably unique. We were doing this nicely for the default-to-primary-key case, but were being lazy for the other case. Dean Rasheed --- diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f51f1f8c48..07bc393200 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.296 2009/08/07 15:27:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.297 2009/08/12 23:00:12 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -5117,6 +5117,7 @@ transformFkeyCheckAttrs(Relation pkrel, { Oid indexoid = InvalidOid; bool found = false; + bool found_deferrable = false; List *indexoidlist; ListCell *indexoidscan; @@ -5143,12 +5144,11 @@ transformFkeyCheckAttrs(Relation pkrel, indexStruct = (Form_pg_index) GETSTRUCT(indexTuple); /* - * Must have the right number of columns; must be unique (non - * deferrable) and not a partial index; forget it if there are any - * expressions, too + * Must have the right number of columns; must be unique and not a + * partial index; forget it if there are any expressions, too */ if (indexStruct->indnatts == numattrs && - indexStruct->indisunique && indexStruct->indimmediate && + indexStruct->indisunique && heap_attisnull(indexTuple, Anum_pg_index_indpred) && heap_attisnull(indexTuple, Anum_pg_index_indexprs)) { @@ -5198,6 +5198,21 @@ transformFkeyCheckAttrs(Relation pkrel, 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,10 +5220,18 @@ transformFkeyCheckAttrs(Relation pkrel, } if (!found) - ereport(ERROR, - (errcode(ERRCODE_INVALID_FOREIGN_KEY), - errmsg("there is no unique constraint matching given keys for referenced table \"%s\"", - RelationGetRelationName(pkrel)))); + { + 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);