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

📄 pltcl.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
				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;			typioparam = getTypeIOParam(typeTup);			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(typioparam),					   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);	}	PG_CATCH();	{		ckfree((char *) ret_values);		PG_RE_THROW();	}	PG_END_TRY();	ckfree((char *) ret_values);	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[33 * FUNC_MAX_ARGS];		Datum		prosrcdatum;		bool		isnull;		char	   *proc_source;		char		buf[32];		/************************************************************		 * 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);		/* Remember if function is STABLE/IMMUTABLE */		prodesc->fn_readonly =			(procStruct->provolatile != PROVOLATILE_VOLATILE);		/************************************************************		 * 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->typtype == 'c')			{				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_typioparam = getTypeIOParam(typeTup);			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.values[i]),										 0, 0, 0);				if (!HeapTupleIsValid(typeTup))				{					free(prodesc->proname);					free(prodesc);					elog(ERROR, "cache lookup failed for type %u",						 procStruct->proargtypes.values[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.values[i]))));				}				if (typeStruct->typtype == 'c')				{					prodesc->arg_is_rowtype[i] = true;					snprintf(buf, sizeof(buf), "__PLTcl_Tup_%d", i + 1);				}				else				{					prodesc->arg_is_rowtype[i] = false;					perm_fmgr_info(typeStruct->typoutput,								   &(prodesc->arg_out_func[i]));					snprintf(buf, sizeof(buf), "%d", i + 1);				}				if (i > 0)					strcat(proc_internal_args, " ");				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_rowtype[i])				{					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"							  "foreach v $args {\n"							  "  incr i\n"							  "  set $i $v\n"							  "}\n"							  "unset i v\n\n", -1);		}		/************************************************************		 * Add user's function definition to proc body		 ************************************************************/		prosrcdatum = SysCacheGetAttr(PROCOID, procTup,									  Anum_pg_proc_prosrc, &isnull);		if (isnull)			elog(ERROR, "null prosrc");		proc_source = DatumGetCString(DirectFunctionCall1(textout,														  prosrcdatum));		UTF_BEGIN;		Tcl_DStringAppend(&proc_internal_body, UTF_E2U(proc_source), -1);		UTF_END;		pfree(proc_source);		Tcl_DStringAppendElement(&proc_internal_def,								 Tcl_DStringValue(&proc_internal_body));		Tcl_DStringFree(&proc_internal_body);		/************************************************************		 * Create the procedure in the interpreter		 ************************************************************/		tcl_rc = Tcl_GlobalEval(interp,								Tcl_DStringValue(&proc_internal_def));		Tcl_DStringFree(&proc_internal_def);		if (tcl_rc != TCL_OK)		{			free(prodesc->proname);			free(prodesc);			elog(ERROR, "could not create internal procedure \"%s\": %s",				 internal_proname, interp->result);		}		/************************************************************		 * Add the proc description block to the hashtable		 ************************************************************/		hashent = Tcl_CreateHashEntry(pltcl_proc_hash,									  prodesc->proname, &hashnew);		Tcl_SetHashValue(hashent, (ClientData) prodesc);	}	ReleaseSysCache(procTup);	return prodesc;}/********************************************************************** * pltcl_elog()		- elog() support for PLTcl **********************************************************************/static intpltcl_elog(ClientData cdata, Tcl_Interp *interp,		   int argc, CONST84 char *argv[]){	volatile int level;	MemoryContext oldcontext;	if (argc != 3)	{		Tcl_SetResult(interp, "syntax error - 'elog level msg'",					  TCL_VOLATILE);		return TCL_ERROR;	}	if (strcmp(argv[1], "DEBUG") == 0)		level = DEBUG2;	else if (strcmp(argv[1], "LOG") == 0)		level = LOG;	else if (strcmp(argv[1], "INFO") == 0)		level = INFO;	else if (strcmp(argv[1], "NOTICE") == 0)		level = NOTICE;	else if (strcmp(argv[1], "WARNING") == 0)		level = WARNING;	else if (strcmp(argv[1], "ERROR") == 0)		level = ERROR;	else if (strcmp(argv[1], "FATAL") == 0)		level = FATAL;	else	{		Tcl_AppendResult(interp, "Unknown elog level '", argv[1],						 "'", NULL);		return TCL_ERROR;	}	/************************************************************	 * If elog() throws an error, catch it and return the error to the	 * Tcl interpreter.  Note we are assuming that elog() can't have any	 * internal failures that are so bad as to require a transaction abort.	 ************************************************************/	oldcontext = CurrentMemoryContext;	PG_TRY();	{		UTF_BEGIN;		elog(level, "%s", UTF_U2E(argv[2]));		UTF_END;	}	PG_CATCH();	{		ErrorData  *edata;

⌨️ 快捷键说明

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