📄 plpython.c
字号:
} else { modvalues[i] = (Datum) 0; modnulls[i] = 'n'; } Py_DECREF(plval); plval = NULL; } rtup = SPI_modifytuple(tdata->tg_relation, otup, natts, modattrs, modvalues, modnulls); if (rtup == NULL) elog(ERROR, "SPI_modifytuple failed -- error %d", SPI_result); } PG_CATCH(); { Py_XDECREF(plntup); Py_XDECREF(plkeys); Py_XDECREF(plval); Py_XDECREF(plstr); if (modnulls) pfree(modnulls); if (modvalues) pfree(modvalues); if (modattrs) pfree(modattrs); PG_RE_THROW(); } PG_END_TRY(); Py_DECREF(plntup); Py_DECREF(plkeys); pfree(modattrs); pfree(modvalues); pfree(modnulls); return rtup;}static PyObject *PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc, HeapTuple *rv){ TriggerData *tdata = (TriggerData *) fcinfo->context; PyObject *pltname, *pltevent, *pltwhen, *pltlevel, *pltrelid; PyObject *pltargs, *pytnew, *pytold; PyObject *volatile pltdata = NULL; char *stroid; PG_TRY(); { 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 = 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); } PG_CATCH(); { Py_XDECREF(pltdata); PG_RE_THROW(); } PG_END_TRY(); return pltdata;}/* function handler and friends */static DatumPLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc){ Datum rv; PyObject *volatile plargs = NULL; PyObject *volatile plrv = NULL; PyObject *volatile plrv_so = NULL; char *plrv_sc; PG_TRY(); { plargs = PLy_function_build_args(fcinfo, proc); plrv = PLy_procedure_call(proc, "args", plargs); Assert(plrv != NULL); Assert(!PLy_error_in_progress); /* * 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"); /* * convert the python PyObject to a postgresql Datum */ if (plrv == Py_None) { fcinfo->isnull = true; rv = (Datum) NULL; } else { fcinfo->isnull = false; plrv_so = PyObject_Str(plrv); if (!plrv_so) PLy_elog(ERROR, "function \"%s\" could not create return value", proc->proname); plrv_sc = PyString_AsString(plrv_so); rv = FunctionCall3(&proc->result.out.d.typfunc, PointerGetDatum(plrv_sc), ObjectIdGetDatum(proc->result.out.d.typioparam), Int32GetDatum(-1)); } } PG_CATCH(); { Py_XDECREF(plargs); Py_XDECREF(plrv); Py_XDECREF(plrv_so); PG_RE_THROW(); } PG_END_TRY(); Py_XDECREF(plargs); Py_DECREF(plrv); Py_XDECREF(plrv_so); return rv;}static PyObject *PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs){ PyObject *rv; PyDict_SetItemString(proc->globals, kargs, vargs); rv = PyEval_EvalCode((PyCodeObject *) proc->code, proc->globals, proc->globals); /* * If there was an error in a PG callback, propagate that no matter what * Python claims about its success. */ if (PLy_error_in_progress) { ErrorData *edata = PLy_error_in_progress; PLy_error_in_progress = NULL; ReThrowError(edata); } if ((rv == NULL) || (PyErr_Occurred())) { Py_XDECREF(rv); PLy_elog(ERROR, "function \"%s\" failed", proc->proname); } return rv;}static PyObject *PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc){ PyObject *volatile arg = NULL; PyObject *volatile args = NULL; int i; PG_TRY(); { args = PyList_New(proc->nargs); for (i = 0; i < proc->nargs; i++) { if (proc->args[i].is_rowtype > 0) { if (fcinfo->argnull[i]) arg = NULL; 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); /* Set up I/O funcs if not done yet */ if (proc->args[i].is_rowtype != 1) PLy_input_tuple_funcs(&(proc->args[i]), tupdesc); /* Build a temporary HeapTuple control structure */ tmptup.t_len = HeapTupleHeaderGetDatumLength(td); tmptup.t_data = td; arg = PLyDict_FromTuple(&(proc->args[i]), &tmptup, tupdesc); FreeTupleDesc(tupdesc); } } else { if (fcinfo->argnull[i]) arg = NULL; else { char *ct; Datum dt; dt = FunctionCall3(&(proc->args[i].in.d.typfunc), fcinfo->arg[i], ObjectIdGetDatum(proc->args[i].in.d.typioparam), Int32GetDatum(-1)); ct = DatumGetCString(dt); arg = (proc->args[i].in.d.func) (ct); pfree(ct); } } if (arg == NULL) { Py_INCREF(Py_None); arg = Py_None; } /* * FIXME -- error check this */ PyList_SetItem(args, i, arg); arg = NULL; } } PG_CATCH(); { Py_XDECREF(arg); Py_XDECREF(args); PG_RE_THROW(); } PG_END_TRY(); 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; 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"); 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]; Form_pg_proc procStruct; PLyProcedure *volatile proc; char *volatile procSource = NULL; Datum prosrcdatum; bool isnull; int i, rv; 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); /* Remember if function is STABLE/IMMUTABLE */ proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE); 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; PG_TRY(); { /* * 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); /* Disallow pseudotype result */ if (rvTypeStruct->typtype == 'p') { if (procStruct->prorettype == TRIGGEROID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("trigger functions may only be called as triggers"))); else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plpython functions cannot return type %s", format_type_be(procStruct->prorettype)))); } if (rvTypeStruct->typtype == 'c') ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -