mirror of
https://github.com/postgres/postgres.git
synced 2025-07-18 17:42:25 +03:00
Back-patch Jan's fix to avoid primary key lookup (and lock) if foreign key
does not change on UPDATE.
This commit is contained in:
@ -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.43.2.2 2003/04/26 22:21:58 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.43.2.3 2003/05/21 18:14:46 tgl Exp $
|
||||||
*
|
*
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
@ -395,13 +395,19 @@ RI_FKey_check(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: We cannot avoid the check on UPDATE, even if old and new key
|
* No need to check anything if old and new references are the
|
||||||
* are the same. Otherwise, someone could DELETE the PK that consists
|
* same on UPDATE.
|
||||||
* of the DEFAULT values, and if there are any references, a ON DELETE
|
|
||||||
* SET DEFAULT action would update the references to exactly these
|
|
||||||
* values but we wouldn't see that weired case (this is the only place
|
|
||||||
* to see it).
|
|
||||||
*/
|
*/
|
||||||
|
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
|
{
|
||||||
|
if (ri_KeysEqual(fk_rel, old_row, new_row, &qkey,
|
||||||
|
RI_KEYPAIR_FK_IDX))
|
||||||
|
{
|
||||||
|
heap_close(pk_rel, RowShareLock);
|
||||||
|
return PointerGetDatum(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(WARNING, "SPI_connect() failed in RI_FKey_check()");
|
elog(WARNING, "SPI_connect() failed in RI_FKey_check()");
|
||||||
|
|
||||||
@ -2741,6 +2747,16 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
heap_close(fk_rel, RowExclusiveLock);
|
heap_close(fk_rel, RowExclusiveLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the case we delete the row who's key is equal to the
|
||||||
|
* default values AND a referencing row in the foreign key
|
||||||
|
* table exists, we would just have updated it to the same
|
||||||
|
* values. We need to do another lookup now and in case a
|
||||||
|
* reference exists, abort the operation. That is already
|
||||||
|
* implemented in the NO ACTION trigger.
|
||||||
|
*/
|
||||||
|
RI_FKey_noaction_del(fcinfo);
|
||||||
|
|
||||||
return PointerGetDatum(NULL);
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3010,6 +3026,16 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
heap_close(fk_rel, RowExclusiveLock);
|
heap_close(fk_rel, RowExclusiveLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the case we updated the row who's key was equal to the
|
||||||
|
* default values AND a referencing row in the foreign key
|
||||||
|
* table exists, we would just have updated it to the same
|
||||||
|
* values. We need to do another lookup now and in case a
|
||||||
|
* reference exists, abort the operation. That is already
|
||||||
|
* implemented in the NO ACTION trigger.
|
||||||
|
*/
|
||||||
|
RI_FKey_noaction_upd(fcinfo);
|
||||||
|
|
||||||
return PointerGetDatum(NULL);
|
return PointerGetDatum(NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -882,7 +882,7 @@ delete from pktable where base1=2;
|
|||||||
ERROR: $1 referential integrity violation - key in pktable still referenced from pktable
|
ERROR: $1 referential integrity violation - key in pktable 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 referenced from pktable not found in pktable
|
ERROR: $1 referential integrity violation - key in pktable 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;
|
||||||
|
Reference in New Issue
Block a user