PostgreSQL Source Code  git master
plpy_procedure.h File Reference
#include "plpy_typeio.h"
Include dependency graph for plpy_procedure.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PLySavedArgs
 
struct  PLyProcedure
 
struct  PLyProcedureKey
 
struct  PLyProcedureEntry
 

Typedefs

typedef struct PLySavedArgs PLySavedArgs
 
typedef struct PLyProcedure PLyProcedure
 
typedef struct PLyProcedureKey PLyProcedureKey
 
typedef struct PLyProcedureEntry PLyProcedureEntry
 

Functions

void init_procedure_caches (void)
 
char * PLy_procedure_name (PLyProcedure *proc)
 
PLyProcedurePLy_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)
 

Typedef Documentation

◆ PLyProcedure

◆ PLyProcedureEntry

◆ PLyProcedureKey

◆ PLySavedArgs

Function Documentation

◆ init_procedure_caches()

void init_procedure_caches ( void  )

Definition at line 38 of file plpy_procedure.c.

References HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, and HASHCTL::keysize.

Referenced by PLy_initialize().

39 {
40  HASHCTL hash_ctl;
41 
42  memset(&hash_ctl, 0, sizeof(hash_ctl));
43  hash_ctl.keysize = sizeof(PLyProcedureKey);
44  hash_ctl.entrysize = sizeof(PLyProcedureEntry);
45  PLy_procedure_cache = hash_create("PL/Python procedures", 32, &hash_ctl,
47 }
#define HASH_ELEM
Definition: hsearch.h:87
Size entrysize
Definition: hsearch.h:73
struct PLyProcedureEntry PLyProcedureEntry
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72
struct PLyProcedureKey PLyProcedureKey
static HTAB * PLy_procedure_cache

◆ PLy_procedure_compile()

void PLy_procedure_compile ( PLyProcedure proc,
const char *  src 
)

Definition at line 361 of file plpy_procedure.c.

References PLyProcedure::code, elog, ERROR, PLyProcedure::globals, PLyProcedure::mcxt, MemoryContextStrdup(), NAMEDATALEN, pfree(), PLy_elog, PLy_interp_globals, PLy_procedure_munge_source(), PLyProcedure::proname, PLyProcedure::pyname, snprintf(), PLyProcedure::src, and PLyProcedure::statics.

Referenced by plpython_inline_handler(), and PLy_procedure_create().

362 {
363  PyObject *crv = NULL;
364  char *msrc;
365 
366  proc->globals = PyDict_Copy(PLy_interp_globals);
367 
368  /*
369  * SD is private preserved data between calls. GD is global data shared by
370  * all functions
371  */
372  proc->statics = PyDict_New();
373  if (!proc->statics)
374  PLy_elog(ERROR, NULL);
375  PyDict_SetItemString(proc->globals, "SD", proc->statics);
376 
377  /*
378  * insert the function code into the interpreter
379  */
380  msrc = PLy_procedure_munge_source(proc->pyname, src);
381  /* Save the mangled source for later inclusion in tracebacks */
382  proc->src = MemoryContextStrdup(proc->mcxt, msrc);
383  crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL);
384  pfree(msrc);
385 
386  if (crv != NULL)
387  {
388  int clen;
389  char call[NAMEDATALEN + 256];
390 
391  Py_DECREF(crv);
392 
393  /*
394  * compile a call to the function
395  */
396  clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
397  if (clen < 0 || clen >= sizeof(call))
398  elog(ERROR, "string would overflow buffer");
399  proc->code = Py_CompileString(call, "<string>", Py_eval_input);
400  if (proc->code != NULL)
401  return;
402  }
403 
404  if (proc->proname)
405  PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
406  proc->proname);
407  else
408  PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
409 }
static char * PLy_procedure_munge_source(const char *name, const char *src)
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define NAMEDATALEN
void pfree(void *pointer)
Definition: mcxt.c:936
#define ERROR
Definition: elog.h:43
MemoryContext mcxt
PyObject * PLy_interp_globals
Definition: plpy_main.c:71
PyObject * statics
#define PLy_elog
Definition: plpy_elog.h:36
PyObject * code
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1050
#define elog
Definition: elog.h:219
PyObject * globals

◆ PLy_procedure_delete()

void PLy_procedure_delete ( PLyProcedure proc)

Definition at line 412 of file plpy_procedure.c.

References PLyProcedure::code, PLyProcedure::globals, PLyProcedure::mcxt, MemoryContextDelete(), and PLyProcedure::statics.

Referenced by plpython_inline_handler(), PLy_procedure_create(), and PLy_procedure_get().

413 {
414  Py_XDECREF(proc->code);
415  Py_XDECREF(proc->statics);
416  Py_XDECREF(proc->globals);
417  MemoryContextDelete(proc->mcxt);
418 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:198
MemoryContext mcxt
PyObject * statics
PyObject * code
PyObject * globals

◆ PLy_procedure_get()

PLyProcedure* PLy_procedure_get ( Oid  fn_oid,
Oid  fn_rel,
bool  is_trigger 
)

Definition at line 77 of file plpy_procedure.c.

References elog, ERROR, PLyProcedureKey::fn_oid, PLyProcedureKey::fn_rel, HASH_ENTER, HASH_REMOVE, hash_search(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_procedure_create(), PLy_procedure_delete(), PLy_procedure_valid(), PLyProcedureEntry::proc, PROCOID, ReleaseSysCache(), and SearchSysCache1().

Referenced by plpython_call_handler(), and plpython_validator().

78 {
79  bool use_cache = !(is_trigger && fn_rel == InvalidOid);
80  HeapTuple procTup;
81  PLyProcedureKey key;
82  PLyProcedureEntry *volatile entry = NULL;
83  PLyProcedure *volatile proc = NULL;
84  bool found = false;
85 
86  procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid));
87  if (!HeapTupleIsValid(procTup))
88  elog(ERROR, "cache lookup failed for function %u", fn_oid);
89 
90  /*
91  * Look for the function in the cache, unless we don't have the necessary
92  * information (e.g. during validation). In that case we just don't cache
93  * anything.
94  */
95  if (use_cache)
96  {
97  key.fn_oid = fn_oid;
98  key.fn_rel = fn_rel;
99  entry = hash_search(PLy_procedure_cache, &key, HASH_ENTER, &found);
100  proc = entry->proc;
101  }
102 
103  PG_TRY();
104  {
105  if (!found)
106  {
107  /* Haven't found it, create a new procedure */
108  proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
109  if (use_cache)
110  entry->proc = proc;
111  }
112  else if (!PLy_procedure_valid(proc, procTup))
113  {
114  /* Found it, but it's invalid, free and reuse the cache entry */
115  entry->proc = NULL;
116  if (proc)
117  PLy_procedure_delete(proc);
118  proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
119  entry->proc = proc;
120  }
121  /* Found it and it's valid, it's fine to use it */
122  }
123  PG_CATCH();
124  {
125  /* Do not leave an uninitialized entry in the cache */
126  if (use_cache)
128  PG_RE_THROW();
129  }
130  PG_END_TRY();
131 
132  ReleaseSysCache(procTup);
133 
134  return proc;
135 }
void PLy_procedure_delete(PLyProcedure *proc)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:904
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define InvalidOid
Definition: postgres_ext.h:36
static PLyProcedure * PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
#define PG_CATCH()
Definition: elog.h:293
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define PG_RE_THROW()
Definition: elog.h:314
PLyProcedure * proc
static HTAB * PLy_procedure_cache
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300

◆ PLy_procedure_name()

char* PLy_procedure_name ( PLyProcedure proc)

Definition at line 57 of file plpy_procedure.c.

References PLyProcedure::proname.

Referenced by plpython_error_callback(), and PLy_traceback().

58 {
59  if (proc == NULL)
60  return "<unknown procedure>";
61  return proc->proname;
62 }