Make further use of new bitmapset code: executor's chgParam, extParam,

locParam lists can be converted to bitmapsets to speed updating.  Also,
replace 'locParam' with 'allParam', which contains all the paramIDs
relevant to the node (i.e., the union of extParam and locParam); this
saves a step during SetChangedParamList() without costing anything
elsewhere.
This commit is contained in:
Tom Lane 2003-02-09 00:30:41 +00:00
parent c15a4c2aef
commit 145014f811
17 changed files with 267 additions and 193 deletions

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.68 2002/12/14 00:17:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.69 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -55,7 +55,7 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
InstrEndLoop(node->instrument); InstrEndLoop(node->instrument);
/* If we have changed parameters, propagate that info */ /* If we have changed parameters, propagate that info */
if (node->chgParam != NIL) if (node->chgParam != NULL)
{ {
List *lst; List *lst;
@ -64,10 +64,10 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
SubPlanState *sstate = (SubPlanState *) lfirst(lst); SubPlanState *sstate = (SubPlanState *) lfirst(lst);
PlanState *splan = sstate->planstate; PlanState *splan = sstate->planstate;
if (splan->plan->extParam != NIL) /* don't care about child if (splan->plan->extParam != NULL) /* don't care about child
* locParam */ * local Params */
SetChangedParamList(splan, node->chgParam); UpdateChangedParamSet(splan, node->chgParam);
if (splan->chgParam != NIL) if (splan->chgParam != NULL)
ExecReScanSetParamPlan(sstate, node); ExecReScanSetParamPlan(sstate, node);
} }
foreach(lst, node->subPlan) foreach(lst, node->subPlan)
@ -75,14 +75,14 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
SubPlanState *sstate = (SubPlanState *) lfirst(lst); SubPlanState *sstate = (SubPlanState *) lfirst(lst);
PlanState *splan = sstate->planstate; PlanState *splan = sstate->planstate;
if (splan->plan->extParam != NIL) if (splan->plan->extParam != NULL)
SetChangedParamList(splan, node->chgParam); UpdateChangedParamSet(splan, node->chgParam);
} }
/* Well. Now set chgParam for left/right trees. */ /* Well. Now set chgParam for left/right trees. */
if (node->lefttree != NULL) if (node->lefttree != NULL)
SetChangedParamList(node->lefttree, node->chgParam); UpdateChangedParamSet(node->lefttree, node->chgParam);
if (node->righttree != NULL) if (node->righttree != NULL)
SetChangedParamList(node->righttree, node->chgParam); UpdateChangedParamSet(node->righttree, node->chgParam);
} }
switch (nodeTag(node)) switch (nodeTag(node))
@ -165,10 +165,10 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
return; return;
} }
if (node->chgParam != NIL) if (node->chgParam != NULL)
{ {
freeList(node->chgParam); bms_free(node->chgParam);
node->chgParam = NIL; node->chgParam = NULL;
} }
} }

View File

@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.34 2002/12/14 00:17:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.35 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -282,7 +282,7 @@ ExecProcNode(PlanState *node)
if (node == NULL) if (node == NULL)
return NULL; return NULL;
if (node->chgParam != NIL) /* something changed */ if (node->chgParam != NULL) /* something changed */
ExecReScan(node, NULL); /* let ReScan handle this */ ExecReScan(node, NULL); /* let ReScan handle this */
if (node->instrument) if (node->instrument)
@ -504,10 +504,10 @@ ExecEndNode(PlanState *node)
foreach(subp, node->subPlan) foreach(subp, node->subPlan)
ExecEndSubPlan((SubPlanState *) lfirst(subp)); ExecEndSubPlan((SubPlanState *) lfirst(subp));
if (node->chgParam != NIL) if (node->chgParam != NULL)
{ {
freeList(node->chgParam); bms_free(node->chgParam);
node->chgParam = NIL; node->chgParam = NULL;
} }
switch (nodeTag(node)) switch (nodeTag(node))

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.96 2003/01/23 05:10:39 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.97 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -874,25 +874,28 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
} }
} }
/*
* UpdateChangedParamSet
* Add changed parameters to a plan node's chgParam set
*/
void void
SetChangedParamList(PlanState *node, List *newchg) UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
{ {
List *nl; Bitmapset *parmset;
foreach(nl, newchg) /*
{ * The plan node only depends on params listed in its allParam set.
int paramId = lfirsti(nl); * Don't include anything else into its chgParam set.
*/
/* if this node doesn't depend on a param ... */ parmset = bms_intersect(node->plan->allParam, newchg);
if (!intMember(paramId, node->plan->extParam) && /*
!intMember(paramId, node->plan->locParam)) * Keep node->chgParam == NULL if there's not actually any members;
continue; * this allows the simplest possible tests in executor node files.
/* if this param is already in list of changed ones ... */ */
if (intMember(paramId, node->chgParam)) if (!bms_is_empty(parmset))
continue; node->chgParam = bms_join(node->chgParam, parmset);
/* else - add this param to the list */ else
node->chgParam = lappendi(node->chgParam, paramId); bms_free(parmset);
}
} }
/* /*

View File

@ -45,7 +45,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/nodeAgg.c,v 1.103 2003/02/04 00:48:23 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.104 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1405,7 +1405,7 @@ ExecReScanAgg(AggState *node, ExprContext *exprCtxt)
* if chgParam of subnode is not null then plan will be re-scanned by * if chgParam of subnode is not null then plan will be re-scanned by
* first ExecProcNode. * first ExecProcNode.
*/ */
if (((PlanState *) node)->lefttree->chgParam == NIL) if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt); ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.51 2002/12/05 15:50:33 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.52 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -361,14 +361,14 @@ ExecReScanAppend(AppendState *node, ExprContext *exprCtxt)
* ExecReScan doesn't know about my subplans, so I have to do * ExecReScan doesn't know about my subplans, so I have to do
* changed-parameter signaling myself. * changed-parameter signaling myself.
*/ */
if (node->ps.chgParam != NIL) if (node->ps.chgParam != NULL)
SetChangedParamList(subnode, node->ps.chgParam); UpdateChangedParamSet(subnode, node->ps.chgParam);
/* /*
* if chgParam of subnode is not null then plan will be re-scanned * if chgParam of subnode is not null then plan will be re-scanned
* by first ExecProcNode. * by first ExecProcNode.
*/ */
if (subnode->chgParam == NIL) if (subnode->chgParam == NULL)
{ {
/* make sure estate is correct for this subnode (needed??) */ /* make sure estate is correct for this subnode (needed??) */
node->as_whichplan = i; node->as_whichplan = i;

View File

@ -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.43 2003/01/12 04:03:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.44 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -80,7 +80,7 @@ ExecHashSubPlan(SubPlanState *node,
* If first time through or we need to rescan the subplan, build * If first time through or we need to rescan the subplan, build
* the hash table. * the hash table.
*/ */
if (node->hashtable == NULL || planstate->chgParam != NIL) if (node->hashtable == NULL || planstate->chgParam != NULL)
buildSubPlanHash(node); buildSubPlanHash(node);
/* /*
@ -218,22 +218,18 @@ ExecScanSubPlan(SubPlanState *node,
* Set Params of this plan from parent plan correlation Vars * Set Params of this plan from parent plan correlation Vars
*/ */
pvar = node->args; pvar = node->args;
if (subplan->parParam != NIL) foreach(lst, subplan->parParam)
{ {
foreach(lst, subplan->parParam) int paramid = lfirsti(lst);
{ ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
ParamExecData *prm;
prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]); Assert(pvar != NIL);
Assert(pvar != NIL); prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar), econtext,
econtext, &(prm->isnull),
&(prm->isnull), NULL);
NULL); pvar = lnext(pvar);
pvar = lnext(pvar); planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
}
planstate->chgParam = nconc(planstate->chgParam,
listCopy(subplan->parParam));
} }
Assert(pvar == NIL); Assert(pvar == NIL);
@ -686,7 +682,12 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
/* /*
* If this plan is un-correlated or undirect correlated one and want * If this plan is un-correlated or undirect correlated one and want
* to set params for parent plan then prepare parameters. * to set params for parent plan then mark parameters as needing
* evaluation.
*
* Note that in the case of un-correlated subqueries we don't care
* about setting parent->chgParam here: indices take care about
* it, for others - it doesn't matter...
*/ */
if (subplan->setParam != NIL) if (subplan->setParam != NIL)
{ {
@ -694,16 +695,11 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
foreach(lst, subplan->setParam) foreach(lst, subplan->setParam)
{ {
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]); int paramid = lfirsti(lst);
ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
prm->execPlan = node; prm->execPlan = node;
} }
/*
* Note that in the case of un-correlated subqueries we don't care
* about setting parent->chgParam here: indices take care about
* it, for others - it doesn't matter...
*/
} }
/* /*
@ -884,7 +880,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
if (subLinkType == EXISTS_SUBLINK) if (subLinkType == EXISTS_SUBLINK)
{ {
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(subplan->setParam)]); /* There can be only one param... */
int paramid = lfirsti(subplan->setParam);
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
prm->execPlan = NULL; prm->execPlan = NULL;
prm->value = BoolGetDatum(true); prm->value = BoolGetDatum(true);
@ -914,9 +912,13 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
node->curTuple = tup; node->curTuple = tup;
MemoryContextSwitchTo(node->sub_estate->es_query_cxt); MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
/*
* Now set all the setParam params from the columns of the tuple
*/
foreach(lst, subplan->setParam) foreach(lst, subplan->setParam)
{ {
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]); int paramid = lfirsti(lst);
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
prm->execPlan = NULL; prm->execPlan = NULL;
prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull)); prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
@ -928,7 +930,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
{ {
if (subLinkType == EXISTS_SUBLINK) if (subLinkType == EXISTS_SUBLINK)
{ {
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(subplan->setParam)]); /* There can be only one param... */
int paramid = lfirsti(subplan->setParam);
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
prm->execPlan = NULL; prm->execPlan = NULL;
prm->value = BoolGetDatum(false); prm->value = BoolGetDatum(false);
@ -938,7 +942,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
{ {
foreach(lst, subplan->setParam) foreach(lst, subplan->setParam)
{ {
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]); int paramid = lfirsti(lst);
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
prm->execPlan = NULL; prm->execPlan = NULL;
prm->value = (Datum) 0; prm->value = (Datum) 0;
@ -979,12 +984,12 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
EState *estate = parent->state; EState *estate = parent->state;
List *lst; List *lst;
if (subplan->parParam != NULL) if (subplan->parParam != NIL)
elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet"); elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
if (subplan->setParam == NULL) if (subplan->setParam == NIL)
elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL"); elog(ERROR, "ExecReScanSetParamPlan: setParam list is empty");
if (planstate->plan->extParam == NULL) if (bms_is_empty(planstate->plan->extParam))
elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL"); elog(ERROR, "ExecReScanSetParamPlan: extParam set of plan is empty");
/* /*
* Don't actually re-scan: ExecSetParamPlan does it if needed. * Don't actually re-scan: ExecSetParamPlan does it if needed.
@ -995,10 +1000,10 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
*/ */
foreach(lst, subplan->setParam) foreach(lst, subplan->setParam)
{ {
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]); int paramid = lfirsti(lst);
ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
prm->execPlan = node; prm->execPlan = node;
parent->chgParam = bms_add_member(parent->chgParam, paramid);
} }
parent->chgParam = nconc(parent->chgParam, listCopy(subplan->setParam));
} }

View File

@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.17 2003/01/12 22:01:38 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.18 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -261,10 +261,10 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
* ExecReScan doesn't know about my subplan, so I have to do * ExecReScan doesn't know about my subplan, so I have to do
* changed-parameter signaling myself. This is just as well, * changed-parameter signaling myself. This is just as well,
* because the subplan has its own memory context in which its * because the subplan has its own memory context in which its
* chgParam lists live. * chgParam state lives.
*/ */
if (node->ss.ps.chgParam != NULL) if (node->ss.ps.chgParam != NULL)
SetChangedParamList(node->subplan, node->ss.ps.chgParam); UpdateChangedParamSet(node->subplan, node->ss.ps.chgParam);
/* /*
* if chgParam of subnode is not null then plan will be re-scanned by * if chgParam of subnode is not null then plan will be re-scanned by

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.32 2003/02/03 15:07:07 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.33 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -349,7 +349,7 @@ ExecInitTidScan(TidScan *node, EState *estate)
Oid relid; Oid relid;
Oid reloid; Oid reloid;
Relation currentRelation; Relation currentRelation;
List *execParam = NIL; Bitmapset *execParam = NULL;
/* /*
* create state structure * create state structure

View File

@ -15,7 +15,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/nodes/copyfuncs.c,v 1.240 2003/02/08 20:20:53 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.241 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -120,8 +120,8 @@ CopyPlanFields(Plan *from, Plan *newnode)
COPY_NODE_FIELD(lefttree); COPY_NODE_FIELD(lefttree);
COPY_NODE_FIELD(righttree); COPY_NODE_FIELD(righttree);
COPY_NODE_FIELD(initPlan); COPY_NODE_FIELD(initPlan);
COPY_INTLIST_FIELD(extParam); COPY_BITMAPSET_FIELD(extParam);
COPY_INTLIST_FIELD(locParam); COPY_BITMAPSET_FIELD(allParam);
COPY_SCALAR_FIELD(nParamExec); COPY_SCALAR_FIELD(nParamExec);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.196 2003/02/08 20:20:54 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.197 2003/02/09 00:30:39 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
@ -255,8 +255,8 @@ _outPlanInfo(StringInfo str, Plan *node)
WRITE_NODE_FIELD(lefttree); WRITE_NODE_FIELD(lefttree);
WRITE_NODE_FIELD(righttree); WRITE_NODE_FIELD(righttree);
WRITE_NODE_FIELD(initPlan); WRITE_NODE_FIELD(initPlan);
WRITE_INTLIST_FIELD(extParam); WRITE_BITMAPSET_FIELD(extParam);
WRITE_INTLIST_FIELD(locParam); WRITE_BITMAPSET_FIELD(allParam);
WRITE_INT_FIELD(nParamExec); WRITE_INT_FIELD(nParamExec);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.144 2003/02/04 00:50:00 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.145 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -268,14 +268,14 @@ subquery_planner(Query *parse, double tuple_fraction)
/* /*
* If any subplans were generated, or if we're inside a subplan, build * If any subplans were generated, or if we're inside a subplan, build
* initPlan, extParam and locParam lists for plan nodes. * initPlan list and extParam/allParam sets for plan nodes.
*/ */
if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1) if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1)
{ {
Cost initplan_cost = 0; Cost initplan_cost = 0;
/* Prepare extParam/locParam data for all nodes in tree */ /* Prepare extParam/allParam sets for all nodes in tree */
(void) SS_finalize_plan(plan, parse->rtable); SS_finalize_plan(plan, parse->rtable);
/* /*
* SS_finalize_plan doesn't handle initPlans, so we have to manually * SS_finalize_plan doesn't handle initPlans, so we have to manually
@ -293,8 +293,8 @@ subquery_planner(Query *parse, double tuple_fraction)
{ {
SubPlan *initplan = (SubPlan *) lfirst(lst); SubPlan *initplan = (SubPlan *) lfirst(lst);
plan->extParam = set_unioni(plan->extParam, plan->extParam = bms_add_members(plan->extParam,
initplan->plan->extParam); initplan->plan->extParam);
initplan_cost += initplan->plan->total_cost; initplan_cost += initplan->plan->total_cost;
} }

View File

@ -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/optimizer/plan/subselect.c,v 1.70 2003/02/08 20:20:54 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.71 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -57,10 +57,11 @@ int PlannerPlanId = 0; /* to assign unique ID to subquery plans */
*/ */
typedef struct finalize_primnode_results typedef struct finalize_primnode_context
{ {
List *paramids; /* List of PARAM_EXEC paramids found */ Bitmapset *paramids; /* Set of PARAM_EXEC paramids found */
} finalize_primnode_results; Bitmapset *outer_params; /* Set of accessible outer paramids */
} finalize_primnode_context;
static List *convert_sublink_opers(List *lefthand, List *operOids, static List *convert_sublink_opers(List *lefthand, List *operOids,
@ -69,7 +70,10 @@ static List *convert_sublink_opers(List *lefthand, List *operOids,
static bool subplan_is_hashable(SubLink *slink, SubPlan *node); static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
static Node *replace_correlation_vars_mutator(Node *node, void *context); static Node *replace_correlation_vars_mutator(Node *node, void *context);
static Node *process_sublinks_mutator(Node *node, bool *isTopQual); static Node *process_sublinks_mutator(Node *node, bool *isTopQual);
static bool finalize_primnode(Node *node, finalize_primnode_results *results); static Bitmapset *finalize_plan(Plan *plan, List *rtable,
Bitmapset *outer_params,
Bitmapset *valid_params);
static bool finalize_primnode(Node *node, finalize_primnode_context *context);
/* /*
@ -178,6 +182,8 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
Query *subquery = (Query *) (slink->subselect); Query *subquery = (Query *) (slink->subselect);
double tuple_fraction; double tuple_fraction;
Plan *plan; Plan *plan;
Bitmapset *tmpset;
int paramid;
List *lst; List *lst;
Node *result; Node *result;
@ -246,15 +252,16 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
* Make parParam list of params that current query level will pass to * Make parParam list of params that current query level will pass to
* this child plan. * this child plan.
*/ */
foreach(lst, plan->extParam) tmpset = bms_copy(plan->extParam);
while ((paramid = bms_first_member(tmpset)) >= 0)
{ {
int paramid = lfirsti(lst);
Var *var = nth(paramid, PlannerParamVar); Var *var = nth(paramid, PlannerParamVar);
/* note varlevelsup is absolute level number */ /* note varlevelsup is absolute level number */
if (var->varlevelsup == PlannerQueryLevel) if (var->varlevelsup == PlannerQueryLevel)
node->parParam = lappendi(node->parParam, paramid); node->parParam = lappendi(node->parParam, paramid);
} }
bms_free(tmpset);
/* /*
* Un-correlated or undirect correlated plans of EXISTS, EXPR, or * Un-correlated or undirect correlated plans of EXISTS, EXPR, or
@ -269,7 +276,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
Param *prm; Param *prm;
prm = generate_new_param(BOOLOID, -1); prm = generate_new_param(BOOLOID, -1);
node->setParam = lappendi(node->setParam, prm->paramid); node->setParam = makeListi1(prm->paramid);
PlannerInitPlan = lappend(PlannerInitPlan, node); PlannerInitPlan = lappend(PlannerInitPlan, node);
result = (Node *) prm; result = (Node *) prm;
} }
@ -280,7 +287,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
Assert(!te->resdom->resjunk); Assert(!te->resdom->resjunk);
prm = generate_new_param(te->resdom->restype, te->resdom->restypmod); prm = generate_new_param(te->resdom->restype, te->resdom->restypmod);
node->setParam = lappendi(node->setParam, prm->paramid); node->setParam = makeListi1(prm->paramid);
PlannerInitPlan = lappend(PlannerInitPlan, node); PlannerInitPlan = lappend(PlannerInitPlan, node);
result = (Node *) prm; result = (Node *) prm;
} }
@ -294,7 +301,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
plan->targetlist, plan->targetlist,
0, 0,
&node->paramIds); &node->paramIds);
node->setParam = nconc(node->setParam, listCopy(node->paramIds)); node->setParam = listCopy(node->paramIds);
PlannerInitPlan = lappend(PlannerInitPlan, node); PlannerInitPlan = lappend(PlannerInitPlan, node);
/* /*
* The executable expressions are returned to become part of the * The executable expressions are returned to become part of the
@ -387,8 +394,8 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
matplan->plan_rows = plan->plan_rows; matplan->plan_rows = plan->plan_rows;
matplan->plan_width = plan->plan_width; matplan->plan_width = plan->plan_width;
/* parameter kluge --- see comments above */ /* parameter kluge --- see comments above */
matplan->extParam = listCopy(plan->extParam); matplan->extParam = bms_copy(plan->extParam);
matplan->locParam = listCopy(plan->locParam); matplan->allParam = bms_copy(plan->allParam);
node->plan = plan = matplan; node->plan = plan = matplan;
} }
} }
@ -769,44 +776,94 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
/* /*
* SS_finalize_plan - do final sublink processing for a completed Plan. * SS_finalize_plan - do final sublink processing for a completed Plan.
* *
* This recursively computes and sets the extParam and locParam lists * This recursively computes the extParam and allParam sets
* for every Plan node in the given tree. * for every Plan node in the given plan tree.
*/ */
List * void
SS_finalize_plan(Plan *plan, List *rtable) SS_finalize_plan(Plan *plan, List *rtable)
{ {
List *extParam = NIL; Bitmapset *outer_params = NULL;
List *locParam = NIL; Bitmapset *valid_params = NULL;
finalize_primnode_results results; int paramid;
List *lst;
/*
* First, scan the param list to discover the sets of params that
* are available from outer query levels and my own query level.
* We do this once to save time in the per-plan recursion steps.
*/
paramid = 0;
foreach(lst, PlannerParamVar)
{
Var *var = (Var *) lfirst(lst);
/* note varlevelsup is absolute level number */
if (var->varlevelsup < PlannerQueryLevel)
{
/* valid outer-level parameter */
outer_params = bms_add_member(outer_params, paramid);
valid_params = bms_add_member(valid_params, paramid);
}
else if (var->varlevelsup == PlannerQueryLevel &&
var->varno == 0 && var->varattno == 0)
{
/* valid local parameter (i.e., a setParam of my child) */
valid_params = bms_add_member(valid_params, paramid);
}
paramid++;
}
/*
* Now recurse through plan tree.
*/
(void) finalize_plan(plan, rtable, outer_params, valid_params);
bms_free(outer_params);
bms_free(valid_params);
}
/*
* Recursive processing of all nodes in the plan tree
*
* The return value is the computed allParam set for the given Plan node.
* This is just an internal notational convenience.
*/
static Bitmapset *
finalize_plan(Plan *plan, List *rtable,
Bitmapset *outer_params, Bitmapset *valid_params)
{
finalize_primnode_context context;
List *lst; List *lst;
if (plan == NULL) if (plan == NULL)
return NIL; return NULL;
results.paramids = NIL; /* initialize list to NIL */ context.paramids = NULL; /* initialize set to empty */
context.outer_params = outer_params;
/* /*
* When we call finalize_primnode, results.paramids lists are * When we call finalize_primnode, context.paramids sets are
* automatically merged together. But when recursing to self, we have * automatically merged together. But when recursing to self, we have
* to do it the hard way. We want the paramids list to include params * to do it the hard way. We want the paramids set to include params
* in subplans as well as at this level. * in subplans as well as at this level.
*/ */
/* Find params in targetlist and qual */ /* Find params in targetlist and qual */
finalize_primnode((Node *) plan->targetlist, &results); finalize_primnode((Node *) plan->targetlist, &context);
finalize_primnode((Node *) plan->qual, &results); finalize_primnode((Node *) plan->qual, &context);
/* Check additional node-type-specific fields */ /* Check additional node-type-specific fields */
switch (nodeTag(plan)) switch (nodeTag(plan))
{ {
case T_Result: case T_Result:
finalize_primnode(((Result *) plan)->resconstantqual, finalize_primnode(((Result *) plan)->resconstantqual,
&results); &context);
break; break;
case T_IndexScan: case T_IndexScan:
finalize_primnode((Node *) ((IndexScan *) plan)->indxqual, finalize_primnode((Node *) ((IndexScan *) plan)->indxqual,
&results); &context);
/* /*
* we need not look at indxqualorig, since it will have the * we need not look at indxqualorig, since it will have the
@ -816,7 +873,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
case T_TidScan: case T_TidScan:
finalize_primnode((Node *) ((TidScan *) plan)->tideval, finalize_primnode((Node *) ((TidScan *) plan)->tideval,
&results); &context);
break; break;
case T_SubqueryScan: case T_SubqueryScan:
@ -828,7 +885,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
* subplan's extParams list, which represents the params it * subplan's extParams list, which represents the params it
* needs from my level and higher levels. * needs from my level and higher levels.
*/ */
results.paramids = set_unioni(results.paramids, context.paramids = bms_add_members(context.paramids,
((SubqueryScan *) plan)->subplan->extParam); ((SubqueryScan *) plan)->subplan->extParam);
break; break;
@ -839,39 +896,44 @@ SS_finalize_plan(Plan *plan, List *rtable)
rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid, rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
rtable); rtable);
Assert(rte->rtekind == RTE_FUNCTION); Assert(rte->rtekind == RTE_FUNCTION);
finalize_primnode(rte->funcexpr, &results); finalize_primnode(rte->funcexpr, &context);
} }
break; break;
case T_Append: case T_Append:
foreach(lst, ((Append *) plan)->appendplans) foreach(lst, ((Append *) plan)->appendplans)
results.paramids = set_unioni(results.paramids, {
SS_finalize_plan((Plan *) lfirst(lst), context.paramids =
rtable)); bms_add_members(context.paramids,
finalize_plan((Plan *) lfirst(lst),
rtable,
outer_params,
valid_params));
}
break; break;
case T_NestLoop: case T_NestLoop:
finalize_primnode((Node *) ((Join *) plan)->joinqual, finalize_primnode((Node *) ((Join *) plan)->joinqual,
&results); &context);
break; break;
case T_MergeJoin: case T_MergeJoin:
finalize_primnode((Node *) ((Join *) plan)->joinqual, finalize_primnode((Node *) ((Join *) plan)->joinqual,
&results); &context);
finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses, finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses,
&results); &context);
break; break;
case T_HashJoin: case T_HashJoin:
finalize_primnode((Node *) ((Join *) plan)->joinqual, finalize_primnode((Node *) ((Join *) plan)->joinqual,
&results); &context);
finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses, finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses,
&results); &context);
break; break;
case T_Hash: case T_Hash:
finalize_primnode((Node *) ((Hash *) plan)->hashkeys, finalize_primnode((Node *) ((Hash *) plan)->hashkeys,
&results); &context);
break; break;
case T_Agg: case T_Agg:
@ -885,50 +947,55 @@ SS_finalize_plan(Plan *plan, List *rtable)
break; break;
default: default:
elog(ERROR, "SS_finalize_plan: node %d unsupported", elog(ERROR, "finalize_plan: node %d unsupported",
nodeTag(plan)); nodeTag(plan));
} }
/* Process left and right child plans, if any */ /* Process left and right child plans, if any */
results.paramids = set_unioni(results.paramids, context.paramids = bms_add_members(context.paramids,
SS_finalize_plan(plan->lefttree, finalize_plan(plan->lefttree,
rtable)); rtable,
results.paramids = set_unioni(results.paramids, outer_params,
SS_finalize_plan(plan->righttree, valid_params));
rtable));
context.paramids = bms_add_members(context.paramids,
finalize_plan(plan->righttree,
rtable,
outer_params,
valid_params));
/* Now we have all the paramids */ /* Now we have all the paramids */
foreach(lst, results.paramids) if (!bms_is_subset(context.paramids, valid_params))
{ elog(ERROR, "finalize_plan: plan shouldn't reference subplan's variable");
int paramid = lfirsti(lst);
Var *var = nth(paramid, PlannerParamVar);
/* note varlevelsup is absolute level number */ plan->extParam = bms_intersect(context.paramids, outer_params);
if (var->varlevelsup < PlannerQueryLevel) plan->allParam = context.paramids;
extParam = lappendi(extParam, paramid);
else if (var->varlevelsup > PlannerQueryLevel) /*
elog(ERROR, "SS_finalize_plan: plan shouldn't reference subplan's variable"); * For speed at execution time, make sure extParam/allParam are actually
else * NULL if they are empty sets.
{ */
Assert(var->varno == 0 && var->varattno == 0); if (bms_is_empty(plan->extParam))
locParam = lappendi(locParam, paramid); {
} bms_free(plan->extParam);
plan->extParam = NULL;
}
if (bms_is_empty(plan->allParam))
{
bms_free(plan->allParam);
plan->allParam = NULL;
} }
plan->extParam = extParam; return plan->allParam;
plan->locParam = locParam;
return results.paramids;
} }
/* /*
* finalize_primnode: build lists of params appearing * finalize_primnode: add IDs of all PARAM_EXEC params appearing in the given
* in the given expression tree. NOTE: items are added to list passed in, * expression tree to the result set.
* so caller must initialize list to NIL before first call!
*/ */
static bool static bool
finalize_primnode(Node *node, finalize_primnode_results *results) finalize_primnode(Node *node, finalize_primnode_context *context)
{ {
if (node == NULL) if (node == NULL)
return false; return false;
@ -938,29 +1005,20 @@ finalize_primnode(Node *node, finalize_primnode_results *results)
{ {
int paramid = (int) ((Param *) node)->paramid; int paramid = (int) ((Param *) node)->paramid;
if (!intMember(paramid, results->paramids)) context->paramids = bms_add_member(context->paramids, paramid);
results->paramids = lconsi(paramid, results->paramids);
} }
return false; /* no more to do here */ return false; /* no more to do here */
} }
if (is_subplan(node)) if (is_subplan(node))
{ {
SubPlan *subplan = (SubPlan *) node; SubPlan *subplan = (SubPlan *) node;
List *lst;
/* Check extParam list for params to add to paramids */ /* Add outer-level params needed by the subplan to paramids */
foreach(lst, subplan->plan->extParam) context->paramids = bms_join(context->paramids,
{ bms_intersect(subplan->plan->extParam,
int paramid = lfirsti(lst); context->outer_params));
Var *var = nth(paramid, PlannerParamVar);
/* note varlevelsup is absolute level number */
if (var->varlevelsup < PlannerQueryLevel &&
!intMember(paramid, results->paramids))
results->paramids = lconsi(paramid, results->paramids);
}
/* fall through to recurse into subplan args */ /* fall through to recurse into subplan args */
} }
return expression_tree_walker(node, finalize_primnode, return expression_tree_walker(node, finalize_primnode,
(void *) results); (void *) context);
} }

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, 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.88 2003/02/03 15:07:07 tgl Exp $ * $Id: executor.h,v 1.89 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -160,7 +160,7 @@ extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
TupleDesc tupType); TupleDesc tupType);
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid); extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
extern void SetChangedParamList(PlanState *node, List *newchg); extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);
typedef struct TupOutputState typedef struct TupOutputState
{ {

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, 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.93 2003/02/03 21:15:44 tgl Exp $ * $Id: execnodes.h,v 1.94 2003/02/09 00:30:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -18,6 +18,7 @@
#include "executor/hashjoin.h" #include "executor/hashjoin.h"
#include "executor/tuptable.h" #include "executor/tuptable.h"
#include "fmgr.h" #include "fmgr.h"
#include "nodes/bitmapset.h"
#include "nodes/params.h" #include "nodes/params.h"
#include "nodes/plannodes.h" #include "nodes/plannodes.h"
#include "utils/tuplestore.h" #include "utils/tuplestore.h"
@ -616,7 +617,7 @@ typedef struct PlanState
/* /*
* State for management of parameter-change-driven rescanning * State for management of parameter-change-driven rescanning
*/ */
List *chgParam; /* integer list of IDs of changed Params */ Bitmapset *chgParam; /* set of IDs of changed Params */
/* /*
* Other run-time state needed by most if not all node types. * Other run-time state needed by most if not all node types.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, 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: plannodes.h,v 1.63 2002/12/12 15:49:40 tgl Exp $ * $Id: plannodes.h,v 1.64 2003/02/09 00:30:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -15,6 +15,7 @@
#define PLANNODES_H #define PLANNODES_H
#include "access/sdir.h" #include "access/sdir.h"
#include "nodes/bitmapset.h"
#include "nodes/primnodes.h" #include "nodes/primnodes.h"
@ -65,14 +66,17 @@ typedef struct Plan
/* /*
* Information for management of parameter-change-driven rescanning * Information for management of parameter-change-driven rescanning
*
* extParam includes the paramIDs of all external PARAM_EXEC params
* affecting this plan node or its children. setParam params from
* the node's initPlans are not included, but their extParams are.
*
* allParam includes all the extParam paramIDs, plus the IDs of local
* params that affect the node (i.e., the setParams of its initplans).
* These are _all_ the PARAM_EXEC params that affect this node.
*/ */
List *extParam; /* indices of _all_ _external_ PARAM_EXEC Bitmapset *extParam;
* for this plan in global Bitmapset *allParam;
* es_param_exec_vals. Params from
* setParam from initPlan-s are not
* included, but their execParam-s are
* here!!! */
List *locParam; /* someones from setParam-s */
/* /*
* We really need in some TopPlan node to store range table and * We really need in some TopPlan node to store range table and

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, 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: primnodes.h,v 1.78 2003/02/03 21:15:44 tgl Exp $ * $Id: primnodes.h,v 1.79 2003/02/09 00:30:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -435,9 +435,11 @@ typedef struct SubLink
* expressions to be evaluated in the outer-query context (currently these * expressions to be evaluated in the outer-query context (currently these
* args are always just Vars, but in principle they could be any expression). * args are always just Vars, but in principle they could be any expression).
* The values are assigned to the global PARAM_EXEC params indexed by parParam * The values are assigned to the global PARAM_EXEC params indexed by parParam
* (the parParam and args lists must have the same length). setParam is a * (the parParam and args lists must have the same ordering). setParam is a
* list of the PARAM_EXEC params that are computed by the sub-select, if it * list of the PARAM_EXEC params that are computed by the sub-select, if it
* is an initplan. * is an initplan; they are listed in order by sub-select output column
* position. (parParam and setParam are integer Lists, not Bitmapsets,
* because their ordering is significant.)
*/ */
typedef struct SubPlan typedef struct SubPlan
{ {
@ -449,6 +451,7 @@ typedef struct SubPlan
/* The combining operators, transformed to executable expressions: */ /* The combining operators, transformed to executable expressions: */
List *exprs; /* list of OpExpr expression trees */ List *exprs; /* list of OpExpr expression trees */
List *paramIds; /* IDs of Params embedded in the above */ List *paramIds; /* IDs of Params embedded in the above */
/* Note: paramIds has a one-to-one correspondence to the exprs list */
/* The subselect, transformed to a Plan: */ /* The subselect, transformed to a Plan: */
struct Plan *plan; /* subselect plan itself */ struct Plan *plan; /* subselect plan itself */
int plan_id; /* dummy thing because of we haven't equal int plan_id; /* dummy thing because of we haven't equal

View File

@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, 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: subselect.h,v 1.17 2003/01/20 18:55:05 tgl Exp $ * $Id: subselect.h,v 1.18 2003/02/09 00:30:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -22,6 +22,6 @@ extern int PlannerPlanId; /* to assign unique ID to subquery plans */
extern Node *convert_IN_to_join(Query *parse, SubLink *sublink); extern Node *convert_IN_to_join(Query *parse, SubLink *sublink);
extern Node *SS_replace_correlation_vars(Node *expr); extern Node *SS_replace_correlation_vars(Node *expr);
extern Node *SS_process_sublinks(Node *expr, bool isQual); extern Node *SS_process_sublinks(Node *expr, bool isQual);
extern List *SS_finalize_plan(Plan *plan, List *rtable); extern void SS_finalize_plan(Plan *plan, List *rtable);
#endif /* SUBSELECT_H */ #endif /* SUBSELECT_H */