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

📄 pltcl.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	SPI_freetuptable(tuptable);	return my_rc;}/********************************************************************** * pltcl_SPI_prepare()		- Builtin support for prepared plans *				  The Tcl command SPI_prepare *				  always saves the plan using *				  SPI_saveplan and returns a key for *				  access. There is no chance to prepare *				  and not save the plan currently. **********************************************************************/static intpltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,				  int argc, CONST84 char *argv[]){	int			nargs;	CONST84 char **args;	pltcl_query_desc *qdesc;	void	   *plan;	int			i;	HeapTuple	typeTup;	Tcl_HashEntry *hashent;	int			hashnew;	Tcl_HashTable *query_hash;	MemoryContext oldcontext = CurrentMemoryContext;	ResourceOwner oldowner = CurrentResourceOwner;	/************************************************************	 * Check the call syntax	 ************************************************************/	if (argc != 3)	{		Tcl_SetResult(interp, "syntax error - 'SPI_prepare query argtypes'",					  TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Split the argument type list	 ************************************************************/	if (Tcl_SplitList(interp, argv[2], &nargs, &args) != TCL_OK)		return TCL_ERROR;	/************************************************************	 * Allocate the new querydesc structure	 ************************************************************/	qdesc = (pltcl_query_desc *) malloc(sizeof(pltcl_query_desc));	snprintf(qdesc->qname, sizeof(qdesc->qname), "%lx", (long) qdesc);	qdesc->nargs = nargs;	qdesc->argtypes = (Oid *) malloc(nargs * sizeof(Oid));	qdesc->arginfuncs = (FmgrInfo *) malloc(nargs * sizeof(FmgrInfo));	qdesc->argtypioparams = (Oid *) malloc(nargs * sizeof(Oid));	/************************************************************	 * Execute the prepare inside a sub-transaction, so we can cope with	 * errors sanely	 ************************************************************/	pltcl_subtrans_begin(oldcontext, oldowner);	PG_TRY();	{		/************************************************************		 * Lookup the argument types by name in the system cache		 * and remember the required information for input conversion		 ************************************************************/		for (i = 0; i < nargs; i++)		{			char	   *argcopy;			List	   *names = NIL;			ListCell   *l;			TypeName   *typename;			/************************************************************			 * Use SplitIdentifierString() on a copy of the type name,			 * turn the resulting pointer list into a TypeName node			 * and call typenameType() to get the pg_type tuple.			 ************************************************************/			argcopy = pstrdup(args[i]);			SplitIdentifierString(argcopy, '.', &names);			typename = makeNode(TypeName);			foreach(l, names)				typename->names = lappend(typename->names, makeString(lfirst(l)));			typeTup = typenameType(typename);			qdesc->argtypes[i] = HeapTupleGetOid(typeTup);			perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,						   &(qdesc->arginfuncs[i]));			qdesc->argtypioparams[i] = getTypeIOParam(typeTup);			ReleaseSysCache(typeTup);			list_free(typename->names);			pfree(typename);			list_free(names);			pfree(argcopy);		}		/************************************************************		 * Prepare the plan and check for errors		 ************************************************************/		UTF_BEGIN;		plan = SPI_prepare(UTF_U2E(argv[1]), nargs, qdesc->argtypes);		UTF_END;		if (plan == NULL)			elog(ERROR, "SPI_prepare() failed");		/************************************************************		 * Save the plan into permanent memory (right now it's in the		 * SPI procCxt, which will go away at function end).		 ************************************************************/		qdesc->plan = SPI_saveplan(plan);		if (qdesc->plan == NULL)			elog(ERROR, "SPI_saveplan() failed");		/* Release the procCxt copy to avoid within-function memory leak */		SPI_freeplan(plan);		pltcl_subtrans_commit(oldcontext, oldowner);	}	PG_CATCH();	{		pltcl_subtrans_abort(interp, oldcontext, oldowner);		free(qdesc->argtypes);		free(qdesc->arginfuncs);		free(qdesc->argtypioparams);		free(qdesc);		ckfree((char *) args);		return TCL_ERROR;	}	PG_END_TRY();	/************************************************************	 * Insert a hashtable entry for the plan and return	 * the key to the caller	 ************************************************************/	if (interp == pltcl_norm_interp)		query_hash = pltcl_norm_query_hash;	else		query_hash = pltcl_safe_query_hash;	hashent = Tcl_CreateHashEntry(query_hash, qdesc->qname, &hashnew);	Tcl_SetHashValue(hashent, (ClientData) qdesc);	ckfree((char *) args);	Tcl_SetResult(interp, qdesc->qname, TCL_VOLATILE);	return TCL_OK;}/********************************************************************** * pltcl_SPI_execute_plan()		- Execute a prepared plan **********************************************************************/static intpltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,					   int argc, CONST84 char *argv[]){	int			my_rc;	int			spi_rc;	int			i;	int			j;	Tcl_HashEntry *hashent;	pltcl_query_desc *qdesc;	const char *volatile nulls = NULL;	CONST84 char *volatile arrayname = NULL;	CONST84 char *volatile loop_body = NULL;	int			count = 0;	int			callnargs;	CONST84 char **callargs = NULL;	Datum	   *argvalues;	MemoryContext oldcontext = CurrentMemoryContext;	ResourceOwner oldowner = CurrentResourceOwner;	Tcl_HashTable *query_hash;	char	   *usage = "syntax error - 'SPI_execp "	"?-nulls string? ?-count n? "	"?-array name? query ?args? ?loop body?";	/************************************************************	 * Get the options and check syntax	 ************************************************************/	i = 1;	while (i < argc)	{		if (strcmp(argv[i], "-array") == 0)		{			if (++i >= argc)			{				Tcl_SetResult(interp, usage, TCL_VOLATILE);				return TCL_ERROR;			}			arrayname = argv[i++];			continue;		}		if (strcmp(argv[i], "-nulls") == 0)		{			if (++i >= argc)			{				Tcl_SetResult(interp, usage, TCL_VOLATILE);				return TCL_ERROR;			}			nulls = argv[i++];			continue;		}		if (strcmp(argv[i], "-count") == 0)		{			if (++i >= argc)			{				Tcl_SetResult(interp, usage, TCL_VOLATILE);				return TCL_ERROR;			}			if (Tcl_GetInt(interp, argv[i++], &count) != TCL_OK)				return TCL_ERROR;			continue;		}		break;	}	/************************************************************	 * Get the prepared plan descriptor by its key	 ************************************************************/	if (i >= argc)	{		Tcl_SetResult(interp, usage, TCL_VOLATILE);		return TCL_ERROR;	}	if (interp == pltcl_norm_interp)		query_hash = pltcl_norm_query_hash;	else		query_hash = pltcl_safe_query_hash;	hashent = Tcl_FindHashEntry(query_hash, argv[i]);	if (hashent == NULL)	{		Tcl_AppendResult(interp, "invalid queryid '", argv[i], "'", NULL);		return TCL_ERROR;	}	qdesc = (pltcl_query_desc *) Tcl_GetHashValue(hashent);	i++;	/************************************************************	 * If a nulls string is given, check for correct length	 ************************************************************/	if (nulls != NULL)	{		if (strlen(nulls) != qdesc->nargs)		{			Tcl_SetResult(interp,					   "length of nulls string doesn't match # of arguments",						  TCL_VOLATILE);			return TCL_ERROR;		}	}	/************************************************************	 * If there was a argtype list on preparation, we need	 * an argument value list now	 ************************************************************/	if (qdesc->nargs > 0)	{		if (i >= argc)		{			Tcl_SetResult(interp, "missing argument list", TCL_VOLATILE);			return TCL_ERROR;		}		/************************************************************		 * Split the argument values		 ************************************************************/		if (Tcl_SplitList(interp, argv[i++], &callnargs, &callargs) != TCL_OK)			return TCL_ERROR;		/************************************************************		 * Check that the # of arguments matches		 ************************************************************/		if (callnargs != qdesc->nargs)		{			Tcl_SetResult(interp,			   "argument list length doesn't match # of arguments for query",						  TCL_VOLATILE);			ckfree((char *) callargs);			return TCL_ERROR;		}	}	else		callnargs = 0;	/************************************************************	 * Get loop body if present	 ************************************************************/	if (i < argc)		loop_body = argv[i++];	if (i != argc)	{		Tcl_SetResult(interp, usage, TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Execute the plan inside a sub-transaction, so we can cope with	 * errors sanely	 ************************************************************/	pltcl_subtrans_begin(oldcontext, oldowner);	PG_TRY();	{		/************************************************************		 * Setup the value array for SPI_execute_plan() using		 * the type specific input functions		 ************************************************************/		argvalues = (Datum *) palloc(callnargs * sizeof(Datum));		for (j = 0; j < callnargs; j++)		{			if (nulls && nulls[j] == 'n')			{				/* don't try to convert the input for a null */				argvalues[j] = (Datum) 0;			}			else			{				UTF_BEGIN;				argvalues[j] =					FunctionCall3(&qdesc->arginfuncs[j],								  CStringGetDatum(UTF_U2E(callargs[j])),								  ObjectIdGetDatum(qdesc->argtypioparams[j]),								  Int32GetDatum(-1));				UTF_END;			}		}		if (callargs)			ckfree((char *) callargs);		callargs = NULL;		/************************************************************		 * Execute the plan		 ************************************************************/		spi_rc = SPI_execute_plan(qdesc->plan, argvalues, nulls,								  pltcl_current_prodesc->fn_readonly, count);		my_rc = pltcl_process_SPI_result(interp,										 arrayname,										 loop_body,										 spi_rc,										 SPI_tuptable,										 SPI_processed);		pltcl_subtrans_commit(oldcontext, oldowner);	}	PG_CATCH();	{		pltcl_subtrans_abort(interp, oldcontext, oldowner);		if (callargs)			ckfree((char *) callargs);		return TCL_ERROR;	}	PG_END_TRY();	return my_rc;}/********************************************************************** * pltcl_SPI_lastoid()	- return the last oid. To *		  be used after insert queries **********************************************************************/static intpltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp,				  int argc, CONST84 char *argv[]){	char		buf[64];	snprintf(buf, sizeof(buf), "%u", SPI_lastoid);	Tcl_SetResult(interp, buf, TCL_VOLATILE);	return TCL_OK;}/********************************************************************** * pltcl_set_tuple_values() - Set variables for all attributes *				  of a given tuple **********************************************************************/static voidpltcl_set_tuple_values(Tcl_Interp *interp, CONST84 char *arrayname,					   int tupno, HeapTuple tuple, TupleDesc tupdesc){	int			i;	char	   *outputstr;	char		buf[64];	Datum		attr;	bool		isnull;	CONST84 char *attname;	HeapTuple	typeTup;	Oid			typoutput;	CONST84 char **arrptr;	CONST84 char **nameptr;	CONST84 char *nullname = NULL;	/************************************************************	 * Prepare pointers for Tcl_SetVar2() below and in array	 * mode set the .tupno element	 ************************************************************/	if (arrayname == NULL)	{		arrptr = &attname;		nameptr = &nullname;	}	else	{		arrptr = &arrayname;		nameptr = &attname;		snprintf(buf, sizeof(buf), "%d", tupno);		Tcl_SetVar2(interp, arrayname, ".tupno", buf, 0);	}	for (i = 0; i < tupdesc->natts; i++)	{		/* ignore dropped attributes */		if (tupdesc->attrs[i]->attisdropped)			continue;		/************************************************************		 * Get the attribute name		 ************************************************************/		attname = NameStr(tupdesc

⌨️ 快捷键说明

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