⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nodesubplan.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
			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 + -