*** src/backend/commands/explain.c.orig Mon Aug 11 16:46:46 2003 --- src/backend/commands/explain.c Thu Sep 25 12:51:27 2003 *************** *** 207,213 **** gettimeofday(&starttime, NULL); /* call ExecutorStart to prepare the plan for execution */ ! ExecutorStart(queryDesc, !stmt->analyze); /* Execute the plan for statistics if asked for */ if (stmt->analyze) --- 207,213 ---- gettimeofday(&starttime, NULL); /* call ExecutorStart to prepare the plan for execution */ ! ExecutorStart(queryDesc, false, !stmt->analyze); /* Execute the plan for statistics if asked for */ if (stmt->analyze) *** src/backend/commands/trigger.c.orig Thu Sep 25 10:22:57 2003 --- src/backend/commands/trigger.c Thu Sep 25 12:51:27 2003 *************** *** 1863,1874 **** heap_freetuple(rettuple); /* - * Might have been a referential integrity constraint trigger. Reset - * the snapshot overriding flag. - */ - ReferentialIntegritySnapshotOverride = false; - - /* * Release buffers */ if (ItemPointerIsValid(&(event->dte_oldctid))) --- 1863,1868 ---- *** src/backend/executor/execMain.c.orig Thu Sep 25 10:22:59 2003 --- src/backend/executor/execMain.c Thu Sep 25 14:00:34 2003 *************** *** 104,109 **** --- 104,112 ---- * 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. * + * 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, * only to set up for EXPLAIN; so skip unwanted side-effects. * *************** *** 112,118 **** * ---------------------------------------------------------------- */ void ! ExecutorStart(QueryDesc *queryDesc, bool explainOnly) { EState *estate; MemoryContext oldcontext; --- 115,121 ---- * ---------------------------------------------------------------- */ void ! ExecutorStart(QueryDesc *queryDesc, bool useSnapshotNow, bool explainOnly) { EState *estate; MemoryContext oldcontext; *************** *** 154,160 **** * the life of this query, even if it outlives the current command and * current snapshot. */ ! estate->es_snapshot = CopyQuerySnapshot(); /* * Initialize the plan state tree --- 157,172 ---- * the life of this query, even if it outlives the current command and * current snapshot. */ ! if (useSnapshotNow) ! { ! estate->es_snapshot = SnapshotNow; ! estate->es_snapshot_cid = GetCurrentCommandId(); ! } ! else ! { ! estate->es_snapshot = CopyQuerySnapshot(); ! estate->es_snapshot_cid = estate->es_snapshot->curcid; ! } /* * Initialize the plan state tree *************** *** 1106,1112 **** tuple.t_self = *((ItemPointer) DatumGetPointer(datum)); test = heap_mark4update(erm->relation, &tuple, &buffer, ! estate->es_snapshot->curcid); ReleaseBuffer(buffer); switch (test) { --- 1118,1124 ---- tuple.t_self = *((ItemPointer) DatumGetPointer(datum)); test = heap_mark4update(erm->relation, &tuple, &buffer, ! estate->es_snapshot_cid); ReleaseBuffer(buffer); switch (test) { *************** *** 1266,1272 **** if (estate->es_into_relation_descriptor != NULL) { heap_insert(estate->es_into_relation_descriptor, tuple, ! estate->es_snapshot->curcid); IncrAppended(); } --- 1278,1284 ---- if (estate->es_into_relation_descriptor != NULL) { heap_insert(estate->es_into_relation_descriptor, tuple, ! estate->es_snapshot_cid); IncrAppended(); } *************** *** 1342,1348 **** * insert the tuple */ newId = heap_insert(resultRelationDesc, tuple, ! estate->es_snapshot->curcid); IncrAppended(); (estate->es_processed)++; --- 1354,1360 ---- * insert the tuple */ newId = heap_insert(resultRelationDesc, tuple, ! estate->es_snapshot_cid); IncrAppended(); (estate->es_processed)++; *************** *** 1394,1400 **** bool dodelete; dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid, ! estate->es_snapshot->curcid); if (!dodelete) /* "do nothing" */ return; --- 1406,1412 ---- bool dodelete; dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid, ! estate->es_snapshot_cid); if (!dodelete) /* "do nothing" */ return; *************** *** 1406,1412 **** ldelete:; result = heap_delete(resultRelationDesc, tupleid, &ctid, ! estate->es_snapshot->curcid, true /* wait for commit */); switch (result) { --- 1418,1424 ---- ldelete:; result = heap_delete(resultRelationDesc, tupleid, &ctid, ! estate->es_snapshot_cid, true /* wait for commit */); switch (result) { *************** *** 1505,1511 **** newtuple = ExecBRUpdateTriggers(estate, resultRelInfo, tupleid, tuple, ! estate->es_snapshot->curcid); if (newtuple == NULL) /* "do nothing" */ return; --- 1517,1523 ---- newtuple = ExecBRUpdateTriggers(estate, resultRelInfo, tupleid, tuple, ! estate->es_snapshot_cid); if (newtuple == NULL) /* "do nothing" */ return; *************** *** 1541,1547 **** */ result = heap_update(resultRelationDesc, tupleid, tuple, &ctid, ! estate->es_snapshot->curcid, true /* wait for commit */); switch (result) { --- 1553,1559 ---- */ result = heap_update(resultRelationDesc, tupleid, tuple, &ctid, ! estate->es_snapshot_cid, true /* wait for commit */); switch (result) { *************** *** 2027,2032 **** --- 2039,2045 ---- */ epqstate->es_direction = ForwardScanDirection; epqstate->es_snapshot = estate->es_snapshot; + epqstate->es_snapshot_cid = estate->es_snapshot_cid; epqstate->es_range_table = estate->es_range_table; epqstate->es_result_relations = estate->es_result_relations; epqstate->es_num_result_relations = estate->es_num_result_relations; *** src/backend/executor/execUtils.c.orig Wed Sep 24 14:54:01 2003 --- src/backend/executor/execUtils.c Thu Sep 25 14:00:35 2003 *************** *** 178,183 **** --- 178,184 ---- */ estate->es_direction = ForwardScanDirection; estate->es_snapshot = SnapshotNow; + estate->es_snapshot_cid = FirstCommandId; estate->es_range_table = NIL; estate->es_result_relations = NULL; *** src/backend/executor/functions.c.orig Thu Sep 25 10:22:59 2003 --- src/backend/executor/functions.c Thu Sep 25 12:51:10 2003 *************** *** 291,297 **** /* Utility commands don't need Executor. */ if (es->qd->operation != CMD_UTILITY) ! ExecutorStart(es->qd, false); es->status = F_EXEC_RUN; } --- 291,297 ---- /* Utility commands don't need Executor. */ if (es->qd->operation != CMD_UTILITY) ! ExecutorStart(es->qd, false, false); es->status = F_EXEC_RUN; } *** src/backend/executor/nodeSubplan.c.orig Thu Sep 25 10:22:59 2003 --- src/backend/executor/nodeSubplan.c Thu Sep 25 14:00:35 2003 *************** *** 709,714 **** --- 709,715 ---- sp_estate->es_tupleTable = ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10); sp_estate->es_snapshot = estate->es_snapshot; + sp_estate->es_snapshot_cid = estate->es_snapshot_cid; sp_estate->es_instrument = estate->es_instrument; /* *** src/backend/executor/nodeSubqueryscan.c.orig Sun Aug 3 23:00:35 2003 --- src/backend/executor/nodeSubqueryscan.c Thu Sep 25 14:00:35 2003 *************** *** 177,182 **** --- 177,183 ---- sp_estate->es_tupleTable = ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10); sp_estate->es_snapshot = estate->es_snapshot; + sp_estate->es_snapshot_cid = estate->es_snapshot_cid; sp_estate->es_instrument = estate->es_instrument; /* *** src/backend/executor/spi.c.orig Tue Sep 23 11:11:33 2003 --- src/backend/executor/spi.c Thu Sep 25 12:51:11 2003 *************** *** 32,41 **** static int _SPI_curid = -1; 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_execute_plan(_SPI_plan *plan, ! Datum *Values, const char *Nulls, int tcount); static void _SPI_cursor_operation(Portal portal, bool forward, int count, DestReceiver *dest); --- 32,43 ---- static int _SPI_curid = -1; static int _SPI_execute(const char *src, int tcount, _SPI_plan *plan); ! static int _SPI_pquery(QueryDesc *queryDesc, bool runit, ! bool useSnapshotNow, int tcount); static int _SPI_execute_plan(_SPI_plan *plan, ! Datum *Values, const char *Nulls, ! bool useSnapshotNow, int tcount); static void _SPI_cursor_operation(Portal portal, bool forward, int count, DestReceiver *dest); *************** *** 236,242 **** if (res < 0) return res; ! res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, tcount); _SPI_end_call(true); return res; --- 238,270 ---- if (res < 0) return res; ! 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); return res; *************** *** 1068,1074 **** { qdesc = CreateQueryDesc(queryTree, planTree, dest, NULL, false); ! res = _SPI_pquery(qdesc, true, queryTree->canSetTag ? tcount : 0); if (res < 0) return res; --- 1096,1102 ---- { qdesc = CreateQueryDesc(queryTree, planTree, dest, NULL, false); ! res = _SPI_pquery(qdesc, true, false, queryTree->canSetTag ? tcount : 0); if (res < 0) return res; *************** *** 1078,1084 **** { qdesc = CreateQueryDesc(queryTree, planTree, dest, NULL, false); ! res = _SPI_pquery(qdesc, false, 0); if (res < 0) return res; } --- 1106,1112 ---- { qdesc = CreateQueryDesc(queryTree, planTree, dest, NULL, false); ! res = _SPI_pquery(qdesc, false, false, 0); if (res < 0) return res; } *************** *** 1096,1102 **** static int _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, ! int tcount) { List *query_list_list = plan->qtlist; List *plan_list = plan->ptlist; --- 1124,1130 ---- static int _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, ! bool useSnapshotNow, int tcount) { List *query_list_list = plan->qtlist; List *plan_list = plan->ptlist; *************** *** 1167,1173 **** { qdesc = CreateQueryDesc(queryTree, planTree, dest, paramLI, false); ! res = _SPI_pquery(qdesc, true, queryTree->canSetTag ? tcount : 0); if (res < 0) return res; --- 1195,1201 ---- { qdesc = CreateQueryDesc(queryTree, planTree, dest, paramLI, false); ! res = _SPI_pquery(qdesc, true, useSnapshotNow, queryTree->canSetTag ? tcount : 0); if (res < 0) return res; *************** *** 1180,1186 **** } static int ! _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount) { int operation = queryDesc->operation; int res; --- 1208,1214 ---- } static int ! _SPI_pquery(QueryDesc *queryDesc, bool runit, bool useSnapshotNow, int tcount) { int operation = queryDesc->operation; int res; *************** *** 1217,1223 **** ResetUsage(); #endif ! ExecutorStart(queryDesc, false); ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount); --- 1245,1251 ---- ResetUsage(); #endif ! ExecutorStart(queryDesc, useSnapshotNow, false); ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount); *** src/backend/tcop/pquery.c.orig Tue Aug 12 14:23:21 2003 --- src/backend/tcop/pquery.c Thu Sep 25 12:50:59 2003 *************** *** 131,137 **** /* * Call ExecStart to prepare the plan for execution */ ! ExecutorStart(queryDesc, false); /* * Run the plan to completion. --- 131,137 ---- /* * Call ExecStart to prepare the plan for execution */ ! ExecutorStart(queryDesc, false, false); /* * Run the plan to completion. *************** *** 269,275 **** /* * Call ExecStart to prepare the plan for execution */ ! ExecutorStart(queryDesc, false); /* * This tells PortalCleanup to shut down the executor --- 269,275 ---- /* * Call ExecStart to prepare the plan for execution */ ! ExecutorStart(queryDesc, false, false); /* * This tells PortalCleanup to shut down the executor *** src/backend/utils/adt/ri_triggers.c.orig Thu Sep 25 10:23:14 2003 --- src/backend/utils/adt/ri_triggers.c Thu Sep 25 12:50:46 2003 *************** *** 187,194 **** int i; int match_type; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 187,192 ---- *************** *** 627,634 **** int i; int match_type; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 625,630 ---- *************** *** 807,814 **** int i; int match_type; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 803,808 ---- *************** *** 995,1002 **** void *qplan; int i; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 989,994 ---- *************** *** 1159,1166 **** int i; int j; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 1151,1156 ---- *************** *** 1349,1356 **** void *qplan; int i; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 1339,1344 ---- *************** *** 1520,1527 **** void *qplan; int i; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 1508,1513 ---- *************** *** 1694,1701 **** void *qplan; int i; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 1680,1685 ---- *************** *** 1868,1875 **** int match_type; bool use_cached_query; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 1852,1857 ---- *************** *** 2083,2090 **** RI_QueryKey qkey; void *qplan; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 2065,2070 ---- *************** *** 2296,2303 **** void *qplan; int match_type; - ReferentialIntegritySnapshotOverride = true; - /* * Check that this is a valid trigger call on the right time and * event. --- 2276,2281 ---- *************** *** 2936,2950 **** */ limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0; ! /* Run the plan */ ! spi_result = SPI_execp(qplan, vals, nulls, limit); /* Restore UID */ SetUserId(save_uid); /* Check result */ if (spi_result < 0) ! elog(ERROR, "SPI_execp failed"); if (expect_OK >= 0 && spi_result != expect_OK) ri_ReportViolation(qkey, constrname ? constrname : "", --- 2914,2932 ---- */ limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0; ! /* ! * 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 */ SetUserId(save_uid); /* Check result */ if (spi_result < 0) ! elog(ERROR, "SPI_execp_now returned %d", spi_result); if (expect_OK >= 0 && spi_result != expect_OK) ri_ReportViolation(qkey, constrname ? constrname : "", *** src/backend/utils/time/tqual.c.orig Sun Sep 21 20:47:23 2003 --- src/backend/utils/time/tqual.c Thu Sep 25 12:50:38 2003 *************** *** 39,46 **** TransactionId RecentXmin = InvalidTransactionId; TransactionId RecentGlobalXmin = InvalidTransactionId; - bool ReferentialIntegritySnapshotOverride = false; - /* * HeapTupleSatisfiesItself --- 39,44 ---- *************** *** 665,674 **** bool 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_INVALID) --- 663,668 ---- *************** *** 978,986 **** void SetQuerySnapshot(void) { - /* Initialize snapshot overriding to false */ - ReferentialIntegritySnapshotOverride = false; - /* 1st call in xaction? */ if (SerializableSnapshot == NULL) { --- 972,977 ---- *** src/include/access/valid.h.orig Sun Aug 3 23:01:27 2003 --- src/include/access/valid.h Thu Sep 25 12:50:32 2003 *************** *** 93,99 **** relation, \ buffer, \ disk_page, \ ! seeself, \ nKeys, \ key, \ res) \ --- 93,99 ---- relation, \ buffer, \ disk_page, \ ! snapshot, \ nKeys, \ key, \ res) \ *************** *** 112,118 **** { \ uint16 _infomask = (tuple)->t_data->t_infomask; \ \ ! (res) = HeapTupleSatisfiesVisibility((tuple), (seeself)); \ if ((tuple)->t_data->t_infomask != _infomask) \ SetBufferCommitInfoNeedsSave(buffer); \ } \ --- 112,118 ---- { \ uint16 _infomask = (tuple)->t_data->t_infomask; \ \ ! (res) = HeapTupleSatisfiesVisibility((tuple), (snapshot)); \ if ((tuple)->t_data->t_infomask != _infomask) \ SetBufferCommitInfoNeedsSave(buffer); \ } \ *** src/include/executor/executor.h.orig Mon Aug 18 21:13:41 2003 --- src/include/executor/executor.h Thu Sep 25 12:50:26 2003 *************** *** 85,91 **** /* * prototypes from functions in execMain.c */ ! extern void ExecutorStart(QueryDesc *queryDesc, bool explainOnly); extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count); extern void ExecutorEnd(QueryDesc *queryDesc); --- 85,92 ---- /* * prototypes from functions in execMain.c */ ! extern void ExecutorStart(QueryDesc *queryDesc, bool useSnapshotNow, ! bool explainOnly); extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count); extern void ExecutorEnd(QueryDesc *queryDesc); *** src/include/executor/spi.h.orig Sun Aug 3 23:01:33 2003 --- src/include/executor/spi.h Thu Sep 25 12:50:26 2003 *************** *** 84,89 **** --- 84,91 ---- extern int SPI_exec(const char *src, int tcount); extern int SPI_execp(void *plan, Datum *values, const char *Nulls, 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_saveplan(void *plan); extern int SPI_freeplan(void *plan); *** src/include/nodes/execnodes.h.orig Fri Aug 22 16:30:27 2003 --- src/include/nodes/execnodes.h Thu Sep 25 13:52:34 2003 *************** *** 286,291 **** --- 286,292 ---- /* Basic state for all query types: */ ScanDirection es_direction; /* current scan direction */ Snapshot es_snapshot; /* time qual to use */ + CommandId es_snapshot_cid; /* CommandId component of time qual */ List *es_range_table; /* List of RangeTableEntrys */ /* Info about target table for insert/update/delete queries: */ *** src/include/utils/tqual.h.orig Sun Aug 3 23:01:45 2003 --- src/include/utils/tqual.h Thu Sep 25 12:50:12 2003 *************** *** 44,57 **** extern TransactionId RecentXmin; 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 --- 44,49 ---- *************** *** 62,80 **** * Beware of multiple evaluations of snapshot argument. */ #define HeapTupleSatisfiesVisibility(tuple, snapshot) \ ! (IsSnapshotNow(snapshot) ? \ HeapTupleSatisfiesNow((tuple)->t_data) \ : \ ! (IsSnapshotSelf(snapshot) ? \ HeapTupleSatisfiesItself((tuple)->t_data) \ : \ ! (IsSnapshotAny(snapshot) ? \ true \ : \ ! (IsSnapshotToast(snapshot) ? \ HeapTupleSatisfiesToast((tuple)->t_data) \ : \ ! (IsSnapshotDirty(snapshot) ? \ HeapTupleSatisfiesDirty((tuple)->t_data) \ : \ HeapTupleSatisfiesSnapshot((tuple)->t_data, snapshot) \ --- 54,72 ---- * Beware of multiple evaluations of snapshot argument. */ #define HeapTupleSatisfiesVisibility(tuple, snapshot) \ ! ((snapshot) == SnapshotNow ? \ HeapTupleSatisfiesNow((tuple)->t_data) \ : \ ! ((snapshot) == SnapshotSelf ? \ HeapTupleSatisfiesItself((tuple)->t_data) \ : \ ! ((snapshot) == SnapshotAny ? \ true \ : \ ! ((snapshot) == SnapshotToast ? \ HeapTupleSatisfiesToast((tuple)->t_data) \ : \ ! ((snapshot) == SnapshotDirty ? \ HeapTupleSatisfiesDirty((tuple)->t_data) \ : \ HeapTupleSatisfiesSnapshot((tuple)->t_data, snapshot) \