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

📄 execqual.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (attname == NULL)		elog(ERROR, "GetAttributeByName: Invalid attribute name");	if (isNull == (bool *) NULL)		elog(ERROR, "GetAttributeByName: a NULL isNull flag was passed");	if (TupIsNull(slot))	{		*isNull = true;		return (char *) NULL;	}	tupdesc = slot->ttc_tupleDescriptor;	natts = slot->val->t_data->t_natts;	attrno = InvalidAttrNumber;	for (i = 0; i < tupdesc->natts; i++)	{		if (namestrcmp(&(tupdesc->attrs[i]->attname), attname) == 0)		{			attrno = tupdesc->attrs[i]->attnum;			break;		}	}	if (attrno == InvalidAttrNumber)		elog(ERROR, "GetAttributeByName: attribute %s not found", attname);	retval = heap_getattr(slot->val,						  attrno,						  tupdesc,						  isNull);	if (*isNull)		return (char *) NULL;	return (char *) retval;}/* XXX name for catalogs */#ifdef NOT_USEDchar *att_by_name(TupleTableSlot *slot, char *attname, bool *isNull){	return GetAttributeByName(slot, attname, isNull);}#endifstatic voidExecEvalFuncArgs(FunctionCachePtr fcache,				 ExprContext *econtext,				 List *argList,				 Datum argV[],				 bool *argIsDone){	int			i;	bool		argIsNull,			   *nullVect;	List	   *arg;	nullVect = fcache->nullVect;	i = 0;	foreach(arg, argList)	{		/*		 * evaluate the expression, in general functions cannot take sets		 * as arguments but we make an exception in the case of nested dot		 * expressions.  We have to watch out for this case here.		 */		argV[i] = (Datum)			ExecEvalExpr((Node *) lfirst(arg),						 econtext,						 &argIsNull,						 argIsDone);		if (!(*argIsDone))		{			Assert(i == 0);			fcache->setArg = (char *) argV[0];			fcache->hasSetArg = true;		}		if (argIsNull)			nullVect[i] = true;		else			nullVect[i] = false;		i++;	}}/* *		ExecMakeFunctionResult */static DatumExecMakeFunctionResult(Node *node,					   List *arguments,					   ExprContext *econtext,					   bool *isNull,					   bool *isDone){	Datum		argV[MAXFMGRARGS];	FunctionCachePtr fcache;	Func	   *funcNode = NULL;	Oper	   *operNode = NULL;	bool		funcisset = false;	/*	 * This is kind of ugly, Func nodes now have targetlists so that we	 * know when and what to project out from postquel function results.	 * This means we have to pass the func node all the way down instead	 * of using only the fcache struct as before.  ExecMakeFunctionResult	 * becomes a little bit more of a dual personality as a result.	 */	if (IsA(node, Func))	{		funcNode = (Func *) node;		fcache = funcNode->func_fcache;	}	else	{		operNode = (Oper *) node;		fcache = operNode->op_fcache;	}	/*	 * arguments is a list of expressions to evaluate before passing to	 * the function manager. We collect the results of evaluating the	 * expressions into a datum array (argV) and pass this array to	 * arrayFmgr()	 */	if (fcache->nargs != 0)	{		bool		argDone;		if (fcache->nargs > MAXFMGRARGS)			elog(ERROR, "ExecMakeFunctionResult: too many arguments");		/*		 * If the setArg in the fcache is set we have an argument		 * returning a set of tuples (i.e. a nested dot expression).  We		 * don't want to evaluate the arguments again until the function		 * is done. hasSetArg will always be false until we eval the args		 * for the first time. We should set this in the parser.		 */		if ((fcache->hasSetArg) && fcache->setArg != NULL)		{			argV[0] = (Datum) fcache->setArg;			argDone = false;		}		else			ExecEvalFuncArgs(fcache, econtext, arguments, argV, &argDone);		if ((fcache->hasSetArg) && (argDone))		{			if (isDone)				*isDone = true;			return (Datum) NULL;		}	}	/*	 * If this function is really a set, we have to diddle with things. If	 * the function has already been called at least once, then the setArg	 * field of the fcache holds the OID of this set in pg_proc.  (This is	 * not quite legit, since the setArg field is really for functions	 * which take sets of tuples as input - set functions take no inputs	 * at all.	But it's a nice place to stash this value, for now.)	 *	 * If this is the first call of the set's function, then the call to	 * ExecEvalFuncArgs above just returned the OID of the pg_proc tuple	 * which defines this set.	So replace the existing funcid in the	 * funcnode with the set's OID.  Also, we want a new fcache which	 * points to the right function, so get that, now that we have the	 * right OID.  Also zero out the argV, since the real set doesn't take	 * any arguments.	 */	if (((Func *) node)->funcid == F_SETEVAL)	{		funcisset = true;		if (fcache->setArg)		{			argV[0] = 0;			((Func *) node)->funcid = (Oid) PointerGetDatum(fcache->setArg);		}		else		{			((Func *) node)->funcid = (Oid) argV[0];			setFcache(node, argV[0], NIL, econtext);			fcache = ((Func *) node)->func_fcache;			fcache->setArg = (char *) argV[0];			argV[0] = (Datum) 0;		}	}	/*	 * now return the value gotten by calling the function manager,	 * passing the function the evaluated parameter values.	 */	if (fcache->language == SQLlanguageId)	{		Datum		result;		Assert(funcNode);		result = postquel_function(funcNode, (char **) argV, isNull, isDone);		/*		 * finagle the situation where we are iterating through all		 * results in a nested dot function (whose argument function		 * returns a set of tuples) and the current function finally		 * finishes.  We need to get the next argument in the set and run		 * the function all over again.  This is getting unclean.		 */		if ((*isDone) && (fcache->hasSetArg))		{			bool		argDone;			ExecEvalFuncArgs(fcache, econtext, arguments, argV, &argDone);			if (argDone)			{				fcache->setArg = (char *) NULL;				*isDone = true;				result = (Datum) NULL;			}			else				result = postquel_function(funcNode,										   (char **) argV,										   isNull,										   isDone);		}		if (funcisset)		{			/*			 * reset the funcid so that next call to this routine will			 * still recognize this func as a set. Note that for now we			 * assume that the set function in pg_proc must be a Postquel			 * function - the funcid is not reset below for C functions.			 */			((Func *) node)->funcid = F_SETEVAL;			/*			 * If we're done with the results of this function, get rid of			 * its func cache.			 */			if (*isDone)				((Func *) node)->func_fcache = NULL;		}		return result;	}	else	{		int			i;		if (isDone)			*isDone = true;		for (i = 0; i < fcache->nargs; i++)			if (fcache->nullVect[i] == true)				*isNull = true;		return (Datum) fmgr_c(&fcache->func, (FmgrValues *) argV, isNull);	}}/* ---------------------------------------------------------------- *		ExecEvalOper *		ExecEvalFunc * *		Evaluate the functional result of a list of arguments by calling the *		function manager.  Note that in the case of operator expressions, the *		optimizer had better have already replaced the operator OID with the *		appropriate function OID or we're hosed. * * old comments *		Presumably the function manager will not take null arguments, so we *		check for null arguments before sending the arguments to (fmgr). * *		Returns the value of the functional expression. * ---------------------------------------------------------------- *//* ---------------------------------------------------------------- *		ExecEvalOper * ---------------------------------------------------------------- */static DatumExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull){	Oper	   *op;	List	   *argList;	FunctionCachePtr fcache;	bool		isDone;	/*	 * an opclause is a list (op args).  (I think)	 *	 * we extract the oid of the function associated with the op and then	 * pass the work onto ExecMakeFunctionResult which evaluates the	 * arguments and returns the result of calling the function on the	 * evaluated arguments.	 */	op = (Oper *) opClause->oper;	argList = opClause->args;	/*	 * get the fcache from the Oper node. If it is NULL, then initialize	 * it	 */	fcache = op->op_fcache;	if (fcache == NULL)	{		setFcache((Node *) op, op->opid, argList, econtext);		fcache = op->op_fcache;	}	/*	 * call ExecMakeFunctionResult() with a dummy isDone that we ignore.	 * We don't have operator whose arguments are sets.	 */	return ExecMakeFunctionResult((Node *) op, argList, econtext, isNull, &isDone);}/* ---------------------------------------------------------------- *		ExecEvalFunc * ---------------------------------------------------------------- */static DatumExecEvalFunc(Expr *funcClause,			 ExprContext *econtext,			 bool *isNull,			 bool *isDone){	Func	   *func;	List	   *argList;	FunctionCachePtr fcache;	/*	 * an funcclause is a list (func args).  (I think)	 *	 * we extract the oid of the function associated with the func node and	 * then pass the work onto ExecMakeFunctionResult which evaluates the	 * arguments and returns the result of calling the function on the	 * evaluated arguments.	 *	 * this is nearly identical to the ExecEvalOper code.	 */	func = (Func *) funcClause->oper;	argList = funcClause->args;	/*	 * get the fcache from the Func node. If it is NULL, then initialize	 * it	 */	fcache = func->func_fcache;	if (fcache == NULL)	{		setFcache((Node *) func, func->funcid, argList, econtext);		fcache = func->func_fcache;	}	return ExecMakeFunctionResult((Node *) func, argList, econtext, isNull, isDone);}/* ---------------------------------------------------------------- *		ExecEvalNot *		ExecEvalOr *		ExecEvalAnd * *		Evaluate boolean expressions.  Evaluation of 'or' is *		short-circuited when the first true (or null) value is found. * *		The query planner reformulates clause expressions in the *		qualification to conjunctive normal form.  If we ever get *		an AND to evaluate, we can be sure that it's not a top-level *		clause in the qualification, but appears lower (as a function *		argument, for example), or in the target list.	Not that you *		need to know this, mind you... * ---------------------------------------------------------------- */static DatumExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull){	Datum		expr_value;	Node	   *clause;	bool		isDone;	clause = lfirst(notclause->args);	/*	 * We don't iterate over sets in the quals, so pass in an isDone flag,	 * but ignore it.	 */	expr_value = ExecEvalExpr(clause, econtext, isNull, &isDone);	/*	 * if the expression evaluates to null, then we just cascade the null	 * back to whoever called us.	 */	if (*isNull)		return expr_value;	/*	 * evaluation of 'not' is simple.. expr is false, then return 'true'	 * and vice versa.	 */	if (DatumGetInt32(expr_value) == 0)		return (Datum) true;	return (Datum) false;}/* ---------------------------------------------------------------- *		ExecEvalOr * ---------------------------------------------------------------- */static DatumExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull){	List	   *clauses;	List	   *clause;	bool		isDone;	bool		IsNull;	Datum		const_value = 0;	IsNull = false;	clauses = orExpr->args;	/*	 * we use three valued logic functions here... we evaluate each of the	 * clauses in turn, as soon as one is true we return that value.  If	 * none is true and  none of the clauses evaluate to NULL we return	 * the value of the last clause evaluated (which should be false) with	 * *isNull set to false else if none is true and at least one clause	 * evaluated to NULL we set *isNull flag to true -	 */	foreach(clause, clauses)	{		/*		 * We don't iterate over sets in the quals, so pass in an isDone		 * flag, but ignore it.		 */		const_value = ExecEvalExpr((Node *) lfirst(clause),								   econtext,								   isNull,								   &isDone);		/*		 * if the expression evaluates to null, then we remember it in the		 * local IsNull flag, if none of the clauses are true then we need		 * to set *isNull to true again.		 */		if (*isNull)		{			IsNull = *isNull;			/*			 * Many functions don't (or can't!) check if an argument is			 * NULL or NOT_NULL and may return TRUE (1) with *isNull TRUE			 * (an_int4_column <> 1: int4ne returns TRUE for NULLs). Not			 * having time to fix the function manager I want to fix OR:			 * if we had 'x <> 1 OR x isnull' then when x is NULL TRUE was			 * returned by the 'x <> 1' clause ... but ExecQualClause says			 * that the qualification should *fail* if isnull is TRUE for			 * any value returned by ExecEvalExpr. So, force this rule			 * here: if isnull is TRUE then the clause failed. Note:			 * nullvalue() & nonnullvalue() always sets isnull to FALSE			 * for NULLs. - vadim 09/22/97			 */			const_value = 0;		}		/*		 * if we have a true result, then we return it.		 */		if (DatumGetInt32(const_value) != 0)			return const_value;	}	/* IsNull is true if at least one clause evaluated to NULL */	*isNull = IsNull;	return const_value;}/* ---------------------------------------------------------------- *		ExecEvalAnd * ---------------------------------------------------------------- */static DatumExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull){	List	   *clauses;	List	   *clause;	Datum		const_value = 0;	bool		isDone;	bool		IsNull;	IsNull = false;	clauses = andExpr->args;	/*	 * we evaluate each of the clauses in turn, as soon as one is false we	 * return that value.  If none are false or NULL then we return the	 * value of the last clause evaluated, which should be true.	 */	foreach(clause, clauses)	{		/*		 * We don't iterate over sets in the quals, so pass in an isDone		 * flag, but ignore it.		 */		const_value = ExecEvalExpr((Node *) lfirst(clause),								   econtext,								   isNull,								   &isDone);		/*		 * if the expression evaluates to null, then we remember it in		 * IsNull, if none of the clauses after this evaluates to false we		 * will have to set *isNull to true again.		 */		if (*isNull)			IsNull = *isNull;		/*		 * if we have a false result, then we return it, since the		 * conjunction must be false.		 */		if (DatumGetInt32(const_value) == 0)			return const_value;	}	*isNull = IsNull;	return const_value;}/* ---------------------------------------------------------------- *		ExecEvalCase *

⌨️ 快捷键说明

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