@ -977,8 +977,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate - > es_tupleTable = NIL ;
/* mark EvalPlanQual not active */
estate - > es_epqTuple = NULL ;
estate - > es_epqTupleSet = NULL ;
estate - > es_epqTupleSlot = NULL ;
estate - > es_epqScanDone = NULL ;
/*
@ -2441,35 +2440,29 @@ EvalPlanQual(EState *estate, EPQState *epqstate,
ItemPointer tid , TransactionId priorXmax )
{
TupleTableSlot * slot ;
HeapTuple copyTuple ;
TupleTableSlot * testslot ;
Assert ( rti > 0 ) ;
/*
* Get and lock the updated version of the row ; if fail , return NULL .
* Need to run a recheck subquery . Initialize or reinitialize EPQ state .
*/
copyTuple = EvalPlanQualFetch ( estate , relation , lockmode , LockWaitBlock ,
tid , priorXmax ) ;
EvalPlanQualBegin ( epqstate , estate ) ;
if ( copyTuple = = NULL )
/*
* Get and lock the updated version of the row ; if fail , return NULL .
*/
testslot = EvalPlanQualSlot ( epqstate , relation , rti ) ;
if ( ! EvalPlanQualFetch ( estate , relation , lockmode , LockWaitBlock ,
tid , priorXmax ,
testslot ) )
return NULL ;
/*
* For UPDATE / DELETE we have to return tid of actual row we ' re executing
* PQ for .
*/
* tid = copyTuple - > t_self ;
/*
* Need to run a recheck subquery . Initialize or reinitialize EPQ state .
*/
EvalPlanQualBegin ( epqstate , estate ) ;
/*
* Free old test tuple , if any , and store new tuple where relation ' s scan
* node will see it
*/
EvalPlanQualSetTuple ( epqstate , rti , copyTuple ) ;
* tid = testslot - > tts_tid ;
/*
* Fetch any non - locked source rows
@ -2496,7 +2489,7 @@ EvalPlanQual(EState *estate, EPQState *epqstate,
* re - used to test a tuple for a different relation . ( Not clear that can
* really happen , but let ' s be safe . )
*/
EvalPlanQualSetTuple ( epqstate , rti , NULL ) ;
ExecClearTuple ( testslot ) ;
return slot ;
}
@ -2510,21 +2503,22 @@ EvalPlanQual(EState *estate, EPQState *epqstate,
* wait_policy - requested lock wait policy
* * tid - t_ctid from the outdated tuple ( ie , next updated version )
* priorXmax - t_xmax from the outdated tuple
* slot - slot to store newest tuple version
*
* Returns a palloc ' d copy of the newest tuple version , or NULL if we find
* that there is no newest version ( ie , the row was deleted not updated ) .
* We also return NULL if the tuple is locked and the wait policy is to skip
* Returns true , with slot containing the newest tuple version , or false if we
* find that there is no newest version ( ie , the row was deleted not updated ) .
* We also return false if the tuple is locked and the wait policy is to skip
* such tuples .
*
* If successful , we have locked the newest tuple version , so caller does not
* need to worry about it changing anymore .
*/
HeapTuple
bool
EvalPlanQualFetch ( EState * estate , Relation relation , LockTupleMode lockmode ,
LockWaitPolicy wait_policy ,
ItemPointer tid , TransactionId priorXmax )
ItemPointer tid , TransactionId priorXmax ,
TupleTableSlot * slot )
{
HeapTuple copyTuple = NULL ;
HeapTupleData tuple ;
SnapshotData SnapshotDirty ;
@ -2557,7 +2551,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
priorXmax ) )
{
ReleaseBuffer ( buffer ) ;
return NULL ;
return false ;
}
/* otherwise xmin should not be dirty... */
@ -2580,7 +2574,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
break ;
case LockWaitSkip :
if ( ! ConditionalXactLockTableWait ( SnapshotDirty . xmax ) )
return NULL ; /* skip instead of waiting */
return false ; /* skip instead of waiting */
break ;
case LockWaitError :
if ( ! ConditionalXactLockTableWait ( SnapshotDirty . xmax ) )
@ -2608,7 +2602,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
HeapTupleHeaderGetCmin ( tuple . t_data ) > = estate - > es_output_cid )
{
ReleaseBuffer ( buffer ) ;
return NULL ;
return false ;
}
/*
@ -2640,7 +2634,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
* now , treat the tuple as deleted and do not process .
*/
ReleaseBuffer ( buffer ) ;
return NULL ;
return false ;
case HeapTupleMayBeUpdated :
/* successfully locked */
@ -2668,11 +2662,11 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
continue ;
}
/* tuple was deleted, so give up */
return NULL ;
return false ;
case HeapTupleWouldBlock :
ReleaseBuffer ( buffer ) ;
return NULL ;
return false ;
case HeapTupleInvisible :
elog ( ERROR , " attempted to lock invisible tuple " ) ;
@ -2682,14 +2676,14 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
ReleaseBuffer ( buffer ) ;
elog ( ERROR , " unrecognized heap_lock_tuple status: %u " ,
test ) ;
return NULL ; /* keep compiler quiet */
return false ; /* keep compiler quiet */
}
/*
* We got tuple - now copy it for use by recheck query .
* We got tuple - store it for use by the recheck query .
*/
copyTuple = heap_copytuple ( & tuple ) ;
ReleaseBuffer ( buffer ) ;
ExecStorePinnedBufferHeapTuple ( & tuple , slot , buffer ) ;
ExecMaterializeSlot ( slot ) ;
break ;
}
@ -2700,7 +2694,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
if ( tuple . t_data = = NULL )
{
ReleaseBuffer ( buffer ) ;
return NULL ;
return false ;
}
/*
@ -2710,7 +2704,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
priorXmax ) )
{
ReleaseBuffer ( buffer ) ;
return NULL ;
return false ;
}
/*
@ -2737,7 +2731,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
{
/* deleted, so forget about it */
ReleaseBuffer ( buffer ) ;
return NULL ;
return false ;
}
/* updated, so look at the updated row */
@ -2748,10 +2742,8 @@ EvalPlanQualFetch(EState *estate, Relation relation, LockTupleMode lockmode,
/* loop back to fetch next in chain */
}
/*
* Return the copied tuple
*/
return copyTuple ;
/* signal success */
return true ;
}
/*
@ -2792,38 +2784,36 @@ EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
}
/*
* Install one test tuple into EPQ state , or clear test tuple if tuple = = NULL
*
* NB : passed tuple must be palloc ' d ; it may get freed later
* Return , and create if necessary , a slot for an EPQ test tuple .
*/
void
EvalPlanQualSetTuple ( EPQState * epqstate , Index rti , HeapTuple tuple )
TupleTableSlot *
EvalPlanQualSlot ( EPQState * epqstate ,
Relation relation , Index rti )
{
EState * estate = epqstate - > estate ;
TupleTableSlot * * slot ;
Assert ( rti > 0 ) ;
Assert ( rti > 0 & & rti < = epqstate - > estate - > es_range_table_size ) ;
slot = & epqstate - > estate - > es_epqTupleSlot [ rti - 1 ] ;
/*
* free old test tuple , if any , and store new tuple where relation ' s scan
* node will see it
*/
if ( estate - > es_epqTuple [ rti - 1 ] ! = NULL )
heap_freetuple ( estate - > es_epqTuple [ rti - 1 ] ) ;
estate - > es_epqTuple [ rti - 1 ] = tuple ;
estate - > es_epqTupleSet [ rti - 1 ] = true ;
}
if ( * slot = = NULL )
{
MemoryContext oldcontext ;
/*
* Fetch back the current test tuple ( if any ) for the specified RTI
*/
HeapTuple
EvalPlanQualGetTuple ( EPQState * epqstate , Index rti )
{
EState * estate = epqstate - > estate ;
oldcontext = MemoryContextSwitchTo ( epqstate - > estate - > es_query_cxt ) ;
Assert ( rti > 0 ) ;
if ( relation )
* slot = ExecAllocTableSlot ( & epqstate - > estate - > es_tupleTable ,
RelationGetDescr ( relation ) ,
& TTSOpsBufferHeapTuple ) ;
else
* slot = ExecAllocTableSlot ( & epqstate - > estate - > es_tupleTable ,
epqstate - > origslot - > tts_tupleDescriptor ,
& TTSOpsVirtual ) ;
MemoryContextSwitchTo ( oldcontext ) ;
}
return estate - > es_epqTuple [ rti - 1 ] ;
return * slot ;
}
/*
@ -2844,13 +2834,14 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
ExecRowMark * erm = aerm - > rowmark ;
Datum datum ;
bool isNull ;
HeapTupleData tuple ;
TupleTableSlot * slot ;
if ( RowMarkRequiresRowShareLock ( erm - > markType ) )
elog ( ERROR , " EvalPlanQual doesn't support locking rowmarks " ) ;
/* clear any leftover test tuple for this rel */
EvalPlanQualSetTuple ( epqstate , erm - > rti , NULL ) ;
slot = EvalPlanQualSlot ( epqstate , erm - > relation , erm - > rti ) ;
ExecClearTuple ( slot ) ;
/* if child rel, must check whether it produced this row */
if ( erm - > rti ! = erm - > prti )
@ -2875,8 +2866,6 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
if ( erm - > markType = = ROW_MARK_REFERENCE )
{
HeapTuple copyTuple ;
Assert ( erm - > relation ! = NULL ) ;
/* fetch the tuple's ctid */
@ -2900,11 +2889,13 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " cannot lock rows in foreign table \" %s \" " ,
RelationGetRelationName ( erm - > relation ) ) ) ) ;
copyTuple = fdwroutine - > RefetchForeignRow ( epqstate - > estate ,
fdwroutine - > RefetchForeignRow ( epqstate - > estate ,
erm ,
datum ,
slot ,
& updated ) ;
if ( copyTuple = = NULL )
if ( TupIsNull ( slot ) )
elog ( ERROR , " failed to fetch tuple for EvalPlanQual recheck " ) ;
/*
@ -2916,6 +2907,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
else
{
/* ordinary table, fetch the tuple */
HeapTupleData tuple ;
Buffer buffer ;
tuple . t_self = * ( ( ItemPointer ) DatumGetPointer ( datum ) ) ;
@ -2923,18 +2915,13 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
false , NULL ) )
elog ( ERROR , " failed to fetch tuple for EvalPlanQual recheck " ) ;
/* successful, copy tuple */
copyTuple = heap_copytuple ( & tuple ) ;
ReleaseBuffer ( buffer ) ;
/* successful, store tuple */
ExecStorePinnedBufferHeapTuple ( & tuple , slot , buffer ) ;
ExecMaterializeSlot ( slot ) ;
}
/* store tuple */
EvalPlanQualSetTuple ( epqstate , erm - > rti , copyTuple ) ;
}
else
{
HeapTupleHeader td ;
Assert ( erm - > markType = = ROW_MARK_COPY ) ;
/* fetch the whole-row Var for the relation */
@ -2944,19 +2931,8 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
/* non-locked rels could be on the inside of outer joins */
if ( isNull )
continue ;
td = DatumGetHeapTupleHeader ( datum ) ;
/* build a temporary HeapTuple control structure */
tuple . t_len = HeapTupleHeaderGetDatumLength ( td ) ;
tuple . t_data = td ;
/* relation might be a foreign table, if so provide tableoid */
tuple . t_tableOid = erm - > relid ;
/* also copy t_ctid in case there's valid data there */
tuple . t_self = td - > t_ctid ;
/* copy and store tuple */
EvalPlanQualSetTuple ( epqstate , erm - > rti ,
heap_copytuple ( & tuple ) ) ;
ExecStoreHeapTupleDatum ( datum , slot ) ;
}
}
}
@ -3152,17 +3128,14 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
* sub - rechecks to inherit the values being examined by an outer recheck .
*/
estate - > es_epqScanDone = ( bool * ) palloc0 ( rtsize * sizeof ( bool ) ) ;
if ( parentestate - > es_epqTuple ! = NULL )
if ( parentestate - > es_epqTupleSlot ! = NULL )
{
estate - > es_epqTuple = parentestate - > es_epqTuple ;
estate - > es_epqTupleSet = parentestate - > es_epqTupleSet ;
estate - > es_epqTupleSlot = parentestate - > es_epqTupleSlot ;
}
else
{
estate - > es_epqTuple = ( HeapTuple * )
palloc0 ( rtsize * sizeof ( HeapTuple ) ) ;
estate - > es_epqTupleSet = ( bool * )
palloc0 ( rtsize * sizeof ( bool ) ) ;
estate - > es_epqTupleSlot = ( TupleTableSlot * * )
palloc0 ( rtsize * sizeof ( TupleTableSlot * ) ) ;
}
/*