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

📄 pltcl.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* Must reset elog.c's state */		MemoryContextSwitchTo(oldcontext);		edata = CopyErrorData();		FlushErrorState();		/* Pass the error message to Tcl */		Tcl_SetResult(interp, edata->message, TCL_VOLATILE);		FreeErrorData(edata);		return TCL_ERROR;	}	PG_END_TRY();	return TCL_OK;}/********************************************************************** * pltcl_quote()	- quote literal strings that are to *			  be used in SPI_execute query strings **********************************************************************/static intpltcl_quote(ClientData cdata, Tcl_Interp *interp,			int argc, CONST84 char *argv[]){	char	   *tmp;	const char *cp1;	char	   *cp2;	/************************************************************	 * Check call syntax	 ************************************************************/	if (argc != 2)	{		Tcl_SetResult(interp, "syntax error - 'quote string'", TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Allocate space for the maximum the string can	 * grow to and initialize pointers	 ************************************************************/	tmp = palloc(strlen(argv[1]) * 2 + 1);	cp1 = argv[1];	cp2 = tmp;	/************************************************************	 * Walk through string and double every quote and backslash	 ************************************************************/	while (*cp1)	{		if (*cp1 == '\'')			*cp2++ = '\'';		else		{			if (*cp1 == '\\')				*cp2++ = '\\';		}		*cp2++ = *cp1++;	}	/************************************************************	 * Terminate the string and set it as result	 ************************************************************/	*cp2 = '\0';	Tcl_SetResult(interp, tmp, TCL_VOLATILE);	pfree(tmp);	return TCL_OK;}/********************************************************************** * pltcl_argisnull()	- determine if a specific argument is NULL **********************************************************************/static intpltcl_argisnull(ClientData cdata, Tcl_Interp *interp,				int argc, CONST84 char *argv[]){	int			argno;	FunctionCallInfo fcinfo = pltcl_current_fcinfo;	/************************************************************	 * Check call syntax	 ************************************************************/	if (argc != 2)	{		Tcl_SetResult(interp, "syntax error - 'argisnull argno'", TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Check that we're called as a normal function	 ************************************************************/	if (fcinfo == NULL)	{		Tcl_SetResult(interp, "argisnull cannot be used in triggers",					  TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Get the argument number	 ************************************************************/	if (Tcl_GetInt(interp, argv[1], &argno) != TCL_OK)		return TCL_ERROR;	/************************************************************	 * Check that the argno is valid	 ************************************************************/	argno--;	if (argno < 0 || argno >= fcinfo->nargs)	{		Tcl_SetResult(interp, "argno out of range", TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Get the requested NULL state	 ************************************************************/	if (PG_ARGISNULL(argno))		Tcl_SetResult(interp, "1", TCL_VOLATILE);	else		Tcl_SetResult(interp, "0", TCL_VOLATILE);	return TCL_OK;}/********************************************************************** * pltcl_returnnull()	- Cause a NULL return from a function **********************************************************************/static intpltcl_returnnull(ClientData cdata, Tcl_Interp *interp,				 int argc, CONST84 char *argv[]){	FunctionCallInfo fcinfo = pltcl_current_fcinfo;	/************************************************************	 * Check call syntax	 ************************************************************/	if (argc != 1)	{		Tcl_SetResult(interp, "syntax error - 'return_null'", TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Check that we're called as a normal function	 ************************************************************/	if (fcinfo == NULL)	{		Tcl_SetResult(interp, "return_null cannot be used in triggers",					  TCL_VOLATILE);		return TCL_ERROR;	}	/************************************************************	 * Set the NULL return flag and cause Tcl to return from the	 * procedure.	 ************************************************************/	fcinfo->isnull = true;	return TCL_RETURN;}/*---------- * Support for running SPI operations inside subtransactions * * Intended usage pattern is: * *	MemoryContext oldcontext = CurrentMemoryContext; *	ResourceOwner oldowner = CurrentResourceOwner; * *	... *	pltcl_subtrans_begin(oldcontext, oldowner); *	PG_TRY(); *	{ *		do something risky; *		pltcl_subtrans_commit(oldcontext, oldowner); *	} *	PG_CATCH(); *	{ *		pltcl_subtrans_abort(interp, oldcontext, oldowner); *		return TCL_ERROR; *	} *	PG_END_TRY(); *	return TCL_OK; *---------- */static voidpltcl_subtrans_begin(MemoryContext oldcontext, ResourceOwner oldowner){	BeginInternalSubTransaction(NULL);	/* Want to run inside function's memory context */	MemoryContextSwitchTo(oldcontext);}static voidpltcl_subtrans_commit(MemoryContext oldcontext, ResourceOwner oldowner){	/* Commit the inner transaction, return to outer xact context */	ReleaseCurrentSubTransaction();	MemoryContextSwitchTo(oldcontext);	CurrentResourceOwner = oldowner;	/*	 * AtEOSubXact_SPI() should not have popped any SPI context, but just in	 * case it did, make sure we remain connected.	 */	SPI_restore_connection();}static voidpltcl_subtrans_abort(Tcl_Interp *interp,					 MemoryContext oldcontext, ResourceOwner oldowner){	ErrorData  *edata;	/* Save error info */	MemoryContextSwitchTo(oldcontext);	edata = CopyErrorData();	FlushErrorState();	/* Abort the inner transaction */	RollbackAndReleaseCurrentSubTransaction();	MemoryContextSwitchTo(oldcontext);	CurrentResourceOwner = oldowner;	/*	 * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will	 * have left us in a disconnected state.  We need this hack to return to	 * connected state.	 */	SPI_restore_connection();	/* Pass the error message to Tcl */	Tcl_SetResult(interp, edata->message, TCL_VOLATILE);	FreeErrorData(edata);}/********************************************************************** * pltcl_SPI_execute()		- The builtin SPI_execute command *				  for the Tcl interpreter **********************************************************************/static intpltcl_SPI_execute(ClientData cdata, Tcl_Interp *interp,				  int argc, CONST84 char *argv[]){	int			my_rc;	int			spi_rc;	int			query_idx;	int			i;	int			count = 0;	CONST84 char *volatile arrayname = NULL;	CONST84 char *volatile loop_body = NULL;	MemoryContext oldcontext = CurrentMemoryContext;	ResourceOwner oldowner = CurrentResourceOwner;	char	   *usage = "syntax error - 'SPI_exec "	"?-count n? "	"?-array name? query ?loop body?";	/************************************************************	 * Check the call syntax and get the options	 ************************************************************/	if (argc < 2)	{		Tcl_SetResult(interp, usage, TCL_VOLATILE);		return TCL_ERROR;	}	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], "-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;	}	query_idx = i;	if (query_idx >= argc || query_idx + 2 < argc)	{		Tcl_SetResult(interp, usage, TCL_VOLATILE);		return TCL_ERROR;	}	if (query_idx + 1 < argc)		loop_body = argv[query_idx + 1];	/************************************************************	 * Execute the query inside a sub-transaction, so we can cope with	 * errors sanely	 ************************************************************/	pltcl_subtrans_begin(oldcontext, oldowner);	PG_TRY();	{		UTF_BEGIN;		spi_rc = SPI_execute(UTF_U2E(argv[query_idx]),							 pltcl_current_prodesc->fn_readonly, count);		UTF_END;		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);		return TCL_ERROR;	}	PG_END_TRY();	return my_rc;}/* * Process the result from SPI_execute or SPI_execute_plan * * Shared code between pltcl_SPI_execute and pltcl_SPI_execute_plan */static intpltcl_process_SPI_result(Tcl_Interp *interp,						 CONST84 char *arrayname,						 CONST84 char *loop_body,						 int spi_rc,						 SPITupleTable *tuptable,						 int ntuples){	int			my_rc = TCL_OK;	char		buf[64];	int			i;	int			loop_rc;	HeapTuple  *tuples;	TupleDesc	tupdesc;	switch (spi_rc)	{		case SPI_OK_UTILITY:			Tcl_SetResult(interp, "0", TCL_VOLATILE);			break;		case SPI_OK_SELINTO:		case SPI_OK_INSERT:		case SPI_OK_DELETE:		case SPI_OK_UPDATE:			snprintf(buf, sizeof(buf), "%d", ntuples);			Tcl_SetResult(interp, buf, TCL_VOLATILE);			break;		case SPI_OK_SELECT:			/*			 * Process the tuples we got			 */			tuples = tuptable->vals;			tupdesc = tuptable->tupdesc;			if (loop_body == NULL)			{				/*				 * If there is no loop body given, just set the variables from				 * the first tuple (if any)				 */				if (ntuples > 0)					pltcl_set_tuple_values(interp, arrayname, 0,										   tuples[0], tupdesc);			}			else			{				/*				 * There is a loop body - process all tuples and evaluate the				 * body on each				 */				for (i = 0; i < ntuples; i++)				{					pltcl_set_tuple_values(interp, arrayname, i,										   tuples[i], tupdesc);					loop_rc = Tcl_Eval(interp, loop_body);					if (loop_rc == TCL_OK)						continue;					if (loop_rc == TCL_CONTINUE)						continue;					if (loop_rc == TCL_RETURN)					{						my_rc = TCL_RETURN;						break;					}					if (loop_rc == TCL_BREAK)						break;					my_rc = TCL_ERROR;					break;				}			}			if (my_rc == TCL_OK)			{				snprintf(buf, sizeof(buf), "%d", ntuples);				Tcl_SetResult(interp, buf, TCL_VOLATILE);			}			break;		default:			Tcl_AppendResult(interp, "pltcl: SPI_execute failed: ",							 SPI_result_code_string(spi_rc), NULL);			my_rc = TCL_ERROR;			break;	}

⌨️ 快捷键说明

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