Re: [GENERAL] postgres error reporting - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: [GENERAL] postgres error reporting |
Date | |
Msg-id | 200303180025.h2I0Pa800449@candle.pha.pa.us Whole thread Raw |
In response to | Re: [GENERAL] postgres error reporting (Dmitry Tkach <dmitry@openratings.com>) |
List | pgsql-patches |
FYI, this has already been applied, two days ago. --------------------------------------------------------------------------- Dmitry Tkach wrote: > > Tom Lane wrote: > > >Dima Tkach <dmitry@openratings.com> writes: > > > > > >>What drives me crazy though is the way it reports referential integrity > >>violations: > >> > >> > > > > > > > >>ERROR: <unnamed> referential integrity violation - key referenced from > >>child not found in parent > >> > >> > > > > > > > >>Now, is it really that hard to tell *which* value for the key was not > >>found? > >> > >> > > > >Send a patch ;-) > > > > > Ok :-) Here it is. > There was also a bug, that I fixed in "no action" triggers - they were > setting the uid to the owner of the PK table, but actually looking at > the FK, so it would > barf if it was owned by a different user, with no 'select' permission to > the PK-owner.... > > There are actually *two* different patches - In ri_patch.txt I also took > the liberty to eliminate some code duplication by extracting the code, > common between all of the triggers into separate functions... if you > don't like that for some reason, there is a "lighter" version - > ri_msg_patch.txt, that only takes care about the error reporting, and > fixes that table owner problem, leaving everything else intact... Just > pick the one you like better... > > These are both against REL7_3_STABLE. I compiled and tested them, and > did not see any problems... > > If you need a separate version for the HEAD, let me know - I can send > that too... > > Dima > > *** ri_triggers.c Fri Feb 28 13:48:56 2003 > --- ri_triggers.old Thu Feb 27 13:47:36 2003 > *************** > *** 64,87 **** > #define RI_PLAN_NOACTION_DEL_CHECKREF 1 > #define RI_PLAN_NOACTION_UPD_CHECKREF 1 > #define RI_PLAN_RESTRICT_DEL_CHECKREF 1 > #define RI_PLAN_RESTRICT_UPD_CHECKREF 1 > #define RI_PLAN_SETNULL_DEL_DOUPDATE 1 > #define RI_PLAN_SETNULL_UPD_DOUPDATE 1 > > #define MAX_QUOTED_NAME_LEN (NAMEDATALEN*2+3) > #define MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2) > > - #define RI_TRIGTYPE_INSERT 1 > - #define RI_TRIGTYPE_UPDATE 2 > - #define RI_TRIGTYPE_INUP 3 > - #define RI_TRIGTYPE_DELETE 4 > > /* ---------- > * RI_QueryKey > * > * The key identifying a prepared SPI plan in our private hashtable > * ---------- > */ > typedef struct RI_QueryKey > { > int32 constr_type; > --- 64,83 ---- > *************** > *** 145,202 **** > static bool ri_OneKeyEqual(Relation rel, int column, HeapTuple oldtup, > HeapTuple newtup, RI_QueryKey *key, int pairidx); > static bool ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue); > static bool ri_Check_Pk_Match(Relation pk_rel, HeapTuple old_row, > Oid tgoid, int match_type, int tgnargs, char **tgargs); > > static void ri_InitHashTables(void); > static void *ri_FetchPreparedPlan(RI_QueryKey *key); > static void ri_HashPreparedPlan(RI_QueryKey *key, void *plan); > > - static void ri_CheckTrigger (PG_FUNCTION_ARGS, const char *name, int tgkind); > - static bool ri_PerformCheck (RI_QueryKey *qkey, void *qplan, Relation fk_rel, > - Relation pk_rel, HeapTuple old_tuple, > - HeapTuple new_tuple, const char *constr); > - static void ri_ExtractValues (RI_QueryKey *qkey, int key_idx, Relation rel, > - HeapTuple check, HeapTuple upd, > - Datum *vals, char *nulls); > - static void ri_ReportViolation (const char *constr, Relation pk_rel, > - Relation fk_rel, RI_QueryKey *qkey, > - HeapTuple violator); > /* ---------- > * RI_FKey_check - > * > * Check foreign key existence (combined for INSERT and UPDATE). > * ---------- > */ > static Datum > RI_FKey_check(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > int match_type; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 141,201 ---- > static bool ri_OneKeyEqual(Relation rel, int column, HeapTuple oldtup, > HeapTuple newtup, RI_QueryKey *key, int pairidx); > static bool ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue); > static bool ri_Check_Pk_Match(Relation pk_rel, HeapTuple old_row, > Oid tgoid, int match_type, int tgnargs, char **tgargs); > > static void ri_InitHashTables(void); > static void *ri_FetchPreparedPlan(RI_QueryKey *key); > static void ri_HashPreparedPlan(RI_QueryKey *key, void *plan); > > /* ---------- > * RI_FKey_check - > * > * Check foreign key existence (combined for INSERT and UPDATE). > * ---------- > */ > static Datum > RI_FKey_check(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum check_values[RI_MAX_NUMKEYS]; > + char check_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > int i; > int match_type; > + Oid save_uid; > + > + save_uid = GetUserId(); > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_check() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_check() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) && > ! !TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_check() must be fired for INSERT or 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_check()"); > if (tgnargs > RI_MAX_ARGUMENTS) > elog(ERROR, "too many keys (%d max) in call to RI_FKey_check()", > *************** > *** 284,305 **** > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > * Execute the plan > */ > if (SPI_connect() != SPI_OK_CONNECT) > elog(WARNING, "SPI_connect() failed in RI_FKey_check()"); > > ! ri_PerformCheck (&qkey,qplan,fk_rel,pk_rel,NULL,NULL, > ! tgargs[RI_CONSTRAINT_NAME_ARGNO]); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); > > heap_close(pk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > } > > --- 283,314 ---- > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > * Execute the plan > */ > if (SPI_connect() != SPI_OK_CONNECT) > elog(WARNING, "SPI_connect() failed in RI_FKey_check()"); > > ! SetUserId(RelationGetForm(pk_rel)->relowner); > ! > ! if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_check()"); > ! > ! SetUserId(save_uid); > ! > ! if (SPI_processed == 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "no rows found in %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); > > heap_close(pk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > } > > *************** > *** 431,455 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > * Now check that foreign key exists in PK table > */ > > ! ri_PerformCheck (&qkey,qplan,fk_rel,pk_rel,NULL,new_row, > ! tgargs[RI_CONSTRAINT_NAME_ARGNO]); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); > > heap_close(pk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Never reached > --- 440,499 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > + * We have a plan now. Build up the arguments for SPI_execp() from the > + * key values in the new FK tuple. > + */ > + for (i = 0; i < qkey.nkeypairs; i++) > + { > + /* > + * We can implement MATCH PARTIAL by excluding this column from > + * the query if it is null. Simple! Unfortunately, the > + * referential actions aren't so I've not bothered to do so for > + * the moment. > + */ > + > + check_values[i] = SPI_getbinval(new_row, > + fk_rel->rd_att, > + qkey.keypair[i][RI_KEYPAIR_FK_IDX], > + &isnull); > + if (isnull) > + check_nulls[i] = 'n'; > + else > + check_nulls[i] = ' '; > + } > + check_nulls[i] = '\0'; > + > + /* > * Now check that foreign key exists in PK table > */ > > ! SetUserId(RelationGetForm(pk_rel)->relowner); > ! > ! if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_check()"); > ! > ! SetUserId(save_uid); > ! > ! if (SPI_processed == 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key referenced from %s not found in %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(fk_rel), > ! RelationGetRelationName(pk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); > > heap_close(pk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Never reached > *************** > *** 491,513 **** > --- 535,563 ---- > * Check for matching value of old pk row in current state for > * noaction triggers. Returns false if no row was found and a fk row > * could potentially be referencing this row, true otherwise. > * ---------- > */ > static bool > ri_Check_Pk_Match(Relation pk_rel, HeapTuple old_row, Oid tgoid, int match_type, int tgnargs, char **tgargs) > { > void *qplan; > RI_QueryKey qkey; > + bool isnull; > + Datum check_values[RI_MAX_NUMKEYS]; > + char check_nulls[RI_MAX_NUMKEYS + 1]; > int i; > + Oid save_uid; > bool result; > > + save_uid = GetUserId(); > + > ri_BuildQueryKeyPkCheck(&qkey, tgoid, > RI_PLAN_CHECK_LOOKUPPK, pk_rel, > tgnargs, tgargs); > > switch (ri_NullCheck(pk_rel, old_row, &qkey, RI_KEYPAIR_PK_IDX)) > { > case RI_KEYS_ALL_NULL: > > /* > * No check - nothing could have been referencing this row > *************** > *** 595,617 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Run it. > */ > ! result = ri_PerformCheck (&qkey, qplan,NULL, pk_rel, old_row, NULL, NULL); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in ri_Check_Pk_Match()"); > > return result; > } > > > /* ---------- > * RI_FKey_noaction_del - > --- 645,692 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() from the > ! * key values in the new FK tuple. > */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! check_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! check_nulls[i] = 'n'; > ! else > ! check_nulls[i] = ' '; > ! } > ! check_nulls[i] = '\0'; > ! > ! /* > ! * Now check that foreign key exists in PK table > ! */ > ! > ! SetUserId(RelationGetForm(pk_rel)->relowner); > ! > ! if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) > ! elog(ERROR, "SPI_execp() failed in ri_Check_Pk_Match()"); > ! > ! SetUserId(save_uid); > ! > ! result = (SPI_processed != 0); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in ri_Check_Pk_Match()"); > > return result; > } > > > /* ---------- > * RI_FKey_noaction_del - > *************** > *** 625,655 **** > RI_FKey_noaction_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > int match_type; > > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 700,741 ---- > RI_FKey_noaction_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum del_values[RI_MAX_NUMKEYS]; > + char del_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > int i; > int match_type; > + Oid save_uid; > > + save_uid = GetUserId(); > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_noaction_del() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_noaction_del() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_noaction_del() must be fired for 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()", > *************** > *** 768,792 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Run it. > */ > > ! ri_PerformCheck (&qkey, qplan,fk_rel,pk_rel,old_row,NULL, > ! tgargs[RI_CONSTRAINT_NAME_ARGNO]); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_del()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict delete. > --- 854,905 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the deleted PK tuple. > ! */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! del_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! del_nulls[i] = 'n'; > ! else > ! del_nulls[i] = ' '; > ! } > ! del_nulls[i] = '\0'; > ! > ! /* > ! * Now check for existing references > */ > + SetUserId(RelationGetForm(pk_rel)->relowner); > + > + if (SPI_execp(qplan, del_values, del_nulls, 1) != SPI_OK_SELECT) > + elog(ERROR, "SPI_execp() failed in RI_FKey_noaction_del()"); > > ! SetUserId(save_uid); > ! > ! if (SPI_processed > 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key in %s still referenced from %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel), > ! RelationGetRelationName(fk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_del()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict delete. > *************** > *** 817,846 **** > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > int match_type; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 930,971 ---- > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum upd_values[RI_MAX_NUMKEYS]; > + char upd_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > int i; > int match_type; > + Oid save_uid; > + > + save_uid = GetUserId(); > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_noaction_upd() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_noaction_upd() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_noaction_upd() must be fired for 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()", > *************** > *** 970,993 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Run it. > */ > ! ri_PerformCheck (&qkey, qplan,fk_rel,pk_rel,old_row,NULL, > ! tgargs[RI_CONSTRAINT_NAME_ARGNO]); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_upd()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL noaction update. > --- 1095,1146 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the updated PK tuple. > ! */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! upd_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! upd_nulls[i] = 'n'; > ! else > ! upd_nulls[i] = ' '; > ! } > ! upd_nulls[i] = '\0'; > ! > ! /* > ! * Now check for existing references > */ > ! SetUserId(RelationGetForm(pk_rel)->relowner); > ! > ! if (SPI_execp(qplan, upd_values, upd_nulls, 1) != SPI_OK_SELECT) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_noaction_upd()"); > ! > ! SetUserId(save_uid); > ! > ! if (SPI_processed > 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key in %s still referenced from %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel), > ! RelationGetRelationName(fk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_upd()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL noaction update. > *************** > *** 1015,1043 **** > RI_FKey_cascade_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 1168,1207 ---- > RI_FKey_cascade_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum del_values[RI_MAX_NUMKEYS]; > + char del_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > int i; > + Oid save_uid; > + Oid fk_owner; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_cascade_del() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_cascade_del() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_cascade_del() must be fired for 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()", > *************** > *** 1058,1077 **** > --- 1222,1242 ---- > */ > 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; > + fk_owner = RelationGetForm(fk_rel)->relowner; > > switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) > { > /* ---------- > * SQL3 11.9 <referential constraint definition> > * Gereral rules 6) a) i): > * MATCH <unspecified> or MATCH FULL > * ... ON DELETE CASCADE > * ---------- > */ > *************** > *** 1142,1166 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments > ! * from the key values in the deleted PK tuple and delete the > ! * referencing rows > */ > ! ri_PerformCheck (&qkey, qplan,fk_rel,pk_rel,old_row,NULL,NULL); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_del()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL cascaded delete. > --- 1307,1352 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the deleted PK tuple. > */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! del_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! del_nulls[i] = 'n'; > ! else > ! del_nulls[i] = ' '; > ! } > ! del_nulls[i] = '\0'; > ! > ! /* > ! * Now delete constraint > ! */ > ! save_uid = GetUserId(); > ! SetUserId(fk_owner); > ! > ! if (SPI_execp(qplan, del_values, del_nulls, 0) != SPI_OK_DELETE) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_cascade_del()"); > ! > ! SetUserId(save_uid); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_del()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL cascaded delete. > *************** > *** 1189,1218 **** > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > int j; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 1375,1415 ---- > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum upd_values[RI_MAX_NUMKEYS * 2]; > + char upd_nulls[RI_MAX_NUMKEYS * 2 + 1]; > + bool isnull; > int i; > int j; > + Oid save_uid; > + Oid fk_owner; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_cascade_upd() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_cascade_upd() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_cascade_upd() must be fired for 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()", > *************** > *** 1234,1253 **** > --- 1431,1451 ---- > 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; > old_row = trigdata->tg_trigtuple; > + fk_owner = RelationGetForm(fk_rel)->relowner; > > switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) > { > /* ---------- > * SQL3 11.9 <referential constraint definition> > * Gereral rules 7) a) i): > * MATCH <unspecified> or MATCH FULL > * ... ON UPDATE CASCADE > * ---------- > */ > *************** > *** 1339,1361 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs * 2, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Run it. > */ > ! ri_PerformCheck (&qkey, qplan,fk_rel,pk_rel,old_row,new_row,NULL); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_upd()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL cascade update. > --- 1537,1591 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs * 2, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the updated PK tuple. > ! */ > ! for (i = 0, j = qkey.nkeypairs; i < qkey.nkeypairs; i++, j++) > ! { > ! upd_values[i] = SPI_getbinval(new_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! upd_nulls[i] = 'n'; > ! else > ! upd_nulls[i] = ' '; > ! > ! upd_values[j] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! upd_nulls[j] = 'n'; > ! else > ! upd_nulls[j] = ' '; > ! } > ! upd_nulls[j] = '\0'; > ! > ! /* > ! * Now update the existing references > */ > ! save_uid = GetUserId(); > ! SetUserId(fk_owner); > ! > ! if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_cascade_upd()"); > ! > ! SetUserId(save_uid); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_upd()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL cascade update. > *************** > *** 1390,1418 **** > RI_FKey_restrict_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 1620,1659 ---- > RI_FKey_restrict_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum del_values[RI_MAX_NUMKEYS]; > + char del_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > int i; > + Oid save_uid; > + Oid fk_owner; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_restrict_del() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_restrict_del() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_restrict_del() must be fired for 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()", > *************** > *** 1433,1452 **** > --- 1674,1694 ---- > */ > 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; > + fk_owner = RelationGetForm(fk_rel)->relowner; > > switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) > { > /* ---------- > * SQL3 11.9 <referential constraint definition> > * Gereral rules 6) a) iv): > * MATCH <unspecified> or MATCH FULL > * ... ON DELETE CASCADE > * ---------- > */ > *************** > *** 1519,1543 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Run it. > */ > > ! ri_PerformCheck (&qkey, qplan, fk_rel, pk_rel, old_row, NULL, > ! tgargs[RI_CONSTRAINT_NAME_ARGNO]); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_del()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict delete. > --- 1761,1813 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the deleted PK tuple. > ! */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! del_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! del_nulls[i] = 'n'; > ! else > ! del_nulls[i] = ' '; > ! } > ! del_nulls[i] = '\0'; > ! > ! /* > ! * Now check for existing references > */ > + save_uid = GetUserId(); > + SetUserId(fk_owner); > + > + if (SPI_execp(qplan, del_values, del_nulls, 1) != SPI_OK_SELECT) > + elog(ERROR, "SPI_execp() failed in RI_FKey_restrict_del()"); > + > + SetUserId(save_uid); > > ! if (SPI_processed > 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key in %s still referenced from %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel), > ! RelationGetRelationName(fk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_del()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict delete. > *************** > *** 1573,1601 **** > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 1843,1882 ---- > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum upd_values[RI_MAX_NUMKEYS]; > + char upd_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > int i; > + Oid save_uid; > + Oid fk_owner; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_restrict_upd() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_restrict_upd() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_restrict_upd() must be fired for 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()", > *************** > *** 1617,1636 **** > --- 1898,1918 ---- > 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; > old_row = trigdata->tg_trigtuple; > + fk_owner = RelationGetForm(fk_rel)->relowner; > > switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) > { > /* ---------- > * SQL3 11.9 <referential constraint definition> > * Gereral rules 6) a) iv): > * MATCH <unspecified> or MATCH FULL > * ... ON DELETE CASCADE > * ---------- > */ > *************** > *** 1713,1736 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Run it. > */ > ! ri_PerformCheck (&qkey, qplan, fk_rel, pk_rel, old_row, NULL, > ! tgargs[RI_CONSTRAINT_NAME_ARGNO]); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_upd()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict update. > --- 1995,2049 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the updated PK tuple. > */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! upd_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! upd_nulls[i] = 'n'; > ! else > ! upd_nulls[i] = ' '; > ! } > ! upd_nulls[i] = '\0'; > ! > ! /* > ! * Now check for existing references > ! */ > ! save_uid = GetUserId(); > ! SetUserId(fk_owner); > ! > ! SetUserId(RelationGetForm(pk_rel)->relowner); > ! > ! if (SPI_execp(qplan, upd_values, upd_nulls, 1) != SPI_OK_SELECT) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_restrict_upd()"); > ! > ! SetUserId(save_uid); > ! > ! if (SPI_processed > 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key in %s still referenced from %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel), > ! RelationGetRelationName(fk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_upd()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict update. > *************** > *** 1758,1786 **** > RI_FKey_setnull_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 2071,2110 ---- > RI_FKey_setnull_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum upd_values[RI_MAX_NUMKEYS]; > + char upd_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > int i; > + Oid save_uid; > + Oid fk_owner; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_setnull_del() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_setnull_del() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_setnull_del() must be fired for 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()", > *************** > *** 1801,1820 **** > --- 2125,2145 ---- > */ > 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; > + fk_owner = RelationGetForm(fk_rel)->relowner; > > switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) > { > /* ---------- > * SQL3 11.9 <referential constraint definition> > * Gereral rules 6) a) ii): > * MATCH <UNSPECIFIED> or MATCH FULL > * ... ON DELETE SET NULL > * ---------- > */ > *************** > *** 1895,1917 **** > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Run it. > */ > ! ri_PerformCheck (&qkey, qplan, fk_rel, pk_rel, old_row, NULL, NULL); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_del()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL set null delete. > --- 2220,2265 ---- > > /* > * Prepare, save and remember the new plan. > */ > qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids); > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the updated PK tuple. > */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! upd_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! upd_nulls[i] = 'n'; > ! else > ! upd_nulls[i] = ' '; > ! } > ! upd_nulls[i] = '\0'; > ! > ! /* > ! * Now update the existing references > ! */ > ! save_uid = GetUserId(); > ! SetUserId(fk_owner); > ! > ! if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_setnull_del()"); > ! > ! SetUserId(save_uid); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_del()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL set null delete. > *************** > *** 1940,1970 **** > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int i; > int match_type; > bool use_cached_query; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 2288,2329 ---- > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum upd_values[RI_MAX_NUMKEYS]; > + char upd_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > int i; > int match_type; > bool use_cached_query; > + Oid save_uid; > + Oid fk_owner; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_setnull_upd() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_setnull_upd() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_setnull_upd() must be fired for 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()", > *************** > *** 1987,2006 **** > --- 2346,2366 ---- > 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; > old_row = trigdata->tg_trigtuple; > match_type = ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]); > + fk_owner = RelationGetForm(fk_rel)->relowner; > > switch (match_type) > { > /* ---------- > * SQL3 11.9 <referential constraint definition> > * Gereral rules 7) a) ii) 2): > * MATCH FULL > * ... ON UPDATE SET NULL > * ---------- > */ > *************** > *** 2128,2151 **** > * "standard" plan. > */ > if (use_cached_query) > { > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > } > > /* > ! * We have a plan now. > * Now update the existing references > */ > ! ri_PerformCheck (&qkey, qplan, fk_rel, pk_rel, old_row, NULL, NULL); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_upd()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL set null update. > --- 2488,2533 ---- > * "standard" plan. > */ > if (use_cached_query) > { > qplan = SPI_saveplan(qplan); > ri_HashPreparedPlan(&qkey, qplan); > } > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the updated PK tuple. > ! */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! upd_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! upd_nulls[i] = 'n'; > ! else > ! upd_nulls[i] = ' '; > ! } > ! upd_nulls[i] = '\0'; > ! > ! /* > * Now update the existing references > */ > ! save_uid = GetUserId(); > ! SetUserId(fk_owner); > ! > ! if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_setnull_upd()"); > ! > ! SetUserId(save_uid); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_upd()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL set null update. > *************** > *** 2173,2200 **** > RI_FKey_setdefault_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 2555,2594 ---- > RI_FKey_setdefault_del(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum upd_values[RI_MAX_NUMKEYS]; > + char upd_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > + int i; > + Oid save_uid; > + Oid fk_owner; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_setdefault_del() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_setdefault_del() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_setdefault_del() must be fired for 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()", > *************** > *** 2215,2234 **** > --- 2609,2629 ---- > */ > 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; > + fk_owner = RelationGetForm(fk_rel)->relowner; > > switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) > { > /* ---------- > * SQL3 11.9 <referential constraint definition> > * Gereral rules 6) a) iii): > * MATCH <UNSPECIFIED> or MATCH FULL > * ... ON DELETE SET DEFAULT > * ---------- > */ > *************** > *** 2353,2376 **** > spi_plan->targetlist); > spi_qptle->expr = stringToNode(defval[j].adbin); > > break; > } > } > } > } > > /* > ! * We have a plan now. > * Now update the existing references > */ > ! ri_PerformCheck (&qkey, qplan, fk_rel, pk_rel, old_row, NULL, NULL); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_del()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL set null delete. > --- 2748,2793 ---- > spi_plan->targetlist); > spi_qptle->expr = stringToNode(defval[j].adbin); > > break; > } > } > } > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the deleted PK tuple. > ! */ > ! for (i = 0; i < qkey.nkeypairs; i++) > ! { > ! upd_values[i] = SPI_getbinval(old_row, > ! pk_rel->rd_att, > ! qkey.keypair[i][RI_KEYPAIR_PK_IDX], > ! &isnull); > ! if (isnull) > ! upd_nulls[i] = 'n'; > ! else > ! upd_nulls[i] = ' '; > ! } > ! upd_nulls[i] = '\0'; > ! > ! /* > * Now update the existing references > */ > ! save_uid = GetUserId(); > ! SetUserId(fk_owner); > ! > ! if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_setdefault_del()"); > ! > ! SetUserId(save_uid); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_del()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL set null delete. > *************** > *** 2399,2427 **** > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > int match_type; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! 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()", > --- 2816,2856 ---- > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > int tgnargs; > char **tgargs; > Relation fk_rel; > Relation pk_rel; > HeapTuple new_row; > HeapTuple old_row; > RI_QueryKey qkey; > void *qplan; > + Datum upd_values[RI_MAX_NUMKEYS]; > + char upd_nulls[RI_MAX_NUMKEYS + 1]; > + bool isnull; > + int i; > int match_type; > + Oid save_uid; > + Oid fk_owner; > > ReferentialIntegritySnapshotOverride = true; > > /* > * Check that this is a valid trigger call on the right time and > * event. > */ > ! if (!CALLED_AS_TRIGGER(fcinfo)) > ! elog(ERROR, "RI_FKey_setdefault_upd() not fired by trigger manager"); > ! if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > ! !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_setdefault_upd() must be fired AFTER ROW"); > ! if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) > ! elog(ERROR, "RI_FKey_setdefault_upd() must be fired for 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()", > *************** > *** 2443,2462 **** > --- 2872,2892 ---- > 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; > old_row = trigdata->tg_trigtuple; > + fk_owner = RelationGetForm(fk_rel)->relowner; > > match_type = ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]); > > switch (match_type) > { > /* ---------- > * SQL3 11.9 <referential constraint definition> > * Gereral rules 7) a) iii): > * MATCH <UNSPECIFIED> or MATCH FULL > * ... ON UPDATE SET DEFAULT > *************** > *** 2609,2632 **** > spi_qptle->expr = stringToNode(defval[j].adbin); > > break; > } > } > } > } > } > > /* > ! * We have a plan now. Run it. > */ > > ! ri_PerformCheck (&qkey, qplan, fk_rel, pk_rel, old_row, NULL, NULL); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_upd()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL set null delete. > --- 3039,3084 ---- > spi_qptle->expr = stringToNode(defval[j].adbin); > > break; > } > } > } > } > } > > /* > ! * We have a plan now. Build up the arguments for SPI_execp() > ! * from the key values in the deleted PK tuple. > */ > + for (i = 0; i < qkey.nkeypairs; i++) > + { > + upd_values[i] = SPI_getbinval(old_row, > + pk_rel->rd_att, > + qkey.keypair[i][RI_KEYPAIR_PK_IDX], > + &isnull); > + if (isnull) > + upd_nulls[i] = 'n'; > + else > + upd_nulls[i] = ' '; > + } > + upd_nulls[i] = '\0'; > > ! /* > ! * Now update the existing references > ! */ > ! save_uid = GetUserId(); > ! SetUserId(fk_owner); > ! > ! if (SPI_execp(qplan, upd_values, upd_nulls, 0) != SPI_OK_UPDATE) > ! elog(ERROR, "SPI_execp() failed in RI_FKey_setdefault_upd()"); > ! > ! SetUserId(save_uid); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_upd()"); > > heap_close(fk_rel, RowExclusiveLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL set null delete. > *************** > *** 2853,3039 **** > 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]); > key->keypair[i][RI_KEYPAIR_PK_IDX] = fno; > } > } > > - static void ri_CheckTrigger (PG_FUNCTION_ARGS, const char *name, int tgkind) > - { > - TriggerData *trigdata = (TriggerData *) fcinfo -> context; > - > - if (!CALLED_AS_TRIGGER(fcinfo)) > - elog(ERROR, "%s() not fired by trigger manager", name); > - if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || > - !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) > - elog(ERROR, "%s() must be fired AFTER ROW", name); > - > - if (tgkind == RI_TRIGTYPE_INUP && > - !TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) && > - !TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) > - elog(ERROR, "%s() must be fired for INSERT or UPDATE", name); > - else if (tgkind == RI_TRIGTYPE_INSERT && > - !TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) > - elog (ERROR, "%s() must be fired for INSERT", name); > - else if (tgkind == RI_TRIGTYPE_UPDATE && > - !TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) > - elog (ERROR, "%s() must be fired for UPDATE", name); > - else if (tgkind == RI_TRIGTYPE_DELETE && > - !TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) > - elog (ERROR, "%s() must be fired for DELETE", name); > - } > - > - > - static bool ri_PerformCheck (RI_QueryKey *qkey, void *qplan, Relation fk_rel, > - Relation pk_rel, HeapTuple old_tuple, > - HeapTuple new_tuple, const char *constr) > - { > - /* The query is always run against the FK table except > - * when this is an update/insert trigger on the FK table itself - > - * either RI_PLAN_CHECK_LOOKUPPK or RI_PLAN_CHECK_LOOKUPPK_NOCOLS, which > - * is equivalent to nkeypairs == 0 > - */ > - Relation query_rel = qkey -> constr_queryno == RI_PLAN_CHECK_LOOKUPPK || > - qkey -> nkeypairs == 0 ? pk_rel : fk_rel; > - > - /** The values for the query are taken from the table on which the trigger > - * is called - it is normally the other one with respect to query_rel. > - * An exception is ri_Check_Pk_Match(), which uses the PK table for both > - * (the case when fk_rel == NULL) > - */ > - Relation source_rel = qkey -> constr_queryno == RI_PLAN_CHECK_LOOKUPPK && > - fk_rel ? fk_rel : pk_rel; > - > - /** If the vals are taken from fk_rel, then ..FK_IDX, otherwise PK_IDX */ > - int key_idx = source_rel == fk_rel ? RI_KEYPAIR_FK_IDX : RI_KEYPAIR_PK_IDX; > - > - /** If constr is given, this is a 'noaction' trigger - we only want to check > - * if there are any rows that satisfy the query, thus limit=1, also, if > - * the query is LOOKUPPK, we are just checking if the row is there... > - * Otherwise, we want to perform some action on the matching rows, so > - * do not limit the number of results. > - */ > - int limit = constr || qkey -> constr_queryno==RI_PLAN_CHECK_LOOKUPPK ? 1 : 0; > - > - Oid save_uid = GetUserId (); > - > - Datum vals [RI_MAX_NUMKEYS * 2]; > - char nulls[RI_MAX_NUMKEYS * 2 + 1]; > - > - ri_ExtractValues (qkey, key_idx, source_rel, > - new_tuple ? new_tuple : old_tuple, > - new_tuple ? old_tuple : NULL, vals, nulls); > - > - SetUserId (RelationGetForm (query_rel) -> relowner); > - > - if (SPI_execp(qplan, vals, nulls, limit) < 0) > - elog(ERROR, "SPI_execp() failed in ri_PerformCheck()"); > - > - SetUserId(save_uid); > - > - if (constr && > - (SPI_processed==0) == (qkey->constr_queryno==RI_PLAN_CHECK_LOOKUPPK)) > - ri_ReportViolation (constr, pk_rel, fk_rel, qkey, > - new_tuple ? new_tuple : old_tuple); > - > - return SPI_processed != 0; > - } > - > - static void ri_ExtractValues (RI_QueryKey *qkey, int key_idx, Relation rel, > - HeapTuple check, HeapTuple upd, > - Datum *vals, char *nulls) > - { > - int i,j; > - bool isnull; > - > - for (i = 0, j = qkey -> nkeypairs; i < qkey -> nkeypairs; i++, j++) > - { > - vals[i]=SPI_getbinval(check,rel->rd_att,qkey->keypair[i][key_idx],&isnull); > - nulls[i]=isnull ? 'n' : ' '; > - > - if (upd) > - { > - vals[j]=SPI_getbinval(upd,rel->rd_att,qkey->keypair[i][key_idx],&isnull); > - nulls[j] = isnull ? 'n' : ' '; > - } > - } > - nulls [upd ? j : i] = '\0'; > - } > - > - static void ri_ReportViolation (const char *constr, Relation pk_rel, > - Relation fk_rel, RI_QueryKey *qkey, > - HeapTuple violator) > - { > - static char *null_str = "null"; > - > - char key_names [512]; > - char key_values [512]; > - > - char *name_ptr = key_names; > - char *val_ptr = key_values; > - int idx = 0; > - > - /* 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' > - * Otherwise, the attr names and values come from the PK table and the > - * message looks like 'key blah in PK still referenced in FK'. > - * So, rel is set to where the tuple description is coming from > - * (FK in the first case, and PK in the second case), and it also is > - * the first relation mentioned in the message, other_rel is respectively > - * the other relation. > - */ > - > - bool onfk = (qkey -> constr_queryno == RI_PLAN_CHECK_LOOKUPPK); > - > - int key_idx = onfk ? RI_KEYPAIR_FK_IDX : RI_KEYPAIR_PK_IDX; > - Relation rel = onfk ? fk_rel : pk_rel; > - Relation other_rel = onfk ? pk_rel : fk_rel; > - > - /* Special case - if there are no keys at all, this is a 'no column' > - * constraint - no need to try to extract the values, and the message > - * in this case looks differently > - */ > - if (qkey -> nkeypairs == 0) > - elog(ERROR, "%s referential integrity violation - no rows found in %s", > - constr, RelationGetRelationName(pk_rel)); > - > - for (idx = 0; idx < qkey->nkeypairs; idx++) > - { > - int fnum = qkey->keypair[idx][key_idx]; > - char *name = SPI_fname (rel->rd_att, fnum); > - char *val = SPI_getvalue (violator, rel->rd_att, fnum); > - if (!val) > - val = null_str; > - > - if (name_ptr - key_names + strlen(name) + 5 >= 512 || > - val_ptr - key_values + strlen (val) + 5 >= 512) > - { > - sprintf (name_ptr, "..."); > - sprintf (val_ptr, "..."); > - break; > - } > - > - name_ptr += sprintf (name_ptr, "%s%s", idx > 0 ? "," : "", name); > - val_ptr += sprintf (val_ptr, "%s%s", idx > 0 ? "," : "", val); > - } > - > - elog (ERROR, "%s referential integrity violation - key (%s)=(%s) " > - "%s %s %s in %s", constr, key_names, key_values, > - onfk ? "referenced from" : "in", RelationGetRelationName (rel), > - onfk ? "not found" : "still referenced", > - RelationGetRelationName (other_rel)); > - } > - > /* ---------- > * ri_BuildQueryKeyPkCheck - > * > * Build up a new hashtable key for a prepared SPI plan of a > * check for PK rows in noaction triggers. > * > * constr_type is FULL > * constr_id is the OID of the pg_trigger row that invoked us > * constr_queryno is an internal number of the query inside the proc > * pk_relid is the OID of referenced relation > --- 3305,3324 ---- > *************** > *** 3378,3402 **** > /* > * If not found, lookup the operator, then do the function manager > * lookup, and remember that info. > */ > if (!entry) > { > Oid opr_proc; > FmgrInfo finfo; > > opr_proc = compatible_oper_funcid(makeList1(makeString("=")), > ! typeid, typeid, true); > if (!OidIsValid(opr_proc)) > ! elog (ERROR, > ! "ri_AttributesEqual(): cannot find '=' operator for type %u", > ! typeid); > > /* > * Since fmgr_info could fail, call it *before* creating the > * hashtable entry --- otherwise we could elog 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. > */ > fmgr_info_cxt(opr_proc, &finfo, TopMemoryContext); > > --- 3663,3687 ---- > /* > * If not found, lookup the operator, then do the function manager > * lookup, and remember that info. > */ > if (!entry) > { > Oid opr_proc; > FmgrInfo finfo; > > opr_proc = compatible_oper_funcid(makeList1(makeString("=")), > ! typeid, typeid, true); > if (!OidIsValid(opr_proc)) > ! elog(ERROR, > ! "ri_AttributesEqual(): cannot find '=' operator for type %u", > ! typeid); > > /* > * Since fmgr_info could fail, call it *before* creating the > * hashtable entry --- otherwise we could elog 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. > */ > fmgr_info_cxt(opr_proc, &finfo, TopMemoryContext); > > *** ri_triggers.msg Thu Feb 27 13:53:22 2003 > --- ri_triggers.old Thu Feb 27 13:47:36 2003 > *************** > *** 141,163 **** > static bool ri_OneKeyEqual(Relation rel, int column, HeapTuple oldtup, > HeapTuple newtup, RI_QueryKey *key, int pairidx); > static bool ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue); > static bool ri_Check_Pk_Match(Relation pk_rel, HeapTuple old_row, > Oid tgoid, int match_type, int tgnargs, char **tgargs); > > static void ri_InitHashTables(void); > static void *ri_FetchPreparedPlan(RI_QueryKey *key); > static void ri_HashPreparedPlan(RI_QueryKey *key, void *plan); > > - static void ri_ReportViolation (const char *constr, Relation pk_rel, > - Relation fk_rel, RI_QueryKey *qkey, > - HeapTuple violator); > /* ---------- > * RI_FKey_check - > * > * Check foreign key existence (combined for INSERT and UPDATE). > * ---------- > */ > static Datum > RI_FKey_check(PG_FUNCTION_ARGS) > { > TriggerData *trigdata = (TriggerData *) fcinfo->context; > --- 141,160 ---- > *************** > *** 294,315 **** > elog(WARNING, "SPI_connect() failed in RI_FKey_check()"); > > SetUserId(RelationGetForm(pk_rel)->relowner); > > if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_check()"); > > SetUserId(save_uid); > > if (SPI_processed == 0) > ! ri_ReportViolation (tgargs[RI_CONSTRAINT_NAME_ARGNO], pk_rel, fk_rel, > ! &qkey, NULL); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); > > heap_close(pk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > } > > --- 291,314 ---- > elog(WARNING, "SPI_connect() failed in RI_FKey_check()"); > > SetUserId(RelationGetForm(pk_rel)->relowner); > > if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_check()"); > > SetUserId(save_uid); > > if (SPI_processed == 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "no rows found in %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); > > heap_close(pk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > } > > *************** > *** 476,497 **** > */ > > SetUserId(RelationGetForm(pk_rel)->relowner); > > if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_check()"); > > SetUserId(save_uid); > > if (SPI_processed == 0) > ! ri_ReportViolation (tgargs[RI_CONSTRAINT_NAME_ARGNO], pk_rel, fk_rel, > ! &qkey, new_row); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); > > heap_close(pk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Never reached > --- 475,499 ---- > */ > > SetUserId(RelationGetForm(pk_rel)->relowner); > > if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_check()"); > > SetUserId(save_uid); > > if (SPI_processed == 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key referenced from %s not found in %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(fk_rel), > ! RelationGetRelationName(pk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); > > heap_close(pk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Never reached > *************** > *** 871,900 **** > if (isnull) > del_nulls[i] = 'n'; > else > del_nulls[i] = ' '; > } > del_nulls[i] = '\0'; > > /* > * Now check for existing references > */ > ! SetUserId(RelationGetForm(fk_rel)->relowner); > > if (SPI_execp(qplan, del_values, del_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_noaction_del()"); > > SetUserId(save_uid); > > if (SPI_processed > 0) > ! ri_ReportViolation (tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! pk_rel, fk_rel, &qkey, old_row); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_del()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict delete. > --- 873,905 ---- > if (isnull) > del_nulls[i] = 'n'; > else > del_nulls[i] = ' '; > } > del_nulls[i] = '\0'; > > /* > * Now check for existing references > */ > ! SetUserId(RelationGetForm(pk_rel)->relowner); > > if (SPI_execp(qplan, del_values, del_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_noaction_del()"); > > SetUserId(save_uid); > > if (SPI_processed > 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key in %s still referenced from %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel), > ! RelationGetRelationName(fk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_del()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict delete. > *************** > *** 1109,1138 **** > if (isnull) > upd_nulls[i] = 'n'; > else > upd_nulls[i] = ' '; > } > upd_nulls[i] = '\0'; > > /* > * Now check for existing references > */ > ! SetUserId(RelationGetForm(fk_rel)->relowner); > > if (SPI_execp(qplan, upd_values, upd_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_noaction_upd()"); > > SetUserId(save_uid); > > if (SPI_processed > 0) > ! ri_ReportViolation (tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! pk_rel, fk_rel, &qkey, old_row); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_upd()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL noaction update. > --- 1114,1146 ---- > if (isnull) > upd_nulls[i] = 'n'; > else > upd_nulls[i] = ' '; > } > upd_nulls[i] = '\0'; > > /* > * Now check for existing references > */ > ! SetUserId(RelationGetForm(pk_rel)->relowner); > > if (SPI_execp(qplan, upd_values, upd_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_noaction_upd()"); > > SetUserId(save_uid); > > if (SPI_processed > 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key in %s still referenced from %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel), > ! RelationGetRelationName(fk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_upd()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL noaction update. > *************** > *** 1781,1802 **** > */ > save_uid = GetUserId(); > SetUserId(fk_owner); > > if (SPI_execp(qplan, del_values, del_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_restrict_del()"); > > SetUserId(save_uid); > > if (SPI_processed > 0) > ! ri_ReportViolation (tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! pk_rel, fk_rel, &qkey, old_row); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_del()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict delete. > --- 1789,1813 ---- > */ > save_uid = GetUserId(); > SetUserId(fk_owner); > > if (SPI_execp(qplan, del_values, del_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_restrict_del()"); > > SetUserId(save_uid); > > if (SPI_processed > 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key in %s still referenced from %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel), > ! RelationGetRelationName(fk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_del()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict delete. > *************** > *** 2014,2035 **** > SetUserId(fk_owner); > > SetUserId(RelationGetForm(pk_rel)->relowner); > > if (SPI_execp(qplan, upd_values, upd_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_restrict_upd()"); > > SetUserId(save_uid); > > if (SPI_processed > 0) > ! ri_ReportViolation (tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! pk_rel, fk_rel, &qkey, old_row); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_upd()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict update. > --- 2025,2049 ---- > SetUserId(fk_owner); > > SetUserId(RelationGetForm(pk_rel)->relowner); > > if (SPI_execp(qplan, upd_values, upd_nulls, 1) != SPI_OK_SELECT) > elog(ERROR, "SPI_execp() failed in RI_FKey_restrict_upd()"); > > SetUserId(save_uid); > > if (SPI_processed > 0) > ! elog(ERROR, "%s referential integrity violation - " > ! "key in %s still referenced from %s", > ! tgargs[RI_CONSTRAINT_NAME_ARGNO], > ! RelationGetRelationName(pk_rel), > ! RelationGetRelationName(fk_rel)); > > if (SPI_finish() != SPI_OK_FINISH) > elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_upd()"); > > heap_close(fk_rel, RowShareLock); > > return PointerGetDatum(NULL); > > /* > * Handle MATCH PARTIAL restrict update. > *************** > *** 3289,3373 **** > 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]); > key->keypair[i][RI_KEYPAIR_PK_IDX] = fno; > } > - } > - > - static void ri_ReportViolation (const char *constr, Relation pk_rel, > - Relation fk_rel, RI_QueryKey *qkey, > - HeapTuple violator) > - { > - static char *null_str = "null"; > - > - char key_names [512]; > - char key_values [512]; > - > - char *name_ptr = key_names; > - char *val_ptr = key_values; > - int idx = 0; > - > - /* 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' > - * Otherwise, the attr names and values come from the PK table and the > - * message looks like 'key blah in PK still referenced in FK'. > - * So, rel is set to where the tuple description is coming from > - * (FK in the first case, and PK in the second case), and it also is > - * the first relation mentioned in the message, other_rel is respectively > - * the other relation. > - */ > - > - bool onfk = (qkey -> constr_queryno == RI_PLAN_CHECK_LOOKUPPK); > - > - int key_idx = onfk ? RI_KEYPAIR_FK_IDX : RI_KEYPAIR_PK_IDX; > - Relation rel = onfk ? fk_rel : pk_rel; > - Relation other_rel = onfk ? pk_rel : fk_rel; > - > - /* Special case - if there are no keys at all, this is a 'no column' > - * constraint - no need to try to extract the values, and the message > - * in this case looks differently > - */ > - if (qkey -> nkeypairs == 0) > - elog(ERROR, "%s referential integrity violation - no rows found in %s", > - constr, RelationGetRelationName(pk_rel)); > - > - for (idx = 0; idx < qkey->nkeypairs; idx++) > - { > - int fnum = qkey->keypair[idx][key_idx]; > - char *name = SPI_fname (rel->rd_att, fnum); > - char *val = SPI_getvalue (violator, rel->rd_att, fnum); > - if (!val) > - val = null_str; > - > - if (name_ptr - key_names + strlen(name) + 5 >= 512 || > - val_ptr - key_values + strlen (val) + 5 >= 512) > - { > - sprintf (name_ptr, "..."); > - sprintf (val_ptr, "..."); > - break; > - } > - > - name_ptr += sprintf (name_ptr, "%s%s", idx > 0 ? "," : "", name); > - val_ptr += sprintf (val_ptr, "%s%s", idx > 0 ? "," : "", val); > - } > - > - elog (ERROR, "%s referential integrity violation - key (%s)=(%s) " > - "%s %s %s in %s", constr, key_names, key_values, > - onfk ? "referenced from" : "in", RelationGetRelationName (rel), > - onfk ? "not found" : "still referenced", > - RelationGetRelationName (other_rel)); > } > > /* ---------- > * ri_BuildQueryKeyPkCheck - > * > * Build up a new hashtable key for a prepared SPI plan of a > * check for PK rows in noaction triggers. > * > * constr_type is FULL > * constr_id is the OID of the pg_trigger row that invoked us > --- 3303,3322 ---- -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
pgsql-patches by date: