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

📄 execqual.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * execQual.c *	  Routines to evaluate qualification and targetlist expressions * * 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/execQual.c,v 1.150.2.1 2003/12/18 22:23:54 tgl Exp $ * *------------------------------------------------------------------------- *//* *	 INTERFACE ROUTINES *		ExecEvalExpr	- evaluate an expression and return a datum *		ExecEvalExprSwitchContext - same, but switch into eval memory context *		ExecQual		- return true/false if qualification is satisfied *		ExecProject		- form a new tuple by projecting the given tuple * *	 NOTES *		ExecEvalExpr() and ExecEvalVar() are hotspots.	making these faster *		will speed up the entire system.  Unfortunately they are currently *		implemented recursively.  Eliminating the recursion is bound to *		improve the speed of the executor. * *		ExecProject() is used to make tuple projections.  Rather then *		trying to speed it up, the execution plan should be pre-processed *		to facilitate attribute sharing between nodes wherever possible, *		instead of doing needless copying.	-cim 5/31/91 * */#include "postgres.h"#include "access/heapam.h"#include "catalog/pg_type.h"#include "commands/typecmds.h"#include "executor/execdebug.h"#include "executor/functions.h"#include "executor/nodeSubplan.h"#include "miscadmin.h"#include "optimizer/planmain.h"#include "parser/parse_expr.h"#include "utils/acl.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/lsyscache.h"/* static function decls */static Datum ExecEvalAggref(AggrefExprState *aggref,			   ExprContext *econtext,			   bool *isNull);static Datum ExecEvalArrayRef(ArrayRefExprState *astate,				 ExprContext *econtext,				 bool *isNull, ExprDoneCond *isDone);static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);static Datum ExecEvalParam(Param *expression, ExprContext *econtext,			  bool *isNull);static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext,			 bool *isNull, ExprDoneCond *isDone);static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext,			 bool *isNull, ExprDoneCond *isDone);static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext,				 bool *isNull);static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,					  ExprContext *econtext, bool *isNull);static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo,				 List *argList, ExprContext *econtext);static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,			bool *isNull);static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,		   bool *isNull);static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,			bool *isNull);static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,			 bool *isNull, ExprDoneCond *isDone);static Datum ExecEvalArray(ArrayExprState *astate,			  ExprContext *econtext,			  bool *isNull);static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,				 ExprContext *econtext,				 bool *isNull);static Datum ExecEvalNullIf(FuncExprState *nullIfExpr, ExprContext *econtext,			   bool *isNull);static Datum ExecEvalNullTest(GenericExprState *nstate,				 ExprContext *econtext,				 bool *isNull, ExprDoneCond *isDone);static Datum ExecEvalBooleanTest(GenericExprState *bstate,					ExprContext *econtext,					bool *isNull, ExprDoneCond *isDone);static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate,					   ExprContext *econtext,					   bool *isNull, ExprDoneCond *isDone);static Datum ExecEvalCoerceToDomainValue(CoerceToDomainValue *conVal,							ExprContext *econtext, bool *isNull);static Datum ExecEvalFieldSelect(GenericExprState *fstate,					ExprContext *econtext,					bool *isNull, ExprDoneCond *isDone);/*---------- *	  ExecEvalArrayRef * *	   This function takes an ArrayRef and returns the extracted Datum *	   if it's a simple reference, or the modified array value if it's *	   an array assignment (i.e., array element or slice insertion). * * NOTE: if we get a NULL result from a subexpression, we return NULL when * it's an array reference, or the unmodified source array when it's an * array assignment.  This may seem peculiar, but if we return NULL (as was * done in versions up through 7.0) then an assignment like *			UPDATE table SET arrayfield[4] = NULL * will result in setting the whole array to NULL, which is certainly not * very desirable.	By returning the source array we make the assignment * into a no-op, instead.  (Eventually we need to redesign arrays so that * individual elements can be NULL, but for now, let's try to protect users * from shooting themselves in the foot.) * * NOTE: we deliberately refrain from applying DatumGetArrayTypeP() here, * even though that might seem natural, because this code needs to support * both varlena arrays and fixed-length array types.  DatumGetArrayTypeP() * only works for the varlena kind.  The routines we call in arrayfuncs.c * have to know the difference (that's what they need refattrlength for). *---------- */static DatumExecEvalArrayRef(ArrayRefExprState *astate,				 ExprContext *econtext,				 bool *isNull,				 ExprDoneCond *isDone){	ArrayRef   *arrayRef = (ArrayRef *) astate->xprstate.expr;	ArrayType  *array_source;	ArrayType  *resultArray;	bool		isAssignment = (arrayRef->refassgnexpr != NULL);	List	   *elt;	int			i = 0,				j = 0;	IntArray	upper,				lower;	int		   *lIndex;	if (arrayRef->refexpr != NULL)	{		array_source = (ArrayType *)			DatumGetPointer(ExecEvalExpr(astate->refexpr,										 econtext,										 isNull,										 isDone));		/*		 * If refexpr yields NULL, result is always NULL, for now anyway.		 * (This means you cannot assign to an element or slice of an		 * array that's NULL; it'll just stay NULL.)		 */		if (*isNull)			return (Datum) NULL;	}	else	{		/*		 * Empty refexpr indicates we are doing an INSERT into an array		 * column. For now, we just take the refassgnexpr (which the		 * parser will have ensured is an array value) and return it		 * as-is, ignoring any subscripts that may have been supplied in		 * the INSERT column list. This is a kluge, but it's not real		 * clear what the semantics ought to be...		 */		array_source = NULL;	}	foreach(elt, astate->refupperindexpr)	{		if (i >= MAXDIM)			ereport(ERROR,					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),					 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",							i, MAXDIM)));		upper.indx[i++] = DatumGetInt32(ExecEvalExpr((ExprState *) lfirst(elt),													 econtext,													 isNull,													 NULL));		/* If any index expr yields NULL, result is NULL or source array */		if (*isNull)		{			if (!isAssignment || array_source == NULL)				return (Datum) NULL;			*isNull = false;			return PointerGetDatum(array_source);		}	}	if (astate->reflowerindexpr != NIL)	{		foreach(elt, astate->reflowerindexpr)		{			if (j >= MAXDIM)				ereport(ERROR,						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),						 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",								i, MAXDIM)));			lower.indx[j++] = DatumGetInt32(ExecEvalExpr((ExprState *) lfirst(elt),														 econtext,														 isNull,														 NULL));			/*			 * If any index expr yields NULL, result is NULL or source			 * array			 */			if (*isNull)			{				if (!isAssignment || array_source == NULL)					return (Datum) NULL;				*isNull = false;				return PointerGetDatum(array_source);			}		}		/* this can't happen unless parser messed up */		if (i != j)			elog(ERROR, "upper and lower index lists are not same length");		lIndex = lower.indx;	}	else		lIndex = NULL;	if (isAssignment)	{		Datum		sourceData = ExecEvalExpr(astate->refassgnexpr,											  econtext,											  isNull,											  NULL);		/*		 * For now, can't cope with inserting NULL into an array, so make		 * it a no-op per discussion above...		 */		if (*isNull)		{			if (array_source == NULL)				return (Datum) NULL;			*isNull = false;			return PointerGetDatum(array_source);		}		if (array_source == NULL)			return sourceData;	/* XXX do something else? */		if (lIndex == NULL)			resultArray = array_set(array_source, i,									upper.indx,									sourceData,									astate->refattrlength,									astate->refelemlength,									astate->refelembyval,									astate->refelemalign,									isNull);		else			resultArray = array_set_slice(array_source, i,										  upper.indx, lower.indx,							   (ArrayType *) DatumGetPointer(sourceData),										  astate->refattrlength,										  astate->refelemlength,										  astate->refelembyval,										  astate->refelemalign,										  isNull);		return PointerGetDatum(resultArray);	}	if (lIndex == NULL)		return array_ref(array_source, i, upper.indx,						 astate->refattrlength,						 astate->refelemlength,						 astate->refelembyval,						 astate->refelemalign,						 isNull);	else	{		resultArray = array_get_slice(array_source, i,									  upper.indx, lower.indx,									  astate->refattrlength,									  astate->refelemlength,									  astate->refelembyval,									  astate->refelemalign,									  isNull);		return PointerGetDatum(resultArray);	}}/* ---------------------------------------------------------------- *		ExecEvalAggref * *		Returns a Datum whose value is the value of the precomputed *		aggregate found in the given expression context. * ---------------------------------------------------------------- */static DatumExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, bool *isNull){	if (econtext->ecxt_aggvalues == NULL)		/* safety check */		elog(ERROR, "no aggregates in this expression context");	*isNull = econtext->ecxt_aggnulls[aggref->aggno];	return econtext->ecxt_aggvalues[aggref->aggno];}/* ---------------------------------------------------------------- *		ExecEvalVar * *		Returns a Datum whose value is the value of a range *		variable with respect to given expression context. * ---------------------------------------------------------------- */static DatumExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull){	Datum		result;	TupleTableSlot *slot;	AttrNumber	attnum;	HeapTuple	heapTuple;	TupleDesc	tuple_type;	/*	 * get the slot we want	 */	switch (variable->varno)	{		case INNER:				/* get the tuple from the inner node */			slot = econtext->ecxt_innertuple;			break;		case OUTER:				/* get the tuple from the outer node */			slot = econtext->ecxt_outertuple;			break;		default:				/* get the tuple from the relation being								 * scanned */			slot = econtext->ecxt_scantuple;			break;	}	/*	 * extract tuple information from the slot	 */	heapTuple = slot->val;	tuple_type = slot->ttc_tupleDescriptor;	attnum = variable->varattno;	/*	 * Some checks that are only applied for user attribute numbers	 * (bogus system attnums will be caught inside heap_getattr).	 */	if (attnum > 0)	{		/*		 * This assert checks that the attnum is valid.		 */		Assert(attnum <= tuple_type->natts &&			   tuple_type->attrs[attnum - 1] != NULL);		/*		 * If the attribute's column has been dropped, we force a NULL result.		 * This case should not happen in normal use, but it could happen if		 * we are executing a plan cached before the column was dropped.		 */		if (tuple_type->attrs[attnum - 1]->attisdropped)		{			*isNull = true;			return (Datum) 0;		}		/*		 * This assert checks that the datatype the plan expects to get (as		 * told by our "variable" argument) is in fact the datatype of the		 * attribute being fetched (as seen in the current context, identified		 * by our "econtext" argument).  Otherwise crashes are likely.		 *		 * Note that we can't check dropped columns, since their atttypid		 * has been zeroed.		 */		Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid);	}	/*	 * If the attribute number is invalid, then we are supposed to return	 * the entire tuple; we give back a whole slot so that callers know	 * what the tuple looks like.	 *	 * XXX this is a horrid crock: since the pointer to the slot might live	 * longer than the current evaluation context, we are forced to copy	 * the tuple and slot into a long-lived context --- we use the	 * econtext's per-query memory which should be safe enough.  This	 * represents a serious memory leak if many such tuples are processed	 * in one command, however.  We ought to redesign the representation	 * of whole-tuple datums so that this is not necessary.	 *	 * We assume it's OK to point to the existing tupleDescriptor, rather	 * than copy that too.	 */	if (attnum == InvalidAttrNumber)	{		MemoryContext oldContext;		TupleTableSlot *tempSlot;		HeapTuple	tup;		oldContext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);		tempSlot = MakeTupleTableSlot();		tup = heap_copytuple(heapTuple);		ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);		ExecSetSlotDescriptor(tempSlot, tuple_type, false);		MemoryContextSwitchTo(oldContext);		return PointerGetDatum(tempSlot);	}	result = heap_getattr(heapTuple,	/* tuple containing attribute */						  attnum,		/* attribute number of desired										 * attribute */						  tuple_type,	/* tuple descriptor of tuple */						  isNull);		/* return: is attribute null? */	return result;}/* ---------------------------------------------------------------- *		ExecEvalParam * *		Returns the value of a parameter.  A param node contains *		something like ($.name) and the expression context contains *		the current parameter bindings (name = "sam") (age = 34)... *		so our job is to find and return the appropriate datum ("sam"). * *		Q: if we have a parameter ($.foo) without a binding, i.e. *		   there is no (foo = xxx) in the parameter list info, *		   is this a fatal error or should this be a "not available" *		   (in which case we could return NULL)?	-cim 10/13/89 * ---------------------------------------------------------------- */static DatumExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull){	int			thisParamKind = expression->paramkind;	AttrNumber	thisParamId = expression->paramid;	if (thisParamKind == PARAM_EXEC)	{		/*		 * PARAM_EXEC params (internal executor parameters) are stored in		 * the ecxt_param_exec_vals array, and can be accessed by array		 * index.		 */		ParamExecData *prm;		prm = &(econtext->ecxt_param_exec_vals[thisParamId]);		if (prm->execPlan != NULL)		{			/* Parameter not evaluated yet, so go do it */			ExecSetParamPlan(prm->execPlan, econtext);			/* ExecSetParamPlan should have processed this param... */			Assert(prm->execPlan == NULL);		}		*isNull = prm->isnull;		return prm->value;	}	else	{		/*		 * All other parameter types must be sought in		 * ecxt_param_list_info. NOTE: The last entry in the param array		 * is always an entry with kind == PARAM_INVALID.		 */		ParamListInfo paramList = econtext->ecxt_param_list_info;

⌨️ 快捷键说明

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