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

📄 execqual.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
		/*		 * 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);		}		/*		 * 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?		 */		MemSet(&fcinfo, 0, sizeof(fcinfo));		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 return NULL (actually an empty set).		 */		if (fcache->func.fn_strict)		{			int			i;			for (i = 0; i < fcinfo.nargs; i++)			{				if (fcinfo.argnull[i])				{					*returnDesc = NULL;					return NULL;				}			}		}	}	else	{		/* Treat funcexpr as a generic expression */		direct_function_call = false;	}	funcrettype = exprType((Node *) funcexpr->expr);	/*	 * 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.	 */	fcinfo.resultinfo = (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;	/*	 * Switch to short-lived context for calling the function or	 * expression.	 */	callerContext = 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;		/*		 * 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.			 *			 * Note: if function returns an empty set, we don't build a			 * tupdesc or tuplestore (since we can't get a tupdesc in the			 * function-returning-tuple case)			 */			if (rsinfo.isDone == ExprEndResult)				break;			/*			 * If first time through, build tupdesc and tuplestore for			 * result			 */			if (first_time)			{				oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);				if (funcrettype == RECORDOID ||					get_typtype(funcrettype) == 'c')				{					/*					 * Composite type, so function should have returned a					 * TupleTableSlot; use its descriptor					 */					slot = (TupleTableSlot *) DatumGetPointer(result);					if (fcinfo.isnull || !slot)						ereport(ERROR,								(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),								 errmsg("function returning row cannot return null value")));					if (!IsA(slot, TupleTableSlot) ||						!slot->ttc_tupleDescriptor)						ereport(ERROR,								(errcode(ERRCODE_DATATYPE_MISMATCH),								 errmsg("function returning row did not return a valid tuple slot")));					tupdesc = CreateTupleDescCopy(slot->ttc_tupleDescriptor);					returnsTuple = true;				}				else				{					/*					 * Scalar type, so make a single-column descriptor					 */					tupdesc = CreateTemplateTupleDesc(1, false);					TupleDescInitEntry(tupdesc,									   (AttrNumber) 1,									   "column",									   funcrettype,									   -1,									   0,									   false);				}				tupstore = tuplestore_begin_heap(true, false, SortMem);				MemoryContextSwitchTo(oldcontext);				rsinfo.setResult = tupstore;				rsinfo.setDesc = tupdesc;			}			/*			 * Store current resultset item.			 */			if (returnsTuple)			{				slot = (TupleTableSlot *) DatumGetPointer(result);				if (fcinfo.isnull ||					!slot ||					!IsA(slot, TupleTableSlot) ||					TupIsNull(slot))					ereport(ERROR,							(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),							 errmsg("function returning row cannot return null value")));				tuple = slot->val;			}			else			{				char		nullflag;				nullflag = fcinfo.isnull ? 'n' : ' ';				tuple = heap_formtuple(tupdesc, &result, &nullflag);			}			oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);			tuplestore_puttuple(tupstore, tuple);			MemoryContextSwitchTo(oldcontext);			/*			 * Are we done?			 */			if (rsinfo.isDone != ExprMultipleResult)				break;		}		else if (rsinfo.returnMode == SFRM_Materialize)		{			/* check we're on the same page as the function author */			if (!first_time || rsinfo.isDone != ExprSingleResult)				ereport(ERROR,						(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),						 errmsg("table-function protocol for materialize mode was not followed")));			/* Done evaluating the set result */			break;		}		else			ereport(ERROR,					(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),					 errmsg("unrecognized table-function returnMode: %d",							(int) rsinfo.returnMode)));		first_time = false;	}	MemoryContextSwitchTo(callerContext);	/* The returned pointers are those in rsinfo */	*returnDesc = rsinfo.setDesc;	return rsinfo.setResult;}/* ---------------------------------------------------------------- *		ExecEvalFunc *		ExecEvalOper * *		Evaluate the functional result of a list of arguments by calling the *		function manager. * ---------------------------------------------------------------- *//* ---------------------------------------------------------------- *		ExecEvalFunc * ---------------------------------------------------------------- */static DatumExecEvalFunc(FuncExprState *fcache,			 ExprContext *econtext,			 bool *isNull,			 ExprDoneCond *isDone){	/*	 * 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);	}	return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);}/* ---------------------------------------------------------------- *		ExecEvalOper * ---------------------------------------------------------------- */static DatumExecEvalOper(FuncExprState *fcache,			 ExprContext *econtext,			 bool *isNull,			 ExprDoneCond *isDone){	/*	 * Initialize function cache if first time through	 */	if (fcache->func.fn_oid == InvalidOid)	{		OpExpr	   *op = (OpExpr *) fcache->xprstate.expr;		init_fcache(op->opfuncid, fcache, econtext->ecxt_per_query_memory);	}	return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);}/* ---------------------------------------------------------------- *		ExecEvalDistinct * * IS DISTINCT FROM must evaluate arguments to determine whether * they are NULL; if either is NULL then the result is already * known. If neither is NULL, then proceed to evaluate the * function. Note that this is *always* derived from the equals * operator, but since we need special processing of the arguments * we can not simply reuse ExecEvalOper() or ExecEvalFunc(). * ---------------------------------------------------------------- */static DatumExecEvalDistinct(FuncExprState *fcache,				 ExprContext *econtext,				 bool *isNull){	Datum		result;	FunctionCallInfoData fcinfo;	ExprDoneCond argDone;	List	   *argList;	/*	 * Initialize function cache if first time through	 */	if (fcache->func.fn_oid == InvalidOid)	{		DistinctExpr *op = (DistinctExpr *) fcache->xprstate.expr;		init_fcache(op->opfuncid, fcache, econtext->ecxt_per_query_memory);		Assert(!fcache->func.fn_retset);	}	/*	 * extract info from fcache	 */	argList = fcache->args;	/* Need to prep callinfo structure */	MemSet(&fcinfo, 0, sizeof(fcinfo));	fcinfo.flinfo = &(fcache->func);	argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext);	if (argDone != ExprSingleResult)		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),			 errmsg("IS DISTINCT FROM does not support set arguments")));	Assert(fcinfo.nargs == 2);	if (fcinfo.argnull[0] && fcinfo.argnull[1])	{		/* Both NULL? Then is not distinct... */		result = BoolGetDatum(FALSE);	}	else if (fcinfo.argnull[0] || fcinfo.argnull[1])	{		/* Only one is NULL? Then is distinct... */		result = BoolGetDatum(TRUE);	}	else	{		fcinfo.isnull = false;		result = FunctionCallInvoke(&fcinfo);		*isNull = fcinfo.isnull;		/* Must invert result of "=" */		result = BoolGetDatum(!DatumGetBool(result));	}	return result;}/* * ExecEvalScalarArrayOp * * Evaluate "scalar op ANY/ALL (array)".  The operator always yields boolean, * and we combine the results across all array elements using OR and AND * (for ANY and ALL respectively).	Of course we short-circuit as soon as * the result is known. */static DatumExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,					  ExprContext *econtext, bool *isNull){	ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr;	bool		useOr = opexpr->useOr;	ArrayType  *arr;	int			nitems;	Datum		result;	bool		resultnull;	FunctionCallInfoData fcinfo;	ExprDoneCond argDone;	int			i;	int16		typlen;	bool		typbyval;	char		typalign;	char	   *s;	/*	 * Initialize function cache if first time through	 */	if (sstate->fxprstate.func.fn_oid == InvalidOid)	{		init_fcache(opexpr->opfuncid, &sstate->fxprstate,					econtext->ecxt_per_query_memory);		Assert(!sstate->fxprstate.func.fn_retset);	}	/* Need to prep callinfo structure */	MemSet(&fcinfo, 0, sizeof(fcinfo));	fcinfo.flinfo = &(sstate->fxprstate.func);	argDone = ExecEvalFuncArgs(&fcinfo, sstate->fxprstate.args, econtext);	if (argDone != ExprSingleResult)		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),		   errmsg("op ANY/ALL (array) does not support set arguments")));	Assert(fcinfo.nargs == 2);	/*	 * If the array is NULL then we return NULL --- it's not very	 * meaningful to do anything else, even if the operator isn't strict.	 */	if (fcinfo.argnull[1])	{		*isNull = true;		return (Datum) 0;	}	/* Else okay to fetch and detoast the array */	arr = DatumGetArrayTypeP(fcinfo.arg[1]);	/*	 * If the array is empty, we return either FALSE or TRUE per the useOr	 * flag.  This is correct even if the scalar is NULL; since we would	 * evaluate the operator zero times, it matters not whether it would	 * want to return NULL.	 */	nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));	if (nitems <= 0)		return BoolGetDatum(!useOr);	/*	 * If the scalar is NULL, and the function is strict, return NULL.	 * This is just to avoid having to test for strictness inside the	 * loop.  (XXX but if arrays could have null elements, we'd need a	 * test anyway.)	 */	if (fcinfo.argnull[0] && sstate->fxprstate.func.fn_strict)	{		*isNull = true;		return (Datum) 0;	}	/*	 * We arrange to look up info about the element type only once per	 * series of calls, assuming the element type doesn't change	 * underneath us.	 */	if (sstate->element_type != ARR_ELEMTYPE(arr))	{		get_typlenbyvalalign(ARR_ELEMTYPE(arr),							 &sstate->typlen,							 &sstate->typbyval,							 &sstate->typalign);		sstate->element_type = ARR_ELEMTYPE(arr);	}	typlen = sstate->typlen;	typbyval = sstate->typbyval;	typalign = sstate->typalign;	result = BoolGetDatum(!useOr);	resultnull = false;	/* Loop over the array elements */	s = (char *) ARR_DATA_PTR(arr);	for (i = 0; i < nitems; i++)	{		Datum		elt;		Datum		thisresult;		/* Get array element */		elt = fetch_att(s, typbyval, typlen);		s = att_addlength(s, typlen, PointerGetDatum(s));		s = (char *) att_align(s, typalign);		/* Call comparison function */		fcinfo.arg[1] = elt;		fcinfo.argnull[1] = false;		fcinfo.isnull = false;		thisresult = FunctionCallInvoke(&fcinfo);		/* Combine results per OR or AND semantics */		if (fcinfo.isnull)			resultnull = true;		else if (useOr)

⌨️ 快捷键说明

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