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

Error message editing for foreign-key triggers.

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