@ -7,7 +7,7 @@
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / executor / nodeSubplan . c , v 1.86 2007 / 02 / 22 22 : 00 : 23 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / executor / nodeSubplan . c , v 1.87 2007 / 02 / 27 01 : 11 : 25 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -15,7 +15,6 @@
* INTERFACE ROUTINES
* ExecSubPlan - process a subselect
* ExecInitSubPlan - initialize a subselect
* ExecEndSubPlan - shut down a subselect
*/
# include "postgres.h"
@ -37,7 +36,7 @@ static Datum ExecHashSubPlan(SubPlanState *node,
static Datum ExecScanSubPlan ( SubPlanState * node ,
ExprContext * econtext ,
bool * isNull ) ;
static void buildSubPlanHash ( SubPlanState * node ) ;
static void buildSubPlanHash ( SubPlanState * node , ExprContext * econtext ) ;
static bool findPartialMatch ( TupleHashTable hashtable , TupleTableSlot * slot ) ;
static bool slotAllNulls ( TupleTableSlot * slot ) ;
static bool slotNoNulls ( TupleTableSlot * slot ) ;
@ -91,7 +90,7 @@ ExecHashSubPlan(SubPlanState *node,
* table .
*/
if ( node - > hashtable = = NULL | | planstate - > chgParam ! = NULL )
buildSubPlanHash ( node ) ;
buildSubPlanHash ( node , econtext ) ;
/*
* The result for an empty subplan is always FALSE ; no need to evaluate
@ -219,10 +218,10 @@ ExecScanSubPlan(SubPlanState *node,
/*
* We are probably in a short - lived expression - evaluation context . Switch
* to the child plan ' s per - query context for manipulating it s chgParam ,
* to the per - query context for manipulating the child plan ' s chgParam ,
* calling ExecProcNode on it , etc .
*/
oldcontext = MemoryContextSwitchTo ( node - > sub_estate - > es_query_cxt ) ;
oldcontext = MemoryContextSwitchTo ( econtext - > ecxt_per_query_memory ) ;
/*
* Set Params of this plan from parent plan correlation values . ( Any
@ -299,11 +298,9 @@ ExecScanSubPlan(SubPlanState *node,
* node - > curTuple keeps track of the copied tuple for eventual
* freeing .
*/
MemoryContextSwitchTo ( econtext - > ecxt_per_query_memory ) ;
if ( node - > curTuple )
heap_freetuple ( node - > curTuple ) ;
node - > curTuple = ExecCopySlotTuple ( slot ) ;
MemoryContextSwitchTo ( node - > sub_estate - > es_query_cxt ) ;
result = heap_getattr ( node - > curTuple , 1 , tdesc , isNull ) ;
/* keep scanning subplan to make sure there's only one tuple */
@ -416,7 +413,7 @@ ExecScanSubPlan(SubPlanState *node,
* buildSubPlanHash : load hash table by scanning subplan output .
*/
static void
buildSubPlanHash ( SubPlanState * node )
buildSubPlanHash ( SubPlanState * node , ExprContext * econtext )
{
SubPlan * subplan = ( SubPlan * ) node - > xprstate . expr ;
PlanState * planstate = node - > planstate ;
@ -485,9 +482,9 @@ buildSubPlanHash(SubPlanState *node)
/*
* We are probably in a short - lived expression - evaluation context . Switch
* to the child plan ' s per - query context for calling ExecProcNode .
* to the per - query context for manipulating the child plan .
*/
oldcontext = MemoryContextSwitchTo ( node - > sub_estate - > es_query_cxt ) ;
oldcontext = MemoryContextSwitchTo ( econtext - > ecxt_per_query_memory ) ;
/*
* Reset subplan to start .
@ -628,72 +625,45 @@ slotNoNulls(TupleTableSlot *slot)
/* ----------------------------------------------------------------
* ExecInitSubPlan
*
* Note : the eflags are those passed to the parent plan node of this
* subplan ; they don ' t directly describe the execution conditions the
* subplan will face .
* Create a SubPlanState for a SubPlan ; this is the SubPlan - specific part
* of ExecInitExpr ( ) . We split it out so that it can be used for InitPlans
* as well as regular SubPlans . Note that we don ' t link the SubPlan into
* the parent ' s subPlan list , because that shouldn ' t happen for InitPlans .
* Instead , ExecInitExpr ( ) does that one part .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
ExecInitSubPlan ( SubPlanState * node , EState * estate , int eflags )
SubPlanState *
ExecInitSubPlan ( SubPlan * subplan , PlanState * parent )
{
SubPlan * subplan = ( SubPlan * ) node - > xprstate . expr ;
Plan * plan = exec_subplan_get_plan ( estate - > es_plannedstmt , subplan ) ;
EState * sp_estate ;
SubPlanState * sstate = makeNode ( SubPlanState ) ;
EState * estate = parent - > state ;
/*
* initialize my state
*/
node - > needShutdown = false ;
node - > curTuple = NULL ;
node - > projLeft = NULL ;
node - > projRight = NULL ;
node - > hashtable = NULL ;
node - > hashnulls = NULL ;
node - > tablecxt = NULL ;
node - > innerecontext = NULL ;
node - > keyColIdx = NULL ;
node - > tab_hash_funcs = NULL ;
node - > tab_eq_funcs = NULL ;
node - > lhs_hash_funcs = NULL ;
node - > cur_eq_funcs = NULL ;
sstate - > xprstate . evalfunc = ( ExprStateEvalFunc ) ExecSubPlan ;
sstate - > xprstate . expr = ( Expr * ) subplan ;
/*
* create an EState for the subplan
*
* The subquery needs its own EState because it has its own rangetable . It
* shares our Param ID space and es_query_cxt , however . XXX if rangetable
* access were done differently , the subquery could share our EState ,
* which would eliminate some thrashing about in this module . . .
*
* XXX make that happen !
*/
sp_estate = CreateSubExecutorState ( estate ) ;
node - > sub_estate = sp_estate ;
sp_estate - > es_range_table = estate - > es_range_table ;
sp_estate - > es_param_list_info = estate - > es_param_list_info ;
sp_estate - > es_param_exec_vals = estate - > es_param_exec_vals ;
sp_estate - > es_tupleTable =
ExecCreateTupleTable ( ExecCountSlotsNode ( plan ) + 10 ) ;
sp_estate - > es_snapshot = estate - > es_snapshot ;
sp_estate - > es_crosscheck_snapshot = estate - > es_crosscheck_snapshot ;
sp_estate - > es_instrument = estate - > es_instrument ;
sp_estate - > es_plannedstmt = estate - > es_plannedstmt ;
/* Link the SubPlanState to already-initialized subplan */
sstate - > planstate = ( PlanState * ) list_nth ( estate - > es_subplanstates ,
subplan - > plan_id - 1 ) ;
/* Initialize subexpressions */
sstate - > testexpr = ExecInitExpr ( ( Expr * ) subplan - > testexpr , parent ) ;
sstate - > args = ( List * ) ExecInitExpr ( ( Expr * ) subplan - > args , parent ) ;
/*
* Start up the subplan ( this is a very cut - down form of InitPlan ( ) )
*
* The subplan will never need to do BACKWARD scan or MARK / RESTORE . If it
* is a parameterless subplan ( not initplan ) , we suggest that it be
* prepared to handle REWIND efficiently ; otherwise there is no need .
* initialize my state
*/
eflags & = EXEC_FLAG_EXPLAIN_ONLY ;
if ( subplan - > parParam = = NIL & & subplan - > setParam = = NIL )
eflags | = EXEC_FLAG_REWIND ;
node - > planstate = ExecInitNode ( plan , sp_estate , eflags ) ;
node - > needShutdown = true ; /* now we need to shutdown the subplan */
sstate - > curTuple = NULL ;
sstate - > projLeft = NULL ;
sstate - > projRight = NULL ;
sstate - > hashtable = NULL ;
sstate - > hashnulls = NULL ;
sstate - > tablecxt = NULL ;
sstate - > innerecontext = NULL ;
sstate - > keyColIdx = NULL ;
sstate - > tab_hash_funcs = NULL ;
sstate - > tab_eq_funcs = NULL ;
sstate - > lhs_hash_funcs = NULL ;
sstate - > cur_eq_funcs = NULL ;
/*
* If this plan is un - correlated or undirect correlated one and want to
@ -712,7 +682,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
int paramid = lfirst_int ( lst ) ;
ParamExecData * prm = & ( estate - > es_param_exec_vals [ paramid ] ) ;
prm - > execPlan = nod e;
prm - > execPlan = sstat e;
}
}
@ -735,19 +705,19 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
ListCell * l ;
/* We need a memory context to hold the hash table(s) */
nod e- > tablecxt =
sstat e- > tablecxt =
AllocSetContextCreate ( CurrentMemoryContext ,
" Subplan HashTable Context " ,
ALLOCSET_DEFAULT_MINSIZE ,
ALLOCSET_DEFAULT_INITSIZE ,
ALLOCSET_DEFAULT_MAXSIZE ) ;
/* and a short-lived exprcontext for function evaluation */
nod e- > innerecontext = CreateExprContext ( estate ) ;
sstat e- > innerecontext = CreateExprContext ( estate ) ;
/* Silly little array of column numbers 1..n */
ncols = list_length ( subplan - > paramIds ) ;
nod e- > keyColIdx = ( AttrNumber * ) palloc ( ncols * sizeof ( AttrNumber ) ) ;
sstat e- > keyColIdx = ( AttrNumber * ) palloc ( ncols * sizeof ( AttrNumber ) ) ;
for ( i = 0 ; i < ncols ; i + + )
nod e- > keyColIdx [ i ] = i + 1 ;
sstat e- > keyColIdx [ i ] = i + 1 ;
/*
* We use ExecProject to evaluate the lefthand and righthand
@ -763,32 +733,32 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
* We also extract the combining operators themselves to initialize
* the equality and hashing functions for the hash tables .
*/
if ( IsA ( nod e- > testexpr - > expr , OpExpr ) )
if ( IsA ( sstat e- > testexpr - > expr , OpExpr ) )
{
/* single combining operator */
oplist = list_make1 ( nod e- > testexpr ) ;
oplist = list_make1 ( sstat e- > testexpr ) ;
}
else if ( and_clause ( ( Node * ) nod e- > testexpr - > expr ) )
else if ( and_clause ( ( Node * ) sstat e- > testexpr - > expr ) )
{
/* multiple combining operators */
Assert ( IsA ( nod e- > testexpr , BoolExprState ) ) ;
oplist = ( ( BoolExprState * ) nod e- > testexpr ) - > args ;
Assert ( IsA ( sstat e- > testexpr , BoolExprState ) ) ;
oplist = ( ( BoolExprState * ) sstat e- > testexpr ) - > args ;
}
else
{
/* shouldn't see anything else in a hashable subplan */
elog ( ERROR , " unrecognized testexpr type: %d " ,
( int ) nodeTag ( nod e- > testexpr - > expr ) ) ;
( int ) nodeTag ( sstat e- > testexpr - > expr ) ) ;
oplist = NIL ; /* keep compiler quiet */
}
Assert ( list_length ( oplist ) = = ncols ) ;
lefttlist = righttlist = NIL ;
leftptlist = rightptlist = NIL ;
nod e- > tab_hash_funcs = ( FmgrInfo * ) palloc ( ncols * sizeof ( FmgrInfo ) ) ;
nod e- > tab_eq_funcs = ( FmgrInfo * ) palloc ( ncols * sizeof ( FmgrInfo ) ) ;
nod e- > lhs_hash_funcs = ( FmgrInfo * ) palloc ( ncols * sizeof ( FmgrInfo ) ) ;
nod e- > cur_eq_funcs = ( FmgrInfo * ) palloc ( ncols * sizeof ( FmgrInfo ) ) ;
sstat e- > tab_hash_funcs = ( FmgrInfo * ) palloc ( ncols * sizeof ( FmgrInfo ) ) ;
sstat e- > tab_eq_funcs = ( FmgrInfo * ) palloc ( ncols * sizeof ( FmgrInfo ) ) ;
sstat e- > lhs_hash_funcs = ( FmgrInfo * ) palloc ( ncols * sizeof ( FmgrInfo ) ) ;
sstat e- > cur_eq_funcs = ( FmgrInfo * ) palloc ( ncols * sizeof ( FmgrInfo ) ) ;
i = 1 ;
foreach ( l , oplist )
{
@ -835,23 +805,23 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
rightptlist = lappend ( rightptlist , tle ) ;
/* Lookup the equality function (potentially cross-type) */
fmgr_info ( opexpr - > opfuncid , & nod e- > cur_eq_funcs [ i - 1 ] ) ;
nod e- > cur_eq_funcs [ i - 1 ] . fn_expr = ( Node * ) opexpr ;
fmgr_info ( opexpr - > opfuncid , & sstat e- > cur_eq_funcs [ i - 1 ] ) ;
sstat e- > cur_eq_funcs [ i - 1 ] . fn_expr = ( Node * ) opexpr ;
/* Look up the equality function for the RHS type */
if ( ! get_compatible_hash_operators ( opexpr - > opno ,
NULL , & rhs_eq_oper ) )
elog ( ERROR , " could not find compatible hash operator for operator %u " ,
opexpr - > opno ) ;
fmgr_info ( get_opcode ( rhs_eq_oper ) , & nod e- > tab_eq_funcs [ i - 1 ] ) ;
fmgr_info ( get_opcode ( rhs_eq_oper ) , & sstat e- > tab_eq_funcs [ i - 1 ] ) ;
/* Lookup the associated hash functions */
if ( ! get_op_hash_functions ( opexpr - > opno ,
& left_hashfn , & right_hashfn ) )
elog ( ERROR , " could not find hash function for hash operator %u " ,
opexpr - > opno ) ;
fmgr_info ( left_hashfn , & nod e- > lhs_hash_funcs [ i - 1 ] ) ;
fmgr_info ( right_hashfn , & nod e- > tab_hash_funcs [ i - 1 ] ) ;
fmgr_info ( left_hashfn , & sstat e- > lhs_hash_funcs [ i - 1 ] ) ;
fmgr_info ( right_hashfn , & sstat e- > tab_hash_funcs [ i - 1 ] ) ;
i + + ;
}
@ -876,7 +846,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
tupDesc = ExecTypeFromTL ( leftptlist , false ) ;
slot = ExecAllocTableSlot ( tupTable ) ;
ExecSetSlotDescriptor ( slot , tupDesc ) ;
nod e- > projLeft = ExecBuildProjectionInfo ( lefttlist ,
sstat e- > projLeft = ExecBuildProjectionInfo ( lefttlist ,
NULL ,
slot ,
NULL ) ;
@ -884,11 +854,13 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
tupDesc = ExecTypeFromTL ( rightptlist , false ) ;
slot = ExecAllocTableSlot ( tupTable ) ;
ExecSetSlotDescriptor ( slot , tupDesc ) ;
nod e- > projRight = ExecBuildProjectionInfo ( righttlist ,
nod e- > innerecontext ,
sstat e- > projRight = ExecBuildProjectionInfo ( righttlist ,
sstat e- > innerecontext ,
slot ,
NULL ) ;
}
return sstate ;
}
/* ----------------------------------------------------------------
@ -917,9 +889,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
ArrayBuildState * astate = NULL ;
/*
* Must switch to child query ' s per - query memory context .
* Must switch to per - query memory context .
*/
oldcontext = MemoryContextSwitchTo ( node - > sub_estate - > es_query_cxt ) ;
oldcontext = MemoryContextSwitchTo ( econtext - > ecxt_per_query_memory ) ;
if ( subLinkType = = ANY_SUBLINK | |
subLinkType = = ALL_SUBLINK )
@ -978,11 +950,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
* the param structs will point at this copied tuple ! node - > curTuple
* keeps track of the copied tuple for eventual freeing .
*/
MemoryContextSwitchTo ( econtext - > ecxt_per_query_memory ) ;
if ( node - > curTuple )
heap_freetuple ( node - > curTuple ) ;
node - > curTuple = ExecCopySlotTuple ( slot ) ;
MemoryContextSwitchTo ( node - > sub_estate - > es_query_cxt ) ;
/*
* Now set all the setParam params from the columns of the tuple
@ -1040,23 +1010,6 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
MemoryContextSwitchTo ( oldcontext ) ;
}
/* ----------------------------------------------------------------
* ExecEndSubPlan
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
ExecEndSubPlan ( SubPlanState * node )
{
if ( node - > needShutdown )
{
ExecEndPlan ( node - > planstate , node - > sub_estate ) ;
FreeExecutorState ( node - > sub_estate ) ;
node - > sub_estate = NULL ;
node - > planstate = NULL ;
node - > needShutdown = false ;
}
}
/*
* Mark an initplan as needing recalculation
*/