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

📄 execqual.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* Need to prep callinfo structure */		InitFunctionCallInfoData(fcinfo, &(fcache->func), 0, NULL, NULL);		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 && *isDone == ExprMultipleResult)				{					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.				 */				if (hasSetArg)					*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.		 *		 * We change the ExprState function pointer to use the simpler		 * ExecMakeFunctionResultNoSets on subsequent calls.  This amounts to		 * assuming that no argument can return a set if it didn't do so the		 * first time.		 */		fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;		if (isDone)			*isDone = ExprSingleResult;		/*		 * 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;}/* *		ExecMakeFunctionResultNoSets * * Simplified version of ExecMakeFunctionResult that can only handle * non-set cases.  Hand-tuned for speed. */static DatumExecMakeFunctionResultNoSets(FuncExprState *fcache,							 ExprContext *econtext,							 bool *isNull,							 ExprDoneCond *isDone){	ListCell   *arg;	Datum		result;	FunctionCallInfoData fcinfo;	int			i;	/* Guard against stack overflow due to overly complex expressions */	check_stack_depth();	if (isDone)		*isDone = ExprSingleResult;	/* inlined, simplified version of ExecEvalFuncArgs */	i = 0;	foreach(arg, fcache->args)	{		ExprState  *argstate = (ExprState *) lfirst(arg);		fcinfo.arg[i] = ExecEvalExpr(argstate,									 econtext,									 &fcinfo.argnull[i],									 NULL);		i++;	}	InitFunctionCallInfoData(fcinfo, &(fcache->func), i, NULL, NULL);	/*	 * If function is strict, and there are any NULL arguments, skip calling	 * the function and return NULL.	 */	if (fcache->func.fn_strict)	{		while (--i >= 0)		{			if (fcinfo.argnull[i])			{				*isNull = true;				return (Datum) 0;			}		}	}	/* fcinfo.isnull = false; */	/* handled by InitFunctionCallInfoData */	result = FunctionCallInvoke(&fcinfo);	*isNull = fcinfo.isnull;	return result;}/* *		ExecMakeTableFunctionResult * * Evaluate a table function, producing a materialized result in a Tuplestore * object.	*returnDesc is set to the tupledesc actually returned by the * function, or NULL if it didn't provide one. */Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr,							ExprContext *econtext,							TupleDesc expectedDesc,							TupleDesc *returnDesc){	Tuplestorestate *tupstore = NULL;	TupleDesc	tupdesc = NULL;	Oid			funcrettype;	bool		returnsTuple;	bool		returnsSet = false;	FunctionCallInfoData fcinfo;	ReturnSetInfo rsinfo;	HeapTupleData tmptup;	MemoryContext callerContext;	MemoryContext oldcontext;	bool		direct_function_call;	bool		first_time = true;	callerContext = CurrentMemoryContext;	funcrettype = exprType((Node *) funcexpr->expr);	returnsTuple = (funcrettype == RECORDOID ||					get_typtype(funcrettype) == 'c');	/*	 * Prepare a resultinfo node for communication.  We always do this even if	 * not expecting a set result, so that we can pass expectedDesc.  In the	 * generic-expression case, the expression doesn't actually get to see the	 * resultinfo, but set it up anyway because we use some of the fields as	 * our own state variables.	 */	InitFunctionCallInfoData(fcinfo, NULL, 0, NULL, (Node *) &rsinfo);	rsinfo.type = T_ReturnSetInfo;	rsinfo.econtext = econtext;	rsinfo.expectedDesc = expectedDesc;	rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize);	rsinfo.returnMode = SFRM_ValuePerCall;	/* isDone is filled below */	rsinfo.setResult = NULL;	rsinfo.setDesc = NULL;	/*	 * 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;		/*		 * This path is similar to ExecMakeFunctionResult.		 */		direct_function_call = true;		/*		 * Initialize function cache if first time through		 */		if (fcache->func.fn_oid == InvalidOid)		{			FuncExpr   *func = (FuncExpr *) fcache->xprstate.expr;			init_fcache(func->funcid, fcache, econtext->ecxt_per_query_memory);		}		returnsSet = fcache->func.fn_retset;		/*		 * Evaluate the function's argument list.		 *		 * Note: ideally, we'd do this in the per-tuple context, but then the		 * argument values would disappear when we reset the context in the		 * inner loop.	So do it in caller context.  Perhaps we should make a		 * separate context just to hold the evaluated arguments?		 */		fcinfo.flinfo = &(fcache->func);		argDone = ExecEvalFuncArgs(&fcinfo, fcache->args, econtext);		/* We don't allow sets in the arguments of the table function */		if (argDone != ExprSingleResult)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("set-valued function called in context that cannot accept a set")));		/*		 * If function is strict, and there are any NULL arguments, skip		 * calling the function and act like it returned NULL (or an empty		 * set, in the returns-set case).		 */		if (fcache->func.fn_strict)		{			int			i;			for (i = 0; i < fcinfo.nargs; i++)			{				if (fcinfo.argnull[i])					goto no_function_result;			}		}	}	else	{		/* Treat funcexpr as a generic expression */		direct_function_call = false;	}	/*	 * Switch to short-lived context for calling the function or expression.	 */	MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);	/*	 * Loop to handle the ValuePerCall protocol (which is also the same	 * behavior needed in the generic ExecEvalExpr path).	 */	for (;;)	{		Datum		result;		HeapTuple	tuple;		CHECK_FOR_INTERRUPTS();		/*		 * reset per-tuple memory context before each call of the function or		 * expression. This cleans up any local memory the function may leak		 * when called.		 */		ResetExprContext(econtext);		/* Call the function or expression one time */		if (direct_function_call)		{			fcinfo.isnull = false;			rsinfo.isDone = ExprSingleResult;			result = FunctionCallInvoke(&fcinfo);		}		else		{			result = ExecEvalExpr(funcexpr, econtext,								  &fcinfo.isnull, &rsinfo.isDone);		}		/* Which protocol does function want to use? */		if (rsinfo.returnMode == SFRM_ValuePerCall)		{			/*			 * Check for end of result set.			 */			if (rsinfo.isDone == ExprEndResult)				break;			/*			 * Can't do anything very useful with NULL rowtype values. For a			 * function returning set, we consider this a protocol violation			 * (but another alternative would be to just ignore the result and			 * "continue" to get another row).	For a function not returning			 * set, we fall out of the loop; we'll cons up an all-nulls result			 * row below.			 */			if (returnsTuple && fcinfo.isnull)			{				if (!returnsSet)					break;				ereport(ERROR,						(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),						 errmsg("function returning set of rows cannot return null value")));			}			/*			 * If first time through, build tupdesc and tuplestore for result			 */			if (first_time)			{				oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);				if (returnsTuple)				{					/*					 * Use the type info embedded in the rowtype Datum to look					 * up the needed tupdesc.  Make a copy for the query.					 */					HeapTupleHeader td;					td = DatumGetHeapTupleHeader(result);					tupdesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(td),											   HeapTupleHeaderGetTypMod(td));					tupdesc = CreateTupleDescCopy(tupdesc);				}				else				{

⌨️ 快捷键说明

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