PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
plpy_procedure.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "plpy_elog.h"
#include "plpy_main.h"
#include "plpy_procedure.h"
#include "plpython.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
Include dependency graph for plpy_procedure.c:

Go to the source code of this file.

Functions

static PLyProcedurePLy_procedure_create (HeapTuple procTup, Oid fn_oid, bool is_trigger)
 
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)
 
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)
 

Variables

static HTABPLy_procedure_cache = NULL
 

Function Documentation

◆ init_procedure_caches()

void init_procedure_caches ( void  )

Definition at line 30 of file plpy_procedure.c.

31 {
32  HASHCTL hash_ctl;
33 
34  hash_ctl.keysize = sizeof(PLyProcedureKey);
35  hash_ctl.entrysize = sizeof(PLyProcedureEntry);
36  PLy_procedure_cache = hash_create("PL/Python procedures", 32, &hash_ctl,
38 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
static HTAB * PLy_procedure_cache
struct PLyProcedureKey PLyProcedureKey
struct PLyProcedureEntry PLyProcedureEntry
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

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

Referenced by PLy_initialize().

◆ PLy_procedure_compile()

void PLy_procedure_compile ( PLyProcedure proc,
const char *  src 
)

Definition at line 349 of file plpy_procedure.c.

350 {
351  PyObject *crv = NULL;
352  char *msrc;
353 
354  proc->globals = PyDict_Copy(PLy_interp_globals);
355 
356  /*
357  * SD is private preserved data between calls. GD is global data shared by
358  * all functions
359  */
360  proc->statics = PyDict_New();
361  if (!proc->statics)
362  PLy_elog(ERROR, NULL);
363  PyDict_SetItemString(proc->globals, "SD", proc->statics);
364 
365  /*
366  * insert the function code into the interpreter
367  */
368  msrc = PLy_procedure_munge_source(proc->pyname, src);
369  /* Save the mangled source for later inclusion in tracebacks */
370  proc->src = MemoryContextStrdup(proc->mcxt, msrc);
371  crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL);
372  pfree(msrc);
373 
374  if (crv != NULL)
375  {
376  int clen;
377  char call[NAMEDATALEN + 256];
378 
379  Py_DECREF(crv);
380 
381  /*
382  * compile a call to the function
383  */
384  clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
385  if (clen < 0 || clen >= sizeof(call))
386  elog(ERROR, "string would overflow buffer");
387  proc->code = Py_CompileString(call, "<string>", Py_eval_input);
388  if (proc->code != NULL)
389  return;
390  }
391 
392  if (proc->proname)
393  PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
394  proc->proname);
395  else
396  PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
397 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define PLy_elog
void pfree(void *pointer)
Definition: mcxt.c:1521
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
#define NAMEDATALEN
PyObject * PLy_interp_globals
Definition: plpy_main.c:51
static char * PLy_procedure_munge_source(const char *name, const char *src)
#define snprintf
Definition: port.h:238
PyObject * code
MemoryContext mcxt
PyObject * globals
PyObject * statics

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 plpython3_inline_handler(), and PLy_procedure_create().

◆ PLy_procedure_create()

static PLyProcedure * PLy_procedure_create ( HeapTuple  procTup,
Oid  fn_oid,
bool  is_trigger 
)
static

Definition at line 130 of file plpy_procedure.c.

131 {
132  char procName[NAMEDATALEN + 256];
133  Form_pg_proc procStruct;
134  PLyProcedure *volatile proc;
135  MemoryContext cxt;
136  MemoryContext oldcxt;
137  int rv;
138  char *ptr;
139 
140  procStruct = (Form_pg_proc) GETSTRUCT(procTup);
141  rv = snprintf(procName, sizeof(procName),
142  "__plpython_procedure_%s_%u",
143  NameStr(procStruct->proname),
144  fn_oid);
145  if (rv >= sizeof(procName) || rv < 0)
146  elog(ERROR, "procedure name would overrun buffer");
147 
148  /* Replace any not-legal-in-Python-names characters with '_' */
149  for (ptr = procName; *ptr; ptr++)
150  {
151  if (!((*ptr >= 'A' && *ptr <= 'Z') ||
152  (*ptr >= 'a' && *ptr <= 'z') ||
153  (*ptr >= '0' && *ptr <= '9')))
154  *ptr = '_';
155  }
156 
157  /* Create long-lived context that all procedure info will live in */
159  "PL/Python function",
161 
162  oldcxt = MemoryContextSwitchTo(cxt);
163 
164  proc = (PLyProcedure *) palloc0(sizeof(PLyProcedure));
165  proc->mcxt = cxt;
166 
167  PG_TRY();
168  {
169  Datum protrftypes_datum;
170  Datum prosrcdatum;
171  bool isnull;
172  char *procSource;
173  int i;
174 
175  proc->proname = pstrdup(NameStr(procStruct->proname));
177  proc->pyname = pstrdup(procName);
178  proc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
179  proc->fn_tid = procTup->t_self;
180  proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
181  proc->is_setof = procStruct->proretset;
182  proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
183  proc->is_trigger = is_trigger;
184  proc->src = NULL;
185  proc->argnames = NULL;
186  proc->args = NULL;
187  proc->nargs = 0;
188  proc->langid = procStruct->prolang;
189  protrftypes_datum = SysCacheGetAttr(PROCOID, procTup,
190  Anum_pg_proc_protrftypes,
191  &isnull);
192  proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum);
193  proc->code = NULL;
194  proc->statics = NULL;
195  proc->globals = NULL;
196  proc->calldepth = 0;
197  proc->argstack = NULL;
198 
199  /*
200  * get information required for output conversion of the return value,
201  * but only if this isn't a trigger.
202  */
203  if (!is_trigger)
204  {
205  Oid rettype = procStruct->prorettype;
206  HeapTuple rvTypeTup;
207  Form_pg_type rvTypeStruct;
208 
209  rvTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettype));
210  if (!HeapTupleIsValid(rvTypeTup))
211  elog(ERROR, "cache lookup failed for type %u", rettype);
212  rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
213 
214  /* Disallow pseudotype result, except for void or record */
215  if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
216  {
217  if (rettype == VOIDOID ||
218  rettype == RECORDOID)
219  /* okay */ ;
220  else if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
221  ereport(ERROR,
222  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
223  errmsg("trigger functions can only be called as triggers")));
224  else
225  ereport(ERROR,
226  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
227  errmsg("PL/Python functions cannot return type %s",
228  format_type_be(rettype))));
229  }
230 
231  /* set up output function for procedure result */
232  PLy_output_setup_func(&proc->result, proc->mcxt,
233  rettype, -1, proc);
234 
235  ReleaseSysCache(rvTypeTup);
236  }
237  else
238  {
239  /*
240  * In a trigger function, we use proc->result and proc->result_in
241  * for converting tuples, but we don't yet have enough info to set
242  * them up. PLy_exec_trigger will deal with it.
243  */
244  proc->result.typoid = InvalidOid;
245  proc->result_in.typoid = InvalidOid;
246  }
247 
248  /*
249  * Now get information required for input conversion of the
250  * procedure's arguments. Note that we ignore output arguments here.
251  * If the function returns record, those I/O functions will be set up
252  * when the function is first called.
253  */
254  if (procStruct->pronargs)
255  {
256  Oid *types;
257  char **names,
258  *modes;
259  int pos,
260  total;
261 
262  /* extract argument type info from the pg_proc tuple */
263  total = get_func_arg_info(procTup, &types, &names, &modes);
264 
265  /* count number of in+inout args into proc->nargs */
266  if (modes == NULL)
267  proc->nargs = total;
268  else
269  {
270  /* proc->nargs was initialized to 0 above */
271  for (i = 0; i < total; i++)
272  {
273  if (modes[i] != PROARGMODE_OUT &&
274  modes[i] != PROARGMODE_TABLE)
275  (proc->nargs)++;
276  }
277  }
278 
279  /* Allocate arrays for per-input-argument data */
280  proc->argnames = (char **) palloc0(sizeof(char *) * proc->nargs);
281  proc->args = (PLyDatumToOb *) palloc0(sizeof(PLyDatumToOb) * proc->nargs);
282 
283  for (i = pos = 0; i < total; i++)
284  {
285  HeapTuple argTypeTup;
286  Form_pg_type argTypeStruct;
287 
288  if (modes &&
289  (modes[i] == PROARGMODE_OUT ||
290  modes[i] == PROARGMODE_TABLE))
291  continue; /* skip OUT arguments */
292 
293  Assert(types[i] == procStruct->proargtypes.values[pos]);
294 
295  argTypeTup = SearchSysCache1(TYPEOID,
297  if (!HeapTupleIsValid(argTypeTup))
298  elog(ERROR, "cache lookup failed for type %u", types[i]);
299  argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
300 
301  /* disallow pseudotype arguments */
302  if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
303  ereport(ERROR,
304  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
305  errmsg("PL/Python functions cannot accept type %s",
306  format_type_be(types[i]))));
307 
308  /* set up I/O function info */
309  PLy_input_setup_func(&proc->args[pos], proc->mcxt,
310  types[i], -1, /* typmod not known */
311  proc);
312 
313  /* get argument name */
314  proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
315 
316  ReleaseSysCache(argTypeTup);
317 
318  pos++;
319  }
320  }
321 
322  /*
323  * get the text of the function.
324  */
325  prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup,
326  Anum_pg_proc_prosrc);
327  procSource = TextDatumGetCString(prosrcdatum);
328 
329  PLy_procedure_compile(proc, procSource);
330 
331  pfree(procSource);
332  }
333  PG_CATCH();
334  {
335  MemoryContextSwitchTo(oldcxt);
336  PLy_procedure_delete(proc);
337  PG_RE_THROW();
338  }
339  PG_END_TRY();
340 
341  MemoryContextSwitchTo(oldcxt);
342  return proc;
343 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:725
#define Assert(condition)
Definition: c.h:837
struct typedefs * types
Definition: ecpg.c:30
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define PG_RE_THROW()
Definition: elog.h:412
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_CATCH(...)
Definition: elog.h:381
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:304
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
int i
Definition: isn.c:72
char * pstrdup(const char *in)
Definition: mcxt.c:1696
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * palloc0(Size size)
Definition: mcxt.c:1347
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:612
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define NIL
Definition: pg_list.h:68
List * oid_array_to_list(Datum datum)
Definition: pg_proc.c:1184
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
void PLy_procedure_compile(PLyProcedure *proc, const char *src)
void PLy_procedure_delete(PLyProcedure *proc)
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:296
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:418
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContextSwitchTo(old_ctx)
ItemPointerData t_self
Definition: htup.h:65
HeapTupleHeader t_data
Definition: htup.h:68
PLyDatumToOb * args
PLyObToDatum result
PLyDatumToOb result_in
PLySavedArgs * argstack
char ** argnames
ItemPointerData fn_tid
TransactionId fn_xmin
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:631

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, PLyProcedure::argnames, PLyProcedure::args, PLyProcedure::argstack, Assert, PLyProcedure::calldepth, PLyProcedure::code, elog, ereport, errcode(), errmsg(), ERROR, PLyProcedure::fn_readonly, PLyProcedure::fn_tid, PLyProcedure::fn_xmin, format_type_be(), get_func_arg_info(), GETSTRUCT, PLyProcedure::globals, HeapTupleHeaderGetRawXmin, HeapTupleIsValid, i, InvalidOid, PLyProcedure::is_procedure, PLyProcedure::is_setof, PLyProcedure::is_trigger, PLyProcedure::langid, PLyProcedure::mcxt, MemoryContextSetIdentifier(), MemoryContextSwitchTo(), NAMEDATALEN, NameStr, PLyProcedure::nargs, NIL, ObjectIdGetDatum(), oid_array_to_list(), palloc0(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_input_setup_func(), PLy_output_setup_func(), PLy_procedure_compile(), PLy_procedure_delete(), PLyProcedure::proname, pstrdup(), PLyProcedure::pyname, ReleaseSysCache(), PLyProcedure::result, PLyProcedure::result_in, SearchSysCache1(), snprintf, PLyProcedure::src, PLyProcedure::statics, SysCacheGetAttr(), SysCacheGetAttrNotNull(), HeapTupleData::t_data, HeapTupleData::t_self, TextDatumGetCString, TopMemoryContext, PLyProcedure::trftypes, types, PLyDatumToOb::typoid, and PLyObToDatum::typoid.

Referenced by PLy_procedure_get().

◆ PLy_procedure_delete()

void PLy_procedure_delete ( PLyProcedure proc)

Definition at line 400 of file plpy_procedure.c.

401 {
402  Py_XDECREF(proc->code);
403  Py_XDECREF(proc->statics);
404  Py_XDECREF(proc->globals);
405  MemoryContextDelete(proc->mcxt);
406 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

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

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

◆ PLy_procedure_get()

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

Definition at line 66 of file plpy_procedure.c.

67 {
68  bool use_cache = !(is_trigger && fn_rel == InvalidOid);
69  HeapTuple procTup;
71  PLyProcedureEntry *volatile entry = NULL;
72  PLyProcedure *volatile proc = NULL;
73  bool found = false;
74 
75  procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid));
76  if (!HeapTupleIsValid(procTup))
77  elog(ERROR, "cache lookup failed for function %u", fn_oid);
78 
79  /*
80  * Look for the function in the cache, unless we don't have the necessary
81  * information (e.g. during validation). In that case we just don't cache
82  * anything.
83  */
84  if (use_cache)
85  {
86  key.fn_oid = fn_oid;
87  key.fn_rel = fn_rel;
88  entry = hash_search(PLy_procedure_cache, &key, HASH_ENTER, &found);
89  proc = entry->proc;
90  }
91 
92  PG_TRY();
93  {
94  if (!found)
95  {
96  /* Haven't found it, create a new procedure */
97  proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
98  if (use_cache)
99  entry->proc = proc;
100  }
101  else if (!PLy_procedure_valid(proc, procTup))
102  {
103  /* Found it, but it's invalid, free and reuse the cache entry */
104  entry->proc = NULL;
105  if (proc)
106  PLy_procedure_delete(proc);
107  proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
108  entry->proc = proc;
109  }
110  /* Found it and it's valid, it's fine to use it */
111  }
112  PG_CATCH();
113  {
114  /* Do not leave an uninitialized entry in the cache */
115  if (use_cache)
117  PG_RE_THROW();
118  }
119  PG_END_TRY();
120 
121  ReleaseSysCache(procTup);
122 
123  return proc;
124 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
static PLyProcedure * PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
PLyProcedure * proc

References elog, ERROR, HASH_ENTER, HASH_REMOVE, hash_search(), HeapTupleIsValid, InvalidOid, sort-test::key, ObjectIdGetDatum(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_procedure_cache, PLy_procedure_create(), PLy_procedure_delete(), PLy_procedure_valid(), PLyProcedureEntry::proc, ReleaseSysCache(), and SearchSysCache1().

Referenced by plpython3_call_handler(), and plpython3_validator().

◆ PLy_procedure_munge_source()

static char * PLy_procedure_munge_source ( const char *  name,
const char *  src 
)
static

Definition at line 426 of file plpy_procedure.c.

427 {
428  char *mrc,
429  *mp;
430  const char *sp;
431  size_t mlen;
432  int plen;
433 
434  /*
435  * room for function source and the def statement
436  */
437  mlen = (strlen(src) * 2) + strlen(name) + 16;
438 
439  mrc = palloc(mlen);
440  plen = snprintf(mrc, mlen, "def %s():\n\t", name);
441  Assert(plen >= 0 && plen < mlen);
442 
443  sp = src;
444  mp = mrc + plen;
445 
446  while (*sp != '\0')
447  {
448  if (*sp == '\r' && *(sp + 1) == '\n')
449  sp++;
450 
451  if (*sp == '\n' || *sp == '\r')
452  {
453  *mp++ = '\n';
454  *mp++ = '\t';
455  sp++;
456  }
457  else
458  *mp++ = *sp++;
459  }
460  *mp++ = '\n';
461  *mp++ = '\n';
462  *mp = '\0';
463 
464  if (mp > (mrc + mlen))
465  elog(FATAL, "buffer overrun in PLy_procedure_munge_source");
466 
467  return mrc;
468 }
#define FATAL
Definition: elog.h:41
void * palloc(Size size)
Definition: mcxt.c:1317
const char * name

References Assert, elog, FATAL, name, palloc(), and snprintf.

Referenced by PLy_procedure_compile().

◆ PLy_procedure_name()

char* PLy_procedure_name ( PLyProcedure proc)

Definition at line 46 of file plpy_procedure.c.

47 {
48  if (proc == NULL)
49  return "<unknown procedure>";
50  return proc->proname;
51 }

References PLyProcedure::proname.

Referenced by plpython_error_callback(), and PLy_traceback().

◆ PLy_procedure_valid()

static bool PLy_procedure_valid ( PLyProcedure proc,
HeapTuple  procTup 
)
static

Definition at line 412 of file plpy_procedure.c.

413 {
414  if (proc == NULL)
415  return false;
416 
417  /* If the pg_proc tuple has changed, it's not valid */
418  if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
419  ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
420  return false;
421 
422  return true;
423 }
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:35

References PLyProcedure::fn_tid, PLyProcedure::fn_xmin, HeapTupleHeaderGetRawXmin, ItemPointerEquals(), HeapTupleData::t_data, and HeapTupleData::t_self.

Referenced by PLy_procedure_get().

Variable Documentation

◆ PLy_procedure_cache

HTAB* PLy_procedure_cache = NULL
static

Definition at line 22 of file plpy_procedure.c.

Referenced by init_procedure_caches(), and PLy_procedure_get().