See More

/* * Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden * Distributed under the terms shown in the file COPYRIGHT * found in the root folder of this project or at * http://eng.tada.se/osprojects/COPYRIGHT.html * * @author Thomas Hallgren */ #include #include #include "org_postgresql_pljava_jdbc_Invocation.h" #include "pljava/Invocation.h" #include "pljava/Function.h" #include "pljava/PgObject.h" #include "pljava/JNICalls.h" #include "pljava/Backend.h" #define LOCAL_FRAME_SIZE 128 struct CallLocal_ { /** * Pointer to the call local structure. */ void* pointer; /** * The invocation where this CallLocal was allocated */ Invocation* invocation; /** * Next CallLocal in a double linked list */ CallLocal* next; /** * Previous CallLocal in a double linked list */ CallLocal* prev; }; static jmethodID s_Invocation_onExit; static unsigned int s_callLevel = 0; Invocation* currentInvocation; extern void Invocation_initialize(void); void Invocation_initialize(void) { jclass cls; JNINativeMethod invocationMethods[] = { { "_getCurrent", "()Lorg/postgresql/pljava/jdbc/Invocation;", Java_org_postgresql_pljava_jdbc_Invocation__1getCurrent }, { "_getNestingLevel", "()I", Java_org_postgresql_pljava_jdbc_Invocation__1getNestingLevel }, { "_clearErrorCondition", "()V", Java_org_postgresql_pljava_jdbc_Invocation__1clearErrorCondition }, { "_register", "()V", Java_org_postgresql_pljava_jdbc_Invocation__1register }, { 0, 0, 0 } }; cls = PgObject_getJavaClass("org/postgresql/pljava/jdbc/Invocation"); PgObject_registerNatives2(cls, invocationMethods); s_Invocation_onExit = PgObject_getJavaMethod(cls, "onExit", "()V"); JNI_deleteLocalRef(cls); } void Invocation_assertConnect(void) { if(!currentInvocation->hasConnected) { SPI_connect(); currentInvocation->hasConnected = true; } } void Invocation_assertDisconnect(void) { if(currentInvocation->hasConnected) { SPI_finish(); currentInvocation->hasConnected = false; } } jobject Invocation_getTypeMap(void) { Function f = currentInvocation->function; return f == 0 ? 0 : Function_getTypeMap(f); } void Invocation_pushBootContext(Invocation* ctx) { ctx->invocation = 0; ctx->function = 0; ctx->trusted = false; ctx->hasConnected = false; ctx->upperContext = CurrentMemoryContext; ctx->errorOccured = false; ctx->inExprContextCB = false; ctx->previous = 0; ctx->callLocals = 0; currentInvocation = ctx; ++s_callLevel; } void Invocation_popBootContext(void) { currentInvocation = 0; --s_callLevel; } void Invocation_pushInvocation(Invocation* ctx, bool trusted) { JNI_pushLocalFrame(LOCAL_FRAME_SIZE); ctx->invocation = 0; ctx->function = 0; ctx->trusted = trusted; ctx->hasConnected = false; ctx->upperContext = CurrentMemoryContext; ctx->errorOccured = false; ctx->inExprContextCB = false; ctx->previous = currentInvocation; ctx->callLocals = 0; currentInvocation = ctx; Backend_setJavaSecurity(trusted); ++s_callLevel; } void Invocation_popInvocation(bool wasException) { CallLocal* cl; Invocation* ctx = currentInvocation->previous; if(currentInvocation->invocation != 0) { if(!wasException) JNI_callVoidMethod(currentInvocation->invocation, s_Invocation_onExit); JNI_deleteGlobalRef(currentInvocation->invocation); } if(currentInvocation->hasConnected) SPI_finish(); JNI_popLocalFrame(0); if(ctx != 0) { PG_TRY(); { Backend_setJavaSecurity(ctx->trusted); } PG_CATCH(); { elog(FATAL, "Failed to reinstate untrusted security after a trusted call or vice versa"); } PG_END_TRY(); MemoryContextSwitchTo(ctx->upperContext); } /** * Reset all local wrappers that has been allocated during this call. Yank them * from the double linked list but do *not* remove them. */ cl = currentInvocation->callLocals; if(cl != 0) { CallLocal* first = cl; do { cl->pointer = 0; cl->invocation = 0; cl = cl->next; } while(cl != first); } currentInvocation = ctx; --s_callLevel; } void Invocation_freeLocalWrapper(jlong wrapper) { Ptr2Long p2l; Invocation* ctx; CallLocal* cl; CallLocal* prev; p2l.longVal = wrapper; cl = (CallLocal*)p2l.ptrVal; prev = cl->prev; if(prev != cl) { /* Disconnect */ CallLocal* next = cl->next; prev->next = next; next->prev = prev; } /* If this CallLocal is freed before its owning invocation was * popped then there's a risk that this is the first CallLocal * in the list. */ ctx = cl->invocation; if(ctx != 0 && ctx->callLocals == cl) { if(prev == cl) prev = 0; ctx->callLocals = prev; } pfree(cl); } void* Invocation_getWrappedPointer(jlong wrapper) { Ptr2Long p2l; p2l.longVal = wrapper; return ((CallLocal*)p2l.ptrVal)->pointer; } jlong Invocation_createLocalWrapper(void* pointer) { /* Create a local wrapper for the pointer */ Ptr2Long p2l; CallLocal* cl = (CallLocal*)MemoryContextAlloc(JavaMemoryContext, sizeof(CallLocal)); CallLocal* prev = currentInvocation->callLocals; if(prev == 0) { currentInvocation->callLocals = cl; cl->prev = cl; cl->next = cl; } else { CallLocal* next = prev->next; cl->prev = prev; cl->next = next; prev->next = cl; next->prev = cl; } cl->pointer = pointer; cl->invocation = currentInvocation; p2l.longVal = 0L; /* ensure that the rest is zeroed out */ p2l.ptrVal = cl; return p2l.longVal; } MemoryContext Invocation_switchToUpperContext(void) { return MemoryContextSwitchTo(currentInvocation->upperContext); } /* * Class: org_postgresql_pljava_jdbc_Invocation * Method: _getNestingLevel * Signature: ()I */ JNIEXPORT jint JNICALL Java_org_postgresql_pljava_jdbc_Invocation__1getNestingLevel(JNIEnv* env, jclass cls) { return s_callLevel; } /* * Class: org_postgresql_pljava_jdbc_Invocation * Method: _getCurrent * Signature: ()Lorg/postgresql/pljava/jdbc/Invocation; */ JNIEXPORT jobject JNICALL Java_org_postgresql_pljava_jdbc_Invocation__1getCurrent(JNIEnv* env, jclass cls) { return currentInvocation->invocation; } /* * Class: org_postgresql_pljava_jdbc_Invocation * Method: _clearErrorCondition * Signature: ()V */ JNIEXPORT void JNICALL Java_org_postgresql_pljava_jdbc_Invocation__1clearErrorCondition(JNIEnv* env, jclass cls) { currentInvocation->errorOccured = false; } /* * Class: org_postgresql_pljava_jdbc_Invocation * Method: _register * Signature: ()V */ JNIEXPORT void JNICALL Java_org_postgresql_pljava_jdbc_Invocation__1register(JNIEnv* env, jobject _this) { currentInvocation->invocation = (*env)->NewGlobalRef(env, _this); }