PostgreSQL Source Code  git master
plpy_main.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "executor/spi.h"
#include "miscadmin.h"
#include "plpy_elog.h"
#include "plpy_exec.h"
#include "plpy_main.h"
#include "plpy_plpymodule.h"
#include "plpy_procedure.h"
#include "plpy_subxactobject.h"
#include "plpython.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for plpy_main.c:

Go to the source code of this file.

Functions

void _PG_init (void)
 
 PG_FUNCTION_INFO_V1 (plpython3_validator)
 
 PG_FUNCTION_INFO_V1 (plpython3_call_handler)
 
 PG_FUNCTION_INFO_V1 (plpython3_inline_handler)
 
static bool PLy_procedure_is_trigger (Form_pg_proc procStruct)
 
static void plpython_error_callback (void *arg)
 
static void plpython_inline_error_callback (void *arg)
 
static void PLy_init_interp (void)
 
static PLyExecutionContextPLy_push_execution_context (bool atomic_context)
 
static void PLy_pop_execution_context (void)
 
static void PLy_initialize (void)
 
Datum plpython3_validator (PG_FUNCTION_ARGS)
 
Datum plpython3_call_handler (PG_FUNCTION_ARGS)
 
Datum plpython3_inline_handler (PG_FUNCTION_ARGS)
 
PLyExecutionContextPLy_current_execution_context (void)
 
MemoryContext PLy_get_scratch_context (PLyExecutionContext *context)
 

Variables

 PG_MODULE_MAGIC
 
static int * plpython_version_bitmask_ptr = NULL
 
static int plpython_version_bitmask = 0
 
PyObject * PLy_interp_globals = NULL
 
static PLyExecutionContextPLy_execution_contexts = NULL
 

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 60 of file plpy_main.c.

61 {
62  int **bitmask_ptr;
63 
64  /*
65  * Set up a shared bitmask variable telling which Python version(s) are
66  * loaded into this process's address space. If there's more than one, we
67  * cannot call into libpython for fear of causing crashes. But postpone
68  * the actual failure for later, so that operations like pg_restore can
69  * load more than one plpython library so long as they don't try to do
70  * anything much with the language.
71  *
72  * While we only support Python 3 these days, somebody might create an
73  * out-of-tree version adding back support for Python 2. Conflicts with
74  * such an extension should be detected.
75  */
76  bitmask_ptr = (int **) find_rendezvous_variable("plpython_version_bitmask");
77  if (!(*bitmask_ptr)) /* am I the first? */
78  *bitmask_ptr = &plpython_version_bitmask;
79  /* Retain pointer to the agreed-on shared variable ... */
80  plpython_version_bitmask_ptr = *bitmask_ptr;
81  /* ... and announce my presence */
82  *plpython_version_bitmask_ptr |= (1 << PY_MAJOR_VERSION);
83 
84  /*
85  * This should be safe even in the presence of conflicting plpythons, and
86  * it's necessary to do it before possibly throwing a conflict error, or
87  * the error message won't get localized.
88  */
90 }
void ** find_rendezvous_variable(const char *varName)
Definition: dfmgr.c:616
#define TEXTDOMAIN
Definition: elog.h:146
void pg_bindtextdomain(const char *domain)
Definition: miscinit.c:1720
static int plpython_version_bitmask
Definition: plpy_main.c:50
static int * plpython_version_bitmask_ptr
Definition: plpy_main.c:49

References find_rendezvous_variable(), pg_bindtextdomain(), plpython_version_bitmask, plpython_version_bitmask_ptr, and TEXTDOMAIN.

◆ PG_FUNCTION_INFO_V1() [1/3]

PG_FUNCTION_INFO_V1 ( plpython3_call_handler  )

◆ PG_FUNCTION_INFO_V1() [2/3]

PG_FUNCTION_INFO_V1 ( plpython3_inline_handler  )

◆ PG_FUNCTION_INFO_V1() [3/3]

PG_FUNCTION_INFO_V1 ( plpython3_validator  )

◆ plpython3_call_handler()

Datum plpython3_call_handler ( PG_FUNCTION_ARGS  )

Definition at line 193 of file plpy_main.c.

194 {
195  bool nonatomic;
196  Datum retval;
197  PLyExecutionContext *exec_ctx;
198  ErrorContextCallback plerrcontext;
199 
200  PLy_initialize();
201 
202  nonatomic = fcinfo->context &&
203  IsA(fcinfo->context, CallContext) &&
204  !castNode(CallContext, fcinfo->context)->atomic;
205 
206  /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
207  if (SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0) != SPI_OK_CONNECT)
208  elog(ERROR, "SPI_connect failed");
209 
210  /*
211  * Push execution context onto stack. It is important that this get
212  * popped again, so avoid putting anything that could throw error between
213  * here and the PG_TRY.
214  */
215  exec_ctx = PLy_push_execution_context(!nonatomic);
216 
217  PG_TRY();
218  {
219  Oid funcoid = fcinfo->flinfo->fn_oid;
220  PLyProcedure *proc;
221 
222  /*
223  * Setup error traceback support for ereport(). Note that the PG_TRY
224  * structure pops this for us again at exit, so we needn't do that
225  * explicitly, nor do we risk the callback getting called after we've
226  * destroyed the exec_ctx.
227  */
228  plerrcontext.callback = plpython_error_callback;
229  plerrcontext.arg = exec_ctx;
230  plerrcontext.previous = error_context_stack;
231  error_context_stack = &plerrcontext;
232 
233  if (CALLED_AS_TRIGGER(fcinfo))
234  {
235  Relation tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
236  HeapTuple trv;
237 
238  proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), true);
239  exec_ctx->curr_proc = proc;
240  trv = PLy_exec_trigger(fcinfo, proc);
241  retval = PointerGetDatum(trv);
242  }
243  else
244  {
245  proc = PLy_procedure_get(funcoid, InvalidOid, false);
246  exec_ctx->curr_proc = proc;
247  retval = PLy_exec_function(fcinfo, proc);
248  }
249  }
250  PG_CATCH();
251  {
253  PyErr_Clear();
254  PG_RE_THROW();
255  }
256  PG_END_TRY();
257 
258  /* Destroy the execution context */
260 
261  return retval;
262 }
ErrorContextCallback * error_context_stack
Definition: elog.c:93
#define PG_RE_THROW()
Definition: elog.h:340
#define PG_END_TRY()
Definition: elog.h:324
#define PG_TRY()
Definition: elog.h:299
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define PG_CATCH()
Definition: elog.h:309
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
#define castNode(_type_, nodeptr)
Definition: nodes.h:642
Datum PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
Definition: plpy_exec.c:55
HeapTuple PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
Definition: plpy_exec.c:305
static void PLy_initialize(void)
Definition: plpy_main.c:97
static void plpython_error_callback(void *arg)
Definition: plpy_main.c:347
static PLyExecutionContext * PLy_push_execution_context(bool atomic_context)
Definition: plpy_main.c:393
static void PLy_pop_execution_context(void)
Definition: plpy_main.c:409
PLyProcedure * PLy_procedure_get(Oid fn_oid, Oid fn_rel, bool is_trigger)
uintptr_t Datum
Definition: postgres.h:411
#define PointerGetDatum(X)
Definition: postgres.h:600
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:489
int SPI_connect_ext(int options)
Definition: spi.c:101
#define SPI_OPT_NONATOMIC
Definition: spi.h:101
#define SPI_OK_CONNECT
Definition: spi.h:82
struct ErrorContextCallback * previous
Definition: elog.h:232
void(* callback)(void *arg)
Definition: elog.h:233
PLyProcedure * curr_proc
Definition: plpy_main.h:20
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:26

References ErrorContextCallback::arg, ErrorContextCallback::callback, CALLED_AS_TRIGGER, castNode, PLyExecutionContext::curr_proc, elog, ERROR, error_context_stack, InvalidOid, IsA, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, plpython_error_callback(), PLy_exec_function(), PLy_exec_trigger(), PLy_initialize(), PLy_pop_execution_context(), PLy_procedure_get(), PLy_push_execution_context(), PointerGetDatum, ErrorContextCallback::previous, RelationGetRelid, SPI_connect_ext(), SPI_OK_CONNECT, and SPI_OPT_NONATOMIC.

◆ plpython3_inline_handler()

Datum plpython3_inline_handler ( PG_FUNCTION_ARGS  )

Definition at line 265 of file plpy_main.c.

266 {
267  LOCAL_FCINFO(fake_fcinfo, 0);
269  FmgrInfo flinfo;
270  PLyProcedure proc;
271  PLyExecutionContext *exec_ctx;
272  ErrorContextCallback plerrcontext;
273 
274  PLy_initialize();
275 
276  /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
277  if (SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC) != SPI_OK_CONNECT)
278  elog(ERROR, "SPI_connect failed");
279 
280  MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
281  MemSet(&flinfo, 0, sizeof(flinfo));
282  fake_fcinfo->flinfo = &flinfo;
283  flinfo.fn_oid = InvalidOid;
284  flinfo.fn_mcxt = CurrentMemoryContext;
285 
286  MemSet(&proc, 0, sizeof(PLyProcedure));
288  "__plpython_inline_block",
290  proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
291  proc.langid = codeblock->langOid;
292 
293  /*
294  * This is currently sufficient to get PLy_exec_function to work, but
295  * someday we might need to be honest and use PLy_output_setup_func.
296  */
297  proc.result.typoid = VOIDOID;
298 
299  /*
300  * Push execution context onto stack. It is important that this get
301  * popped again, so avoid putting anything that could throw error between
302  * here and the PG_TRY.
303  */
304  exec_ctx = PLy_push_execution_context(codeblock->atomic);
305 
306  PG_TRY();
307  {
308  /*
309  * Setup error traceback support for ereport().
310  * plpython_inline_error_callback doesn't currently need exec_ctx, but
311  * for consistency with plpython_call_handler we do it the same way.
312  */
314  plerrcontext.arg = exec_ctx;
315  plerrcontext.previous = error_context_stack;
316  error_context_stack = &plerrcontext;
317 
318  PLy_procedure_compile(&proc, codeblock->source_text);
319  exec_ctx->curr_proc = &proc;
320  PLy_exec_function(fake_fcinfo, &proc);
321  }
322  PG_CATCH();
323  {
325  PLy_procedure_delete(&proc);
326  PyErr_Clear();
327  PG_RE_THROW();
328  }
329  PG_END_TRY();
330 
331  /* Destroy the execution context */
333 
334  /* Now clean up the transient procedure we made */
335  PLy_procedure_delete(&proc);
336 
337  PG_RETURN_VOID();
338 }
#define MemSet(start, val, len)
Definition: c.h:1008
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
MemoryContext TopMemoryContext
Definition: mcxt.c:48
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1292
#define AllocSetContextCreate
Definition: memutils.h:173
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
static void plpython_inline_error_callback(void *arg)
Definition: plpy_main.c:363
void PLy_procedure_compile(PLyProcedure *proc, const char *src)
void PLy_procedure_delete(PLyProcedure *proc)
#define DatumGetPointer(X)
Definition: postgres.h:593
Definition: fmgr.h:57
MemoryContext fn_mcxt
Definition: fmgr.h:65
Oid fn_oid
Definition: fmgr.h:59
char * source_text
Definition: parsenodes.h:3369
PLyObToDatum result
MemoryContext mcxt

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ErrorContextCallback::arg, InlineCodeBlock::atomic, ErrorContextCallback::callback, PLyExecutionContext::curr_proc, CurrentMemoryContext, DatumGetPointer, elog, ERROR, error_context_stack, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, InvalidOid, PLyProcedure::langid, InlineCodeBlock::langOid, LOCAL_FCINFO, PLyProcedure::mcxt, MemoryContextStrdup(), MemSet, PG_CATCH, PG_END_TRY, PG_GETARG_DATUM, PG_RE_THROW, PG_RETURN_VOID, PG_TRY, plpython_inline_error_callback(), PLy_exec_function(), PLy_initialize(), PLy_pop_execution_context(), PLy_procedure_compile(), PLy_procedure_delete(), PLy_push_execution_context(), ErrorContextCallback::previous, PLyProcedure::pyname, PLyProcedure::result, SizeForFunctionCallInfo, InlineCodeBlock::source_text, SPI_connect_ext(), SPI_OK_CONNECT, SPI_OPT_NONATOMIC, TopMemoryContext, and PLyObToDatum::typoid.

◆ plpython3_validator()

Datum plpython3_validator ( PG_FUNCTION_ARGS  )

Definition at line 160 of file plpy_main.c.

161 {
162  Oid funcoid = PG_GETARG_OID(0);
163  HeapTuple tuple;
164  Form_pg_proc procStruct;
165  bool is_trigger;
166 
167  if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
168  PG_RETURN_VOID();
169 
171  PG_RETURN_VOID();
172 
173  /* Do this only after making sure we need to do something */
174  PLy_initialize();
175 
176  /* Get the new function's pg_proc entry */
177  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
178  if (!HeapTupleIsValid(tuple))
179  elog(ERROR, "cache lookup failed for function %u", funcoid);
180  procStruct = (Form_pg_proc) GETSTRUCT(tuple);
181 
182  is_trigger = PLy_procedure_is_trigger(procStruct);
183 
184  ReleaseSysCache(tuple);
185 
186  /* We can't validate triggers against any particular table ... */
187  PLy_procedure_get(funcoid, InvalidOid, is_trigger);
188 
189  PG_RETURN_VOID();
190 }
bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid)
Definition: fmgr.c:2021
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
bool check_function_bodies
Definition: guc.c:626
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
static bool PLy_procedure_is_trigger(Form_pg_proc procStruct)
Definition: plpy_main.c:341
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ PROCOID
Definition: syscache.h:79

References check_function_bodies, CheckFunctionValidatorAccess(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, PG_GETARG_OID, PG_RETURN_VOID, PLy_initialize(), PLy_procedure_get(), PLy_procedure_is_trigger(), PROCOID, ReleaseSysCache(), and SearchSysCache1().

◆ plpython_error_callback()

static void plpython_error_callback ( void *  arg)
static

Definition at line 347 of file plpy_main.c.

348 {
350 
351  if (exec_ctx->curr_proc)
352  {
353  if (exec_ctx->curr_proc->is_procedure)
354  errcontext("PL/Python procedure \"%s\"",
355  PLy_procedure_name(exec_ctx->curr_proc));
356  else
357  errcontext("PL/Python function \"%s\"",
358  PLy_procedure_name(exec_ctx->curr_proc));
359  }
360 }
#define errcontext
Definition: elog.h:190
void * arg
char * PLy_procedure_name(PLyProcedure *proc)

References arg, PLyExecutionContext::curr_proc, errcontext, PLyProcedure::is_procedure, and PLy_procedure_name().

Referenced by plpython3_call_handler().

◆ plpython_inline_error_callback()

static void plpython_inline_error_callback ( void *  arg)
static

Definition at line 363 of file plpy_main.c.

364 {
365  errcontext("PL/Python anonymous code block");
366 }

References errcontext.

Referenced by plpython3_inline_handler().

◆ PLy_current_execution_context()

◆ PLy_get_scratch_context()

MemoryContext PLy_get_scratch_context ( PLyExecutionContext context)

Definition at line 378 of file plpy_main.c.

379 {
380  /*
381  * A scratch context might never be needed in a given plpython procedure,
382  * so allocate it on first request.
383  */
384  if (context->scratch_ctx == NULL)
385  context->scratch_ctx =
387  "PL/Python scratch context",
389  return context->scratch_ctx;
390 }
MemoryContext TopTransactionContext
Definition: mcxt.c:53
MemoryContext scratch_ctx
Definition: plpy_main.h:21

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, PLyExecutionContext::scratch_ctx, and TopTransactionContext.

Referenced by PLy_input_convert(), and PLy_input_from_tuple().

◆ PLy_init_interp()

static void PLy_init_interp ( void  )
static

Definition at line 140 of file plpy_main.c.

141 {
142  static PyObject *PLy_interp_safe_globals = NULL;
143  PyObject *mainmod;
144 
145  mainmod = PyImport_AddModule("__main__");
146  if (mainmod == NULL || PyErr_Occurred())
147  PLy_elog(ERROR, "could not import \"__main__\" module");
148  Py_INCREF(mainmod);
149  PLy_interp_globals = PyModule_GetDict(mainmod);
150  PLy_interp_safe_globals = PyDict_New();
151  if (PLy_interp_safe_globals == NULL)
152  PLy_elog(ERROR, NULL);
153  PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
154  Py_DECREF(mainmod);
155  if (PLy_interp_globals == NULL || PyErr_Occurred())
156  PLy_elog(ERROR, "could not initialize globals");
157 }
#define PLy_elog
PyObject * PLy_interp_globals
Definition: plpy_main.c:53

References ERROR, PLy_elog, and PLy_interp_globals.

Referenced by PLy_initialize().

◆ PLy_initialize()

static void PLy_initialize ( void  )
static

Definition at line 97 of file plpy_main.c.

98 {
99  static bool inited = false;
100 
101  /*
102  * Check for multiple Python libraries before actively doing anything with
103  * libpython. This must be repeated on each entry to PL/Python, in case a
104  * conflicting library got loaded since we last looked.
105  *
106  * It is attractive to weaken this error from FATAL to ERROR, but there
107  * would be corner cases, so it seems best to be conservative.
108  */
109  if (*plpython_version_bitmask_ptr != (1 << PY_MAJOR_VERSION))
110  ereport(FATAL,
111  (errmsg("multiple Python libraries are present in session"),
112  errdetail("Only one Python major version can be used in one session.")));
113 
114  /* The rest should only be done once per session */
115  if (inited)
116  return;
117 
118  PyImport_AppendInittab("plpy", PyInit_plpy);
119  Py_Initialize();
120  PyImport_ImportModule("plpy");
121  PLy_init_interp();
122  PLy_init_plpy();
123  if (PyErr_Occurred())
124  PLy_elog(FATAL, "untrapped error in initialization");
125 
127 
129 
130  PLy_execution_contexts = NULL;
131 
132  inited = true;
133 }
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define FATAL
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:143
#define NIL
Definition: pg_list.h:65
static void PLy_init_interp(void)
Definition: plpy_main.c:140
PyMODINIT_FUNC PyInit_plpy(void)
void PLy_init_plpy(void)
void init_procedure_caches(void)
List * explicit_subtransactions

References ereport, errdetail(), errmsg(), explicit_subtransactions, FATAL, init_procedure_caches(), NIL, plpython_version_bitmask_ptr, PLy_elog, PLy_execution_contexts, PLy_init_interp(), PLy_init_plpy(), and PyInit_plpy().

Referenced by plpython3_call_handler(), plpython3_inline_handler(), and plpython3_validator().

◆ PLy_pop_execution_context()

static void PLy_pop_execution_context ( void  )
static

Definition at line 409 of file plpy_main.c.

410 {
412 
413  if (context == NULL)
414  elog(ERROR, "no Python function is currently executing");
415 
416  PLy_execution_contexts = context->next;
417 
418  if (context->scratch_ctx)
420  pfree(context);
421 }
void pfree(void *pointer)
Definition: mcxt.c:1175
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
struct PLyExecutionContext * next
Definition: plpy_main.h:22

References elog, ERROR, MemoryContextDelete(), PLyExecutionContext::next, pfree(), PLy_execution_contexts, and PLyExecutionContext::scratch_ctx.

Referenced by plpython3_call_handler(), and plpython3_inline_handler().

◆ PLy_procedure_is_trigger()

static bool PLy_procedure_is_trigger ( Form_pg_proc  procStruct)
static

Definition at line 341 of file plpy_main.c.

342 {
343  return (procStruct->prorettype == TRIGGEROID);
344 }

Referenced by plpython3_validator().

◆ PLy_push_execution_context()

static PLyExecutionContext * PLy_push_execution_context ( bool  atomic_context)
static

Definition at line 393 of file plpy_main.c.

394 {
395  PLyExecutionContext *context;
396 
397  /* Pick a memory context similar to what SPI uses. */
398  context = (PLyExecutionContext *)
400  sizeof(PLyExecutionContext));
401  context->curr_proc = NULL;
402  context->scratch_ctx = NULL;
403  context->next = PLy_execution_contexts;
404  PLy_execution_contexts = context;
405  return context;
406 }
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
MemoryContext PortalContext
Definition: mcxt.c:57

References PLyExecutionContext::curr_proc, MemoryContextAlloc(), PLyExecutionContext::next, PLy_execution_contexts, PortalContext, PLyExecutionContext::scratch_ctx, and TopTransactionContext.

Referenced by plpython3_call_handler(), and plpython3_inline_handler().

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 33 of file plpy_main.c.

◆ plpython_version_bitmask

int plpython_version_bitmask = 0
static

Definition at line 50 of file plpy_main.c.

Referenced by _PG_init().

◆ plpython_version_bitmask_ptr

int* plpython_version_bitmask_ptr = NULL
static

Definition at line 49 of file plpy_main.c.

Referenced by _PG_init(), and PLy_initialize().

◆ PLy_execution_contexts

PLyExecutionContext* PLy_execution_contexts = NULL
static

◆ PLy_interp_globals

PyObject* PLy_interp_globals = NULL

Definition at line 53 of file plpy_main.c.

Referenced by PLy_init_interp(), and PLy_procedure_compile().