diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index b940315bbf18c794866fba88f4f2bf3ea995c68b..ed95d8ed6c444a4af6ba4cc1da5a7fdbeea80f52 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -17,7 +17,7 @@ * * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.51 2003/06/11 15:02:25 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.52 2003/07/22 22:14:57 tgl Exp $ * * ---------- */ @@ -204,16 +204,8 @@ RI_FKey_check(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_check", RI_TRIGTYPE_INUP); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_check()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_check()", - RI_MAX_NUMKEYS); /* * Get the relation descriptors of the FK and PK tables and the new @@ -221,16 +213,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) * * pk_rel is opened in RowShareLock mode since that's what our eventual * SELECT FOR UPDATE will get on it. - * - * Error check here is needed because of ancient pg_dump bug; see notes - * in CreateTrigger(). */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - pk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock); fk_rel = trigdata->tg_relation; if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) @@ -277,7 +260,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) tgnargs, tgargs); if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_check()"); + elog(ERROR, "SPI_connect failed"); if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { @@ -308,7 +291,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_check()"); + elog(ERROR, "SPI_finish failed"); heap_close(pk_rel, RowShareLock); @@ -319,10 +302,9 @@ RI_FKey_check(PG_FUNCTION_ARGS) match_type = ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]); if (match_type == RI_MATCH_TYPE_PARTIAL) - { - elog(ERROR, "MATCH PARTIAL not yet supported"); - return PointerGetDatum(NULL); - } + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); ri_BuildQueryKeyFull(&qkey, trigdata->tg_trigger->tgoid, RI_PLAN_CHECK_LOOKUPPK, fk_rel, pk_rel, @@ -356,10 +338,12 @@ RI_FKey_check(PG_FUNCTION_ARGS) * Not allowed - MATCH FULL says either all or none of * the attributes can be NULLs */ - elog(ERROR, "%s referential integrity violation - " - "MATCH FULL doesn't allow mixing of NULL " - "and NON-NULL key values", - tgargs[RI_CONSTRAINT_NAME_ARGNO]); + ereport(ERROR, + (errcode(ERRCODE_FOREIGN_KEY_VIOLATION), + errmsg("insert or update on \"%s\" violates foreign key constraint \"%s\"", + RelationGetRelationName(trigdata->tg_relation), + tgargs[RI_CONSTRAINT_NAME_ARGNO]), + errdetail("MATCH FULL does not allow mixing of NULL and non-NULL key values."))); heap_close(pk_rel, RowShareLock); return PointerGetDatum(NULL); @@ -380,7 +364,9 @@ RI_FKey_check(PG_FUNCTION_ARGS) * query below to only include non-null columns, or by * writing a special version here) */ - elog(ERROR, "MATCH PARTIAL not yet implemented"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); heap_close(pk_rel, RowShareLock); return PointerGetDatum(NULL); } @@ -409,7 +395,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_check()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the real check @@ -462,7 +448,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_check()"); + elog(ERROR, "SPI_finish failed"); heap_close(pk_rel, RowShareLock); @@ -554,7 +540,9 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, * query below to only include non-null columns, or by * writing a special version here) */ - elog(ERROR, "MATCH PARTIAL not yet implemented"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); break; } @@ -568,7 +556,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_check()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the real check @@ -620,7 +608,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, SPI_OK_SELECT, NULL); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in ri_Check_Pk_Match()"); + elog(ERROR, "SPI_finish failed"); return result; } @@ -656,16 +644,8 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_noaction_del", RI_TRIGTYPE_DELETE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_noaction_del()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_noaction_del()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -680,12 +660,6 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) * fk_rel is opened in RowShareLock mode since that's what our eventual * SELECT FOR UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock); pk_rel = trigdata->tg_relation; old_row = trigdata->tg_trigtuple; @@ -740,7 +714,7 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_noaction_del()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the restrict delete @@ -794,7 +768,7 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_noaction_del()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowShareLock); @@ -804,14 +778,16 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL restrict delete. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #2 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -847,16 +823,8 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_noaction_upd", RI_TRIGTYPE_UPDATE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_noaction_upd()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_noaction_upd()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -871,12 +839,6 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) * fk_rel is opened in RowShareLock mode since that's what our eventual * SELECT FOR UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock); pk_rel = trigdata->tg_relation; new_row = trigdata->tg_newtuple; @@ -943,7 +905,7 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_noaction_upd()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the noaction update @@ -997,7 +959,7 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_noaction_upd()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowShareLock); @@ -1007,14 +969,16 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL noaction update. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #3 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -1046,16 +1010,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_cascade_del", RI_TRIGTYPE_DELETE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_cascade_del()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_cascade_del()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -1070,12 +1026,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) * fk_rel is opened in RowExclusiveLock mode since that's what our * eventual DELETE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock); pk_rel = trigdata->tg_relation; old_row = trigdata->tg_trigtuple; @@ -1117,7 +1067,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_cascade_del()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the cascaded delete @@ -1171,7 +1121,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_cascade_del()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowExclusiveLock); @@ -1181,14 +1131,16 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL cascaded delete. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #4 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -1222,16 +1174,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_cascade_upd", RI_TRIGTYPE_UPDATE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_cascade_upd()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_cascade_upd()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -1246,12 +1190,6 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) * fk_rel is opened in RowExclusiveLock mode since that's what our * eventual UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock); pk_rel = trigdata->tg_relation; new_row = trigdata->tg_newtuple; @@ -1304,7 +1242,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_cascade_upd()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the cascaded update of @@ -1367,7 +1305,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_cascade_upd()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowExclusiveLock); @@ -1377,14 +1315,16 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL cascade update. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #5 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -1423,16 +1363,8 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_restrict_del", RI_TRIGTYPE_DELETE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_restrict_del()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_restrict_del()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -1447,12 +1379,6 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) * fk_rel is opened in RowShareLock mode since that's what our eventual * SELECT FOR UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock); pk_rel = trigdata->tg_relation; old_row = trigdata->tg_trigtuple; @@ -1494,7 +1420,7 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_restrict_del()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the restrict delete @@ -1548,7 +1474,7 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_restrict_del()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowShareLock); @@ -1558,14 +1484,16 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL restrict delete. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #6 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -1605,16 +1533,8 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_restrict_upd", RI_TRIGTYPE_UPDATE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_restrict_upd()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_restrict_upd()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -1629,12 +1549,6 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) * fk_rel is opened in RowShareLock mode since that's what our eventual * SELECT FOR UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock); pk_rel = trigdata->tg_relation; new_row = trigdata->tg_newtuple; @@ -1687,7 +1601,7 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_restrict_upd()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the restrict update @@ -1741,7 +1655,7 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_restrict_upd()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowShareLock); @@ -1751,14 +1665,16 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL restrict update. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #7 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -1790,16 +1706,8 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_setnull_del", RI_TRIGTYPE_DELETE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_setnull_del()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_setnull_del()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -1814,12 +1722,6 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) * fk_rel is opened in RowExclusiveLock mode since that's what our * eventual UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock); pk_rel = trigdata->tg_relation; old_row = trigdata->tg_trigtuple; @@ -1861,7 +1763,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_setnull_del()"); + elog(ERROR, "SPI_connect failed"); /* * Fetch or prepare a saved plan for the set null delete @@ -1923,7 +1825,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_setnull_del()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowExclusiveLock); @@ -1933,14 +1835,16 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL set null delete. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #8 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -1975,16 +1879,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_setnull_upd", RI_TRIGTYPE_UPDATE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_setnull_upd()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_setnull_upd()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -1999,12 +1895,6 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) * fk_rel is opened in RowExclusiveLock mode since that's what our * eventual UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock); pk_rel = trigdata->tg_relation; new_row = trigdata->tg_newtuple; @@ -2058,7 +1948,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_setnull_upd()"); + elog(ERROR, "SPI_connect failed"); /* * "MATCH <unspecified>" only changes columns corresponding to @@ -2153,7 +2043,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_setnull_upd()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowExclusiveLock); @@ -2163,14 +2053,16 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL set null update. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #9 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -2201,16 +2093,8 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_del", RI_TRIGTYPE_DELETE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_setdefault_del()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_setdefault_del()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -2225,12 +2109,6 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) * fk_rel is opened in RowExclusiveLock mode since that's what our * eventual UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock); pk_rel = trigdata->tg_relation; old_row = trigdata->tg_trigtuple; @@ -2272,7 +2150,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_setdefault_del()"); + elog(ERROR, "SPI_connect failed"); /* * Prepare a plan for the set default delete operation. @@ -2365,7 +2243,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_setdefault_del()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowExclusiveLock); @@ -2385,14 +2263,16 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL set null delete. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #10 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -2425,16 +2305,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) */ ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_upd", RI_TRIGTYPE_UPDATE); - /* - * Check for the correct # of call arguments - */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_setdefault_upd()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_setdefault_upd()", - RI_MAX_NUMKEYS); /* * Nothing to do if no column names to compare given @@ -2449,12 +2321,6 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) * fk_rel is opened in RowExclusiveLock mode since that's what our * eventual UPDATE will get on it. */ - if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); - fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock); pk_rel = trigdata->tg_relation; new_row = trigdata->tg_newtuple; @@ -2509,7 +2375,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) } if (SPI_connect() != SPI_OK_CONNECT) - elog(ERROR, "SPI_connect() failed in RI_FKey_setdefault_upd()"); + elog(ERROR, "SPI_connect failed"); /* * Prepare a plan for the set default delete operation. @@ -2612,7 +2478,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) tgargs[RI_CONSTRAINT_NAME_ARGNO]); if (SPI_finish() != SPI_OK_FINISH) - elog(ERROR, "SPI_finish() failed in RI_FKey_setdefault_upd()"); + elog(ERROR, "SPI_finish failed"); heap_close(fk_rel, RowExclusiveLock); @@ -2632,14 +2498,16 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) * Handle MATCH PARTIAL set null delete. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); return PointerGetDatum(NULL); } /* * Never reached */ - elog(ERROR, "internal error #11 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return PointerGetDatum(NULL); } @@ -2669,11 +2537,13 @@ RI_FKey_keyequal_upd(TriggerData *trigdata) */ tgnargs = trigdata->tg_trigger->tgnargs; tgargs = trigdata->tg_trigger->tgargs; - if (tgnargs < 4 || (tgnargs % 2) != 0) - elog(ERROR, "wrong # of arguments in call to RI_FKey_keyequal_upd()"); - if (tgnargs > RI_MAX_ARGUMENTS) - elog(ERROR, "too many keys (%d max) in call to RI_FKey_keyequal_upd()", - RI_MAX_NUMKEYS); + if (tgnargs < 4 || + tgnargs > RI_MAX_ARGUMENTS || + (tgnargs % 2) != 0) + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("%s() called with wrong number of trigger arguments", + "RI_FKey_keyequal_upd"))); /* * Nothing to do if no column names to compare given @@ -2688,10 +2558,12 @@ RI_FKey_keyequal_upd(TriggerData *trigdata) * Use minimal locking for fk_rel here. */ if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) - elog(ERROR, "No target table given for trigger \"%s\" on \"%s\"" - "\n\tRemove these RI triggers and do ALTER TABLE ADD CONSTRAINT", - trigdata->tg_trigger->tgname, - RelationGetRelationName(trigdata->tg_relation)); + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("no target table given for trigger \"%s\" on \"%s\"", + trigdata->tg_trigger->tgname, + RelationGetRelationName(trigdata->tg_relation)), + errhint("Remove this RI trigger and its mates, then do ALTER TABLE ADD CONSTRAINT."))); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, AccessShareLock); pk_rel = trigdata->tg_relation; @@ -2722,14 +2594,16 @@ RI_FKey_keyequal_upd(TriggerData *trigdata) * Handle MATCH PARTIAL set null delete. */ case RI_MATCH_TYPE_PARTIAL: - elog(ERROR, "MATCH PARTIAL not yet supported"); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("MATCH PARTIAL not yet implemented"))); break; } /* * Never reached */ - elog(ERROR, "internal error #12 in ri_triggers.c"); + elog(ERROR, "invalid match_type"); return false; } @@ -2794,7 +2668,7 @@ ri_DetermineMatchType(char *str) if (strcmp(str, "PARTIAL") == 0) return RI_MATCH_TYPE_PARTIAL; - elog(ERROR, "unrecognized referential integrity MATCH type '%s'", str); + elog(ERROR, "unrecognized referential integrity match type \"%s\"", str); return 0; } @@ -2844,18 +2718,22 @@ ri_BuildQueryKeyFull(RI_QueryKey *key, Oid constr_id, int32 constr_queryno, { fno = SPI_fnumber(fk_rel->rd_att, argv[j]); if (fno == SPI_ERROR_NOATTRIBUTE) - elog(ERROR, "constraint %s: table %s does not have an attribute %s", - argv[RI_CONSTRAINT_NAME_ARGNO], - RelationGetRelationName(fk_rel), - argv[j]); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("table \"%s\" does not have attribute \"%s\" referenced by constraint \"%s\"", + RelationGetRelationName(fk_rel), + argv[j], + argv[RI_CONSTRAINT_NAME_ARGNO]))); key->keypair[i][RI_KEYPAIR_FK_IDX] = fno; fno = SPI_fnumber(pk_rel->rd_att, argv[j + 1]); if (fno == SPI_ERROR_NOATTRIBUTE) - elog(ERROR, "constraint %s: table %s does not have an attribute %s", - argv[RI_CONSTRAINT_NAME_ARGNO], - RelationGetRelationName(pk_rel), - argv[j + 1]); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("table \"%s\" does not have attribute \"%s\" referenced by constraint \"%s\"", + RelationGetRelationName(pk_rel), + argv[j + 1], + argv[RI_CONSTRAINT_NAME_ARGNO]))); key->keypair[i][RI_KEYPAIR_PK_IDX] = fno; } } @@ -2867,34 +2745,75 @@ static void ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname, int tgkind) { TriggerData *trigdata = (TriggerData *) fcinfo->context; + int tgnargs; if (!CALLED_AS_TRIGGER(fcinfo)) - elog(ERROR, "%s() not fired by trigger manager", funcname); + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("%s() was not fired by trigger manager", funcname))); + + /* + * Check proper event + */ if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) - elog(ERROR, "%s() must be fired AFTER ROW", funcname); + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("%s() must be fired AFTER ROW", funcname))); switch (tgkind) { case RI_TRIGTYPE_INSERT: if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) - elog(ERROR, "%s() must be fired for INSERT", funcname); + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("%s() must be fired for INSERT", funcname))); break; case RI_TRIGTYPE_UPDATE: if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - elog(ERROR, "%s() must be fired for UPDATE", funcname); + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("%s() must be fired for UPDATE", funcname))); break; case RI_TRIGTYPE_INUP: if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) && !TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) - elog(ERROR, "%s() must be fired for INSERT or UPDATE", - funcname); + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("%s() must be fired for INSERT or UPDATE", + funcname))); break; case RI_TRIGTYPE_DELETE: if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) - elog(ERROR, "%s() must be fired for DELETE", funcname); + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("%s() must be fired for DELETE", funcname))); break; } + + /* + * Check for the correct # of call arguments + */ + tgnargs = trigdata->tg_trigger->tgnargs; + if (tgnargs < 4 || + tgnargs > RI_MAX_ARGUMENTS || + (tgnargs % 2) != 0) + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("%s() called with wrong number of trigger arguments", + funcname))); + + /* + * Check that tgconstrrelid is known. We need to check here because of + * ancient pg_dump bug; see notes in CreateTrigger(). + */ + if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("no target table given for trigger \"%s\" on \"%s\"", + trigdata->tg_trigger->tgname, + RelationGetRelationName(trigdata->tg_relation)), + errhint("Remove this RI trigger and its mates, then do ALTER TABLE ADD CONSTRAINT."))); } @@ -3025,7 +2944,7 @@ ri_PerformCheck(RI_QueryKey *qkey, void *qplan, /* Check result */ if (spi_result < 0) - elog(ERROR, "SPI_execp() failed in ri_PerformCheck()"); + elog(ERROR, "SPI_execp failed"); if (expect_OK >= 0 && spi_result != expect_OK) ri_ReportViolation(qkey, constrname ? constrname : "", @@ -3069,9 +2988,9 @@ ri_ExtractValues(RI_QueryKey *qkey, int key_idx, * * If the failed constraint was on insert/update to the FK table, * we want the key names and values extracted from there, and the error - * message to look like 'key blah referenced from FK not found in PK'. + * message to look like 'key blah is not present in PK'. * Otherwise, the attr names and values come from the PK table and the - * message looks like 'key blah in PK still referenced from FK'. + * message looks like 'key blah is still referenced from FK'. */ static void ri_ReportViolation(RI_QueryKey *qkey, const char *constrname, @@ -3084,27 +3003,31 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname, char *name_ptr = key_names; char *val_ptr = key_values; bool onfk; - Relation rel, - other_rel; + Relation rel; int idx, key_idx; + if (spi_err) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("referential integrity query on \"%s\" from constraint \"%s\" on \"%s\" gave unexpected result", + RelationGetRelationName(pk_rel), + constrname, + RelationGetRelationName(fk_rel)), + errhint("This is most likely due to a rule having rewritten the query."))); + /* - * rel is set to where the tuple description is coming from, and it also - * is the first relation mentioned in the message, other_rel is - * respectively the other relation. + * rel is set to where the tuple description is coming from. */ onfk = (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK); if (onfk) { rel = fk_rel; - other_rel = pk_rel; key_idx = RI_KEYPAIR_FK_IDX; } else { rel = pk_rel; - other_rel = fk_rel; key_idx = RI_KEYPAIR_PK_IDX; } @@ -3115,14 +3038,12 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname, */ if (qkey->nkeypairs == 0) { - if (spi_err) - elog(ERROR, "%s referential action on %s from %s rewritten by rule", - constrname, - RelationGetRelationName(fk_rel), - RelationGetRelationName(pk_rel)); - else - elog(ERROR, "%s referential integrity violation - no rows found in %s", - constrname, RelationGetRelationName(pk_rel)); + ereport(ERROR, + (errcode(ERRCODE_FOREIGN_KEY_VIOLATION), + errmsg("insert or update on \"%s\" violates foreign key constraint \"%s\"", + RelationGetRelationName(fk_rel), constrname), + errdetail("No rows were found in \"%s\".", + RelationGetRelationName(pk_rel)))); } /* Get printable versions of the keys involved */ @@ -3151,24 +3072,25 @@ ri_ReportViolation(RI_QueryKey *qkey, const char *constrname, name_ptr += sprintf(name_ptr, "%s%s", idx > 0 ? "," : "", name); val_ptr += sprintf(val_ptr, "%s%s", idx > 0 ? "," : "", val); - } - - if (spi_err) - elog(ERROR, "%s referential action on %s from %s for (%s)=(%s) rewritten by rule", - constrname, - RelationGetRelationName(fk_rel), - RelationGetRelationName(pk_rel), - key_names, key_values); - else if (onfk) - elog(ERROR, "%s referential integrity violation - key (%s)=(%s) referenced from %s not found in %s", - constrname, key_names, key_values, - RelationGetRelationName(rel), - RelationGetRelationName(other_rel)); - else - elog(ERROR, "%s referential integrity violation - key (%s)=(%s) in %s still referenced from %s", - constrname, key_names, key_values, - RelationGetRelationName(rel), - RelationGetRelationName(other_rel)); + } + + if (onfk) + ereport(ERROR, + (errcode(ERRCODE_FOREIGN_KEY_VIOLATION), + errmsg("insert or update on \"%s\" violates foreign key constraint \"%s\"", + RelationGetRelationName(fk_rel), constrname), + errdetail("Key (%s)=(%s) is not present in \"%s\".", + key_names, key_values, + RelationGetRelationName(pk_rel)))); + else + ereport(ERROR, + (errcode(ERRCODE_FOREIGN_KEY_VIOLATION), + errmsg("update or delete on \"%s\" violates foreign key constraint \"%s\" on \"%s\"", + RelationGetRelationName(pk_rel), + constrname, RelationGetRelationName(fk_rel)), + errdetail("Key (%s)=(%s) is still referenced from \"%s\".", + key_names, key_values, + RelationGetRelationName(fk_rel)))); } /* ---------- @@ -3215,10 +3137,12 @@ ri_BuildQueryKeyPkCheck(RI_QueryKey *key, Oid constr_id, int32 constr_queryno, { fno = SPI_fnumber(pk_rel->rd_att, argv[j]); if (fno == SPI_ERROR_NOATTRIBUTE) - elog(ERROR, "constraint %s: table %s does not have an attribute %s", - argv[RI_CONSTRAINT_NAME_ARGNO], - RelationGetRelationName(pk_rel), - argv[j + 1]); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("table \"%s\" does not have attribute \"%s\" referenced by constraint \"%s\"", + RelationGetRelationName(pk_rel), + argv[j], + argv[RI_CONSTRAINT_NAME_ARGNO]))); key->keypair[i][RI_KEYPAIR_PK_IDX] = fno; key->keypair[i][RI_KEYPAIR_FK_IDX] = 0; } @@ -3343,7 +3267,9 @@ ri_HashPreparedPlan(RI_QueryKey *key, void *plan) (void *) key, HASH_ENTER, &found); if (entry == NULL) - elog(ERROR, "out of memory for RI plan cache"); + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); entry->plan = plan; } @@ -3532,7 +3458,7 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue) /* * Since fmgr_info could fail, call it *before* creating the - * hashtable entry --- otherwise we could elog leaving an + * hashtable entry --- otherwise we could ereport leaving an * incomplete entry in the hashtable. Also, because this will be * a permanent table entry, we must make sure any subsidiary * structures of the fmgr record are kept in TopMemoryContext. @@ -3543,7 +3469,9 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue) (void *) &typeid, HASH_ENTER, &found); if (entry == NULL) - elog(ERROR, "out of memory for RI operator cache"); + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); entry->typeid = typeid; memcpy(&(entry->oprfmgrinfo), &finfo, sizeof(FmgrInfo)); diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 732b0e7cfbd0b643555e9847a31a450b0c973fd1..661187269db555e7fecd592affb59cc5dd9ee6ee 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: elog.h,v 1.54 2003/07/22 19:00:12 tgl Exp $ + * $Id: elog.h,v 1.55 2003/07/22 22:14:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -162,7 +162,7 @@ #define ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION MAKE_SQLSTATE('2','3', '0','0','0') #define ERRCODE_RESTRICT_VIOLATION MAKE_SQLSTATE('2','3', '0','0','1') #define ERRCODE_NOT_NULL_VIOLATION MAKE_SQLSTATE('2','3', '5','0','2') -#define ERRCODE_FOREIGN_KEY_VALUE_NOT_FOUND MAKE_SQLSTATE('2','3', '5','0','3') +#define ERRCODE_FOREIGN_KEY_VIOLATION MAKE_SQLSTATE('2','3', '5','0','3') #define ERRCODE_UNIQUE_VIOLATION MAKE_SQLSTATE('2','3', '5','0','5') #define ERRCODE_CHECK_VIOLATION MAKE_SQLSTATE('2','3', '5','1','4') diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 677dce17ea5c2fcdcfc03946287048f111b4669c..19e60662c7f1c7446f9d0435c4401f84d84cb4ad 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -316,7 +316,8 @@ ERROR: column "b" referenced in foreign key constraint does not exist -- Try (and fail) to add constraint due to invalid data ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s) -ERROR: tmpconstr referential integrity violation - key (a)=(5) referenced from tmp3 not found in tmp2 +ERROR: insert or update on "tmp3" violates foreign key constraint "tmpconstr" +DETAIL: Key (a)=(5) is not present in "tmp2". -- Delete failing row DELETE FROM tmp3 where a=5; -- Try (and succeed) diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out index 50507fc961a5fd76937f2e87f3fc7443786d0654..9a28df62d10ba65641f1ce536d15125fe8cf37dd 100644 --- a/src/test/regress/expected/cluster.out +++ b/src/test/regress/expected/cluster.out @@ -248,7 +248,8 @@ SELECT a,b,c,substring(d for 30), length(d) from clstr_tst; -- Verify that foreign key link still works INSERT INTO clstr_tst (b, c) VALUES (1111, 'this should fail'); -ERROR: clstr_tst_con referential integrity violation - key (b)=(1111) referenced from clstr_tst not found in clstr_tst_s +ERROR: insert or update on "clstr_tst" violates foreign key constraint "clstr_tst_con" +DETAIL: Key (b)=(1111) is not present in "clstr_tst_s". SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass; conname ---------------- diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index 7ac2eb387d30add072aae0818a5e5ab7c2ee6295..cb6fc35eb6d134ad59f3490f3fb67b13e397ce96 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -22,7 +22,8 @@ INSERT INTO FKTABLE VALUES (3, 4); INSERT INTO FKTABLE VALUES (NULL, 1); -- Insert a failed row into FK TABLE INSERT INTO FKTABLE VALUES (100, 2); -ERROR: $1 referential integrity violation - key (ftest1)=(100) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "$1" +DETAIL: Key (ftest1)=(100) is not present in "pktable". -- Check FKTABLE SELECT * FROM FKTABLE; ftest1 | ftest2 @@ -80,13 +81,17 @@ INSERT INTO FKTABLE VALUES (3, 6, 12); INSERT INTO FKTABLE VALUES (NULL, NULL, 0); -- Insert failed rows into FK TABLE INSERT INTO FKTABLE VALUES (100, 2, 4); -ERROR: constrname referential integrity violation - key (ftest1,ftest2)=(100,2) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname" +DETAIL: Key (ftest1,ftest2)=(100,2) is not present in "pktable". INSERT INTO FKTABLE VALUES (2, 2, 4); -ERROR: constrname referential integrity violation - key (ftest1,ftest2)=(2,2) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname" +DETAIL: Key (ftest1,ftest2)=(2,2) is not present in "pktable". INSERT INTO FKTABLE VALUES (NULL, 2, 4); -ERROR: constrname referential integrity violation - MATCH FULL doesn't allow mixing of NULL and NON-NULL key values +ERROR: insert or update on "fktable" violates foreign key constraint "constrname" +DETAIL: MATCH FULL does not allow mixing of NULL and non-NULL key values. INSERT INTO FKTABLE VALUES (1, NULL, 4); -ERROR: constrname referential integrity violation - MATCH FULL doesn't allow mixing of NULL and NON-NULL key values +ERROR: insert or update on "fktable" violates foreign key constraint "constrname" +DETAIL: MATCH FULL does not allow mixing of NULL and non-NULL key values. -- Check FKTABLE SELECT * FROM FKTABLE; ftest1 | ftest2 | ftest3 @@ -165,13 +170,17 @@ INSERT INTO FKTABLE VALUES (3, 6, 12); INSERT INTO FKTABLE VALUES (NULL, NULL, 0); -- Insert failed rows into FK TABLE INSERT INTO FKTABLE VALUES (100, 2, 4); -ERROR: constrname2 referential integrity violation - key (ftest1,ftest2)=(100,2) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname2" +DETAIL: Key (ftest1,ftest2)=(100,2) is not present in "pktable". INSERT INTO FKTABLE VALUES (2, 2, 4); -ERROR: constrname2 referential integrity violation - key (ftest1,ftest2)=(2,2) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname2" +DETAIL: Key (ftest1,ftest2)=(2,2) is not present in "pktable". INSERT INTO FKTABLE VALUES (NULL, 2, 4); -ERROR: constrname2 referential integrity violation - MATCH FULL doesn't allow mixing of NULL and NON-NULL key values +ERROR: insert or update on "fktable" violates foreign key constraint "constrname2" +DETAIL: MATCH FULL does not allow mixing of NULL and non-NULL key values. INSERT INTO FKTABLE VALUES (1, NULL, 4); -ERROR: constrname2 referential integrity violation - MATCH FULL doesn't allow mixing of NULL and NON-NULL key values +ERROR: insert or update on "fktable" violates foreign key constraint "constrname2" +DETAIL: MATCH FULL does not allow mixing of NULL and non-NULL key values. -- Check FKTABLE SELECT * FROM FKTABLE; ftest1 | ftest2 | ftest3 @@ -250,7 +259,8 @@ INSERT INTO FKTABLE VALUES (3, 4); INSERT INTO FKTABLE VALUES (NULL, 1); -- Insert a failed row into FK TABLE INSERT INTO FKTABLE VALUES (100, 2); -ERROR: $1 referential integrity violation - key (ftest1)=(100) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "$1" +DETAIL: Key (ftest1)=(100) is not present in "pktable". -- Check FKTABLE SELECT * FROM FKTABLE; ftest1 | ftest2 @@ -274,7 +284,8 @@ SELECT * FROM PKTABLE; -- Delete a row from PK TABLE (should fail) DELETE FROM PKTABLE WHERE ptest1=1; -ERROR: $1 referential integrity violation - key (ptest1)=(1) in pktable still referenced from fktable +ERROR: update or delete on "pktable" violates foreign key constraint "$1" on "fktable" +DETAIL: Key (ptest1)=(1) is still referenced from "fktable". -- Delete a row from PK TABLE (should succeed) DELETE FROM PKTABLE WHERE ptest1=5; -- Check PKTABLE for deletes @@ -289,7 +300,8 @@ SELECT * FROM PKTABLE; -- Update a row from PK TABLE (should fail) UPDATE PKTABLE SET ptest1=0 WHERE ptest1=2; -ERROR: $1 referential integrity violation - key (ptest1)=(2) in pktable still referenced from fktable +ERROR: update or delete on "pktable" violates foreign key constraint "$1" on "fktable" +DETAIL: Key (ptest1)=(2) is still referenced from "fktable". -- Update a row from PK TABLE (should succeed) UPDATE PKTABLE SET ptest1=0 WHERE ptest1=4; -- Check PKTABLE for updates @@ -324,7 +336,8 @@ INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4); INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5); -- Insert a failed values INSERT INTO FKTABLE VALUES (1, 2, 7, 6); -ERROR: constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,2,7) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname3" +DETAIL: Key (ftest1,ftest2,ftest3)=(1,2,7) is not present in "pktable". -- Show FKTABLE SELECT * from FKTABLE; ftest1 | ftest2 | ftest3 | ftest4 @@ -338,12 +351,14 @@ SELECT * from FKTABLE; -- Try to update something that should fail UPDATE PKTABLE set ptest2=5 where ptest2=2; -ERROR: constrname3 referential integrity violation - key (ptest1,ptest2,ptest3)=(1,2,3) in pktable still referenced from fktable +ERROR: update or delete on "pktable" violates foreign key constraint "constrname3" on "fktable" +DETAIL: Key (ptest1,ptest2,ptest3)=(1,2,3) is still referenced from "fktable". -- Try to update something that should succeed UPDATE PKTABLE set ptest1=1 WHERE ptest2=3; -- Try to delete something that should fail DELETE FROM PKTABLE where ptest1=1 and ptest2=2 and ptest3=3; -ERROR: constrname3 referential integrity violation - key (ptest1,ptest2,ptest3)=(1,2,3) in pktable still referenced from fktable +ERROR: update or delete on "pktable" violates foreign key constraint "constrname3" on "fktable" +DETAIL: Key (ptest1,ptest2,ptest3)=(1,2,3) is still referenced from "fktable". -- Try to delete something that should work DELETE FROM PKTABLE where ptest1=2; -- Show PKTABLE and FKTABLE @@ -387,7 +402,8 @@ INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4); INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5); -- Insert a failed values INSERT INTO FKTABLE VALUES (1, 2, 7, 6); -ERROR: constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,2,7) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname3" +DETAIL: Key (ftest1,ftest2,ftest3)=(1,2,7) is not present in "pktable". -- Show FKTABLE SELECT * from FKTABLE; ftest1 | ftest2 | ftest3 | ftest4 @@ -485,7 +501,8 @@ INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4); INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5); -- Insert a failed values INSERT INTO FKTABLE VALUES (1, 2, 7, 6); -ERROR: constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,2,7) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname3" +DETAIL: Key (ftest1,ftest2,ftest3)=(1,2,7) is not present in "pktable". -- Show FKTABLE SELECT * from FKTABLE; ftest1 | ftest2 | ftest3 | ftest4 @@ -591,7 +608,8 @@ INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4); INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5); -- Insert a failed values INSERT INTO FKTABLE VALUES (1, 2, 7, 6); -ERROR: constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,2,7) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname3" +DETAIL: Key (ftest1,ftest2,ftest3)=(1,2,7) is not present in "pktable". -- Show FKTABLE SELECT * from FKTABLE; ftest1 | ftest2 | ftest3 | ftest4 @@ -607,7 +625,8 @@ SELECT * from FKTABLE; -- Try to update something that will fail UPDATE PKTABLE set ptest2=5 where ptest2=2; -ERROR: constrname3 referential integrity violation - key (ftest1,ftest2,ftest3)=(1,-1,3) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "constrname3" +DETAIL: Key (ftest1,ftest2,ftest3)=(1,-1,3) is not present in "pktable". -- Try to update something that will set default UPDATE PKTABLE set ptest1=0, ptest2=5, ptest3=10 where ptest2=2; UPDATE PKTABLE set ptest2=10 where ptest2=4; @@ -819,17 +838,20 @@ insert into pktable(base1) values (1); insert into pktable(base1) values (2); -- let's insert a non-existant fktable value insert into fktable(ftest1) values (3); -ERROR: $1 referential integrity violation - key (ftest1)=(3) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "$1" +DETAIL: Key (ftest1)=(3) is not present in "pktable". -- let's make a valid row for that insert into pktable(base1) values (3); insert into fktable(ftest1) values (3); -- let's try removing a row that should fail from pktable delete from pktable where base1>2; -ERROR: $1 referential integrity violation - key (base1)=(3) in pktable still referenced from fktable +ERROR: update or delete on "pktable" violates foreign key constraint "$1" on "fktable" +DETAIL: Key (base1)=(3) is still referenced from "fktable". -- okay, let's try updating all of the base1 values to *4 -- which should fail. update pktable set base1=base1*4; -ERROR: $1 referential integrity violation - key (base1)=(3) in pktable still referenced from fktable +ERROR: update or delete on "pktable" violates foreign key constraint "$1" on "fktable" +DETAIL: Key (base1)=(3) is still referenced from "fktable". -- okay, let's try an update that should work. update pktable set base1=base1*4 where base1<3; -- and a delete that should work @@ -845,17 +867,20 @@ insert into pktable(base1, ptest1) values (1, 1); insert into pktable(base1, ptest1) values (2, 2); -- let's insert a non-existant fktable value insert into fktable(ftest1, ftest2) values (3, 1); -ERROR: $1 referential integrity violation - key (ftest1,ftest2)=(3,1) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "$1" +DETAIL: Key (ftest1,ftest2)=(3,1) is not present in "pktable". -- let's make a valid row for that insert into pktable(base1,ptest1) values (3, 1); insert into fktable(ftest1, ftest2) values (3, 1); -- let's try removing a row that should fail from pktable delete from pktable where base1>2; -ERROR: $1 referential integrity violation - key (base1,ptest1)=(3,1) in pktable still referenced from fktable +ERROR: update or delete on "pktable" violates foreign key constraint "$1" on "fktable" +DETAIL: Key (base1,ptest1)=(3,1) is still referenced from "fktable". -- okay, let's try updating all of the base1 values to *4 -- which should fail. update pktable set base1=base1*4; -ERROR: $1 referential integrity violation - key (base1,ptest1)=(3,1) in pktable still referenced from fktable +ERROR: update or delete on "pktable" violates foreign key constraint "$1" on "fktable" +DETAIL: Key (base1,ptest1)=(3,1) is still referenced from "fktable". -- okay, let's try an update that should work. update pktable set base1=base1*4 where base1<3; -- and a delete that should work @@ -876,13 +901,16 @@ insert into pktable (base1, ptest1, base2, ptest2) values (2, 2, 2, 1); insert into pktable (base1, ptest1, base2, ptest2) values (1, 3, 2, 2); -- fails (3,2) isn't in base1, ptest1 insert into pktable (base1, ptest1, base2, ptest2) values (2, 3, 3, 2); -ERROR: $1 referential integrity violation - key (base2,ptest2)=(3,2) referenced from pktable not found in pktable +ERROR: insert or update on "pktable" violates foreign key constraint "$1" +DETAIL: Key (base2,ptest2)=(3,2) is not present in "pktable". -- fails (2,2) is being referenced delete from pktable where base1=2; -ERROR: $1 referential integrity violation - key (base1,ptest1)=(2,2) in pktable still referenced from pktable +ERROR: update or delete on "pktable" violates foreign key constraint "$1" on "pktable" +DETAIL: Key (base1,ptest1)=(2,2) is still referenced from "pktable". -- fails (1,1) is being referenced (twice) update pktable set base1=3 where base1=1; -ERROR: $1 referential integrity violation - key (base1,ptest1)=(1,1) in pktable still referenced from pktable +ERROR: update or delete on "pktable" violates foreign key constraint "$1" on "pktable" +DETAIL: Key (base1,ptest1)=(1,1) is still referenced from "pktable". -- this sequence of two deletes will work, since after the first there will be no (2,*) references delete from pktable where base2=2; delete from pktable where base1=2; @@ -963,7 +991,8 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "fktable_pkey" fo NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) -- default to immediate: should fail INSERT INTO fktable VALUES (5, 10); -ERROR: $1 referential integrity violation - key (fk)=(10) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "$1" +DETAIL: Key (fk)=(10) is not present in "pktable". -- explicitely defer the constraint BEGIN; SET CONSTRAINTS ALL DEFERRED; @@ -993,7 +1022,8 @@ BEGIN; SET CONSTRAINTS ALL IMMEDIATE; -- should fail INSERT INTO fktable VALUES (500, 1000); -ERROR: $1 referential integrity violation - key (fk)=(1000) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "$1" +DETAIL: Key (fk)=(1000) is not present in "pktable". COMMIT; DROP TABLE fktable, pktable; -- tricky behavior: according to SQL99, if a deferred constraint is set @@ -1017,7 +1047,8 @@ SET CONSTRAINTS ALL DEFERRED; INSERT INTO fktable VALUES (1000, 2000); -- should cause transaction abort, due to preceding error SET CONSTRAINTS ALL IMMEDIATE; -ERROR: $1 referential integrity violation - key (fk)=(2000) referenced from fktable not found in pktable +ERROR: insert or update on "fktable" violates foreign key constraint "$1" +DETAIL: Key (fk)=(2000) is not present in "pktable". INSERT INTO pktable VALUES (2000, 3); -- too late ERROR: current transaction is aborted, queries ignored until end of transaction block COMMIT;