PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 "plpy_util.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, PLyTrigType is_trigger)
 
static bool PLy_procedure_valid (PLyProcedure *proc, HeapTuple procTup)
 
static charPLy_procedure_munge_source (const char *name, const char *src)
 
void init_procedure_caches (void)
 
charPLy_procedure_name (PLyProcedure *proc)
 
PLyProcedurePLy_procedure_get (Oid fn_oid, Oid fn_rel, PLyTrigType 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{
33
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, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
#define HASH_ELEM
Definition hsearch.h:95
#define HASH_BLOBS
Definition hsearch.h:97
static HTAB * PLy_procedure_cache
static int fb(int x)
Size keysize
Definition hsearch.h:75

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

Referenced by _PG_init().

◆ PLy_procedure_compile()

void PLy_procedure_compile ( PLyProcedure proc,
const char src 
)

Definition at line 365 of file plpy_procedure.c.

366{
367 PyObject *crv = NULL;
368 char *msrc;
370
372
373 /*
374 * SD is private preserved data between calls. GD is global data shared by
375 * all functions
376 */
377 proc->statics = PyDict_New();
378 if (!proc->statics)
380 PyDict_SetItemString(proc->globals, "SD", proc->statics);
381
382 /*
383 * insert the function code into the interpreter
384 */
386 /* Save the mangled source for later inclusion in tracebacks */
387 proc->src = MemoryContextStrdup(proc->mcxt, msrc);
389 if (code0)
391 pfree(msrc);
392
393 if (crv != NULL)
394 {
395 int clen;
396 char call[NAMEDATALEN + 256];
397
398 Py_DECREF(crv);
399
400 /*
401 * compile a call to the function
402 */
403 clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
404 if (clen < 0 || clen >= sizeof(call))
405 elog(ERROR, "string would overflow buffer");
406 proc->code = Py_CompileString(call, "<string>", Py_eval_input);
407 if (proc->code != NULL)
408 return;
409 }
410
411 if (proc->proname)
412 PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
413 proc->proname);
414 else
415 PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
416}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define PLy_elog
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition mcxt.c:1768
void pfree(void *pointer)
Definition mcxt.c:1616
#define NAMEDATALEN
PyObject * PLy_interp_globals
Definition plpy_main.c:50
static char * PLy_procedure_munge_source(const char *name, const char *src)
#define snprintf
Definition port.h:260
PyObject * code
MemoryContext mcxt
PyObject * globals
PyObject * statics

References PLyProcedure::code, elog, ERROR, fb(), 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,
PLyTrigType  is_trigger 
)
static

Definition at line 146 of file plpy_procedure.c.

147{
148 char procName[NAMEDATALEN + 256];
150 PLyProcedure *volatile proc;
151 MemoryContext cxt;
153 int rv;
154 char *ptr;
155
157 rv = snprintf(procName, sizeof(procName),
158 "__plpython_procedure_%s_%u",
159 NameStr(procStruct->proname),
160 fn_oid);
161 if (rv >= sizeof(procName) || rv < 0)
162 elog(ERROR, "procedure name would overrun buffer");
163
164 /* Replace any not-legal-in-Python-names characters with '_' */
165 for (ptr = procName; *ptr; ptr++)
166 {
167 if (!((*ptr >= 'A' && *ptr <= 'Z') ||
168 (*ptr >= 'a' && *ptr <= 'z') ||
169 (*ptr >= '0' && *ptr <= '9')))
170 *ptr = '_';
171 }
172
173 /* Create long-lived context that all procedure info will live in */
175 "PL/Python function",
177
179
181 proc->mcxt = cxt;
182
183 PG_TRY();
184 {
187 bool isnull;
188 char *procSource;
189 int i;
190
191 proc->proname = pstrdup(NameStr(procStruct->proname));
193 proc->pyname = pstrdup(procName);
195 proc->fn_tid = procTup->t_self;
196 proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
197 proc->is_setof = procStruct->proretset;
198 proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
199 proc->is_trigger = is_trigger;
200 proc->src = NULL;
201 proc->argnames = NULL;
202 proc->args = NULL;
203 proc->nargs = 0;
204 proc->langid = procStruct->prolang;
207 &isnull);
209 proc->code = NULL;
210 proc->statics = NULL;
211 proc->globals = NULL;
212 proc->calldepth = 0;
213 proc->argstack = NULL;
214
215 /*
216 * get information required for output conversion of the return value,
217 * but only if this isn't a trigger.
218 */
219 if (is_trigger == PLPY_NOT_TRIGGER)
220 {
221 Oid rettype = procStruct->prorettype;
224
227 elog(ERROR, "cache lookup failed for type %u", rettype);
229
230 /* Disallow pseudotype result, except for void or record */
231 if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
232 {
233 if (rettype == VOIDOID ||
234 rettype == RECORDOID)
235 /* okay */ ;
236 else if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
239 errmsg("trigger functions can only be called as triggers")));
240 else
243 errmsg("PL/Python functions cannot return type %s",
244 format_type_be(rettype))));
245 }
246
247 /* set up output function for procedure result */
248 PLy_output_setup_func(&proc->result, proc->mcxt,
249 rettype, -1, proc);
250
252 }
253 else
254 {
255 /*
256 * In a trigger function, we use proc->result and proc->result_in
257 * for converting tuples, but we don't yet have enough info to set
258 * them up. PLy_exec_trigger will deal with it.
259 */
260 proc->result.typoid = InvalidOid;
262 }
263
264 /*
265 * Now get information required for input conversion of the
266 * procedure's arguments. Note that we ignore output arguments here.
267 * If the function returns record, those I/O functions will be set up
268 * when the function is first called.
269 */
270 if (procStruct->pronargs)
271 {
272 Oid *types;
273 char **names,
274 *modes;
275 int pos,
276 total;
277
278 /* extract argument type info from the pg_proc tuple */
279 total = get_func_arg_info(procTup, &types, &names, &modes);
280
281 /* count number of in+inout args into proc->nargs */
282 if (modes == NULL)
283 proc->nargs = total;
284 else
285 {
286 /* proc->nargs was initialized to 0 above */
287 for (i = 0; i < total; i++)
288 {
289 if (modes[i] != PROARGMODE_OUT &&
291 (proc->nargs)++;
292 }
293 }
294
295 /* Allocate arrays for per-input-argument data */
296 proc->argnames = (char **) palloc0_array(char *, proc->nargs);
298
299 for (i = pos = 0; i < total; i++)
300 {
303
304 if (modes &&
305 (modes[i] == PROARGMODE_OUT ||
307 continue; /* skip OUT arguments */
308
309 Assert(types[i] == procStruct->proargtypes.values[pos]);
310
314 elog(ERROR, "cache lookup failed for type %u", types[i]);
316
317 /* disallow pseudotype arguments */
318 if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
321 errmsg("PL/Python functions cannot accept type %s",
323
324 /* set up I/O function info */
325 PLy_input_setup_func(&proc->args[pos], proc->mcxt,
326 types[i], -1, /* typmod not known */
327 proc);
328
329 /* get argument name */
330 proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
331
333
334 pos++;
335 }
336 }
337
338 /*
339 * get the text of the function.
340 */
344
346
348 }
349 PG_CATCH();
350 {
353 PG_RE_THROW();
354 }
355 PG_END_TRY();
356
358 return proc;
359}
#define TextDatumGetCString(d)
Definition builtins.h:98
#define NameStr(name)
Definition c.h:765
#define Assert(condition)
Definition c.h:873
struct typedefs * types
Definition ecpg.c:30
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define PG_RE_THROW()
Definition elog.h:405
#define PG_TRY(...)
Definition elog.h:372
#define PG_END_TRY(...)
Definition elog.h:397
#define PG_CATCH(...)
Definition elog.h:382
#define ereport(elevel,...)
Definition elog.h:150
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define palloc0_object(type)
Definition fe_memutils.h:75
char * format_type_be(Oid type_oid)
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
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
static void * GETSTRUCT(const HeapTupleData *tuple)
int i
Definition isn.c:77
char * pstrdup(const char *in)
Definition mcxt.c:1781
MemoryContext TopMemoryContext
Definition mcxt.c:166
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition mcxt.c:661
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define NIL
Definition pg_list.h:68
List * oid_array_to_list(Datum datum)
Definition pg_proc.c:1230
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)
@ PLPY_NOT_TRIGGER
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
unsigned int Oid
PLyDatumToOb * args
PLyTrigType is_trigger
PLyObToDatum result
PLyDatumToOb result_in
PLySavedArgs * argstack
ItemPointerData fn_tid
TransactionId fn_xmin
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, PLyProcedure::argnames, PLyProcedure::args, PLyProcedure::argstack, Assert, PLyProcedure::calldepth, PLyProcedure::code, elog, ereport, errcode(), errmsg(), ERROR, fb(), 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_array, palloc0_object, pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLPY_NOT_TRIGGER, 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(), 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 419 of file plpy_procedure.c.

420{
421 Py_XDECREF(proc->code);
422 Py_XDECREF(proc->statics);
423 Py_XDECREF(proc->globals);
425}
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472

References PLyProcedure::code, fb(), 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,
PLyTrigType  is_trigger 
)

Definition at line 71 of file plpy_procedure.c.

72{
73 bool use_cache;
76 PLyProcedureEntry *volatile entry = NULL;
77 PLyProcedure *volatile proc = NULL;
78 bool found = false;
79
80 if (is_trigger == PLPY_TRIGGER && fn_rel == InvalidOid)
81 use_cache = false;
82 else
83 use_cache = true;
84
87 elog(ERROR, "cache lookup failed for function %u", fn_oid);
88
89 /*
90 * Look for the function in the cache, unless we don't have the necessary
91 * information (e.g. during validation). In that case we just don't cache
92 * anything.
93 */
94 if (use_cache)
95 {
96 key.fn_oid = fn_oid;
97 key.fn_rel = fn_rel;
98 entry = hash_search(PLy_procedure_cache, &key, HASH_ENTER, &found);
99 proc = entry->proc;
100 }
101
102 PG_TRY();
103 {
104 if (!found)
105 {
106 /* Haven't found it, create a new procedure */
107 proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
108 if (use_cache)
109 entry->proc = proc;
110 else
111 {
112 /* Delete the proc, otherwise it's a memory leak */
114 proc = NULL;
115 }
116 }
117 else if (!PLy_procedure_valid(proc, procTup))
118 {
119 /* Found it, but it's invalid, free and reuse the cache entry */
120 entry->proc = NULL;
121 if (proc)
123 proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
124 entry->proc = proc;
125 }
126 /* Found it and it's valid, it's fine to use it */
127 }
128 PG_CATCH();
129 {
130 /* Do not leave an uninitialized entry in the cache */
131 if (use_cache)
133 PG_RE_THROW();
134 }
135 PG_END_TRY();
136
138
139 return proc;
140}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
@ HASH_REMOVE
Definition hsearch.h:115
@ HASH_ENTER
Definition hsearch.h:114
static PLyProcedure * PLy_procedure_create(HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger)
static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
@ PLPY_TRIGGER
PLyProcedure * proc

References elog, ERROR, fb(), HASH_ENTER, HASH_REMOVE, hash_search(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLPY_TRIGGER, 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 445 of file plpy_procedure.c.

446{
447 char *mrc,
448 *mp;
449 const char *sp;
450 size_t mlen;
451 int plen;
452
453 /*
454 * room for function source and the def statement
455 */
456 mlen = (strlen(src) * 2) + strlen(name) + 16;
457
458 mrc = palloc(mlen);
459 plen = snprintf(mrc, mlen, "def %s():\n\t", name);
460 Assert(plen >= 0 && plen < mlen);
461
462 sp = src;
463 mp = mrc + plen;
464
465 while (*sp != '\0')
466 {
467 if (*sp == '\r' && *(sp + 1) == '\n')
468 sp++;
469
470 if (*sp == '\n' || *sp == '\r')
471 {
472 *mp++ = '\n';
473 *mp++ = '\t';
474 sp++;
475 }
476 else
477 *mp++ = *sp++;
478 }
479 *mp++ = '\n';
480 *mp++ = '\n';
481 *mp = '\0';
482
483 if (mp > (mrc + mlen))
484 elog(FATAL, "buffer overrun in PLy_procedure_munge_source");
485
486 return mrc;
487}
#define FATAL
Definition elog.h:41
void * palloc(Size size)
Definition mcxt.c:1387
const char * name

References Assert, elog, FATAL, fb(), 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 fb(), and 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 431 of file plpy_procedure.c.

432{
433 if (proc == NULL)
434 return false;
435
436 /* If the pg_proc tuple has changed, it's not valid */
437 if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
438 ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
439 return false;
440
441 return true;
442}
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
Definition itemptr.c:35

References fb(), PLyProcedure::fn_tid, PLyProcedure::fn_xmin, HeapTupleHeaderGetRawXmin(), and ItemPointerEquals().

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().