📄 plpython.c
字号:
errmsg("plpython functions cannot return tuples yet"))); else PLy_output_datum_func(&proc->result, rvTypeTup); 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 procedure's * arguments. */ proc->nargs = fcinfo->nargs; for (i = 0; i < fcinfo->nargs; i++) { HeapTuple argTypeTup; Form_pg_type argTypeStruct; argTypeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(procStruct->proargtypes.values[i]), 0, 0, 0); if (!HeapTupleIsValid(argTypeTup)) elog(ERROR, "cache lookup failed for type %u", procStruct->proargtypes.values[i]); argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup); /* Disallow pseudotype argument */ if (argTypeStruct->typtype == 'p') ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plpython functions cannot take type %s", format_type_be(procStruct->proargtypes.values[i])))); if (argTypeStruct->typtype != 'c') PLy_input_datum_func(&(proc->args[i]), procStruct->proargtypes.values[i], argTypeTup); else proc->args[i].is_rowtype = 2; /* still need to set I/O funcs */ ReleaseSysCache(argTypeTup); } /* * get the text of the function. */ prosrcdatum = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_prosrc, &isnull); if (isnull) elog(ERROR, "null prosrc"); procSource = DatumGetCString(DirectFunctionCall1(textout, prosrcdatum)); PLy_procedure_compile(proc, procSource); pfree(procSource); proc->me = PyCObject_FromVoidPtr(proc, NULL); PyDict_SetItemString(PLy_procedure_cache, key, proc->me); } PG_CATCH(); { PLy_procedure_delete(proc); if (procSource) pfree(procSource); PG_RE_THROW(); } PG_END_TRY(); return proc;}static voidPLy_procedure_compile(PLyProcedure * proc, const char *src){ PyObject *crv = NULL; char *msrc; proc->globals = PyDict_Copy(PLy_interp_globals); /* * SD is private preserved data between calls GD is global data shared by * all functions */ proc->statics = PyDict_New(); PyDict_SetItemString(proc->globals, "SD", proc->statics); /* * insert the function code into the interpreter */ msrc = PLy_procedure_munge_source(proc->pyname, src); crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL); free(msrc); if ((crv != NULL) && (!PyErr_Occurred())) { int clen; char call[NAMEDATALEN + 256]; Py_DECREF(crv); /* * compile a call to the function */ clen = snprintf(call, sizeof(call), "%s()", proc->pyname); if ((clen < 0) || (clen >= sizeof(call))) elog(ERROR, "string would overflow buffer"); proc->code = Py_CompileString(call, "<string>", Py_eval_input); if ((proc->code != NULL) && (!PyErr_Occurred())) return; } else Py_XDECREF(crv); PLy_elog(ERROR, "could not compile function \"%s\"", proc->proname);}static char *PLy_procedure_munge_source(const char *name, const char *src){ char *mrc, *mp; const char *sp; size_t mlen, plen; /* * room for function source and the def statement */ mlen = (strlen(src) * 2) + strlen(name) + 16; mrc = PLy_malloc(mlen); plen = snprintf(mrc, mlen, "def %s():\n\t", name); Assert(plen >= 0 && plen < mlen); sp = src; mp = mrc + plen; while (*sp != '\0') { if (*sp == '\r' && *(sp + 1) == '\n') sp++; if (*sp == '\n' || *sp == '\r') { *mp++ = '\n'; *mp++ = '\t'; sp++; } else *mp++ = *sp++; } *mp++ = '\n'; *mp++ = '\n'; *mp = '\0'; if (mp > (mrc + mlen)) elog(FATAL, "buffer overrun in PLy_munge_source"); return mrc;}static voidPLy_procedure_delete(PLyProcedure * proc){ int i; Py_XDECREF(proc->code); Py_XDECREF(proc->statics); Py_XDECREF(proc->globals); Py_XDECREF(proc->me); if (proc->proname) PLy_free(proc->proname); if (proc->pyname) PLy_free(proc->pyname); for (i = 0; i < proc->nargs; i++) if (proc->args[i].is_rowtype == 1) { if (proc->args[i].in.r.atts) PLy_free(proc->args[i].in.r.atts); if (proc->args[i].out.r.atts) PLy_free(proc->args[i].out.r.atts); }}/* conversion functions. remember output from python is * input to postgresql, and vis versa. */static voidPLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc){ int i; if (arg->is_rowtype == 0) elog(ERROR, "PLyTypeInfo struct is initialized for a Datum"); arg->is_rowtype = 1; arg->in.r.natts = desc->natts; arg->in.r.atts = malloc(desc->natts * sizeof(PLyDatumToOb)); for (i = 0; i < desc->natts; i++) { HeapTuple typeTup; if (desc->attrs[i]->attisdropped) continue; typeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(desc->attrs[i]->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", desc->attrs[i]->atttypid); PLy_input_datum_func2(&(arg->in.r.atts[i]), desc->attrs[i]->atttypid, typeTup); ReleaseSysCache(typeTup); }}static voidPLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc){ int i; if (arg->is_rowtype == 0) elog(ERROR, "PLyTypeInfo struct is initialized for a Datum"); arg->is_rowtype = 1; arg->out.r.natts = desc->natts; arg->out.r.atts = malloc(desc->natts * sizeof(PLyDatumToOb)); for (i = 0; i < desc->natts; i++) { HeapTuple typeTup; if (desc->attrs[i]->attisdropped) continue; typeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(desc->attrs[i]->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", desc->attrs[i]->atttypid); PLy_output_datum_func2(&(arg->out.r.atts[i]), typeTup); ReleaseSysCache(typeTup); }}static voidPLy_output_datum_func(PLyTypeInfo * arg, HeapTuple typeTup){ if (arg->is_rowtype > 0) elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple"); arg->is_rowtype = 0; PLy_output_datum_func2(&(arg->out.d), typeTup);}static voidPLy_output_datum_func2(PLyObToDatum * arg, HeapTuple typeTup){ Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); perm_fmgr_info(typeStruct->typinput, &arg->typfunc); arg->typioparam = getTypeIOParam(typeTup); arg->typbyval = typeStruct->typbyval;}static voidPLy_input_datum_func(PLyTypeInfo * arg, Oid typeOid, HeapTuple typeTup){ if (arg->is_rowtype > 0) elog(ERROR, "PLyTypeInfo struct is initialized for Tuple"); arg->is_rowtype = 0; PLy_input_datum_func2(&(arg->in.d), typeOid, typeTup);}static voidPLy_input_datum_func2(PLyDatumToOb * arg, Oid typeOid, HeapTuple typeTup){ Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Get the type's conversion information */ perm_fmgr_info(typeStruct->typoutput, &arg->typfunc); arg->typioparam = getTypeIOParam(typeTup); arg->typbyval = typeStruct->typbyval; /* Determine which kind of Python object we will convert to */ switch (typeOid) { case BOOLOID: arg->func = PLyBool_FromString; break; case FLOAT4OID: case FLOAT8OID: case NUMERICOID: arg->func = PLyFloat_FromString; break; case INT2OID: case INT4OID: arg->func = PLyInt_FromString; break; case INT8OID: arg->func = PLyLong_FromString; break; default: arg->func = PLyString_FromString; break; }}static voidPLy_typeinfo_init(PLyTypeInfo * arg){ arg->is_rowtype = -1; arg->in.r.natts = arg->out.r.natts = 0; arg->in.r.atts = NULL; arg->out.r.atts = NULL;}static voidPLy_typeinfo_dealloc(PLyTypeInfo * arg){ if (arg->is_rowtype == 1) { if (arg->in.r.atts) PLy_free(arg->in.r.atts); if (arg->out.r.atts) PLy_free(arg->out.r.atts); }}/* assumes that a bool is always returned as a 't' or 'f' */static PyObject *PLyBool_FromString(const char *src){ if (src[0] == 't') return PyInt_FromLong(1); return PyInt_FromLong(0);}static PyObject *PLyFloat_FromString(const char *src){ double v; char *eptr; errno = 0; v = strtod(src, &eptr); if ((*eptr != '\0') || (errno)) return NULL; return PyFloat_FromDouble(v);}static PyObject *PLyInt_FromString(const char *src){ long v; char *eptr; errno = 0; v = strtol(src, &eptr, 0); if ((*eptr != '\0') || (errno)) return NULL; return PyInt_FromLong(v);}static PyObject *PLyLong_FromString(const char *src){ return PyLong_FromString((char *) src, NULL, 0);}static PyObject *PLyString_FromString(const char *src){ return PyString_FromString(src);}static PyObject *PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc){ PyObject *volatile dict; int i; if (info->is_rowtype != 1) elog(ERROR, "PLyTypeInfo structure describes a datum"); dict = PyDict_New(); if (dict == NULL) PLy_elog(ERROR, "could not create tuple dictionary"); PG_TRY(); { for (i = 0; i < info->in.r.natts; i++) { char *key, *vsrc; Datum vattr, vdat; bool is_null; PyObject *value; if (desc->attrs[i]->attisdropped) continue; key = NameStr(desc->attrs[i]->attname); vattr = heap_getattr(tuple, (i + 1), desc, &is_null); if ((is_null) || (info->in.r.atts[i].func == NULL)) PyDict_SetItemString(dict, key, Py_None); else { vdat = FunctionCall3(&info->in.r.atts[i].typfunc, vattr, ObjectIdGetDatum(info->in.r.atts[i].typioparam), Int32GetDatum(desc->attrs[i]->atttypmod)); vsrc = DatumGetCString(vdat); /* * no exceptions allowed */ value = info->in.r.atts[i].func(vsrc); pfree(vsrc); PyDict_SetItemString(dict, key, value); Py_DECREF(value); } } } PG_CATCH(); { Py_DECREF(dict); PG_RE_THROW(); } PG_END_TRY(); return dict;}/* initialization, some python variables function declared here *//* interface to postgresql elog */static PyObject *PLy_debug(PyObject *, PyObject *);static PyObject *PLy_log(PyObject *, PyObject *);static PyObject *PLy_info(PyObject *, PyObject *);static PyObject *PLy_notice(PyObject *, PyObject *);static PyObject *PLy_warning(PyObject *, PyObject *);static PyObject *PLy_error(PyObject *, PyObject *);static PyObject *PLy_fatal(PyObject *, PyObject *);/* PLyPlanObject, PLyResultObject and SPI interface */#define is_PLyPlanObject(x) ((x)->ob_type == &PLy_PlanType)static PyObject *PLy_plan_new(void);static void PLy_plan_dealloc(PyObject *);static PyObject *PLy_plan_getattr(PyObject *, char *);static PyObject *PLy_plan_status(PyObject *, PyObject *);static PyObject *PLy_result_new(void);static void PLy_result_dealloc(PyObject *);static PyObject *PLy_result_getattr(PyObject *, char *);static PyObject *PLy_result_nrows(PyObject *, PyObject *);static PyObject *PLy_result_status(PyObject *, PyObject *);static int PLy_result_length(PyObject *);static PyObject *PLy_result_item(PyObject *, int);static PyObject *PLy_result_slice(PyObject *, int, int);static int PLy_result_ass_item(PyObject *, int, PyObject *);static int PLy_result_ass_slice(PyObject *, int, int, PyObject *);static PyObject *PLy_spi_prepare(PyObject *, PyObject *);static PyObject *PLy_spi_execute(PyObject *, PyObject *);static PyObject *PLy_spi_execute_query(char *query, long limit);static PyObject *PLy_spi_execute_plan(PyObject *, PyObject *, long);static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *, int, int);static PyTypeObject PLy_PlanType = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "PLyPlan", /* tp_name */ sizeof(PLyPlanObject), /* tp_size */ 0, /* tp_itemsize */ /* * methods */ (destructor) PLy_plan_dealloc, /* tp_dealloc */ 0, /* tp_print */ (getattrfunc) PLy_plan_getattr, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ 0, /* tp_xxx4 */ PLy_plan_doc, /* tp_doc */};static PyMethodDef PLy_plan_methods[] = { {"status", PLy_plan_status, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL}};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -