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

📄 execqual.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
		char	   *thisParamName = expression->paramname;		bool		matchFound = false;		if (paramList != NULL)		{			while (paramList->kind != PARAM_INVALID && !matchFound)			{				if (thisParamKind == paramList->kind)				{					switch (thisParamKind)					{						case PARAM_NAMED:							if (strcmp(paramList->name, thisParamName) == 0)								matchFound = true;							break;						case PARAM_NUM:							if (paramList->id == thisParamId)								matchFound = true;							break;						default:							elog(ERROR, "unrecognized paramkind: %d",								 thisParamKind);					}				}				if (!matchFound)					paramList++;			}					/* while */		}						/* if */		if (!matchFound)		{			if (thisParamKind == PARAM_NAMED)				ereport(ERROR,						(errcode(ERRCODE_UNDEFINED_OBJECT),						 errmsg("no value found for parameter \"%s\"",								thisParamName)));			else				ereport(ERROR,						(errcode(ERRCODE_UNDEFINED_OBJECT),						 errmsg("no value found for parameter %d",								thisParamId)));		}		*isNull = paramList->isnull;		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(). */DatumGetAttributeByNum(TupleTableSlot *slot,				  AttrNumber attrno,				  bool *isNull){	Datum		retval;	if (!AttributeNumberIsValid(attrno))		elog(ERROR, "invalid attribute number %d", attrno);	if (isNull == (bool *) NULL)		elog(ERROR, "a NULL isNull pointer was passed");	if (TupIsNull(slot))	{		*isNull = true;		return (Datum) 0;	}	retval = heap_getattr(slot->val,						  attrno,						  slot->ttc_tupleDescriptor,						  isNull);	if (*isNull)		return (Datum) 0;	return retval;}DatumGetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull){	AttrNumber	attrno;	TupleDesc	tupdesc;	Datum		retval;	int			natts;	int			i;	if (attname == NULL)		elog(ERROR, "invalid attribute name");	if (isNull == (bool *) NULL)		elog(ERROR, "a NULL isNull pointer was passed");	if (TupIsNull(slot))	{		*isNull = true;		return (Datum) 0;	}	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, "attribute \"%s\" does not exist", attname);	retval = heap_getattr(slot->val,						  attrno,						  tupdesc,						  isNull);	if (*isNull)		return (Datum) 0;	return retval;}/* * init_fcache - initialize a FuncExprState node during first use */voidinit_fcache(Oid foid, FuncExprState *fcache, MemoryContext fcacheCxt){	AclResult	aclresult;	/* Check permission to call function */	aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);	if (aclresult != ACLCHECK_OK)		aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid));	/* Safety check (should never fail, as parser should check sooner) */	if (length(fcache->args) > FUNC_MAX_ARGS)		elog(ERROR, "too many arguments");	/* Set up the primary fmgr lookup information */	fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);	/* Initialize additional info */	fcache->setArgsValid = false;	fcache->shutdown_reg = false;	fcache->func.fn_expr = (Node *) fcache->xprstate.expr;}/* * callback function in case a FuncExpr returning a set needs to be shut down * before it has been run to completion */static voidShutdownFuncExpr(Datum arg){	FuncExprState *fcache = (FuncExprState *) DatumGetPointer(arg);	/* Clear any active set-argument state */	fcache->setArgsValid = false;	/* execUtils will deregister the callback... */	fcache->shutdown_reg = false;}/* * Evaluate arguments for a function. */static ExprDoneCondExecEvalFuncArgs(FunctionCallInfo fcinfo,				 List *argList,				 ExprContext *econtext){	ExprDoneCond argIsDone;	int			i;	List	   *arg;	argIsDone = ExprSingleResult;		/* default assumption */	i = 0;	foreach(arg, argList)	{		ExprDoneCond thisArgIsDone;		fcinfo->arg[i] = ExecEvalExpr((ExprState *) lfirst(arg),									  econtext,									  &fcinfo->argnull[i],									  &thisArgIsDone);		if (thisArgIsDone != ExprSingleResult)		{			/*			 * We allow only one argument to have a set value; we'd need			 * much more complexity to keep track of multiple set			 * arguments (cf. ExecTargetList) and it doesn't seem worth			 * it.			 */			if (argIsDone != ExprSingleResult)				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("functions and operators can take at most one set argument")));			argIsDone = thisArgIsDone;		}		i++;	}	fcinfo->nargs = i;	return argIsDone;}/* *		ExecMakeFunctionResult * * Evaluate the arguments to a function and then the function itself. */DatumExecMakeFunctionResult(FuncExprState *fcache,					   ExprContext *econtext,					   bool *isNull,					   ExprDoneCond *isDone){	List	   *arguments = fcache->args;	Datum		result;	FunctionCallInfoData fcinfo;	ReturnSetInfo rsinfo;		/* for functions returning sets */	ExprDoneCond argDone;	bool		hasSetArg;	int			i;	/*	 * arguments is a list of expressions to evaluate before passing to	 * the function manager.  We skip the evaluation if it was already	 * done in the previous call (ie, we are continuing the evaluation of	 * a set-valued function).	Otherwise, collect the current argument	 * values into fcinfo.	 */	if (!fcache->setArgsValid)	{		/* Need to prep callinfo structure */		MemSet(&fcinfo, 0, sizeof(fcinfo));		fcinfo.flinfo = &(fcache->func);		argDone = ExecEvalFuncArgs(&fcinfo, arguments, econtext);		if (argDone == ExprEndResult)		{			/* input is an empty set, so return an empty set. */			*isNull = true;			if (isDone)				*isDone = ExprEndResult;			else				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("set-valued function called in context that cannot accept a set")));			return (Datum) 0;		}		hasSetArg = (argDone != ExprSingleResult);	}	else	{		/* Copy callinfo from previous evaluation */		memcpy(&fcinfo, &fcache->setArgs, sizeof(fcinfo));		hasSetArg = fcache->setHasSetArg;		/* Reset flag (we may set it again below) */		fcache->setArgsValid = false;	}	/*	 * If function returns set, prepare a resultinfo node for	 * communication	 */	if (fcache->func.fn_retset)	{		fcinfo.resultinfo = (Node *) &rsinfo;		rsinfo.type = T_ReturnSetInfo;		rsinfo.econtext = econtext;		rsinfo.expectedDesc = NULL;		rsinfo.allowedModes = (int) SFRM_ValuePerCall;		rsinfo.returnMode = SFRM_ValuePerCall;		/* isDone is filled below */		rsinfo.setResult = NULL;		rsinfo.setDesc = NULL;	}	/*	 * now return the value gotten by calling the function manager,	 * passing the function the evaluated parameter values.	 */	if (fcache->func.fn_retset || hasSetArg)	{		/*		 * We need to return a set result.	Complain if caller not ready		 * to accept one.		 */		if (isDone == NULL)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("set-valued function called in context that cannot accept a set")));		/*		 * This loop handles the situation where we have both a set		 * argument and a set-valued function.	Once we have exhausted the		 * function's value(s) for a particular argument value, we have to		 * get the next argument value and start the function over again.		 * We might have to do it more than once, if the function produces		 * an empty result set for a particular input value.		 */		for (;;)		{			/*			 * If function is strict, and there are any NULL arguments,			 * skip calling the function (at least for this set of args).			 */			bool		callit = true;			if (fcache->func.fn_strict)			{				for (i = 0; i < fcinfo.nargs; i++)				{					if (fcinfo.argnull[i])					{						callit = false;						break;					}				}			}			if (callit)			{				fcinfo.isnull = false;				rsinfo.isDone = ExprSingleResult;				result = FunctionCallInvoke(&fcinfo);				*isNull = fcinfo.isnull;				*isDone = rsinfo.isDone;			}			else			{				result = (Datum) 0;				*isNull = true;				*isDone = ExprEndResult;			}			if (*isDone != ExprEndResult)			{				/*				 * Got a result from current argument.	If function itself				 * returns set, save the current argument values to re-use				 * on the next call.				 */				if (fcache->func.fn_retset)				{					memcpy(&fcache->setArgs, &fcinfo, sizeof(fcinfo));					fcache->setHasSetArg = hasSetArg;					fcache->setArgsValid = true;					/* Register cleanup callback if we didn't already */					if (!fcache->shutdown_reg)					{						RegisterExprContextCallback(econtext,													ShutdownFuncExpr,													PointerGetDatum(fcache));						fcache->shutdown_reg = true;					}				}				/*				 * Make sure we say we are returning a set, even if the				 * function itself doesn't return sets.				 */				*isDone = ExprMultipleResult;				break;			}			/* Else, done with this argument */			if (!hasSetArg)				break;			/* input not a set, so done */			/* Re-eval args to get the next element of the input set */			argDone = ExecEvalFuncArgs(&fcinfo, arguments, econtext);			if (argDone != ExprMultipleResult)			{				/* End of argument set, so we're done. */				*isNull = true;				*isDone = ExprEndResult;				result = (Datum) 0;				break;			}			/*			 * If we reach here, loop around to run the function on the			 * new argument.			 */		}	}	else	{		/*		 * Non-set case: much easier.		 *		 * If function is strict, and there are any NULL arguments, skip		 * calling the function and return NULL.		 */		if (fcache->func.fn_strict)		{			for (i = 0; i < fcinfo.nargs; i++)			{				if (fcinfo.argnull[i])				{					*isNull = true;					return (Datum) 0;				}			}		}		fcinfo.isnull = false;		result = FunctionCallInvoke(&fcinfo);		*isNull = fcinfo.isnull;	}	return result;}/* *		ExecMakeTableFunctionResult * * Evaluate a table function, producing a materialized result in a Tuplestore * object.	(If function returns an empty set, we just return NULL instead.) */Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr,							ExprContext *econtext,							TupleDesc expectedDesc,							TupleDesc *returnDesc){	Tuplestorestate *tupstore = NULL;	TupleDesc	tupdesc = NULL;	Oid			funcrettype;	FunctionCallInfoData fcinfo;	ReturnSetInfo rsinfo;	MemoryContext callerContext;	MemoryContext oldcontext;	TupleTableSlot *slot;	bool		direct_function_call;	bool		first_time = true;	bool		returnsTuple = false;	/*	 * Normally the passed expression tree will be a FuncExprState, since	 * the grammar only allows a function call at the top level of a table	 * function reference.	However, if the function doesn't return set	 * then the planner might have replaced the function call via	 * constant-folding or inlining.  So if we see any other kind of	 * expression node, execute it via the general ExecEvalExpr() code;	 * the only difference is that we don't get a chance to pass a special	 * ReturnSetInfo to any functions buried in the expression.	 */	if (funcexpr && IsA(funcexpr, FuncExprState) &&		IsA(funcexpr->expr, FuncExpr))	{		FuncExprState *fcache = (FuncExprState *) funcexpr;		ExprDoneCond argDone;

⌨️ 快捷键说明

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