PostgreSQL Source Code  git master
plpy_procedure.c File Reference
#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 "plpy_elog.h"
#include "plpy_main.h"
#include "plpy_procedure.h"
#include "plpython.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/inval.h"
#include "utils/lsyscache.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 33 of file plpy_procedure.c.

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

Referenced by PLy_initialize().

34 {
35  HASHCTL hash_ctl;
36 
37  memset(&hash_ctl, 0, sizeof(hash_ctl));
38  hash_ctl.keysize = sizeof(PLyProcedureKey);
39  hash_ctl.entrysize = sizeof(PLyProcedureEntry);
40  PLy_procedure_cache = hash_create("PL/Python procedures", 32, &hash_ctl,
42 }
#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 354 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().

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

◆ PLy_procedure_create()

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

Definition at line 134 of file plpy_procedure.c.

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::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(), PROCOID, PLyProcedure::proname, pstrdup(), PLyProcedure::pyname, ReleaseSysCache(), PLyProcedure::result, PLyProcedure::result_in, SearchSysCache1(), snprintf, PLyProcedure::src, PLyProcedure::statics, SysCacheGetAttr(), HeapTupleData::t_data, HeapTupleData::t_self, TextDatumGetCString, TopMemoryContext, PLyProcedure::trftypes, TYPEOID, types, PLyDatumToOb::typoid, and PLyObToDatum::typoid.

Referenced by PLy_procedure_get().

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

◆ PLy_procedure_delete()

void PLy_procedure_delete ( PLyProcedure proc)

Definition at line 405 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().

406 {
407  Py_XDECREF(proc->code);
408  Py_XDECREF(proc->statics);
409  Py_XDECREF(proc->globals);
410  MemoryContextDelete(proc->mcxt);
411 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
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 70 of file plpy_procedure.c.

References elog, ERROR, PLyProcedureKey::fn_oid, PLyProcedureKey::fn_rel, HASH_ENTER, HASH_REMOVE, hash_search(), HeapTupleIsValid, InvalidOid, sort-test::key, 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().

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

◆ PLy_procedure_munge_source()

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

Definition at line 431 of file plpy_procedure.c.

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

Referenced by PLy_procedure_compile().

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

◆ PLy_procedure_name()

char* PLy_procedure_name ( PLyProcedure proc)

Definition at line 50 of file plpy_procedure.c.

References PLyProcedure::proname.

Referenced by plpython_error_callback(), and PLy_traceback().

51 {
52  if (proc == NULL)
53  return "<unknown procedure>";
54  return proc->proname;
55 }

◆ PLy_procedure_valid()

static bool PLy_procedure_valid ( PLyProcedure proc,
HeapTuple  procTup 
)
static

Definition at line 417 of file plpy_procedure.c.

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

Referenced by PLy_procedure_get().

418 {
419  if (proc == NULL)
420  return false;
421 
422  /* If the pg_proc tuple has changed, it's not valid */
423  if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
424  ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
425  return false;
426 
427  return true;
428 }
ItemPointerData fn_tid
TransactionId fn_xmin
HeapTupleHeader t_data
Definition: htup.h:68
ItemPointerData t_self
Definition: htup.h:65
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:308
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29

Variable Documentation

◆ PLy_procedure_cache

HTAB* PLy_procedure_cache = NULL
static

Definition at line 25 of file plpy_procedure.c.