Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007 #include "postgres.h"
00008
00009 #include "access/htup_details.h"
00010 #include "catalog/pg_proc.h"
00011 #include "catalog/pg_type.h"
00012 #include "commands/trigger.h"
00013 #include "executor/spi.h"
00014 #include "miscadmin.h"
00015 #include "utils/guc.h"
00016 #include "utils/memutils.h"
00017 #include "utils/rel.h"
00018 #include "utils/syscache.h"
00019
00020 #include "plpython.h"
00021
00022 #include "plpy_main.h"
00023
00024 #include "plpy_elog.h"
00025 #include "plpy_exec.h"
00026 #include "plpy_plpymodule.h"
00027 #include "plpy_procedure.h"
00028 #include "plpy_subxactobject.h"
00029
00030
00031
00032
00033
00034
00035 #if PY_MAJOR_VERSION >= 3
00036
00037 #define plpython_validator plpython3_validator
00038 #define plpython_call_handler plpython3_call_handler
00039 #define plpython_inline_handler plpython3_inline_handler
00040 #endif
00041
00042 extern void _PG_init(void);
00043 extern Datum plpython_validator(PG_FUNCTION_ARGS);
00044 extern Datum plpython_call_handler(PG_FUNCTION_ARGS);
00045 extern Datum plpython_inline_handler(PG_FUNCTION_ARGS);
00046
00047 #if PY_MAJOR_VERSION < 3
00048
00049 extern Datum plpython2_validator(PG_FUNCTION_ARGS);
00050 extern Datum plpython2_call_handler(PG_FUNCTION_ARGS);
00051 extern Datum plpython2_inline_handler(PG_FUNCTION_ARGS);
00052 #endif
00053
00054 PG_MODULE_MAGIC;
00055
00056 PG_FUNCTION_INFO_V1(plpython_validator);
00057 PG_FUNCTION_INFO_V1(plpython_call_handler);
00058 PG_FUNCTION_INFO_V1(plpython_inline_handler);
00059
00060 #if PY_MAJOR_VERSION < 3
00061 PG_FUNCTION_INFO_V1(plpython2_validator);
00062 PG_FUNCTION_INFO_V1(plpython2_call_handler);
00063 PG_FUNCTION_INFO_V1(plpython2_inline_handler);
00064 #endif
00065
00066
00067 static bool PLy_procedure_is_trigger(Form_pg_proc procStruct);
00068 static void plpython_error_callback(void *arg);
00069 static void plpython_inline_error_callback(void *arg);
00070 static void PLy_init_interp(void);
00071
00072 static PLyExecutionContext *PLy_push_execution_context(void);
00073 static void PLy_pop_execution_context(void);
00074
00075 static const int plpython_python_version = PY_MAJOR_VERSION;
00076
00077
00078 PyObject *PLy_interp_globals = NULL;
00079
00080
00081 static PLyExecutionContext *PLy_execution_contexts = NULL;
00082
00083
00084 void
00085 _PG_init(void)
00086 {
00087
00088 static bool inited = false;
00089 const int **version_ptr;
00090
00091 if (inited)
00092 return;
00093
00094
00095 version_ptr = (const int **) find_rendezvous_variable("plpython_python_version");
00096 if (!(*version_ptr))
00097 *version_ptr = &plpython_python_version;
00098 else
00099 {
00100 if (**version_ptr != plpython_python_version)
00101 ereport(FATAL,
00102 (errmsg("Python major version mismatch in session"),
00103 errdetail("This session has previously used Python major version %d, and it is now attempting to use Python major version %d.",
00104 **version_ptr, plpython_python_version),
00105 errhint("Start a new session to use a different Python major version.")));
00106 }
00107
00108 pg_bindtextdomain(TEXTDOMAIN);
00109
00110 #if PY_MAJOR_VERSION >= 3
00111 PyImport_AppendInittab("plpy", PyInit_plpy);
00112 #endif
00113 Py_Initialize();
00114 #if PY_MAJOR_VERSION >= 3
00115 PyImport_ImportModule("plpy");
00116 #endif
00117 PLy_init_interp();
00118 PLy_init_plpy();
00119 if (PyErr_Occurred())
00120 PLy_elog(FATAL, "untrapped error in initialization");
00121
00122 init_procedure_caches();
00123
00124 explicit_subtransactions = NIL;
00125
00126 PLy_execution_contexts = NULL;
00127
00128 inited = true;
00129 }
00130
00131
00132
00133
00134
00135 void
00136 PLy_init_interp(void)
00137 {
00138 static PyObject *PLy_interp_safe_globals = NULL;
00139 PyObject *mainmod;
00140
00141 mainmod = PyImport_AddModule("__main__");
00142 if (mainmod == NULL || PyErr_Occurred())
00143 PLy_elog(ERROR, "could not import \"__main__\" module");
00144 Py_INCREF(mainmod);
00145 PLy_interp_globals = PyModule_GetDict(mainmod);
00146 PLy_interp_safe_globals = PyDict_New();
00147 if (PLy_interp_safe_globals == NULL)
00148 PLy_elog(ERROR, "could not create globals");
00149 PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
00150 Py_DECREF(mainmod);
00151 if (PLy_interp_globals == NULL || PyErr_Occurred())
00152 PLy_elog(ERROR, "could not initialize globals");
00153 }
00154
00155 Datum
00156 plpython_validator(PG_FUNCTION_ARGS)
00157 {
00158 Oid funcoid = PG_GETARG_OID(0);
00159 HeapTuple tuple;
00160 Form_pg_proc procStruct;
00161 bool is_trigger;
00162
00163 if (!check_function_bodies)
00164 {
00165 PG_RETURN_VOID();
00166 }
00167
00168
00169 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
00170 if (!HeapTupleIsValid(tuple))
00171 elog(ERROR, "cache lookup failed for function %u", funcoid);
00172 procStruct = (Form_pg_proc) GETSTRUCT(tuple);
00173
00174 is_trigger = PLy_procedure_is_trigger(procStruct);
00175
00176 ReleaseSysCache(tuple);
00177
00178
00179 PLy_procedure_get(funcoid, InvalidOid, is_trigger);
00180
00181 PG_RETURN_VOID();
00182 }
00183
00184 #if PY_MAJOR_VERSION < 3
00185 Datum
00186 plpython2_validator(PG_FUNCTION_ARGS)
00187 {
00188 return plpython_validator(fcinfo);
00189 }
00190 #endif
00191
00192 Datum
00193 plpython_call_handler(PG_FUNCTION_ARGS)
00194 {
00195 Datum retval;
00196 PLyExecutionContext *exec_ctx;
00197 ErrorContextCallback plerrcontext;
00198
00199
00200 if (SPI_connect() != SPI_OK_CONNECT)
00201 elog(ERROR, "SPI_connect failed");
00202
00203
00204
00205
00206
00207
00208
00209 exec_ctx = PLy_push_execution_context();
00210
00211
00212
00213
00214 plerrcontext.callback = plpython_error_callback;
00215 plerrcontext.previous = error_context_stack;
00216 error_context_stack = &plerrcontext;
00217
00218 PG_TRY();
00219 {
00220 Oid funcoid = fcinfo->flinfo->fn_oid;
00221 PLyProcedure *proc;
00222
00223 if (CALLED_AS_TRIGGER(fcinfo))
00224 {
00225 Relation tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
00226 HeapTuple trv;
00227
00228 proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), true);
00229 exec_ctx->curr_proc = proc;
00230 trv = PLy_exec_trigger(fcinfo, proc);
00231 retval = PointerGetDatum(trv);
00232 }
00233 else
00234 {
00235 proc = PLy_procedure_get(funcoid, InvalidOid, false);
00236 exec_ctx->curr_proc = proc;
00237 retval = PLy_exec_function(fcinfo, proc);
00238 }
00239 }
00240 PG_CATCH();
00241 {
00242 PLy_pop_execution_context();
00243 PyErr_Clear();
00244 PG_RE_THROW();
00245 }
00246 PG_END_TRY();
00247
00248
00249 error_context_stack = plerrcontext.previous;
00250
00251 PLy_pop_execution_context();
00252
00253 return retval;
00254 }
00255
00256 #if PY_MAJOR_VERSION < 3
00257 Datum
00258 plpython2_call_handler(PG_FUNCTION_ARGS)
00259 {
00260 return plpython_call_handler(fcinfo);
00261 }
00262 #endif
00263
00264 Datum
00265 plpython_inline_handler(PG_FUNCTION_ARGS)
00266 {
00267 InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
00268 FunctionCallInfoData fake_fcinfo;
00269 FmgrInfo flinfo;
00270 PLyProcedure proc;
00271 PLyExecutionContext *exec_ctx;
00272 ErrorContextCallback plerrcontext;
00273
00274
00275 if (SPI_connect() != SPI_OK_CONNECT)
00276 elog(ERROR, "SPI_connect failed");
00277
00278 MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
00279 MemSet(&flinfo, 0, sizeof(flinfo));
00280 fake_fcinfo.flinfo = &flinfo;
00281 flinfo.fn_oid = InvalidOid;
00282 flinfo.fn_mcxt = CurrentMemoryContext;
00283
00284 MemSet(&proc, 0, sizeof(PLyProcedure));
00285 proc.pyname = PLy_strdup("__plpython_inline_block");
00286 proc.result.out.d.typoid = VOIDOID;
00287
00288
00289
00290
00291
00292
00293
00294
00295 exec_ctx = PLy_push_execution_context();
00296
00297
00298
00299
00300 plerrcontext.callback = plpython_inline_error_callback;
00301 plerrcontext.previous = error_context_stack;
00302 error_context_stack = &plerrcontext;
00303
00304 PG_TRY();
00305 {
00306 PLy_procedure_compile(&proc, codeblock->source_text);
00307 exec_ctx->curr_proc = &proc;
00308 PLy_exec_function(&fake_fcinfo, &proc);
00309 }
00310 PG_CATCH();
00311 {
00312 PLy_pop_execution_context();
00313 PLy_procedure_delete(&proc);
00314 PyErr_Clear();
00315 PG_RE_THROW();
00316 }
00317 PG_END_TRY();
00318
00319
00320 error_context_stack = plerrcontext.previous;
00321
00322 PLy_pop_execution_context();
00323
00324
00325 PLy_procedure_delete(&proc);
00326
00327 PG_RETURN_VOID();
00328 }
00329
00330 #if PY_MAJOR_VERSION < 3
00331 Datum
00332 plpython2_inline_handler(PG_FUNCTION_ARGS)
00333 {
00334 return plpython_inline_handler(fcinfo);
00335 }
00336 #endif
00337
00338 static bool
00339 PLy_procedure_is_trigger(Form_pg_proc procStruct)
00340 {
00341 return (procStruct->prorettype == TRIGGEROID ||
00342 (procStruct->prorettype == OPAQUEOID &&
00343 procStruct->pronargs == 0));
00344 }
00345
00346 static void
00347 plpython_error_callback(void *arg)
00348 {
00349 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
00350
00351 if (exec_ctx->curr_proc)
00352 errcontext("PL/Python function \"%s\"",
00353 PLy_procedure_name(exec_ctx->curr_proc));
00354 }
00355
00356 static void
00357 plpython_inline_error_callback(void *arg)
00358 {
00359 errcontext("PL/Python anonymous code block");
00360 }
00361
00362 PLyExecutionContext *
00363 PLy_current_execution_context(void)
00364 {
00365 if (PLy_execution_contexts == NULL)
00366 elog(ERROR, "no Python function is currently executing");
00367
00368 return PLy_execution_contexts;
00369 }
00370
00371 static PLyExecutionContext *
00372 PLy_push_execution_context(void)
00373 {
00374 PLyExecutionContext *context = PLy_malloc(sizeof(PLyExecutionContext));
00375
00376 context->curr_proc = NULL;
00377 context->scratch_ctx = AllocSetContextCreate(TopTransactionContext,
00378 "PL/Python scratch context",
00379 ALLOCSET_DEFAULT_MINSIZE,
00380 ALLOCSET_DEFAULT_INITSIZE,
00381 ALLOCSET_DEFAULT_MAXSIZE);
00382 context->next = PLy_execution_contexts;
00383 PLy_execution_contexts = context;
00384 return context;
00385 }
00386
00387 static void
00388 PLy_pop_execution_context(void)
00389 {
00390 PLyExecutionContext *context = PLy_execution_contexts;
00391
00392 if (context == NULL)
00393 elog(ERROR, "no Python function is currently executing");
00394
00395 PLy_execution_contexts = context->next;
00396
00397 MemoryContextDelete(context->scratch_ctx);
00398 PLy_free(context);
00399 }