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

📄 functions.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 2 页
字号:
	else		paramLI = (ParamListInfo) NULL;	if (fcache->paramLI)		pfree(fcache->paramLI);	fcache->paramLI = paramLI;}static TupleTableSlot *copy_function_result(SQLFunctionCachePtr fcache,					 TupleTableSlot *resultSlot){	TupleTableSlot *funcSlot;	TupleDesc	resultTd;	HeapTuple	resultTuple;	HeapTuple	newTuple;	Assert(!TupIsNull(resultSlot));	resultTuple = resultSlot->val;	funcSlot = fcache->funcSlot;	if (funcSlot == NULL)		return resultSlot;		/* no need to copy result */	/*	 * If first time through, we have to initialize the funcSlot's tuple	 * descriptor.	 */	if (funcSlot->ttc_tupleDescriptor == NULL)	{		resultTd = CreateTupleDescCopy(resultSlot->ttc_tupleDescriptor);		ExecSetSlotDescriptor(funcSlot, resultTd, true);		ExecSetSlotDescriptorIsNew(funcSlot, true);	}	newTuple = heap_copytuple(resultTuple);	return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true);}static Datumpostquel_execute(execution_state *es,				 FunctionCallInfo fcinfo,				 SQLFunctionCachePtr fcache){	TupleTableSlot *slot;	Datum		value;	if (es->status == F_EXEC_START)		postquel_start(es, fcache);	slot = postquel_getnext(es);	if (TupIsNull(slot))	{		postquel_end(es);		fcinfo->isnull = true;		/*		 * If this isn't the last command for the function we have to		 * increment the command counter so that subsequent commands can		 * see changes made by previous ones.		 */		if (!LAST_POSTQUEL_COMMAND(es))			CommandCounterIncrement();		return (Datum) NULL;	}	if (LAST_POSTQUEL_COMMAND(es))	{		TupleTableSlot *resSlot;		/*		 * Copy the result.  copy_function_result is smart enough to do		 * nothing when no action is called for.  This helps reduce the		 * logic and code redundancy here.		 */		resSlot = copy_function_result(fcache, slot);		/*		 * If we are supposed to return a tuple, we return the tuple slot		 * pointer converted to Datum.	If we are supposed to return a		 * simple value, then project out the first attribute of the		 * result tuple (ie, take the first result column of the final		 * SELECT).		 */		if (fcache->returnsTuple)		{			/*			 * XXX do we need to remove junk attrs from the result tuple?			 * Probably OK to leave them, as long as they are at the end.			 */			value = PointerGetDatum(resSlot);			fcinfo->isnull = false;		}		else		{			value = heap_getattr(resSlot->val,								 1,								 resSlot->ttc_tupleDescriptor,								 &(fcinfo->isnull));			/*			 * Note: if result type is pass-by-reference then we are			 * returning a pointer into the tuple copied by			 * copy_function_result.  This is OK.			 */		}		/*		 * If this is a single valued function we have to end the function		 * execution now.		 */		if (!fcinfo->flinfo->fn_retset)			postquel_end(es);		return value;	}	/*	 * If this isn't the last command for the function, we don't return	 * any results, but we have to increment the command counter so that	 * subsequent commands can see changes made by previous ones.	 */	CommandCounterIncrement();	return (Datum) NULL;}Datumfmgr_sql(PG_FUNCTION_ARGS){	MemoryContext oldcontext;	SQLFunctionCachePtr fcache;	ErrorContextCallback sqlerrcontext;	execution_state *es;	Datum		result = 0;	/*	 * Switch to context in which the fcache lives.  This ensures that	 * parsetrees, plans, etc, will have sufficient lifetime.  The	 * sub-executor is responsible for deleting per-tuple information.	 */	oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);	/*	 * Setup error traceback support for ereport()	 */	sqlerrcontext.callback = sql_exec_error_callback;	sqlerrcontext.arg = fcinfo->flinfo;	sqlerrcontext.previous = error_context_stack;	error_context_stack = &sqlerrcontext;	/*	 * Initialize fcache (build plans) if first time through.	 */	fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;	if (fcache == NULL)	{		init_sql_fcache(fcinfo->flinfo);		fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;	}	es = fcache->func_state;	/*	 * Convert params to appropriate format if starting a fresh execution.	 * (If continuing execution, we can re-use prior params.)	 */	if (es && es->status == F_EXEC_START)		postquel_sub_params(fcache, fcinfo);	/*	 * Find first unfinished query in function.	 */	while (es && es->status == F_EXEC_DONE)		es = es->next;	/*	 * Execute each command in the function one after another until we're	 * executing the final command and get a result or we run out of	 * commands.	 */	while (es)	{		result = postquel_execute(es, fcinfo, fcache);		if (es->status != F_EXEC_DONE)			break;		es = es->next;	}	/*	 * If we've gone through every command in this function, we are done.	 */	if (es == (execution_state *) NULL)	{		/*		 * Reset the execution states to start over again on next call.		 */		es = fcache->func_state;		while (es)		{			es->status = F_EXEC_START;			es = es->next;		}		/*		 * Let caller know we're finished.		 */		if (fcinfo->flinfo->fn_retset)		{			ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;			if (rsi && IsA(rsi, ReturnSetInfo))				rsi->isDone = ExprEndResult;			else				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("set-valued function called in context that cannot accept a set")));			fcinfo->isnull = true;			result = (Datum) 0;			/* Deregister shutdown callback, if we made one */			if (fcache->shutdown_reg)			{				UnregisterExprContextCallback(rsi->econtext,											  ShutdownSQLFunction,											  PointerGetDatum(fcache));				fcache->shutdown_reg = false;			}		}		error_context_stack = sqlerrcontext.previous;		MemoryContextSwitchTo(oldcontext);		return result;	}	/*	 * If we got a result from a command within the function it has to be	 * the final command.  All others shouldn't be returning anything.	 */	Assert(LAST_POSTQUEL_COMMAND(es));	/*	 * Let caller know we're not finished.	 */	if (fcinfo->flinfo->fn_retset)	{		ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;		if (rsi && IsA(rsi, ReturnSetInfo))			rsi->isDone = ExprMultipleResult;		else			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("set-valued function called in context that cannot accept a set")));		/*		 * Ensure we will get shut down cleanly if the exprcontext is not		 * run to completion.		 */		if (!fcache->shutdown_reg)		{			RegisterExprContextCallback(rsi->econtext,										ShutdownSQLFunction,										PointerGetDatum(fcache));			fcache->shutdown_reg = true;		}	}	error_context_stack = sqlerrcontext.previous;	MemoryContextSwitchTo(oldcontext);	return result;}/* * error context callback to let us supply a call-stack traceback */static voidsql_exec_error_callback(void *arg){	FmgrInfo   *flinfo = (FmgrInfo *) arg;	SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) flinfo->fn_extra;	char	   *fn_name;	fn_name = get_func_name(flinfo->fn_oid);	/* safety check, shouldn't happen */	if (fn_name == NULL)		return;	/*	 * Try to determine where in the function we failed.  If there is a	 * query with non-null QueryDesc, finger it.  (We check this rather	 * than looking for F_EXEC_RUN state, so that errors during	 * ExecutorStart or ExecutorEnd are blamed on the appropriate query;	 * see postquel_start and postquel_end.)	 */	if (fcache)	{		execution_state *es;		int			query_num;		es = fcache->func_state;		query_num = 1;		while (es)		{			if (es->qd)			{				errcontext("SQL function \"%s\" statement %d",						   fn_name, query_num);				break;			}			es = es->next;			query_num++;		}		if (es == NULL)		{			/*			 * couldn't identify a running query; might be function entry,			 * function exit, or between queries.			 */			errcontext("SQL function \"%s\"", fn_name);		}	}	else	{		/* must have failed during init_sql_fcache() */		errcontext("SQL function \"%s\" during startup", fn_name);	}	/* free result of get_func_name (in case this is only a notice) */	pfree(fn_name);}/* * callback function in case a function-returning-set needs to be shut down * before it has been run to completion */static voidShutdownSQLFunction(Datum arg){	SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) DatumGetPointer(arg);	execution_state *es = fcache->func_state;	while (es != NULL)	{		/* Shut down anything still running */		if (es->status == F_EXEC_RUN)			postquel_end(es);		/* Reset states to START in case we're called again */		es->status = F_EXEC_START;		es = es->next;	}	/* execUtils will deregister the callback... */	fcache->shutdown_reg = false;}

⌨️ 快捷键说明

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