📄 nodesubplan.c
字号:
if (col == 1) { rowresult = expresult; rownull = expnull; } else if (useOr) { /* combine within row per OR semantics */ if (expnull) rownull = true; else if (DatumGetBool(expresult)) { rowresult = BoolGetDatum(true); rownull = false; break; /* needn't look at any more columns */ } } else { /* combine within row per AND semantics */ if (expnull) rownull = true; else if (!DatumGetBool(expresult)) { rowresult = BoolGetDatum(false); rownull = false; break; /* needn't look at any more columns */ } } plst = lnext(plst); col++; } if (subLinkType == ANY_SUBLINK) { /* combine across rows per OR semantics */ if (rownull) *isNull = true; else if (DatumGetBool(rowresult)) { result = BoolGetDatum(true); *isNull = false; break; /* needn't look at any more rows */ } } else if (subLinkType == ALL_SUBLINK) { /* combine across rows per AND semantics */ if (rownull) *isNull = true; else if (!DatumGetBool(rowresult)) { result = BoolGetDatum(false); *isNull = false; break; /* needn't look at any more rows */ } } else { /* must be MULTIEXPR_SUBLINK */ result = rowresult; *isNull = rownull; } } if (!found) { /* * deal with empty subplan result. result/isNull were previously * initialized correctly for all sublink types except EXPR, ARRAY, * and MULTIEXPR; for those, return NULL. */ if (subLinkType == EXPR_SUBLINK || subLinkType == ARRAY_SUBLINK || subLinkType == MULTIEXPR_SUBLINK) { result = (Datum) 0; *isNull = true; } } else if (subLinkType == ARRAY_SUBLINK) { Assert(astate != NULL); /* We return the result in the caller's context */ result = makeArrayResult(astate, oldcontext); } MemoryContextSwitchTo(oldcontext); return result;}/* * buildSubPlanHash: load hash table by scanning subplan output. */static voidbuildSubPlanHash(SubPlanState *node){ SubPlan *subplan = (SubPlan *) node->xprstate.expr; PlanState *planstate = node->planstate; int ncols = length(node->exprs); ExprContext *innerecontext = node->innerecontext; MemoryContext tempcxt = innerecontext->ecxt_per_tuple_memory; MemoryContext oldcontext; int nbuckets; TupleTableSlot *slot; Assert(subplan->subLinkType == ANY_SUBLINK); Assert(!subplan->useOr); /* * If we already had any hash tables, destroy 'em; then create empty * hash table(s). * * If we need to distinguish accurately between FALSE and UNKNOWN (i.e., * NULL) results of the IN operation, then we have to store subplan * output rows that are partly or wholly NULL. We store such rows in * a separate hash table that we expect will be much smaller than the * main table. (We can use hashing to eliminate partly-null rows that * are not distinct. We keep them separate to minimize the cost of * the inevitable full-table searches; see findPartialMatch.) * * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't * need to store subplan output rows that contain NULL. */ MemoryContextReset(node->tablecxt); node->hashtable = NULL; node->hashnulls = NULL; node->havehashrows = false; node->havenullrows = false; nbuckets = (int) ceil(planstate->plan->plan_rows); if (nbuckets < 1) nbuckets = 1; node->hashtable = BuildTupleHashTable(ncols, node->keyColIdx, node->eqfunctions, node->hashfunctions, nbuckets, sizeof(TupleHashEntryData), node->tablecxt, tempcxt); if (!subplan->unknownEqFalse) { if (ncols == 1) nbuckets = 1; /* there can only be one entry */ else { nbuckets /= 16; if (nbuckets < 1) nbuckets = 1; } node->hashnulls = BuildTupleHashTable(ncols, node->keyColIdx, node->eqfunctions, node->hashfunctions, nbuckets, sizeof(TupleHashEntryData), node->tablecxt, tempcxt); } /* * We are probably in a short-lived expression-evaluation context. * Switch to the child plan's per-query context for calling * ExecProcNode. */ oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt); /* * Reset subplan to start. */ ExecReScan(planstate, NULL); /* * Scan the subplan and load the hash table(s). Note that when there * are duplicate rows coming out of the sub-select, only one copy is * stored. */ for (slot = ExecProcNode(planstate); !TupIsNull(slot); slot = ExecProcNode(planstate)) { HeapTuple tup = slot->val; TupleDesc tdesc = slot->ttc_tupleDescriptor; int col = 1; List *plst; bool isnew; /* * Load up the Params representing the raw sub-select outputs, * then form the projection tuple to store in the hashtable. */ foreach(plst, subplan->paramIds) { int paramid = lfirsti(plst); ParamExecData *prmdata; prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]); Assert(prmdata->execPlan == NULL); prmdata->value = heap_getattr(tup, col, tdesc, &(prmdata->isnull)); col++; } slot = ExecProject(node->projRight, NULL); tup = slot->val; /* * If result contains any nulls, store separately or not at all. * (Since we know the projection tuple has no junk columns, we can * just look at the overall hasnull info bit, instead of groveling * through the columns.) */ if (HeapTupleNoNulls(tup)) { (void) LookupTupleHashEntry(node->hashtable, slot, &isnew); node->havehashrows = true; } else if (node->hashnulls) { (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew); node->havenullrows = true; } /* * Reset innerecontext after each inner tuple to free any memory * used in hash computation or comparison routines. */ ResetExprContext(innerecontext); } /* * Since the projected tuples are in the sub-query's context and not * the main context, we'd better clear the tuple slot before there's * any chance of a reset of the sub-query's context. Else we will * have the potential for a double free attempt. */ ExecClearTuple(node->projRight->pi_slot); MemoryContextSwitchTo(oldcontext);}/* * findPartialMatch: does the hashtable contain an entry that is not * provably distinct from the tuple? * * We have to scan the whole hashtable; we can't usefully use hashkeys * to guide probing, since we might get partial matches on tuples with * hashkeys quite unrelated to what we'd get from the given tuple. */static boolfindPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot){ int numCols = hashtable->numCols; AttrNumber *keyColIdx = hashtable->keyColIdx; HeapTuple tuple = slot->val; TupleDesc tupdesc = slot->ttc_tupleDescriptor; TupleHashIterator hashiter; TupleHashEntry entry; ResetTupleHashIterator(hashtable, &hashiter); while ((entry = ScanTupleHashTable(&hashiter)) != NULL) { if (!execTuplesUnequal(entry->firstTuple, tuple, tupdesc, numCols, keyColIdx, hashtable->eqfunctions, hashtable->tempcxt)) return true; } return false;}/* * tupleAllNulls: is the tuple completely NULL? */static booltupleAllNulls(HeapTuple tuple){ int ncols = tuple->t_data->t_natts; int i; for (i = 1; i <= ncols; i++) { if (!heap_attisnull(tuple, i)) return false; } return true;}/* ---------------------------------------------------------------- * ExecInitSubPlan * ---------------------------------------------------------------- */voidExecInitSubPlan(SubPlanState *node, EState *estate){ SubPlan *subplan = (SubPlan *) node->xprstate.expr; EState *sp_estate; MemoryContext oldcontext; /* * Do access checking on the rangetable entries in the subquery. Here, * we assume the subquery is a SELECT. */ ExecCheckRTPerms(subplan->rtable, CMD_SELECT); /* * 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->eqfunctions = NULL; node->hashfunctions = NULL; /* * create an EState for the subplan * * The subquery needs its own EState because it has its own rangetable. * It shares our Param ID space, however. XXX if rangetable access * were done differently, the subquery could share our EState, which * would eliminate some thrashing about in this module... */ sp_estate = CreateExecutorState(); node->sub_estate = sp_estate; oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt); sp_estate->es_range_table = subplan->rtable; 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(subplan->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; /* * Start up the subplan (this is a very cut-down form of InitPlan()) */ node->planstate = ExecInitNode(subplan->plan, sp_estate); node->needShutdown = true; /* now we need to shutdown the subplan */ MemoryContextSwitchTo(oldcontext); /* * 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... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -