/* * Push a new audit event onto the stack and create a new memory context to * store it. */ static AuditEventStackItem * stack_push() { MemoryContext contextAudit; MemoryContext contextOld; AuditEventStackItem *stackItem; /* * Create a new memory context to contain the stack item. This will be * free'd on stack_pop, or by our callback when the parent context is * destroyed. */ contextAudit = AllocSetContextCreate(CurrentMemoryContext, "pg_audit stack context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* Save the old context to switch back to at the end */ contextOld = MemoryContextSwitchTo(contextAudit); /* Create our new stack item in our context */ stackItem = palloc0(sizeof(AuditEventStackItem)); stackItem->contextAudit = contextAudit; stackItem->stackId = ++stackTotal; /* * Setup a callback in case an error happens. stack_free() will truncate * the stack at this item. */ stackItem->contextCallback.func = stack_free; stackItem->contextCallback.arg = (void *) stackItem; MemoryContextRegisterResetCallback(contextAudit, &stackItem->contextCallback); /* Push new item onto the stack */ if (auditEventStack != NULL) stackItem->next = auditEventStack; else stackItem->next = NULL; auditEventStack = stackItem; MemoryContextSwitchTo(contextOld); return stackItem; }
/* function subhandler */ Datum PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc) { Datum rv; PyObject *volatile plargs = NULL; PyObject *volatile plrv = NULL; FuncCallContext *volatile funcctx = NULL; PLySRFState *volatile srfstate = NULL; ErrorContextCallback plerrcontext; /* * If the function is called recursively, we must push outer-level * arguments into the stack. This must be immediately before the PG_TRY * to ensure that the corresponding pop happens. */ PLy_global_args_push(proc); PG_TRY(); { if (proc->is_setof) { /* First Call setup */ if (SRF_IS_FIRSTCALL()) { funcctx = SRF_FIRSTCALL_INIT(); srfstate = (PLySRFState *) MemoryContextAllocZero(funcctx->multi_call_memory_ctx, sizeof(PLySRFState)); /* Immediately register cleanup callback */ srfstate->callback.func = plpython_srf_cleanup_callback; srfstate->callback.arg = (void *) srfstate; MemoryContextRegisterResetCallback(funcctx->multi_call_memory_ctx, &srfstate->callback); funcctx->user_fctx = (void *) srfstate; } /* Every call setup */ funcctx = SRF_PERCALL_SETUP(); Assert(funcctx != NULL); srfstate = (PLySRFState *) funcctx->user_fctx; } if (srfstate == NULL || srfstate->iter == NULL) { /* * Non-SETOF function or first time for SETOF function: build * args, then actually execute the function. */ plargs = PLy_function_build_args(fcinfo, proc); plrv = PLy_procedure_call(proc, "args", plargs); Assert(plrv != NULL); } else { /* * Second or later call for a SETOF function: restore arguments in * globals dict to what they were when we left off. We must do * this in case multiple evaluations of the same SETOF function * are interleaved. It's a bit annoying, since the iterator may * not look at the arguments at all, but we have no way to know * that. Fortunately this isn't terribly expensive. */ if (srfstate->savedargs) PLy_function_restore_args(proc, srfstate->savedargs); srfstate->savedargs = NULL; /* deleted by restore_args */ } /* * If it returns a set, call the iterator to get the next return item. * We stay in the SPI context while doing this, because PyIter_Next() * calls back into Python code which might contain SPI calls. */ if (proc->is_setof) { if (srfstate->iter == NULL) { /* first time -- do checks and setup */ ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo; if (!rsi || !IsA(rsi, ReturnSetInfo) || (rsi->allowedModes & SFRM_ValuePerCall) == 0) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("unsupported set function return mode"), errdetail("PL/Python set-returning functions only support returning one value per call."))); } rsi->returnMode = SFRM_ValuePerCall; /* Make iterator out of returned object */ srfstate->iter = PyObject_GetIter(plrv); Py_DECREF(plrv); plrv = NULL; if (srfstate->iter == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("returned object cannot be iterated"), errdetail("PL/Python set-returning functions must return an iterable object."))); } /* Fetch next from iterator */ plrv = PyIter_Next(srfstate->iter); if (plrv == NULL) { /* Iterator is exhausted or error happened */ bool has_error = (PyErr_Occurred() != NULL); Py_DECREF(srfstate->iter); srfstate->iter = NULL; if (has_error) PLy_elog(ERROR, "error fetching next item from iterator"); /* Pass a null through the data-returning steps below */ Py_INCREF(Py_None); plrv = Py_None; } else { /* * This won't be last call, so save argument values. We do * this again each time in case the iterator is changing those * values. */ srfstate->savedargs = PLy_function_save_args(proc); } } /* * Disconnect from SPI manager and then create the return values datum * (if the input function does a palloc for it this must not be * allocated in the SPI memory context because SPI_finish would free * it). */ if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); plerrcontext.callback = plpython_return_error_callback; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; /* * If the function is declared to return void, the Python return value * must be None. For void-returning functions, we also treat a None * return value as a special "void datum" rather than NULL (as is the * case for non-void-returning functions). */ if (proc->result.out.d.typoid == VOIDOID) { if (plrv != Py_None) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("PL/Python function with return type \"void\" did not return None"))); fcinfo->isnull = false; rv = (Datum) 0; } else if (plrv == Py_None) { fcinfo->isnull = true; /* * In a SETOF function, the iteration-ending null isn't a real * value; don't pass it through the input function, which might * complain. */ if (srfstate && srfstate->iter == NULL) rv = (Datum) 0; else if (proc->result.is_rowtype < 1) rv = InputFunctionCall(&proc->result.out.d.typfunc, NULL, proc->result.out.d.typioparam, -1); else /* Tuple as None */ rv = (Datum) NULL; } else if (proc->result.is_rowtype >= 1) { TupleDesc desc; /* make sure it's not an unnamed record */ Assert((proc->result.out.d.typoid == RECORDOID && proc->result.out.d.typmod != -1) || (proc->result.out.d.typoid != RECORDOID && proc->result.out.d.typmod == -1)); desc = lookup_rowtype_tupdesc(proc->result.out.d.typoid, proc->result.out.d.typmod); rv = PLyObject_ToCompositeDatum(&proc->result, desc, plrv); fcinfo->isnull = (rv == (Datum) NULL); ReleaseTupleDesc(desc); } else { fcinfo->isnull = false; rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv); } } PG_CATCH(); { /* Pop old arguments from the stack if they were pushed above */ PLy_global_args_pop(proc); Py_XDECREF(plargs); Py_XDECREF(plrv); /* * If there was an error within a SRF, the iterator might not have * been exhausted yet. Clear it so the next invocation of the * function will start the iteration again. (This code is probably * unnecessary now; plpython_srf_cleanup_callback should take care of * cleanup. But it doesn't hurt anything to do it here.) */ if (srfstate) { Py_XDECREF(srfstate->iter); srfstate->iter = NULL; /* And drop any saved args; we won't need them */ if (srfstate->savedargs) PLy_function_drop_args(srfstate->savedargs); srfstate->savedargs = NULL; } PG_RE_THROW(); } PG_END_TRY(); error_context_stack = plerrcontext.previous; /* Pop old arguments from the stack if they were pushed above */ PLy_global_args_pop(proc); Py_XDECREF(plargs); Py_DECREF(plrv); if (srfstate) { /* We're in a SRF, exit appropriately */ if (srfstate->iter == NULL) { /* Iterator exhausted, so we're done */ SRF_RETURN_DONE(funcctx); } else if (fcinfo->isnull) SRF_RETURN_NEXT_NULL(funcctx); else SRF_RETURN_NEXT(funcctx, rv); } /* Plain function, just return the Datum value (possibly null) */ return rv; }