PostgreSQL Source Code git master
Loading...
Searching...
No Matches
plpy_procedure.c File Reference
#include "postgres.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/event_trigger.h"
#include "commands/trigger.h"
#include "funcapi.h"
#include "plpy_elog.h"
#include "plpy_exec.h"
#include "plpy_main.h"
#include "plpy_procedure.h"
#include "plpy_util.h"
#include "utils/builtins.h"
#include "utils/funccache.h"
#include "utils/syscache.h"
Include dependency graph for plpy_procedure.c:

Go to the source code of this file.

Functions

static void PLy_procedure_create (PLyProcedure *proc, HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger)
 
static charPLy_procedure_munge_source (const char *name, const char *src)
 
static void PLy_compile_callback (FunctionCallInfo fcinfo, HeapTuple procTup, const CachedFunctionHashKey *hashkey, CachedFunction *cfunc, bool forValidator)
 
static void PLy_delete_callback (CachedFunction *cfunc)
 
static void RemovePLyProcedureCache (void *arg)
 
charPLy_procedure_name (PLyProcedure *proc)
 
PLyProcedureCachePLy_procedure_get (FunctionCallInfo fcinfo, bool forValidator)
 
void PLy_procedure_compile (PLyProcedure *proc, const char *src)
 
void PLy_procedure_delete (PLyProcedure *proc)
 

Function Documentation

◆ PLy_compile_callback()

static void PLy_compile_callback ( FunctionCallInfo  fcinfo,
HeapTuple  procTup,
const CachedFunctionHashKey hashkey,
CachedFunction cfunc,
bool  forValidator 
)
static

Definition at line 478 of file plpy_procedure.c.

483{
484 PLyProcedure *proc = (PLyProcedure *) cfunc;
485 Oid fn_oid = fcinfo->flinfo->fn_oid;
486 PLyTrigType is_trigger;
487
488 /*
489 * Derive the trigger type from the call context, matching what
490 * plpython3_call_handler dispatches on.
491 */
492 if (CALLED_AS_TRIGGER(fcinfo))
493 is_trigger = PLPY_TRIGGER;
494 else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
495 is_trigger = PLPY_EVENT_TRIGGER;
496 else
497 is_trigger = PLPY_NOT_TRIGGER;
498
499 PLy_procedure_create(proc, procTup, fn_oid, is_trigger);
500}
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
static void PLy_procedure_create(PLyProcedure *proc, HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger)
PLyTrigType
@ PLPY_EVENT_TRIGGER
@ PLPY_TRIGGER
@ PLPY_NOT_TRIGGER
unsigned int Oid
static int fb(int x)
Oid fn_oid
Definition fmgr.h:59
FmgrInfo * flinfo
Definition fmgr.h:87
#define CALLED_AS_TRIGGER(fcinfo)
Definition trigger.h:26

References CALLED_AS_EVENT_TRIGGER, CALLED_AS_TRIGGER, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_oid, PLPY_EVENT_TRIGGER, PLPY_NOT_TRIGGER, PLPY_TRIGGER, and PLy_procedure_create().

Referenced by PLy_procedure_get().

◆ PLy_delete_callback()

static void PLy_delete_callback ( CachedFunction cfunc)
static

Definition at line 510 of file plpy_procedure.c.

511{
512 PLyProcedure *proc = (PLyProcedure *) cfunc;
513
514 Assert(proc->cfunc.use_count == 0);
515 Assert(proc->calldepth == 0);
516
518}
#define Assert(condition)
Definition c.h:999
void PLy_procedure_delete(PLyProcedure *proc)
uint64 use_count
Definition funccache.h:117
CachedFunction cfunc

References Assert, PLyProcedure::calldepth, PLyProcedure::cfunc, PLy_procedure_delete(), and CachedFunction::use_count.

Referenced by PLy_procedure_get().

◆ PLy_procedure_compile()

void PLy_procedure_compile ( PLyProcedure proc,
const char src 
)

Definition at line 362 of file plpy_procedure.c.

363{
364 PyObject *crv = NULL;
365 char *msrc;
367
369
370 /*
371 * SD is private preserved data between calls. GD is global data shared by
372 * all functions
373 */
374 proc->statics = PyDict_New();
375 if (!proc->statics)
377 PyDict_SetItemString(proc->globals, "SD", proc->statics);
378
379 /*
380 * insert the function code into the interpreter
381 */
383 /* Save the mangled source for later inclusion in tracebacks */
384 proc->src = MemoryContextStrdup(proc->mcxt, msrc);
386 if (code0)
388 pfree(msrc);
389
390 if (crv != NULL)
391 {
392 int clen;
393 char call[NAMEDATALEN + 256];
394
395 Py_DECREF(crv);
396
397 /*
398 * compile a call to the function
399 */
400 clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
401 if (clen < 0 || clen >= sizeof(call))
402 elog(ERROR, "string would overflow buffer");
403 proc->code = Py_CompileString(call, "<string>", Py_eval_input);
404 if (proc->code != NULL)
405 return;
406 }
407
408 if (proc->proname)
409 PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
410 proc->proname);
411 else
412 PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
413}
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define PLy_elog
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition mcxt.c:1897
void pfree(void *pointer)
Definition mcxt.c:1619
#define NAMEDATALEN
PyObject * PLy_interp_globals
Definition plpy_main.c:46
static char * PLy_procedure_munge_source(const char *name, const char *src)
#define snprintf
Definition port.h:261
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 void PLy_procedure_create ( PLyProcedure proc,
HeapTuple  procTup,
Oid  fn_oid,
PLyTrigType  is_trigger 
)
static

Definition at line 145 of file plpy_procedure.c.

149{
150 char procName[NAMEDATALEN + 256];
152 MemoryContext cxt;
154 int rv;
155 char *ptr;
156
158 rv = snprintf(procName, sizeof(procName),
159 "__plpython_procedure_%s_%u",
160 NameStr(procStruct->proname),
161 fn_oid);
162 if (rv >= sizeof(procName) || rv < 0)
163 elog(ERROR, "procedure name would overrun buffer");
164
165 /* Replace any not-legal-in-Python-names characters with '_' */
166 for (ptr = procName; *ptr; ptr++)
167 {
168 if (!((*ptr >= 'A' && *ptr <= 'Z') ||
169 (*ptr >= 'a' && *ptr <= 'z') ||
170 (*ptr >= '0' && *ptr <= '9')))
171 *ptr = '_';
172 }
173
174 /* Create long-lived context that all procedure info will live in */
176 "PL/Python function",
178
180
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);
194 proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
195 proc->is_setof = procStruct->proretset;
196 proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
197 proc->is_trigger = is_trigger;
198 proc->src = NULL;
199 proc->argnames = NULL;
200 proc->args = NULL;
201 proc->nargs = 0;
202 proc->langid = procStruct->prolang;
205 &isnull);
207 proc->code = NULL;
208 proc->statics = NULL;
209 proc->globals = NULL;
210 proc->calldepth = 0;
211 proc->argstack = NULL;
212
213 /*
214 * get information required for output conversion of the return value,
215 * but only if this isn't a trigger.
216 */
217 if (is_trigger == PLPY_NOT_TRIGGER)
218 {
219 Oid rettype = procStruct->prorettype;
222
225 elog(ERROR, "cache lookup failed for type %u", rettype);
227
228 /* Disallow pseudotype result, except for void or record */
229 if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
230 {
231 if (rettype == VOIDOID ||
232 rettype == RECORDOID)
233 /* okay */ ;
234 else if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
237 errmsg("trigger functions can only be called as triggers")));
238 else
241 errmsg("PL/Python functions cannot return type %s",
242 format_type_be(rettype))));
243 }
244
245 /* set up output function for procedure result */
246 PLy_output_setup_func(&proc->result, proc->mcxt,
247 rettype, -1, proc);
248
250 }
251 else
252 {
253 /*
254 * In a trigger function, we use proc->result and proc->result_in
255 * for converting tuples, but we don't yet have enough info to set
256 * them up. PLy_exec_trigger will deal with it.
257 */
258 proc->result.typoid = InvalidOid;
260 }
261
262 /*
263 * Now get information required for input conversion of the
264 * procedure's arguments. Note that we ignore output arguments here.
265 * If the function returns record, those I/O functions will be set up
266 * when the function is first called.
267 */
268 if (procStruct->pronargs)
269 {
270 Oid *types;
271 char **names,
272 *modes;
273 int pos,
274 total;
275
276 /* extract argument type info from the pg_proc tuple */
277 total = get_func_arg_info(procTup, &types, &names, &modes);
278
279 /* count number of in+inout args into proc->nargs */
280 if (modes == NULL)
281 proc->nargs = total;
282 else
283 {
284 /* proc->nargs was initialized to 0 above */
285 for (i = 0; i < total; i++)
286 {
287 if (modes[i] != PROARGMODE_OUT &&
289 (proc->nargs)++;
290 }
291 }
292
293 /* Allocate arrays for per-input-argument data */
294 proc->argnames = (char **) palloc0_array(char *, proc->nargs);
296
297 for (i = pos = 0; i < total; i++)
298 {
301
302 if (modes &&
303 (modes[i] == PROARGMODE_OUT ||
305 continue; /* skip OUT arguments */
306
307 Assert(types[i] == procStruct->proargtypes.values[pos]);
308
312 elog(ERROR, "cache lookup failed for type %u", types[i]);
314
315 /* disallow pseudotype arguments */
316 if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
319 errmsg("PL/Python functions cannot accept type %s",
321
322 /* set up I/O function info */
323 PLy_input_setup_func(&proc->args[pos], proc->mcxt,
324 types[i], -1, /* typmod not known */
325 proc);
326
327 /* get argument name */
328 proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
329
331
332 pos++;
333 }
334 }
335
336 /*
337 * get the text of the function.
338 */
342
344
346 }
347 PG_CATCH();
348 {
351 PG_RE_THROW();
352 }
353 PG_END_TRY();
354
356}
#define TextDatumGetCString(d)
Definition builtins.h:99
#define NameStr(name)
Definition c.h:891
struct typedefs * types
Definition ecpg.c:30
int errcode(int sqlerrcode)
Definition elog.c:875
#define PG_RE_THROW()
Definition elog.h:407
#define PG_TRY(...)
Definition elog.h:374
#define PG_END_TRY(...)
Definition elog.h:399
#define PG_CATCH(...)
Definition elog.h:384
#define ereport(elevel,...)
Definition elog.h:152
#define palloc0_array(type, count)
Definition fe_memutils.h:92
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:1382
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
int i
Definition isn.c:77
char * pstrdup(const char *in)
Definition mcxt.c:1910
MemoryContext TopMemoryContext
Definition mcxt.c:167
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition mcxt.c:664
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
#define NIL
Definition pg_list.h:68
List * oid_array_to_list(Datum datum)
Definition pg_proc.c:1230
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265
void PLy_procedure_compile(PLyProcedure *proc, const char *src)
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:252
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
PLyDatumToOb * args
PLyTrigType is_trigger
PLyObToDatum result
PLyDatumToOb result_in
PLySavedArgs * argstack
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596

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, Form_pg_proc, Form_pg_type, format_type_be(), get_func_arg_info(), GETSTRUCT(), PLyProcedure::globals, 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, 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_compile_callback().

◆ PLy_procedure_delete()

void PLy_procedure_delete ( PLyProcedure proc)

Definition at line 416 of file plpy_procedure.c.

417{
418 Py_XDECREF(proc->code);
419 Py_XDECREF(proc->statics);
420 Py_XDECREF(proc->globals);
422}
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:475

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

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

◆ PLy_procedure_get()

PLyProcedureCache * PLy_procedure_get ( FunctionCallInfo  fcinfo,
bool  forValidator 
)

Definition at line 62 of file plpy_procedure.c.

63{
64 FmgrInfo *finfo = fcinfo->flinfo;
66 PLyProcedure *proc;
67
68 /*
69 * If this is the first execution for this FmgrInfo, set up a cache struct
70 * (initially containing null pointers). The cache must live as long as
71 * the FmgrInfo, so it goes in fn_mcxt. Also set up a memory context
72 * callback that will be invoked when fn_mcxt is reset/deleted.
73 */
74 pcache = finfo->fn_extra;
75 if (pcache == NULL)
76 {
79
80 pcache->fcontext = finfo->fn_mcxt;
82 pcache->mcb.arg = pcache;
83
85
86 finfo->fn_extra = pcache;
87 }
88
89 /*
90 * If we are resuming execution of a set-returning function, just keep
91 * using the same cache. We do not ask funccache.c to re-validate the
92 * PLyProcedure: we want to run to completion using the function's initial
93 * definition.
94 *
95 * A live iterator (srfstate->iter != NULL) reliably means a genuine
96 * resume: when an iteration ends for any reason, srfstate->iter is reset
97 * to NULL (see comments for PLy_function_cleanup_srfstate).
98 */
99 if (pcache->srfstate != NULL && pcache->srfstate->iter != NULL)
100 {
101 Assert(pcache->proc != NULL);
102 return pcache;
103 }
104
105 /*
106 * Look up, or re-validate, the long-lived hash entry. Like SQL-language
107 * functions, make the hash key depend on the result of
108 * get_call_result_type() when that's composite, so that we can safely
109 * assume that we'll build a new hash entry if the composite rowtype
110 * changes.
111 */
112 proc = (PLyProcedure *)
114 (CachedFunction *) pcache->proc,
117 sizeof(PLyProcedure),
118 true,
120
121 /*
122 * Install the hash pointer in the PLyProcedureCache, and increment its
123 * use count to reflect that. If cached_function_compile gave us back a
124 * different hash entry than we were using before, we must decrement that
125 * one's use count.
126 */
127 if (proc != pcache->proc)
128 {
129 if (pcache->proc != NULL)
130 {
131 Assert(pcache->proc->cfunc.use_count > 0);
132 pcache->proc->cfunc.use_count--;
133 }
134 pcache->proc = proc;
135 proc->cfunc.use_count++;
136 }
137
138 return pcache;
139}
CachedFunction * cached_function_compile(FunctionCallInfo fcinfo, CachedFunction *function, CachedFunctionCompileCallback ccallback, CachedFunctionDeleteCallback dcallback, Size cacheEntrySize, bool includeResultType, bool forValidator)
Definition funccache.c:480
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1269
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition mcxt.c:585
static void PLy_compile_callback(FunctionCallInfo fcinfo, HeapTuple procTup, const CachedFunctionHashKey *hashkey, CachedFunction *cfunc, bool forValidator)
static void PLy_delete_callback(CachedFunction *cfunc)
static void RemovePLyProcedureCache(void *arg)
void * fn_extra
Definition fmgr.h:64
MemoryContext fn_mcxt
Definition fmgr.h:65

References Assert, cached_function_compile(), PLyProcedure::cfunc, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, MemoryContextAllocZero(), MemoryContextRegisterResetCallback(), PLy_compile_callback(), PLy_delete_callback(), RemovePLyProcedureCache(), and CachedFunction::use_count.

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 425 of file plpy_procedure.c.

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

44{
45 if (proc == NULL)
46 return "<unknown procedure>";
47 return proc->proname;
48}

References fb(), and PLyProcedure::proname.

Referenced by plpython_error_callback(), and PLy_traceback().

◆ RemovePLyProcedureCache()

static void RemovePLyProcedureCache ( void arg)
static

Definition at line 536 of file plpy_procedure.c.

537{
539
540 /* Release any Python state left behind by an interrupted SRF */
542
543 /* Release reference count on PLyProcedure */
544 if (pcache->proc != NULL)
545 {
546 Assert(pcache->proc->cfunc.use_count > 0);
547 pcache->proc->cfunc.use_count--;
548 pcache->proc = NULL;
549 }
550
551 /* We needn't free the pcache object itself, context cleanup does that */
552}
Datum arg
Definition elog.c:1323
void PLy_function_cleanup_srfstate(PLyProcedureCache *pcache)
Definition plpy_exec.c:357

References arg, Assert, fb(), and PLy_function_cleanup_srfstate().

Referenced by PLy_procedure_get().