Datum Function_invoke(Function self, PG_FUNCTION_ARGS) { Datum retVal; int32 top; jvalue* args; Type invokerType; fcinfo->isnull = false; currentInvocation->function = self; if(self->isUDT) return self->func.udt.udtFunction(self->func.udt.udt, fcinfo); if(self->func.nonudt.isMultiCall && SRF_IS_FIRSTCALL()) Invocation_assertDisconnect(); top = self->func.nonudt.numParams; /* Leave room for one extra parameter. Functions that returns unmapped * composite types must have a single row ResultSet as an OUT parameter. */ args = (jvalue*)palloc((top + 1) * sizeof(jvalue)); invokerType = self->func.nonudt.returnType; if(top > 0) { int32 idx; Type* types = self->func.nonudt.paramTypes; /* a class loader or other mechanism might have connected already. This * connection must be dropped since its parent context is wrong. */ if(Type_isDynamic(invokerType)) invokerType = Type_getRealType(invokerType, get_fn_expr_rettype(fcinfo->flinfo), self->func.nonudt.typeMap); for(idx = 0; idx < top; ++idx) { if(PG_ARGISNULL(idx)) /* * Set this argument to zero (or null in case of object) */ args[idx].j = 0L; else { Type paramType = types[idx]; if(Type_isDynamic(paramType)) paramType = Type_getRealType(paramType, get_fn_expr_argtype(fcinfo->flinfo, idx), self->func.nonudt.typeMap); args[idx] = Type_coerceDatum(paramType, PG_GETARG_DATUM(idx)); } } } retVal = self->func.nonudt.isMultiCall ? Type_invokeSRF(invokerType, self->clazz, self->func.nonudt.method, args, fcinfo) : Type_invoke(invokerType, self->clazz, self->func.nonudt.method, args, fcinfo); pfree(args); return retVal; }
static void _closeIteration(CallContextData* ctxData) { currentInvocation->hasConnected = ctxData->hasConnected; currentInvocation->invocation = ctxData->invocation; Type_closeSRF(ctxData->elemType, ctxData->rowProducer); JNI_deleteGlobalRef(ctxData->rowProducer); if(ctxData->rowCollector != 0) JNI_deleteGlobalRef(ctxData->rowCollector); MemoryContextDelete(ctxData->rowContext); if(ctxData->hasConnected && ctxData->spiContext != 0) { /* Connect during SRF_IS_FIRSTCALL(). Switch context back to what * it was at that time and disconnect. */ MemoryContext currCtx = MemoryContextSwitchTo(ctxData->spiContext); Invocation_assertDisconnect(); MemoryContextSwitchTo(currCtx); } }
Datum Type_invokeSRF(Type self, jclass cls, jmethodID method, jvalue* args, PG_FUNCTION_ARGS) { bool hasRow; CallContextData* ctxData; FuncCallContext* context; MemoryContext currCtx; /* stuff done only on the first call of the function */ if(SRF_IS_FIRSTCALL()) { jobject tmp; /* create a function context for cross-call persistence */ context = SRF_FIRSTCALL_INIT(); currCtx = MemoryContextSwitchTo(context->multi_call_memory_ctx); /* Call the declared Java function. It returns an instance that can produce * the rows. */ tmp = Type_getSRFProducer(self, cls, method, args); if(tmp == 0) { Invocation_assertDisconnect(); MemoryContextSwitchTo(currCtx); fcinfo->isnull = true; SRF_RETURN_DONE(context); } ctxData = (CallContextData*)palloc(sizeof(CallContextData)); context->user_fctx = ctxData; ctxData->elemType = self; ctxData->rowProducer = JNI_newGlobalRef(tmp); JNI_deleteLocalRef(tmp); /* Some row producers will need a writable result set in order * to produce the row. If one is needed, it's created here. */ tmp = Type_getSRFCollector(self, fcinfo); if(tmp == 0) ctxData->rowCollector = 0; else { ctxData->rowCollector = JNI_newGlobalRef(tmp); JNI_deleteLocalRef(tmp); } ctxData->trusted = currentInvocation->trusted; ctxData->hasConnected = currentInvocation->hasConnected; ctxData->invocation = currentInvocation->invocation; if(ctxData->hasConnected) ctxData->spiContext = CurrentMemoryContext; else ctxData->spiContext = 0; ctxData->rowContext = AllocSetContextCreate(context->multi_call_memory_ctx, "PL/Java row context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* Register callback to be called when the function ends */ RegisterExprContextCallback(((ReturnSetInfo*)fcinfo->resultinfo)->econtext, _endOfSetCB, PointerGetDatum(ctxData)); MemoryContextSwitchTo(currCtx); } context = SRF_PERCALL_SETUP(); ctxData = (CallContextData*)context->user_fctx; MemoryContextReset(ctxData->rowContext); currCtx = MemoryContextSwitchTo(ctxData->rowContext); currentInvocation->hasConnected = ctxData->hasConnected; currentInvocation->invocation = ctxData->invocation; hasRow = Type_hasNextSRF(self, ctxData->rowProducer, ctxData->rowCollector, (jint)context->call_cntr); ctxData->hasConnected = currentInvocation->hasConnected; ctxData->invocation = currentInvocation->invocation; currentInvocation->hasConnected = false; currentInvocation->invocation = 0; if(hasRow) { Datum result = Type_nextSRF(self, ctxData->rowProducer, ctxData->rowCollector); MemoryContextSwitchTo(currCtx); SRF_RETURN_NEXT(context, result); } MemoryContextSwitchTo(currCtx); /* Unregister this callback and call it manually. We do this because * otherwise it will be called when the backend is in progress of * cleaning up Portals. If we close cursors (i.e. drop portals) in * the close, then that mechanism fails since attempts are made to * delete portals more then once. */ UnregisterExprContextCallback( ((ReturnSetInfo*)fcinfo->resultinfo)->econtext, _endOfSetCB, PointerGetDatum(ctxData)); _closeIteration(ctxData); /* This is the end of the set. */ SRF_RETURN_DONE(context); }