blob: 6e1e4c9803f843c271152cb9bacb9a5ef65d54f3 [file] [log] [blame]
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
#include "LmRoutineJavaObj.h"
#include "org_trafodion_sql_udr_UDR.h"
LmResult LmRoutineJavaObj::setRuntimeInfo(
const char *qid,
int totalNumInstances,
int myInstanceNum,
ComDiagsArea *da)
{
LmResult result = LM_OK;
JNIEnv *jni = (JNIEnv*)getLM()->jniEnv_;
jstring jqid = jni->NewString((const jchar *) qid, strlen(qid));
// call the Java method that will ultimately call the user code
jni->CallVoidMethod(
udrInvokeObjectG_,
(jmethodID) getLM()->setRuntimeInfoId_,
jqid,
(jint) totalNumInstances,
(jint) myInstanceNum);
if (jni->ExceptionOccurred())
{
getLM()->exceptionReporter_->checkJVMException(da, 0);
if (da)
{
// an error without a diagnostic message from Java
*da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
<< DgString0(getNameForDiags())
<< DgString1("runtime")
<< DgString2("LmRoutineJavaObj::setRuntimeInfo()")
<< DgString3("Exception in JNI call");
}
result = LM_ERR;
}
// delete input parameter objects
jni->DeleteLocalRef(jqid);
return result;
}
LmResult LmRoutineJavaObj::invokeRoutineMethod(
/* IN */ tmudr::UDRInvocationInfo::CallPhase phase,
/* IN */ const char *serializedInvocationInfo,
/* IN */ Int32 invocationInfoLen,
/* OUT */ Int32 *invocationInfoLenOut,
/* IN */ const char *serializedPlanInfo,
/* IN */ Int32 planInfoLen,
/* IN */ Int32 planNum,
/* OUT */ Int32 *planInfoLenOut,
/* IN */ char *inputRow,
/* IN */ Int32 inputRowLen,
/* OUT */ char *outputRow,
/* IN */ Int32 outputRowLen,
/* IN/OUT */ ComDiagsArea *da)
{
LmResult result = LM_OK;
JNIEnv *jni = (JNIEnv*)getLM()->jniEnv_;
if (inputRowLen >= 0)
inputRowLen_ = inputRowLen;
if (outputRowLen >= 0)
outputRowLen_ = outputRowLen;
jbyteArray jii = jni->NewByteArray((jint) invocationInfoLen);
jbyteArray jpi = jni->NewByteArray((jint) planInfoLen);
jbyteArray jir = jni->NewByteArray((jint) inputRowLen_);
jni->SetByteArrayRegion(jii,
(jsize) 0,
(jsize) invocationInfoLen,
(const jbyte *) serializedInvocationInfo);
jni->SetByteArrayRegion(jpi,
(jsize) 0,
(jsize) planInfoLen,
(const jbyte *) serializedPlanInfo);
jni->SetByteArrayRegion(jir,
(jsize) 0,
(jsize) inputRowLen_,
(const jbyte *) inputRow);
// call the Java method that will ultimately call the user code
jobject jniResult = jni->CallObjectMethod(
udrInvokeObjectG_,
(jmethodID) getLM()->routineMethodInvokeId_,
(jint) phase,
jii,
jpi,
(jint) planNum,
jir);
if (jniResult == NULL || jni->ExceptionOccurred())
{
// this catches any exceptions other than UDRException
// thrown in the Java code
getLM()->exceptionReporter_->checkJVMException(da, 0);
if (da && da->mainSQLCODE() >= 0)
{
// an error without a diagnostic message from Java
char buf[4];
snprintf(buf, sizeof(buf), "%d", static_cast<int>(phase));
*da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
<< DgString0(getNameForDiags())
<< DgString1(buf)
<< DgString2("LmRoutineJavaObj::invokeRoutineMethod()")
<< DgString3("JNI call returned a NULL object");
}
result = LM_ERR;
}
// delete input parameter objects
jni->DeleteLocalRef(jii);
jni->DeleteLocalRef(jpi);
jni->DeleteLocalRef(jir);
// clear return info from any previous calls
if (returnedIIL_)
{
jni->DeleteLocalRef(returnedIIL_);
returnedIIL_ = NULL;
}
if (returnedPIL_)
{
jni->DeleteLocalRef(returnedPIL_);
returnedPIL_ = NULL;
}
iiLen_ = piLen_ = 0;
if (result == LM_OK)
{
// retrieve returned information
jint returnStatus = jni->GetIntField(
jniResult,
(jfieldID) getLM()->returnInfoStatusField_);
if (returnStatus != 0)
{
getLM()->exceptionReporter_->processJavaObjException(
jniResult,
returnStatus,
static_cast<int>(phase),
"LmRoutineJavaObj::invokeRoutineMethod()",
getNameForDiags(),
da);
result = LM_ERR;
}
else
{
returnedIIL_ = static_cast<jbyteArray>(
jni->GetObjectField(
jniResult,
(jfieldID) getLM()->returnInfoRIIField_));
returnedPIL_ = static_cast<jbyteArray>(
jni->GetObjectField(
jniResult,
(jfieldID) getLM()->returnInfoRPIField_));
if (returnedIIL_)
iiLen_ = jni->GetArrayLength(returnedIIL_);
if (returnedPIL_)
piLen_ = jni->GetArrayLength(returnedPIL_);
}
if (phase == tmudr::UDRInvocationInfo::RUNTIME_WORK_CALL &&
result == LM_OK)
{
SQLUDR_Q_STATE qs = SQLUDR_Q_EOD;
// emit the EOD (end of data) for the result table
(*emitRowPtr_)(NULL,0,&qs);
}
}
jni->DeleteLocalRef(jniResult);
if (invocationInfoLenOut)
*invocationInfoLenOut = static_cast<Int32>(iiLen_);
if (planInfoLenOut)
*planInfoLenOut = static_cast<Int32>(piLen_);
return result;
}
LmResult LmRoutineJavaObj::getRoutineInvocationInfo(
/* IN/OUT */ char *serializedInvocationInfo,
/* IN */ Int32 invocationInfoMaxLen,
/* OUT */ Int32 *invocationInfoLenOut,
/* IN/OUT */ char *serializedPlanInfo,
/* IN */ Int32 planInfoMaxLen,
/* IN */ Int32 planNum,
/* OUT */ Int32 *planInfoLenOut,
/* IN/OUT */ ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)getLM()->jniEnv_;
LmResult result = LM_OK;
// return the serialized invocation info
if (returnedIIL_)
{
if (invocationInfoMaxLen < iiLen_ && serializedInvocationInfo)
{
if (da)
*da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
<< DgString0(getNameForDiags())
<< DgString1("unknown")
<< DgString2("getRoutineInvocationInfo()")
<< DgString3("Buffer too short for invocation info");
iiLen_ = 0;
result = LM_ERR;
}
else if (serializedInvocationInfo)
{
jbyte * returnedIIChar = jni->GetByteArrayElements(returnedIIL_, NULL);
str_cpy_all(serializedInvocationInfo,
reinterpret_cast<const char *>(returnedIIChar),
iiLen_);
jni->ReleaseByteArrayElements(returnedIIL_, returnedIIChar, JNI_ABORT);
}
jni->DeleteLocalRef(returnedIIL_);
returnedIIL_ = NULL;
}
if (invocationInfoLenOut)
*invocationInfoLenOut = iiLen_;
iiLen_ = 0;
// return the serialized plan info
if (returnedPIL_)
{
if (planInfoMaxLen < piLen_ && serializedPlanInfo)
{
if (da)
*da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
<< DgString0(getNameForDiags())
<< DgString1("unknown")
<< DgString2("getRoutineInvocationInfo()")
<< DgString3("Buffer too short for plan info");
piLen_ = 0;
result = LM_ERR;
}
else if (serializedPlanInfo)
{
jbyte * returnedPIChar = jni->GetByteArrayElements(returnedPIL_, NULL);
str_cpy_all(serializedPlanInfo,
reinterpret_cast<const char *>(returnedPIChar),
piLen_);
jni->ReleaseByteArrayElements(returnedPIL_, returnedPIChar, JNI_ABORT);
}
jni->DeleteLocalRef(returnedPIL_);
returnedPIL_ = NULL;
}
if (planInfoLenOut)
*planInfoLenOut = piLen_;
piLen_ = 0;
return result;
}
LmResult LmRoutineJavaObj::setFunctionPtrs(
SQLUDR_GetNextRow getNextRowPtr,
SQLUDR_EmitRow emitRowPtr,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)getLM()->jniEnv_;
LmResult result = LM_OK;
// save a local copy to be able to emit the EOD (end of data)
emitRowPtr_ = emitRowPtr;
const JNINativeMethod methods[2] = {
{ const_cast<char *>("SpInfoGetNextRowJava"),
const_cast<char *>("([BILorg/trafodion/sql/udr/UDR$QueueStateInfo;)V"),
reinterpret_cast<void *>(jniGetNextRowPtr_) },
{ const_cast<char *>("SpInfoEmitRowJava"),
const_cast<char *>("([BILorg/trafodion/sql/udr/UDR$QueueStateInfo;)V"),
reinterpret_cast<void *>(jniEmitRowPtr_) }
};
// use this method to register the native methods, which are already
// loaded in the executable, not need to load a separate DLL
jint returnStatus = jni->RegisterNatives(
reinterpret_cast<jclass>(getLM()->udrClass_),
methods,
static_cast<jint>(sizeof(methods)/sizeof(methods[0])));
if (returnStatus != 0 || jni->ExceptionOccurred())
{
getLM()->exceptionReporter_->insertDiags(
da,
-LME_INTERNAL_ERROR,
": Error in LmRoutineJavaObj::setFunctionPtrs()");
if (da)
{
char buf2[80];
snprintf(buf2, sizeof(buf2), "Return status %d from JNI call", returnStatus);
*da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
<< DgString0(getNameForDiags())
<< DgString1("runtime initial")
<< DgString2("LmRoutineJavaObj::setFunctionPtrs()")
<< DgString3(buf2);
}
result = LM_ERR;
}
return result;
}
void LmRoutineJavaObj::setJNIFunctionPtrs(void *jniGetNextRowPtr,
void *jniEmitRowPtr)
{
jniGetNextRowPtr_ = jniGetNextRowPtr;
jniEmitRowPtr_ = jniEmitRowPtr;
}
void LmRoutineJavaObj::setRowLengths(int inputRowLen,
int outputRowLen)
{
inputRowLen_ = inputRowLen;
outputRowLen_ = outputRowLen;
}
LmRoutineJavaObj::LmRoutineJavaObj(
const char *sqlName,
const char *externalName,
const char *librarySqlName,
ComRoutineTransactionAttributes transactionAttrs,
ComRoutineSQLAccess sqlAccessMode,
ComRoutineExternalSecurity externalSecurity,
Int32 routineOwnerId,
const char *serializedInvocationInfo,
int invocationInfoLen,
const char *serializedPlanInfo,
int planInfoLen,
LmLanguageManagerJava *lm,
jobject udrObject,
LmContainer *container,
ComDiagsArea *diagsArea) : LmRoutineJava(sqlName,
externalName,
librarySqlName,
0,
NULL,
0,
NULL,
COM_STYLE_JAVA_OBJ,
transactionAttrs,
sqlAccessMode,
externalSecurity,
routineOwnerId,
NULL,
0,
0,
NULL,
NULL,
NULL,
lm,
(LmHandle) NULL,
container,
diagsArea),
udrObjectG_(NULL),
udrInvokeObjectG_(NULL),
returnedIIL_(NULL),
returnedPIL_(NULL),
iiLen_(0),
piLen_(0),
inputRowLen_(-1),
outputRowLen_(-1),
emitRowPtr_(NULL),
jniGetNextRowPtr_(NULL),
jniEmitRowPtr_(NULL)
{
JNIEnv *jni = (JNIEnv*)getLM()->jniEnv_;
jbyteArray jii = jni->NewByteArray((jint) invocationInfoLen);
jbyteArray jpi = NULL;
jobject udrInvokeObject = NULL;
jni->SetByteArrayRegion(jii,
(jsize) 0,
(jsize) invocationInfoLen,
(const jbyte *) serializedInvocationInfo);
if (planInfoLen > 0)
{
jpi = jni->NewByteArray((jint) planInfoLen);
jni->SetByteArrayRegion(jpi,
(jsize) 0,
(jsize) planInfoLen,
(const jbyte *) serializedPlanInfo);
}
if (!jni->ExceptionOccurred())
// Do a JNI call to allocate an LmUDRObjMethodInvoke object
udrInvokeObject = jni->CallStaticObjectMethod(
(jclass) getLM()->lmObjMethodInvokeClass_,
(jmethodID) getLM()->makeNewObjId_,
udrObject,
jii,
jpi);
jni->DeleteLocalRef(jii);
if (planInfoLen > 0)
jni->DeleteLocalRef(jpi);
if (udrInvokeObject != NULL && !jni->ExceptionOccurred())
{
// create global references for these objects, they will
// last as long as the LmRoutineJavaObj
udrObjectG_ = jni->NewGlobalRef(udrObject);
jni->DeleteLocalRef(udrObject);
udrInvokeObjectG_ = jni->NewGlobalRef(udrInvokeObject);
jni->DeleteLocalRef(udrInvokeObject);
}
if (udrObjectG_ == NULL || udrInvokeObjectG_ == NULL || jni->ExceptionOccurred())
{
getLM()->exceptionReporter_->insertDiags(
diagsArea,
-LME_INTERNAL_ERROR,
": Error in LmRoutineJavaObj::LmRoutineJavaObj()");
}
}
LmRoutineJavaObj::~LmRoutineJavaObj()
{
JNIEnv *jni = (JNIEnv*)getLM()->jniEnv_;
if (udrObjectG_ != NULL)
jni->DeleteGlobalRef(udrObjectG_);
if (udrInvokeObjectG_ != NULL)
jni->DeleteGlobalRef(udrInvokeObjectG_);
if (returnedIIL_)
jni->DeleteLocalRef(returnedIIL_);
if (returnedPIL_)
jni->DeleteLocalRef(returnedPIL_);
}
ComBoolean LmRoutineJavaObj::isValid() const
{
return udrObjectG_ != NULL && udrInvokeObjectG_ != NULL;
}