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

📄 pltcl.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
		}	}	PG_CATCH();	{		pltcl_current_fcinfo = save_fcinfo;		pltcl_current_prodesc = save_prodesc;		PG_RE_THROW();	}	PG_END_TRY();	pltcl_current_fcinfo = save_fcinfo;	pltcl_current_prodesc = save_prodesc;	return retval;}/* * Alternate handler for unsafe functions */PG_FUNCTION_INFO_V1(pltclu_call_handler);/* keep non-static */Datumpltclu_call_handler(PG_FUNCTION_ARGS){	return pltcl_call_handler(fcinfo);}/********************************************************************** * pltcl_func_handler()		- Handler for regular function calls **********************************************************************/static Datumpltcl_func_handler(PG_FUNCTION_ARGS){	pltcl_proc_desc *prodesc;	Tcl_Interp *volatile interp;	Tcl_DString tcl_cmd;	Tcl_DString list_tmp;	int			i;	int			tcl_rc;	Datum		retval;	/* Connect to SPI manager */	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "could not connect to SPI manager");	/* Find or compile the function */	prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid, InvalidOid);	pltcl_current_prodesc = prodesc;	if (prodesc->lanpltrusted)		interp = pltcl_safe_interp;	else		interp = pltcl_norm_interp;	/************************************************************	 * Create the tcl command to call the internal	 * proc in the Tcl interpreter	 ************************************************************/	Tcl_DStringInit(&tcl_cmd);	Tcl_DStringInit(&list_tmp);	Tcl_DStringAppendElement(&tcl_cmd, prodesc->proname);	/************************************************************	 * Add all call arguments to the command	 ************************************************************/	PG_TRY();	{		for (i = 0; i < prodesc->nargs; i++)		{			if (prodesc->arg_is_rowtype[i])			{				/**************************************************				 * For tuple values, add a list for 'array set ...'				 **************************************************/				if (fcinfo->argnull[i])					Tcl_DStringAppendElement(&tcl_cmd, "");				else				{					HeapTupleHeader td;					Oid			tupType;					int32		tupTypmod;					TupleDesc	tupdesc;					HeapTupleData tmptup;					td = DatumGetHeapTupleHeader(fcinfo->arg[i]);					/* Extract rowtype info and find a tupdesc */					tupType = HeapTupleHeaderGetTypeId(td);					tupTypmod = HeapTupleHeaderGetTypMod(td);					tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);					tupdesc = CreateTupleDescCopy(tupdesc);					/* Build a temporary HeapTuple control structure */					tmptup.t_len = HeapTupleHeaderGetDatumLength(td);					tmptup.t_data = td;					Tcl_DStringSetLength(&list_tmp, 0);					pltcl_build_tuple_argument(&tmptup, tupdesc, &list_tmp);					Tcl_DStringAppendElement(&tcl_cmd,											 Tcl_DStringValue(&list_tmp));					FreeTupleDesc(tupdesc);				}			}			else			{				/**************************************************				 * Single values are added as string element				 * of their external representation				 **************************************************/				if (fcinfo->argnull[i])					Tcl_DStringAppendElement(&tcl_cmd, "");				else				{					char	   *tmp;					tmp = DatumGetCString(FunctionCall1(&prodesc->arg_out_func[i],														fcinfo->arg[i]));					UTF_BEGIN;					Tcl_DStringAppendElement(&tcl_cmd, UTF_E2U(tmp));					UTF_END;					pfree(tmp);				}			}		}	}	PG_CATCH();	{		Tcl_DStringFree(&tcl_cmd);		Tcl_DStringFree(&list_tmp);		PG_RE_THROW();	}	PG_END_TRY();	Tcl_DStringFree(&list_tmp);	/************************************************************	 * Call the Tcl function	 *	 * We assume no PG error can be thrown directly from this call.	 ************************************************************/	tcl_rc = Tcl_GlobalEval(interp, Tcl_DStringValue(&tcl_cmd));	Tcl_DStringFree(&tcl_cmd);	/************************************************************	 * Check for errors reported by Tcl.	 ************************************************************/	if (tcl_rc != TCL_OK)	{		UTF_BEGIN;		ereport(ERROR,				(errmsg("%s", interp->result),				 errcontext("%s",							UTF_U2E(Tcl_GetVar(interp, "errorInfo",											   TCL_GLOBAL_ONLY)))));		UTF_END;	}	/************************************************************	 * Disconnect from SPI manager and then create the return	 * value 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).  But don't try to call	 * the result_in_func if we've been told to return a NULL;	 * the contents of interp->result may not be a valid value of	 * the result type in that case.	 ************************************************************/	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "SPI_finish() failed");	if (fcinfo->isnull)		retval = (Datum) 0;	else	{		UTF_BEGIN;		retval = FunctionCall3(&prodesc->result_in_func,							   PointerGetDatum(UTF_U2E(interp->result)),							   ObjectIdGetDatum(prodesc->result_typioparam),							   Int32GetDatum(-1));		UTF_END;	}	return retval;}/********************************************************************** * pltcl_trigger_handler()	- Handler for trigger calls **********************************************************************/static HeapTuplepltcl_trigger_handler(PG_FUNCTION_ARGS){	pltcl_proc_desc *prodesc;	Tcl_Interp *volatile interp;	TriggerData *trigdata = (TriggerData *) fcinfo->context;	char	   *stroid;	TupleDesc	tupdesc;	volatile 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;	CONST84 char **ret_values;	/* Connect to SPI manager */	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "could not connect to SPI manager");	/* Find or compile the function */	prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid,									 RelationGetRelid(trigdata->tg_relation));	pltcl_current_prodesc = prodesc;	if (prodesc->lanpltrusted)		interp = pltcl_safe_interp;	else		interp = pltcl_norm_interp;	tupdesc = trigdata->tg_relation->rd_att;	/************************************************************	 * Create the tcl command to call the internal	 * proc in the interpreter	 ************************************************************/	Tcl_DStringInit(&tcl_cmd);	Tcl_DStringInit(&tcl_trigtup);	Tcl_DStringInit(&tcl_newtup);	PG_TRY();	{		/* The procedure name */		Tcl_DStringAppendElement(&tcl_cmd, prodesc->proname);		/* The trigger name for argument TG_name */		Tcl_DStringAppendElement(&tcl_cmd, trigdata->tg_trigger->tgname);		/* The oid of the trigger relation for argument TG_relid */		stroid = DatumGetCString(DirectFunctionCall1(oidout,							ObjectIdGetDatum(trigdata->tg_relation->rd_id)));		Tcl_DStringAppendElement(&tcl_cmd, stroid);		pfree(stroid);		/* A list of attribute names for argument TG_relatts */		Tcl_DStringAppendElement(&tcl_trigtup, "");		for (i = 0; i < tupdesc->natts; i++)		{			if (tupdesc->attrs[i]->attisdropped)				Tcl_DStringAppendElement(&tcl_trigtup, "");			else				Tcl_DStringAppendElement(&tcl_trigtup,										 NameStr(tupdesc->attrs[i]->attname));		}		Tcl_DStringAppendElement(&tcl_cmd, Tcl_DStringValue(&tcl_trigtup));		Tcl_DStringFree(&tcl_trigtup);		Tcl_DStringInit(&tcl_trigtup);		/* The when part of the event for TG_when */		if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))			Tcl_DStringAppendElement(&tcl_cmd, "BEFORE");		else if (TRIGGER_FIRED_AFTER(trigdata->tg_event))			Tcl_DStringAppendElement(&tcl_cmd, "AFTER");		else			elog(ERROR, "unrecognized WHEN tg_event: %u", trigdata->tg_event);		/* The level part of the event for TG_level */		if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))		{			Tcl_DStringAppendElement(&tcl_cmd, "ROW");			/* Build the data list for the trigtuple */			pltcl_build_tuple_argument(trigdata->tg_trigtuple,									   tupdesc, &tcl_trigtup);			/*			 * Now the command part of the event for TG_op and data for NEW			 * and OLD			 */			if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))			{				Tcl_DStringAppendElement(&tcl_cmd, "INSERT");				Tcl_DStringAppendElement(&tcl_cmd, Tcl_DStringValue(&tcl_trigtup));				Tcl_DStringAppendElement(&tcl_cmd, "");				rettup = trigdata->tg_trigtuple;			}			else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))			{				Tcl_DStringAppendElement(&tcl_cmd, "DELETE");				Tcl_DStringAppendElement(&tcl_cmd, "");				Tcl_DStringAppendElement(&tcl_cmd, Tcl_DStringValue(&tcl_trigtup));				rettup = trigdata->tg_trigtuple;			}			else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))			{				Tcl_DStringAppendElement(&tcl_cmd, "UPDATE");				pltcl_build_tuple_argument(trigdata->tg_newtuple,										   tupdesc, &tcl_newtup);				Tcl_DStringAppendElement(&tcl_cmd, Tcl_DStringValue(&tcl_newtup));				Tcl_DStringAppendElement(&tcl_cmd, Tcl_DStringValue(&tcl_trigtup));				rettup = trigdata->tg_newtuple;			}			else				elog(ERROR, "unrecognized OP tg_event: %u", trigdata->tg_event);		}		else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))		{			Tcl_DStringAppendElement(&tcl_cmd, "STATEMENT");			if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))				Tcl_DStringAppendElement(&tcl_cmd, "INSERT");			else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))				Tcl_DStringAppendElement(&tcl_cmd, "DELETE");			else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))				Tcl_DStringAppendElement(&tcl_cmd, "UPDATE");			else				elog(ERROR, "unrecognized OP tg_event: %u", trigdata->tg_event);			Tcl_DStringAppendElement(&tcl_cmd, "");			Tcl_DStringAppendElement(&tcl_cmd, "");			rettup = (HeapTuple) NULL;		}		else			elog(ERROR, "unrecognized LEVEL tg_event: %u", trigdata->tg_event);		/* Finally append the arguments from CREATE TRIGGER */		for (i = 0; i < trigdata->tg_trigger->tgnargs; i++)			Tcl_DStringAppendElement(&tcl_cmd, trigdata->tg_trigger->tgargs[i]);	}	PG_CATCH();	{		Tcl_DStringFree(&tcl_cmd);		Tcl_DStringFree(&tcl_trigtup);		Tcl_DStringFree(&tcl_newtup);		PG_RE_THROW();	}	PG_END_TRY();	Tcl_DStringFree(&tcl_trigtup);	Tcl_DStringFree(&tcl_newtup);	/************************************************************	 * Call the Tcl function	 *	 * We assume no PG error can be thrown directly from this call.	 ************************************************************/	tcl_rc = Tcl_GlobalEval(interp, Tcl_DStringValue(&tcl_cmd));	Tcl_DStringFree(&tcl_cmd);	/************************************************************	 * Check for errors reported by Tcl.	 ************************************************************/	if (tcl_rc != TCL_OK)	{		UTF_BEGIN;		ereport(ERROR,				(errmsg("%s", interp->result),				 errcontext("%s",							UTF_U2E(Tcl_GetVar(interp, "errorInfo",											   TCL_GLOBAL_ONLY)))));		UTF_END;	}	/************************************************************	 * 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);	/* Use a TRY to ensure ret_values will get freed */	PG_TRY();	{		if (ret_numvals % 2 != 0)			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);		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			typioparam;			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)

⌨️ 快捷键说明

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