📄 nodesubplan.c
字号:
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 */ } } 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 = list_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)) { int col = 1; ListCell *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 = lfirst_int(plst); ParamExecData *prmdata; prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]); Assert(prmdata->execPlan == NULL); prmdata->value = slot_getattr(slot, col, &(prmdata->isnull)); col++; } slot = ExecProject(node->projRight, NULL); /* * If result contains any nulls, store separately or not at all. */ if (slotNoNulls(slot)) { (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. (XXX possibly no longer needed, * but can't hurt.) */ 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; TupleHashIterator hashiter; TupleHashEntry entry; ResetTupleHashIterator(hashtable, &hashiter); while ((entry = ScanTupleHashTable(&hashiter)) != NULL) { ExecStoreTuple(entry->firstTuple, hashtable->tableslot, InvalidBuffer, false); if (!execTuplesUnequal(hashtable->tableslot, slot, numCols, keyColIdx, hashtable->eqfunctions, hashtable->tempcxt)) return true; } return false;}/* * slotAllNulls: is the slot completely NULL? * * This does not test for dropped columns, which is OK because we only * use it on projected tuples. */static boolslotAllNulls(TupleTableSlot *slot){ int ncols = slot->tts_tupleDescriptor->natts; int i; for (i = 1; i <= ncols; i++) { if (!slot_attisnull(slot, i)) return false; } return true;}/* * slotNoNulls: is the slot entirely not NULL? * * This does not test for dropped columns, which is OK because we only * use it on projected tuples. */static boolslotNoNulls(TupleTableSlot *slot){ int ncols = slot->tts_tupleDescriptor->natts; int i; for (i = 1; i <= ncols; i++) { if (slot_attisnull(slot, 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. */ ExecCheckRTPerms(subplan->rtable); /* * 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -