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

📄 pltcl.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
						"pltcl: SPI_exec() failed - SPI_ERROR_OPUNKNOWN",						  TCL_VOLATILE);			return TCL_ERROR;		default:			snprintf(buf, sizeof(buf), "%d", spi_rc);			Tcl_AppendResult(interp, "pltcl: SPI_exec() failed - ",							 "unknown RC ", buf, NULL);			return TCL_ERROR;	}	/************************************************************	 * Only SELECT queries fall through to here - remember the	 * tuples we got	 ************************************************************/	ntuples = SPI_processed;	if (ntuples > 0)	{		tuples = SPI_tuptable->vals;		tupdesc = SPI_tuptable->tupdesc;	}	/************************************************************	 * Again prepare for elog(ERROR)	 ************************************************************/	if (sigsetjmp(Warn_restart, 1) != 0)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		pltcl_restart_in_progress = 1;		Tcl_SetResult(interp, "Transaction abort", TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * If there is no loop body given, just set the variables	 * from the first tuple (if any) and return the number of	 * tuples selected	 ************************************************************/	if (argc == query_idx + 1)	{		if (ntuples > 0)			pltcl_set_tuple_values(interp, arrayname, 0, tuples[0], tupdesc);		snprintf(buf, sizeof(buf), "%d", ntuples);		Tcl_SetResult(interp, buf, TCL_VOLATILE);		SPI_freetuptable(SPI_tuptable);		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		return TCL_OK;	}	tuptable = SPI_tuptable;	/************************************************************	 * There is a loop body - process all tuples and evaluate	 * the body on each	 ************************************************************/	query_idx++;	for (i = 0; i < ntuples; i++)	{		pltcl_set_tuple_values(interp, arrayname, i, tuples[i], tupdesc);		loop_rc = Tcl_Eval(interp, argv[query_idx]);		if (loop_rc == TCL_OK)			continue;		if (loop_rc == TCL_CONTINUE)			continue;		if (loop_rc == TCL_RETURN)		{			SPI_freetuptable(tuptable);			memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));			return TCL_RETURN;		}		if (loop_rc == TCL_BREAK)			break;		SPI_freetuptable(tuptable);		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		return TCL_ERROR;	}	SPI_freetuptable(tuptable);	/************************************************************	 * Finally return the number of tuples	 ************************************************************/	memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));	snprintf(buf, sizeof(buf), "%d", ntuples);	Tcl_SetResult(interp, buf, TCL_VOLATILE);	return TCL_OK;}/********************************************************************** * 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;	sigjmp_buf	save_restart;	Tcl_HashTable *query_hash;	/************************************************************	 * Don't do anything if we are already in restart mode	 ************************************************************/	if (pltcl_restart_in_progress)		return TCL_ERROR;	/************************************************************	 * 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->argtypelems = (Oid *) malloc(nargs * sizeof(Oid));	/************************************************************	 * Prepare to start a controlled return through all	 * interpreter levels on transaction abort	 ************************************************************/	memcpy(&save_restart, &Warn_restart, sizeof(save_restart));	if (sigsetjmp(Warn_restart, 1) != 0)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		pltcl_restart_in_progress = 1;		free(qdesc->argtypes);		free(qdesc->arginfuncs);		free(qdesc->argtypelems);		free(qdesc);		ckfree((char *) args);		return TCL_ERROR;	}	/************************************************************	 * 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;		List		   *lp;		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 (lp, names)			typename->names = lappend(typename->names, makeString(lfirst(lp)));		typeTup = typenameType(typename);		qdesc->argtypes[i] = HeapTupleGetOid(typeTup);		perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,					   &(qdesc->arginfuncs[i]));		qdesc->argtypelems[i] = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;		ReleaseSysCache(typeTup);		freeList(typename->names);		pfree(typename);		freeList(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)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		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)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		elog(ERROR, "SPI_saveplan() failed");	}	/* Release the procCxt copy to avoid within-function memory leak */	SPI_freeplan(plan);	/************************************************************	 * 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;	memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));	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_execp()		- Execute a prepared plan **********************************************************************/static intpltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,				int argc, CONST84 char *argv[]){	int			spi_rc;	char		buf[64];	volatile int i;	int			j;	int			loop_body;	Tcl_HashEntry *hashent;	pltcl_query_desc *qdesc;	Datum	   *volatile argvalues = NULL;	const char *volatile nulls = NULL;	CONST84 char *volatile arrayname = NULL;	int			count = 0;	int			callnargs;	static CONST84 char **callargs = NULL;	int			loop_rc;	int			ntuples;	HeapTuple  *volatile tuples = NULL;	volatile TupleDesc tupdesc = NULL;	SPITupleTable *tuptable;	sigjmp_buf	save_restart;	Tcl_HashTable *query_hash;	char	   *usage = "syntax error - 'SPI_execp "	"?-nulls string? ?-count n? "	"?-array name? query ?args? ?loop body?";	/************************************************************	 * Tidy up from an earlier abort	 ************************************************************/	if (callargs != NULL)	{		ckfree((char *) callargs);		callargs = NULL;	}	/************************************************************	 * Don't do anything if we are already in restart mode	 ************************************************************/	if (pltcl_restart_in_progress)		return TCL_ERROR;	/************************************************************	 * 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;	}	/************************************************************	 * Check minimum call arguments	 ************************************************************/	if (i >= argc)	{		Tcl_SetResult(interp, usage, TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Get the prepared plan descriptor by its key	 ************************************************************/	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);	/************************************************************	 * 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);			if (callargs != NULL)			{				ckfree((char *) callargs);				callargs = NULL;			}			return TCL_ERROR;		}		/************************************************************		 * Prepare to start a controlled return through all		 

⌨️ 快捷键说明

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