PostgreSQL Source Code  git master
plpy_procedure.c
Go to the documentation of this file.
1 /*
2  * Python procedure manipulation for plpython
3  *
4  * src/pl/plpython/plpy_procedure.c
5  */
6 
7 #include "postgres.h"
8 
9 #include "access/htup_details.h"
10 #include "access/transam.h"
11 #include "funcapi.h"
12 #include "catalog/pg_proc.h"
13 #include "catalog/pg_proc_fn.h"
14 #include "catalog/pg_type.h"
15 #include "utils/builtins.h"
16 #include "utils/hsearch.h"
17 #include "utils/inval.h"
18 #include "utils/lsyscache.h"
19 #include "utils/memutils.h"
20 #include "utils/syscache.h"
21 
22 #include "plpython.h"
23 
24 #include "plpy_procedure.h"
25 
26 #include "plpy_elog.h"
27 #include "plpy_main.h"
28 
29 
30 static HTAB *PLy_procedure_cache = NULL;
31 
32 static PLyProcedure *PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger);
33 static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup);
34 static char *PLy_procedure_munge_source(const char *name, const char *src);
35 
36 
37 void
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 }
48 
49 /*
50  * PLy_procedure_name: get the name of the specified procedure.
51  *
52  * NB: this returns the SQL name, not the internal Python procedure name
53  */
54 char *
56 {
57  if (proc == NULL)
58  return "<unknown procedure>";
59  return proc->proname;
60 }
61 
62 /*
63  * PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and
64  * returns a new PLyProcedure.
65  *
66  * fn_oid is the OID of the function requested
67  * fn_rel is InvalidOid or the relation this function triggers on
68  * is_trigger denotes whether the function is a trigger function
69  *
70  * The reason that both fn_rel and is_trigger need to be passed is that when
71  * trigger functions get validated we don't know which relation(s) they'll
72  * be used with, so no sensible fn_rel can be passed.
73  */
75 PLy_procedure_get(Oid fn_oid, Oid fn_rel, bool is_trigger)
76 {
77  bool use_cache = !(is_trigger && fn_rel == InvalidOid);
78  HeapTuple procTup;
79  PLyProcedureKey key;
80  PLyProcedureEntry *volatile entry = NULL;
81  PLyProcedure *volatile proc = NULL;
82  bool found = false;
83 
84  procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid));
85  if (!HeapTupleIsValid(procTup))
86  elog(ERROR, "cache lookup failed for function %u", fn_oid);
87 
88  /*
89  * Look for the function in the cache, unless we don't have the necessary
90  * information (e.g. during validation). In that case we just don't cache
91  * anything.
92  */
93  if (use_cache)
94  {
95  key.fn_oid = fn_oid;
96  key.fn_rel = fn_rel;
97  entry = hash_search(PLy_procedure_cache, &key, HASH_ENTER, &found);
98  proc = entry->proc;
99  }
100 
101  PG_TRY();
102  {
103  if (!found)
104  {
105  /* Haven't found it, create a new procedure */
106  proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
107  if (use_cache)
108  entry->proc = proc;
109  }
110  else if (!PLy_procedure_valid(proc, procTup))
111  {
112  /* Found it, but it's invalid, free and reuse the cache entry */
113  entry->proc = NULL;
114  if (proc)
115  PLy_procedure_delete(proc);
116  proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
117  entry->proc = proc;
118  }
119  /* Found it and it's valid, it's fine to use it */
120  }
121  PG_CATCH();
122  {
123  /* Do not leave an uninitialized entry in the cache */
124  if (use_cache)
125  hash_search(PLy_procedure_cache, &key, HASH_REMOVE, NULL);
126  PG_RE_THROW();
127  }
128  PG_END_TRY();
129 
130  ReleaseSysCache(procTup);
131 
132  return proc;
133 }
134 
135 /*
136  * Create a new PLyProcedure structure
137  */
138 static PLyProcedure *
139 PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
140 {
141  char procName[NAMEDATALEN + 256];
142  Form_pg_proc procStruct;
143  PLyProcedure *volatile proc;
144  MemoryContext cxt;
145  MemoryContext oldcxt;
146  int rv;
147  char *ptr;
148 
149  procStruct = (Form_pg_proc) GETSTRUCT(procTup);
150  rv = snprintf(procName, sizeof(procName),
151  "__plpython_procedure_%s_%u",
152  NameStr(procStruct->proname),
153  fn_oid);
154  if (rv >= sizeof(procName) || rv < 0)
155  elog(ERROR, "procedure name would overrun buffer");
156 
157  /* Replace any not-legal-in-Python-names characters with '_' */
158  for (ptr = procName; *ptr; ptr++)
159  {
160  if (!((*ptr >= 'A' && *ptr <= 'Z') ||
161  (*ptr >= 'a' && *ptr <= 'z') ||
162  (*ptr >= '0' && *ptr <= '9')))
163  *ptr = '_';
164  }
165 
166  /* Create long-lived context that all procedure info will live in */
168  procName,
171 
172  oldcxt = MemoryContextSwitchTo(cxt);
173 
174  proc = (PLyProcedure *) palloc0(sizeof(PLyProcedure));
175  proc->mcxt = cxt;
176 
177  PG_TRY();
178  {
179  Datum protrftypes_datum;
180  Datum prosrcdatum;
181  bool isnull;
182  char *procSource;
183  int i;
184 
185  proc->proname = pstrdup(NameStr(procStruct->proname));
186  proc->pyname = pstrdup(procName);
187  proc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
188  proc->fn_tid = procTup->t_self;
189  proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
190  proc->is_setof = procStruct->proretset;
191  proc->is_procedure = (procStruct->prorettype == InvalidOid);
192  proc->src = NULL;
193  proc->argnames = NULL;
194  proc->args = NULL;
195  proc->nargs = 0;
196  proc->langid = procStruct->prolang;
197  protrftypes_datum = SysCacheGetAttr(PROCOID, procTup,
199  &isnull);
200  proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum);
201  proc->code = NULL;
202  proc->statics = NULL;
203  proc->globals = NULL;
204  proc->calldepth = 0;
205  proc->argstack = NULL;
206 
207  /*
208  * get information required for output conversion of the return value,
209  * but only if this isn't a trigger or procedure.
210  */
211  if (!is_trigger && procStruct->prorettype)
212  {
213  Oid rettype = procStruct->prorettype;
214  HeapTuple rvTypeTup;
215  Form_pg_type rvTypeStruct;
216 
217  rvTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettype));
218  if (!HeapTupleIsValid(rvTypeTup))
219  elog(ERROR, "cache lookup failed for type %u", rettype);
220  rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
221 
222  /* Disallow pseudotype result, except for void or record */
223  if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
224  {
225  if (rettype == VOIDOID ||
226  rettype == RECORDOID)
227  /* okay */ ;
228  else if (rettype == TRIGGEROID || rettype == EVTTRIGGEROID)
229  ereport(ERROR,
230  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
231  errmsg("trigger functions can only be called as triggers")));
232  else
233  ereport(ERROR,
234  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
235  errmsg("PL/Python functions cannot return type %s",
236  format_type_be(rettype))));
237  }
238 
239  /* set up output function for procedure result */
240  PLy_output_setup_func(&proc->result, proc->mcxt,
241  rettype, -1, proc);
242 
243  ReleaseSysCache(rvTypeTup);
244  }
245  else
246  {
247  /*
248  * In a trigger function, we use proc->result and proc->result_in
249  * for converting tuples, but we don't yet have enough info to set
250  * them up. PLy_exec_trigger will deal with it.
251  */
252  proc->result.typoid = InvalidOid;
253  proc->result_in.typoid = InvalidOid;
254  }
255 
256  /*
257  * Now get information required for input conversion of the
258  * procedure's arguments. Note that we ignore output arguments here.
259  * If the function returns record, those I/O functions will be set up
260  * when the function is first called.
261  */
262  if (procStruct->pronargs)
263  {
264  Oid *types;
265  char **names,
266  *modes;
267  int pos,
268  total;
269 
270  /* extract argument type info from the pg_proc tuple */
271  total = get_func_arg_info(procTup, &types, &names, &modes);
272 
273  /* count number of in+inout args into proc->nargs */
274  if (modes == NULL)
275  proc->nargs = total;
276  else
277  {
278  /* proc->nargs was initialized to 0 above */
279  for (i = 0; i < total; i++)
280  {
281  if (modes[i] != PROARGMODE_OUT &&
282  modes[i] != PROARGMODE_TABLE)
283  (proc->nargs)++;
284  }
285  }
286 
287  /* Allocate arrays for per-input-argument data */
288  proc->argnames = (char **) palloc0(sizeof(char *) * proc->nargs);
289  proc->args = (PLyDatumToOb *) palloc0(sizeof(PLyDatumToOb) * proc->nargs);
290 
291  for (i = pos = 0; i < total; i++)
292  {
293  HeapTuple argTypeTup;
294  Form_pg_type argTypeStruct;
295 
296  if (modes &&
297  (modes[i] == PROARGMODE_OUT ||
298  modes[i] == PROARGMODE_TABLE))
299  continue; /* skip OUT arguments */
300 
301  Assert(types[i] == procStruct->proargtypes.values[pos]);
302 
303  argTypeTup = SearchSysCache1(TYPEOID,
304  ObjectIdGetDatum(types[i]));
305  if (!HeapTupleIsValid(argTypeTup))
306  elog(ERROR, "cache lookup failed for type %u", types[i]);
307  argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
308 
309  /* disallow pseudotype arguments */
310  if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
311  ereport(ERROR,
312  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
313  errmsg("PL/Python functions cannot accept type %s",
314  format_type_be(types[i]))));
315 
316  /* set up I/O function info */
317  PLy_input_setup_func(&proc->args[pos], proc->mcxt,
318  types[i], -1, /* typmod not known */
319  proc);
320 
321  /* get argument name */
322  proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
323 
324  ReleaseSysCache(argTypeTup);
325 
326  pos++;
327  }
328  }
329 
330  /*
331  * get the text of the function.
332  */
333  prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
334  Anum_pg_proc_prosrc, &isnull);
335  if (isnull)
336  elog(ERROR, "null prosrc");
337  procSource = TextDatumGetCString(prosrcdatum);
338 
339  PLy_procedure_compile(proc, procSource);
340 
341  pfree(procSource);
342  }
343  PG_CATCH();
344  {
345  MemoryContextSwitchTo(oldcxt);
346  PLy_procedure_delete(proc);
347  PG_RE_THROW();
348  }
349  PG_END_TRY();
350 
351  MemoryContextSwitchTo(oldcxt);
352  return proc;
353 }
354 
355 /*
356  * Insert the procedure into the Python interpreter
357  */
358 void
359 PLy_procedure_compile(PLyProcedure *proc, const char *src)
360 {
361  PyObject *crv = NULL;
362  char *msrc;
363 
364  proc->globals = PyDict_Copy(PLy_interp_globals);
365 
366  /*
367  * SD is private preserved data between calls. GD is global data shared by
368  * all functions
369  */
370  proc->statics = PyDict_New();
371  if (!proc->statics)
372  PLy_elog(ERROR, NULL);
373  PyDict_SetItemString(proc->globals, "SD", proc->statics);
374 
375  /*
376  * insert the function code into the interpreter
377  */
378  msrc = PLy_procedure_munge_source(proc->pyname, src);
379  /* Save the mangled source for later inclusion in tracebacks */
380  proc->src = MemoryContextStrdup(proc->mcxt, msrc);
381  crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL);
382  pfree(msrc);
383 
384  if (crv != NULL)
385  {
386  int clen;
387  char call[NAMEDATALEN + 256];
388 
389  Py_DECREF(crv);
390 
391  /*
392  * compile a call to the function
393  */
394  clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
395  if (clen < 0 || clen >= sizeof(call))
396  elog(ERROR, "string would overflow buffer");
397  proc->code = Py_CompileString(call, "<string>", Py_eval_input);
398  if (proc->code != NULL)
399  return;
400  }
401 
402  if (proc->proname)
403  PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
404  proc->proname);
405  else
406  PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
407 }
408 
409 void
411 {
412  Py_XDECREF(proc->code);
413  Py_XDECREF(proc->statics);
414  Py_XDECREF(proc->globals);
415  MemoryContextDelete(proc->mcxt);
416 }
417 
418 /*
419  * Decide whether a cached PLyProcedure struct is still valid
420  */
421 static bool
423 {
424  if (proc == NULL)
425  return false;
426 
427  /* If the pg_proc tuple has changed, it's not valid */
428  if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
429  ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
430  return false;
431 
432  return true;
433 }
434 
435 static char *
436 PLy_procedure_munge_source(const char *name, const char *src)
437 {
438  char *mrc,
439  *mp;
440  const char *sp;
441  size_t mlen;
442  int plen;
443 
444  /*
445  * room for function source and the def statement
446  */
447  mlen = (strlen(src) * 2) + strlen(name) + 16;
448 
449  mrc = palloc(mlen);
450  plen = snprintf(mrc, mlen, "def %s():\n\t", name);
451  Assert(plen >= 0 && plen < mlen);
452 
453  sp = src;
454  mp = mrc + plen;
455 
456  while (*sp != '\0')
457  {
458  if (*sp == '\r' && *(sp + 1) == '\n')
459  sp++;
460 
461  if (*sp == '\n' || *sp == '\r')
462  {
463  *mp++ = '\n';
464  *mp++ = '\t';
465  sp++;
466  }
467  else
468  *mp++ = *sp++;
469  }
470  *mp++ = '\n';
471  *mp++ = '\n';
472  *mp = '\0';
473 
474  if (mp > (mrc + mlen))
475  elog(FATAL, "buffer overrun in PLy_munge_source");
476 
477  return mrc;
478 }
#define NIL
Definition: pg_list.h:69
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:198
ItemPointerData fn_tid
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
static char * PLy_procedure_munge_source(const char *name, const char *src)
#define HASH_ELEM
Definition: hsearch.h:87
struct typedefs * types
Definition: ecpg.c:29
#define MEMCONTEXT_COPY_NAME
Definition: memutils.h:188
char * pstrdup(const char *in)
Definition: mcxt.c:1063
void init_procedure_caches(void)
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:846
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define Anum_pg_proc_prosrc
Definition: pg_proc.h:115
Size entrysize
Definition: hsearch.h:73
void PLy_procedure_delete(PLyProcedure *proc)
int errcode(int sqlerrcode)
Definition: elog.c:575
void PLy_procedure_compile(PLyProcedure *proc, const char *src)
char * format_type_be(Oid type_oid)
Definition: format_type.c:320
#define Anum_pg_proc_protrftypes
Definition: pg_proc.h:114
TransactionId fn_xmin
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:904
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
unsigned int Oid
Definition: postgres_ext.h:31
#define PROARGMODE_OUT
Definition: pg_proc.h:5599
PLyDatumToOb * args
HeapTupleHeader t_data
Definition: htup.h:67
#define NAMEDATALEN
List * oid_array_to_list(Datum datum)
Definition: pg_proc.c:1157
char ** argnames
PLyProcedure * PLy_procedure_get(Oid fn_oid, Oid fn_rel, bool is_trigger)
Definition: dynahash.c:208
void pfree(void *pointer)
Definition: mcxt.c:936
char * PLy_procedure_name(PLyProcedure *proc)
#define VOIDOID
Definition: pg_type.h:690
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
MemoryContext AllocSetContextCreateExtended(MemoryContext parent, const char *name, int flags, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:394
#define FATAL
Definition: elog.h:52
struct PLyProcedureEntry PLyProcedureEntry
#define TRIGGEROID
Definition: pg_type.h:692
#define PROARGMODE_TABLE
Definition: pg_proc.h:5602
MemoryContext mcxt
ItemPointerData t_self
Definition: htup.h:65
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
PyObject * PLy_interp_globals
Definition: plpy_main.c:71
PyObject * statics
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:421
#define RECORDOID
Definition: pg_type.h:680
#define ereport(elevel, rest)
Definition: elog.h:122
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define PROVOLATILE_VOLATILE
Definition: pg_proc.h:5582
static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define PLy_elog
Definition: plpy_elog.h:36
#define HASH_BLOBS
Definition: hsearch.h:88
#define TextDatumGetCString(d)
Definition: builtins.h:92
PyObject * code
void * palloc0(Size size)
Definition: mcxt.c:864
uintptr_t Datum
Definition: postgres.h:365
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
Size keysize
Definition: hsearch.h:72
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
#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 EVTTRIGGEROID
Definition: pg_type.h:694
#define Assert(condition)
Definition: c.h:688
PLyDatumToOb result_in
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:307
struct PLyProcedureKey PLyProcedureKey
#define PG_RE_THROW()
Definition: elog.h:314
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
const char * name
Definition: encode.c:521
PLySavedArgs * argstack
#define TYPTYPE_PSEUDO
Definition: pg_type.h:724
PLyProcedure * proc
static HTAB * PLy_procedure_cache
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:299
PLyObToDatum result
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1050
int i
#define NameStr(name)
Definition: c.h:565
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
PyObject * globals
#define PG_END_TRY()
Definition: elog.h:300