Commit c63a5452 authored by Tom Lane's avatar Tom Lane

Get rid of ReferentialIntegritySnapshotOverride by extending Executor API

to allow es_snapshot to be set to SnapshotNow rather than a query snapshot.
This solves a bug reported by Wade Klaver, wherein triggers fired as a
result of RI cascade updates could misbehave.
parent 7ab5c5b8
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.115 2003/08/11 20:46:46 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.116 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -207,7 +207,7 @@ ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt, ...@@ -207,7 +207,7 @@ ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
gettimeofday(&starttime, NULL); gettimeofday(&starttime, NULL);
/* call ExecutorStart to prepare the plan for execution */ /* call ExecutorStart to prepare the plan for execution */
ExecutorStart(queryDesc, !stmt->analyze); ExecutorStart(queryDesc, false, !stmt->analyze);
/* Execute the plan for statistics if asked for */ /* Execute the plan for statistics if asked for */
if (stmt->analyze) if (stmt->analyze)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.157 2003/09/25 06:57:58 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.158 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1862,12 +1862,6 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno, ...@@ -1862,12 +1862,6 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple) if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
heap_freetuple(rettuple); heap_freetuple(rettuple);
/*
* Might have been a referential integrity constraint trigger. Reset
* the snapshot overriding flag.
*/
ReferentialIntegritySnapshotOverride = false;
/* /*
* Release buffers * Release buffers
*/ */
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.218 2003/09/25 06:57:59 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.219 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -104,6 +104,9 @@ static void EvalPlanQualStop(evalPlanQual *epq); ...@@ -104,6 +104,9 @@ static void EvalPlanQualStop(evalPlanQual *epq);
* field of the QueryDesc is filled in to describe the tuples that will be * field of the QueryDesc is filled in to describe the tuples that will be
* returned, and the internal fields (estate and planstate) are set up. * returned, and the internal fields (estate and planstate) are set up.
* *
* If useSnapshotNow is true, run the query with SnapshotNow time qual rules
* instead of the normal use of QuerySnapshot.
*
* If explainOnly is true, we are not actually intending to run the plan, * If explainOnly is true, we are not actually intending to run the plan,
* only to set up for EXPLAIN; so skip unwanted side-effects. * only to set up for EXPLAIN; so skip unwanted side-effects.
* *
...@@ -112,7 +115,7 @@ static void EvalPlanQualStop(evalPlanQual *epq); ...@@ -112,7 +115,7 @@ static void EvalPlanQualStop(evalPlanQual *epq);
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
ExecutorStart(QueryDesc *queryDesc, bool explainOnly) ExecutorStart(QueryDesc *queryDesc, bool useSnapshotNow, bool explainOnly)
{ {
EState *estate; EState *estate;
MemoryContext oldcontext; MemoryContext oldcontext;
...@@ -154,7 +157,16 @@ ExecutorStart(QueryDesc *queryDesc, bool explainOnly) ...@@ -154,7 +157,16 @@ ExecutorStart(QueryDesc *queryDesc, bool explainOnly)
* the life of this query, even if it outlives the current command and * the life of this query, even if it outlives the current command and
* current snapshot. * current snapshot.
*/ */
if (useSnapshotNow)
{
estate->es_snapshot = SnapshotNow;
estate->es_snapshot_cid = GetCurrentCommandId();
}
else
{
estate->es_snapshot = CopyQuerySnapshot(); estate->es_snapshot = CopyQuerySnapshot();
estate->es_snapshot_cid = estate->es_snapshot->curcid;
}
/* /*
* Initialize the plan state tree * Initialize the plan state tree
...@@ -1106,7 +1118,7 @@ lnext: ; ...@@ -1106,7 +1118,7 @@ lnext: ;
tuple.t_self = *((ItemPointer) DatumGetPointer(datum)); tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
test = heap_mark4update(erm->relation, &tuple, &buffer, test = heap_mark4update(erm->relation, &tuple, &buffer,
estate->es_snapshot->curcid); estate->es_snapshot_cid);
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
switch (test) switch (test)
{ {
...@@ -1266,7 +1278,7 @@ ExecSelect(TupleTableSlot *slot, ...@@ -1266,7 +1278,7 @@ ExecSelect(TupleTableSlot *slot,
if (estate->es_into_relation_descriptor != NULL) if (estate->es_into_relation_descriptor != NULL)
{ {
heap_insert(estate->es_into_relation_descriptor, tuple, heap_insert(estate->es_into_relation_descriptor, tuple,
estate->es_snapshot->curcid); estate->es_snapshot_cid);
IncrAppended(); IncrAppended();
} }
...@@ -1342,7 +1354,7 @@ ExecInsert(TupleTableSlot *slot, ...@@ -1342,7 +1354,7 @@ ExecInsert(TupleTableSlot *slot,
* insert the tuple * insert the tuple
*/ */
newId = heap_insert(resultRelationDesc, tuple, newId = heap_insert(resultRelationDesc, tuple,
estate->es_snapshot->curcid); estate->es_snapshot_cid);
IncrAppended(); IncrAppended();
(estate->es_processed)++; (estate->es_processed)++;
...@@ -1394,7 +1406,7 @@ ExecDelete(TupleTableSlot *slot, ...@@ -1394,7 +1406,7 @@ ExecDelete(TupleTableSlot *slot,
bool dodelete; bool dodelete;
dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid, dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid,
estate->es_snapshot->curcid); estate->es_snapshot_cid);
if (!dodelete) /* "do nothing" */ if (!dodelete) /* "do nothing" */
return; return;
...@@ -1406,7 +1418,7 @@ ExecDelete(TupleTableSlot *slot, ...@@ -1406,7 +1418,7 @@ ExecDelete(TupleTableSlot *slot,
ldelete:; ldelete:;
result = heap_delete(resultRelationDesc, tupleid, result = heap_delete(resultRelationDesc, tupleid,
&ctid, &ctid,
estate->es_snapshot->curcid, estate->es_snapshot_cid,
true /* wait for commit */); true /* wait for commit */);
switch (result) switch (result)
{ {
...@@ -1505,7 +1517,7 @@ ExecUpdate(TupleTableSlot *slot, ...@@ -1505,7 +1517,7 @@ ExecUpdate(TupleTableSlot *slot,
newtuple = ExecBRUpdateTriggers(estate, resultRelInfo, newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,
tupleid, tuple, tupleid, tuple,
estate->es_snapshot->curcid); estate->es_snapshot_cid);
if (newtuple == NULL) /* "do nothing" */ if (newtuple == NULL) /* "do nothing" */
return; return;
...@@ -1541,7 +1553,7 @@ lreplace:; ...@@ -1541,7 +1553,7 @@ lreplace:;
*/ */
result = heap_update(resultRelationDesc, tupleid, tuple, result = heap_update(resultRelationDesc, tupleid, tuple,
&ctid, &ctid,
estate->es_snapshot->curcid, estate->es_snapshot_cid,
true /* wait for commit */); true /* wait for commit */);
switch (result) switch (result)
{ {
...@@ -2027,6 +2039,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq) ...@@ -2027,6 +2039,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
*/ */
epqstate->es_direction = ForwardScanDirection; epqstate->es_direction = ForwardScanDirection;
epqstate->es_snapshot = estate->es_snapshot; epqstate->es_snapshot = estate->es_snapshot;
epqstate->es_snapshot_cid = estate->es_snapshot_cid;
epqstate->es_range_table = estate->es_range_table; epqstate->es_range_table = estate->es_range_table;
epqstate->es_result_relations = estate->es_result_relations; epqstate->es_result_relations = estate->es_result_relations;
epqstate->es_num_result_relations = estate->es_num_result_relations; epqstate->es_num_result_relations = estate->es_num_result_relations;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.104 2003/09/24 18:54:01 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.105 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -178,6 +178,7 @@ CreateExecutorState(void) ...@@ -178,6 +178,7 @@ CreateExecutorState(void)
*/ */
estate->es_direction = ForwardScanDirection; estate->es_direction = ForwardScanDirection;
estate->es_snapshot = SnapshotNow; estate->es_snapshot = SnapshotNow;
estate->es_snapshot_cid = FirstCommandId;
estate->es_range_table = NIL; estate->es_range_table = NIL;
estate->es_result_relations = NULL; estate->es_result_relations = NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.74 2003/09/25 06:57:59 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.75 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -291,7 +291,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache) ...@@ -291,7 +291,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
/* Utility commands don't need Executor. */ /* Utility commands don't need Executor. */
if (es->qd->operation != CMD_UTILITY) if (es->qd->operation != CMD_UTILITY)
ExecutorStart(es->qd, false); ExecutorStart(es->qd, false, false);
es->status = F_EXEC_RUN; es->status = F_EXEC_RUN;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.56 2003/09/25 06:57:59 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.57 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -709,6 +709,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) ...@@ -709,6 +709,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
sp_estate->es_tupleTable = sp_estate->es_tupleTable =
ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10); ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10);
sp_estate->es_snapshot = estate->es_snapshot; sp_estate->es_snapshot = estate->es_snapshot;
sp_estate->es_snapshot_cid = estate->es_snapshot_cid;
sp_estate->es_instrument = estate->es_instrument; sp_estate->es_instrument = estate->es_instrument;
/* /*
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.20 2003/08/04 02:39:59 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.21 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -177,6 +177,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate) ...@@ -177,6 +177,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
sp_estate->es_tupleTable = sp_estate->es_tupleTable =
ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10); ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
sp_estate->es_snapshot = estate->es_snapshot; sp_estate->es_snapshot = estate->es_snapshot;
sp_estate->es_snapshot_cid = estate->es_snapshot_cid;
sp_estate->es_instrument = estate->es_instrument; sp_estate->es_instrument = estate->es_instrument;
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.105 2003/09/23 15:11:33 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.106 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,10 +32,12 @@ static int _SPI_connected = -1; ...@@ -32,10 +32,12 @@ static int _SPI_connected = -1;
static int _SPI_curid = -1; static int _SPI_curid = -1;
static int _SPI_execute(const char *src, int tcount, _SPI_plan *plan); static int _SPI_execute(const char *src, int tcount, _SPI_plan *plan);
static int _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount); static int _SPI_pquery(QueryDesc *queryDesc, bool runit,
bool useSnapshotNow, int tcount);
static int _SPI_execute_plan(_SPI_plan *plan, static int _SPI_execute_plan(_SPI_plan *plan,
Datum *Values, const char *Nulls, int tcount); Datum *Values, const char *Nulls,
bool useSnapshotNow, int tcount);
static void _SPI_cursor_operation(Portal portal, bool forward, int count, static void _SPI_cursor_operation(Portal portal, bool forward, int count,
DestReceiver *dest); DestReceiver *dest);
...@@ -236,7 +238,33 @@ SPI_execp(void *plan, Datum *Values, const char *Nulls, int tcount) ...@@ -236,7 +238,33 @@ SPI_execp(void *plan, Datum *Values, const char *Nulls, int tcount)
if (res < 0) if (res < 0)
return res; return res;
res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, tcount); res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, false, tcount);
_SPI_end_call(true);
return res;
}
/*
* SPI_execp_now -- identical to SPI_execp, except that we use SnapshotNow
* instead of the normal QuerySnapshot. This is currently not documented
* in spi.sgml because it is only intended for use by RI triggers.
*/
int
SPI_execp_now(void *plan, Datum *Values, const char *Nulls, int tcount)
{
int res;
if (plan == NULL || tcount < 0)
return SPI_ERROR_ARGUMENT;
if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
return SPI_ERROR_PARAM;
res = _SPI_begin_call(true);
if (res < 0)
return res;
res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, true, tcount);
_SPI_end_call(true); _SPI_end_call(true);
return res; return res;
...@@ -1068,7 +1096,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) ...@@ -1068,7 +1096,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
{ {
qdesc = CreateQueryDesc(queryTree, planTree, dest, qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL, false); NULL, false);
res = _SPI_pquery(qdesc, true, res = _SPI_pquery(qdesc, true, false,
queryTree->canSetTag ? tcount : 0); queryTree->canSetTag ? tcount : 0);
if (res < 0) if (res < 0)
return res; return res;
...@@ -1078,7 +1106,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) ...@@ -1078,7 +1106,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
{ {
qdesc = CreateQueryDesc(queryTree, planTree, dest, qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL, false); NULL, false);
res = _SPI_pquery(qdesc, false, 0); res = _SPI_pquery(qdesc, false, false, 0);
if (res < 0) if (res < 0)
return res; return res;
} }
...@@ -1096,7 +1124,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) ...@@ -1096,7 +1124,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
static int static int
_SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
int tcount) bool useSnapshotNow, int tcount)
{ {
List *query_list_list = plan->qtlist; List *query_list_list = plan->qtlist;
List *plan_list = plan->ptlist; List *plan_list = plan->ptlist;
...@@ -1167,7 +1195,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, ...@@ -1167,7 +1195,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
{ {
qdesc = CreateQueryDesc(queryTree, planTree, dest, qdesc = CreateQueryDesc(queryTree, planTree, dest,
paramLI, false); paramLI, false);
res = _SPI_pquery(qdesc, true, res = _SPI_pquery(qdesc, true, useSnapshotNow,
queryTree->canSetTag ? tcount : 0); queryTree->canSetTag ? tcount : 0);
if (res < 0) if (res < 0)
return res; return res;
...@@ -1180,7 +1208,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, ...@@ -1180,7 +1208,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
} }
static int static int
_SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount) _SPI_pquery(QueryDesc *queryDesc, bool runit, bool useSnapshotNow, int tcount)
{ {
int operation = queryDesc->operation; int operation = queryDesc->operation;
int res; int res;
...@@ -1217,7 +1245,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount) ...@@ -1217,7 +1245,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
ResetUsage(); ResetUsage();
#endif #endif
ExecutorStart(queryDesc, false); ExecutorStart(queryDesc, useSnapshotNow, false);
ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount); ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.72 2003/08/12 18:23:21 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.73 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -131,7 +131,7 @@ ProcessQuery(Query *parsetree, ...@@ -131,7 +131,7 @@ ProcessQuery(Query *parsetree,
/* /*
* Call ExecStart to prepare the plan for execution * Call ExecStart to prepare the plan for execution
*/ */
ExecutorStart(queryDesc, false); ExecutorStart(queryDesc, false, false);
/* /*
* Run the plan to completion. * Run the plan to completion.
...@@ -269,7 +269,7 @@ PortalStart(Portal portal, ParamListInfo params) ...@@ -269,7 +269,7 @@ PortalStart(Portal portal, ParamListInfo params)
/* /*
* Call ExecStart to prepare the plan for execution * Call ExecStart to prepare the plan for execution
*/ */
ExecutorStart(queryDesc, false); ExecutorStart(queryDesc, false, false);
/* /*
* This tells PortalCleanup to shut down the executor * This tells PortalCleanup to shut down the executor
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* *
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.57 2003/09/25 06:58:04 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.58 2003/09/25 18:58:35 tgl Exp $
* *
* ---------- * ----------
*/ */
...@@ -187,8 +187,6 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -187,8 +187,6 @@ RI_FKey_check(PG_FUNCTION_ARGS)
int i; int i;
int match_type; int match_type;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -627,8 +625,6 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) ...@@ -627,8 +625,6 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
int i; int i;
int match_type; int match_type;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -807,8 +803,6 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) ...@@ -807,8 +803,6 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
int i; int i;
int match_type; int match_type;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -995,8 +989,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) ...@@ -995,8 +989,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
void *qplan; void *qplan;
int i; int i;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -1159,8 +1151,6 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) ...@@ -1159,8 +1151,6 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
int i; int i;
int j; int j;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -1349,8 +1339,6 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) ...@@ -1349,8 +1339,6 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
void *qplan; void *qplan;
int i; int i;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -1520,8 +1508,6 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) ...@@ -1520,8 +1508,6 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
void *qplan; void *qplan;
int i; int i;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -1694,8 +1680,6 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) ...@@ -1694,8 +1680,6 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
void *qplan; void *qplan;
int i; int i;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -1868,8 +1852,6 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ...@@ -1868,8 +1852,6 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
int match_type; int match_type;
bool use_cached_query; bool use_cached_query;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -2083,8 +2065,6 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) ...@@ -2083,8 +2065,6 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
RI_QueryKey qkey; RI_QueryKey qkey;
void *qplan; void *qplan;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -2296,8 +2276,6 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ...@@ -2296,8 +2276,6 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
void *qplan; void *qplan;
int match_type; int match_type;
ReferentialIntegritySnapshotOverride = true;
/* /*
* Check that this is a valid trigger call on the right time and * Check that this is a valid trigger call on the right time and
* event. * event.
...@@ -2936,15 +2914,19 @@ ri_PerformCheck(RI_QueryKey *qkey, void *qplan, ...@@ -2936,15 +2914,19 @@ ri_PerformCheck(RI_QueryKey *qkey, void *qplan,
*/ */
limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0; limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0;
/* Run the plan */ /*
spi_result = SPI_execp(qplan, vals, nulls, limit); * Run the plan, using SnapshotNow time qual rules so that we can see
* all committed tuples, even those committed after our own transaction
* or query started.
*/
spi_result = SPI_execp_now(qplan, vals, nulls, limit);
/* Restore UID */ /* Restore UID */
SetUserId(save_uid); SetUserId(save_uid);
/* Check result */ /* Check result */
if (spi_result < 0) if (spi_result < 0)
elog(ERROR, "SPI_execp failed"); elog(ERROR, "SPI_execp_now returned %d", spi_result);
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 : "",
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.68 2003/09/22 00:47:23 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.69 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,8 +39,6 @@ Snapshot SerializableSnapshot = NULL; ...@@ -39,8 +39,6 @@ Snapshot SerializableSnapshot = NULL;
TransactionId RecentXmin = InvalidTransactionId; TransactionId RecentXmin = InvalidTransactionId;
TransactionId RecentGlobalXmin = InvalidTransactionId; TransactionId RecentGlobalXmin = InvalidTransactionId;
bool ReferentialIntegritySnapshotOverride = false;
/* /*
* HeapTupleSatisfiesItself * HeapTupleSatisfiesItself
...@@ -665,10 +663,6 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) ...@@ -665,10 +663,6 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple)
bool bool
HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot)
{ {
/* XXX this is horribly ugly: */
if (ReferentialIntegritySnapshotOverride)
return HeapTupleSatisfiesNow(tuple);
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
{ {
if (tuple->t_infomask & HEAP_XMIN_INVALID) if (tuple->t_infomask & HEAP_XMIN_INVALID)
...@@ -978,9 +972,6 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) ...@@ -978,9 +972,6 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin)
void void
SetQuerySnapshot(void) SetQuerySnapshot(void)
{ {
/* Initialize snapshot overriding to false */
ReferentialIntegritySnapshotOverride = false;
/* 1st call in xaction? */ /* 1st call in xaction? */
if (SerializableSnapshot == NULL) if (SerializableSnapshot == NULL)
{ {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, 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: valid.h,v 1.30 2003/08/04 02:40:10 momjian Exp $ * $Id: valid.h,v 1.31 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -93,7 +93,7 @@ do \ ...@@ -93,7 +93,7 @@ do \
relation, \ relation, \
buffer, \ buffer, \
disk_page, \ disk_page, \
seeself, \ snapshot, \
nKeys, \ nKeys, \
key, \ key, \
res) \ res) \
...@@ -112,7 +112,7 @@ do \ ...@@ -112,7 +112,7 @@ do \
{ \ { \
uint16 _infomask = (tuple)->t_data->t_infomask; \ uint16 _infomask = (tuple)->t_data->t_infomask; \
\ \
(res) = HeapTupleSatisfiesVisibility((tuple), (seeself)); \ (res) = HeapTupleSatisfiesVisibility((tuple), (snapshot)); \
if ((tuple)->t_data->t_infomask != _infomask) \ if ((tuple)->t_data->t_infomask != _infomask) \
SetBufferCommitInfoNeedsSave(buffer); \ SetBufferCommitInfoNeedsSave(buffer); \
} \ } \
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, 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: executor.h,v 1.100 2003/08/19 01:13:41 tgl Exp $ * $Id: executor.h,v 1.101 2003/09/25 18:58:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -85,7 +85,8 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot); ...@@ -85,7 +85,8 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
/* /*
* prototypes from functions in execMain.c * prototypes from functions in execMain.c
*/ */
extern void ExecutorStart(QueryDesc *queryDesc, bool explainOnly); extern void ExecutorStart(QueryDesc *queryDesc, bool useSnapshotNow,
bool explainOnly);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count); ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc); extern void ExecutorEnd(QueryDesc *queryDesc);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* *
* spi.h * spi.h
* *
* $Id: spi.h,v 1.37 2003/08/04 00:43:31 momjian Exp $ * $Id: spi.h,v 1.38 2003/09/25 18:58:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -84,6 +84,8 @@ extern void SPI_pop(void); ...@@ -84,6 +84,8 @@ extern void SPI_pop(void);
extern int SPI_exec(const char *src, int tcount); extern int SPI_exec(const char *src, int tcount);
extern int SPI_execp(void *plan, Datum *values, const char *Nulls, extern int SPI_execp(void *plan, Datum *values, const char *Nulls,
int tcount); int tcount);
extern int SPI_execp_now(void *plan, Datum *values, const char *Nulls,
int tcount);
extern void *SPI_prepare(const char *src, int nargs, Oid *argtypes); extern void *SPI_prepare(const char *src, int nargs, Oid *argtypes);
extern void *SPI_saveplan(void *plan); extern void *SPI_saveplan(void *plan);
extern int SPI_freeplan(void *plan); extern int SPI_freeplan(void *plan);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, 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: execnodes.h,v 1.105 2003/08/22 20:26:43 tgl Exp $ * $Id: execnodes.h,v 1.106 2003/09/25 18:58:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -286,6 +286,7 @@ typedef struct EState ...@@ -286,6 +286,7 @@ typedef struct EState
/* Basic state for all query types: */ /* Basic state for all query types: */
ScanDirection es_direction; /* current scan direction */ ScanDirection es_direction; /* current scan direction */
Snapshot es_snapshot; /* time qual to use */ Snapshot es_snapshot; /* time qual to use */
CommandId es_snapshot_cid; /* CommandId component of time qual */
List *es_range_table; /* List of RangeTableEntrys */ List *es_range_table; /* List of RangeTableEntrys */
/* Info about target table for insert/update/delete queries: */ /* Info about target table for insert/update/delete queries: */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, 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: tqual.h,v 1.46 2003/08/04 02:40:15 momjian Exp $ * $Id: tqual.h,v 1.47 2003/09/25 18:58:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -44,14 +44,6 @@ extern DLLIMPORT Snapshot SerializableSnapshot; ...@@ -44,14 +44,6 @@ extern DLLIMPORT Snapshot SerializableSnapshot;
extern TransactionId RecentXmin; extern TransactionId RecentXmin;
extern TransactionId RecentGlobalXmin; extern TransactionId RecentGlobalXmin;
extern bool ReferentialIntegritySnapshotOverride;
#define IsSnapshotNow(snapshot) ((Snapshot) (snapshot) == SnapshotNow)
#define IsSnapshotSelf(snapshot) ((Snapshot) (snapshot) == SnapshotSelf)
#define IsSnapshotAny(snapshot) ((Snapshot) (snapshot) == SnapshotAny)
#define IsSnapshotToast(snapshot) ((Snapshot) (snapshot) == SnapshotToast)
#define IsSnapshotDirty(snapshot) ((Snapshot) (snapshot) == SnapshotDirty)
/* /*
* HeapTupleSatisfiesVisibility * HeapTupleSatisfiesVisibility
...@@ -62,19 +54,19 @@ extern bool ReferentialIntegritySnapshotOverride; ...@@ -62,19 +54,19 @@ extern bool ReferentialIntegritySnapshotOverride;
* Beware of multiple evaluations of snapshot argument. * Beware of multiple evaluations of snapshot argument.
*/ */
#define HeapTupleSatisfiesVisibility(tuple, snapshot) \ #define HeapTupleSatisfiesVisibility(tuple, snapshot) \
(IsSnapshotNow(snapshot) ? \ ((snapshot) == SnapshotNow ? \
HeapTupleSatisfiesNow((tuple)->t_data) \ HeapTupleSatisfiesNow((tuple)->t_data) \
: \ : \
(IsSnapshotSelf(snapshot) ? \ ((snapshot) == SnapshotSelf ? \
HeapTupleSatisfiesItself((tuple)->t_data) \ HeapTupleSatisfiesItself((tuple)->t_data) \
: \ : \
(IsSnapshotAny(snapshot) ? \ ((snapshot) == SnapshotAny ? \
true \ true \
: \ : \
(IsSnapshotToast(snapshot) ? \ ((snapshot) == SnapshotToast ? \
HeapTupleSatisfiesToast((tuple)->t_data) \ HeapTupleSatisfiesToast((tuple)->t_data) \
: \ : \
(IsSnapshotDirty(snapshot) ? \ ((snapshot) == SnapshotDirty ? \
HeapTupleSatisfiesDirty((tuple)->t_data) \ HeapTupleSatisfiesDirty((tuple)->t_data) \
: \ : \
HeapTupleSatisfiesSnapshot((tuple)->t_data, snapshot) \ HeapTupleSatisfiesSnapshot((tuple)->t_data, snapshot) \
......
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