1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-11 20:28:21 +03:00

Repair problems occurring when multiple RI updates have to be done to the same

row within one query: we were firing check triggers before all the updates
were done, leading to bogus failures.  Fix by making the triggers queued by
an RI update go at the end of the outer query's trigger event list, thereby
effectively making the processing "breadth-first".  This was indeed how it
worked pre-8.0, so the bug does not occur in the 7.x branches.
Per report from Pavel Stehule.
This commit is contained in:
Tom Lane
2007-08-15 19:15:47 +00:00
parent 5ff95e6b8e
commit 9cb8409762
6 changed files with 170 additions and 42 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.179 2007/04/27 22:05:47 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.180 2007/08/15 19:15:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -39,9 +39,9 @@ static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan);
static int _SPI_execute_plan(SPIPlanPtr plan,
Datum *Values, const char *Nulls,
Snapshot snapshot, Snapshot crosscheck_snapshot,
bool read_only, long tcount);
bool read_only, bool fire_triggers, long tcount);
static int _SPI_pquery(QueryDesc *queryDesc, long tcount);
static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount);
static void _SPI_error_callback(void *arg);
@ -316,7 +316,7 @@ SPI_execute(const char *src, bool read_only, long tcount)
res = _SPI_execute_plan(&plan, NULL, NULL,
InvalidSnapshot, InvalidSnapshot,
read_only, tcount);
read_only, true, tcount);
_SPI_end_call(true);
return res;
@ -349,7 +349,7 @@ SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
res = _SPI_execute_plan(plan,
Values, Nulls,
InvalidSnapshot, InvalidSnapshot,
read_only, tcount);
read_only, true, tcount);
_SPI_end_call(true);
return res;
@ -364,9 +364,12 @@ SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
/*
* SPI_execute_snapshot -- identical to SPI_execute_plan, except that we allow
* the caller to specify exactly which snapshots to use. This is currently
* not documented in spi.sgml because it is only intended for use by RI
* triggers.
* the caller to specify exactly which snapshots to use. Also, the caller
* may specify that AFTER triggers should be queued as part of the outer
* query rather than being fired immediately at the end of the command.
*
* This is currently not documented in spi.sgml because it is only intended
* for use by RI triggers.
*
* Passing snapshot == InvalidSnapshot will select the normal behavior of
* fetching a new snapshot for each query.
@ -375,7 +378,7 @@ int
SPI_execute_snapshot(SPIPlanPtr plan,
Datum *Values, const char *Nulls,
Snapshot snapshot, Snapshot crosscheck_snapshot,
bool read_only, long tcount)
bool read_only, bool fire_triggers, long tcount)
{
int res;
@ -392,7 +395,7 @@ SPI_execute_snapshot(SPIPlanPtr plan,
res = _SPI_execute_plan(plan,
Values, Nulls,
snapshot, crosscheck_snapshot,
read_only, tcount);
read_only, fire_triggers, tcount);
_SPI_end_call(true);
return res;
@ -1428,12 +1431,14 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
* behavior of taking a new snapshot for each query.
* crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
* read_only: TRUE for read-only execution (no CommandCounterIncrement)
* fire_triggers: TRUE to fire AFTER triggers at end of query (normal case);
* FALSE means any AFTER triggers are postponed to end of outer query
* tcount: execution tuple-count limit, or 0 for none
*/
static int
_SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
Snapshot snapshot, Snapshot crosscheck_snapshot,
bool read_only, long tcount)
bool read_only, bool fire_triggers, long tcount)
{
volatile int my_res = 0;
volatile uint32 my_processed = 0;
@ -1589,7 +1594,8 @@ _SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
crosscheck_snapshot,
dest,
paramLI, false);
res = _SPI_pquery(qdesc, canSetTag ? tcount : 0);
res = _SPI_pquery(qdesc, fire_triggers,
canSetTag ? tcount : 0);
FreeQueryDesc(qdesc);
}
else
@ -1680,7 +1686,7 @@ fail:
}
static int
_SPI_pquery(QueryDesc *queryDesc, long tcount)
_SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount)
{
int operation = queryDesc->operation;
int res;
@ -1726,7 +1732,8 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
ResetUsage();
#endif
AfterTriggerBeginQuery();
if (fire_triggers)
AfterTriggerBeginQuery();
ExecutorStart(queryDesc, 0);
@ -1743,7 +1750,8 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
}
/* Take care of any queued AFTER triggers */
AfterTriggerEndQuery(queryDesc->estate);
if (fire_triggers)
AfterTriggerEndQuery(queryDesc->estate);
ExecutorEnd(queryDesc);