Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * Python procedure manipulation for plpython
3 : : *
4 : : * src/pl/plpython/plpy_procedure.c
5 : : */
6 : :
7 : : #include "postgres.h"
8 : :
9 : : #include "catalog/pg_proc.h"
10 : : #include "catalog/pg_type.h"
11 : : #include "commands/event_trigger.h"
12 : : #include "commands/trigger.h"
13 : : #include "funcapi.h"
14 : : #include "plpy_elog.h"
15 : : #include "plpy_exec.h"
16 : : #include "plpy_main.h"
17 : : #include "plpy_procedure.h"
18 : : #include "plpy_util.h"
19 : : #include "utils/builtins.h"
20 : : #include "utils/funccache.h"
21 : : #include "utils/syscache.h"
22 : :
23 : : static void PLy_procedure_create(PLyProcedure *proc,
24 : : HeapTuple procTup,
25 : : Oid fn_oid,
26 : : PLyTrigType is_trigger);
27 : : static char *PLy_procedure_munge_source(const char *name, const char *src);
28 : : static void PLy_compile_callback(FunctionCallInfo fcinfo,
29 : : HeapTuple procTup,
30 : : const CachedFunctionHashKey *hashkey,
31 : : CachedFunction *cfunc,
32 : : bool forValidator);
33 : : static void PLy_delete_callback(CachedFunction *cfunc);
34 : : static void RemovePLyProcedureCache(void *arg);
35 : :
36 : :
37 : : /*
38 : : * PLy_procedure_name: get the name of the specified procedure.
39 : : *
40 : : * NB: this returns the SQL name, not the internal Python procedure name
41 : : */
42 : : char *
5436 peter_e@gmx.net 43 :CBC 552 : PLy_procedure_name(PLyProcedure *proc)
44 : : {
45 [ - + ]: 552 : if (proc == NULL)
5436 peter_e@gmx.net 46 :UBC 0 : return "<unknown procedure>";
5436 peter_e@gmx.net 47 :CBC 552 : return proc->proname;
48 : : }
49 : :
50 : : /*
51 : : * PLy_procedure_get: returns a PLyProcedureCache struct for the function,
52 : : * making it valid if necessary.
53 : : *
54 : : * The PLyProcedureCache contains a pointer to the long-lived PLyProcedure
55 : : * (managed by funccache.c) and execution-specific state like SRF state.
56 : : *
57 : : * For SRFs, if we are resuming execution (srfstate->iter != NULL), we skip
58 : : * revalidation and continue using the same PLyProcedure to ensure consistent
59 : : * behavior throughout the SRF execution.
60 : : */
61 : : PLyProcedureCache *
137 tgl@sss.pgh.pa.us 62 : 1000 : PLy_procedure_get(FunctionCallInfo fcinfo, bool forValidator)
63 : : {
64 : 1000 : FmgrInfo *finfo = fcinfo->flinfo;
65 : : PLyProcedureCache *pcache;
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 : 1000 : pcache = finfo->fn_extra;
75 [ + + ]: 1000 : if (pcache == NULL)
76 : : {
77 : : pcache = (PLyProcedureCache *)
78 : 805 : MemoryContextAllocZero(finfo->fn_mcxt, sizeof(PLyProcedureCache));
79 : :
80 : 805 : pcache->fcontext = finfo->fn_mcxt;
81 : 805 : pcache->mcb.func = RemovePLyProcedureCache;
82 : 805 : pcache->mcb.arg = pcache;
83 : :
84 : 805 : MemoryContextRegisterResetCallback(finfo->fn_mcxt, &pcache->mcb);
85 : :
86 : 805 : 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 [ + + + - ]: 1000 : if (pcache->srfstate != NULL && pcache->srfstate->iter != NULL)
100 : : {
101 [ - + ]: 156 : Assert(pcache->proc != NULL);
102 : 156 : 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 *)
113 : 844 : cached_function_compile(fcinfo,
114 : 844 : (CachedFunction *) pcache->proc,
115 : : PLy_compile_callback,
116 : : PLy_delete_callback,
117 : : sizeof(PLyProcedure),
118 : : true,
119 : : forValidator);
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 [ + + ]: 840 : if (proc != pcache->proc)
128 : : {
129 [ - + ]: 801 : if (pcache->proc != NULL)
130 : : {
137 tgl@sss.pgh.pa.us 131 [ # # ]:UBC 0 : Assert(pcache->proc->cfunc.use_count > 0);
132 : 0 : pcache->proc->cfunc.use_count--;
133 : : }
137 tgl@sss.pgh.pa.us 134 :CBC 801 : pcache->proc = proc;
135 : 801 : proc->cfunc.use_count++;
136 : : }
137 : :
138 : 840 : return pcache;
139 : : }
140 : :
141 : : /*
142 : : * Create (well, fill in) a new PLyProcedure structure
143 : : */
144 : : static void
145 : 378 : PLy_procedure_create(PLyProcedure *proc,
146 : : HeapTuple procTup,
147 : : Oid fn_oid,
148 : : PLyTrigType is_trigger)
149 : : {
150 : : char procName[NAMEDATALEN + 256];
151 : : Form_pg_proc procStruct;
152 : : MemoryContext cxt;
153 : : MemoryContext oldcxt;
154 : : int rv;
155 : : char *ptr;
156 : :
5436 peter_e@gmx.net 157 : 378 : procStruct = (Form_pg_proc) GETSTRUCT(procTup);
158 : 756 : rv = snprintf(procName, sizeof(procName),
159 : : "__plpython_procedure_%s_%u",
160 : 378 : NameStr(procStruct->proname),
161 : : fn_oid);
162 [ + - - + ]: 378 : if (rv >= sizeof(procName) || rv < 0)
5436 peter_e@gmx.net 163 [ # # ]:UBC 0 : elog(ERROR, "procedure name would overrun buffer");
164 : :
165 : : /* Replace any not-legal-in-Python-names characters with '_' */
3915 tgl@sss.pgh.pa.us 166 [ + + ]:CBC 17647 : for (ptr = procName; *ptr; ptr++)
167 : : {
168 [ + + + + ]: 17269 : if (!((*ptr >= 'A' && *ptr <= 'Z') ||
169 [ + + - + ]: 17267 : (*ptr >= 'a' && *ptr <= 'z') ||
170 [ + + + + ]: 4642 : (*ptr >= '0' && *ptr <= '9')))
171 : 2627 : *ptr = '_';
172 : : }
173 : :
174 : : /* Create long-lived context that all procedure info will live in */
3145 175 : 378 : cxt = AllocSetContextCreate(TopMemoryContext,
176 : : "PL/Python function",
177 : : ALLOCSET_DEFAULT_SIZES);
178 : :
4018 179 : 378 : oldcxt = MemoryContextSwitchTo(cxt);
180 : :
181 : 378 : proc->mcxt = cxt;
182 : :
5436 peter_e@gmx.net 183 [ + + ]: 378 : PG_TRY();
184 : : {
185 : : Datum protrftypes_datum;
186 : : Datum prosrcdatum;
187 : : bool isnull;
188 : : char *procSource;
189 : : int i;
190 : :
4018 tgl@sss.pgh.pa.us 191 : 378 : proc->proname = pstrdup(NameStr(procStruct->proname));
3145 192 : 378 : MemoryContextSetIdentifier(cxt, proc->proname);
4018 193 : 378 : proc->pyname = pstrdup(procName);
3866 194 : 378 : proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
195 : 378 : proc->is_setof = procStruct->proretset;
3170 peter_e@gmx.net 196 : 378 : proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
912 tgl@sss.pgh.pa.us 197 : 378 : proc->is_trigger = is_trigger;
3866 198 : 378 : proc->src = NULL;
199 : 378 : proc->argnames = NULL;
3276 200 : 378 : proc->args = NULL;
4018 201 : 378 : proc->nargs = 0;
202 : 378 : proc->langid = procStruct->prolang;
203 : 378 : protrftypes_datum = SysCacheGetAttr(PROCOID, procTup,
204 : : Anum_pg_proc_protrftypes,
205 : : &isnull);
206 [ + + ]: 378 : proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum);
3866 207 : 378 : proc->code = NULL;
208 : 378 : proc->statics = NULL;
4018 209 : 378 : proc->globals = NULL;
3866 210 : 378 : proc->calldepth = 0;
211 : 378 : 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 : : */
441 peter@eisentraut.org 217 [ + + ]: 378 : if (is_trigger == PLPY_NOT_TRIGGER)
218 : : {
3276 tgl@sss.pgh.pa.us 219 : 324 : Oid rettype = procStruct->prorettype;
220 : :
221 : : /* reject if function is in fact a trigger function */
4 tgl@sss.pgh.pa.us 222 [ + + - + ]:GNC 324 : if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
223 [ + - ]: 1 : ereport(ERROR,
224 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
225 : : errmsg("trigger functions can only be called as triggers")));
226 : :
227 : : /* set up output function for procedure result */
3276 tgl@sss.pgh.pa.us 228 :CBC 323 : PLy_output_setup_func(&proc->result, proc->mcxt,
229 : : rettype, -1, proc);
230 : : }
231 : : else
232 : : {
233 : : /*
234 : : * In a trigger function, we use proc->result and proc->result_in
235 : : * for converting tuples, but we don't yet have enough info to set
236 : : * them up. PLy_exec_trigger will deal with it.
237 : : */
238 : 54 : proc->result.typoid = InvalidOid;
239 : 54 : proc->result_in.typoid = InvalidOid;
240 : : }
241 : :
242 : : /*
243 : : * Now get information required for input conversion of the
244 : : * procedure's arguments. Note that we ignore output arguments here.
245 : : * If the function returns record, those I/O functions will be set up
246 : : * when the function is first called.
247 : : */
5436 peter_e@gmx.net 248 [ + + ]: 377 : if (procStruct->pronargs)
249 : : {
250 : : Oid *types;
251 : : char **names,
252 : : *modes;
253 : : int pos,
254 : : total;
255 : :
256 : : /* extract argument type info from the pg_proc tuple */
257 : 170 : total = get_func_arg_info(procTup, &types, &names, &modes);
258 : :
259 : : /* count number of in+inout args into proc->nargs */
260 [ + + ]: 170 : if (modes == NULL)
261 : 146 : proc->nargs = total;
262 : : else
263 : : {
264 : : /* proc->nargs was initialized to 0 above */
265 [ + + ]: 88 : for (i = 0; i < total; i++)
266 : : {
1974 tgl@sss.pgh.pa.us 267 [ + + ]: 64 : if (modes[i] != PROARGMODE_OUT &&
5436 peter_e@gmx.net 268 [ + - ]: 38 : modes[i] != PROARGMODE_TABLE)
269 : 38 : (proc->nargs)++;
270 : : }
271 : : }
272 : :
273 : : /* Allocate arrays for per-input-argument data */
80 michael@paquier.xyz 274 :GNC 170 : proc->argnames = palloc0_array(char *, proc->nargs);
275 : 170 : proc->args = palloc0_array(PLyDatumToOb, proc->nargs);
276 : :
5436 peter_e@gmx.net 277 [ + + ]:CBC 455 : for (i = pos = 0; i < total; i++)
278 : : {
279 [ + + ]: 285 : if (modes &&
1974 tgl@sss.pgh.pa.us 280 [ + + ]: 64 : (modes[i] == PROARGMODE_OUT ||
5436 peter_e@gmx.net 281 [ - + ]: 38 : modes[i] == PROARGMODE_TABLE))
282 : 26 : continue; /* skip OUT arguments */
283 : :
284 [ - + ]: 259 : Assert(types[i] == procStruct->proargtypes.values[pos]);
285 : :
286 : : /* set up I/O function info */
3276 tgl@sss.pgh.pa.us 287 : 259 : PLy_input_setup_func(&proc->args[pos], proc->mcxt,
288 : 259 : types[i], -1, /* typmod not known */
289 : : proc);
290 : :
291 : : /* get argument name */
4018 292 [ + + ]: 259 : proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
293 : :
5436 peter_e@gmx.net 294 : 259 : pos++;
295 : : }
296 : : }
297 : :
298 : : /*
299 : : * get the text of the function.
300 : : */
1321 dgustafsson@postgres 301 : 377 : prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup,
302 : : Anum_pg_proc_prosrc);
5436 peter_e@gmx.net 303 : 377 : procSource = TextDatumGetCString(prosrcdatum);
304 : :
305 : 377 : PLy_procedure_compile(proc, procSource);
306 : :
307 : 374 : pfree(procSource);
308 : : }
309 : 4 : PG_CATCH();
310 : : {
4018 tgl@sss.pgh.pa.us 311 : 4 : MemoryContextSwitchTo(oldcxt);
5436 peter_e@gmx.net 312 : 4 : PLy_procedure_delete(proc);
313 : 4 : PG_RE_THROW();
314 : : }
315 [ - + ]: 374 : PG_END_TRY();
316 : :
4018 tgl@sss.pgh.pa.us 317 : 374 : MemoryContextSwitchTo(oldcxt);
5436 peter_e@gmx.net 318 : 374 : }
319 : :
320 : : /*
321 : : * Insert the procedure into the Python interpreter
322 : : */
323 : : void
324 : 398 : PLy_procedure_compile(PLyProcedure *proc, const char *src)
325 : : {
326 : 398 : PyObject *crv = NULL;
327 : : char *msrc;
328 : : PyObject *code0;
329 : :
330 : 398 : proc->globals = PyDict_Copy(PLy_interp_globals);
331 : :
332 : : /*
333 : : * SD is private preserved data between calls. GD is global data shared by
334 : : * all functions
335 : : */
336 : 398 : proc->statics = PyDict_New();
3292 337 [ - + ]: 398 : if (!proc->statics)
3292 peter_e@gmx.net 338 :UBC 0 : PLy_elog(ERROR, NULL);
5436 peter_e@gmx.net 339 :CBC 398 : PyDict_SetItemString(proc->globals, "SD", proc->statics);
340 : :
341 : : /*
342 : : * insert the function code into the interpreter
343 : : */
344 : 398 : msrc = PLy_procedure_munge_source(proc->pyname, src);
345 : : /* Save the mangled source for later inclusion in tracebacks */
4018 tgl@sss.pgh.pa.us 346 : 398 : proc->src = MemoryContextStrdup(proc->mcxt, msrc);
603 peter@eisentraut.org 347 : 398 : code0 = Py_CompileString(msrc, "<string>", Py_file_input);
348 [ + + ]: 398 : if (code0)
349 : 395 : crv = PyEval_EvalCode(code0, proc->globals, NULL);
5436 peter_e@gmx.net 350 : 398 : pfree(msrc);
351 : :
352 [ + + ]: 398 : if (crv != NULL)
353 : : {
354 : : int clen;
355 : : char call[NAMEDATALEN + 256];
356 : :
357 : : Py_DECREF(crv);
358 : :
359 : : /*
360 : : * compile a call to the function
361 : : */
362 : 395 : clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
363 [ + - - + ]: 395 : if (clen < 0 || clen >= sizeof(call))
5436 peter_e@gmx.net 364 [ # # ]:UBC 0 : elog(ERROR, "string would overflow buffer");
5436 peter_e@gmx.net 365 :CBC 395 : proc->code = Py_CompileString(call, "<string>", Py_eval_input);
366 [ + - ]: 395 : if (proc->code != NULL)
367 : 395 : return;
368 : : }
369 : :
370 [ + - ]: 3 : if (proc->proname)
371 : 3 : PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
372 : : proc->proname);
373 : : else
5436 peter_e@gmx.net 374 :UBC 0 : PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
375 : : }
376 : :
377 : : void
5436 peter_e@gmx.net 378 :CBC 30 : PLy_procedure_delete(PLyProcedure *proc)
379 : : {
380 : 30 : Py_XDECREF(proc->code);
381 : 30 : Py_XDECREF(proc->statics);
382 : 30 : Py_XDECREF(proc->globals);
4018 tgl@sss.pgh.pa.us 383 : 30 : MemoryContextDelete(proc->mcxt);
5436 peter_e@gmx.net 384 : 30 : }
385 : :
386 : : static char *
387 : 398 : PLy_procedure_munge_source(const char *name, const char *src)
388 : : {
389 : : char *mrc,
390 : : *mp;
391 : : const char *sp;
392 : : size_t mlen;
393 : : int plen;
394 : :
395 : : /*
396 : : * room for function source and the def statement
397 : : */
398 : 398 : mlen = (strlen(src) * 2) + strlen(name) + 16;
399 : :
400 : 398 : mrc = palloc(mlen);
401 : 398 : plen = snprintf(mrc, mlen, "def %s():\n\t", name);
402 [ + - - + ]: 398 : Assert(plen >= 0 && plen < mlen);
403 : :
404 : 398 : sp = src;
405 : 398 : mp = mrc + plen;
406 : :
407 [ + + ]: 44773 : while (*sp != '\0')
408 : : {
409 [ + + + + ]: 44375 : if (*sp == '\r' && *(sp + 1) == '\n')
410 : 3 : sp++;
411 : :
412 [ + + + + ]: 44375 : if (*sp == '\n' || *sp == '\r')
413 : : {
414 : 1893 : *mp++ = '\n';
415 : 1893 : *mp++ = '\t';
416 : 1893 : sp++;
417 : : }
418 : : else
419 : 42482 : *mp++ = *sp++;
420 : : }
421 : 398 : *mp++ = '\n';
422 : 398 : *mp++ = '\n';
423 : 398 : *mp = '\0';
424 : :
425 [ - + ]: 398 : if (mp > (mrc + mlen))
2649 michael@paquier.xyz 426 [ # # ]:UBC 0 : elog(FATAL, "buffer overrun in PLy_procedure_munge_source");
427 : :
5436 peter_e@gmx.net 428 :CBC 398 : return mrc;
429 : : }
430 : :
431 : : /*
432 : : * Compile callback for funccache.c.
433 : : *
434 : : * cached_function_compile() calls this when it needs to (re)compile the
435 : : * long-lived PLyProcedure for a function. The CachedFunction handed to us is
436 : : * pre-zeroed workspace of size sizeof(PLyProcedure); we just have to fill in
437 : : * the PL/Python-specific fields.
438 : : */
439 : : static void
137 tgl@sss.pgh.pa.us 440 : 378 : PLy_compile_callback(FunctionCallInfo fcinfo,
441 : : HeapTuple procTup,
442 : : const CachedFunctionHashKey *hashkey,
443 : : CachedFunction *cfunc,
444 : : bool forValidator)
445 : : {
446 : 378 : PLyProcedure *proc = (PLyProcedure *) cfunc;
447 : 378 : Oid fn_oid = fcinfo->flinfo->fn_oid;
448 : : PLyTrigType is_trigger;
449 : :
450 : : /*
451 : : * Derive the trigger type from the call context, matching what
452 : : * plpython3_call_handler dispatches on.
453 : : */
454 [ + + + + ]: 378 : if (CALLED_AS_TRIGGER(fcinfo))
455 : 53 : is_trigger = PLPY_TRIGGER;
456 [ + + + + ]: 325 : else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
457 : 1 : is_trigger = PLPY_EVENT_TRIGGER;
458 : : else
459 : 324 : is_trigger = PLPY_NOT_TRIGGER;
460 : :
461 : 378 : PLy_procedure_create(proc, procTup, fn_oid, is_trigger);
462 : 374 : }
463 : :
464 : : /*
465 : : * Deletion callback for funccache.c.
466 : : *
467 : : * cached_function_compile() calls this when it discards a cache entry, which
468 : : * only happens once the entry's use count has dropped to zero. We must free
469 : : * the subsidiary data but not the CachedFunction struct itself.
470 : : */
471 : : static void
472 : 5 : PLy_delete_callback(CachedFunction *cfunc)
473 : : {
474 : 5 : PLyProcedure *proc = (PLyProcedure *) cfunc;
475 : :
476 [ - + ]: 5 : Assert(proc->cfunc.use_count == 0);
477 [ - + ]: 5 : Assert(proc->calldepth == 0);
478 : :
479 : 5 : PLy_procedure_delete(proc);
480 : 5 : }
481 : :
482 : : /*
483 : : * MemoryContext callback function
484 : : *
485 : : * We register this in the memory context that contains a PLyProcedureCache
486 : : * struct (that is, the FmgrInfo's fn_mcxt). When the memory context is reset
487 : : * or deleted, we release the reference count (if any) that the cache holds on
488 : : * the long-lived hash entry. Note that this will happen even during error
489 : : * aborts.
490 : : *
491 : : * This is also our opportunity to release the Python references held by an
492 : : * interrupted set-returning function. ShutdownPLyFunction() handles that for
493 : : * routine in-query cancellation cases, but it does not run during an error
494 : : * abort; this callback does, so it is the backstop that prevents leaking the
495 : : * SRF's iterator and saved arguments when a query errors out mid-iteration.
496 : : */
497 : : static void
498 : 805 : RemovePLyProcedureCache(void *arg)
499 : : {
500 : 805 : PLyProcedureCache *pcache = (PLyProcedureCache *) arg;
501 : :
502 : : /* Release any Python state left behind by an interrupted SRF */
503 : 805 : PLy_function_cleanup_srfstate(pcache);
504 : :
505 : : /* Release reference count on PLyProcedure */
506 [ + + ]: 805 : if (pcache->proc != NULL)
507 : : {
508 [ - + ]: 533 : Assert(pcache->proc->cfunc.use_count > 0);
509 : 533 : pcache->proc->cfunc.use_count--;
510 : 533 : pcache->proc = NULL;
511 : : }
512 : :
513 : : /* We needn't free the pcache object itself, context cleanup does that */
514 : 805 : }
|