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

📄 pltcl.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 5 页
字号:
pltcl_func_handler(FmgrInfo *proinfo,				   FmgrValues *proargs,				   bool *isNull){	int			i;	char		internal_proname[512];	char	   *stroid;	Tcl_HashEntry *hashent;	int			hashnew;	pltcl_proc_desc *prodesc;	Tcl_DString tcl_cmd;	Tcl_DString list_tmp;	int			tcl_rc;	Datum		retval;	sigjmp_buf	save_restart;	/************************************************************	 * Build our internal proc name from the functions Oid	 ************************************************************/	stroid = oidout(proinfo->fn_oid);	strcpy(internal_proname, "__PLTcl_proc_");	strcat(internal_proname, stroid);	pfree(stroid);	/************************************************************	 * Lookup the internal proc name in the hashtable	 ************************************************************/	hashent = Tcl_FindHashEntry(pltcl_proc_hash, internal_proname);	if (hashent == NULL)	{		/************************************************************		 * If we haven't found it in the hashtable, we analyze		 * the functions arguments and returntype and store		 * the in-/out-functions in the prodesc block and create		 * a new hashtable entry for it.		 *		 * Then we load the procedure into the safe interpreter.		 ************************************************************/		HeapTuple	procTup;		HeapTuple	typeTup;		Form_pg_proc procStruct;		Form_pg_type typeStruct;		Tcl_DString proc_internal_def;		Tcl_DString proc_internal_body;		char		proc_internal_args[4096];		char	   *proc_source;		char		buf[512];		/************************************************************		 * Allocate a new procedure description block		 ************************************************************/		prodesc = (pltcl_proc_desc *) malloc(sizeof(pltcl_proc_desc));		prodesc->proname = malloc(strlen(internal_proname) + 1);		strcpy(prodesc->proname, internal_proname);		/************************************************************		 * Lookup the pg_proc tuple by Oid		 ************************************************************/		procTup = SearchSysCacheTuple(PROOID,									  ObjectIdGetDatum(proinfo->fn_oid),									  0, 0, 0);		if (!HeapTupleIsValid(procTup))		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "pltcl: cache lookup from pg_proc failed");		}		procStruct = (Form_pg_proc) GETSTRUCT(procTup);		/************************************************************		 * Get the required information for input conversion of the		 * return value.		 ************************************************************/		typeTup = SearchSysCacheTuple(TYPOID,								ObjectIdGetDatum(procStruct->prorettype),									  0, 0, 0);		if (!HeapTupleIsValid(typeTup))		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "pltcl: cache lookup for return type failed");		}		typeStruct = (Form_pg_type) GETSTRUCT(typeTup);		if (typeStruct->typrelid != InvalidOid)		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "pltcl: return types of tuples not supported yet");		}		fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));		prodesc->result_in_elem = (Oid) (typeStruct->typelem);		prodesc->result_in_len = typeStruct->typlen;		/************************************************************		 * Get the required information for output conversion		 * of all procedure arguments		 ************************************************************/		prodesc->nargs = proinfo->fn_nargs;		proc_internal_args[0] = '\0';		for (i = 0; i < proinfo->fn_nargs; i++)		{			typeTup = SearchSysCacheTuple(TYPOID,							ObjectIdGetDatum(procStruct->proargtypes[i]),										  0, 0, 0);			if (!HeapTupleIsValid(typeTup))			{				free(prodesc->proname);				free(prodesc);				elog(ERROR, "pltcl: cache lookup for argument type failed");			}			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);			if (typeStruct->typrelid != InvalidOid)			{				prodesc->arg_is_rel[i] = 1;				if (i > 0)					strcat(proc_internal_args, " ");				sprintf(buf, "__PLTcl_Tup_%d", i + 1);				strcat(proc_internal_args, buf);				continue;			}			else				prodesc->arg_is_rel[i] = 0;			fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));			prodesc->arg_out_elem[i] = (Oid) (typeStruct->typelem);			prodesc->arg_out_len[i] = typeStruct->typlen;			if (i > 0)				strcat(proc_internal_args, " ");			sprintf(buf, "%d", i + 1);			strcat(proc_internal_args, buf);		}		/************************************************************		 * Create the tcl command to define the internal		 * procedure		 ************************************************************/		Tcl_DStringInit(&proc_internal_def);		Tcl_DStringInit(&proc_internal_body);		Tcl_DStringAppendElement(&proc_internal_def, "proc");		Tcl_DStringAppendElement(&proc_internal_def, internal_proname);		Tcl_DStringAppendElement(&proc_internal_def, proc_internal_args);		/************************************************************		 * prefix procedure body with		 * upvar #0 <internal_procname> GD		 * and with appropriate upvars for tuple arguments		 ************************************************************/		Tcl_DStringAppend(&proc_internal_body, "upvar #0 ", -1);		Tcl_DStringAppend(&proc_internal_body, internal_proname, -1);		Tcl_DStringAppend(&proc_internal_body, " GD\n", -1);		for (i = 0; i < proinfo->fn_nargs; i++)		{			if (!prodesc->arg_is_rel[i])				continue;			sprintf(buf, "array set %d $__PLTcl_Tup_%d\n", i + 1, i + 1);			Tcl_DStringAppend(&proc_internal_body, buf, -1);		}		proc_source = textout(&(procStruct->prosrc));		Tcl_DStringAppend(&proc_internal_body, proc_source, -1);		pfree(proc_source);		Tcl_DStringAppendElement(&proc_internal_def,								 Tcl_DStringValue(&proc_internal_body));		Tcl_DStringFree(&proc_internal_body);		/************************************************************		 * Create the procedure in the safe interpreter		 ************************************************************/		tcl_rc = Tcl_GlobalEval(pltcl_safe_interp,								Tcl_DStringValue(&proc_internal_def));		Tcl_DStringFree(&proc_internal_def);		if (tcl_rc != TCL_OK)		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "pltcl: cannot create internal procedure %s - %s",				 internal_proname, pltcl_safe_interp->result);		}		/************************************************************		 * Add the proc description block to the hashtable		 ************************************************************/		hashent = Tcl_CreateHashEntry(pltcl_proc_hash,									  prodesc->proname, &hashnew);		Tcl_SetHashValue(hashent, (ClientData) prodesc);	}	else	{		/************************************************************		 * Found the proc description block in the hashtable		 ************************************************************/		prodesc = (pltcl_proc_desc *) Tcl_GetHashValue(hashent);	}	/************************************************************	 * Create the tcl command to call the internal	 * proc in the safe interpreter	 ************************************************************/	Tcl_DStringInit(&tcl_cmd);	Tcl_DStringInit(&list_tmp);	Tcl_DStringAppendElement(&tcl_cmd, internal_proname);	/************************************************************	 * Catch elog(ERROR) during build of the Tcl command	 ************************************************************/	memcpy(&save_restart, &Warn_restart, sizeof(save_restart));	if (sigsetjmp(Warn_restart, 1) != 0)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		Tcl_DStringFree(&tcl_cmd);		Tcl_DStringFree(&list_tmp);		pltcl_restart_in_progress = 1;		if (--pltcl_call_level == 0)			pltcl_restart_in_progress = 0;		siglongjmp(Warn_restart, 1);	}	/************************************************************	 * Add all call arguments to the command	 ************************************************************/	for (i = 0; i < prodesc->nargs; i++)	{		if (prodesc->arg_is_rel[i])		{			/**************************************************			 * For tuple values, add a list for 'array set ...'			 **************************************************/			Tcl_DStringInit(&list_tmp);			pltcl_build_tuple_argument(							((TupleTableSlot *) (proargs->data[i]))->val,			((TupleTableSlot *) (proargs->data[i]))->ttc_tupleDescriptor,									   &list_tmp);			Tcl_DStringAppendElement(&tcl_cmd, Tcl_DStringValue(&list_tmp));			Tcl_DStringFree(&list_tmp);			Tcl_DStringInit(&list_tmp);		}		else		{			/**************************************************			 * Single values are added as string element			 * of their external representation			 **************************************************/			char	   *tmp;			tmp = (*fmgr_faddr(&(prodesc->arg_out_func[i])))				(proargs->data[i],				 prodesc->arg_out_elem[i],				 prodesc->arg_out_len[i]);			Tcl_DStringAppendElement(&tcl_cmd, tmp);			pfree(tmp);		}	}	Tcl_DStringFree(&list_tmp);	memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));	/************************************************************	 * Call the Tcl function	 ************************************************************/	tcl_rc = Tcl_GlobalEval(pltcl_safe_interp, Tcl_DStringValue(&tcl_cmd));	Tcl_DStringFree(&tcl_cmd);	/************************************************************	 * Check the return code from Tcl and handle	 * our special restart mechanism to get rid	 * of all nested call levels on transaction	 * abort.	 ************************************************************/	if (tcl_rc != TCL_OK || pltcl_restart_in_progress)	{		if (!pltcl_restart_in_progress)		{			pltcl_restart_in_progress = 1;			if (--pltcl_call_level == 0)				pltcl_restart_in_progress = 0;			elog(ERROR, "pltcl: %s", pltcl_safe_interp->result);		}		if (--pltcl_call_level == 0)			pltcl_restart_in_progress = 0;		siglongjmp(Warn_restart, 1);	}	/************************************************************	 * Convert the result value from the safe interpreter	 * into it's PostgreSQL data format and return it.	 * Again, the call to fmgr() could fire an elog and we	 * have to count for the current interpreter level we are	 * on. The save_restart from above is still good.	 ************************************************************/	if (sigsetjmp(Warn_restart, 1) != 0)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		pltcl_restart_in_progress = 1;		if (--pltcl_call_level == 0)			pltcl_restart_in_progress = 0;		siglongjmp(Warn_restart, 1);	}	/************************************************************	 * Disconnect from SPI manager and then create the return	 * values datum (if the input function does a palloc for it	 * this must not be allocated in the SPI memory context	 * because SPI_finish would free it).	 ************************************************************/	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "pltcl: SPI_finish() failed");	retval = (Datum) (*fmgr_faddr(&prodesc->result_in_func))		(pltcl_safe_interp->result,		 prodesc->result_in_elem,		 prodesc->result_in_len);	memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));	return retval;}/********************************************************************** * pltcl_trigger_handler()	- Handler for trigger calls **********************************************************************/static HeapTuplepltcl_trigger_handler(FmgrInfo *proinfo){	TriggerData *trigdata;	char		internal_proname[512];	char	   *stroid;	Tcl_HashEntry *hashent;	int			hashnew;	pltcl_proc_desc *prodesc;	TupleDesc	tupdesc;	HeapTuple	rettup;	Tcl_DString tcl_cmd;	Tcl_DString tcl_trigtup;	Tcl_DString tcl_newtup;	int			tcl_rc;	int			i;	int		   *modattrs;	Datum	   *modvalues;	char	   *modnulls;	int			ret_numvals;	char	  **ret_values;	sigjmp_buf	save_restart;	/************************************************************	 * Save the current trigger data local	 ************************************************************/	trigdata = CurrentTriggerData;	CurrentTriggerData = NULL;	/************************************************************	 * Build our internal proc name from the functions Oid	 ************************************************************/	stroid = oidout(proinfo->fn_oid);	strcpy(internal_proname, "__PLTcl_proc_");	strcat(internal_proname, stroid);	pfree(stroid);	/************************************************************	 * Lookup the internal proc name in the hashtable	 ************************************************************/	hashent = Tcl_FindHashEntry(pltcl_proc_hash, internal_proname);	if (hashent == NULL)	{		/************************************************************		 * If we haven't found it in the hashtable,		 * we load the procedure into the safe interpreter.		 ************************************************************/		Tcl_DString proc_internal_def;		Tcl_DString proc_internal_body;		HeapTuple	procTup;		Form_pg_proc procStruct;		char	   *proc_source;		/************************************************************		 * Allocate a new procedure description block		 ************************************************************/		prodesc = (pltcl_proc_desc *) malloc(sizeof(pltcl_proc_desc));		memset(prodesc, 0, sizeof(pltcl_proc_desc));		prodesc->proname = malloc(strlen(internal_proname) + 1);		strcpy(prodesc->proname, internal_proname);		/************************************************************		 * Lookup the pg_proc tuple by Oid		 ************************************************************/		procTup = SearchSysCacheTuple(PROOID,									  ObjectIdGetDatum(proinfo->fn_oid),									  0, 0, 0);		if (!HeapTupleIsValid(procTup))		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "pltcl: cache lookup from pg_proc failed");		}		procStruct = (Form_pg_proc) GETSTRUCT(procTup);		/************************************************************		 * Create the tcl command to define the internal		 * procedure		 ************************************************************/		Tcl_DStringInit(&proc_internal_def);		Tcl_DStringInit(&proc_internal_body);		Tcl_DStringAppendElement(&proc_internal_def, "proc");		Tcl_DStringAppendElement(&proc_internal_def, internal_proname);		Tcl_DStringAppendElement(&proc_internal_def,								 "TG_name TG_relid TG_relatts TG_when TG_level TG_op __PLTcl_Tup_NEW __PLTcl_Tup_OLD args");		/************************************************************

⌨️ 快捷键说明

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