Line data Source code
1 : /*
2 : * PL/Python main entry points
3 : *
4 : * src/pl/plpython/plpy_main.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 "commands/event_trigger.h"
13 : #include "commands/trigger.h"
14 : #include "executor/spi.h"
15 : #include "miscadmin.h"
16 : #include "plpy_elog.h"
17 : #include "plpy_exec.h"
18 : #include "plpy_main.h"
19 : #include "plpy_plpymodule.h"
20 : #include "plpy_procedure.h"
21 : #include "plpy_subxactobject.h"
22 : #include "plpy_util.h"
23 : #include "utils/guc.h"
24 : #include "utils/memutils.h"
25 : #include "utils/rel.h"
26 : #include "utils/syscache.h"
27 :
28 : /*
29 : * exported functions
30 : */
31 :
32 46 : PG_MODULE_MAGIC_EXT(
33 : .name = "plpython",
34 : .version = PG_VERSION
35 : );
36 :
37 52 : PG_FUNCTION_INFO_V1(plpython3_validator);
38 52 : PG_FUNCTION_INFO_V1(plpython3_call_handler);
39 16 : PG_FUNCTION_INFO_V1(plpython3_inline_handler);
40 :
41 :
42 : static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct);
43 : static void plpython_error_callback(void *arg);
44 : static void plpython_inline_error_callback(void *arg);
45 :
46 : static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
47 : static void PLy_pop_execution_context(void);
48 :
49 : /* initialize global variables */
50 : PyObject *PLy_interp_globals = NULL;
51 :
52 : /* this doesn't need to be global; use PLy_current_execution_context() */
53 : static PLyExecutionContext *PLy_execution_contexts = NULL;
54 :
55 :
56 : void
57 46 : _PG_init(void)
58 : {
59 : PyObject *main_mod;
60 : PyObject *main_dict;
61 : PyObject *GD;
62 : PyObject *plpy_mod;
63 :
64 46 : pg_bindtextdomain(TEXTDOMAIN);
65 :
66 : /* Add plpy to table of built-in modules. */
67 46 : PyImport_AppendInittab("plpy", PyInit_plpy);
68 :
69 : /* Initialize Python interpreter. */
70 46 : Py_Initialize();
71 :
72 46 : main_mod = PyImport_AddModule("__main__");
73 46 : if (main_mod == NULL || PyErr_Occurred())
74 0 : PLy_elog(ERROR, "could not import \"%s\" module", "__main__");
75 46 : Py_INCREF(main_mod);
76 :
77 46 : main_dict = PyModule_GetDict(main_mod);
78 46 : if (main_dict == NULL)
79 0 : PLy_elog(ERROR, NULL);
80 :
81 : /*
82 : * Set up GD.
83 : */
84 46 : GD = PyDict_New();
85 46 : if (GD == NULL)
86 0 : PLy_elog(ERROR, NULL);
87 46 : PyDict_SetItemString(main_dict, "GD", GD);
88 :
89 : /*
90 : * Import plpy.
91 : */
92 46 : plpy_mod = PyImport_ImportModule("plpy");
93 46 : if (plpy_mod == NULL)
94 0 : PLy_elog(ERROR, "could not import \"%s\" module", "plpy");
95 46 : if (PyDict_SetItemString(main_dict, "plpy", plpy_mod) == -1)
96 0 : PLy_elog(ERROR, NULL);
97 :
98 46 : if (PyErr_Occurred())
99 0 : PLy_elog(FATAL, "untrapped error in initialization");
100 :
101 46 : Py_INCREF(main_dict);
102 46 : PLy_interp_globals = main_dict;
103 :
104 46 : Py_DECREF(main_mod);
105 :
106 46 : init_procedure_caches();
107 :
108 46 : explicit_subtransactions = NIL;
109 :
110 46 : PLy_execution_contexts = NULL;
111 46 : }
112 :
113 : Datum
114 502 : plpython3_validator(PG_FUNCTION_ARGS)
115 : {
116 502 : Oid funcoid = PG_GETARG_OID(0);
117 : HeapTuple tuple;
118 : Form_pg_proc procStruct;
119 : PLyTrigType is_trigger;
120 :
121 502 : if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
122 0 : PG_RETURN_VOID();
123 :
124 502 : if (!check_function_bodies)
125 2 : PG_RETURN_VOID();
126 :
127 : /* Get the new function's pg_proc entry */
128 500 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
129 500 : if (!HeapTupleIsValid(tuple))
130 0 : elog(ERROR, "cache lookup failed for function %u", funcoid);
131 500 : procStruct = (Form_pg_proc) GETSTRUCT(tuple);
132 :
133 500 : is_trigger = PLy_procedure_is_trigger(procStruct);
134 :
135 500 : ReleaseSysCache(tuple);
136 :
137 : /* We can't validate triggers against any particular table ... */
138 500 : (void) PLy_procedure_get(funcoid, InvalidOid, is_trigger);
139 :
140 498 : PG_RETURN_VOID();
141 : }
142 :
143 : Datum
144 1402 : plpython3_call_handler(PG_FUNCTION_ARGS)
145 : {
146 : bool nonatomic;
147 : Datum retval;
148 : PLyExecutionContext *exec_ctx;
149 : ErrorContextCallback plerrcontext;
150 :
151 2938 : nonatomic = fcinfo->context &&
152 1418 : IsA(fcinfo->context, CallContext) &&
153 16 : !castNode(CallContext, fcinfo->context)->atomic;
154 :
155 : /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
156 1402 : SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0);
157 :
158 : /*
159 : * Push execution context onto stack. It is important that this get
160 : * popped again, so avoid putting anything that could throw error between
161 : * here and the PG_TRY.
162 : */
163 1402 : exec_ctx = PLy_push_execution_context(!nonatomic);
164 :
165 1402 : PG_TRY();
166 : {
167 1402 : Oid funcoid = fcinfo->flinfo->fn_oid;
168 : PLyProcedure *proc;
169 :
170 : /*
171 : * Setup error traceback support for ereport(). Note that the PG_TRY
172 : * structure pops this for us again at exit, so we needn't do that
173 : * explicitly, nor do we risk the callback getting called after we've
174 : * destroyed the exec_ctx.
175 : */
176 1402 : plerrcontext.callback = plpython_error_callback;
177 1402 : plerrcontext.arg = exec_ctx;
178 1402 : plerrcontext.previous = error_context_stack;
179 1402 : error_context_stack = &plerrcontext;
180 :
181 1402 : if (CALLED_AS_TRIGGER(fcinfo))
182 80 : {
183 98 : Relation tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
184 : HeapTuple trv;
185 :
186 98 : proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), PLPY_TRIGGER);
187 98 : exec_ctx->curr_proc = proc;
188 98 : trv = PLy_exec_trigger(fcinfo, proc);
189 80 : retval = PointerGetDatum(trv);
190 : }
191 1304 : else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
192 : {
193 20 : proc = PLy_procedure_get(funcoid, InvalidOid, PLPY_EVENT_TRIGGER);
194 20 : exec_ctx->curr_proc = proc;
195 20 : PLy_exec_event_trigger(fcinfo, proc);
196 20 : retval = (Datum) 0;
197 : }
198 : else
199 : {
200 1284 : proc = PLy_procedure_get(funcoid, InvalidOid, PLPY_NOT_TRIGGER);
201 1278 : exec_ctx->curr_proc = proc;
202 1278 : retval = PLy_exec_function(fcinfo, proc);
203 : }
204 : }
205 186 : PG_CATCH();
206 : {
207 186 : PLy_pop_execution_context();
208 186 : PyErr_Clear();
209 186 : PG_RE_THROW();
210 : }
211 1216 : PG_END_TRY();
212 :
213 : /* Destroy the execution context */
214 1216 : PLy_pop_execution_context();
215 :
216 1216 : return retval;
217 : }
218 :
219 : Datum
220 42 : plpython3_inline_handler(PG_FUNCTION_ARGS)
221 : {
222 42 : LOCAL_FCINFO(fake_fcinfo, 0);
223 42 : InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
224 : FmgrInfo flinfo;
225 : PLyProcedure proc;
226 : PLyExecutionContext *exec_ctx;
227 : ErrorContextCallback plerrcontext;
228 :
229 : /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
230 42 : SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);
231 :
232 210 : MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
233 294 : MemSet(&flinfo, 0, sizeof(flinfo));
234 42 : fake_fcinfo->flinfo = &flinfo;
235 42 : flinfo.fn_oid = InvalidOid;
236 42 : flinfo.fn_mcxt = CurrentMemoryContext;
237 :
238 1764 : MemSet(&proc, 0, sizeof(PLyProcedure));
239 42 : proc.mcxt = AllocSetContextCreate(TopMemoryContext,
240 : "__plpython_inline_block",
241 : ALLOCSET_DEFAULT_SIZES);
242 42 : proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
243 42 : proc.langid = codeblock->langOid;
244 :
245 : /*
246 : * This is currently sufficient to get PLy_exec_function to work, but
247 : * someday we might need to be honest and use PLy_output_setup_func.
248 : */
249 42 : proc.result.typoid = VOIDOID;
250 :
251 : /*
252 : * Push execution context onto stack. It is important that this get
253 : * popped again, so avoid putting anything that could throw error between
254 : * here and the PG_TRY.
255 : */
256 42 : exec_ctx = PLy_push_execution_context(codeblock->atomic);
257 :
258 42 : PG_TRY();
259 : {
260 : /*
261 : * Setup error traceback support for ereport().
262 : * plpython_inline_error_callback doesn't currently need exec_ctx, but
263 : * for consistency with plpython3_call_handler we do it the same way.
264 : */
265 42 : plerrcontext.callback = plpython_inline_error_callback;
266 42 : plerrcontext.arg = exec_ctx;
267 42 : plerrcontext.previous = error_context_stack;
268 42 : error_context_stack = &plerrcontext;
269 :
270 42 : PLy_procedure_compile(&proc, codeblock->source_text);
271 42 : exec_ctx->curr_proc = &proc;
272 42 : PLy_exec_function(fake_fcinfo, &proc);
273 : }
274 22 : PG_CATCH();
275 : {
276 22 : PLy_pop_execution_context();
277 22 : PLy_procedure_delete(&proc);
278 22 : PyErr_Clear();
279 22 : PG_RE_THROW();
280 : }
281 20 : PG_END_TRY();
282 :
283 : /* Destroy the execution context */
284 20 : PLy_pop_execution_context();
285 :
286 : /* Now clean up the transient procedure we made */
287 20 : PLy_procedure_delete(&proc);
288 :
289 20 : PG_RETURN_VOID();
290 : }
291 :
292 : static PLyTrigType
293 500 : PLy_procedure_is_trigger(Form_pg_proc procStruct)
294 : {
295 : PLyTrigType ret;
296 :
297 500 : switch (procStruct->prorettype)
298 : {
299 48 : case TRIGGEROID:
300 48 : ret = PLPY_TRIGGER;
301 48 : break;
302 2 : case EVENT_TRIGGEROID:
303 2 : ret = PLPY_EVENT_TRIGGER;
304 2 : break;
305 450 : default:
306 450 : ret = PLPY_NOT_TRIGGER;
307 450 : break;
308 : }
309 :
310 500 : return ret;
311 : }
312 :
313 : static void
314 932 : plpython_error_callback(void *arg)
315 : {
316 932 : PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
317 :
318 932 : if (exec_ctx->curr_proc)
319 : {
320 926 : if (exec_ctx->curr_proc->is_procedure)
321 8 : errcontext("PL/Python procedure \"%s\"",
322 : PLy_procedure_name(exec_ctx->curr_proc));
323 : else
324 918 : errcontext("PL/Python function \"%s\"",
325 : PLy_procedure_name(exec_ctx->curr_proc));
326 : }
327 932 : }
328 :
329 : static void
330 56 : plpython_inline_error_callback(void *arg)
331 : {
332 56 : errcontext("PL/Python anonymous code block");
333 56 : }
334 :
335 : PLyExecutionContext *
336 2856 : PLy_current_execution_context(void)
337 : {
338 2856 : if (PLy_execution_contexts == NULL)
339 0 : elog(ERROR, "no Python function is currently executing");
340 :
341 2856 : return PLy_execution_contexts;
342 : }
343 :
344 : MemoryContext
345 1586 : PLy_get_scratch_context(PLyExecutionContext *context)
346 : {
347 : /*
348 : * A scratch context might never be needed in a given plpython procedure,
349 : * so allocate it on first request.
350 : */
351 1586 : if (context->scratch_ctx == NULL)
352 884 : context->scratch_ctx =
353 884 : AllocSetContextCreate(TopTransactionContext,
354 : "PL/Python scratch context",
355 : ALLOCSET_DEFAULT_SIZES);
356 1586 : return context->scratch_ctx;
357 : }
358 :
359 : static PLyExecutionContext *
360 1444 : PLy_push_execution_context(bool atomic_context)
361 : {
362 : PLyExecutionContext *context;
363 :
364 : /* Pick a memory context similar to what SPI uses. */
365 : context = (PLyExecutionContext *)
366 1444 : MemoryContextAlloc(atomic_context ? TopTransactionContext : PortalContext,
367 : sizeof(PLyExecutionContext));
368 1444 : context->curr_proc = NULL;
369 1444 : context->scratch_ctx = NULL;
370 1444 : context->next = PLy_execution_contexts;
371 1444 : PLy_execution_contexts = context;
372 1444 : return context;
373 : }
374 :
375 : static void
376 1444 : PLy_pop_execution_context(void)
377 : {
378 1444 : PLyExecutionContext *context = PLy_execution_contexts;
379 :
380 1444 : if (context == NULL)
381 0 : elog(ERROR, "no Python function is currently executing");
382 :
383 1444 : PLy_execution_contexts = context->next;
384 :
385 1444 : if (context->scratch_ctx)
386 850 : MemoryContextDelete(context->scratch_ctx);
387 1444 : pfree(context);
388 1444 : }
|