LCOV - code coverage report
Current view: top level - src/pl/plpython - plpy_main.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 157 169 92.9 %
Date: 2019-11-15 22:06:47 Functions: 23 23 100.0 %
Legend: Lines: hit not hit

          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/trigger.h"
      13             : #include "executor/spi.h"
      14             : #include "miscadmin.h"
      15             : #include "utils/guc.h"
      16             : #include "utils/memutils.h"
      17             : #include "utils/rel.h"
      18             : #include "utils/syscache.h"
      19             : 
      20             : #include "plpython.h"
      21             : 
      22             : #include "plpy_main.h"
      23             : 
      24             : #include "plpy_elog.h"
      25             : #include "plpy_exec.h"
      26             : #include "plpy_plpymodule.h"
      27             : #include "plpy_procedure.h"
      28             : #include "plpy_subxactobject.h"
      29             : 
      30             : 
      31             : /*
      32             :  * exported functions
      33             :  */
      34             : 
      35             : #if PY_MAJOR_VERSION >= 3
      36             : /* Use separate names to avoid clash in pg_pltemplate */
      37             : #define plpython_validator plpython3_validator
      38             : #define plpython_call_handler plpython3_call_handler
      39             : #define plpython_inline_handler plpython3_inline_handler
      40             : #endif
      41             : 
      42             : extern void _PG_init(void);
      43             : 
      44          58 : PG_MODULE_MAGIC;
      45             : 
      46          52 : PG_FUNCTION_INFO_V1(plpython_validator);
      47          52 : PG_FUNCTION_INFO_V1(plpython_call_handler);
      48          16 : PG_FUNCTION_INFO_V1(plpython_inline_handler);
      49             : 
      50             : #if PY_MAJOR_VERSION < 3
      51             : /* Define aliases plpython2_call_handler etc */
      52          16 : PG_FUNCTION_INFO_V1(plpython2_validator);
      53          16 : PG_FUNCTION_INFO_V1(plpython2_call_handler);
      54          10 : PG_FUNCTION_INFO_V1(plpython2_inline_handler);
      55             : #endif
      56             : 
      57             : 
      58             : static bool PLy_procedure_is_trigger(Form_pg_proc procStruct);
      59             : static void plpython_error_callback(void *arg);
      60             : static void plpython_inline_error_callback(void *arg);
      61             : static void PLy_init_interp(void);
      62             : 
      63             : static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
      64             : static void PLy_pop_execution_context(void);
      65             : 
      66             : /* static state for Python library conflict detection */
      67             : static int *plpython_version_bitmask_ptr = NULL;
      68             : static int  plpython_version_bitmask = 0;
      69             : 
      70             : /* initialize global variables */
      71             : PyObject   *PLy_interp_globals = NULL;
      72             : 
      73             : /* this doesn't need to be global; use PLy_current_execution_context() */
      74             : static PLyExecutionContext *PLy_execution_contexts = NULL;
      75             : 
      76             : 
      77             : void
      78          58 : _PG_init(void)
      79             : {
      80             :     int       **bitmask_ptr;
      81             : 
      82             :     /*
      83             :      * Set up a shared bitmask variable telling which Python version(s) are
      84             :      * loaded into this process's address space.  If there's more than one, we
      85             :      * cannot call into libpython for fear of causing crashes.  But postpone
      86             :      * the actual failure for later, so that operations like pg_restore can
      87             :      * load more than one plpython library so long as they don't try to do
      88             :      * anything much with the language.
      89             :      */
      90          58 :     bitmask_ptr = (int **) find_rendezvous_variable("plpython_version_bitmask");
      91          58 :     if (!(*bitmask_ptr))        /* am I the first? */
      92          58 :         *bitmask_ptr = &plpython_version_bitmask;
      93             :     /* Retain pointer to the agreed-on shared variable ... */
      94          58 :     plpython_version_bitmask_ptr = *bitmask_ptr;
      95             :     /* ... and announce my presence */
      96          58 :     *plpython_version_bitmask_ptr |= (1 << PY_MAJOR_VERSION);
      97             : 
      98             :     /*
      99             :      * This should be safe even in the presence of conflicting plpythons, and
     100             :      * it's necessary to do it before possibly throwing a conflict error, or
     101             :      * the error message won't get localized.
     102             :      */
     103          58 :     pg_bindtextdomain(TEXTDOMAIN);
     104          58 : }
     105             : 
     106             : /*
     107             :  * Perform one-time setup of PL/Python, after checking for a conflict
     108             :  * with other versions of Python.
     109             :  */
     110             : static void
     111        1852 : PLy_initialize(void)
     112             : {
     113             :     static bool inited = false;
     114             : 
     115             :     /*
     116             :      * Check for multiple Python libraries before actively doing anything with
     117             :      * libpython.  This must be repeated on each entry to PL/Python, in case a
     118             :      * conflicting library got loaded since we last looked.
     119             :      *
     120             :      * It is attractive to weaken this error from FATAL to ERROR, but there
     121             :      * would be corner cases, so it seems best to be conservative.
     122             :      */
     123        1852 :     if (*plpython_version_bitmask_ptr != (1 << PY_MAJOR_VERSION))
     124           0 :         ereport(FATAL,
     125             :                 (errmsg("multiple Python libraries are present in session"),
     126             :                  errdetail("Only one Python major version can be used in one session.")));
     127             : 
     128             :     /* The rest should only be done once per session */
     129        1852 :     if (inited)
     130        1806 :         return;
     131             : 
     132             : #if PY_MAJOR_VERSION >= 3
     133             :     PyImport_AppendInittab("plpy", PyInit_plpy);
     134             : #endif
     135          46 :     Py_Initialize();
     136             : #if PY_MAJOR_VERSION >= 3
     137             :     PyImport_ImportModule("plpy");
     138             : #endif
     139          46 :     PLy_init_interp();
     140          46 :     PLy_init_plpy();
     141          46 :     if (PyErr_Occurred())
     142           0 :         PLy_elog(FATAL, "untrapped error in initialization");
     143             : 
     144          46 :     init_procedure_caches();
     145             : 
     146          46 :     explicit_subtransactions = NIL;
     147             : 
     148          46 :     PLy_execution_contexts = NULL;
     149             : 
     150          46 :     inited = true;
     151             : }
     152             : 
     153             : /*
     154             :  * This should be called only once, from PLy_initialize. Initialize the Python
     155             :  * interpreter and global data.
     156             :  */
     157             : static void
     158          46 : PLy_init_interp(void)
     159             : {
     160             :     static PyObject *PLy_interp_safe_globals = NULL;
     161             :     PyObject   *mainmod;
     162             : 
     163          46 :     mainmod = PyImport_AddModule("__main__");
     164          46 :     if (mainmod == NULL || PyErr_Occurred())
     165           0 :         PLy_elog(ERROR, "could not import \"__main__\" module");
     166          46 :     Py_INCREF(mainmod);
     167          46 :     PLy_interp_globals = PyModule_GetDict(mainmod);
     168          46 :     PLy_interp_safe_globals = PyDict_New();
     169          46 :     if (PLy_interp_safe_globals == NULL)
     170           0 :         PLy_elog(ERROR, NULL);
     171          46 :     PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
     172          46 :     Py_DECREF(mainmod);
     173          46 :     if (PLy_interp_globals == NULL || PyErr_Occurred())
     174           0 :         PLy_elog(ERROR, "could not initialize globals");
     175          46 : }
     176             : 
     177             : Datum
     178         474 : plpython_validator(PG_FUNCTION_ARGS)
     179             : {
     180         474 :     Oid         funcoid = PG_GETARG_OID(0);
     181             :     HeapTuple   tuple;
     182             :     Form_pg_proc procStruct;
     183             :     bool        is_trigger;
     184             : 
     185         474 :     if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
     186           0 :         PG_RETURN_VOID();
     187             : 
     188         474 :     if (!check_function_bodies)
     189           2 :         PG_RETURN_VOID();
     190             : 
     191             :     /* Do this only after making sure we need to do something */
     192         472 :     PLy_initialize();
     193             : 
     194             :     /* Get the new function's pg_proc entry */
     195         472 :     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
     196         472 :     if (!HeapTupleIsValid(tuple))
     197           0 :         elog(ERROR, "cache lookup failed for function %u", funcoid);
     198         472 :     procStruct = (Form_pg_proc) GETSTRUCT(tuple);
     199             : 
     200         472 :     is_trigger = PLy_procedure_is_trigger(procStruct);
     201             : 
     202         472 :     ReleaseSysCache(tuple);
     203             : 
     204             :     /* We can't validate triggers against any particular table ... */
     205         472 :     PLy_procedure_get(funcoid, InvalidOid, is_trigger);
     206             : 
     207         470 :     PG_RETURN_VOID();
     208             : }
     209             : 
     210             : #if PY_MAJOR_VERSION < 3
     211             : Datum
     212           8 : plpython2_validator(PG_FUNCTION_ARGS)
     213             : {
     214             :     /* call plpython validator with our fcinfo so it gets our oid */
     215           8 :     return plpython_validator(fcinfo);
     216             : }
     217             : #endif                          /* PY_MAJOR_VERSION < 3 */
     218             : 
     219             : Datum
     220        1340 : plpython_call_handler(PG_FUNCTION_ARGS)
     221             : {
     222             :     bool        nonatomic;
     223             :     Datum       retval;
     224             :     PLyExecutionContext *exec_ctx;
     225             :     ErrorContextCallback plerrcontext;
     226             : 
     227        1340 :     PLy_initialize();
     228             : 
     229        2786 :     nonatomic = fcinfo->context &&
     230        1354 :         IsA(fcinfo->context, CallContext) &&
     231          14 :         !castNode(CallContext, fcinfo->context)->atomic;
     232             : 
     233             :     /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
     234        1340 :     if (SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0) != SPI_OK_CONNECT)
     235           0 :         elog(ERROR, "SPI_connect failed");
     236             : 
     237             :     /*
     238             :      * Push execution context onto stack.  It is important that this get
     239             :      * popped again, so avoid putting anything that could throw error between
     240             :      * here and the PG_TRY.
     241             :      */
     242        1340 :     exec_ctx = PLy_push_execution_context(!nonatomic);
     243             : 
     244        1340 :     PG_TRY();
     245             :     {
     246        1340 :         Oid         funcoid = fcinfo->flinfo->fn_oid;
     247             :         PLyProcedure *proc;
     248             : 
     249             :         /*
     250             :          * Setup error traceback support for ereport().  Note that the PG_TRY
     251             :          * structure pops this for us again at exit, so we needn't do that
     252             :          * explicitly, nor do we risk the callback getting called after we've
     253             :          * destroyed the exec_ctx.
     254             :          */
     255        1340 :         plerrcontext.callback = plpython_error_callback;
     256        1340 :         plerrcontext.arg = exec_ctx;
     257        1340 :         plerrcontext.previous = error_context_stack;
     258        1340 :         error_context_stack = &plerrcontext;
     259             : 
     260        1340 :         if (CALLED_AS_TRIGGER(fcinfo))
     261          74 :         {
     262          92 :             Relation    tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
     263             :             HeapTuple   trv;
     264             : 
     265          92 :             proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), true);
     266          92 :             exec_ctx->curr_proc = proc;
     267          92 :             trv = PLy_exec_trigger(fcinfo, proc);
     268          74 :             retval = PointerGetDatum(trv);
     269             :         }
     270             :         else
     271             :         {
     272        1248 :             proc = PLy_procedure_get(funcoid, InvalidOid, false);
     273        1242 :             exec_ctx->curr_proc = proc;
     274        1242 :             retval = PLy_exec_function(fcinfo, proc);
     275             :         }
     276             :     }
     277         174 :     PG_CATCH();
     278             :     {
     279         174 :         PLy_pop_execution_context();
     280         174 :         PyErr_Clear();
     281         174 :         PG_RE_THROW();
     282             :     }
     283        1166 :     PG_END_TRY();
     284             : 
     285             :     /* Destroy the execution context */
     286        1166 :     PLy_pop_execution_context();
     287             : 
     288        1166 :     return retval;
     289             : }
     290             : 
     291             : #if PY_MAJOR_VERSION < 3
     292             : Datum
     293           8 : plpython2_call_handler(PG_FUNCTION_ARGS)
     294             : {
     295           8 :     return plpython_call_handler(fcinfo);
     296             : }
     297             : #endif                          /* PY_MAJOR_VERSION < 3 */
     298             : 
     299             : Datum
     300          40 : plpython_inline_handler(PG_FUNCTION_ARGS)
     301             : {
     302          40 :     LOCAL_FCINFO(fake_fcinfo, 0);
     303          40 :     InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
     304             :     FmgrInfo    flinfo;
     305             :     PLyProcedure proc;
     306             :     PLyExecutionContext *exec_ctx;
     307             :     ErrorContextCallback plerrcontext;
     308             : 
     309          40 :     PLy_initialize();
     310             : 
     311             :     /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
     312          40 :     if (SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC) != SPI_OK_CONNECT)
     313           0 :         elog(ERROR, "SPI_connect failed");
     314             : 
     315          40 :     MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
     316          40 :     MemSet(&flinfo, 0, sizeof(flinfo));
     317          40 :     fake_fcinfo->flinfo = &flinfo;
     318          40 :     flinfo.fn_oid = InvalidOid;
     319          40 :     flinfo.fn_mcxt = CurrentMemoryContext;
     320             : 
     321          40 :     MemSet(&proc, 0, sizeof(PLyProcedure));
     322          40 :     proc.mcxt = AllocSetContextCreate(TopMemoryContext,
     323             :                                       "__plpython_inline_block",
     324             :                                       ALLOCSET_DEFAULT_SIZES);
     325          40 :     proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
     326          40 :     proc.langid = codeblock->langOid;
     327             : 
     328             :     /*
     329             :      * This is currently sufficient to get PLy_exec_function to work, but
     330             :      * someday we might need to be honest and use PLy_output_setup_func.
     331             :      */
     332          40 :     proc.result.typoid = VOIDOID;
     333             : 
     334             :     /*
     335             :      * Push execution context onto stack.  It is important that this get
     336             :      * popped again, so avoid putting anything that could throw error between
     337             :      * here and the PG_TRY.
     338             :      */
     339          40 :     exec_ctx = PLy_push_execution_context(codeblock->atomic);
     340             : 
     341          40 :     PG_TRY();
     342             :     {
     343             :         /*
     344             :          * Setup error traceback support for ereport().
     345             :          * plpython_inline_error_callback doesn't currently need exec_ctx, but
     346             :          * for consistency with plpython_call_handler we do it the same way.
     347             :          */
     348          40 :         plerrcontext.callback = plpython_inline_error_callback;
     349          40 :         plerrcontext.arg = exec_ctx;
     350          40 :         plerrcontext.previous = error_context_stack;
     351          40 :         error_context_stack = &plerrcontext;
     352             : 
     353          40 :         PLy_procedure_compile(&proc, codeblock->source_text);
     354          40 :         exec_ctx->curr_proc = &proc;
     355          40 :         PLy_exec_function(fake_fcinfo, &proc);
     356             :     }
     357          20 :     PG_CATCH();
     358             :     {
     359          20 :         PLy_pop_execution_context();
     360          20 :         PLy_procedure_delete(&proc);
     361          20 :         PyErr_Clear();
     362          20 :         PG_RE_THROW();
     363             :     }
     364          20 :     PG_END_TRY();
     365             : 
     366             :     /* Destroy the execution context */
     367          20 :     PLy_pop_execution_context();
     368             : 
     369             :     /* Now clean up the transient procedure we made */
     370          20 :     PLy_procedure_delete(&proc);
     371             : 
     372          20 :     PG_RETURN_VOID();
     373             : }
     374             : 
     375             : #if PY_MAJOR_VERSION < 3
     376             : Datum
     377           2 : plpython2_inline_handler(PG_FUNCTION_ARGS)
     378             : {
     379           2 :     return plpython_inline_handler(fcinfo);
     380             : }
     381             : #endif                          /* PY_MAJOR_VERSION < 3 */
     382             : 
     383             : static bool
     384         472 : PLy_procedure_is_trigger(Form_pg_proc procStruct)
     385             : {
     386         944 :     return (procStruct->prorettype == TRIGGEROID ||
     387         426 :             (procStruct->prorettype == OPAQUEOID &&
     388           0 :              procStruct->pronargs == 0));
     389             : }
     390             : 
     391             : static void
     392         882 : plpython_error_callback(void *arg)
     393             : {
     394         882 :     PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
     395             : 
     396         882 :     if (exec_ctx->curr_proc)
     397             :     {
     398         876 :         if (exec_ctx->curr_proc->is_procedure)
     399           4 :             errcontext("PL/Python procedure \"%s\"",
     400             :                        PLy_procedure_name(exec_ctx->curr_proc));
     401             :         else
     402         872 :             errcontext("PL/Python function \"%s\"",
     403             :                        PLy_procedure_name(exec_ctx->curr_proc));
     404             :     }
     405         882 : }
     406             : 
     407             : static void
     408          46 : plpython_inline_error_callback(void *arg)
     409             : {
     410          46 :     errcontext("PL/Python anonymous code block");
     411          46 : }
     412             : 
     413             : PLyExecutionContext *
     414        2794 : PLy_current_execution_context(void)
     415             : {
     416        2794 :     if (PLy_execution_contexts == NULL)
     417           0 :         elog(ERROR, "no Python function is currently executing");
     418             : 
     419        2794 :     return PLy_execution_contexts;
     420             : }
     421             : 
     422             : MemoryContext
     423        1556 : PLy_get_scratch_context(PLyExecutionContext *context)
     424             : {
     425             :     /*
     426             :      * A scratch context might never be needed in a given plpython procedure,
     427             :      * so allocate it on first request.
     428             :      */
     429        1556 :     if (context->scratch_ctx == NULL)
     430         866 :         context->scratch_ctx =
     431         866 :             AllocSetContextCreate(TopTransactionContext,
     432             :                                   "PL/Python scratch context",
     433             :                                   ALLOCSET_DEFAULT_SIZES);
     434        1556 :     return context->scratch_ctx;
     435             : }
     436             : 
     437             : static PLyExecutionContext *
     438        1380 : PLy_push_execution_context(bool atomic_context)
     439             : {
     440             :     PLyExecutionContext *context;
     441             : 
     442             :     /* Pick a memory context similar to what SPI uses. */
     443        1380 :     context = (PLyExecutionContext *)
     444        1380 :         MemoryContextAlloc(atomic_context ? TopTransactionContext : PortalContext,
     445             :                            sizeof(PLyExecutionContext));
     446        1380 :     context->curr_proc = NULL;
     447        1380 :     context->scratch_ctx = NULL;
     448        1380 :     context->next = PLy_execution_contexts;
     449        1380 :     PLy_execution_contexts = context;
     450        1380 :     return context;
     451             : }
     452             : 
     453             : static void
     454        1380 : PLy_pop_execution_context(void)
     455             : {
     456        1380 :     PLyExecutionContext *context = PLy_execution_contexts;
     457             : 
     458        1380 :     if (context == NULL)
     459           0 :         elog(ERROR, "no Python function is currently executing");
     460             : 
     461        1380 :     PLy_execution_contexts = context->next;
     462             : 
     463        1380 :     if (context->scratch_ctx)
     464         832 :         MemoryContextDelete(context->scratch_ctx);
     465        1380 :     pfree(context);
     466        1380 : }

Generated by: LCOV version 1.13