@ -827,86 +827,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate - > es_plannedstmt = plannedstmt ;
/*
* Initialize ResultRelInfo data structures , and open the result rels .
*/
if ( plannedstmt - > resultRelations )
{
List * resultRelations = plannedstmt - > resultRelations ;
int numResultRelations = list_length ( resultRelations ) ;
ResultRelInfo * resultRelInfos ;
ResultRelInfo * resultRelInfo ;
resultRelInfos = ( ResultRelInfo * )
palloc ( numResultRelations * sizeof ( ResultRelInfo ) ) ;
resultRelInfo = resultRelInfos ;
foreach ( l , resultRelations )
{
Index resultRelationIndex = lfirst_int ( l ) ;
Relation resultRelation ;
resultRelation = ExecGetRangeTableRelation ( estate ,
resultRelationIndex ) ;
InitResultRelInfo ( resultRelInfo ,
resultRelation ,
resultRelationIndex ,
NULL ,
estate - > es_instrument ) ;
resultRelInfo + + ;
}
estate - > es_result_relations = resultRelInfos ;
estate - > es_num_result_relations = numResultRelations ;
/* es_result_relation_info is NULL except when within ModifyTable */
estate - > es_result_relation_info = NULL ;
/*
* In the partitioned result relation case , also build ResultRelInfos
* for all the partitioned table roots , because we will need them to
* fire statement - level triggers , if any .
*/
if ( plannedstmt - > rootResultRelations )
{
int num_roots = list_length ( plannedstmt - > rootResultRelations ) ;
resultRelInfos = ( ResultRelInfo * )
palloc ( num_roots * sizeof ( ResultRelInfo ) ) ;
resultRelInfo = resultRelInfos ;
foreach ( l , plannedstmt - > rootResultRelations )
{
Index resultRelIndex = lfirst_int ( l ) ;
Relation resultRelDesc ;
resultRelDesc = ExecGetRangeTableRelation ( estate ,
resultRelIndex ) ;
InitResultRelInfo ( resultRelInfo ,
resultRelDesc ,
resultRelIndex ,
NULL ,
estate - > es_instrument ) ;
resultRelInfo + + ;
}
estate - > es_root_result_relations = resultRelInfos ;
estate - > es_num_root_result_relations = num_roots ;
}
else
{
estate - > es_root_result_relations = NULL ;
estate - > es_num_root_result_relations = 0 ;
}
}
else
{
/*
* if no result relation , then set state appropriately
*/
estate - > es_result_relations = NULL ;
estate - > es_num_result_relations = 0 ;
estate - > es_result_relation_info = NULL ;
estate - > es_root_result_relations = NULL ;
estate - > es_num_root_result_relations = 0 ;
}
/* es_result_relation_info is NULL except when within ModifyTable */
estate - > es_result_relation_info = NULL ;
/*
* Next , build the ExecRowMark array from the PlanRowMark ( s ) , if any .
@ -1334,8 +1256,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
*
* Most of the time , triggers are fired on one of the result relations of the
* query , and so we can just return a member of the es_result_relations array ,
* or the es_root_result_relations array ( if any ) , or the
* es_tuple_routing_result_relations list ( if any ) . ( Note : in self - join
* or the es_tuple_routing_result_relations list ( if any ) . ( Note : in self - join
* situations there might be multiple members with the same OID ; if so it
* doesn ' t matter which one we pick . )
*
@ -1352,30 +1273,16 @@ ResultRelInfo *
ExecGetTriggerResultRel ( EState * estate , Oid relid )
{
ResultRelInfo * rInfo ;
int nr ;
ListCell * l ;
Relation rel ;
MemoryContext oldcontext ;
/* First, search through the query result relations */
rInfo = estate - > es_result_relations ;
nr = estate - > es_num_result_relations ;
while ( nr > 0 )
foreach ( l , estate - > es_opened_result_relations )
{
rInfo = lfirst ( l ) ;
if ( RelationGetRelid ( rInfo - > ri_RelationDesc ) = = relid )
return rInfo ;
rInfo + + ;
nr - - ;
}
/* Second, search through the root result relations, if any */
rInfo = estate - > es_root_result_relations ;
nr = estate - > es_num_root_result_relations ;
while ( nr > 0 )
{
if ( RelationGetRelid ( rInfo - > ri_RelationDesc ) = = relid )
return rInfo ;
rInfo + + ;
nr - - ;
}
/*
@ -1428,35 +1335,6 @@ ExecGetTriggerResultRel(EState *estate, Oid relid)
return rInfo ;
}
/*
* Close any relations that have been opened by ExecGetTriggerResultRel ( ) .
*/
void
ExecCleanUpTriggerState ( EState * estate )
{
ListCell * l ;
foreach ( l , estate - > es_trig_target_relations )
{
ResultRelInfo * resultRelInfo = ( ResultRelInfo * ) lfirst ( l ) ;
/*
* Assert this is a " dummy " ResultRelInfo , see above . Otherwise we
* might be issuing a duplicate close against a Relation opened by
* ExecGetRangeTableRelation .
*/
Assert ( resultRelInfo - > ri_RangeTableIndex = = 0 ) ;
/*
* Since ExecGetTriggerResultRel doesn ' t call ExecOpenIndices for
* these rels , we needn ' t call ExecCloseIndices either .
*/
Assert ( resultRelInfo - > ri_NumIndices = = 0 ) ;
table_close ( resultRelInfo - > ri_RelationDesc , NoLock ) ;
}
}
/* ----------------------------------------------------------------
* ExecPostprocessPlan
*
@ -1512,9 +1390,6 @@ ExecPostprocessPlan(EState *estate)
static void
ExecEndPlan ( PlanState * planstate , EState * estate )
{
ResultRelInfo * resultRelInfo ;
Index num_relations ;
Index i ;
ListCell * l ;
/*
@ -1541,29 +1416,69 @@ ExecEndPlan(PlanState *planstate, EState *estate)
ExecResetTupleTable ( estate - > es_tupleTable , false ) ;
/*
* close indexes of result relation ( s ) if any . ( Rels themselves get
* closed next . )
* Close any Relations that have been opened for range table entries or
* result relations .
*/
resultRelInfo = estate - > es_result_relations ;
for ( i = estate - > es_num_result_relations ; i > 0 ; i - - )
ExecCloseResultRelations ( estate ) ;
ExecCloseRangeTableRelations ( estate ) ;
}
/*
* Close any relations that have been opened for ResultRelInfos .
*/
void
ExecCloseResultRelations ( EState * estate )
{
ListCell * l ;
/*
* close indexes of result relation ( s ) if any . ( Rels themselves are
* closed in ExecCloseRangeTableRelations ( ) )
*/
foreach ( l , estate - > es_opened_result_relations )
{
ResultRelInfo * resultRelInfo = lfirst ( l ) ;
ExecCloseIndices ( resultRelInfo ) ;
resultRelInfo + + ;
}
/*
* close whatever rangetable Relations have been opened . We do not
* release any locks we might hold on those rels .
*/
num_relations = estate - > es_range_table_size ;
for ( i = 0 ; i < num_relations ; i + + )
/* Close any relations that have been opened by ExecGetTriggerResultRel(). */
foreach ( l , estate - > es_trig_target_relations )
{
ResultRelInfo * resultRelInfo = ( ResultRelInfo * ) lfirst ( l ) ;
/*
* Assert this is a " dummy " ResultRelInfo , see above . Otherwise we
* might be issuing a duplicate close against a Relation opened by
* ExecGetRangeTableRelation .
*/
Assert ( resultRelInfo - > ri_RangeTableIndex = = 0 ) ;
/*
* Since ExecGetTriggerResultRel doesn ' t call ExecOpenIndices for
* these rels , we needn ' t call ExecCloseIndices either .
*/
Assert ( resultRelInfo - > ri_NumIndices = = 0 ) ;
table_close ( resultRelInfo - > ri_RelationDesc , NoLock ) ;
}
}
/*
* Close all relations opened by ExecGetRangeTableRelation ( ) .
*
* We do not release any locks we might hold on those rels .
*/
void
ExecCloseRangeTableRelations ( EState * estate )
{
int i ;
for ( i = 0 ; i < estate - > es_range_table_size ; i + + )
{
if ( estate - > es_relations [ i ] )
table_close ( estate - > es_relations [ i ] , NoLock ) ;
}
/* likewise close any trigger target relations */
ExecCleanUpTriggerState ( estate ) ;
}
/* ----------------------------------------------------------------
@ -2758,17 +2673,9 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
/*
* Child EPQ EStates share the parent ' s copy of unchanging state such as
* the snapshot , rangetable , result - rel info , and external Param info .
* They need their own copies of local state , including a tuple table ,
* es_param_exec_vals , etc .
*
* The ResultRelInfo array management is trickier than it looks . We
* create fresh arrays for the child but copy all the content from the
* parent . This is because it ' s okay for the child to share any
* per - relation state the parent has already created - - - but if the child
* sets up any ResultRelInfo fields , such as its own junkfilter , that
* state must * not * propagate back to the parent . ( For one thing , the
* pointed - to data is in a memory context that won ' t last long enough . )
* the snapshot , rangetable , and external Param info . They need their own
* copies of local state , including a tuple table , es_param_exec_vals ,
* result - rel info , etc .
*/
rcestate - > es_direction = ForwardScanDirection ;
rcestate - > es_snapshot = parentestate - > es_snapshot ;
@ -2781,30 +2688,12 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
rcestate - > es_plannedstmt = parentestate - > es_plannedstmt ;
rcestate - > es_junkFilter = parentestate - > es_junkFilter ;
rcestate - > es_output_cid = parentestate - > es_output_cid ;
if ( parentestate - > es_num_result_relations > 0 )
{
int numResultRelations = parentestate - > es_num_result_relations ;
int numRootResultRels = parentestate - > es_num_root_result_relations ;
ResultRelInfo * resultRelInfos ;
resultRelInfos = ( ResultRelInfo * )
palloc ( numResultRelations * sizeof ( ResultRelInfo ) ) ;
memcpy ( resultRelInfos , parentestate - > es_result_relations ,
numResultRelations * sizeof ( ResultRelInfo ) ) ;
rcestate - > es_result_relations = resultRelInfos ;
rcestate - > es_num_result_relations = numResultRelations ;
/* Also transfer partitioned root result relations. */
if ( numRootResultRels > 0 )
{
resultRelInfos = ( ResultRelInfo * )
palloc ( numRootResultRels * sizeof ( ResultRelInfo ) ) ;
memcpy ( resultRelInfos , parentestate - > es_root_result_relations ,
numRootResultRels * sizeof ( ResultRelInfo ) ) ;
rcestate - > es_root_result_relations = resultRelInfos ;
rcestate - > es_num_root_result_relations = numRootResultRels ;
}
}
/*
* ResultRelInfos needed by subplans are initialized from scratch when the
* subplans themselves are initialized .
*/
parentestate - > es_result_relations = NULL ;
/* es_result_relation_info must NOT be copied */
/* es_trig_target_relations must NOT be copied */
rcestate - > es_top_eflags = parentestate - > es_top_eflags ;
@ -2914,8 +2803,9 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
* This is a cut - down version of ExecutorEnd ( ) ; basically we want to do most
* of the normal cleanup , but * not * close result relations ( which we are
* just sharing from the outer query ) . We do , however , have to close any
* trigger target relations that got opened , since those are not shared .
* ( There probably shouldn ' t be any of the latter , but just in case . . . )
* result and trigger target relations that got opened , since those are not
* shared . ( There probably shouldn ' t be any of the latter , but just in
* case . . . )
*/
void
EvalPlanQualEnd ( EPQState * epqstate )
@ -2957,8 +2847,8 @@ EvalPlanQualEnd(EPQState *epqstate)
/* throw away the per-estate tuple table, some node may have used it */
ExecResetTupleTable ( estate - > es_tupleTable , false ) ;
/* close any trigger target relations attached to this EState */
ExecCleanUpTriggerState ( estate ) ;
/* Close any result and trigger target relations attached to this EState */
ExecCloseResultRelations ( estate ) ;
MemoryContextSwitchTo ( oldcontext ) ;