Commit 56f87688 authored by Tom Lane's avatar Tom Lane

Error message editing for foreign-key triggers.

parent fe5de484
......@@ -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));
......
......@@ -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')
......
......@@ -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)
......
......@@ -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
----------------
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment