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

📄 nodesubplan.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * nodeSubplan.c *	  routines to support subselects * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.70.2.1 2005/11/22 18:23:09 momjian Exp $ * *------------------------------------------------------------------------- *//* *	 INTERFACE ROUTINES *		ExecSubPlan  - process a subselect *		ExecInitSubPlan - initialize a subselect *		ExecEndSubPlan	- shut down a subselect */#include "postgres.h"#include "access/heapam.h"#include "executor/executor.h"#include "executor/nodeSubplan.h"#include "nodes/makefuncs.h"#include "parser/parse_expr.h"#include "utils/array.h"#include "utils/datum.h"#include "utils/lsyscache.h"#include "utils/memutils.h"static Datum ExecHashSubPlan(SubPlanState *node,				ExprContext *econtext,				bool *isNull);static Datum ExecScanSubPlan(SubPlanState *node,				ExprContext *econtext,				bool *isNull);static void buildSubPlanHash(SubPlanState *node);static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);static bool slotAllNulls(TupleTableSlot *slot);static bool slotNoNulls(TupleTableSlot *slot);/* ---------------------------------------------------------------- *		ExecSubPlan * ---------------------------------------------------------------- */DatumExecSubPlan(SubPlanState *node,			ExprContext *econtext,			bool *isNull,			ExprDoneCond *isDone){	SubPlan    *subplan = (SubPlan *) node->xprstate.expr;	/* Set default values for result flags: non-null, not a set result */	*isNull = false;	if (isDone)		*isDone = ExprSingleResult;	if (subplan->setParam != NIL)		elog(ERROR, "cannot set parent params from subquery");	if (subplan->useHashTable)		return ExecHashSubPlan(node, econtext, isNull);	else		return ExecScanSubPlan(node, econtext, isNull);}/* * ExecHashSubPlan: store subselect result in an in-memory hash table */static DatumExecHashSubPlan(SubPlanState *node,				ExprContext *econtext,				bool *isNull){	SubPlan    *subplan = (SubPlan *) node->xprstate.expr;	PlanState  *planstate = node->planstate;	ExprContext *innerecontext = node->innerecontext;	TupleTableSlot *slot;	/* Shouldn't have any direct correlation Vars */	if (subplan->parParam != NIL || node->args != NIL)		elog(ERROR, "hashed subplan with direct correlation not supported");	/*	 * If first time through or we need to rescan the subplan, build the hash	 * table.	 */	if (node->hashtable == NULL || planstate->chgParam != NULL)		buildSubPlanHash(node);	/*	 * The result for an empty subplan is always FALSE; no need to evaluate	 * lefthand side.	 */	*isNull = false;	if (!node->havehashrows && !node->havenullrows)		return BoolGetDatum(false);	/*	 * Evaluate lefthand expressions and form a projection tuple. First we	 * have to set the econtext to use (hack alert!).	 */	node->projLeft->pi_exprContext = econtext;	slot = ExecProject(node->projLeft, NULL);	/*	 * Note: because we are typically called in a per-tuple context, we have	 * to explicitly clear the projected tuple before returning. Otherwise,	 * we'll have a double-free situation: the per-tuple context will probably	 * be reset before we're called again, and then the tuple slot will think	 * it still needs to free the tuple.	 */	/*	 * Since the hashtable routines will use innerecontext's per-tuple memory	 * as working memory, be sure to reset it for each tuple.	 */	ResetExprContext(innerecontext);	/*	 * If the LHS is all non-null, probe for an exact match in the main hash	 * table.  If we find one, the result is TRUE. Otherwise, scan the	 * partly-null table to see if there are any rows that aren't provably	 * unequal to the LHS; if so, the result is UNKNOWN.  (We skip that part	 * if we don't care about UNKNOWN.) Otherwise, the result is FALSE.	 *	 * Note: the reason we can avoid a full scan of the main hash table is	 * that the combining operators are assumed never to yield NULL when both	 * inputs are non-null.  If they were to do so, we might need to produce	 * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the	 * LHS to some main-table entry --- which is a comparison we will not even	 * make, unless there's a chance match of hash keys.	 */	if (slotNoNulls(slot))	{		if (node->havehashrows &&			LookupTupleHashEntry(node->hashtable, slot, NULL) != NULL)		{			ExecClearTuple(slot);			return BoolGetDatum(true);		}		if (node->havenullrows &&			findPartialMatch(node->hashnulls, slot))		{			ExecClearTuple(slot);			*isNull = true;			return BoolGetDatum(false);		}		ExecClearTuple(slot);		return BoolGetDatum(false);	}	/*	 * When the LHS is partly or wholly NULL, we can never return TRUE. If we	 * don't care about UNKNOWN, just return FALSE.  Otherwise, if the LHS is	 * wholly NULL, immediately return UNKNOWN.  (Since the combining	 * operators are strict, the result could only be FALSE if the sub-select	 * were empty, but we already handled that case.) Otherwise, we must scan	 * both the main and partly-null tables to see if there are any rows that	 * aren't provably unequal to the LHS; if so, the result is UNKNOWN.	 * Otherwise, the result is FALSE.	 */	if (node->hashnulls == NULL)	{		ExecClearTuple(slot);		return BoolGetDatum(false);	}	if (slotAllNulls(slot))	{		ExecClearTuple(slot);		*isNull = true;		return BoolGetDatum(false);	}	/* Scan partly-null table first, since more likely to get a match */	if (node->havenullrows &&		findPartialMatch(node->hashnulls, slot))	{		ExecClearTuple(slot);		*isNull = true;		return BoolGetDatum(false);	}	if (node->havehashrows &&		findPartialMatch(node->hashtable, slot))	{		ExecClearTuple(slot);		*isNull = true;		return BoolGetDatum(false);	}	ExecClearTuple(slot);	return BoolGetDatum(false);}/* * ExecScanSubPlan: default case where we have to rescan subplan each time */static DatumExecScanSubPlan(SubPlanState *node,				ExprContext *econtext,				bool *isNull){	SubPlan    *subplan = (SubPlan *) node->xprstate.expr;	PlanState  *planstate = node->planstate;	SubLinkType subLinkType = subplan->subLinkType;	bool		useOr = subplan->useOr;	MemoryContext oldcontext;	TupleTableSlot *slot;	Datum		result;	bool		found = false;	/* TRUE if got at least one subplan tuple */	ListCell   *pvar;	ListCell   *l;	ArrayBuildState *astate = NULL;	/*	 * We are probably in a short-lived expression-evaluation context. Switch	 * to the child plan's per-query context for manipulating its chgParam,	 * calling ExecProcNode on it, etc.	 */	oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);	/*	 * Set Params of this plan from parent plan correlation values. (Any	 * calculation we have to do is done in the parent econtext, since the	 * Param values don't need to have per-query lifetime.)	 */	Assert(list_length(subplan->parParam) == list_length(node->args));	forboth(l, subplan->parParam, pvar, node->args)	{		int			paramid = lfirst_int(l);		ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);		prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),											   econtext,											   &(prm->isnull),											   NULL);		planstate->chgParam = bms_add_member(planstate->chgParam, paramid);	}	ExecReScan(planstate, NULL);	/*	 * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result	 * is boolean as are the results of the combining operators. We combine	 * results within a tuple (if there are multiple columns) using OR	 * semantics if "useOr" is true, AND semantics if not. We then combine	 * results across tuples (if the subplan produces more than one) using OR	 * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.	 * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.)	 * NULL results from the combining operators are handled according to the	 * usual SQL semantics for OR and AND.	The result for no input tuples is	 * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for	 * MULTIEXPR_SUBLINK.	 *	 * For EXPR_SUBLINK we require the subplan to produce no more than one	 * tuple, else an error is raised. For ARRAY_SUBLINK we allow the subplan	 * to produce more than one tuple. In either case, if zero tuples are	 * produced, we return NULL. Assuming we get a tuple, we just use its	 * first column (there can be only one non-junk column in this case).	 */	result = BoolGetDatum(subLinkType == ALL_SUBLINK);	*isNull = false;	for (slot = ExecProcNode(planstate);		 !TupIsNull(slot);		 slot = ExecProcNode(planstate))	{		TupleDesc	tdesc = slot->tts_tupleDescriptor;		Datum		rowresult = BoolGetDatum(!useOr);		bool		rownull = false;		int			col = 1;		ListCell   *plst;		if (subLinkType == EXISTS_SUBLINK)		{			found = true;			result = BoolGetDatum(true);			break;		}		if (subLinkType == EXPR_SUBLINK)		{			/* cannot allow multiple input tuples for EXPR sublink */			if (found)				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 in case the result is of			 * pass-by-ref type --- our return value will point into this			 * copied tuple!  Can't use the subplan's instance of the tuple			 * since it won't still be valid after next ExecProcNode() call.			 * 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);			result = heap_getattr(node->curTuple, col, tdesc, isNull);			/* keep scanning subplan to make sure there's only one tuple */			continue;		}		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;		}		/* cannot allow multiple input tuples for MULTIEXPR sublink either */		if (subLinkType == MULTIEXPR_SUBLINK && found)			ereport(ERROR,					(errcode(ERRCODE_CARDINALITY_VIOLATION),					 errmsg("more than one row returned by a subquery used as an expression")));		found = true;		/*		 * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining		 * operators for columns of tuple.		 */		Assert(list_length(node->exprs) == list_length(subplan->paramIds));		forboth(l, node->exprs, plst, subplan->paramIds)		{			ExprState  *exprstate = (ExprState *) lfirst(l);			int			paramid = lfirst_int(plst);			ParamExecData *prmdata;			Datum		expresult;			bool		expnull;			/*			 * Load up the Param representing this column of the sub-select.			 */			prmdata = &(econtext->ecxt_param_exec_vals[paramid]);			Assert(prmdata->execPlan == NULL);			prmdata->value = slot_getattr(slot, col,										  &(prmdata->isnull));			/*			 * Now we can eval the combining operator for this column.			 */			expresult = ExecEvalExprSwitchContext(exprstate, econtext,												  &expnull, NULL);			/*			 * Combine the result into the row result as appropriate.			 */			if (col == 1)			{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -