Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
plpy_procedure.c
Go to the documentation of this file.
1/*
2 * Python procedure manipulation for plpython
3 *
4 * src/pl/plpython/plpy_procedure.c
5 */
6
7#include "postgres.h"
8
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
23
24static PLyProcedure *PLy_procedure_create(HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger);
25static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup);
26static char *PLy_procedure_munge_source(const char *name, const char *src);
27
28
29void
31{
32 HASHCTL hash_ctl;
33
34 hash_ctl.keysize = sizeof(PLyProcedureKey);
35 hash_ctl.entrysize = sizeof(PLyProcedureEntry);
36 PLy_procedure_cache = hash_create("PL/Python procedures", 32, &hash_ctl,
38}
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 */
45char *
47{
48 if (proc == NULL)
49 return "<unknown procedure>";
50 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.
64 */
66PLy_procedure_get(Oid fn_oid, Oid fn_rel, PLyTrigType is_trigger)
67{
68 bool use_cache;
69 HeapTuple procTup;
71 PLyProcedureEntry *volatile entry = NULL;
72 PLyProcedure *volatile proc = NULL;
73 bool found = false;
74
75 if (is_trigger == PLPY_TRIGGER && fn_rel == InvalidOid)
76 use_cache = false;
77 else
78 use_cache = true;
79
80 procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid));
81 if (!HeapTupleIsValid(procTup))
82 elog(ERROR, "cache lookup failed for function %u", fn_oid);
83
84 /*
85 * Look for the function in the cache, unless we don't have the necessary
86 * information (e.g. during validation). In that case we just don't cache
87 * anything.
88 */
89 if (use_cache)
90 {
91 key.fn_oid = fn_oid;
92 key.fn_rel = fn_rel;
94 proc = entry->proc;
95 }
96
97 PG_TRY();
98 {
99 if (!found)
100 {
101 /* Haven't found it, create a new procedure */
102 proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
103 if (use_cache)
104 entry->proc = proc;
105 }
106 else if (!PLy_procedure_valid(proc, procTup))
107 {
108 /* Found it, but it's invalid, free and reuse the cache entry */
109 entry->proc = NULL;
110 if (proc)
112 proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
113 entry->proc = proc;
114 }
115 /* Found it and it's valid, it's fine to use it */
116 }
117 PG_CATCH();
118 {
119 /* Do not leave an uninitialized entry in the cache */
120 if (use_cache)
122 PG_RE_THROW();
123 }
124 PG_END_TRY();
125
126 ReleaseSysCache(procTup);
127
128 return proc;
129}
130
131/*
132 * Create a new PLyProcedure structure
133 */
134static PLyProcedure *
135PLy_procedure_create(HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger)
136{
137 char procName[NAMEDATALEN + 256];
138 Form_pg_proc procStruct;
139 PLyProcedure *volatile proc;
140 MemoryContext cxt;
141 MemoryContext oldcxt;
142 int rv;
143 char *ptr;
144
145 procStruct = (Form_pg_proc) GETSTRUCT(procTup);
146 rv = snprintf(procName, sizeof(procName),
147 "__plpython_procedure_%s_%u",
148 NameStr(procStruct->proname),
149 fn_oid);
150 if (rv >= sizeof(procName) || rv < 0)
151 elog(ERROR, "procedure name would overrun buffer");
152
153 /* Replace any not-legal-in-Python-names characters with '_' */
154 for (ptr = procName; *ptr; ptr++)
155 {
156 if (!((*ptr >= 'A' && *ptr <= 'Z') ||
157 (*ptr >= 'a' && *ptr <= 'z') ||
158 (*ptr >= '0' && *ptr <= '9')))
159 *ptr = '_';
160 }
161
162 /* Create long-lived context that all procedure info will live in */
164 "PL/Python function",
166
167 oldcxt = MemoryContextSwitchTo(cxt);
168
169 proc = (PLyProcedure *) palloc0(sizeof(PLyProcedure));
170 proc->mcxt = cxt;
171
172 PG_TRY();
173 {
174 Datum protrftypes_datum;
175 Datum prosrcdatum;
176 bool isnull;
177 char *procSource;
178 int i;
179
180 proc->proname = pstrdup(NameStr(procStruct->proname));
182 proc->pyname = pstrdup(procName);
183 proc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
184 proc->fn_tid = procTup->t_self;
185 proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
186 proc->is_setof = procStruct->proretset;
187 proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
188 proc->is_trigger = is_trigger;
189 proc->src = NULL;
190 proc->argnames = NULL;
191 proc->args = NULL;
192 proc->nargs = 0;
193 proc->langid = procStruct->prolang;
194 protrftypes_datum = SysCacheGetAttr(PROCOID, procTup,
195 Anum_pg_proc_protrftypes,
196 &isnull);
197 proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum);
198 proc->code = NULL;
199 proc->statics = NULL;
200 proc->globals = NULL;
201 proc->calldepth = 0;
202 proc->argstack = NULL;
203
204 /*
205 * get information required for output conversion of the return value,
206 * but only if this isn't a trigger.
207 */
208 if (is_trigger == PLPY_NOT_TRIGGER)
209 {
210 Oid rettype = procStruct->prorettype;
211 HeapTuple rvTypeTup;
212 Form_pg_type rvTypeStruct;
213
214 rvTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettype));
215 if (!HeapTupleIsValid(rvTypeTup))
216 elog(ERROR, "cache lookup failed for type %u", rettype);
217 rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
218
219 /* Disallow pseudotype result, except for void or record */
220 if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
221 {
222 if (rettype == VOIDOID ||
223 rettype == RECORDOID)
224 /* okay */ ;
225 else if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
227 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
228 errmsg("trigger functions can only be called as triggers")));
229 else
231 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
232 errmsg("PL/Python functions cannot return type %s",
233 format_type_be(rettype))));
234 }
235
236 /* set up output function for procedure result */
237 PLy_output_setup_func(&proc->result, proc->mcxt,
238 rettype, -1, proc);
239
240 ReleaseSysCache(rvTypeTup);
241 }
242 else
243 {
244 /*
245 * In a trigger function, we use proc->result and proc->result_in
246 * for converting tuples, but we don't yet have enough info to set
247 * them up. PLy_exec_trigger will deal with it.
248 */
249 proc->result.typoid = InvalidOid;
251 }
252
253 /*
254 * Now get information required for input conversion of the
255 * procedure's arguments. Note that we ignore output arguments here.
256 * If the function returns record, those I/O functions will be set up
257 * when the function is first called.
258 */
259 if (procStruct->pronargs)
260 {
261 Oid *types;
262 char **names,
263 *modes;
264 int pos,
265 total;
266
267 /* extract argument type info from the pg_proc tuple */
268 total = get_func_arg_info(procTup, &types, &names, &modes);
269
270 /* count number of in+inout args into proc->nargs */
271 if (modes == NULL)
272 proc->nargs = total;
273 else
274 {
275 /* proc->nargs was initialized to 0 above */
276 for (i = 0; i < total; i++)
277 {
278 if (modes[i] != PROARGMODE_OUT &&
279 modes[i] != PROARGMODE_TABLE)
280 (proc->nargs)++;
281 }
282 }
283
284 /* Allocate arrays for per-input-argument data */
285 proc->argnames = (char **) palloc0(sizeof(char *) * proc->nargs);
286 proc->args = (PLyDatumToOb *) palloc0(sizeof(PLyDatumToOb) * proc->nargs);
287
288 for (i = pos = 0; i < total; i++)
289 {
290 HeapTuple argTypeTup;
291 Form_pg_type argTypeStruct;
292
293 if (modes &&
294 (modes[i] == PROARGMODE_OUT ||
295 modes[i] == PROARGMODE_TABLE))
296 continue; /* skip OUT arguments */
297
298 Assert(types[i] == procStruct->proargtypes.values[pos]);
299
300 argTypeTup = SearchSysCache1(TYPEOID,
302 if (!HeapTupleIsValid(argTypeTup))
303 elog(ERROR, "cache lookup failed for type %u", types[i]);
304 argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
305
306 /* disallow pseudotype arguments */
307 if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
309 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
310 errmsg("PL/Python functions cannot accept type %s",
312
313 /* set up I/O function info */
314 PLy_input_setup_func(&proc->args[pos], proc->mcxt,
315 types[i], -1, /* typmod not known */
316 proc);
317
318 /* get argument name */
319 proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
320
321 ReleaseSysCache(argTypeTup);
322
323 pos++;
324 }
325 }
326
327 /*
328 * get the text of the function.
329 */
330 prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup,
331 Anum_pg_proc_prosrc);
332 procSource = TextDatumGetCString(prosrcdatum);
333
334 PLy_procedure_compile(proc, procSource);
335
336 pfree(procSource);
337 }
338 PG_CATCH();
339 {
340 MemoryContextSwitchTo(oldcxt);
342 PG_RE_THROW();
343 }
344 PG_END_TRY();
345
346 MemoryContextSwitchTo(oldcxt);
347 return proc;
348}
349
350/*
351 * Insert the procedure into the Python interpreter
352 */
353void
354PLy_procedure_compile(PLyProcedure *proc, const char *src)
355{
356 PyObject *crv = NULL;
357 char *msrc;
358 PyObject *code0;
359
360 proc->globals = PyDict_Copy(PLy_interp_globals);
361
362 /*
363 * SD is private preserved data between calls. GD is global data shared by
364 * all functions
365 */
366 proc->statics = PyDict_New();
367 if (!proc->statics)
368 PLy_elog(ERROR, NULL);
369 PyDict_SetItemString(proc->globals, "SD", proc->statics);
370
371 /*
372 * insert the function code into the interpreter
373 */
374 msrc = PLy_procedure_munge_source(proc->pyname, src);
375 /* Save the mangled source for later inclusion in tracebacks */
376 proc->src = MemoryContextStrdup(proc->mcxt, msrc);
377 code0 = Py_CompileString(msrc, "<string>", Py_file_input);
378 if (code0)
379 crv = PyEval_EvalCode(code0, proc->globals, NULL);
380 pfree(msrc);
381
382 if (crv != NULL)
383 {
384 int clen;
385 char call[NAMEDATALEN + 256];
386
387 Py_DECREF(crv);
388
389 /*
390 * compile a call to the function
391 */
392 clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
393 if (clen < 0 || clen >= sizeof(call))
394 elog(ERROR, "string would overflow buffer");
395 proc->code = Py_CompileString(call, "<string>", Py_eval_input);
396 if (proc->code != NULL)
397 return;
398 }
399
400 if (proc->proname)
401 PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
402 proc->proname);
403 else
404 PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
405}
406
407void
409{
410 Py_XDECREF(proc->code);
411 Py_XDECREF(proc->statics);
412 Py_XDECREF(proc->globals);
414}
415
416/*
417 * Decide whether a cached PLyProcedure struct is still valid
418 */
419static bool
421{
422 if (proc == NULL)
423 return false;
424
425 /* If the pg_proc tuple has changed, it's not valid */
426 if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
427 ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
428 return false;
429
430 return true;
431}
432
433static char *
434PLy_procedure_munge_source(const char *name, const char *src)
435{
436 char *mrc,
437 *mp;
438 const char *sp;
439 size_t mlen;
440 int plen;
441
442 /*
443 * room for function source and the def statement
444 */
445 mlen = (strlen(src) * 2) + strlen(name) + 16;
446
447 mrc = palloc(mlen);
448 plen = snprintf(mrc, mlen, "def %s():\n\t", name);
449 Assert(plen >= 0 && plen < mlen);
450
451 sp = src;
452 mp = mrc + plen;
453
454 while (*sp != '\0')
455 {
456 if (*sp == '\r' && *(sp + 1) == '\n')
457 sp++;
458
459 if (*sp == '\n' || *sp == '\r')
460 {
461 *mp++ = '\n';
462 *mp++ = '\t';
463 sp++;
464 }
465 else
466 *mp++ = *sp++;
467 }
468 *mp++ = '\n';
469 *mp++ = '\n';
470 *mp = '\0';
471
472 if (mp > (mrc + mlen))
473 elog(FATAL, "buffer overrun in PLy_procedure_munge_source");
474
475 return mrc;
476}
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:751
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
struct typedefs * types
Definition: ecpg.c:30
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define PG_RE_THROW()
Definition: elog.h:405
#define FATAL
Definition: elog.h:41
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:382
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
Assert(PointerIsAligned(start, uint64))
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
Definition: htup_details.h:318
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
int i
Definition: isn.c:77
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:35
#define PLy_elog
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1746
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
MemoryContext TopMemoryContext
Definition: mcxt.c:166
void * palloc(Size size)
Definition: mcxt.c:1365
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:658
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define NAMEDATALEN
#define NIL
Definition: pg_list.h:68
List * oid_array_to_list(Datum datum)
Definition: pg_proc.c:1205
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
PyObject * PLy_interp_globals
Definition: plpy_main.c:55
char * PLy_procedure_name(PLyProcedure *proc)
void init_procedure_caches(void)
static char * PLy_procedure_munge_source(const char *name, const char *src)
static PLyProcedure * PLy_procedure_create(HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger)
PLyProcedure * PLy_procedure_get(Oid fn_oid, Oid fn_rel, PLyTrigType is_trigger)
static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
static HTAB * PLy_procedure_cache
void PLy_procedure_compile(PLyProcedure *proc, const char *src)
void PLy_procedure_delete(PLyProcedure *proc)
PLyTrigType
@ PLPY_TRIGGER
@ PLPY_NOT_TRIGGER
struct PLyProcedureKey PLyProcedureKey
struct PLyProcedureEntry PLyProcedureEntry
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:296
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:418
#define snprintf
Definition: port.h:239
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
Definition: dynahash.c:222
ItemPointerData t_self
Definition: htup.h:65
HeapTupleHeader t_data
Definition: htup.h:68
PLyProcedure * proc
PLyDatumToOb * args
PLyTrigType is_trigger
PLyObToDatum result
PyObject * code
PLyDatumToOb result_in
PLySavedArgs * argstack
MemoryContext mcxt
char ** argnames
PyObject * globals
ItemPointerData fn_tid
TransactionId fn_xmin
PyObject * statics
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
const char * name