📄 nodesubplan.c
字号:
/* * If this plan is un-correlated or undirect correlated one and want 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) { ListCell *lst; foreach(lst, subplan->setParam) { int paramid = lfirst_int(lst); ParamExecData *prm = &(estate->es_param_exec_vals[paramid]); prm->execPlan = node; } } /* * If we are going to hash the subquery output, initialize relevant stuff. * (We don't create the hashtable until needed, though.) */ if (subplan->useHashTable) { int ncols, i; TupleDesc tupDesc; TupleTable tupTable; TupleTableSlot *slot; List *lefttlist, *righttlist, *leftptlist, *rightptlist; ListCell *lexpr; /* We need a memory context to hold the hash table(s) */ node->tablecxt = AllocSetContextCreate(CurrentMemoryContext, "Subplan HashTable Context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* and a short-lived exprcontext for function evaluation */ node->innerecontext = CreateExprContext(estate); /* Silly little array of column numbers 1..n */ ncols = list_length(node->exprs); node->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber)); for (i = 0; i < ncols; i++) node->keyColIdx[i] = i + 1; /* * We use ExecProject to evaluate the lefthand and righthand * expression lists and form tuples. (You might think that we could * use the sub-select's output tuples directly, but that is not the * case if we had to insert any run-time coercions of the sub-select's * output datatypes; anyway this avoids storing any resjunk columns * that might be in the sub-select's output.) Run through the * combining expressions to build tlists for the lefthand and * righthand sides. We need both the ExprState list (for ExecProject) * and the underlying parse Exprs (for ExecTypeFromTL). * * We also extract the combining operators themselves to initialize * the equality and hashing functions for the hash tables. */ lefttlist = righttlist = NIL; leftptlist = rightptlist = NIL; node->eqfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo)); node->hashfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo)); i = 1; foreach(lexpr, node->exprs) { FuncExprState *fstate = (FuncExprState *) lfirst(lexpr); OpExpr *opexpr = (OpExpr *) fstate->xprstate.expr; ExprState *exstate; Expr *expr; TargetEntry *tle; GenericExprState *tlestate; Oid hashfn; Assert(IsA(fstate, FuncExprState)); Assert(IsA(opexpr, OpExpr)); Assert(list_length(fstate->args) == 2); /* Process lefthand argument */ exstate = (ExprState *) linitial(fstate->args); expr = exstate->expr; tle = makeTargetEntry(expr, i, NULL, false); tlestate = makeNode(GenericExprState); tlestate->xprstate.expr = (Expr *) tle; tlestate->xprstate.evalfunc = NULL; tlestate->arg = exstate; lefttlist = lappend(lefttlist, tlestate); leftptlist = lappend(leftptlist, tle); /* Process righthand argument */ exstate = (ExprState *) lsecond(fstate->args); expr = exstate->expr; tle = makeTargetEntry(expr, i, NULL, false); tlestate = makeNode(GenericExprState); tlestate->xprstate.expr = (Expr *) tle; tlestate->xprstate.evalfunc = NULL; tlestate->arg = exstate; righttlist = lappend(righttlist, tlestate); rightptlist = lappend(rightptlist, tle); /* Lookup the combining function */ fmgr_info(opexpr->opfuncid, &node->eqfunctions[i - 1]); node->eqfunctions[i - 1].fn_expr = (Node *) opexpr; /* Lookup the associated hash function */ hashfn = get_op_hash_function(opexpr->opno); if (!OidIsValid(hashfn)) elog(ERROR, "could not find hash function for hash operator %u", opexpr->opno); fmgr_info(hashfn, &node->hashfunctions[i - 1]); i++; } /* * Create a tupletable to hold these tuples. (Note: we never bother * to free the tupletable explicitly; that's okay because it will * never store raw disk tuples that might have associated buffer pins. * The only resource involved is memory, which will be cleaned up by * freeing the query context.) */ tupTable = ExecCreateTupleTable(2); /* * Construct tupdescs, slots and projection nodes for left and right * sides. The lefthand expressions will be evaluated in the parent * plan node's exprcontext, which we don't have access to here. * Fortunately we can just pass NULL for now and fill it in later * (hack alert!). The righthand expressions will be evaluated in our * own innerecontext. */ tupDesc = ExecTypeFromTL(leftptlist, false); slot = ExecAllocTableSlot(tupTable); ExecSetSlotDescriptor(slot, tupDesc, true); node->projLeft = ExecBuildProjectionInfo(lefttlist, NULL, slot); tupDesc = ExecTypeFromTL(rightptlist, false); slot = ExecAllocTableSlot(tupTable); ExecSetSlotDescriptor(slot, tupDesc, true); node->projRight = ExecBuildProjectionInfo(righttlist, node->innerecontext, slot); }}/* ---------------------------------------------------------------- * ExecSetParamPlan * * Executes an InitPlan subplan and sets its output parameters. * * This is called from ExecEvalParam() when the value of a PARAM_EXEC * parameter is requested and the param's execPlan field is set (indicating * that the param has not yet been evaluated). This allows lazy evaluation * of initplans: we don't run the subplan until/unless we need its output. * Note that this routine MUST clear the execPlan fields of the plan's * output parameters after evaluating them! * ---------------------------------------------------------------- */voidExecSetParamPlan(SubPlanState *node, ExprContext *econtext){ SubPlan *subplan = (SubPlan *) node->xprstate.expr; PlanState *planstate = node->planstate; SubLinkType subLinkType = subplan->subLinkType; MemoryContext oldcontext; TupleTableSlot *slot; ListCell *l; bool found = false; ArrayBuildState *astate = NULL; /* * Must switch to child query's per-query memory context. */ oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt); if (subLinkType == ANY_SUBLINK || subLinkType == ALL_SUBLINK) elog(ERROR, "ANY/ALL subselect unsupported as initplan"); if (planstate->chgParam != NULL) ExecReScan(planstate, NULL); for (slot = ExecProcNode(planstate); !TupIsNull(slot); slot = ExecProcNode(planstate)) { TupleDesc tdesc = slot->tts_tupleDescriptor; int i = 1; if (subLinkType == EXISTS_SUBLINK) { /* There can be only one param... */ int paramid = linitial_int(subplan->setParam); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); prm->execPlan = NULL; prm->value = BoolGetDatum(true); prm->isnull = false; found = true; break; } if (subLinkType == ARRAY_SUBLINK) { Datum dvalue; bool disnull; found = true; /* stash away current value */ dvalue = slot_getattr(slot, 1, &disnull); astate = accumArrayResult(astate, dvalue, disnull, tdesc->attrs[0]->atttypid, oldcontext); /* keep scanning subplan to collect all values */ continue; } if (found && (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), errmsg("more than one row returned by a subquery used as an expression"))); found = true; /* * We need to copy the subplan's tuple into our own context, in case * any of the params are pass-by-ref type --- the pointers stored in * 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 */ foreach(l, subplan->setParam) { int paramid = lfirst_int(l); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); prm->execPlan = NULL; prm->value = heap_getattr(node->curTuple, i, tdesc, &(prm->isnull)); i++; } } if (!found) { if (subLinkType == EXISTS_SUBLINK) { /* There can be only one param... */ int paramid = linitial_int(subplan->setParam); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); prm->execPlan = NULL; prm->value = BoolGetDatum(false); prm->isnull = false; } else { foreach(l, subplan->setParam) { int paramid = lfirst_int(l); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); prm->execPlan = NULL; prm->value = (Datum) 0; prm->isnull = true; } } } else if (subLinkType == ARRAY_SUBLINK) { /* There can be only one param... */ int paramid = linitial_int(subplan->setParam); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); Assert(astate != NULL); prm->execPlan = NULL; /* We build the result in query context so it won't disappear */ prm->value = makeArrayResult(astate, econtext->ecxt_per_query_memory); prm->isnull = false; } MemoryContextSwitchTo(oldcontext);}/* ---------------------------------------------------------------- * ExecEndSubPlan * ---------------------------------------------------------------- */voidExecEndSubPlan(SubPlanState *node){ if (node->needShutdown) { MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt); ExecEndPlan(node->planstate, node->sub_estate); MemoryContextSwitchTo(oldcontext); FreeExecutorState(node->sub_estate); node->sub_estate = NULL; node->planstate = NULL; node->needShutdown = false; }}/* * Mark an initplan as needing recalculation */voidExecReScanSetParamPlan(SubPlanState *node, PlanState *parent){ PlanState *planstate = node->planstate; SubPlan *subplan = (SubPlan *) node->xprstate.expr; EState *estate = parent->state; ListCell *l; /* sanity checks */ if (subplan->parParam != NIL) elog(ERROR, "direct correlated subquery unsupported as initplan"); if (subplan->setParam == NIL) elog(ERROR, "setParam list of initplan is empty"); if (bms_is_empty(planstate->plan->extParam)) elog(ERROR, "extParam set of initplan is empty"); /* * Don't actually re-scan: ExecSetParamPlan does it if needed. */ /* * Mark this subplan's output parameters as needing recalculation */ foreach(l, subplan->setParam) { int paramid = lfirst_int(l); ParamExecData *prm = &(estate->es_param_exec_vals[paramid]); prm->execPlan = node; parent->chgParam = bms_add_member(parent->chgParam, paramid); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -