src/pl/tcl/pltcl.c
static int
pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
				  int objc, Tcl_Obj *const objv[])
{
	volatile MemoryContext plan_cxt = NULL;
	int			nargs;
	Tcl_Obj   **argsObj;
	pltcl_query_desc *qdesc;
	int			i;
	Tcl_HashEntry *hashent;
	int			hashnew;
	Tcl_HashTable *query_hash;
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

	/************************************************************
	 * Check the call syntax
	 ************************************************************/
	if (objc != 3)
	{
		Tcl_WrongNumArgs(interp, 1, objv, "query argtypes");
		return TCL_ERROR;
	}

	/************************************************************
	 * Split the argument type list
	 ************************************************************/
	if (Tcl_ListObjGetElements(interp, objv[2], &nargs, &argsObj) != TCL_OK)
		return TCL_ERROR;

	/************************************************************
	 * Allocate the new querydesc structure
	 *
	 * struct qdesc and subsidiary data all live in plan_cxt.  Note that if the
	 * function is recompiled for whatever reason, permanent memory leaks
	 * occur.  FIXME someday.
	 ************************************************************/
	plan_cxt = AllocSetContextCreate(TopMemoryContext,
									 "PL/Tcl spi_prepare query",
									 ALLOCSET_SMALL_SIZES);
	MemoryContextSwitchTo(plan_cxt);
	qdesc = (pltcl_query_desc *) palloc0(sizeof(pltcl_query_desc));
	snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc);
	qdesc->nargs = nargs;
	qdesc->argtypes = (Oid *) palloc(nargs * sizeof(Oid));
	qdesc->arginfuncs = (FmgrInfo *) palloc(nargs * sizeof(FmgrInfo));
	qdesc->argtypioparams = (Oid *) palloc(nargs * sizeof(Oid));
	MemoryContextSwitchTo(oldcontext);

	/************************************************************
	 * Execute the prepare inside a sub-transaction, so we can cope with
	 * errors sanely
	 ************************************************************/

	pltcl_subtrans_begin(oldcontext, oldowner);

	PG_TRY();
	{
		/************************************************************
		 * Resolve argument type names and then look them up by oid
		 * in the system cache, and remember the required information
		 * for input conversion.
		 ************************************************************/
		for (i = 0; i < nargs; i++)
		{
			Oid			typId,
						typInput,
						typIOParam;
			int32		typmod;

			parseTypeString(Tcl_GetString(argsObj[i]), &typId, &typmod, false);

			getTypeInputInfo(typId, &typInput, &typIOParam);

			qdesc->argtypes[i] = typId;
			fmgr_info_cxt(typInput, &(qdesc->arginfuncs[i]), plan_cxt);
			qdesc->argtypioparams[i] = typIOParam;
		}

		/************************************************************
		 * Prepare the plan and check for errors
		 ************************************************************/
		UTF_BEGIN;
		qdesc->plan = SPI_prepare(UTF_U2E(Tcl_GetString(objv[1])),
								  nargs, qdesc->argtypes);
		UTF_END;

		if (qdesc->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).
		 ************************************************************/
		if (SPI_keepplan(qdesc->plan))
			elog(ERROR, "SPI_keepplan() failed");

		pltcl_subtrans_commit(oldcontext, oldowner);
	}
	PG_CATCH();
	{
		pltcl_subtrans_abort(interp, oldcontext, oldowner);

		MemoryContextDelete(plan_cxt);

		return TCL_ERROR;
	}
	PG_END_TRY();

	/************************************************************
	 * Insert a hashtable entry for the plan and return
	 * the key to the caller
	 ************************************************************/
	query_hash = &pltcl_current_call_state->prodesc->interp_desc->query_hash;

	hashent = Tcl_CreateHashEntry(query_hash, qdesc->qname, &hashnew);
	Tcl_SetHashValue(hashent, (ClientData) qdesc);

	/* qname is ASCII, so no need for encoding conversion */
	Tcl_SetObjResult(interp, Tcl_NewStringObj(qdesc->qname, -1));
	return TCL_OK;
}
/**********************************************************************
 * pltcl_SPI_prepare()		- Builtin support for prepared plans
 *				  The Tcl command SPI_prepare
 *				  always saves the plan using
 *				  SPI_keepplan and returns a key for
 *				  access. There is no chance to prepare
 *				  and not save the plan currently.
 **********************************************************************/
pltcl_SPI_prepare()          - Builtin support for prepared plans
The Tcl command SPI_prepare
always saves the plan using
SPI_keepplan and returns a key for
access. There is no chance to prepare
and not save the plan currently.
pltcl_SPI_prepare () - Builtin support for prepared plans The Tcl command SPI_prepare always saves the plan using SPI_keepplan and returns a key for access . There is no chance to prepare and not save the plan currently .
static int
pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
				  int objc, Tcl_Obj *const objv[])
{
	volatile MemoryContext plan_cxt = NULL;
	int			nargs;
	Tcl_Obj   **argsObj;
	pltcl_query_desc *qdesc;
	int			i;
	Tcl_HashEntry *hashent;
	int			hashnew;
	Tcl_HashTable *query_hash;
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;
	if (objc != 3)
	{
		Tcl_WrongNumArgs(interp, 1, objv, "query argtypes");
		return TCL_ERROR;
	}
	if (Tcl_ListObjGetElements(interp, objv[2], &nargs, &argsObj) != TCL_OK)
		return TCL_ERROR;
	plan_cxt = AllocSetContextCreate(TopMemoryContext,
									 "PL/Tcl spi_prepare query",
									 ALLOCSET_SMALL_SIZES);
	MemoryContextSwitchTo(plan_cxt);
	qdesc = (pltcl_query_desc *) palloc0(sizeof(pltcl_query_desc));
	snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc);
	qdesc->nargs = nargs;
	qdesc->argtypes = (Oid *) palloc(nargs * sizeof(Oid));
	qdesc->arginfuncs = (FmgrInfo *) palloc(nargs * sizeof(FmgrInfo));
	qdesc->argtypioparams = (Oid *) palloc(nargs * sizeof(Oid));
	MemoryContextSwitchTo(oldcontext);
	pltcl_subtrans_begin(oldcontext, oldowner);
	PG_TRY();
	{
		for (i = 0; i < nargs; i++)
		{
			Oid			typId,
						typInput,
						typIOParam;
			int32		typmod;
			parseTypeString(Tcl_GetString(argsObj[i]), &typId, &typmod, false);
			getTypeInputInfo(typId, &typInput, &typIOParam);
			qdesc->argtypes[i] = typId;
			fmgr_info_cxt(typInput, &(qdesc->arginfuncs[i]), plan_cxt);
			qdesc->argtypioparams[i] = typIOParam;
		}
		UTF_BEGIN;
		qdesc->plan = SPI_prepare(UTF_U2E(Tcl_GetString(objv[1])),
								  nargs, qdesc->argtypes);
		UTF_END;
		if (qdesc->plan == NULL)
			elog(ERROR, "SPI_prepare() failed");
		if (SPI_keepplan(qdesc->plan))
			elog(ERROR, "SPI_keepplan() failed");
		pltcl_subtrans_commit(oldcontext, oldowner);
	}
	PG_CATCH();
	{
		pltcl_subtrans_abort(interp, oldcontext, oldowner);
		MemoryContextDelete(plan_cxt);
		return TCL_ERROR;
	}
	PG_END_TRY();
	query_hash = &pltcl_current_call_state->prodesc->interp_desc->query_hash;
	hashent = Tcl_CreateHashEntry(query_hash, qdesc->qname, &hashnew);
	Tcl_SetHashValue(hashent, (ClientData) qdesc);
	Tcl_SetObjResult(interp, Tcl_NewStringObj(qdesc->qname, -1));
	return TCL_OK;
}
static int pltcl_SPI_prepare ( ClientData cdata , Tcl_Interp * interp , int objc , Tcl_Obj * const objv [ ] ) { volatile MemoryContext plan_cxt = NULL ; int nargs ; Tcl_Obj * * argsObj ; pltcl_query_desc * qdesc ; int i ; Tcl_HashEntry * hashent ; int hashnew ; Tcl_HashTable * query_hash ; MemoryContext oldcontext = CurrentMemoryContext ; ResourceOwner oldowner = CurrentResourceOwner ; if ( objc != 3 ) { Tcl_WrongNumArgs ( interp , 1 , objv , " " ) ; return TCL_ERROR ; } if ( Tcl_ListObjGetElements ( interp , objv [ 2 ] , & nargs , & argsObj ) != TCL_OK ) return TCL_ERROR ; plan_cxt = AllocSetContextCreate ( TopMemoryContext , " " , ALLOCSET_SMALL_SIZES ) ; MemoryContextSwitchTo ( plan_cxt ) ; qdesc = ( pltcl_query_desc * ) palloc0 ( sizeof ( pltcl_query_desc ) ) ; snprintf ( qdesc -> qname , sizeof ( qdesc -> qname ) , " " , qdesc ) ; qdesc -> nargs = nargs ; qdesc -> argtypes = ( Oid * ) palloc ( nargs * sizeof ( Oid ) ) ; qdesc -> arginfuncs = ( FmgrInfo * ) palloc ( nargs * sizeof ( FmgrInfo ) ) ; qdesc -> argtypioparams = ( Oid * ) palloc ( nargs * sizeof ( Oid ) ) ; MemoryContextSwitchTo ( oldcontext ) ; pltcl_subtrans_begin ( oldcontext , oldowner ) ; PG_TRY ( ) ; { for ( i = 0 ; i < nargs ; i ++ ) { Oid typId , typInput , typIOParam ; int32 typmod ; parseTypeString ( Tcl_GetString ( argsObj [ i ] ) , & typId , & typmod , false ) ; getTypeInputInfo ( typId , & typInput , & typIOParam ) ; qdesc -> argtypes [ i ] = typId ; fmgr_info_cxt ( typInput , & ( qdesc -> arginfuncs [ i ] ) , plan_cxt ) ; qdesc -> argtypioparams [ i ] = typIOParam ; } UTF_BEGIN ; qdesc -> plan = SPI_prepare ( UTF_U2E ( Tcl_GetString ( objv [ 1 ] ) ) , nargs , qdesc -> argtypes ) ; UTF_END ; if ( qdesc -> plan == NULL ) elog ( ERROR , " " ) ; if ( SPI_keepplan ( qdesc -> plan ) ) elog ( ERROR , " " ) ; pltcl_subtrans_commit ( oldcontext , oldowner ) ; } PG_CATCH ( ) ; { pltcl_subtrans_abort ( interp , oldcontext , oldowner ) ; MemoryContextDelete ( plan_cxt ) ; return TCL_ERROR ; } PG_END_TRY ( ) ; query_hash = & pltcl_current_call_state -> prodesc -> interp_desc -> query_hash ; hashent = Tcl_CreateHashEntry ( query_hash , qdesc -> qname , & hashnew ) ; Tcl_SetHashValue ( hashent , ( ClientData ) qdesc ) ; Tcl_SetObjResult ( interp , Tcl_NewStringObj ( qdesc -> qname , -1 ) ) ; return TCL_OK ; }
pltcl_SPI_prepare()          - Builtin support for prepared plans
                                The Tcl command SPI_prepare
                                always saves the plan using
                                SPI_keepplan and returns a key for
                                access.
pltcl_SPI_prepare () - Builtin support for prepared plans The Tcl command SPI_prepare always saves the plan using SPI_keepplan and returns a key for access .
/************************************************************
	 * Check the call syntax
	 ************************************************************/ /************************************************************
	 * Split the argument type list
	 ************************************************************/ /************************************************************
	 * Allocate the new querydesc structure
	 *
	 * struct qdesc and subsidiary data all live in plan_cxt.  Note that if the
	 * function is recompiled for whatever reason, permanent memory leaks
	 * occur.  FIXME someday.
	 ************************************************************/ /************************************************************
	 * Execute the prepare inside a sub-transaction, so we can cope with
	 * errors sanely
	 ************************************************************/ /************************************************************
		 * Resolve argument type names and then look them up by oid
		 * in the system cache, and remember the required information
		 * for input conversion.
		 ************************************************************/ /************************************************************
		 * Prepare the plan and check for errors
		 ************************************************************/ /************************************************************
		 * Save the plan into permanent memory (right now it's in the
		 * SPI procCxt, which will go away at function end).
		 ************************************************************/ /************************************************************
	 * Insert a hashtable entry for the plan and return
	 * the key to the caller
	 ************************************************************/ /* qname is ASCII, so no need for encoding conversion */