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

📄 functions.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
字号:
/*------------------------------------------------------------------------- * * functions.c *	  Routines to handle functions called from the executor *	  Putting this stuff in fmgr makes the postmaster a mess.... * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/executor/functions.c,v 1.26 1999/05/25 16:08:39 momjian Exp $ * *------------------------------------------------------------------------- */#include <string.h>#include "postgres.h"#include "nodes/primnodes.h"#include "nodes/relation.h"#include "nodes/execnodes.h"#include "nodes/plannodes.h"#include "catalog/pg_proc.h"#include "tcop/pquery.h"#include "tcop/tcopprot.h"#include "tcop/utility.h"#include "nodes/params.h"#include "fmgr.h"#include "utils/fcache.h"#include "utils/datum.h"#include "utils/elog.h"#include "utils/palloc.h"#include "utils/syscache.h"#include "catalog/pg_language.h"#include "access/heapam.h"#include "access/xact.h"#include "executor/executor.h"#include "executor/execdefs.h"#include "executor/functions.h"#undef newtypedef enum{	F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE} ExecStatus;typedef struct local_es{	QueryDesc  *qd;	EState	   *estate;	struct local_es *next;	ExecStatus	status;} execution_state;#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL)/* non-export function prototypes */static TupleDesc postquel_start(execution_state *es);static execution_state *init_execution_state(FunctionCachePtr fcache,					 char *args[]);static TupleTableSlot *postquel_getnext(execution_state *es);static void postquel_end(execution_state *es);static void postquel_sub_params(execution_state *es, int nargs,					char *args[], bool *nullV);static Datum postquel_execute(execution_state *es, FunctionCachePtr fcache,				 List *fTlist, char **args, bool *isNull);DatumProjectAttribute(TupleDesc TD,				 TargetEntry *tlist,				 HeapTuple tup,				 bool *isnullP){	Datum		val,				valueP;	Var		   *attrVar = (Var *) tlist->expr;	AttrNumber	attrno = attrVar->varattno;	val = heap_getattr(tup, attrno, TD, isnullP);	if (*isnullP)		return (Datum) NULL;	valueP = datumCopy(val,					   TD->attrs[attrno - 1]->atttypid,					   TD->attrs[attrno - 1]->attbyval,					   (Size) TD->attrs[attrno - 1]->attlen);	return valueP;}static execution_state *init_execution_state(FunctionCachePtr fcache,					 char *args[]){	execution_state *newes;	execution_state *nextes;	execution_state *preves;	List	   *queryTree_list,			   *planTree_list,			   *qtl_item;	int			nargs = fcache->nargs;	newes = (execution_state *) palloc(sizeof(execution_state));	nextes = newes;	preves = (execution_state *) NULL;	planTree_list = pg_parse_and_plan(fcache->src, fcache->argOidVect,									nargs, &queryTree_list, None, FALSE);	foreach(qtl_item, queryTree_list)	{		Query	   *queryTree = lfirst(qtl_item);		Plan	   *planTree = lfirst(planTree_list);		EState	   *estate;		if (!nextes)			nextes = (execution_state *) palloc(sizeof(execution_state));		if (preves)			preves->next = nextes;		nextes->next = NULL;		nextes->status = F_EXEC_START;		nextes->qd = CreateQueryDesc(queryTree,									 planTree,									 None);		estate = CreateExecutorState();		if (queryTree->limitOffset != NULL || queryTree->limitCount != NULL)			elog(ERROR, "LIMIT clause from SQL functions not yet implemented");		if (nargs > 0)		{			int			i;			ParamListInfo paramLI;			paramLI = (ParamListInfo) palloc((nargs + 1) * sizeof(ParamListInfoData));			MemSet(paramLI, 0, nargs * sizeof(ParamListInfoData));			estate->es_param_list_info = paramLI;			for (i = 0; i < nargs; paramLI++, i++)			{				paramLI->kind = PARAM_NUM;				paramLI->id = i + 1;				paramLI->isnull = false;				paramLI->value = (Datum) NULL;			}			paramLI->kind = PARAM_INVALID;		}		else			estate->es_param_list_info = (ParamListInfo) NULL;		nextes->estate = estate;		preves = nextes;		nextes = (execution_state *) NULL;		planTree_list = lnext(planTree_list);	}	return newes;}static TupleDescpostquel_start(execution_state *es){#ifdef FUNC_UTIL_PATCH	/*	 * Do nothing for utility commands. (create, destroy...)  DZ -	 * 30-8-1996	 */	if (es->qd->operation == CMD_UTILITY)		return (TupleDesc) NULL;#endif	return ExecutorStart(es->qd, es->estate);}static TupleTableSlot *postquel_getnext(execution_state *es){	int			feature;#ifdef FUNC_UTIL_PATCH	if (es->qd->operation == CMD_UTILITY)	{		/*		 * Process an utility command. (create, destroy...)  DZ -		 * 30-8-1996		 */		ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);		if (!LAST_POSTQUEL_COMMAND(es))			CommandCounterIncrement();		return (TupleTableSlot *) NULL;	}#endif	feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;	return ExecutorRun(es->qd, es->estate, feature, (Node *) NULL, (Node *) NULL);}static voidpostquel_end(execution_state *es){#ifdef FUNC_UTIL_PATCH	/*	 * Do nothing for utility commands. (create, destroy...)  DZ -	 * 30-8-1996	 */	if (es->qd->operation == CMD_UTILITY)		return;#endif	ExecutorEnd(es->qd, es->estate);}static voidpostquel_sub_params(execution_state *es,					int nargs,					char *args[],					bool *nullV){	ParamListInfo paramLI;	EState	   *estate;	estate = es->estate;	paramLI = estate->es_param_list_info;	while (paramLI->kind != PARAM_INVALID)	{		if (paramLI->kind == PARAM_NUM)		{			Assert(paramLI->id <= nargs);			paramLI->value = (Datum) args[(paramLI->id - 1)];			paramLI->isnull = nullV[(paramLI->id - 1)];		}		paramLI++;	}}static TupleTableSlot *copy_function_result(FunctionCachePtr fcache,					 TupleTableSlot *resultSlot){	TupleTableSlot *funcSlot;	TupleDesc	resultTd;	HeapTuple	newTuple;	HeapTuple	oldTuple;	Assert(!TupIsNull(resultSlot));	oldTuple = resultSlot->val;	funcSlot = (TupleTableSlot *) fcache->funcSlot;	if (funcSlot == (TupleTableSlot *) NULL)		return resultSlot;	resultTd = resultSlot->ttc_tupleDescriptor;	/*	 * When the funcSlot is NULL we have to initialize the funcSlot's	 * tuple descriptor.	 */	if (TupIsNull(funcSlot))	{		int			i = 0;		TupleDesc	funcTd = funcSlot->ttc_tupleDescriptor;		while (i < oldTuple->t_data->t_natts)		{			funcTd->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);			memmove(funcTd->attrs[i],					resultTd->attrs[i],					ATTRIBUTE_TUPLE_SIZE);			i++;		}	}	newTuple = heap_copytuple(oldTuple);	return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true);}static Datumpostquel_execute(execution_state *es,				 FunctionCachePtr fcache,				 List *fTlist,				 char **args,				 bool *isNull){	TupleTableSlot *slot;	Datum		value;	/*	 * It's more right place to do it (before	 * postquel_start->ExecutorStart). Now	 * ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But	 * note: I HOPE we can do it here). - vadim 01/22/97	 */	if (fcache->nargs > 0)		postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);	if (es->status == F_EXEC_START)	{		postquel_start(es);		es->status = F_EXEC_RUN;	}	slot = postquel_getnext(es);	if (TupIsNull(slot))	{		postquel_end(es);		es->status = F_EXEC_DONE;		*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 (fTlist != NIL)		{			TargetEntry *tle = lfirst(fTlist);			value = ProjectAttribute(resSlot->ttc_tupleDescriptor,									 tle,									 resSlot->val,									 isNull);		}		else		{			value = (Datum) resSlot;			*isNull = false;		}		/*		 * If this is a single valued function we have to end the function		 * execution now.		 */		if (fcache->oneResult)		{			postquel_end(es);			es->status = F_EXEC_DONE;		}		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;}Datumpostquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone){	execution_state *es;	Datum		result = 0;	FunctionCachePtr fcache = funcNode->func_fcache;	CommandId	savedId;	/*	 * Before we start do anything we must save CurrentScanCommandId to	 * restore it before return to upper Executor. Also, we have to set	 * CurrentScanCommandId equal to CurrentCommandId. - vadim 08/29/97	 */	savedId = GetScanCommandId();	SetScanCommandId(GetCurrentCommandId());	es = (execution_state *) fcache->func_state;	if (es == NULL)	{		es = init_execution_state(fcache, args);		fcache->func_state = (char *) es;	}	while (es && es->status == F_EXEC_DONE)		es = es->next;	Assert(es);	/*	 * 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 != (execution_state *) NULL)	{		result = postquel_execute(es,								  fcache,								  funcNode->func_tlist,								  args,								  isNull);		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		 */		es = (execution_state *) fcache->func_state;		while (es)		{			es->status = F_EXEC_START;			es = es->next;		}		/*		 * Let caller know we're finished.		 */		*isDone = true;		SetScanCommandId(savedId);		return (fcache->oneResult) ? result : (Datum) NULL;	}	/*	 * If we got a result from a command within the function it has to be	 * the final command.  All others shouldn't be returing anything.	 */	Assert(LAST_POSTQUEL_COMMAND(es));	*isDone = false;	SetScanCommandId(savedId);	return result;}

⌨️ 快捷键说明

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