#include "postgres.h"
#include "access/htup_details.h"
#include "access/transam.h"
#include "funcapi.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/syscache.h"
#include "plpython.h"
#include "plpy_procedure.h"
#include "plpy_elog.h"
#include "plpy_main.h"
Go to the source code of this file.
Functions | |
static PLyProcedure * | PLy_procedure_create (HeapTuple procTup, Oid fn_oid, bool is_trigger) |
static bool | PLy_procedure_argument_valid (PLyTypeInfo *arg) |
static bool | PLy_procedure_valid (PLyProcedure *proc, HeapTuple procTup) |
static char * | PLy_procedure_munge_source (const char *name, const char *src) |
void | init_procedure_caches (void) |
char * | PLy_procedure_name (PLyProcedure *proc) |
PLyProcedure * | PLy_procedure_get (Oid fn_oid, Oid fn_rel, bool is_trigger) |
void | PLy_procedure_compile (PLyProcedure *proc, const char *src) |
void | PLy_procedure_delete (PLyProcedure *proc) |
Variables | |
static HTAB * | PLy_procedure_cache = NULL |
void init_procedure_caches | ( | void | ) |
Definition at line 35 of file plpy_procedure.c.
References HASHCTL::entrysize, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, and HASHCTL::keysize.
Referenced by _PG_init().
{ HASHCTL hash_ctl; memset(&hash_ctl, 0, sizeof(hash_ctl)); hash_ctl.keysize = sizeof(PLyProcedureKey); hash_ctl.entrysize = sizeof(PLyProcedureEntry); hash_ctl.hash = tag_hash; PLy_procedure_cache = hash_create("PL/Python procedures", 32, &hash_ctl, HASH_ELEM | HASH_FUNCTION); }
static bool PLy_procedure_argument_valid | ( | PLyTypeInfo * | arg | ) | [static] |
Definition at line 423 of file plpy_procedure.c.
References Assert, elog, ERROR, HeapTupleHeaderGetXmin, HeapTupleIsValid, PLyTypeInfo::is_rowtype, ItemPointerEquals(), ItemPointerIsValid, ObjectIdGetDatum, OidIsValid, ReleaseSysCache(), RELOID, SearchSysCache1, HeapTupleData::t_data, HeapTupleData::t_self, TransactionIdIsValid, PLyTypeInfo::typ_relid, PLyTypeInfo::typrel_tid, and PLyTypeInfo::typrel_xmin.
Referenced by PLy_procedure_valid().
{ HeapTuple relTup; bool valid; /* Nothing to cache unless type is composite */ if (arg->is_rowtype != 1) return true; /* * Zero typ_relid means that we got called on an output argument of a * function returning a unnamed record type; the info for it can't change. */ if (!OidIsValid(arg->typ_relid)) return true; /* Else we should have some cached data */ Assert(TransactionIdIsValid(arg->typrel_xmin)); Assert(ItemPointerIsValid(&arg->typrel_tid)); /* Get the pg_class tuple for the data type */ relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid)); if (!HeapTupleIsValid(relTup)) elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid); /* If it has changed, the cached data is not valid */ valid = (arg->typrel_xmin == HeapTupleHeaderGetXmin(relTup->t_data) && ItemPointerEquals(&arg->typrel_tid, &relTup->t_self)); ReleaseSysCache(relTup); return valid; }
void PLy_procedure_compile | ( | PLyProcedure * | proc, | |
const char * | src | |||
) |
Definition at line 341 of file plpy_procedure.c.
References PLyProcedure::code, elog, ERROR, PLyProcedure::globals, NAMEDATALEN, NULL, pfree(), PLy_elog(), PLy_interp_globals, PLy_procedure_munge_source(), PLy_strdup(), PLyProcedure::proname, PLyProcedure::pyname, snprintf(), PLyProcedure::src, and PLyProcedure::statics.
Referenced by plpython_inline_handler(), and PLy_procedure_create().
{ 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); /* Save the mangled source for later inclusion in tracebacks */ proc->src = PLy_strdup(msrc); crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL); pfree(msrc); if (crv != NULL) { 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) return; } if (proc->proname) PLy_elog(ERROR, "could not compile PL/Python function \"%s\"", proc->proname); else PLy_elog(ERROR, "could not compile anonymous PL/Python code block"); }
static PLyProcedure * PLy_procedure_create | ( | HeapTuple | procTup, | |
Oid | fn_oid, | |||
bool | is_trigger | |||
) | [static] |
Definition at line 138 of file plpy_procedure.c.
References Anum_pg_proc_prosrc, PLyProcedure::argnames, PLyProcedure::args, Assert, PLyProcedure::code, PLyTypeOutput::d, elog, ereport, errcode(), errmsg(), ERROR, PLyProcedure::fn_readonly, PLyProcedure::fn_tid, PLyProcedure::fn_xmin, format_type_be(), get_func_arg_info(), GETSTRUCT, PLyProcedure::globals, HeapTupleHeaderGetXmin, HeapTupleIsValid, i, PLyTypeInfo::is_rowtype, PLyProcedure::is_setof, NAMEDATALEN, NameStr, PLyProcedure::nargs, NULL, ObjectIdGetDatum, PLyTypeInfo::out, pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_input_datum_func(), PLy_malloc(), PLy_malloc0(), PLy_output_datum_func(), PLy_procedure_compile(), PLy_procedure_delete(), PLy_strdup(), PLy_typeinfo_init(), PROARGMODE_OUT, PROARGMODE_TABLE, PROCOID, PLyProcedure::proname, PLyProcedure::pyname, RECORDOID, ReleaseSysCache(), PLyProcedure::result, SearchSysCache1, PLyProcedure::setof, snprintf(), PLyProcedure::src, PLyProcedure::statics, SysCacheGetAttr(), HeapTupleData::t_data, HeapTupleData::t_self, TextDatumGetCString, TRIGGEROID, TYPEOID, types, PLyObToDatum::typmod, PLyObToDatum::typoid, TYPTYPE_COMPOSITE, TYPTYPE_PSEUDO, and VOIDOID.
Referenced by PLy_procedure_get().
{ 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); rv = snprintf(procName, sizeof(procName), "__plpython_procedure_%s_%u", NameStr(procStruct->proname), fn_oid); if (rv >= sizeof(procName) || rv < 0) elog(ERROR, "procedure name would overrun buffer"); proc = PLy_malloc(sizeof(PLyProcedure)); proc->proname = PLy_strdup(NameStr(procStruct->proname)); proc->pyname = PLy_strdup(procName); proc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data); proc->fn_tid = procTup->t_self; /* 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 = NULL; proc->is_setof = procStruct->proretset; proc->setof = NULL; proc->src = NULL; proc->argnames = NULL; PG_TRY(); { /* * get information required for output conversion of the return value, * but only if this isn't a trigger. */ if (!is_trigger) { HeapTuple rvTypeTup; Form_pg_type rvTypeStruct; rvTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(procStruct->prorettype)); if (!HeapTupleIsValid(rvTypeTup)) elog(ERROR, "cache lookup failed for type %u", procStruct->prorettype); rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup); /* Disallow pseudotype result, except for void or record */ if (rvTypeStruct->typtype == TYPTYPE_PSEUDO) { if (procStruct->prorettype == TRIGGEROID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("trigger functions can only be called as triggers"))); else if (procStruct->prorettype != VOIDOID && procStruct->prorettype != RECORDOID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Python functions cannot return type %s", format_type_be(procStruct->prorettype)))); } if (rvTypeStruct->typtype == TYPTYPE_COMPOSITE || procStruct->prorettype == RECORDOID) { /* * Tuple: set up later, during first call to * PLy_function_handler */ proc->result.out.d.typoid = procStruct->prorettype; proc->result.out.d.typmod = -1; proc->result.is_rowtype = 2; } else { /* do the real work */ PLy_output_datum_func(&proc->result, rvTypeTup); } ReleaseSysCache(rvTypeTup); } /* * Now get information required for input conversion of the * procedure's arguments. Note that we ignore output arguments here. * If the function returns record, those I/O functions will be set up * when the function is first called. */ if (procStruct->pronargs) { Oid *types; char **names, *modes; int i, pos, total; /* extract argument type info from the pg_proc tuple */ total = get_func_arg_info(procTup, &types, &names, &modes); /* count number of in+inout args into proc->nargs */ if (modes == NULL) proc->nargs = total; else { /* proc->nargs was initialized to 0 above */ for (i = 0; i < total; i++) { if (modes[i] != PROARGMODE_OUT && modes[i] != PROARGMODE_TABLE) (proc->nargs)++; } } proc->argnames = (char **) PLy_malloc0(sizeof(char *) * proc->nargs); for (i = pos = 0; i < total; i++) { HeapTuple argTypeTup; Form_pg_type argTypeStruct; if (modes && (modes[i] == PROARGMODE_OUT || modes[i] == PROARGMODE_TABLE)) continue; /* skip OUT arguments */ Assert(types[i] == procStruct->proargtypes.values[pos]); argTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(types[i])); if (!HeapTupleIsValid(argTypeTup)) elog(ERROR, "cache lookup failed for type %u", types[i]); argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup); /* check argument type is OK, set up I/O function info */ switch (argTypeStruct->typtype) { case TYPTYPE_PSEUDO: /* Disallow pseudotype argument */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Python functions cannot accept type %s", format_type_be(types[i])))); break; case TYPTYPE_COMPOSITE: /* we'll set IO funcs at first call */ proc->args[pos].is_rowtype = 2; break; default: PLy_input_datum_func(&(proc->args[pos]), types[i], argTypeTup); break; } /* get argument name */ proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL; ReleaseSysCache(argTypeTup); pos++; } } /* * get the text of the function. */ prosrcdatum = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_prosrc, &isnull); if (isnull) elog(ERROR, "null prosrc"); procSource = TextDatumGetCString(prosrcdatum); PLy_procedure_compile(proc, procSource); pfree(procSource); procSource = NULL; } PG_CATCH(); { PLy_procedure_delete(proc); if (procSource) pfree(procSource); PG_RE_THROW(); } PG_END_TRY(); return proc; }
void PLy_procedure_delete | ( | PLyProcedure * | proc | ) |
Definition at line 390 of file plpy_procedure.c.
References PLyProcedure::argnames, PLyProcedure::args, PLyObToTuple::atts, PLyTupleToOb::atts, PLyProcedure::code, PLyProcedure::globals, i, PLyTypeInfo::in, PLyTypeInfo::is_rowtype, PLyProcedure::nargs, PLyTypeInfo::out, PLy_free(), PLyProcedure::proname, PLyProcedure::pyname, PLyTypeOutput::r, PLyTypeInput::r, PLyProcedure::src, and PLyProcedure::statics.
Referenced by plpython_inline_handler(), PLy_procedure_create(), and PLy_procedure_get().
{ int i; Py_XDECREF(proc->code); Py_XDECREF(proc->statics); Py_XDECREF(proc->globals); 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); } if (proc->argnames && proc->argnames[i]) PLy_free(proc->argnames[i]); } if (proc->src) PLy_free(proc->src); if (proc->argnames) PLy_free(proc->argnames); }
PLyProcedure* PLy_procedure_get | ( | Oid | fn_oid, | |
Oid | fn_rel, | |||
bool | is_trigger | |||
) |
Definition at line 75 of file plpy_procedure.c.
References elog, ERROR, PLyProcedureKey::fn_oid, PLyProcedureKey::fn_rel, HASH_ENTER, HASH_REMOVE, hash_search(), HeapTupleIsValid, NULL, ObjectIdGetDatum, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_free(), PLy_procedure_create(), PLy_procedure_delete(), PLy_procedure_valid(), PLyProcedureEntry::proc, PROCOID, ReleaseSysCache(), and SearchSysCache1.
Referenced by plpython_call_handler(), and plpython_validator().
{ bool use_cache = !(is_trigger && fn_rel == InvalidOid); HeapTuple procTup; PLyProcedureKey key; PLyProcedureEntry *volatile entry = NULL; PLyProcedure *volatile proc = NULL; bool found = false; procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid)); if (!HeapTupleIsValid(procTup)) elog(ERROR, "cache lookup failed for function %u", fn_oid); /* * Look for the function in the cache, unless we don't have the necessary * information (e.g. during validation). In that case we just don't cache * anything. */ if (use_cache) { key.fn_oid = fn_oid; key.fn_rel = fn_rel; entry = hash_search(PLy_procedure_cache, &key, HASH_ENTER, &found); proc = entry->proc; } PG_TRY(); { if (!found) { /* Haven't found it, create a new procedure */ proc = PLy_procedure_create(procTup, fn_oid, is_trigger); if (use_cache) entry->proc = proc; } else if (!PLy_procedure_valid(proc, procTup)) { /* Found it, but it's invalid, free and reuse the cache entry */ PLy_procedure_delete(proc); PLy_free(proc); proc = PLy_procedure_create(procTup, fn_oid, is_trigger); entry->proc = proc; } /* Found it and it's valid, it's fine to use it */ } PG_CATCH(); { /* Do not leave an uninitialised entry in the cache */ if (use_cache) hash_search(PLy_procedure_cache, &key, HASH_REMOVE, NULL); PG_RE_THROW(); } PG_END_TRY(); ReleaseSysCache(procTup); return proc; }
static char * PLy_procedure_munge_source | ( | const char * | name, | |
const char * | src | |||
) | [static] |
Definition at line 492 of file plpy_procedure.c.
References Assert, elog, FATAL, palloc(), and snprintf().
Referenced by PLy_procedure_compile().
{ 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 = palloc(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; }
char* PLy_procedure_name | ( | PLyProcedure * | proc | ) |
Definition at line 55 of file plpy_procedure.c.
References NULL, and PLyProcedure::proname.
Referenced by plpython_error_callback(), and PLy_traceback().
static bool PLy_procedure_valid | ( | PLyProcedure * | proc, | |
HeapTuple | procTup | |||
) | [static] |
Definition at line 461 of file plpy_procedure.c.
References PLyProcedure::args, Assert, PLyProcedure::fn_tid, PLyProcedure::fn_xmin, HeapTupleHeaderGetXmin, i, ItemPointerEquals(), PLyProcedure::nargs, NULL, PLy_procedure_argument_valid(), PLyProcedure::result, HeapTupleData::t_data, and HeapTupleData::t_self.
Referenced by PLy_procedure_get().
{ int i; bool valid; Assert(proc != NULL); /* If the pg_proc tuple has changed, it's not valid */ if (!(proc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) && ItemPointerEquals(&proc->fn_tid, &procTup->t_self))) return false; /* Else check the input argument datatypes */ valid = true; for (i = 0; i < proc->nargs; i++) { valid = PLy_procedure_argument_valid(&proc->args[i]); /* Short-circuit on first changed argument */ if (!valid) break; } /* if the output type is composite, it might have changed */ if (valid) valid = PLy_procedure_argument_valid(&proc->result); return valid; }
HTAB* PLy_procedure_cache = NULL [static] |
Definition at line 26 of file plpy_procedure.c.