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

📄 pltcl.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
	{		case TCL_OK:			break;		default:			elog(ERROR, "unsupported TCL return code: %d", tcl_rc);	}	/************************************************************	 * The return value from the procedure might be one of	 * the magic strings OK or SKIP or a list from array get	 ************************************************************/	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "SPI_finish() failed");	if (strcmp(interp->result, "OK") == 0)		return rettup;	if (strcmp(interp->result, "SKIP") == 0)		return (HeapTuple) NULL;	/************************************************************	 * Convert the result value from the Tcl interpreter	 * and setup structures for SPI_modifytuple();	 ************************************************************/	if (Tcl_SplitList(interp, interp->result,					  &ret_numvals, &ret_values) != TCL_OK)		elog(ERROR, "could not split return value from trigger: %s",			 interp->result);	if (ret_numvals % 2 != 0)	{		ckfree((char *) ret_values);		elog(ERROR, "invalid return list from trigger - must have even # of elements");	}	modattrs = (int *) palloc(tupdesc->natts * sizeof(int));	modvalues = (Datum *) palloc(tupdesc->natts * sizeof(Datum));	for (i = 0; i < tupdesc->natts; i++)	{		modattrs[i] = i + 1;		modvalues[i] = (Datum) NULL;	}	modnulls = palloc(tupdesc->natts);	memset(modnulls, 'n', tupdesc->natts);	/************************************************************	 * Care for possible elog(ERROR)'s below	 ************************************************************/	if (sigsetjmp(Warn_restart, 1) != 0)	{		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));		ckfree((char *) ret_values);		pltcl_restart_in_progress = 1;		if (--pltcl_call_level == 0)			pltcl_restart_in_progress = 0;		siglongjmp(Warn_restart, 1);	}	for (i = 0; i < ret_numvals; i += 2)	{		CONST84 char *ret_name = ret_values[i];		CONST84 char *ret_value = ret_values[i + 1];		int			attnum;		HeapTuple	typeTup;		Oid			typinput;		Oid			typelem;		FmgrInfo	finfo;		/************************************************************		 * Ignore ".tupno" pseudo elements (see pltcl_set_tuple_values)		 ************************************************************/		if (strcmp(ret_name, ".tupno") == 0)			continue;		/************************************************************		 * Get the attribute number		 ************************************************************/		attnum = SPI_fnumber(tupdesc, ret_name);		if (attnum == SPI_ERROR_NOATTRIBUTE)			elog(ERROR, "invalid attribute \"%s\"", ret_name);		if (attnum <= 0)			elog(ERROR, "cannot set system attribute \"%s\"", ret_name);		/************************************************************		 * Ignore dropped columns		 ************************************************************/		if (tupdesc->attrs[attnum - 1]->attisdropped)			continue;		/************************************************************		 * Lookup the attribute type in the syscache		 * for the input function		 ************************************************************/		typeTup = SearchSysCache(TYPEOID,				  ObjectIdGetDatum(tupdesc->attrs[attnum - 1]->atttypid),								 0, 0, 0);		if (!HeapTupleIsValid(typeTup))			elog(ERROR, "cache lookup failed for type %u",				 tupdesc->attrs[attnum - 1]->atttypid);		typinput = ((Form_pg_type) GETSTRUCT(typeTup))->typinput;		typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;		ReleaseSysCache(typeTup);		/************************************************************		 * Set the attribute to NOT NULL and convert the contents		 ************************************************************/		modnulls[attnum - 1] = ' ';		fmgr_info(typinput, &finfo);		UTF_BEGIN;		modvalues[attnum - 1] =			FunctionCall3(&finfo,						  CStringGetDatum(UTF_U2E(ret_value)),						  ObjectIdGetDatum(typelem),				   Int32GetDatum(tupdesc->attrs[attnum - 1]->atttypmod));		UTF_END;	}	rettup = SPI_modifytuple(trigdata->tg_relation, rettup, tupdesc->natts,							 modattrs, modvalues, modnulls);	pfree(modattrs);	pfree(modvalues);	pfree(modnulls);	if (rettup == NULL)		elog(ERROR, "SPI_modifytuple() failed - RC = %d", SPI_result);	ckfree((char *) ret_values);	memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));	return rettup;}/********************************************************************** * compile_pltcl_function	- compile (or hopefully just look up) function * * tgreloid is the OID of the relation when compiling a trigger, or zero * (InvalidOid) when compiling a plain function. **********************************************************************/static pltcl_proc_desc *compile_pltcl_function(Oid fn_oid, Oid tgreloid){	bool		is_trigger = OidIsValid(tgreloid);	HeapTuple	procTup;	Form_pg_proc procStruct;	char		internal_proname[128];	Tcl_HashEntry *hashent;	pltcl_proc_desc *prodesc = NULL;	Tcl_Interp *interp;	int			i;	int			hashnew;	int			tcl_rc;	/* We'll need the pg_proc tuple in any case... */	procTup = SearchSysCache(PROCOID,							 ObjectIdGetDatum(fn_oid),							 0, 0, 0);	if (!HeapTupleIsValid(procTup))		elog(ERROR, "cache lookup failed for function %u", fn_oid);	procStruct = (Form_pg_proc) GETSTRUCT(procTup);	/************************************************************	 * Build our internal proc name from the functions Oid	 ************************************************************/	if (!is_trigger)		snprintf(internal_proname, sizeof(internal_proname),				 "__PLTcl_proc_%u", fn_oid);	else		snprintf(internal_proname, sizeof(internal_proname),				 "__PLTcl_proc_%u_trigger_%u", fn_oid, tgreloid);	/************************************************************	 * Lookup the internal proc name in the hashtable	 ************************************************************/	hashent = Tcl_FindHashEntry(pltcl_proc_hash, internal_proname);	/************************************************************	 * If it's present, must check whether it's still up to date.	 * This is needed because CREATE OR REPLACE FUNCTION can modify the	 * function's pg_proc entry without changing its OID.	 ************************************************************/	if (hashent != NULL)	{		bool		uptodate;		prodesc = (pltcl_proc_desc *) Tcl_GetHashValue(hashent);		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&			prodesc->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));		if (!uptodate)		{			Tcl_DeleteHashEntry(hashent);			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 Tcl interpreter.	 ************************************************************/	if (hashent == NULL)	{		HeapTuple	langTup;		HeapTuple	typeTup;		Form_pg_language langStruct;		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));		if (prodesc == NULL)			ereport(ERROR,					(errcode(ERRCODE_OUT_OF_MEMORY),					 errmsg("out of memory")));		MemSet(prodesc, 0, sizeof(pltcl_proc_desc));		prodesc->proname = strdup(internal_proname);		prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);		prodesc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);		/************************************************************		 * Lookup the pg_language tuple by Oid		 ************************************************************/		langTup = SearchSysCache(LANGOID,								 ObjectIdGetDatum(procStruct->prolang),								 0, 0, 0);		if (!HeapTupleIsValid(langTup))		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "cache lookup failed for language %u",				 procStruct->prolang);		}		langStruct = (Form_pg_language) GETSTRUCT(langTup);		prodesc->lanpltrusted = langStruct->lanpltrusted;		ReleaseSysCache(langTup);		if (prodesc->lanpltrusted)			interp = pltcl_safe_interp;		else			interp = pltcl_norm_interp;		/************************************************************		 * Get the required information for input conversion of the		 * return value.		 ************************************************************/		if (!is_trigger)		{			typeTup = SearchSysCache(TYPEOID,								ObjectIdGetDatum(procStruct->prorettype),									 0, 0, 0);			if (!HeapTupleIsValid(typeTup))			{				free(prodesc->proname);				free(prodesc);				elog(ERROR, "cache lookup failed for type %u",					 procStruct->prorettype);			}			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);			/* Disallow pseudotype result, except VOID */			if (typeStruct->typtype == 'p')			{				if (procStruct->prorettype == VOIDOID)					 /* okay */ ;				else if (procStruct->prorettype == TRIGGEROID)				{					free(prodesc->proname);					free(prodesc);					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),							 errmsg("trigger functions may only be called as triggers")));				}				else				{					free(prodesc->proname);					free(prodesc);					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						  errmsg("pltcl functions cannot return type %s",							   format_type_be(procStruct->prorettype))));				}			}			if (typeStruct->typrelid != InvalidOid)			{				free(prodesc->proname);				free(prodesc);				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					errmsg("pltcl functions cannot return tuples yet")));			}			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));			prodesc->result_in_elem = typeStruct->typelem;			ReleaseSysCache(typeTup);		}		/************************************************************		 * Get the required information for output conversion		 * of all procedure arguments		 ************************************************************/		if (!is_trigger)		{			prodesc->nargs = procStruct->pronargs;			proc_internal_args[0] = '\0';			for (i = 0; i < prodesc->nargs; i++)			{				typeTup = SearchSysCache(TYPEOID,							ObjectIdGetDatum(procStruct->proargtypes[i]),										 0, 0, 0);				if (!HeapTupleIsValid(typeTup))				{					free(prodesc->proname);					free(prodesc);					elog(ERROR, "cache lookup failed for type %u",						 procStruct->proargtypes[i]);				}				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);				/* Disallow pseudotype argument */				if (typeStruct->typtype == 'p')				{					free(prodesc->proname);					free(prodesc);					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),							 errmsg("pltcl functions cannot take type %s",						   format_type_be(procStruct->proargtypes[i]))));				}				if (typeStruct->typrelid != InvalidOid)				{					prodesc->arg_is_rel[i] = 1;					if (i > 0)						strcat(proc_internal_args, " ");					snprintf(buf, sizeof(buf), "__PLTcl_Tup_%d", i + 1);					strcat(proc_internal_args, buf);					ReleaseSysCache(typeTup);					continue;				}				else					prodesc->arg_is_rel[i] = 0;				perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));				prodesc->arg_out_elem[i] = typeStruct->typelem;				if (i > 0)					strcat(proc_internal_args, " ");				snprintf(buf, sizeof(buf), "%d", i + 1);				strcat(proc_internal_args, buf);				ReleaseSysCache(typeTup);			}		}		else		{			/* trigger procedure has fixed args */			strcpy(proc_internal_args,				   "TG_name TG_relid TG_relatts TG_when TG_level TG_op __PLTcl_Tup_NEW __PLTcl_Tup_OLD args");		}		/************************************************************		 * 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 setting of 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);		if (!is_trigger)		{			for (i = 0; i < prodesc->nargs; i++)			{				if (!prodesc->arg_is_rel[i])					continue;				snprintf(buf, sizeof(buf), "array set %d $__PLTcl_Tup_%d\n",						 i + 1, i + 1);				Tcl_DStringAppend(&proc_internal_body, buf, -1);			}		}		else		{			Tcl_DStringAppend(&proc_internal_body,							  "array set NEW $__PLTcl_Tup_NEW\n", -1);			Tcl_DStringAppend(&proc_internal_body,							  "array set OLD $__PLTcl_Tup_OLD\n", -1);			Tcl_DStringAppend(&proc_internal_body,							  "set i 0\n"							  "set v 0\n"

⌨️ 快捷键说明

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