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 "access/htup_details.h"
10 : : #include "catalog/pg_proc.h"
11 : : #include "catalog/pg_type.h"
12 : : #include "funcapi.h"
13 : : #include "plpy_elog.h"
14 : : #include "plpy_main.h"
15 : : #include "plpy_procedure.h"
16 : : #include "plpy_util.h"
17 : : #include "utils/builtins.h"
18 : : #include "utils/hsearch.h"
19 : : #include "utils/memutils.h"
20 : : #include "utils/syscache.h"
21 : :
22 : : static HTAB *PLy_procedure_cache = NULL;
23 : :
24 : : static PLyProcedure *PLy_procedure_create(HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger);
25 : : static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup);
26 : : static char *PLy_procedure_munge_source(const char *name, const char *src);
27 : :
28 : :
29 : : void
5062 peter_e@gmx.net 30 :CBC 23 : init_procedure_caches(void)
31 : : {
32 : : HASHCTL hash_ctl;
33 : :
4658 tgl@sss.pgh.pa.us 34 : 23 : hash_ctl.keysize = sizeof(PLyProcedureKey);
5062 peter_e@gmx.net 35 : 23 : hash_ctl.entrysize = sizeof(PLyProcedureEntry);
36 : 23 : PLy_procedure_cache = hash_create("PL/Python procedures", 32, &hash_ctl,
37 : : HASH_ELEM | HASH_BLOBS);
38 : 23 : }
39 : :
40 : : /*
41 : : * PLy_procedure_name: get the name of the specified procedure.
42 : : *
43 : : * NB: this returns the SQL name, not the internal Python procedure name
44 : : */
45 : : char *
46 : 531 : PLy_procedure_name(PLyProcedure *proc)
47 : : {
48 [ - + ]: 531 : if (proc == NULL)
5062 peter_e@gmx.net 49 :UBC 0 : return "<unknown procedure>";
5062 peter_e@gmx.net 50 :CBC 531 : return proc->proname;
51 : : }
52 : :
53 : : /*
54 : : * PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and
55 : : * returns a new PLyProcedure.
56 : : *
57 : : * fn_oid is the OID of the function requested
58 : : * fn_rel is InvalidOid or the relation this function triggers on
59 : : * is_trigger denotes whether the function is a trigger function
60 : : *
61 : : * The reason that both fn_rel and is_trigger need to be passed is that when
62 : : * trigger functions get validated we don't know which relation(s) they'll
63 : : * be used with, so no sensible fn_rel can be passed. Also, in that case
64 : : * we can't make a cache entry because we can't construct the right cache key.
65 : : * To forestall leakage of the PLyProcedure in such cases, delete it after
66 : : * construction and return NULL. That's okay because the only caller that
67 : : * would pass that set of values is plpython3_validator, which ignores our
68 : : * result anyway.
69 : : */
70 : : PLyProcedure *
67 peter@eisentraut.org 71 :GNC 951 : PLy_procedure_get(Oid fn_oid, Oid fn_rel, PLyTrigType is_trigger)
72 : : {
73 : : bool use_cache;
74 : : HeapTuple procTup;
75 : : PLyProcedureKey key;
4658 tgl@sss.pgh.pa.us 76 :CBC 951 : PLyProcedureEntry *volatile entry = NULL;
77 : 951 : PLyProcedure *volatile proc = NULL;
78 : 951 : bool found = false;
79 : :
67 peter@eisentraut.org 80 [ + + + + ]:GNC 951 : if (is_trigger == PLPY_TRIGGER && fn_rel == InvalidOid)
81 : 24 : use_cache = false;
82 : : else
83 : 927 : use_cache = true;
84 : :
5062 peter_e@gmx.net 85 :CBC 951 : procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid));
86 [ - + ]: 951 : if (!HeapTupleIsValid(procTup))
5062 peter_e@gmx.net 87 [ # # ]:UBC 0 : 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 : : */
4658 tgl@sss.pgh.pa.us 94 [ + + ]:CBC 951 : if (use_cache)
95 : : {
96 : 927 : key.fn_oid = fn_oid;
97 : 927 : key.fn_rel = fn_rel;
98 : 927 : entry = hash_search(PLy_procedure_cache, &key, HASH_ENTER, &found);
99 : 927 : proc = entry->proc;
100 : : }
101 : :
5062 peter_e@gmx.net 102 [ + + ]: 951 : PG_TRY();
103 : : {
104 [ + + ]: 951 : if (!found)
105 : : {
106 : : /* Haven't found it, create a new procedure */
4658 tgl@sss.pgh.pa.us 107 : 274 : proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
108 [ + + ]: 270 : if (use_cache)
109 : 246 : entry->proc = proc;
110 : : else
111 : : {
112 : : /* Delete the proc, otherwise it's a memory leak */
4 tgl@sss.pgh.pa.us 113 :GNC 24 : PLy_procedure_delete(proc);
114 : 24 : proc = NULL;
115 : : }
116 : : }
4658 tgl@sss.pgh.pa.us 117 [ + + ]:CBC 677 : else if (!PLy_procedure_valid(proc, procTup))
118 : : {
119 : : /* Found it, but it's invalid, free and reuse the cache entry */
3644 120 : 5 : entry->proc = NULL;
121 [ + - ]: 5 : if (proc)
122 : 5 : PLy_procedure_delete(proc);
4658 123 : 5 : proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
124 : 5 : entry->proc = proc;
125 : : }
126 : : /* Found it and it's valid, it's fine to use it */
127 : : }
5062 peter_e@gmx.net 128 : 4 : PG_CATCH();
129 : : {
130 : : /* Do not leave an uninitialized entry in the cache */
4658 tgl@sss.pgh.pa.us 131 [ + - ]: 4 : if (use_cache)
132 : 4 : hash_search(PLy_procedure_cache, &key, HASH_REMOVE, NULL);
5062 peter_e@gmx.net 133 : 4 : PG_RE_THROW();
134 : : }
135 [ - + ]: 947 : PG_END_TRY();
136 : :
137 : 947 : ReleaseSysCache(procTup);
138 : :
4658 tgl@sss.pgh.pa.us 139 : 947 : return proc;
140 : : }
141 : :
142 : : /*
143 : : * Create a new PLyProcedure structure
144 : : */
145 : : static PLyProcedure *
67 peter@eisentraut.org 146 :GNC 279 : PLy_procedure_create(HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger)
147 : : {
148 : : char procName[NAMEDATALEN + 256];
149 : : Form_pg_proc procStruct;
150 : : PLyProcedure *volatile proc;
151 : : MemoryContext cxt;
152 : : MemoryContext oldcxt;
153 : : int rv;
154 : : char *ptr;
155 : :
5062 peter_e@gmx.net 156 :CBC 279 : procStruct = (Form_pg_proc) GETSTRUCT(procTup);
157 : 558 : rv = snprintf(procName, sizeof(procName),
158 : : "__plpython_procedure_%s_%u",
159 : 279 : NameStr(procStruct->proname),
160 : : fn_oid);
161 [ + - - + ]: 279 : if (rv >= sizeof(procName) || rv < 0)
5062 peter_e@gmx.net 162 [ # # ]:UBC 0 : elog(ERROR, "procedure name would overrun buffer");
163 : :
164 : : /* Replace any not-legal-in-Python-names characters with '_' */
3541 tgl@sss.pgh.pa.us 165 [ + + ]:CBC 13067 : for (ptr = procName; *ptr; ptr++)
166 : : {
167 [ + + + + ]: 12788 : if (!((*ptr >= 'A' && *ptr <= 'Z') ||
168 [ + + - + ]: 12787 : (*ptr >= 'a' && *ptr <= 'z') ||
169 [ + + + + ]: 3427 : (*ptr >= '0' && *ptr <= '9')))
170 : 1930 : *ptr = '_';
171 : : }
172 : :
173 : : /* Create long-lived context that all procedure info will live in */
2771 174 : 279 : cxt = AllocSetContextCreate(TopMemoryContext,
175 : : "PL/Python function",
176 : : ALLOCSET_DEFAULT_SIZES);
177 : :
3644 178 : 279 : oldcxt = MemoryContextSwitchTo(cxt);
179 : :
180 : 279 : proc = (PLyProcedure *) palloc0(sizeof(PLyProcedure));
181 : 279 : proc->mcxt = cxt;
182 : :
5062 peter_e@gmx.net 183 [ + + ]: 279 : PG_TRY();
184 : : {
185 : : Datum protrftypes_datum;
186 : : Datum prosrcdatum;
187 : : bool isnull;
188 : : char *procSource;
189 : : int i;
190 : :
3644 tgl@sss.pgh.pa.us 191 : 279 : proc->proname = pstrdup(NameStr(procStruct->proname));
2771 192 : 279 : MemoryContextSetIdentifier(cxt, proc->proname);
3644 193 : 279 : proc->pyname = pstrdup(procName);
194 : 279 : proc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
195 : 279 : proc->fn_tid = procTup->t_self;
3492 196 : 279 : proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
197 : 279 : proc->is_setof = procStruct->proretset;
2796 peter_e@gmx.net 198 : 279 : proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
538 tgl@sss.pgh.pa.us 199 : 279 : proc->is_trigger = is_trigger;
3492 200 : 279 : proc->src = NULL;
201 : 279 : proc->argnames = NULL;
2902 202 : 279 : proc->args = NULL;
3644 203 : 279 : proc->nargs = 0;
204 : 279 : proc->langid = procStruct->prolang;
205 : 279 : protrftypes_datum = SysCacheGetAttr(PROCOID, procTup,
206 : : Anum_pg_proc_protrftypes,
207 : : &isnull);
208 [ + + ]: 279 : proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum);
3492 209 : 279 : proc->code = NULL;
210 : 279 : proc->statics = NULL;
3644 211 : 279 : proc->globals = NULL;
3492 212 : 279 : proc->calldepth = 0;
213 : 279 : 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 : : */
67 peter@eisentraut.org 219 [ + + ]:GNC 279 : if (is_trigger == PLPY_NOT_TRIGGER)
220 : : {
2902 tgl@sss.pgh.pa.us 221 :CBC 228 : Oid rettype = procStruct->prorettype;
222 : : HeapTuple rvTypeTup;
223 : : Form_pg_type rvTypeStruct;
224 : :
225 : 228 : rvTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettype));
5062 peter_e@gmx.net 226 [ - + ]: 228 : if (!HeapTupleIsValid(rvTypeTup))
2902 tgl@sss.pgh.pa.us 227 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", rettype);
5062 peter_e@gmx.net 228 :CBC 228 : rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
229 : :
230 : : /* Disallow pseudotype result, except for void or record */
231 [ + + ]: 228 : if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
232 : : {
2902 tgl@sss.pgh.pa.us 233 [ + + + + ]: 52 : if (rettype == VOIDOID ||
234 : : rettype == RECORDOID)
235 : : /* okay */ ;
1824 236 [ - + - - ]: 1 : else if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
5062 peter_e@gmx.net 237 [ + - ]: 1 : ereport(ERROR,
238 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
239 : : errmsg("trigger functions can only be called as triggers")));
240 : : else
5062 peter_e@gmx.net 241 [ # # ]:UBC 0 : ereport(ERROR,
242 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
243 : : errmsg("PL/Python functions cannot return type %s",
244 : : format_type_be(rettype))));
245 : : }
246 : :
247 : : /* set up output function for procedure result */
2902 tgl@sss.pgh.pa.us 248 :CBC 227 : PLy_output_setup_func(&proc->result, proc->mcxt,
249 : : rettype, -1, proc);
250 : :
5062 peter_e@gmx.net 251 : 227 : ReleaseSysCache(rvTypeTup);
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 : : */
2902 tgl@sss.pgh.pa.us 260 : 51 : proc->result.typoid = InvalidOid;
261 : 51 : proc->result_in.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 : : */
5062 peter_e@gmx.net 270 [ + + ]: 278 : 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 : 107 : total = get_func_arg_info(procTup, &types, &names, &modes);
280 : :
281 : : /* count number of in+inout args into proc->nargs */
282 [ + + ]: 107 : if (modes == NULL)
283 : 96 : proc->nargs = total;
284 : : else
285 : : {
286 : : /* proc->nargs was initialized to 0 above */
287 [ + + ]: 41 : for (i = 0; i < total; i++)
288 : : {
1600 tgl@sss.pgh.pa.us 289 [ + + ]: 30 : if (modes[i] != PROARGMODE_OUT &&
5062 peter_e@gmx.net 290 [ + - ]: 18 : modes[i] != PROARGMODE_TABLE)
291 : 18 : (proc->nargs)++;
292 : : }
293 : : }
294 : :
295 : : /* Allocate arrays for per-input-argument data */
3644 tgl@sss.pgh.pa.us 296 : 107 : proc->argnames = (char **) palloc0(sizeof(char *) * proc->nargs);
2902 297 : 107 : proc->args = (PLyDatumToOb *) palloc0(sizeof(PLyDatumToOb) * proc->nargs);
298 : :
5062 peter_e@gmx.net 299 [ + + ]: 277 : for (i = pos = 0; i < total; i++)
300 : : {
301 : : HeapTuple argTypeTup;
302 : : Form_pg_type argTypeStruct;
303 : :
304 [ + + ]: 170 : if (modes &&
1600 tgl@sss.pgh.pa.us 305 [ + + ]: 30 : (modes[i] == PROARGMODE_OUT ||
5062 peter_e@gmx.net 306 [ - + ]: 18 : modes[i] == PROARGMODE_TABLE))
307 : 12 : continue; /* skip OUT arguments */
308 : :
309 [ - + ]: 158 : Assert(types[i] == procStruct->proargtypes.values[pos]);
310 : :
311 : 158 : argTypeTup = SearchSysCache1(TYPEOID,
312 : 158 : ObjectIdGetDatum(types[i]));
313 [ - + ]: 158 : if (!HeapTupleIsValid(argTypeTup))
5062 peter_e@gmx.net 314 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", types[i]);
5062 peter_e@gmx.net 315 :CBC 158 : argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
316 : :
317 : : /* disallow pseudotype arguments */
2902 tgl@sss.pgh.pa.us 318 [ - + ]: 158 : if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
2902 tgl@sss.pgh.pa.us 319 [ # # ]:UBC 0 : ereport(ERROR,
320 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
321 : : errmsg("PL/Python functions cannot accept type %s",
322 : : format_type_be(types[i]))));
323 : :
324 : : /* set up I/O function info */
2902 tgl@sss.pgh.pa.us 325 :CBC 158 : PLy_input_setup_func(&proc->args[pos], proc->mcxt,
326 : 158 : types[i], -1, /* typmod not known */
327 : : proc);
328 : :
329 : : /* get argument name */
3644 330 [ + + ]: 158 : proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
331 : :
5062 peter_e@gmx.net 332 : 158 : ReleaseSysCache(argTypeTup);
333 : :
334 : 158 : pos++;
335 : : }
336 : : }
337 : :
338 : : /*
339 : : * get the text of the function.
340 : : */
947 dgustafsson@postgres 341 : 278 : prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup,
342 : : Anum_pg_proc_prosrc);
5062 peter_e@gmx.net 343 : 278 : procSource = TextDatumGetCString(prosrcdatum);
344 : :
345 : 278 : PLy_procedure_compile(proc, procSource);
346 : :
347 : 275 : pfree(procSource);
348 : : }
349 : 4 : PG_CATCH();
350 : : {
3644 tgl@sss.pgh.pa.us 351 : 4 : MemoryContextSwitchTo(oldcxt);
5062 peter_e@gmx.net 352 : 4 : PLy_procedure_delete(proc);
353 : 4 : PG_RE_THROW();
354 : : }
355 [ - + ]: 275 : PG_END_TRY();
356 : :
3644 tgl@sss.pgh.pa.us 357 : 275 : MemoryContextSwitchTo(oldcxt);
5062 peter_e@gmx.net 358 : 275 : return proc;
359 : : }
360 : :
361 : : /*
362 : : * Insert the procedure into the Python interpreter
363 : : */
364 : : void
365 : 299 : PLy_procedure_compile(PLyProcedure *proc, const char *src)
366 : : {
367 : 299 : PyObject *crv = NULL;
368 : : char *msrc;
369 : : PyObject *code0;
370 : :
371 : 299 : proc->globals = PyDict_Copy(PLy_interp_globals);
372 : :
373 : : /*
374 : : * SD is private preserved data between calls. GD is global data shared by
375 : : * all functions
376 : : */
377 : 299 : proc->statics = PyDict_New();
2918 378 [ - + ]: 299 : if (!proc->statics)
2918 peter_e@gmx.net 379 :UBC 0 : PLy_elog(ERROR, NULL);
5062 peter_e@gmx.net 380 :CBC 299 : PyDict_SetItemString(proc->globals, "SD", proc->statics);
381 : :
382 : : /*
383 : : * insert the function code into the interpreter
384 : : */
385 : 299 : msrc = PLy_procedure_munge_source(proc->pyname, src);
386 : : /* Save the mangled source for later inclusion in tracebacks */
3644 tgl@sss.pgh.pa.us 387 : 299 : proc->src = MemoryContextStrdup(proc->mcxt, msrc);
229 peter@eisentraut.org 388 : 299 : code0 = Py_CompileString(msrc, "<string>", Py_file_input);
389 [ + + ]: 299 : if (code0)
390 : 296 : crv = PyEval_EvalCode(code0, proc->globals, NULL);
5062 peter_e@gmx.net 391 : 299 : pfree(msrc);
392 : :
393 [ + + ]: 299 : 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 : 296 : clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
404 [ + - - + ]: 296 : if (clen < 0 || clen >= sizeof(call))
5062 peter_e@gmx.net 405 [ # # ]:UBC 0 : elog(ERROR, "string would overflow buffer");
5062 peter_e@gmx.net 406 :CBC 296 : proc->code = Py_CompileString(call, "<string>", Py_eval_input);
407 [ + - ]: 296 : if (proc->code != NULL)
408 : 296 : return;
409 : : }
410 : :
411 [ + - ]: 3 : if (proc->proname)
412 : 3 : PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
413 : : proc->proname);
414 : : else
5062 peter_e@gmx.net 415 :UBC 0 : PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
416 : : }
417 : :
418 : : void
5062 peter_e@gmx.net 419 :CBC 54 : PLy_procedure_delete(PLyProcedure *proc)
420 : : {
421 : 54 : Py_XDECREF(proc->code);
422 : 54 : Py_XDECREF(proc->statics);
423 : 54 : Py_XDECREF(proc->globals);
3644 tgl@sss.pgh.pa.us 424 : 54 : MemoryContextDelete(proc->mcxt);
5062 peter_e@gmx.net 425 : 54 : }
426 : :
427 : : /*
428 : : * Decide whether a cached PLyProcedure struct is still valid
429 : : */
430 : : static bool
431 : 677 : PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
432 : : {
3644 tgl@sss.pgh.pa.us 433 [ - + ]: 677 : if (proc == NULL)
3644 tgl@sss.pgh.pa.us 434 :UBC 0 : return false;
435 : :
436 : : /* If the pg_proc tuple has changed, it's not valid */
4327 rhaas@postgresql.org 437 [ + + - + ]:CBC 1349 : if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
5062 peter_e@gmx.net 438 : 672 : ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
439 : 5 : return false;
440 : :
2902 tgl@sss.pgh.pa.us 441 : 672 : return true;
442 : : }
443 : :
444 : : static char *
5062 peter_e@gmx.net 445 : 299 : PLy_procedure_munge_source(const char *name, const char *src)
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 : 299 : mlen = (strlen(src) * 2) + strlen(name) + 16;
457 : :
458 : 299 : mrc = palloc(mlen);
459 : 299 : plen = snprintf(mrc, mlen, "def %s():\n\t", name);
460 [ + - - + ]: 299 : Assert(plen >= 0 && plen < mlen);
461 : :
462 : 299 : sp = src;
463 : 299 : mp = mrc + plen;
464 : :
465 [ + + ]: 32181 : while (*sp != '\0')
466 : : {
467 [ + + + + ]: 31882 : if (*sp == '\r' && *(sp + 1) == '\n')
468 : 3 : sp++;
469 : :
470 [ + + + + ]: 31882 : if (*sp == '\n' || *sp == '\r')
471 : : {
472 : 1346 : *mp++ = '\n';
473 : 1346 : *mp++ = '\t';
474 : 1346 : sp++;
475 : : }
476 : : else
477 : 30536 : *mp++ = *sp++;
478 : : }
479 : 299 : *mp++ = '\n';
480 : 299 : *mp++ = '\n';
481 : 299 : *mp = '\0';
482 : :
483 [ - + ]: 299 : if (mp > (mrc + mlen))
2275 michael@paquier.xyz 484 [ # # ]:UBC 0 : elog(FATAL, "buffer overrun in PLy_procedure_munge_source");
485 : :
5062 peter_e@gmx.net 486 :CBC 299 : return mrc;
487 : : }
|