📄 nodesubplan.c
字号:
if (subplan->setParam != NIL) { List *lst; foreach(lst, subplan->setParam) { int paramid = lfirsti(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, *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 = 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(length(fstate->args) == 2); /* Process lefthand argument */ exstate = (ExprState *) lfirst(fstate->args); expr = exstate->expr; tle = makeTargetEntry(makeResdom(i, exprType((Node *) expr), exprTypmod((Node *) expr), NULL, false), expr); tlestate = makeNode(GenericExprState); tlestate->xprstate.expr = (Expr *) tle; tlestate->arg = exstate; lefttlist = lappend(lefttlist, tlestate); leftptlist = lappend(leftptlist, tle); /* Process righthand argument */ exstate = (ExprState *) lsecond(fstate->args); expr = exstate->expr; tle = makeTargetEntry(makeResdom(i, exprType((Node *) expr), exprTypmod((Node *) expr), NULL, false), expr); tlestate = makeNode(GenericExprState); tlestate->xprstate.expr = (Expr *) tle; 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; List *lst; 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)) { HeapTuple tup = slot->val; TupleDesc tdesc = slot->ttc_tupleDescriptor; int i = 1; if (subLinkType == EXISTS_SUBLINK) { /* There can be only one param... */ int paramid = lfirsti(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 = heap_getattr(tup, 1, tdesc, &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); tup = heap_copytuple(tup); if (node->curTuple) heap_freetuple(node->curTuple); node->curTuple = tup; MemoryContextSwitchTo(node->sub_estate->es_query_cxt); /* * Now set all the setParam params from the columns of the tuple */ foreach(lst, subplan->setParam) { int paramid = lfirsti(lst); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); prm->execPlan = NULL; prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull)); i++; } } if (!found) { if (subLinkType == EXISTS_SUBLINK) { /* There can be only one param... */ int paramid = lfirsti(subplan->setParam); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); prm->execPlan = NULL; prm->value = BoolGetDatum(false); prm->isnull = false; } else { foreach(lst, subplan->setParam) { int paramid = lfirsti(lst); 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 = lfirsti(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; List *lst; /* 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(lst, subplan->setParam) { int paramid = lfirsti(lst); 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 + -