blob: 38713a921aabc0f40e32760fb8a5a0636977f09e [file] [log] [blame]
/* -*-C++-*-
**********************************************************************
*
* File: LmLangManagerJava.cpp
* Description: Language Manager for Java
*
* Created: 07/01/1999
* Language: C++
*
// @@@ 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 "Platform.h"
#include <seabed/fs.h>
#include <seabed/ms.h>
#include "lmjni.h"
#include "ComSmallDefs.h"
#include "ComRtUtils.h"
#include "sqlcli.h"
#include "Globals.h"
#include "LmLangManagerJava.h"
#include "LmJavaOptions.h"
#include "LmCommon.h"
#include "LmJavaHooks.h"
#include "LmJavaType.h"
#include "LmRoutineJavaObj.h"
#include "LmContManager.h"
#include "LmJavaExceptionReporter.h"
#include "UdrFFDC.h"
#include "Measure.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LmExtFunc.h"
#include "LmAssert.h"
#include "LmDebug.h"
#include "LmUtility.h"
// A helper function to check if the DEFINE name is defined. DEFINE value
// and it's length are returned if definValue & defineValueLen pointers
// are not NULL
// Returns TRUE if define is set
// FALSE otherwise
NABoolean getDefineSetting(const char *defineName,
char *defineValue,
short *defineValueLen)
{
return FALSE;
}
//////////////////////////////////////////////////////////////////////
//
// Global declarations
//
//////////////////////////////////////////////////////////////////////
JavaVM *LmSqlJVM = NULL; // The per process JVM. The JVM is allocated as
// a global so that (1) it remains after all
// LMJ instances are gone, (2) "utilites" can
// potentially access the JVM (future).
//////////////////////////////////////////////////////////////////////
//
// Local declarations
//
//////////////////////////////////////////////////////////////////////
// Error for overflow situation
#define ERR_LM_PARAM_OVERFLOW(result, pos) \
if (result == LM_PARAM_OVERFLOW) \
{ \
*da << DgSqlCode(-LME_DATA_OVERFLOW) \
<< DgInt0(pos); \
result = LM_ERR; \
}
// Warning for overflow situation
#define WARN_LM_PARAM_OVERFLOW(result, pos) \
if (result == LM_PARAM_OVERFLOW) \
{ \
*da << DgSqlCode(LME_DATA_OVERFLOW_WARN) \
<< DgInt0(pos); \
result = LM_OK; \
}
// Defines complete.
//////////////////////////////////////////////////////////////////////
//
// Class LmLanguageManagerJava
//
//////////////////////////////////////////////////////////////////////
char* LmLanguageManagerJava::classPath_ = NULL;
char* LmLanguageManagerJava::sysClassPath_ = NULL;
ComUInt32 LmLanguageManagerJava::maxLMJava_ = 0;
ComUInt32 LmLanguageManagerJava::numLMJava_ = 0;
LmLanguageManagerJava::LmLanguageManagerJava(LmResult &result,
NABoolean commandLineMode,
ComUInt32 maxLMJava,
LmJavaOptions *userOptions,
ComDiagsArea *diagsArea)
: LmLanguageManager(commandLineMode),
contManager_(NULL),
jniEnv_(NULL),
threadId_(0),
userName_(NULL),
userPassword_(NULL),
datasourceName_(NULL),
jdbcSupportsRS_(FALSE),
jdbcSPJRSVer_(0),
diagsArea_(diagsArea),
setDefaultCatSchFlag_(commandLineMode ? FALSE : TRUE),
enableType2Conn_(FALSE),
mapDefaultConnToType2Conn_(FALSE)
{
setRoutineIsActive(FALSE);
LmJavaHooks::init_vfprintfHook();
NABoolean status = lmSetSignalHandlersToDefault();
if (status != TRUE) {
result = LM_ERR;
if (diagsArea)
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not set signal handlers to default before JVM creation");
return;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Set signal handlers to default before JVM creation");
initialize(result, maxLMJava, userOptions, diagsArea);
status = lmRestoreUdrTrapSignalHandlers(TRUE);
if (status != TRUE) {
result = LM_ERR;
if (diagsArea)
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore UDR trap signal handlers after JVM creation");
return;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored UDR trap signal handlers after JVM creation");
// If we captured any JVM messages, add them to the diags area
//
// $$$$ NOTE: Executor does not yet support warnings in the LOAD
// reply. We need to fix that. Once fixed, then if the JVM was
// successfully started but JVM messages were also captured, then
// we can return the JVM messages as warnings. For now, if the JVM
// was successfully started, then such messages will not go into
// the diags area but we will instead send them to stderr.
const char *jvmMessages = LmJavaHooks::get_vfprintfText();
if (jvmMessages && jvmMessages[0])
{
if (diagsArea && result != LM_OK)
{
*diagsArea << DgSqlCode(-LME_JVM_CONSOLE_OUTPUT)
<< DgString0(jvmMessages);
}
else
{
fprintf(stderr, jvmMessages);
fflush(stderr);
}
}
}
void LmLanguageManagerJava::initialize(LmResult &result,
ComUInt32 maxLMJava,
LmJavaOptions *userOptions,
ComDiagsArea *diagsArea)
{
// Initialize Java class handles to NULL.
loaderClass_ = utilityClass_ = stringClass_ = bigintClass_ = NULL;
systemClass_ = bigdecClass_ = dateClass_ = timeClass_ = NULL;
stampClass_ = intClass_ = longClass_ = floatClass_ = NULL;
doubleClass_ = resultSetClass_ = jdbcMxT2Driver_ = connClass_ = NULL;
lmCharsetClass_ = lmDrvrClass_ = jdbcMxT4Driver_ = NULL;
// Initialize method and field IDs to NULL, to make sure they do not
// contain garbage values. Some of the error handling routines
// called by this constructor will use a method ID if it has a
// non-NULL value.
loadClassId_ = loaderSizeId_ = addCpURLsId_ =
removeCpURLsId_ = verifyMethodId_ = createCLId_ = setCPId_ =
utilityInitId_ = classCacheSizeId_ = classCacheEnforceId_ =
systemGetPropId_ = systemSetPropId_ = systemClearPropId_ =
bigdecCtorId_ = bigdecStrId_ = bigdecUnscaleId_ =
bigintIntValueId_ = bigintLongValueId_ =
dateStrId_ = dateValId_ = timeStrId_ =
timeValId_ = stampStrId_ = stampValId_ =
intCtorId_ = intValId_ = longCtorId_ =
longValId_ = floatCtorId_ = floatValId_ =
doubleCtorId_ = doubleValId_ =
bytesToUnicodeId_ = unicodeToBytesId_ =
utilityGetRSInfoId_ = utilityInitRSId_ =
utilityGetT4RSInfoId_ = utilityInitT4RSId_ = utilityGetConnTypeId_ =
lmObjMethodInvokeClass_ = makeNewObjId_ = setRuntimeInfoId_ =
routineMethodInvokeId_ = routineReturnInfoClass_ =
returnInfoStatusField_ = returnInfoSQLStateField_ = returnInfoMessageField_ =
returnInfoRIIField_ = returnInfoRPIField_ =
udrClass_ = udrQueueStateField_ =
rsCloseId_ = rsBeforeFirstId_ = rsNextId_ = rsWasNullId_ = rsGetWarningsId_ =
rsGetShortId_ = rsGetIntId_ = rsGetLongId_ = rsGetFloatId_ =
rsGetDoubleId_ = rsGetStringId_ = rsGetObjectId_ = rsGetBigDecimalId_ =
rsGetDateId_ = rsGetTimeId_ = rsGetTimestampId_ =
driverInitId_ = connCloseId_ = connIsClosedId_ =
hpT4ConnSuspUdrXnId_ = NULL;
result = LM_OK;
sysCatalog_ = sysSchema_ = NULL;
// Adjust the LMJ counter.
if (maxLMJava_ == 0)
maxLMJava_ = maxLMJava;
++numLMJava_;
if (numLMJava_ == 1)
setJavaClassPath();
if (numLMJava_ > maxLMJava_)
{
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Max JVMs exceeded.");
result = LM_ERR;
return;
}
jsize nVMs = 0;
jint jrc = JNI_GetCreatedJavaVMs (&LmSqlJVM, 1, &nVMs);
if (jrc != JNI_OK)
{
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Unable to determine whether JVMs exist.");
result = LM_ERR;
return;
}
if (nVMs == 0)
LmSqlJVM = NULL; // JVM has not yet been started
// Allocate the JVM or attach to it.
if (LmSqlJVM == NULL)
{
// First we make a copy of the JVM startup options being passed
// in, and do some massaging of those options before starting the
// JVM.
LmJavaOptions *actualJvmOptions = new (collHeap()) LmJavaOptions();
if (userOptions)
{
// This call will copy userOptions into actualJvmOptions and do
// any necessary massaging of the options. userOptions will not
// be modified by this call.
processJavaOptions(*userOptions, *actualJvmOptions);
}
#ifdef LM_DEBUG
actualJvmOptions->display();
LM_DEBUG0("");
LM_DEBUG1("classPath_ is %s", classPath_ ? classPath_ : "NULL");
LM_DEBUG1("sysClassPath_ is %s", sysClassPath_ ? sysClassPath_ : "NULL");
const char *jrehome = getenv("JREHOME");
LM_DEBUG1("JREHOME is %s", jrehome ? jrehome : "NULL");
LM_DEBUG1("commandLineMode_ is %s",
getCommandLineMode() ? "TRUE" : "FALSE");
LM_DEBUG1("setDefaultCatSchFlag_ is %s",
setDefaultCatSchFlag_ ? "TRUE" : "FALSE");
LM_DEBUG0("");
#endif
ULng32 numUserOpts = actualJvmOptions->entries();
ULng32 numHookOpts = 3; // for abort, exit, vfprintf hooks
#ifdef _DEBUG
int debugPort = 0;
int debugTimeout = 0;
const char *debugPortStr = getenv("JVM_DEBUG_PORT");
if (debugPortStr != NULL)
debugPort = atoi(debugPortStr);
const char *debugTimeoutStr = getenv("JVM_DEBUG_TIMEOUT");
if (debugTimeoutStr != NULL)
debugTimeout = atoi(debugTimeoutStr);
const char *suspendOnDebug = getenv("JVM_SUSPEND_ON_DEBUG");
if (debugPort > 0)
numHookOpts++;
#endif
// We allow an environment setting to determine whether or not we
// register for JVM callbacks. By default the registration is ON.
if (getenv("SQLMX_NO_JVM_HOOKS"))
{
LM_DEBUG0("*** No JVM hook functions will be registered because");
LM_DEBUG0("*** environment variable SQLMX_NO_JVM_HOOKS is set");
numHookOpts = 0;
}
JavaVMOption *vmOptions = NULL;
if ((numUserOpts + numHookOpts) > 0)
{
const ULng32 numBytes =
(numUserOpts + numHookOpts) * sizeof(JavaVMOption);
vmOptions = (JavaVMOption *) new (collHeap()) char[numBytes];
memset((char *) vmOptions, 0, numBytes);
}
// First we initialize the hook options and then the user
// options. By registering our hooks first, then if an error
// occurs while processing a user option, our hooks still get
// called because they've already been registered. This can
// happen, for example, if a security policy file is specified in
// a user option and there is a syntax error in that file.
ULng32 i = 0;
if (numHookOpts > 0)
{
vmOptions[i].optionString = (char *) "vfprintf";
vmOptions[i++].extraInfo = (void *) LmJavaHooks::vfprintfHookJVM;
vmOptions[i].optionString = (char *) "abort";
vmOptions[i++].extraInfo = (void *) LmJavaHooks::abortHookJVM;
vmOptions[i].optionString = (char *) "exit";
vmOptions[i++].extraInfo = (void *) LmJavaHooks::exitHookJVM;
#ifdef _DEBUG
char debugOptions[300];
if (debugPort > 0)
{
debugPort = debugPort + (GetCliGlobals()->myPin() % 1000);
sprintf(debugOptions,"-agentlib:jdwp=transport=dt_socket,address=%d,server=y,timeout=%d",
debugPort, debugTimeout);
if (suspendOnDebug != NULL)
strcat(debugOptions, ",suspend=y");
else
strcat(debugOptions, ",suspend=n");
vmOptions[i++].optionString = debugOptions;
}
#endif
}
LM_ASSERT(i == numHookOpts);
for (i = 0; i < numUserOpts; i++)
{
vmOptions[i + numHookOpts].optionString =
(char *) (actualJvmOptions->getOption(i));
}
JavaVMInitArgs args;
args.nOptions = (Lng32) (numUserOpts + numHookOpts);
args.version = JNI_VERSION_1_4;
args.options = vmOptions;
args.ignoreUnrecognized = JNI_FALSE;
// Create JVM
TIMER_ON(jvmTimer)
LM_DEBUG0("About to call JNI_CreateJavaVM()...");
Int32 jniResult = JNI_CreateJavaVM(&LmSqlJVM, &jniEnv_, &args);
LM_DEBUG1("JNI_CreateJavaVM() returned %d", jniResult);
result = (LmResult) jniResult;
TIMER_OFF(jvmTimer, "Creating JVM")
// Clean up structures used for JVM initialization only
delete actualJvmOptions;
NADELETEBASIC(vmOptions, collHeap());
if (result < 0)
{
*diagsArea_ << DgSqlCode(-LME_JVM_INIT_ERROR);
result = LM_ERR;
return;
}
} // if (LmSqlJVM == NULL)
else
{
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_4;
args.name = NULL;
args.group = NULL;
result = (LmResult)LmSqlJVM->AttachCurrentThread(&jniEnv_, &args);
}
if (result != LM_OK)
{
*diagsArea_ << DgSqlCode(-LME_JVM_INIT_ERROR);
result = LM_ERR;
return;
}
// Asserts, just to check we don't have NULL pointers
LM_ASSERT(LmSqlJVM != NULL);
LM_ASSERT(jniEnv_ != NULL);
LM_ASSERT(sysClassPath_ != NULL);
// record the constructing thread's ID.
threadId_ = threadId();
jclass jc;
JNIEnv *jni = (JNIEnv*)jniEnv_;
//
// Now load some important classes and methods in them.
// Here we are not checking for the exception after each GetMethodID call.
// But the fact is that GetMethodID returns NULL if it fails to find the
// method and exception won't get cleared until we call ExceptionClear()
// explicitly. So we make bunch of jni calls and at the end we check for
// the errors(basically NULL return values).
//
// Instantiate Exception Mechanism class
exceptionReporter_ = new (collHeap())
LmJavaExceptionReporter((LmHandle) jni,
this,
result,
diagsArea_);
if (result == LM_ERR)
return;
TIMER_ON(lmUtilTimer);
// Load LmUtility class. We can't use loadSysClass because loadSysClass
// uses LmUtility.
jc = (jclass) jni->FindClass("org/trafodion/sql/udr/LmUtility");
TIMER_OFF(lmUtilTimer, "Load LmUtility class")
if (jc)
{
utilityClass_ = (jclass) jni->NewGlobalRef(jc);
jni->DeleteLocalRef(jc);
if (utilityClass_ != NULL)
{
verifyMethodId_ = jni->GetStaticMethodID((jclass)utilityClass_,
"verifyMethodSignature",
"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;III[Ljava/lang/String;[I[Ljava/lang/String;)V");
createCLId_ = jni->GetStaticMethodID((jclass)utilityClass_,
"createClassLoader",
"(Ljava/lang/String;I)Lorg/trafodion/sql/udr/LmClassLoader;");
utilityInitId_ = jni->GetStaticMethodID((jclass)utilityClass_,
"init", "()V");
classCacheSizeId_ = jni->GetStaticFieldID((jclass)utilityClass_,
"classCacheSizeKB_", "I");
classCacheEnforceId_ = jni->GetStaticFieldID((jclass)utilityClass_,
"classCacheEnforceLimit_",
"I");
utilityGetRSInfoId_ = jni->GetStaticMethodID((jclass)utilityClass_,
"getRSInfo", "(Ljava/lang/Object;[I[J[Ljava/lang/Object;[I[Ljava/lang/String;)V");
utilityInitRSId_ = jni->GetStaticMethodID((jclass)utilityClass_,
"initRS", "([J)Z");
utilityGetConnTypeId_ = jni->GetStaticMethodID((jclass)utilityClass_,
"getConnectionType", "(Ljava/lang/Object;)I");
utilityGetT4RSInfoId_ = jni->GetStaticMethodID((jclass)utilityClass_,
"getT4RSInfo", "(Ljava/lang/Object;[J[Z[I[Z[Ljava/lang/String;[Ljava/lang/Object;)V");
utilityInitT4RSId_ = jni->GetStaticMethodID((jclass)utilityClass_,
"initT4RS", "()Z");
if (jni->ExceptionOccurred() || verifyMethodId_ == NULL ||
createCLId_ == NULL || classCacheSizeId_ == NULL ||
classCacheEnforceId_ == NULL || utilityInitId_ == NULL ||
utilityGetRSInfoId_ == NULL || utilityInitRSId_ == NULL ||
utilityGetConnTypeId_ == NULL || utilityGetT4RSInfoId_ == NULL ||
utilityInitT4RSId_ == NULL)
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.LmUtility");
result = LM_ERR;
return;
}
}
}
else
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.LmUtility");
result = LM_ERR;
return;
}
// Now call the LmUtility::init() method
jni->CallStaticVoidMethod((jclass) utilityClass_,
(jmethodID) utilityInitId_);
if (jni->ExceptionOccurred())
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_INTERNAL_ERROR,
": org.trafodion.sql.udr.LmUtility.init()"
" raised an exception.");
result = LM_ERR;
return;
}
// Register the native methods used by LmUtility Java class
if (registerLmUtilityMethods(jni, (jclass)utilityClass_) < 0) {
exceptionReporter_->insertDiags(diagsArea_,
-LME_INTERNAL_ERROR,
": Error registering native methods for "
"org.trafodion.sql.udr.LmUtility class.");
result = LM_ERR;
return;
}
const char *clName = "org/trafodion/sql/udr/LmClassLoader";
const char *name = "org.trafodion.sql.udr.LmClassLoader";
TIMER_ON(lmClassLoaderTimer)
// Load LmClassLoader class and findClass() method
jc = (jclass) loadSysClass(clName, name, diagsArea_);
TIMER_OFF(lmClassLoaderTimer, "Load LmClassLoader class")
if (jc != NULL)
{
loaderClass_ = jc;
loadClassId_ = jni->GetMethodID(jc, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
setCPId_ = jni->GetStaticMethodID(jc, "setClassPath",
"(Ljava/lang/String;)V");
addCpURLsId_ = jni->GetMethodID(jc, "addCpURLs", "()V");
removeCpURLsId_ = jni->GetMethodID(jc, "removeCpURLs", "()V");
loaderSizeId_ = jni->GetMethodID(jc, "size", "()I");
if (jni->ExceptionOccurred() || loadClassId_ == NULL ||
removeCpURLsId_ == NULL || setCPId_ == NULL ||
loaderSizeId_ == NULL || addCpURLsId_ == NULL)
{
result = exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
name);
return;
}
}
else
{
result = LM_ERR;
return;
}
// Set classPath for LmClassLoader(seen by all instances of ClassLoader)
if (classPath_ != NULL)
{
jstring jCP = jni->NewStringUTF(classPath_);
result = exceptionReporter_->checkNewObjectExceptions(jCP, diagsArea_);
if(result == LM_ERR)
return;
jni->CallStaticVoidMethod((jclass)loaderClass_, (jmethodID)setCPId_, jCP);
jni->DeleteLocalRef(jCP);
if (jni->ExceptionOccurred())
{
result = exceptionReporter_->insertDiags(diagsArea_,
-LME_INTERNAL_ERROR,
": Could not set search path "
"in ClassLoader.");
return;
}
}
jc = (jclass) jni->FindClass("org/trafodion/sql/udr/LmCharsetCoder");
if (jc)
{
lmCharsetClass_ = (jclass) jni->NewGlobalRef(jc);
jni->DeleteLocalRef(jc);
if (lmCharsetClass_ != NULL)
{
bytesToUnicodeId_ = jni->GetStaticMethodID((jclass) lmCharsetClass_,
"getUnicodeStringFromBytes",
"([BLjava/lang/String;II)Ljava/lang/String;");
unicodeToBytesId_= jni->GetStaticMethodID((jclass) lmCharsetClass_,
"getBytesFromUnicodeString",
"(Ljava/lang/String;Ljava/lang/String;)[B");
if (jni->ExceptionOccurred() ||
bytesToUnicodeId_ == NULL || unicodeToBytesId_ == NULL)
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.LmCharsetCoder");
result = LM_ERR;
return;
}
}
}
else
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.LmCharsetCoder");
result = LM_ERR;
return;
}
jc = (jclass) jni->FindClass("org/trafodion/sql/udr/LmUDRObjMethodInvoke");
if (jc)
{
lmObjMethodInvokeClass_ = (jclass) jni->NewGlobalRef(jc);
jni->DeleteLocalRef(jc);
if (lmObjMethodInvokeClass_ != NULL)
{
makeNewObjId_ = jni->GetStaticMethodID((jclass) lmObjMethodInvokeClass_,
"makeNewObj",
"(Lorg/trafodion/sql/udr/UDR;[B[B)Lorg/trafodion/sql/udr/LmUDRObjMethodInvoke;");
setRuntimeInfoId_ = jni->GetMethodID((jclass) lmObjMethodInvokeClass_,
"setRuntimeInfo",
"(Ljava/lang/String;II)V");
routineMethodInvokeId_ = jni->GetMethodID((jclass) lmObjMethodInvokeClass_,
"invokeRoutineMethod",
"(I[B[BI[B)Lorg/trafodion/sql/udr/LmUDRObjMethodInvoke$ReturnInfo;");
if (jni->ExceptionOccurred() ||
makeNewObjId_ == NULL ||
setRuntimeInfoId_ == NULL ||
routineMethodInvokeId_ == NULL)
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.LmUDRObjMethodInvoke");
result = LM_ERR;
return;
}
}
}
else
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.LmUDRObjMethodInvoke");
result = LM_ERR;
return;
}
jc = (jclass) jni->FindClass("org/trafodion/sql/udr/LmUDRObjMethodInvoke$ReturnInfo");
if (jc)
{
routineReturnInfoClass_ = (jclass) jni->NewGlobalRef(jc);
jni->DeleteLocalRef(jc);
if (routineReturnInfoClass_ != NULL)
{
returnInfoStatusField_ = jni->GetFieldID(
(jclass) routineReturnInfoClass_,
"returnStatus_",
"I");
returnInfoSQLStateField_ = jni->GetFieldID(
(jclass) routineReturnInfoClass_,
"returnedSQLState_",
"Ljava/lang/String;");
returnInfoMessageField_ = jni->GetFieldID(
(jclass) routineReturnInfoClass_,
"returnedMessage_",
"Ljava/lang/String;");
returnInfoRIIField_ = jni->GetFieldID(
(jclass) routineReturnInfoClass_,
"returnedInvocationInfo_",
"[B");
returnInfoRPIField_ = jni->GetFieldID(
(jclass) routineReturnInfoClass_,
"returnedPlanInfo_",
"[B");
if (jni->ExceptionOccurred() ||
returnInfoStatusField_ == NULL ||
returnInfoSQLStateField_ == NULL ||
returnInfoMessageField_ == NULL ||
returnInfoRIIField_ == NULL ||
returnInfoRPIField_ == NULL)
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.LmUDRObjMethodInvoke$ReturnInfo");
result = LM_ERR;
return;
}
}
}
else
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.LmUDRObjMethodInvoke$ReturnInfo");
result = LM_ERR;
return;
}
jc = (jclass) jni->FindClass("org/trafodion/sql/udr/UDR");
if (jc)
{
udrClass_ = (jclass) jni->NewGlobalRef(jc);
jni->DeleteLocalRef(jc);
}
else
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org.trafodion.sql.udr.UDR");
result = LM_ERR;
return;
}
// this class is used in JNI calls from Java UDRs to C++ code that
// gets and emits rows
jc = (jclass) jni->FindClass("org/trafodion/sql/udr/UDR$QueueStateInfo");
if (jc)
{
udrQueueStateField_ = jni->GetFieldID(
jc,
"queueState_",
"I");
if (jni->ExceptionOccurred() ||
udrQueueStateField_ == NULL)
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org/trafodion/sql/udr/UDR$QueueStateInfo");
result = LM_ERR;
jni->DeleteLocalRef(jc);
return;
}
jni->DeleteLocalRef(jc);
}
else
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"org/trafodion/sql/udr/UDR$QueueStateInfo");
result = LM_ERR;
return;
}
if (initJavaClasses() == LM_ERR)
{
result = LM_ERR;
return;
}
if (jdbcMxT2Driver_)
{
// Now call the LmUtility::initRS() method
jlongArray ver = jni->NewLongArray(1);
if (jni->ExceptionOccurred() ) {
// JVM Out of memory
*diagsArea_ << DgSqlCode(-LME_JVM_OUT_OF_MEMORY);
exceptionReporter_->checkJVMException(diagsArea_, 0);
result = LM_ERR;
return;
}
jboolean jdbcRS = jni->CallStaticBooleanMethod((jclass) utilityClass_,
(jmethodID) utilityInitRSId_, ver);
if (jni->ExceptionOccurred())
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_INTERNAL_ERROR,
": org.trafodion.sql.udr.LmUtility.initRS() "
"raised an exception.");
result = LM_ERR;
jni->DeleteLocalRef(ver);
return;
}
// Set a flag to indicate whether the JDBC/MX driver
// linked into LM has support for SPJ RS or not.
jdbcSupportsRS_ = (jdbcRS) ? TRUE : FALSE;
// Set a flag to indicate whether the JDBC/MX interfaces
// for SPJ RS is supported or not
jlong la[1];
jni->GetLongArrayRegion(ver, 0, 1, la);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jdbcSPJRSVer_ = la[0];
jni->DeleteLocalRef(ver);
LM_DEBUG1("jdbcSupportsRS_ is %s", jdbcSupportsRS_ ? "TRUE" : "FALSE");
LM_DEBUG1("jdbcRSVerMismatch() returned %s", jdbcRSVerMismatch() ? "TRUE" : "FALSE");
LM_DEBUG2("jdbcSPJRSVer_ is %d, Supported version is %d", jdbcSPJRSVer_,
JDBC_SPJRS_VERSION);
}
if (jdbcMxT4Driver_)
{
// Initialize stuff needed for processing T4 result sets
jboolean t4jdbcSupportsRS =
jni->CallStaticBooleanMethod((jclass) utilityClass_,
(jmethodID) utilityInitT4RSId_);
if (jni->ExceptionOccurred())
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_INTERNAL_ERROR,
": org.trafodion.sql.udr.LmUtility.initT4RS() "
"raised an exception.");
result = LM_ERR;
return;
}
if (! t4jdbcSupportsRS)
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_INTERNAL_ERROR,
": JDBC Type 4 driver loaded by UDR Ser"
"ver does not support SPJ Result Sets");
result = LM_ERR;
return;
}
}
// Load org.trafodion.sql.udr.LmSQLMXDriver class
#define LM_DRIVER_CLASS_PATH "org/trafodion/sql/udr/LmT2Driver"
#define LM_DRIVER_CLASS "org.trafodion.sql.udr.LmT2Driver"
jc = (jclass) loadSysClass(LM_DRIVER_CLASS_PATH,
LM_DRIVER_CLASS, diagsArea_);
if (jc != NULL)
{
lmDrvrClass_ = jc;
driverInitId_ = jni->GetStaticMethodID(jc, "init", "(ZZZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
if (jni->ExceptionOccurred() || driverInitId_ == NULL)
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
LM_DRIVER_CLASS);
result = LM_ERR;
return;
}
}
else
{
result = LM_ERR;
return;
}
// Determine if we need to set default catalog and schema values.
// The decision is made whether the caller has set catalog/schema
// values in startup options.
if (userOptions)
{
NABoolean foundCat = FALSE, foundSch = FALSE;
foundCat = userOptions->getSystemProperty("catalog",
&sysCatalog_,
collHeap());
if (foundCat)
{
LM_ASSERT(sysCatalog_);
}
else
{
foundCat = userOptions->getSystemProperty("jdbcmx.catalog",
&sysCatalog_,
collHeap());
if (foundCat)
LM_ASSERT(sysCatalog_);
}
foundSch = userOptions->getSystemProperty("schema",
&sysSchema_,
collHeap());
if (foundSch)
{
LM_ASSERT(sysSchema_);
}
else
{
foundSch = userOptions->getSystemProperty("jdbcmx.schema",
&sysSchema_,
collHeap());
if (foundSch)
LM_ASSERT(sysSchema_);
}
}
// Now call the LmSQLMXDriver::init() method and pass in
// setDefaultCatSchFlag_,
// enableType2Conn_, mapDefaultConnToType2Conn_,
// System Name, User Name, User Password, Datasource Name, Port Number.
//
// Environment variables SYSNAME, USERID, USERPASSWORD, MXODBC_DATASOURCE
// & MXODBC_PORTNUMBER will be used if they are set. These are mainly for
// developer regressions use.
// On Seaquest, ndcsstart script sets environment variables
// MXUDR_MXOAS_NODE and MXUDR_MXOAS_PORTNUMBER while starting mxoas. These
// will be used if SYSNAME and MXODBC_PORTNUMBER are not set. This
// allows developer settings to override the values set by ndcsstart script.
//
short error = 0;
jstring sysName = NULL;
char * sName = getenv("SYSNAME");
if (!sName)
{
MS_Mon_Reg_Get_Type reg_node_info;
// check the MXUDR_MXOAS_NODE environment variable set by ndcsstart script
error = msg_mon_reg_get(MS_Mon_ConfigType_Cluster, // type
false, // next
NULL, // grp (CLUSTER)
(char *) "MXUDR_MXOAS_NODE", // key
&reg_node_info); // info
if(error == XZFIL_ERR_OK && reg_node_info.num_returned == 1)
{
sysName = (jstring) jni->NewStringUTF(reg_node_info.list[0].value);
}
else
{
// We can not return error as CREATE PROCEDURE will fail when ndcs is not started.
// Let's use node n001 of the Seaquest cluster as the default node name.
sysName = (jstring) jni->NewStringUTF("n001");
}
}
else
{
sysName = (jstring) jni->NewStringUTF(sName);
}
// For MXCI applications, the userid that comes from executor does
// not contain password. So we need to depend on the env setting.
// We use USERID and USERPASSWORD env variable if they are set.
// If they are not set then we use the values that are passed from executor.
jstring userName = NULL;
jstring userPassword = NULL;
if (userName_ != NULL)
{
userName = (jstring) jni->NewStringUTF(userName_);
if (userPassword_ != NULL)
userPassword = (jstring) jni->NewStringUTF(userPassword_);
}
jstring dsName = NULL;
if (datasourceName_ == NULL)
dsName = (jstring) jni->NewStringUTF(getenv("MXODBC_DATASOURCE"));
else
dsName = (jstring) jni->NewStringUTF(datasourceName_);
Int32 portNumber = 0;
// set applicationName property for JDBC connection for identification purposes
const int MAX_APP_NAME_LEN = 120;
char appName[MAX_APP_NAME_LEN];
const int MAX_PROGRAM_DIR_LEN = 1024;
char myProgramDir[MAX_PROGRAM_DIR_LEN+1];
short myProcessType;
Int32 myCPU;
char myNodeName[MAX_SEGMENT_NAME_LEN+1];
Lng32 myNodeNum;
short myNodeNameLen = MAX_SEGMENT_NAME_LEN;
char myProcessName[PROCESSNAME_STRING_LEN];
Int64 myProcessStartTime;
pid_t myPin;
Lng32 retStatus = ComRtGetProgramInfo(myProgramDir, MAX_PROGRAM_DIR_LEN, myProcessType, myCPU,
myPin, myNodeNum, myNodeName, myNodeNameLen,
myProcessStartTime, myProcessName);
if (retStatus)
{
char errStr[LMJ_ERR_SIZE_256];
sprintf (errStr, ": Error returned from ComRtGetProgramInfo. Error is: %d.", retStatus);
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(errStr);
result = LM_ERR;
return;
}
sprintf (appName, "UDR:%s:%03d:%02d:%04d", myProcessName, myNodeNum, myCPU, myPin);
if (setSystemProperty("hpt4jdbc.applicationName", appName, diagsArea_) == LM_ERR)
{
result = LM_ERR;
return;
}
LM_DEBUG4("About to init LmSQLMXDriver, setDefaultCatSchFlag_ is %s, enableType2Conn_ is %s, mapDefaultConnToType2Conn_ is %s, port number for Type 4 connections is %d",
setDefaultCatSchFlag_ ? "TRUE" : "FALSE",
enableType2Conn_ ? "TRUE" : "FALSE",
mapDefaultConnToType2Conn_ ? "TRUE" : "FALSE",
portNumber);
jni->CallStaticVoidMethod((jclass) lmDrvrClass_,
(jmethodID) driverInitId_,
(setDefaultCatSchFlag_) ? 1 : 0,
(enableType2Conn_) ? 1 : 0,
(mapDefaultConnToType2Conn_) ? 1 : 0,
sysName,
userName,
userPassword,
dsName,
portNumber);
jni->DeleteLocalRef(sysName);
jni->DeleteLocalRef(userName);
if (userPassword)
jni->DeleteLocalRef(userPassword);
jni->DeleteLocalRef(dsName);
if (jni->ExceptionOccurred())
{
exceptionReporter_->insertDiags(diagsArea_,
-LME_INTERNAL_ERROR,
": org.trafodion.sql.udr.LmSQLMXDriver.init() "
"raised an exception.");
result = LM_ERR;
return;
}
// Register the native methods used by LmT2Driver Java class
if (registerLmT2DriverMethods(jni, (jclass)lmDrvrClass_) < 0) {
exceptionReporter_->insertDiags(diagsArea_,
-LME_INTERNAL_ERROR,
": Error registering native methods for "
"org.trafodion.sql.udr.LmSQLMXDriver class.");
result = LM_ERR;
return;
}
#ifdef LM_NOCACHE
// Used for performance testing only.
contManager_ = new (collHeap()) LmContainerManagerNoCache();
#else
// Create the CM. 1/2 of the JVM's heap is set aside for the aggregate
// of the LMJ's container cache.
jint maxHeapKB = jni->GetStaticIntField((jclass) utilityClass_,
(jfieldID) classCacheSizeId_);
if (maxHeapKB < 1)
{
maxHeapKB = 1;
}
jint enforce = jni->GetStaticIntField((jclass) utilityClass_,
(jfieldID) classCacheEnforceId_);
LM_DEBUG1("LM container cache max size is %d KB", (Lng32) maxHeapKB);
LM_DEBUG1("LM container cache limits %s be enforced",
(enforce != 0 ? "WILL" : "WILL NOT"));
contManager_ = new (collHeap())
LmContainerManagerCache(this,
(maxHeapKB * 1024) / (2 * maxLMJava_),
(enforce != 0 ? TRUE : FALSE), diagsArea_);
#endif
result = LM_OK;
} // LmLanguageManagerJava::initialize()
/* loadSysClass() : Utility function for loading and pining a Java object
* so that JVM doesn't garbage collect it. Used for only system class
* objects. System class is any class that is part of JDK that we load when
* we start LM or the classes provided by us. Checks for the validity of
* the object.
* Returns null if class cannot be found.
*/
LmHandle LmLanguageManagerJava::loadSysClass(
const char *clName,
const char *name,
ComDiagsArea *diagsArea)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
LM_DEBUG1("loadSysClass: loading %s", clName);
jobject lobj = (jobject) jni->FindClass(clName);
if (lobj == NULL || jni->ExceptionOccurred())
{
exceptionReporter_->insertDiags(diagsArea, -LME_JVM_SYS_CLASS_ERROR, name);
// Exception occurred but return a valid pointer.
if (lobj)
{
jni->DeleteLocalRef(lobj);
lobj = NULL;
}
return lobj;
}
jobject gobj = jni->NewGlobalRef(lobj);
if (gobj == NULL)
{
*diagsArea << DgSqlCode(-LME_JVM_OUT_OF_MEMORY);
}
jni->DeleteLocalRef(lobj);
return (LmHandle)gobj;
}
/* unloadSysClass(): Unpins the object so that JVM can garbage collect it.
*/
void LmLanguageManagerJava::unloadSysClass(LmHandle obj)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
if (obj)
jni->DeleteGlobalRef((jobject)obj);
}
/* initJavaClasses() : pre-load the various Java System classes and
* method IDs the LMJ uses when interfacing with the JVM.
* Returns LM_OK on success
* LM_ERR if fails to load a class or a method in it
*/
LmResult LmLanguageManagerJava::initJavaClasses()
{
jclass jc;
JNIEnv *jni = (JNIEnv*)jniEnv_;
TIMER_ON(set2ClsTimer)
// Load java.lang.String
jc = (jclass) loadSysClass("java/lang/String", "java.lang.String", diagsArea_);
if (jc != NULL)
{
stringClass_ = jc;
stringSubstringId_ = jni->GetMethodID(jc, "substring",
"(II)Ljava/lang/String;");
if (jni->ExceptionOccurred() || stringSubstringId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.lang.String");
}
}
else
{
return LM_ERR;
}
// Load java.lang.System
jc = (jclass) loadSysClass("java/lang/System", "java.lang.System", diagsArea_);
if (jc != NULL)
{
systemClass_ = jc;
systemGetPropId_ = jni->GetStaticMethodID(jc, "getProperty",
"(Ljava/lang/String;)Ljava/lang/String;");
systemSetPropId_ = jni->GetStaticMethodID(jc, "setProperty",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
systemClearPropId_ = jni->GetStaticMethodID(jc, "clearProperty",
"(Ljava/lang/String;)Ljava/lang/String;");
if (jni->ExceptionOccurred()
|| systemGetPropId_ == NULL
|| systemSetPropId_ == NULL
|| systemClearPropId_ == NULL
)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.lang.System");
}
}
else
{
return LM_ERR;
}
// Load java.math.BigDecimal
jc = (jclass) loadSysClass("java/math/BigDecimal", "java.math.BigDecimal", diagsArea_);
if (jc != NULL)
{
bigdecClass_ = jc;
bigdecCtorId_ = jni->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
bigdecStrId_ = jni->GetMethodID(jc, "toString", "()Ljava/lang/String;");
bigdecUnscaleId_ = jni->GetMethodID(jc, "unscaledValue", "()Ljava/math/BigInteger;");
if (jni->ExceptionOccurred() || bigdecCtorId_ == NULL ||
bigdecStrId_ == NULL || bigdecUnscaleId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.math.BigDecimal");
}
}
else
{
return LM_ERR;
}
// Load java.math.BigInteger
jc = (jclass) loadSysClass("java/math/BigInteger", "java.math.BigInteger", diagsArea_);
if (jc != NULL)
{
bigintClass_ = jc;
bigintIntValueId_ = jni->GetMethodID(jc, "intValue", "()I");
if (jni->ExceptionOccurred() || bigintIntValueId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.math.BigInteger");
}
bigintLongValueId_ = jni->GetMethodID(jc, "longValue", "()J");
if (jni->ExceptionOccurred() || bigintLongValueId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.math.BigInteger");
}
}
else
{
return LM_ERR;
}
// Load java.sql.Date
jc = (jclass) loadSysClass("java/sql/Date", "java.sql.Date", diagsArea_);
if (jc != NULL)
{
dateClass_ = jc;
dateStrId_ = jni->GetMethodID(jc, "toString", "()Ljava/lang/String;");
dateValId_ = jni->GetStaticMethodID(jc, "valueOf", "(Ljava/lang/String;)Ljava/sql/Date;");
if (jni->ExceptionOccurred() || dateStrId_ == NULL || dateValId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.sql.Date");
}
}
else
{
return LM_ERR;
}
// Load java.sql.Time
jc = (jclass) loadSysClass("java/sql/Time", "java.sql.Time", diagsArea_);
if (jc != NULL)
{
timeClass_ = jc;
timeStrId_ = jni->GetMethodID(jc, "toString", "()Ljava/lang/String;");
timeValId_ = jni->GetStaticMethodID(jc, "valueOf", "(Ljava/lang/String;)Ljava/sql/Time;");
if (jni->ExceptionOccurred() || timeStrId_ == NULL || timeValId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.sql.Time");
}
}
else
{
return LM_ERR;
}
// Load java.sql.Timestamp
jc = (jclass) loadSysClass("java/sql/Timestamp", "java.sql.Timestamp", diagsArea_);
if (jc != NULL)
{
stampClass_ = jc;
stampStrId_ = jni->GetMethodID(jc, "toString", "()Ljava/lang/String;");
stampValId_ = jni->GetStaticMethodID(jc, "valueOf",
"(Ljava/lang/String;)Ljava/sql/Timestamp;");
if (stampStrId_ == NULL || stampValId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.sql.Timestamp");
}
}
else
{
return LM_ERR;
}
// Load java.lang.Integer
jc = (jclass) loadSysClass("java/lang/Integer", "java.lang.Integer", diagsArea_);
if (jc != NULL)
{
intClass_ = jc;
intCtorId_ = jni->GetMethodID(jc, "<init>", "(I)V");
intValId_ = jni->GetMethodID(jc, "intValue", "()I");
if (jni->ExceptionOccurred() || intCtorId_ == NULL || intValId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.lang.Integer");
}
}
else
{
return LM_ERR;
}
// Load java.lang.Long
jc = (jclass) loadSysClass("java/lang/Long", "java.lang.Long", diagsArea_);
if (jc != NULL)
{
longClass_ = jc;
longCtorId_ = jni->GetMethodID(jc, "<init>", "(J)V");
longValId_ = jni->GetMethodID(jc, "longValue", "()J");
if (jni->ExceptionOccurred() || longCtorId_ == NULL || longValId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.lang.Long");
}
}
else
{
return LM_ERR;
}
// Load java.lang.Float
jc = (jclass) loadSysClass("java/lang/Float", "java.lang.Float", diagsArea_);
if (jc != NULL)
{
floatClass_ = jc;
floatCtorId_ = jni->GetMethodID(jc, "<init>", "(F)V");
floatValId_ = jni->GetMethodID(jc, "floatValue", "()F");
if (jni->ExceptionOccurred() || floatCtorId_ == NULL || floatValId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.lang.Float");
}
}
else
{
return LM_ERR;
}
// Load java.lang.Double
jc = (jclass) loadSysClass("java/lang/Double", "java.lang.Double", diagsArea_);
if (jc != NULL)
{
doubleClass_ = jc;
doubleCtorId_ = jni->GetMethodID(jc, "<init>", "(D)V");
doubleValId_ = jni->GetMethodID(jc, "doubleValue", "()D");
if (jni->ExceptionOccurred() || doubleCtorId_ == NULL || doubleValId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.lang.Double");
}
}
else
{
return LM_ERR;
}
// Load java.sql.ResultSet
resultSetClass_ = loadSysClass("java/sql/ResultSet",
"java.sql.ResultSet", diagsArea_);
if (resultSetClass_ == NULL)
return LM_ERR;
rsCloseId_ = jni->GetMethodID((jclass)resultSetClass_, "close", "()V");
rsBeforeFirstId_ = jni->GetMethodID((jclass)resultSetClass_,
"beforeFirst",
"()V");
rsNextId_ = jni->GetMethodID((jclass)resultSetClass_, "next", "()Z");
rsWasNullId_ = jni->GetMethodID((jclass)resultSetClass_, "wasNull", "()Z");
rsGetWarningsId_ = jni->GetMethodID((jclass)resultSetClass_,
"getWarnings",
"()Ljava/sql/SQLWarning;");
rsGetShortId_ = jni->GetMethodID((jclass)resultSetClass_, "getShort", "(I)S");
rsGetIntId_ = jni->GetMethodID((jclass)resultSetClass_, "getInt", "(I)I");
rsGetLongId_ = jni->GetMethodID((jclass)resultSetClass_, "getLong", "(I)J");
rsGetFloatId_ = jni->GetMethodID((jclass)resultSetClass_, "getFloat", "(I)F");
rsGetDoubleId_ = jni->GetMethodID((jclass)resultSetClass_, "getDouble", "(I)D");
rsGetBigDecimalId_ = jni->GetMethodID((jclass)resultSetClass_, "getBigDecimal", "(I)Ljava/math/BigDecimal;");
rsGetStringId_ = jni->GetMethodID((jclass)resultSetClass_,
"getString",
"(I)Ljava/lang/String;");
rsGetObjectId_ = jni->GetMethodID((jclass)resultSetClass_,
"getObject",
"(I)Ljava/lang/Object;");
rsGetDateId_ = jni->GetMethodID((jclass)resultSetClass_,
"getDate",
"(I)Ljava/sql/Date;");
rsGetTimeId_ = jni->GetMethodID((jclass)resultSetClass_,
"getTime",
"(I)Ljava/sql/Time;");
rsGetTimestampId_ = jni->GetMethodID((jclass)resultSetClass_,
"getTimestamp",
"(I)Ljava/sql/Timestamp;");
if (jni->ExceptionOccurred() ||
rsCloseId_ == NULL || rsGetWarningsId_ == NULL ||
rsGetShortId_ == NULL || rsGetIntId_ == NULL ||
rsGetLongId_ == NULL || rsGetFloatId_ == NULL ||
rsGetObjectId_ == NULL || rsGetStringId_ == NULL ||
rsGetBigDecimalId_ == NULL || rsWasNullId_ == NULL ||
rsGetDateId_ == NULL || rsGetTimeId_ == NULL ||
rsBeforeFirstId_ == NULL || rsNextId_ == NULL ||
rsGetDoubleId_ == NULL || rsGetTimestampId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.sql.ResultSet");
}
// Load java.sql.Connection
connClass_ = loadSysClass("java/sql/Connection",
"java.sql.Connection", diagsArea_);
if (connClass_ == NULL)
return LM_ERR;
connCloseId_ = jni->GetMethodID((jclass)connClass_,
"close", "()V");
connIsClosedId_ = jni->GetMethodID((jclass)connClass_,
"isClosed", "()Z");
if (jni->ExceptionOccurred() || connCloseId_ == NULL ||
connIsClosedId_ == NULL)
{
return exceptionReporter_->insertDiags(diagsArea_,
-LME_JVM_SYS_CLASS_ERROR,
"java.sql.Connection");
}
TIMER_OFF(set2ClsTimer, "Load Set 2 of classes");
enableType2Conn_ = TRUE;
mapDefaultConnToType2Conn_ = TRUE;
jdbcMxT2Driver_ = loadSysClass("org/trafodion/jdbc/t2/T2Driver",
"org.trafodion.jdbc.t2.T2Driver", diagsArea_);
if (jdbcMxT2Driver_ == NULL)
return LM_ERR;
return LM_OK;
}
LmLanguageManagerJava::~LmLanguageManagerJava()
{
JNIEnv* jni = (JNIEnv*)jniEnv_;
// Adjust the LMJ counter.
--numLMJava_;
if (numLMJava_ == 0)
{
NADELETEBASIC(sysClassPath_, collHeap());
NADELETEBASIC(classPath_, collHeap());
}
if (userName_)
NADELETEBASIC(userName_, collHeap());
if (userPassword_)
NADELETEBASIC(userPassword_, collHeap());
if (datasourceName_)
NADELETEBASIC(datasourceName_, collHeap());
if( sysCatalog_ )
NADELETEBASIC(sysCatalog_, collHeap());
if( sysSchema_ )
NADELETEBASIC(sysSchema_, collHeap());
// Ensure the LMJ was constructed properly.
if (jni == NULL)
return;
// De-allocate instance objects and unref Java class objects.
delete contManager_;
delete exceptionReporter_;
unloadSysClass(loaderClass_);
unloadSysClass(utilityClass_);
unloadSysClass(lmCharsetClass_);
unloadSysClass(stringClass_);
unloadSysClass(systemClass_);
unloadSysClass(bigdecClass_);
unloadSysClass(dateClass_);
unloadSysClass(timeClass_);
unloadSysClass(stampClass_);
unloadSysClass(intClass_);
unloadSysClass(longClass_);
unloadSysClass(floatClass_);
unloadSysClass(doubleClass_);
unloadSysClass(resultSetClass_);
unloadSysClass(connClass_);
unloadSysClass(lmObjMethodInvokeClass_);
unloadSysClass(routineReturnInfoClass_);
unloadSysClass(jdbcMxT2Driver_);
unloadSysClass(jdbcMxT4Driver_);
// Detach from JVM.
LmSqlJVM->DetachCurrentThread();
}
void LmLanguageManagerJava::destroyVM()
{
LM_ASSERT(numLMJava_ == 0);
if (LmSqlJVM)
{
lmRestoreJavaSignalHandlers();
// Bring down the JVM
LmSqlJVM->DestroyJavaVM();
LmSqlJVM = NULL;
lmRestoreUdrTrapSignalHandlers(TRUE);
}
}
//////////////////////////////////////////////////////////////////////
// LM service: validateRoutine
//////////////////////////////////////////////////////////////////////
LmResult LmLanguageManagerJava::validateRoutine(
ComUInt32 numSqlParam,
ComFSDataType paramType[],
ComUInt32 paramSubType[],
ComColumnDirection direction[],
const char *routineName,
const char *containerName,
const char *externalPath,
char *sigBuf,
ComUInt32 sigLen,
ComFSDataType resultType,
ComUInt32 resultSubType,
ComUInt32 numResultSets,
const char *metaContainerName,
const char *optionalSig,
ComDiagsArea *diagsArea)
{
LmContainer *container;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
ComBoolean isUdrForJavaMain = FALSE;
ComDiagsArea *da = NULL;
da = ((diagsArea != NULL) ? diagsArea : diagsArea_);
if (startService(da) == LM_ERR)
return LM_ERR;
// Get the requested container from the CM.
result = contManager_->getContainer(containerName, externalPath,
&container, da);
if (result == LM_ERR)
return LM_ERR;
//
// Create a Java signature for the specfied routine based upon
// the various SQL attributes such as parameter type and mode.
//
// Special treatment is given if 'UDR is for main()' (UDR-MAIN)
// because main() takes only one parameter.
//
isUdrForJavaMain = ((str_cmp_ne(routineName, "main") == 0) ? TRUE: FALSE);
LmJavaSignature javaSig(NULL, collHeap());
result = javaSig.createSig(paramType, paramSubType, direction,
numSqlParam, resultType, resultSubType,
numResultSets, optionalSig, isUdrForJavaMain,
sigBuf, sigLen, da);
if (result == LM_ERR)
return LM_ERR;
//
// Though UDR-MAIN accepts 0 or more parameters, the underlying Java
// method takes only one parameter.
//
ComUInt32 numJavaParam;
if (isUdrForJavaMain)
numJavaParam = 1;
else
numJavaParam = numSqlParam;
// Using sigBuf signature, call LmUtility@verifyMethodSignature()
jvalue jval[4];
jval[0].l = (jobject) container->getHandle();
jval[1].l = (jstring) jni->NewStringUTF(routineName);
LmResult midChk = exceptionReporter_->checkNewObjectExceptions(jval[1].l, da);
if(midChk == LM_ERR)
return LM_ERR;
jval[2].l = (jstring) jni->NewStringUTF(sigBuf);
midChk = exceptionReporter_->checkNewObjectExceptions(jval[2].l, da);
if(midChk == LM_ERR){
jni->DeleteLocalRef(jval[1].l);
return LM_ERR;
}
jval[3].i = (jint) numJavaParam;
jni->CallStaticVoidMethodA((jclass)utilityClass_,
(jmethodID)verifyMethodId_,
jval);
jni->DeleteLocalRef(jval[1].l);
jni->DeleteLocalRef(jval[2].l);
// verifyMethodSignature() throws exception on failure.
if (jni->ExceptionOccurred() != NULL)
{
LmJavaSignature lmSig(sigBuf, collHeap());
ComSInt32 size = lmSig.getUnpackedSignatureSize();
ComUInt32 totLen = str_len(routineName) + size;
char *signature = new (collHeap()) char[totLen + 1];
sprintf(signature, "%s", routineName);
lmSig.unpackSignature(signature + str_len(routineName));
signature[totLen] = '\0';
result = exceptionReporter_->insertDiags(da,
-LME_ROUTINE_NOT_FOUND,
signature,
containerName);
if (signature) NADELETEBASIC(signature, collHeap());
}
else
{
result = LM_OK;
}
// De-ref the container.
if (container) contManager_->putContainer(container);
return result;
}
//////////////////////////////////////////////////////////////////////
// LM serivce: getRoutine.
//////////////////////////////////////////////////////////////////////
LmResult LmLanguageManagerJava::getRoutine(
ComUInt32 numSqlParam,
LmParameter parameters[],
ComUInt32 numTableInfo,
LmTableInfo tableInfo[],
LmParameter *returnValue,
ComRoutineParamStyle paramStyle,
ComRoutineTransactionAttributes transactionAttrs,
ComRoutineSQLAccess sqlAccessMode,
const char *parentQid,
ComUInt32 inputRowLen,
ComUInt32 outputRowLen,
const char *sqlName,
const char *externalName,
const char *routineSig,
const char *containerName,
const char *externalPath,
const char *librarySqlName,
const char *currentUserName,
const char *sessionUserName,
ComRoutineExternalSecurity externalSecurity,
Int32 routineOwnerId,
LmRoutine **handle,
LmHandle getNextRowPtr,
LmHandle emitRowPtr,
ComUInt32 maxResultSets,
ComDiagsArea *diagsArea)
{
NABoolean status = lmRestoreJavaSignalHandlers();
if (status != TRUE) {
if (diagsArea)
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore Java signal handlers before entering Java in getRoutine");
return LM_ERR;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored Java signal handlers before entering Java in getRoutine");
JNIEnv *jni = (JNIEnv*)jniEnv_;
*handle = NULL;
LmContainer *container = NULL;
LmResult result = LM_OK;
ComDiagsArea *da = NULL;
da = ((diagsArea != NULL) ? diagsArea : diagsArea_);
if (startService(da) == LM_ERR)
result = LM_ERR;
if (result != LM_ERR)
// Get the requested container from the CM.
result = contManager_->getContainer(containerName, externalPath,
&container, da);
if (result != LM_ERR)
{
// Get the method ID from the container for the requested routine.
jmethodID jm = jni->GetStaticMethodID((jclass)container->getHandle(),
externalName, routineSig);
// Handle the result of the method ID look-up.
if (jm != NULL)
{
// allocate an LM handle for the Java method.
LmRoutineJava *h = new (collHeap())
LmRoutineJava(sqlName, externalName, librarySqlName, numSqlParam, returnValue,
maxResultSets, (char *)routineSig,
COM_STYLE_JAVA_CALL,
transactionAttrs,
sqlAccessMode,
externalSecurity,
routineOwnerId,
parentQid, inputRowLen, outputRowLen,
currentUserName, sessionUserName,
parameters, this, jm, container, da);
// Verify the handle.
if (h == NULL || !h->isValid())
{
// DiagsArea is already filled by LmRoutineJava.
if (h)
delete h;
if (container)
contManager_->putContainer(container);
result = LM_ERR;
}
else
{
*handle = h;
}
}
else // Look-up failed. Set Diags area and return error.
{
ComSInt32 size = 0;
LmJavaSignature *lmSig = new (collHeap()) LmJavaSignature(routineSig,
collHeap());
size = lmSig->getUnpackedSignatureSize();
ComUInt32 totLen = str_len(externalName) + size;
char *signature = new (collHeap()) char[totLen + 1];
sprintf(signature, "%s", externalName);
lmSig->unpackSignature(signature + str_len(externalName));
signature[totLen] = '\0';
NADELETEBASIC(lmSig, collHeap());
result = exceptionReporter_->checkGetMethodExceptions(signature,
containerName,
da);
// Upon failure, de-ref the container.
if (container)
contManager_->putContainer(container);
if (signature)
NADELETEBASIC(signature, collHeap());
result = LM_ERR;
}
}
status = lmRestoreUdrTrapSignalHandlers(TRUE);
if (status != TRUE) {
if (diagsArea)
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore UDR trap signal handlers after returning from Java in getRoutine");
return LM_ERR;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored UDR trap signal handlers after returning from Java in getRoutine");
return result;
}
LmResult LmLanguageManagerJava::getObjRoutine(
const char *serializedInvocationInfo,
int invocationInfoLen,
const char *serializedPlanInfo,
int planInfoLen,
ComRoutineLanguage language,
ComRoutineParamStyle paramStyle,
const char *externalName,
const char *containerName,
const char *externalPath,
const char *librarySqlName,
LmRoutine **handle,
ComDiagsArea *diagsArea)
{
*handle = NULL;
NABoolean status = lmRestoreJavaSignalHandlers();
if (status != TRUE) {
if (diagsArea)
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore Java signal handlers before entering Java in getObjRoutine");
return LM_ERR;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored Java signal handlers before entering Java in getObjRoutine");
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmContainer *container = NULL;
LmResult result = LM_OK;
ComDiagsArea *da = NULL;
da = ((diagsArea != NULL) ? diagsArea : diagsArea_);
if (startService(da) == LM_ERR)
result = LM_ERR;
if (result != LM_ERR)
// Get the requested container from the CM.
result = contManager_->getContainer(containerName, externalPath,
&container, da);
if (result != LM_ERR)
{
// Get the method ID from the container for the requested routine.
jmethodID jm = jni->GetMethodID((jclass)container->getHandle(),
externalName,
"()V");
// Handle the result of the method ID look-up.
if (jm != NULL)
{
tmudr::UDRInvocationInfo *invocationInfo = NULL;
ComRoutineTransactionAttributes transactionAttrs = COM_NO_TRANSACTION_REQUIRED;
ComRoutineSQLAccess sqlAccessMode = COM_NO_SQL;
ComRoutineExternalSecurity externalSecurity = COM_ROUTINE_EXTERNAL_SECURITY_DEFINER;
// call the default constructor for the specified class, this
// creates a user-defined object derived from class
// org.trafodion.sql.udr.UDR. We pass this object to the
// Routine constructor, which will allocate a global reference
// for it and dispose of it when it is destroyed. We make this
// call outside the LmRoutineJavaObj constructor so that it
// can also be done for validation.
jobject newUDRObj = jni->NewObject((jclass)container->getHandle(), jm);
if (newUDRObj == NULL || jni->ExceptionOccurred())
{
if (diagsArea)
exceptionReporter_->insertDiags(
diagsArea,
-LME_UDR_METHOD_ERROR,
"constructor",
// Details: field will be blank, detail info
// is provided in a separate error entry.
containerName);
result = LM_ERR;
}
if (invocationInfoLen > 0 && result == LM_OK)
{
// unpack invocation info to get to some info for the routine
invocationInfo = new tmudr::UDRInvocationInfo();
try
{
invocationInfo->deserializeObj(serializedInvocationInfo,
invocationInfoLen);
}
catch (...)
{
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Error unpacking info in LmLanguageManagerJava::getObjRoutine()");
result = LM_ERR;
}
if (result == LM_OK)
{
// for now we don't allow a choice, once we do we need to translate enums
LM_ASSERT(invocationInfo->sqlTransactionType_ ==
tmudr::UDRInvocationInfo::REQUIRES_NO_TRANSACTION);
LM_ASSERT(invocationInfo->sqlAccessType_ ==
tmudr::UDRInvocationInfo::CONTAINS_NO_SQL);
LM_ASSERT(invocationInfo->sqlRights_ ==
tmudr::UDRInvocationInfo::INVOKERS_RIGHTS);
// allocate an LM handle for the Java method.
LmRoutineJavaObj *h = new (collHeap())
LmRoutineJavaObj(invocationInfo->getUDRName().c_str(),
externalName,
librarySqlName,
transactionAttrs,
sqlAccessMode,
externalSecurity,
0, // routine owner id is 0 for now
serializedInvocationInfo,
invocationInfoLen,
serializedPlanInfo,
planInfoLen,
this,
newUDRObj,
container,
da);
// Verify the handle.
if (h == NULL || !h->isValid())
{
// DiagsArea is already filled by LmRoutineJava.
if (h)
delete h;
// no need to deallocate newUDRObj, since it is
// just a local reference
result = LM_ERR;
}
else
{
*handle = h;
}
}
if (invocationInfo)
delete invocationInfo;
} // invocation info was specified
else if (result == LM_OK)
{
// Invocation info length is 0, this happens during
// validation of a routine at DDL time. Return success
// but don't create a routine object.
}
}
else // Look-up failed. Set Diags area and return error.
{
result = exceptionReporter_->checkGetMethodExceptions(externalName,
containerName,
da);
result = LM_ERR;
}
}
status = lmRestoreUdrTrapSignalHandlers(TRUE);
if (status != TRUE) {
if (diagsArea)
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore UDR trap signal handlers after returning from Java in getObjRoutine");
result = LM_ERR;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored UDR trap signal handlers after returning from Java in getObjRoutine");
// avoid leaking a container in the error case
if (result != LM_OK && container)
contManager_->putContainer(container);
return result;
}
//////////////////////////////////////////////////////////////////////
// LM serivce: putRoutine.
//////////////////////////////////////////////////////////////////////
LmResult LmLanguageManagerJava::putRoutine(
LmRoutine *handle,
ComDiagsArea *diagsArea)
{
ComDiagsArea *da = NULL;
da = ((diagsArea != NULL) ? diagsArea : diagsArea_);
if (startService(da) == LM_ERR)
return LM_ERR;
NABoolean status = lmRestoreJavaSignalHandlers();
if (status != TRUE) {
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore Java signal handlers before entering Java in putRoutine");
return LM_ERR;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored Java signal handlers before entering Java in putRoutine");
LmResult result = LM_OK;
// Verify the specified handle.
LmRoutineJava *h = (LmRoutineJava*)handle;
if (h == NULL)
{
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Invalid Routine Handle.");
result = LM_ERR;
}
else
{
// De-ref the container.
if (h->container()) contManager_->putContainer(h->container());
// De-allocate the handle.
delete h;
}
status = lmRestoreUdrTrapSignalHandlers(TRUE);
if (status != TRUE) {
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore UDR trap signal handlers after returning from Java in putRoutine");
return LM_ERR;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored UDR trap signal handlers after returning from Java in putRoutine");
return result;
}
//////////////////////////////////////////////////////////////////////
// LM serivce: invokeRoutine.
//////////////////////////////////////////////////////////////////////
LmResult LmLanguageManagerJava::invokeRoutine(
LmRoutine *handle,
void *inputRow,
void *outputRow,
ComDiagsArea *diagsArea)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
ComDiagsArea *da = NULL;
da = ((diagsArea != NULL) ? diagsArea : diagsArea_);
LmRoutineJava *routine = (LmRoutineJava *) handle;
LmResult result = LM_OK;
if (startService(da) == LM_ERR)
return LM_ERR;
// Verify the specified routine handle.
if (routine == NULL || !routine->isValid())
{
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Invalid Routine Handle.");
return LM_ERR;
}
NABoolean status = lmRestoreJavaSignalHandlers();
if (status != TRUE) {
if (diagsArea)
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore Java signal handlers before entering Java in invokeRoutine");
return LM_ERR;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored Java signal handlers before entering Java in invokeRoutine");
if (routine->getParamStyle() == COM_STYLE_JAVA_OBJ)
{
LmRoutineJavaObj *javaObjRoutine = static_cast<LmRoutineJavaObj *>(routine);
Int32 dummy1, dummy2;
// this path is only used for the run-time call, where we
// have already received the UDRInvocationInfo/UDRPlanInfo
result = javaObjRoutine->invokeRoutineMethod(
tmudr::UDRInvocationInfo::RUNTIME_WORK_CALL,
NULL, // invocation info already there
0,
&dummy1, // expecting no updated invocation info
NULL, // plan info is already there or not used
0,
-1,
&dummy2, // expecting no updated plan info
(char *) inputRow,
-1, // use row length set earlier
(char *) outputRow,
-1, // use row length set earlier
da);
} // Java object routine, used for TMUDFs
else
{
// this is a Java routine with Java parameters, used for SPJs
LmParameter *lmParams = routine->getLmParams();
// Map the in-bound parameters from SQL to Java values.
result = processInParameters(routine, lmParams, inputRow, da);
if (result == LM_ERR)
{
processParametersDone(routine, lmParams);
}
else
{
// Before invoking method, make sure we don't have any pending exceptions.
if (jni->ExceptionOccurred() != NULL)
{
exceptionReporter_->insertDiags(da,
-LME_INTERNAL_ERROR,
": There is a pending exception.");
processParametersDone(routine, lmParams);
result = LM_ERR;
}
}
if (result != LM_ERR)
{
// Invoke the Java method.
routine->setDefaultCatSchFlag(setDefaultCatSchFlag_);
result = routine->invokeRoutine(inputRow, outputRow, da);
// Handle any uncaught Java exceptions.
result = exceptionReporter_->processUserException(routine, da);
NABoolean javaException = (result == LM_OK ? FALSE : TRUE);
// If there are any uncaught Java exceptions then there may be
// Java result set and connection objects created in the SPJ
// method that may still be valid and they need to be cleaned up.
// We need to call processOutParameters() even when exceptions
// are thrown so that we have the necessary LM objects created
// which are required for the cleanup process.
// Map the out-bound parameters from Java to SQL values.
result = processOutParameters(routine, lmParams, outputRow,
javaException, da);
// De-ref any Java objects resulting from the type mappings.
processParametersDone(routine, lmParams);
}
} // Java routine with Java parameters
status = lmRestoreUdrTrapSignalHandlers(TRUE);
if (status != TRUE) {
if (diagsArea)
*diagsArea_ << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Could not restore UDR trap signal handlers after returning from Java in invokeRoutine");
return LM_ERR;
}
LM_DEBUG_SIGNAL_HANDLERS("[SIGNAL] Restored UDR trap signal handlers after returning from Java in invokeRoutine");
return result;
}
//////////////////////////////////////////////////////////////////////
// CM support methods: createLoader, deleteLoader, loadContainer,
// and unloadContainer.
//////////////////////////////////////////////////////////////////////
/* createLoader(): creates a LmClassLoader object for a given directory
* path 'externalPath'
* Returns: pinned ref to LmClassLoader object on SUCCESS
* NULL on FAILURE
*/
LmHandle LmLanguageManagerJava::createLoader(
const char *externalPath,
ComDiagsArea *da)
{
ComUInt32 i;
JNIEnv *jni = (JNIEnv*)jniEnv_;
jobject jobj;
jvalue jval[2];
// Strip the file protocol from the path.
i = skipURLProtocol(externalPath);
//
// The LmClassLoader takes two parameters: path, and debug flag.
// debug flag is not used currently. May be we can make use of it
// in future.
//
jval[0].l = jni->NewStringUTF(&externalPath[i]);
LmResult midChk = exceptionReporter_->checkNewObjectExceptions(jval[0].l, da);
if(midChk == LM_ERR)
return NULL;
jval[1].i = 0;
// Create an LmClassLoader
jobj = jni->CallStaticObjectMethodA((jclass)utilityClass_,
(jmethodID)createCLId_,
jval);
jni->DeleteLocalRef(jval[0].l);
// Check for Exceptions.
if (jni->ExceptionOccurred() != NULL)
{
exceptionReporter_->insertDiags(da, -LME_CLASSLOADER_ERROR);
return NULL;
}
// pin the ClassLoader Object. And delete local reference.
jobject globalobj = jni->NewGlobalRef(jobj);
jni->DeleteLocalRef(jobj);
return globalobj;
}
/* deleteLoader() : De-ref the loader so that the JVM can garbage collect it.
*/
void LmLanguageManagerJava::deleteLoader(LmHandle loader)
{
unloadSysClass((jobject)loader);
}
/* loadcontainer() : Load the 'containerName' class file from 'externalPath'
* directory using extLoader(LmClassLoader object corresponding to path).
* Returns: pinned ref to the class object on success
* NULL on FAILURE
*/
LmHandle LmLanguageManagerJava::loadContainer(
const char *containerName,
const char *externalPath,
LmHandle extLoader,
ComUInt32 *containerSize,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jobject jobj, container;
jstring jstr;
if (extLoader == NULL)
{
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Invalid ClassLoader handle is passed to load a class file.");
return NULL;
}
jstr = jni->NewStringUTF(containerName);
LmResult midChk = exceptionReporter_->checkNewObjectExceptions(jstr, da);
if(midChk == LM_ERR)
return NULL;
//
// Call the ClassLoader's loadClass() method to get the container.
// Before that we need to remove ClassPath from ClassLoader's search
// list so that the class will be loaded only from external path.
// After calling loadClass(), we add ClassPath again.
//
jni->CallVoidMethod((jobject)extLoader, (jmethodID)removeCpURLsId_);
jobj = jni->CallObjectMethod((jobject)extLoader,
(jmethodID)loadClassId_,
jstr);
jni->DeleteLocalRef(jstr);
if (jni->ExceptionOccurred() == NULL)
{
// pin the object for the container
container = jni->NewGlobalRef(jobj);
jni->DeleteLocalRef(jobj);
// Call the LmClassLoader's size method to get its current capacity.
*containerSize =
jni->CallIntMethod((jobject)extLoader, (jmethodID)loaderSizeId_);
}
else
{
container = NULL;
exceptionReporter_->insertDiags(da,
-LME_CONT_NOT_FOUND,
containerName,
externalPath);
}
// Add the CLASSPATH to the search list of the ClassLoader
jni->CallVoidMethod((jobject)extLoader, (jmethodID)addCpURLsId_);
return container;
}
/* unloadContainer() : De-ref the container. Note that it is still
* referenced via the base class loader.
*/
void LmLanguageManagerJava::unloadContainer(LmHandle container)
{
if (container)
((JNIEnv*)jniEnv_)->DeleteGlobalRef((jobject)container);
}
//
// processInParameters(): Maps IN/INOUT params from SQL to Java values.
// For all types except primitive numeric types(eg int, float),
// NULL value is ok. In this case, NULL reference is sent to the
// Java method. If NULL is passed in as input to primitive type,
// then error will be returned.
//
LmResult LmLanguageManagerJava::processInParameters(
LmRoutineJava *handle,
LmParameter params[],
void *inputRow,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jvalue *jval = (jvalue*)handle->javaParams_;
LmResult result = LM_OK;
ComBoolean isUdrForJavaMain = handle->isUdrForJavaMain();
for (Int32 i = 0; i < (Int32)handle->numSqlParam_; i++)
{
LmParameter *p = &params[i];
if (p->direction() == COM_OUTPUT_COLUMN)
continue;
void *thisParamDataPtr = (void*) ((char*)inputRow + p->inDataOffset());
// Check for null value
NABoolean valIsNull = p->isNullInput((char *) inputRow);
switch (LmJavaType(p).getType())
{
case LmJavaType::JT_SHORT:
{
if (valIsNull)
{
*da << DgSqlCode(-LME_NULL_NOT_ALLOWED)
<< DgInt0(i+1);
return LM_ERR;
}
jshort j = *(jshort*) thisParamDataPtr;
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].s = j;
}
else
{
jni->SetShortArrayRegion((jshortArray)jval[i].l, 0, 1, &j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
}
break;
case LmJavaType::JT_INT:
{
if (valIsNull)
{
*da << DgSqlCode(-LME_NULL_NOT_ALLOWED)
<< DgInt0(i+1);
return LM_ERR;
}
jint j = *(jint*) thisParamDataPtr;
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].i = j;
}
else
{
jni->SetIntArrayRegion((jintArray)jval[i].l, 0, 1, &j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
}
break;
case LmJavaType::JT_LONG:
{
if (valIsNull)
{
*da << DgSqlCode(-LME_NULL_NOT_ALLOWED)
<< DgInt0(i+1);
return LM_ERR;
}
jlong j = *(jlong*) thisParamDataPtr;
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].j = j;
}
else
{
jni->SetLongArrayRegion((jlongArray)jval[i].l, 0, 1, &j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
}
break;
case LmJavaType::JT_FLOAT:
{
if (valIsNull)
{
*da << DgSqlCode(-LME_NULL_NOT_ALLOWED)
<< DgInt0(i+1);
return LM_ERR;
}
jfloat j = *(jfloat*) thisParamDataPtr;
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].f = j;
}
else
{
jni->SetFloatArrayRegion((jfloatArray)jval[i].l, 0, 1, &j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
}
break;
case LmJavaType::JT_DOUBLE:
{
if (valIsNull)
{
*da << DgSqlCode(-LME_NULL_NOT_ALLOWED)
<< DgInt0(i+1);
return LM_ERR;
}
jdouble j = *(jdouble*) thisParamDataPtr;
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].d = j;
}
else
{
jni->SetDoubleArrayRegion((jdoubleArray)jval[i].l, 0, 1, &j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
}
break;
case LmJavaType::JT_LANG_STRING:
{
jstring j = NULL;
if (! valIsNull)
{
convertToString(p, inputRow, (LmHandle *) &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
//
// Special treatment for UDR-MAIN
//
// Java method(main()) has only one parameter which is String[]
// So copy all the actual parameters into this array
//
if (isUdrForJavaMain)
{
jni->SetObjectArrayElement((jobjectArray)jval[0].l, i, j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
else
{
jval[i].l = j;
}
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
case LmJavaType::JT_MATH_BIGDEC:
{
LmHandle j = NULL;
if (! valIsNull)
{
result = convertToBigdec(p, inputRow, &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].l = (jobject)j;
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, (jobject)j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
case LmJavaType::JT_SQL_DATE:
{
LmHandle j = NULL;
if (! valIsNull)
{
result = convertToDate(p, inputRow, &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].l = (jobject)j;
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, (jobject)j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
case LmJavaType::JT_SQL_TIME:
{
LmHandle j = NULL;
if (! valIsNull)
{
result = convertToTime(p, inputRow, &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].l = (jobject)j;
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, (jobject)j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
case LmJavaType::JT_SQL_TIMESTAMP:
{
LmHandle j = NULL;
if (! valIsNull)
{
result = convertToTimestamp(p, inputRow, &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].l = (jobject)j;
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, (jobject)j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
case LmJavaType::JT_LANG_INTEGER:
{
LmHandle j = NULL;
if (! valIsNull)
{
result = convertToInteger(p, inputRow, &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].l = (jobject)j;
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, (jobject)j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
case LmJavaType::JT_LANG_LONG:
{
LmHandle j = NULL;
if (! valIsNull)
{
result = convertToLong(p, inputRow, &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].l = (jobject)j;
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, (jobject)j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
case LmJavaType::JT_LANG_FLOAT:
{
LmHandle j = NULL;
if (! valIsNull)
{
result = convertToFloat(p, inputRow, &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].l = (jobject)j;
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, (jobject)j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
case LmJavaType::JT_LANG_DOUBLE:
{
LmHandle j = NULL;
if (! valIsNull)
{
result = convertToDouble(p, inputRow, &j, da);
if (result == LM_ERR)
return result;
}
if (p->direction() == COM_INPUT_COLUMN)
{
jval[i].l = (jobject)j;
}
else
{
jni->SetObjectArrayElement((jobjectArray)jval[i].l, 0, (jobject)j);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
jni->DeleteLocalRef((jobject)j);
}
}
break;
default:
{
char errStr[LMJ_ERR_SIZE_256];
sprintf (errStr, ". Unknown parameter type encountered at parameter position %d.", i+1);
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(errStr);
return LM_ERR;
}
} // Switch
} // For
return LM_OK;
}
/* processOutParameters: Maps OUT/INOUT params from Java to SQL values.
*/
LmResult LmLanguageManagerJava::processOutParameters(
LmRoutineJava *handle,
LmParameter params[],
void *outputRow,
NABoolean uncaughtExp,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jvalue *jval = (jvalue*)handle->javaParams_;
jobject jobj;
LmResult result = LM_OK;
Int32 i;
// Do not process the OUT/INOUT Sql params when there
// are uncaught exceptions from SPJ invocation
if (!uncaughtExp) {
for (i = 0; i < (Int32)handle->numSqlParam_ && result == LM_OK; i++)
{
LmParameter *p = &params[i];
if (p->direction() == COM_INPUT_COLUMN)
continue;
void *thisParamDataPtr = (void*) ((char*)outputRow + p->outDataOffset());
ComBoolean valIsNull = FALSE;
switch (LmJavaType(p).getType())
{
case LmJavaType::JT_SHORT:
{
jni->GetShortArrayRegion((jshortArray)jval[i].l,
0, 1, (jshort*)thisParamDataPtr);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
break;
case LmJavaType::JT_INT:
{
jni->GetIntArrayRegion((jintArray)jval[i].l,
0, 1, (jint*)thisParamDataPtr);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
break;
case LmJavaType::JT_LONG:
{
jni->GetLongArrayRegion((jlongArray)jval[i].l,
0, 1, (jlong*)thisParamDataPtr);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
break;
case LmJavaType::JT_FLOAT:
{
jni->GetFloatArrayRegion((jfloatArray)jval[i].l,
0, 1, (jfloat*)thisParamDataPtr);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
break;
case LmJavaType::JT_DOUBLE:
{
jni->GetDoubleArrayRegion((jdoubleArray)jval[i].l,
0, 1, (jdouble*)thisParamDataPtr);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
}
break;
case LmJavaType::JT_LANG_STRING:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromString(p, outputRow, jobj, da);
jni->DeleteLocalRef(jobj);
WARN_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
case LmJavaType::JT_MATH_BIGDEC:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromBigdec(p, outputRow, jobj);
jni->DeleteLocalRef(jobj);
ERR_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
case LmJavaType::JT_SQL_DATE:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromDate(p, outputRow, jobj);
jni->DeleteLocalRef(jobj);
WARN_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
case LmJavaType::JT_SQL_TIME:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromTime(p, outputRow, jobj);
jni->DeleteLocalRef(jobj);
WARN_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
case LmJavaType::JT_SQL_TIMESTAMP:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromTimestamp(p, outputRow, jobj);
jni->DeleteLocalRef(jobj);
WARN_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
case LmJavaType::JT_LANG_INTEGER:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromInteger(p, outputRow, jobj);
jni->DeleteLocalRef(jobj);
ERR_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
case LmJavaType::JT_LANG_LONG:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromLong(p, outputRow, jobj);
jni->DeleteLocalRef(jobj);
ERR_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
case LmJavaType::JT_LANG_FLOAT:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromFloat(p, outputRow, jobj, da);
jni->DeleteLocalRef(jobj);
ERR_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
case LmJavaType::JT_LANG_DOUBLE:
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
valIsNull = (jobj == NULL) ? TRUE : FALSE;
if (! valIsNull)
{
result = convertFromDouble(p, outputRow, jobj, da);
jni->DeleteLocalRef(jobj);
ERR_LM_PARAM_OVERFLOW(result, i+1);
}
}
break;
default:
{
char errStr[LMJ_ERR_SIZE_256];
sprintf(errStr,
": Unknown parameter type encountered at parameter position %d.",
i+1);
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(errStr);
result = LM_ERR;
}
break;
} // switch (LmJavaType(p)->getType())
// Set Null indicator bytes with correct byte value. The
// setNullOutput() method is safe to call even for NOT NULL
// parameters.
p->setNullOutput((char *) outputRow, valIsNull);
} // for each parameter
} // if (uncaughtExp)
// Now process result set parameters if any returned by the routine.
// The below result set processing logic needs to execute even when
// 'result' != LM_OK since we will need to create LmResultSet objects
// which will help us close any open result sets and the associated
// connections.
LmResult rsResult = LM_OK;
if (handle->maxResultSets_ > 0) {
for (i = (Int32)handle->numSqlParam_;
i < (Int32)handle->numParamsInSig_; i++)
{
jobj = jni->GetObjectArrayElement((jobjectArray)jval[i].l, 0);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
// If errors occurred in previous iterations then we have
// still go ahead and delete the remaining result set objects.
if (rsResult != LM_OK && jobj != NULL) {
jni->DeleteLocalRef(jobj);
continue;
}
// Check if the linked-in JDBC/MX Type 2 driver supports SPJ RS and if it
// does then make sure there is no version mismatch in driver's interfaces.
// If the SPJ method returns a NULL in all of it's RS parameters
// then there are no RS to process and the above check can be waived.
if (jobj != NULL && enableType2Conn_ &&
(!jdbcSupportsRS_ || jdbcRSVerMismatch()))
{
if (!jdbcSupportsRS_)
*da << DgSqlCode(-LME_JDBC_SUPPORT_SPJRS_ERROR)
<< DgString0(handle->getNameForDiags());
else
*da << DgSqlCode(-LME_JDBC_SPJRS_VERSION_ERROR)
<< DgString0(handle->getNameForDiags())
<< DgInt0((Lng32) jdbcSPJRSVer_)
<< DgInt1((Lng32) JDBC_SPJRS_VERSION);
rsResult = LM_ERR;
jni->DeleteLocalRef(jobj);
continue;
}
rsResult = handle->populateResultSetInfo(jobj, i, da);
jni->DeleteLocalRef(jobj);
}
// Check if the SPJ method returned more result sets than it's
// declared maximum
if (result == LM_OK && !uncaughtExp &&
handle->getNumResultSets() > handle->maxResultSets_) {
*da << DgSqlCode(LME_TOO_MANY_RS)
<< DgString0(handle->getNameForDiags())
<< DgInt0((Lng32) handle->maxResultSets_)
<< DgInt1((Lng32) handle->getNumResultSets());
handle->deleteLmResultSetsOverMax(da);
}
}
// We will now go ahead and close any default connections
// that may have been opened within the SPJ method but
// there are no result sets associated with that connection.
handle->closeDefConnWithNoRS(da);
// If there are uncaught exceptions from the SPJ invocation
// or if there were errors processing the routine's out params
// then do result sets clean up and return LM_ERR status.
if (result != LM_OK || rsResult != LM_OK || uncaughtExp) {
handle->cleanupResultSets(da);
result = LM_ERR;
}
return result;
}
/* processParametersDone(): De-ref Java objects resulting from IN mode
* type mappings. Note that de-ref for INOUT param objects is done in
* processInParameters after the object is set as an array element.
*/
void LmLanguageManagerJava::processParametersDone(
LmRoutineJava *handle,
LmParameter params[])
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jvalue *jval = (jvalue*)handle->javaParams_;
ComBoolean isUdrForJavaMain = handle->isUdrForJavaMain();
//
// The objects for IN params for UDr-MAIN are allocated by the
// constructor of LmRoutineJava. So let LmRoutineJava deallocate them.
//
if (isUdrForJavaMain)
{
return;
}
for (Int32 i = 0; i < (Int32)handle->numSqlParam_; i++)
{
LmParameter *p = &params[i];
// No de-ref required for OUT/INOUT.
if (p->isOut())
continue;
// De-ref objects created for IN mode parameters.
if (LmJavaType(p).isJavaTypeObject())
{
if (jval[i].l != NULL)
jni->DeleteLocalRef(jval[i].l);
}
// Each IN mode parameter's Java value is nulled so that INOUT/OUT
// parameter arrays can be recognized and de-ref in the LmRoutineJava
// destructor.
jval[i].l = NULL;
}
}
/*
* convert<To|From><Type>: See comments in LmLangManagerJava.h
*/
LmResult
LmLanguageManagerJava::convertToString(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jobject jobj;
ComUInt32 len = param->actualInDataSize(inputRow);
char *inputChars = ((char *)inputRow) + param->inDataOffset();
NABoolean singleCharWorkAround = FALSE;
if (len == 1 && param->encodingCharSet() == CharInfo::SJIS)
{
// Following is a workaround for a problem when a single ASCII byte
// is passed when SJIS charset is in effect. In this case a String
// with no bytes is being created.
//
// The workaround is to pass atleast two bytes, so we are adding
// a null terminator. Later, the null terminator is removed by
// calling subtring() method.
//
// FIXME: As of August 2009, this problem still exists in NSJ5. If
// we move to a newer NSJ we should once again verify whether the
// problem still exists.
char *localInputChars = inputChars;
inputChars = new (collHeap()) char[len+1];
singleCharWorkAround = TRUE;
str_cpy_all(inputChars, localInputChars, (Lng32) len);
inputChars[len] = '\0';
len++;
}
// Allocate Byte Array in JVM.
jbyteArray javaBytes = jni->NewByteArray((Lng32)len);
LmResult result = exceptionReporter_->
checkNewObjectExceptions(javaBytes, da);
if (result == LM_ERR)
{
// Deallocate inputChars if it was allocated
if (singleCharWorkAround)
NADELETEBASIC(inputChars, collHeap());
return LM_ERR;
}
// Set the Byte array with the input bytes
jni->SetByteArrayRegion(javaBytes, 0, (Lng32)len, (jbyte *)inputChars);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
// Deallocate inputChars if it was allocated
if (singleCharWorkAround)
NADELETEBASIC(inputChars, collHeap());
// Set charset of input
jstring inputCharset = NULL;
switch (param->encodingCharSet())
{
case CharInfo::ISO88591:
inputCharset = jni->NewStringUTF("ISO88591");
break;
case CharInfo::UNICODE:
inputCharset = jni->NewStringUTF("UCS2");
break;
case CharInfo::SJIS:
inputCharset = jni->NewStringUTF("SJIS");
break;
case CharInfo::UTF8:
inputCharset = jni->NewStringUTF("UTF8");
break;
default:
jni->DeleteLocalRef(javaBytes);
LM_ASSERT(0);
break;
}
// Create String object from the byte array
jobj = (jstring)jni->CallStaticObjectMethod((jclass) lmCharsetClass_,
(jmethodID)bytesToUnicodeId_,
javaBytes, inputCharset,
(jint)0, (jint)len);
jni->DeleteLocalRef(inputCharset);
jni->DeleteLocalRef(javaBytes);
result = exceptionReporter_->checkNewObjectExceptions(jobj, da);
if (result == LM_ERR)
return LM_ERR;
// Workaround for single ASCII char for SJIS charset string
if (singleCharWorkAround)
jobj = jni->CallObjectMethod(jobj, (jmethodID) stringSubstringId_, 0 , 1);
*obj = jobj;
return LM_OK;
}
LmResult LmLanguageManagerJava::convertFromString(
LmParameter *param,
void *outputRow,
LmHandle obj,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jstring inputStr = (jstring)obj;
LmResult result = LM_OK;
jbyteArray javaBytesArray;
// Set charset of the output bytes
jstring outputCharset = NULL;
CharInfo::CharSet charset = param->encodingCharSet();
switch (charset)
{
case CharInfo::ISO88591:
outputCharset = jni->NewStringUTF("ISO88591");
break;
case CharInfo::UNICODE:
outputCharset = jni->NewStringUTF("UCS2");
break;
case CharInfo::SJIS:
outputCharset = jni->NewStringUTF("SJIS");
break;
case CharInfo::UTF8:
outputCharset = jni->NewStringUTF("UTF8");
break;
default:
LM_ASSERT(0);
}
// Get the bytes from the String in outputCharset charset
javaBytesArray = (jbyteArray)
jni->CallStaticObjectMethod((jclass) lmCharsetClass_,
(jmethodID) unicodeToBytesId_,
inputStr, outputCharset);
jni->DeleteLocalRef(outputCharset);
if(!javaBytesArray){
exceptionReporter_->checkJVMException(da, NULL);
return LM_ERR;
}
jsize len = jni->GetArrayLength(javaBytesArray);
char *rawBytes = new (collHeap()) char[len];
jni->GetByteArrayRegion(javaBytesArray, 0, len, (signed char *)rawBytes);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
if (charset == CharInfo::SJIS || charset == CharInfo::UTF8)
{
// In some cases, JVM returns NULL Characters at the end for
// SJIS and UTF8 strings. One example is when single byte SJIS
// characters are used, JVM returns two bytes for each character.
//
// Here, we adjust 'len' to ignore the extra NULL Chars that exist
// at the end of the string.
Int32 index;
for (index=len-1; (index >= 0 && rawBytes[index] == '\0'); index--);
len = index + 1;
}
result = param->setOutChar(outputRow, rawBytes, len);
NADELETEBASIC(rawBytes, collHeap());
jni->DeleteLocalRef(javaBytesArray);
return result;
}
LmResult LmLanguageManagerJava::convertFromInterval(
LmParameter *param,
void *outputRow,
LmHandle obj,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jstring jstr = (jstring)obj;
LmResult result = LM_OK;
jbyteArray javaBytesArray;
jstring outputCharset = jni->NewStringUTF("ISO88591");
javaBytesArray = (jbyteArray)
jni->CallStaticObjectMethod((jclass) lmCharsetClass_,
(jmethodID) unicodeToBytesId_,
jstr, outputCharset);
jni->DeleteLocalRef(outputCharset);
if(!javaBytesArray){
exceptionReporter_->checkJVMException(da, NULL);
return LM_ERR;
}
jsize len = 0;
len = jni->GetArrayLength(javaBytesArray);
if (len <= 0)
{
exceptionReporter_->checkJVMException(da, NULL);
jni->DeleteLocalRef(javaBytesArray);
return LM_ERR;
}
char *rawBytes = new (collHeap()) char[len];
jni->GetByteArrayRegion(javaBytesArray, 0, len, (signed char *)rawBytes);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
result = param->setOutInterval(outputRow, rawBytes, len);
NADELETEBASIC(rawBytes, collHeap());
jni->DeleteLocalRef(javaBytesArray);
return result;
}
LmResult LmLanguageManagerJava::convertToBigdec(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
jobject jobj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
char tempbuf[131];
char *inputChars = ((char *)inputRow) + param->inDataOffset();
ComUInt32 len = param->actualInDataSize(inputRow);
// Bigdecimal value will never be more than 130 bytes long
// This includes the optional sign byte and decimal point
LM_ASSERT(len < 131);
// First create the java.lang.String from the input bytes
str_cpy_all(tempbuf, inputChars, (Lng32) len);
tempbuf[len] = '\0';
jstring jstr = jni->NewStringUTF(tempbuf);
if (exceptionReporter_->checkNewObjectExceptions(jstr, da) == LM_ERR)
return LM_ERR;
// Create java.math.BigDecimal object from java.lang.String value
jobj = jni->NewObject((jclass)bigdecClass_, (jmethodID)bigdecCtorId_, jstr);
result = exceptionReporter_->checkNewObjectExceptions(jobj, da);
jni->DeleteLocalRef(jstr);
*obj = jobj;
return result;
}
LmResult LmLanguageManagerJava::convertFromBigdec(
LmParameter *param,
void *outputRow,
LmHandle obj,
ComBoolean resultSet_decimal, // useful to decide setting Numeric or Decimal
// type. The default value FALSE will set
// Numeric type.
ComBoolean copyBinary, // flag to copy binary value into target
// This is true while copying RS bigdec values
ComDiagsArea *da)
{
jobject jobj = (jobject)obj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
jstring jstr;
LmResult result = LM_OK;
jstr = (jstring)jni->CallObjectMethod(jobj, (jmethodID)bigdecStrId_);
if (!jstr)
{
exceptionReporter_->checkJVMException(da, NULL);
return LM_ERR;
}
const char *str = jni->GetStringUTFChars(jstr, NULL);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
if (resultSet_decimal)
{
result = param->setOutDecimal(outputRow, str, collHeap(), da);
}
else
{
result = param->setOutNumeric(outputRow, str, copyBinary, collHeap(), da);
}
jni->ReleaseStringUTFChars(jstr, str);
jni->DeleteLocalRef(jstr);
return result;
}
LmResult LmLanguageManagerJava::convertToDate(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
jobject jobj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
jstring jstr;
LmResult result = LM_OK;
char tempbuf[64];
char *inputChars = ((char *)inputRow) + param->inDataOffset();
ComUInt32 len = param->actualInDataSize(inputRow);
// NOTE: jdbc only handles default date: yyyy-mm-dd.
len = (len <= 10)? len : 10;
// First create the java.lang.String from the input bytes
str_cpy_all(tempbuf, inputChars, (Lng32) len);
tempbuf[len] = '\0';
jstr = jni->NewStringUTF(tempbuf);
if (exceptionReporter_->checkNewObjectExceptions(jstr, da) == LM_ERR)
return LM_ERR;
// Create java.sql.Date object from java.lang.String value
jobj = jni->CallStaticObjectMethod((jclass)dateClass_,
(jmethodID)dateValId_, jstr);
result = exceptionReporter_->checkJVMException(da);
jni->DeleteLocalRef(jstr);
*obj = jobj;
return result;
}
LmResult LmLanguageManagerJava::convertFromDate(
LmParameter *param,
void *outputRow,
LmHandle obj,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jobject jobj = (jobject)obj;
jstring jstr;
LmResult result = LM_OK;
const char *str;
jstr = (jstring)jni->CallObjectMethod(jobj, (jmethodID)dateStrId_);
if (!jstr)
{
exceptionReporter_->checkJVMException(da, NULL);
return LM_ERR;
}
str = jni->GetStringUTFChars(jstr, NULL);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
result = param->setOutDate(outputRow, str);
jni->ReleaseStringUTFChars(jstr, str);
jni->DeleteLocalRef(jstr);
return result;
}
LmResult LmLanguageManagerJava::convertToTime(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
jobject jobj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
char tempbuf[64];
char *inputChars = ((char *)inputRow) + param->inDataOffset();
ComUInt32 len = param->actualInDataSize(inputRow);
// NOTE: jdbc only handles default time: hh:mm:ss.msssss (less .mssss).
len = (len <= 8)? len : 8;
// First create the java.lang.String from the input bytes
str_cpy_all(tempbuf, inputChars, (Lng32) len);
tempbuf[len] = '\0';
jstring jstr = jni->NewStringUTF(tempbuf);
if (exceptionReporter_->checkNewObjectExceptions(jstr, da) == LM_ERR)
return LM_ERR;
// Create java.sql.Time object from java.lang.String value
jobj = jni->CallStaticObjectMethod((jclass)timeClass_,
(jmethodID)timeValId_, jstr);
result = exceptionReporter_->checkJVMException(da);
jni->DeleteLocalRef(jstr);
*obj = jobj;
return result;
}
LmResult LmLanguageManagerJava::convertFromTime(
LmParameter *param,
void *outputRow,
LmHandle obj,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jobject jobj = (jobject)obj;
jstring jstr;
LmResult result = LM_OK;
const char *str;
jstr = (jstring)jni->CallObjectMethod(jobj, (jmethodID)timeStrId_);
if (!jstr)
{
exceptionReporter_->checkJVMException(da, NULL);
return LM_ERR;
}
str = jni->GetStringUTFChars(jstr, NULL);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
result = param->setOutTime(outputRow, str);
jni->ReleaseStringUTFChars(jstr, str);
jni->DeleteLocalRef(jstr);
return result;
}
LmResult LmLanguageManagerJava::convertToTimestamp(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
jobject jobj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
char tempbuf[64];
char *inputChars = ((char *)inputRow) + param->inDataOffset();
ComUInt32 len = param->actualInDataSize(inputRow);
// NOTE: jdbc only handles default timestamp: yyyy-mm-dd hh:mm:ss.msssss.
len = (len <= 26) ? len : 26;
// First create the java.lang.String from the input bytes
str_cpy_all(tempbuf, inputChars, (Lng32) len);
tempbuf[len] = '\0';
jstring jstr = jni->NewStringUTF(tempbuf);
if (exceptionReporter_->checkNewObjectExceptions(jstr, da) == LM_ERR)
return LM_ERR;
// Create java.sql.Timestamp object from java.lang.String value
jobj = jni->CallStaticObjectMethod((jclass)stampClass_,
(jmethodID)stampValId_, jstr);
result = exceptionReporter_->checkJVMException(da);
jni->DeleteLocalRef(jstr);
*obj = jobj;
return result;
}
LmResult LmLanguageManagerJava::convertFromTimestamp(
LmParameter *param,
void *outputRow,
LmHandle obj,
ComDiagsArea *da)
{
JNIEnv *jni = (JNIEnv*)jniEnv_;
jobject jobj = (jobject)obj;
jstring jstr;
LmResult result = LM_OK;
const char *str;
jstr = (jstring)jni->CallObjectMethod(jobj, (jmethodID)stampStrId_);
if (!jstr)
{
exceptionReporter_->checkJVMException(da, NULL);
return LM_ERR;
}
str = jni->GetStringUTFChars(jstr, NULL);
LM_ASSERT(jni->ExceptionOccurred() == NULL);
result = param->setOutTimestamp(outputRow, str);
jni->ReleaseStringUTFChars(jstr, str);
jni->DeleteLocalRef(jstr);
return result;
}
LmResult LmLanguageManagerJava::convertToInteger(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
jobject jobj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
jint val = *(jint*) ((char *)inputRow + param->inDataOffset());
jobj = jni->NewObject((jclass)intClass_, (jmethodID)intCtorId_, val);
result = exceptionReporter_->checkNewObjectExceptions(jobj, da);
*obj = jobj;
return result;
}
LmResult LmLanguageManagerJava::convertFromInteger(
LmParameter *param,
void *outputRow,
LmHandle obj)
{
jobject jobj = (jobject)obj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
jint r = jni->CallIntMethod(jobj, (jmethodID)intValId_);
result = param->setOutInteger(outputRow, r);
return result;
}
LmResult LmLanguageManagerJava::convertToLong(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
jobject jobj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
jlong val = *(jlong*) ((char *)inputRow + param->inDataOffset());
jobj = jni->NewObject((jclass)longClass_, (jmethodID)longCtorId_, val);
result = exceptionReporter_->checkNewObjectExceptions(jobj, da);
*obj = jobj;
return result;
}
LmResult LmLanguageManagerJava::convertFromLong(
LmParameter *param,
void *outputRow,
LmHandle obj)
{
jobject jobj = (jobject)obj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
jlong r = jni->CallLongMethod(jobj, (jmethodID)longValId_);
result = param->setOutLargeInt(outputRow, r);
return result;
}
LmResult LmLanguageManagerJava::convertToFloat(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
jobject jobj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
jfloat val = *(jfloat*) ((char *)inputRow + param->inDataOffset());
jvalue args[1];
args[0].f = val;
jobj = jni->NewObjectA((jclass)floatClass_,
(jmethodID)floatCtorId_, args);
result = exceptionReporter_->checkNewObjectExceptions(jobj, da);
*obj = jobj;
return result;
}
LmResult LmLanguageManagerJava::convertFromFloat(
LmParameter *param,
void *outputRow,
LmHandle obj,
ComDiagsArea *da)
{
jobject jobj = (jobject)obj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
jfloat r = jni->CallFloatMethod(jobj, (jmethodID)floatValId_);
result = param->setOutReal(outputRow, r);
return result;
}
LmResult LmLanguageManagerJava::convertToDouble(
LmParameter *param,
void *inputRow,
LmHandle *obj,
ComDiagsArea *da)
{
jobject jobj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
jdouble val = *(jdouble*) ((char *)inputRow + param->inDataOffset());
jvalue args[1];
args[0].d = val;
jobj = jni->NewObjectA((jclass)doubleClass_,
(jmethodID)doubleCtorId_, args);
result = exceptionReporter_->checkNewObjectExceptions(jobj, da);
*obj = jobj;
return result;
}
LmResult LmLanguageManagerJava::convertFromDouble(
LmParameter *param,
void *outputRow,
LmHandle obj,
ComDiagsArea *da)
{
jobject jobj = (jobject)obj;
JNIEnv *jni = (JNIEnv*)jniEnv_;
LmResult result = LM_OK;
jdouble r = jni->CallDoubleMethod(jobj, (jmethodID)doubleValId_);
result = param->setOutDouble(outputRow, r);
return result;
}
/* startService(): Prepare for next service call and verify that serivce
* can be started.
*/
LmResult LmLanguageManagerJava::startService(ComDiagsArea *da)
{
if (LmSqlJVM != NULL && jniEnv_ != NULL && threadId_ == threadId())
return LM_OK;
else
{
*da << DgSqlCode(-LME_INTERNAL_ERROR)
<< DgString0(": Language Manager is not started yet.");
return LM_ERR;
}
}
void LmLanguageManagerJava::setJavaClassPath()
{
ComUInt32 totLen = 0;
char *ntJars = NULL;
char installdir[LMJ_NT_FILE_PATH_LEN];
Lng32 resultlength = 0;
const char *ntLmJar = "/export/lib/mxlangman.jar";
const char *ntTrafJar = "/export/lib/trafodion-UDR-0.7.0.jar";
const char *ntJdbcT4Jar = "/export/lib/jdbcT2.jar";
char *root = getenv("TRAF_HOME");
LM_ASSERT(root != NULL);
resultlength = strlen(root) + 1;
LM_ASSERT(resultlength < LMJ_NT_FILE_PATH_LEN);
strcpy(installdir, root);
ntJars = new (collHeap())
char[3*resultlength + str_len(ntTrafJar) + str_len(ntLmJar) + str_len(ntJdbcT4Jar) + 3];
sprintf(ntJars, "%s%s:%s%s:%s%s", installdir, ntLmJar, installdir, ntJdbcT4Jar, installdir, ntTrafJar);
char *jExt = NULL;
if (jExt && jExt[0])
{
totLen = str_len(jExt) + str_len(ntJars);
sysClassPath_ = new (collHeap()) char[totLen + 2];
sprintf(sysClassPath_, "%s:%s", jExt, ntJars);
NADELETEBASIC(ntJars, collHeap());
ntJars = NULL;
}
else
{
sysClassPath_ = ntJars;
}
// Now get CLASSPATH if it's set.
char *envClassPath = getenv("CLASSPATH");
if (envClassPath && envClassPath[0])
{
classPath_ = new (collHeap()) char[str_len(envClassPath) + 1];
sprintf(classPath_, "%s", envClassPath);
}
return;
}
/* threadId(): Returns the current thread's ID. OS-dependent.
*/
ComSInt32 LmLanguageManagerJava::threadId()
{
return GetCurrThreadId() ;
}
/* getSystemProperty(): Get the value of a Java system property.
* Returns: LM_ERR if exceptions occur,
* LM_OK Otherwise.
* propertyIsSet is set to TRUE/FALSE depending on property is set or not.
* value is set to the value of the property if the property is set.
*/
LmResult LmLanguageManagerJava::getSystemProperty(
const char *key,
char *value,
ComUInt32 bufferLen,
ComBoolean &propertyIsSet,
ComDiagsArea *diagsArea)
{
JNIEnv *jni = (JNIEnv*) jniEnv_;
jstring jstrIn = NULL, jstrOut = NULL;
const char *cstrOut = NULL;
ComDiagsArea *da = NULL;
da = ((diagsArea != NULL) ? diagsArea : diagsArea_);
propertyIsSet = FALSE;
jstrIn = jni->NewStringUTF(key);
LmResult midChk = exceptionReporter_->checkNewObjectExceptions(jstrIn, da);
if(midChk == LM_ERR)
return LM_ERR;
jstrOut = (jstring) jni->CallStaticObjectMethod(
(jclass) systemClass_, (jmethodID) systemGetPropId_,jstrIn);
jni->DeleteLocalRef(jstrIn);
if (exceptionReporter_->checkJVMException(da, 0) == LM_ERR)
return LM_ERR;
if (jstrOut == NULL)
return LM_OK;
cstrOut = jni->GetStringUTFChars(jstrOut, NULL);
if (cstrOut == NULL)
{
*da << DgSqlCode (-LME_INTERNAL_ERROR)
<< DgString0 (" while getting system property.");
jni->DeleteLocalRef(jstrOut);
return LM_ERR;
}
ComUInt32 len = (ComUInt32) str_len(cstrOut);
if (len < bufferLen)
str_cpy_all(value, cstrOut, (Lng32) (len + 1));
else if (bufferLen > 0)
{
str_cpy_all(value, cstrOut, (Lng32) (bufferLen - 1));
value[bufferLen - 1] = 0;
}
propertyIsSet = TRUE;
jni->ReleaseStringUTFChars(jstrOut, cstrOut);
jni->DeleteLocalRef(jstrOut);
return LM_OK;
}
/* setSystemProperty(): Set the value of a Java system property.
* Returns LM_OK if the operation is successful.
*/
LmResult LmLanguageManagerJava::setSystemProperty(
const char *key,
const char *value,
ComDiagsArea *diagsArea)
{
JNIEnv *jni = (JNIEnv*) jniEnv_;
jstring jstrKey = NULL, jstrVal = NULL, jstrResult = NULL;
ComDiagsArea *da = NULL;
da = ((diagsArea != NULL) ? diagsArea : diagsArea_);
jstrKey = jni->NewStringUTF(key);
LmResult midChk = exceptionReporter_->checkNewObjectExceptions(jstrKey, da);
if(midChk == LM_ERR){
if(jstrKey)
jni->DeleteLocalRef(jstrKey);
return LM_ERR;
}
jstrVal = jni->NewStringUTF(value);
midChk = exceptionReporter_->checkNewObjectExceptions(jstrVal, da);
if(midChk == LM_ERR){
jni->DeleteLocalRef(jstrKey);
if(jstrVal)
jni->DeleteLocalRef(jstrVal);
return LM_ERR;
}
jstrResult = (jstring) jni->CallStaticObjectMethod(
(jclass)systemClass_, (jmethodID)systemSetPropId_, jstrKey, jstrVal);
jni->DeleteLocalRef(jstrResult);
jni->DeleteLocalRef(jstrVal);
jni->DeleteLocalRef(jstrKey);
if (exceptionReporter_->checkJVMException(da, 0) == LM_ERR)
return LM_ERR;
return LM_OK;
}
/* clearSystemProperty(): Clear the value of a Java system property.
* Returns LM_OK if the operation is successful.
* This is used for clearing the sqlmx.udr.defAuthToken property
* for Definer Rights SPJ. The property is first cleared in
* LmSQLMXDriver code, but it is also done here in case the SPJ method
* does not call getConnection.
* There is no exception checking done here for JNI calls
* as that would result in showing internal error in clearSystemProperty
* if there was any exception thrown while invoking the SPJ method.
*/
LmResult LmLanguageManagerJava::clearSystemProperty(
const char *key,
ComDiagsArea *diagsArea)
{
JNIEnv *jni = (JNIEnv*) jniEnv_;
jstring jstrKey = NULL, jstrResult = NULL;
ComDiagsArea *da = NULL;
da = ((diagsArea != NULL) ? diagsArea : diagsArea_);
jstrKey = jni->NewStringUTF(key);
if(jstrKey == NULL)
return LM_ERR;
jstrResult = (jstring) jni->CallStaticObjectMethod(
(jclass)systemClass_, (jmethodID)systemClearPropId_, jstrKey);
jni->DeleteLocalRef(jstrKey);
jni->DeleteLocalRef(jstrResult);
return LM_OK;
}
// Here is where we massage user-specified JVM options into the set
// that we actually want to pass to the JVM. Note that userOptions
// will not be modified by this method.
void
LmLanguageManagerJava::processJavaOptions(const LmJavaOptions &userOptions,
LmJavaOptions &jvmOptions)
{
jvmOptions.merge(userOptions);
// Check if userid information is passed from executor.
jvmOptions.removeSystemProperty("sqlmx.udr.username", &userName_, collHeap());
// Check if password information is passed from executor.
jvmOptions.removeSystemProperty("sqlmx.udr.password", &userPassword_, collHeap());
// Check if datasource information is passed from executor.
jvmOptions.removeSystemProperty("sqlmx.datasource",
&datasourceName_,
collHeap());
// The system property sqlmx.udr.jrehome has special meaning. If
// specified it tells us to set the JREHOME environment variable. We
// look for it here and if found, we set JREHOME and also leave the
// property definition intact.
char *userJreHomeValue = NULL;
NABoolean foundJreHome =
jvmOptions.removeSystemProperty("sqlmx.udr.jrehome",
&userJreHomeValue,
collHeap());
if (foundJreHome)
{
LM_ASSERT(userJreHomeValue);
const char *envPrefix = "JREHOME=";
char *envString = new (collHeap())
char[str_len(envPrefix) + str_len(userJreHomeValue) + 10];
str_sprintf(envString, "%s%s", envPrefix, userJreHomeValue);
putenv(envString);
NADELETEBASIC(envString, collHeap());
jvmOptions.addSystemProperty("sqlmx.udr.jrehome", userJreHomeValue);
NADELETEBASIC(userJreHomeValue, collHeap());
}
// On Yosemite, we need to set environment to pick up correct JVM
// and threads library files. JVM library is included in _RLD_LIB_PATH
// and threads library is included in _RLD_FIRST_LIB_PATH.
// SQL/JRT says this property should be defined in any JVM running
// "within a DBMS". The standard says its value should be
// "jdbc:default:connection". The connections created using the
// above URL (default connections) are only supported from within
// the SPJ environment via the LmSQLMXDriver Java class.
jvmOptions.addSystemProperty("sqlj.defaultconnection",
"jdbc:default:connection");
} // processJavaOptions()