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

📄 execqual.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * execQual.c *	  Routines to evaluate qualification and targetlist expressions * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/executor/execQual.c,v 1.53 1999/06/12 19:22:40 tgl Exp $ * *------------------------------------------------------------------------- *//* *	 INTERFACE ROUTINES *		ExecEvalExpr	- evaluate an expression and return a datum *		ExecQual		- return true/false if qualification is satisified *		ExecTargetList	- 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. * *		ExecTargetList() 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 <string.h>#include "postgres.h"#include "access/heapam.h"#include "catalog/pg_language.h"#include "executor/execdebug.h"#include "executor/executor.h"#include "executor/execFlatten.h"#include "executor/functions.h"#include "executor/nodeSubplan.h"#include "fmgr.h"#include "nodes/memnodes.h"#include "nodes/primnodes.h"#include "nodes/relation.h"#include "optimizer/clauses.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/fcache.h"#include "utils/fcache2.h"#include "utils/mcxt.h"#include "utils/memutils.h"/* *		externs and constants *//* * XXX Used so we can get rid of use of Const nodes in the executor. * Currently only used by ExecHashGetBucket and set only by ExecMakeVarConst * and by ExecEvalArrayRef. */bool		execConstByVal;int			execConstLen;/* static functions decls */static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull);static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,				 bool *isNull, bool *isDone);static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext,			 bool *isNull, bool *isDone);static void ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext,				 List *argList, Datum argV[], bool *argIsDone);static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull);static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext,			 bool *isNull);static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);static Datum ExecMakeFunctionResult(Node *node, List *arguments,					   ExprContext *econtext, bool *isNull, bool *isDone);static bool ExecQualClause(Node *clause, ExprContext *econtext);/* *	  ExecEvalArrayRef * *	   This function takes an ArrayRef and returns a Const Node if it *	   is an array reference or returns the changed Array Node if it is *		   an array assignment. */static DatumExecEvalArrayRef(ArrayRef *arrayRef,				 ExprContext *econtext,				 bool *isNull,				 bool *isDone){	bool		dummy;	int			i = 0,				j = 0;	ArrayType  *array_scanner;	List	   *upperIndexpr,			   *lowerIndexpr;	Node	   *assgnexpr;	List	   *elt;	IntArray	upper,				lower;	int		   *lIndex;	char	   *dataPtr;	*isNull = false;	array_scanner = (ArrayType *) ExecEvalExpr(arrayRef->refexpr,											   econtext,											   isNull,											   isDone);	if (*isNull)		return (Datum) NULL;	upperIndexpr = arrayRef->refupperindexpr;	foreach(elt, upperIndexpr)	{		upper.indx[i++] = (int32) ExecEvalExpr((Node *) lfirst(elt),											   econtext,											   isNull,											   &dummy);		if (*isNull)			return (Datum) NULL;	}	lowerIndexpr = arrayRef->reflowerindexpr;	lIndex = NULL;	if (lowerIndexpr != NIL)	{		foreach(elt, lowerIndexpr)		{			lower.indx[j++] = (int32) ExecEvalExpr((Node *) lfirst(elt),												   econtext,												   isNull,												   &dummy);			if (*isNull)				return (Datum) NULL;		}		if (i != j)			elog(ERROR,				 "ExecEvalArrayRef: upper and lower indices mismatch");		lIndex = lower.indx;	}	assgnexpr = arrayRef->refassgnexpr;	if (assgnexpr != NULL)	{		dataPtr = (char *) ExecEvalExpr((Node *)										assgnexpr, econtext,										isNull, &dummy);		if (*isNull)			return (Datum) NULL;		execConstByVal = arrayRef->refelembyval;		execConstLen = arrayRef->refelemlength;		if (lIndex == NULL)			return (Datum) array_set(array_scanner, i, upper.indx, dataPtr,									 arrayRef->refelembyval,									 arrayRef->refelemlength,									 arrayRef->refattrlength, isNull);		return (Datum) array_assgn(array_scanner, i, upper.indx,								   lower.indx,								   (ArrayType *) dataPtr,								   arrayRef->refelembyval,								   arrayRef->refelemlength, isNull);	}	execConstByVal = arrayRef->refelembyval;	execConstLen = arrayRef->refelemlength;	if (lIndex == NULL)		return (Datum) array_ref(array_scanner, i, upper.indx,								 arrayRef->refelembyval,								 arrayRef->refelemlength,								 arrayRef->refattrlength, isNull);	return (Datum) array_clip(array_scanner, i, upper.indx, lower.indx,							  arrayRef->refelembyval,							  arrayRef->refelemlength, isNull);}/* ---------------------------------------------------------------- *		ExecEvalAggref * *		Returns a Datum whose value is the value of the precomputed *		aggregate found in the given expression context. * ---------------------------------------------------------------- */static DatumExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull){	*isNull = econtext->ecxt_nulls[aggref->aggno];	return econtext->ecxt_values[aggref->aggno];}/* ---------------------------------------------------------------- *		ExecEvalVar * *		Returns a Datum whose value is the value of a range *		variable with respect to given expression context. * * *		As an entry condition, we expect that the datatype the *		plan expects to get (as told by our "variable" argument) is in *		fact the datatype of the attribute the plan says to fetch (as *		seen in the current context, identified by our "econtext" *		argument). * *		If we fetch a Type A attribute and Caller treats it as if it *		were Type B, there will be undefined results (e.g. crash). *		One way these might mismatch now is that we're accessing a *		catalog class and the type information in the pg_attribute *		class does not match the hardcoded pg_attribute information *		(in pg_attribute.h) for the class in question. * *		We have an Assert to make sure this entry condition is met. * * ---------------------------------------------------------------- */static DatumExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull){	Datum		result;	TupleTableSlot *slot;	AttrNumber	attnum;	HeapTuple	heapTuple;	TupleDesc	tuple_type;	Buffer		buffer;	bool		byval;	int16		len;	/*	 * 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;	buffer = slot->ttc_buffer;	attnum = variable->varattno;	/* (See prolog for explanation of this Assert) */	Assert(attnum <= 0 ||		   (attnum - 1 <= tuple_type->natts - 1 &&			tuple_type->attrs[attnum - 1] != NULL &&			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.	 */		if (attnum == InvalidAttrNumber)	{		TupleTableSlot *tempSlot;		TupleDesc	td;		HeapTuple	tup;		tempSlot = makeNode(TupleTableSlot);		tempSlot->ttc_shouldFree = false;		tempSlot->ttc_descIsNew = true;		tempSlot->ttc_tupleDescriptor = (TupleDesc) NULL;		tempSlot->ttc_buffer = InvalidBuffer;		tempSlot->ttc_whichplan = -1;		tup = heap_copytuple(heapTuple);		td = CreateTupleDescCopy(slot->ttc_tupleDescriptor);		ExecSetSlotDescriptor(tempSlot, td);		ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);		return (Datum) 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 null if att is null	 */	if (*isNull)		return (Datum) NULL;	/*	 * get length and type information.. ??? what should we do about	 * variable length attributes - variable length attributes have their	 * length stored in the first 4 bytes of the memory pointed to by the	 * returned value.. If we can determine that the type is a variable	 * length type, we can do the right thing. -cim 9/15/89	 */	if (attnum < 0)	{		/*		 * If this is a pseudo-att, we get the type and fake the length.		 * There ought to be a routine to return the real lengths, so		 * we'll mark this one ... XXX -mao		 */		len = heap_sysattrlen(attnum);	/* XXX see -mao above */		byval = heap_sysattrbyval(attnum);		/* XXX see -mao above */	}	else	{		len = tuple_type->attrs[attnum - 1]->attlen;		byval = tuple_type->attrs[attnum - 1]->attbyval ? true : false;	}	execConstByVal = byval;	execConstLen = len;	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 replace the param node with the datum *		containing the appropriate information ("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 shoud return a Const node with the *			isnull flag) ?	-cim 10/13/89 * *		Minor modification: Param nodes now have an extra field, *		`paramkind' which specifies the type of parameter *		(see params.h). So while searching the paramList for *		a paramname/value pair, we have also to check for `kind'. * *		NOTE: The last entry in `paramList' is always an *		entry with kind == PARAM_INVALID. * ---------------------------------------------------------------- */DatumExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull){	char	   *thisParameterName;	int			thisParameterKind = expression->paramkind;	AttrNumber	thisParameterId = expression->paramid;	int			matchFound;	ParamListInfo paramList;	if (thisParameterKind == PARAM_EXEC)	{		ParamExecData *prm = &(econtext->ecxt_param_exec_vals[thisParameterId]);		if (prm->execPlan != NULL)			ExecSetParamPlan(prm->execPlan);		Assert(prm->execPlan == NULL);		*isNull = prm->isnull;		return prm->value;	}	thisParameterName = expression->paramname;	paramList = econtext->ecxt_param_list_info;	*isNull = false;	/*	 * search the list with the parameter info to find a matching name. An	 * entry with an InvalidName denotes the last element in the array.	 */	matchFound = 0;	if (paramList != NULL)	{		/*		 * search for an entry in 'paramList' that matches the		 * `expression'.		 */		while (paramList->kind != PARAM_INVALID && !matchFound)		{			switch (thisParameterKind)			{				case PARAM_NAMED:					if (thisParameterKind == paramList->kind &&						strcmp(paramList->name, thisParameterName) == 0)						matchFound = 1;					break;				case PARAM_NUM:					if (thisParameterKind == paramList->kind &&						paramList->id == thisParameterId)						matchFound = 1;					break;				case PARAM_OLD:				case PARAM_NEW:					if (thisParameterKind == paramList->kind &&						paramList->id == thisParameterId)					{						matchFound = 1;						/*						 * sanity check						 */						if (strcmp(paramList->name, thisParameterName) != 0)						{							elog(ERROR,								 "ExecEvalParam: new/old params with same id & diff names");						}					}					break;				default:					/*					 * oops! this is not supposed to happen!					 */					elog(ERROR, "ExecEvalParam: invalid paramkind %d",						 thisParameterKind);			}			if (!matchFound)				paramList++;		}						/* while */	}							/* if */	if (!matchFound)	{		/*		 * ooops! we couldn't find this parameter in the parameter list.		 * Signal an error		 */		elog(ERROR, "ExecEvalParam: Unknown value for parameter %s",			 thisParameterName);	}	/*	 * return the value.	 */	if (paramList->isnull)	{		*isNull = true;		return (Datum) NULL;	}	if (expression->param_tlist != NIL)	{		HeapTuple	tup;		Datum		value;		List	   *tlist = expression->param_tlist;		TargetEntry *tle = (TargetEntry *) lfirst(tlist);		TupleTableSlot *slot = (TupleTableSlot *) paramList->value;		tup = slot->val;		value = ProjectAttribute(slot->ttc_tupleDescriptor,								 tle, tup, isNull);		return value;	}	return paramList->value;}/* ---------------------------------------------------------------- *		ExecEvalOper / ExecEvalFunc support routines * ---------------------------------------------------------------- *//* *		GetAttributeByName *		GetAttributeByNum * *		These are functions which return the value of the *		named attribute out of the tuple from the arg slot.  User defined *		C functions which take a tuple as an argument are expected *		to use this.  Ex: overpaid(EMP) might call GetAttributeByNum(). *//* static but gets called from external functions */char *GetAttributeByNum(TupleTableSlot *slot,				  AttrNumber attrno,				  bool *isNull){	Datum		retval;	if (!AttributeNumberIsValid(attrno))		elog(ERROR, "GetAttributeByNum: Invalid attribute number");	if (!AttrNumberIsForUserDefinedAttr(attrno))		elog(ERROR, "GetAttributeByNum: cannot access system attributes here");	if (isNull == (bool *) NULL)		elog(ERROR, "GetAttributeByNum: a NULL isNull flag was passed");	if (TupIsNull(slot))	{		*isNull = true;		return (char *) NULL;	}	retval = heap_getattr(slot->val,						  attrno,						  slot->ttc_tupleDescriptor,						  isNull);	if (*isNull)		return (char *) NULL;	return (char *) retval;}/* XXX name for catalogs */#ifdef NOT_USEDchar *att_by_num(TupleTableSlot *slot,		   AttrNumber attrno,		   bool *isNull){	return GetAttributeByNum(slot, attrno, isNull);}#endifchar *GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull){	AttrNumber	attrno;	TupleDesc	tupdesc;	Datum		retval;	int			natts;	int			i;

⌨️ 快捷键说明

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