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

📄 plpython.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (plval != Py_None && !tupdesc->attrs[atti]->attisdropped)		{			plstr = PyObject_Str(plval);			src = PyString_AsString(plstr);			modvalues[i] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc,										 CStringGetDatum(src),				 ObjectIdGetDatum(proc->result.out.r.atts[atti].typelem),						 Int32GetDatum(tupdesc->attrs[atti]->atttypmod));			modnulls[i] = ' ';			Py_DECREF(plstr);			plstr = NULL;		}		else		{			modvalues[i] = (Datum) 0;			modnulls[i] = 'n';		}		Py_DECREF(plval);		plval = NULL;	}	rtup = SPI_modifytuple(tdata->tg_relation, otup, natts,						   modattrs, modvalues, modnulls);	/*	 * FIXME -- these leak if not explicitly pfree'd by other elog calls,	 * no?  (No, I think, but might as well leave the pfrees here...)	 */	pfree(modattrs);	pfree(modvalues);	pfree(modnulls);	if (rtup == NULL)		elog(ERROR, "SPI_modifytuple failed -- error %d", SPI_result);	Py_DECREF(plntup);	Py_DECREF(plkeys);	RESTORE_EXC();	return rtup;}PyObject *PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc, HeapTuple *rv){	DECLARE_EXC();	TriggerData *tdata;	PyObject   *pltname,			   *pltevent,			   *pltwhen,			   *pltlevel,			   *pltrelid;	PyObject   *pltargs,			   *pytnew,			   *pytold;	PyObject   *volatile pltdata = NULL;	char	   *stroid;	enter();	SAVE_EXC();	if (TRAP_EXC())	{		RESTORE_EXC();		Py_XDECREF(pltdata);		RERAISE_EXC();	}	tdata = (TriggerData *) fcinfo->context;	pltdata = PyDict_New();	if (!pltdata)		PLy_elog(ERROR, "could not build arguments for trigger procedure");	pltname = PyString_FromString(tdata->tg_trigger->tgname);	PyDict_SetItemString(pltdata, "name", pltname);	Py_DECREF(pltname);	stroid = DatumGetCString(DirectFunctionCall1(oidout,						   ObjectIdGetDatum(tdata->tg_relation->rd_id)));	pltrelid = PyString_FromString(stroid);	PyDict_SetItemString(pltdata, "relid", pltrelid);	Py_DECREF(pltrelid);	pfree(stroid);	if (TRIGGER_FIRED_BEFORE(tdata->tg_event))		pltwhen = PyString_FromString("BEFORE");	else if (TRIGGER_FIRED_AFTER(tdata->tg_event))		pltwhen = PyString_FromString("AFTER");	else	{		elog(ERROR, "unrecognized WHEN tg_event: %u", tdata->tg_event);		pltwhen = NULL;			/* keep compiler quiet */	}	PyDict_SetItemString(pltdata, "when", pltwhen);	Py_DECREF(pltwhen);	if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))	{		pltlevel = PyString_FromString("ROW");		PyDict_SetItemString(pltdata, "level", pltlevel);		Py_DECREF(pltlevel);		if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))		{			pltevent = PyString_FromString("INSERT");			PyDict_SetItemString(pltdata, "old", Py_None);			pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,									   tdata->tg_relation->rd_att);			PyDict_SetItemString(pltdata, "new", pytnew);			Py_DECREF(pytnew);			*rv = tdata->tg_trigtuple;		}		else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))		{			pltevent = PyString_FromString("DELETE");			PyDict_SetItemString(pltdata, "new", Py_None);			pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,									   tdata->tg_relation->rd_att);			PyDict_SetItemString(pltdata, "old", pytold);			Py_DECREF(pytold);			*rv = tdata->tg_trigtuple;		}		else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))		{			pltevent = PyString_FromString("UPDATE");			pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newtuple,									   tdata->tg_relation->rd_att);			PyDict_SetItemString(pltdata, "new", pytnew);			Py_DECREF(pytnew);			pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,									   tdata->tg_relation->rd_att);			PyDict_SetItemString(pltdata, "old", pytold);			Py_DECREF(pytold);			*rv = tdata->tg_newtuple;		}		else		{			elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);			pltevent = NULL;	/* keep compiler quiet */		}		PyDict_SetItemString(pltdata, "event", pltevent);		Py_DECREF(pltevent);	}	else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))	{		pltlevel = PyString_FromString("STATEMENT");		PyDict_SetItemString(pltdata, "level", pltlevel);		Py_DECREF(pltlevel);		PyDict_SetItemString(pltdata, "old", Py_None);		PyDict_SetItemString(pltdata, "new", Py_None);		*rv = (HeapTuple) NULL;		if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))			pltevent = PyString_FromString("INSERT");		else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))			pltevent = PyString_FromString("DELETE");		else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))			pltevent = PyString_FromString("UPDATE");		else		{			elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);			pltevent = NULL;	/* keep compiler quiet */		}		PyDict_SetItemString(pltdata, "event", pltevent);		Py_DECREF(pltevent);	}	else		elog(ERROR, "unrecognized LEVEL tg_event: %u", tdata->tg_event);	if (tdata->tg_trigger->tgnargs)	{		/*		 * all strings...		 */		int			i;		PyObject   *pltarg;		pltargs = PyList_New(tdata->tg_trigger->tgnargs);		for (i = 0; i < tdata->tg_trigger->tgnargs; i++)		{			pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);			/*			 * stolen, don't Py_DECREF			 */			PyList_SetItem(pltargs, i, pltarg);		}	}	else	{		Py_INCREF(Py_None);		pltargs = Py_None;	}	PyDict_SetItemString(pltdata, "args", pltargs);	Py_DECREF(pltargs);	RESTORE_EXC();	return pltdata;}/* function handler and friends */DatumPLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc){	DECLARE_EXC();	Datum		rv;	PyObject   *volatile plargs = NULL;	PyObject   *volatile plrv = NULL;	PyObject   *volatile plrv_so = NULL;	char	   *plrv_sc;	enter();	/*	 * setup to catch elog in while building function arguments, and	 * DECREF the plargs if the function call fails	 */	SAVE_EXC();	if (TRAP_EXC())	{		RESTORE_EXC();		Py_XDECREF(plargs);		Py_XDECREF(plrv);		Py_XDECREF(plrv_so);		RERAISE_EXC();	}	plargs = PLy_function_build_args(fcinfo, proc);	plrv = PLy_procedure_call(proc, "args", plargs);	/*	 * 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, "SPI_finish failed");	if (plrv == NULL)	{		elog(FATAL, "PLy_procedure_call returned NULL");#ifdef NOT_USED		if (!PLy_restart_in_progress)			PLy_elog(ERROR, "function \"%s\" failed", proc->proname);		/*		 * FIXME is this dead code?  i'm pretty sure it is for unnested		 * calls, but not for nested calls		 */		RAISE_EXC(1);#endif	}	/*	 * convert the python PyObject to a postgresql Datum FIXME returning a	 * NULL, ie PG_RETURN_NULL() blows the backend to small messy bits...	 * it this a bug or expected?  so just call with the string value of	 * None for now	 */	if (plrv == Py_None)	{		fcinfo->isnull = true;		rv = (Datum) NULL;	}	else	{		fcinfo->isnull = false;		plrv_so = PyObject_Str(plrv);		plrv_sc = PyString_AsString(plrv_so);		rv = FunctionCall3(&proc->result.out.d.typfunc,						   PointerGetDatum(plrv_sc),						   ObjectIdGetDatum(proc->result.out.d.typelem),						   Int32GetDatum(-1));	}	RESTORE_EXC();	Py_XDECREF(plargs);	Py_DECREF(plrv);	Py_XDECREF(plrv_so);	return rv;}PyObject *PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs){	PyObject   *rv;	PLyProcedure *current;	enter();	current = PLy_last_procedure;	PLy_last_procedure = proc;	PyDict_SetItemString(proc->globals, kargs, vargs);	rv = PyEval_EvalCode((PyCodeObject *) proc->code, proc->globals, proc->globals);	PLy_last_procedure = current;	if ((rv == NULL) || (PyErr_Occurred()))	{		Py_XDECREF(rv);		if (!PLy_restart_in_progress)			PLy_elog(ERROR, "function \"%s\" failed", proc->proname);		RAISE_EXC(1);	}	return rv;}PyObject *PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc){	DECLARE_EXC();	PyObject   *volatile arg = NULL;	PyObject   *volatile args = NULL;	int			i;	enter();	/*	 * FIXME -- if the setjmp setup is expensive, add the arg and args	 * field to the procedure struct and cleanup at the start of the next	 * call	 */	SAVE_EXC();	if (TRAP_EXC())	{		RESTORE_EXC();		Py_XDECREF(arg);		Py_XDECREF(args);		RERAISE_EXC();	}	args = PyList_New(proc->nargs);	for (i = 0; i < proc->nargs; i++)	{		if (proc->args[i].is_rel == 1)		{			TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];			arg = PLyDict_FromTuple(&(proc->args[i]), slot->val,									slot->ttc_tupleDescriptor);		}		else		{			if (!fcinfo->argnull[i])			{				char	   *ct;				Datum		dt;				dt = FunctionCall3(&(proc->args[i].in.d.typfunc),								   fcinfo->arg[i],							ObjectIdGetDatum(proc->args[i].in.d.typelem),								   Int32GetDatum(-1));				ct = DatumGetCString(dt);				arg = (proc->args[i].in.d.func) (ct);				pfree(ct);			}			else				arg = NULL;		}		if (arg == NULL)		{			Py_INCREF(Py_None);			arg = Py_None;		}		/*		 * FIXME -- error check this		 */		PyList_SetItem(args, i, arg);	}	RESTORE_EXC();	return args;}/* * PLyProcedure functions *//* PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and * returns a new PLyProcedure.  fcinfo is the call info, tgreloid is the * relation OID when calling a trigger, or InvalidOid (zero) for ordinary * function calls. */static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo, Oid tgreloid){	Oid			fn_oid;	HeapTuple	procTup;	char		key[128];	PyObject   *plproc;	PLyProcedure *proc = NULL;	int			rv;	enter();	fn_oid = fcinfo->flinfo->fn_oid;	procTup = SearchSysCache(PROCOID,							 ObjectIdGetDatum(fn_oid),							 0, 0, 0);	if (!HeapTupleIsValid(procTup))		elog(ERROR, "cache lookup failed for function %u", fn_oid);	rv = snprintf(key, sizeof(key), "%u_%u", fn_oid, tgreloid);	if ((rv >= sizeof(key)) || (rv < 0))		elog(ERROR, "key too long");	plproc = PyDict_GetItemString(PLy_procedure_cache, key);	if (plproc != NULL)	{		Py_INCREF(plproc);		if (!PyCObject_Check(plproc))			elog(FATAL, "expected a PyCObject, didn't get one");		mark();		proc = PyCObject_AsVoidPtr(plproc);		if (proc->me != plproc)			elog(FATAL, "proc->me != plproc");		/* did we find an up-to-date cache entry? */		if (proc->fn_xmin != HeapTupleHeaderGetXmin(procTup->t_data) ||			proc->fn_cmin != HeapTupleHeaderGetCmin(procTup->t_data))		{			Py_DECREF(plproc);			proc = NULL;		}	}	if (proc == NULL)		proc = PLy_procedure_create(fcinfo, tgreloid, procTup, key);	ReleaseSysCache(procTup);	return proc;}static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,					 HeapTuple procTup, char *key){	char		procName[NAMEDATALEN + 256];	DECLARE_EXC();	Form_pg_proc procStruct;	PLyProcedure *volatile proc;	char	   *volatile procSource = NULL;	Datum		procDatum;	int			i,				rv;	enter();	procStruct = (Form_pg_proc) GETSTRUCT(procTup);	if (OidIsValid(tgreloid))		rv = snprintf(procName, sizeof(procName),					  "__plpython_procedure_%s_%u_trigger_%u",					  NameStr(procStruct->proname),					  fcinfo->flinfo->fn_oid,					  tgreloid);	else		rv = snprintf(procName, sizeof(procName),					  "__plpython_procedure_%s_%u",					  NameStr(procStruct->proname),					  fcinfo->flinfo->fn_oid);	if ((rv >= sizeof(procName)) || (rv < 0))		elog(ERROR, "procedure name would overrun buffer");	proc = PLy_malloc(sizeof(PLyProcedure));	proc->proname = PLy_malloc(strlen(NameStr(procStruct->proname)) + 1);	strcpy(proc->proname, NameStr(procStruct->proname));	proc->pyname = PLy_malloc(strlen(procName) + 1);	strcpy(proc->pyname, procName);	proc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);	proc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);	PLy_typeinfo_init(&proc->result);	for (i = 0; i < FUNC_MAX_ARGS; i++)		PLy_typeinfo_init(&proc->args[i]);	proc->nargs = 0;	proc->code = proc->statics = NULL;	proc->globals = proc->me = NULL;	SAVE_EXC();	if (TRAP_EXC())	{		RESTORE_EXC();		PLy_procedure_delete(proc);		if (procSource)			pfree(procSource);		RERAISE_EXC();	}	/*	 * get information required for output conversion of the return value,	 * but only if this isn't a trigger.	 */	if (!CALLED_AS_TRIGGER(fcinfo))	{		HeapTuple	rvTypeTup;		Form_pg_type rvTypeStruct;		rvTypeTup = SearchSysCache(TYPEOID,								ObjectIdGetDatum(procStruct->prorettype),								   0, 0, 0);		if (!HeapTupleIsValid(rvTypeTup))			elog(ERROR, "cache lookup failed for type %u",				 procStruct->prorettype);		rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);		if (rvTypeStruct->typrelid == InvalidOid)			PLy_output_datum_func(&proc->result, rvTypeStruct);		else			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("tuple return types are not supported yet")));		ReleaseSysCache(rvTypeTup);	}	else	{		/*		 * input/output conversion for trigger tuples.	use the result		 * TypeInfo variable to store the tuple conversion info.		 */		TriggerData *tdata = (TriggerData *) fcinfo->context;		PLy_input_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);		PLy_output_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);	}	/*	 * now get information required for input conversion of the procedures

⌨️ 快捷键说明

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