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

📄 nodesubplan.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * nodeSubplan.c *	  routines to support subselects * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.58 2003/10/01 21:30:52 tgl 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"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 tupleAllNulls(HeapTuple tuple);/* ---------------------------------------------------------------- *		ExecSubPlan * ---------------------------------------------------------------- */DatumExecSubPlan(SubPlanState *node,			ExprContext *econtext,			bool *isNull){	SubPlan    *subplan = (SubPlan *) node->xprstate.expr;	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;	HeapTuple	tup;	/* 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);	tup = slot->val;	/*	 * 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 (HeapTupleNoNulls(tup))	{		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 (tupleAllNulls(tup))	{		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 */	List	   *pvar;	List	   *lst;	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.)	 */	pvar = node->args;	foreach(lst, subplan->parParam)	{		int			paramid = lfirsti(lst);		ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);		Assert(pvar != NIL);		prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),											   econtext,											   &(prm->isnull),											   NULL);		pvar = lnext(pvar);		planstate->chgParam = bms_add_member(planstate->chgParam, paramid);	}	Assert(pvar == NIL);	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))	{		HeapTuple	tup = slot->val;		TupleDesc	tdesc = slot->ttc_tupleDescriptor;		Datum		rowresult = BoolGetDatum(!useOr);		bool		rownull = false;		int			col = 1;		List	   *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);			tup = heap_copytuple(tup);			if (node->curTuple)				heap_freetuple(node->curTuple);			node->curTuple = tup;			MemoryContextSwitchTo(node->sub_estate->es_query_cxt);			result = heap_getattr(tup, 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 = heap_getattr(tup, 1, tdesc, &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.		 */		plst = subplan->paramIds;		foreach(lst, node->exprs)		{			ExprState  *exprstate = (ExprState *) lfirst(lst);			int			paramid = lfirsti(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 = heap_getattr(tup, col, tdesc,										  &(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.			 */

⌨️ 快捷键说明

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